feat: bounty board, task lifecycle, AI work performer flow, notifications (phase 8)
- whitelist HTML sanitizer (stdlib tokenizer) with XSS vector tests - developer board: pool-scoped visibility, customer/search/minBounty/sort filters, stale-task age badges, competing-claims visibility setting, saved filters in profile extras - claims: request/withdraw (developer), approve/decline (consultant) with notifications to winners and losers; unassign/abandon back to board - work tracking: start, sanitized comments with @mention notifications, time logging, submit for review - review queue + review with per-AC checklist stored on the timeline; approve writes the immutable bountyAwards row (human assignees only) - assign-to-AI: §5.2 job submission, HMAC-verified callback endpoint, idempotent by jobId, artifacts downloaded into GridFS, failure path keeps the task assigned with timeline + notification - notifications API + bell with unread badge, dropdown, page, WS toasts - pages: bounty board, my-tasks kanban, task detail (role-driven actions, review dialog, AI dialog), review queue, developer pool Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+19
-8
@@ -14,6 +14,7 @@ import (
|
||||
"bountyboard/internal/files"
|
||||
"bountyboard/internal/metrics"
|
||||
"bountyboard/internal/store"
|
||||
"bountyboard/internal/workperform"
|
||||
)
|
||||
|
||||
// shutdownBudget is the §12 graceful-shutdown drain window.
|
||||
@@ -33,14 +34,21 @@ type Server struct {
|
||||
httpSrv *http.Server
|
||||
|
||||
// late-bound subsystem hooks (see providers.go)
|
||||
atomizer BreakerInfo
|
||||
performer BreakerInfo
|
||||
syncProvider StatusProvider
|
||||
jobsProvider StatusProvider
|
||||
syncTrigger func(customerID string)
|
||||
publishFn func(channel, event string, payload any)
|
||||
enqueueFn func(ctx context.Context, kind string, payload any) (string, error)
|
||||
wsHandler func(w http.ResponseWriter, r *http.Request, userID string)
|
||||
atomizer BreakerInfo
|
||||
performer BreakerInfo
|
||||
syncProvider StatusProvider
|
||||
jobsProvider StatusProvider
|
||||
syncTrigger func(customerID string)
|
||||
publishFn func(channel, event string, payload any)
|
||||
enqueueFn func(ctx context.Context, kind string, payload any) (string, error)
|
||||
wsHandler func(w http.ResponseWriter, r *http.Request, userID string)
|
||||
performerClient *workperform.Client
|
||||
}
|
||||
|
||||
// SetPerformerClient wires the §5.2 client (also feeds the status panel).
|
||||
func (s *Server) SetPerformerClient(c *workperform.Client) {
|
||||
s.performerClient = c
|
||||
s.performer = c
|
||||
}
|
||||
|
||||
func New(cfg *config.Config, log *slog.Logger, reg *metrics.Registry, st *store.Store, fs *files.Store) *Server {
|
||||
@@ -70,6 +78,9 @@ func New(cfg *config.Config, log *slog.Logger, reg *metrics.Registry, st *store.
|
||||
s.routesProfile(mux)
|
||||
s.routesAdmin(mux)
|
||||
s.routesTasks(mux)
|
||||
s.routesBoard(mux)
|
||||
s.routesConsultant(mux)
|
||||
s.routesWorkResults(mux)
|
||||
mux.HandleFunc("GET /ws", s.handleWS)
|
||||
s.routesWeb(mux)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user