70a813edfa
- 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>
32 lines
957 B
Go
32 lines
957 B
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"bountyboard/internal/ulid"
|
|
)
|
|
|
|
// BountyAward is the immutable ledger row (§4.5) — never updated, never
|
|
// recomputed from mutable tasks.
|
|
type BountyAward struct {
|
|
ID string `bson:"_id" json:"id"`
|
|
TaskID string `bson:"taskId" json:"taskId"`
|
|
DeveloperID string `bson:"developerId" json:"developerId"`
|
|
ConsultantID string `bson:"consultantId" json:"consultantId"`
|
|
CustomerID string `bson:"customerId" json:"customerId"`
|
|
Amount float64 `bson:"amount" json:"amount"`
|
|
Coefficient float64 `bson:"coefficient" json:"coefficient"`
|
|
AwardedAt time.Time `bson:"awardedAt" json:"awardedAt"`
|
|
}
|
|
|
|
func (s *Store) InsertAward(ctx context.Context, a *BountyAward) error {
|
|
a.ID = ulid.New()
|
|
a.AwardedAt = time.Now().UTC()
|
|
if _, err := s.DB.Collection("bountyAwards").InsertOne(ctx, a); err != nil {
|
|
return fmt.Errorf("insert award: %w", err)
|
|
}
|
|
return nil
|
|
}
|