Skip to content

Let a creator archive or delete a bounty - #560

Merged
ralyodio merged 1 commit into
masterfrom
worktree-bounty-archive-delete
Sep 22, 2026
Merged

ralyodio merged 1 commit into
masterfrom
worktree-bounty-archive-delete

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

Bounties had a status column (open/paused/closed) but no control anywhere to change it, and no way to remove one. This adds both.

Archive

  • New archived status. Keeps the bounty and every submission, invoice and payout record.
  • Hidden from the public list and detail page via RLS (same rule as closed).
  • Moves to its own Archived tab on /dashboard/bounties.
  • Unarchive sets the bounty back to closed, so it does not silently reopen for submissions. Reopen is one more click.

Delete

  • DELETE /api/bounties/:id, creator only.
  • Refused with 409 and archive_instead: true once any submission has been approved, invoiced or paid. The cascade would erase payment history, so the UI offers to archive instead.
  • Pending and rejected submissions delete with the bounty.

UI

  • New BountyActions menu (mirrors GigActions): pause / resume / close, archive / unarchive, delete, with confirm dialogs.
  • Sits in the sidebar of /bounties/:id and on every row of the dashboard list (rows are no longer one big link).
  • Archived bounties show a creator-only notice on the detail page.

GitHub issue comment

When the bounty funds a GitHub issue, the status comment is flipped to "withdrawn" on archive or delete and restored to "posted" on reopen. The comment bodies now live in src/lib/bounty-issue-comments.ts.

Database

Migration applied to the live project via the Supabase MCP and recorded as 20260922045204_bounty_archived_status. It widens the status CHECK and rewrites the public SELECT policy. Both changes are backwards compatible with the code on master.

Docs

public/openapi.json and public/skill.md document the new status, the DELETE endpoint and the 409.

Verification

  • tsc --noEmit clean
  • pnpm lint 0 errors
  • 38 bounty tests pass across 7 files, including 11 new ones for DELETE, the archive/reopen comment sync and the delete guard
  • pnpm build exit 0

Noticed but not changed: updateBountySchema is createBountySchema.partial(), and the payout_currency default survives .partial(), so every PATCH also writes payout_currency: "USD". Harmless today since every bounty is USD.

🤖 Generated with Claude Code

Bounties had a status column (open/paused/closed) but no control anywhere
to change it, and no way to remove one. This adds both.

Archive is a new `archived` status. It keeps the bounty and every
submission, invoice and payout record, hides the bounty from the public
list and detail page (RLS, same as closed) and moves it to its own
Archived tab on /dashboard/bounties. Unarchive sets it back to closed so
it does not silently reopen for submissions.

Delete is DELETE /api/bounties/:id, creator only. It is refused with 409
(and `archive_instead: true`) once any submission has been approved,
invoiced or paid, because the cascade would erase payment history; the
UI then offers to archive. Pending and rejected submissions delete with
the bounty.

The new BountyActions menu mirrors GigActions (pause/resume/close,
archive/unarchive, delete) and sits on the bounty detail page and each
dashboard row. When the bounty funds a GitHub issue, the status comment
is flipped to "withdrawn" on archive or delete and restored on reopen;
the comment bodies now live in one module.

Migration applied to the live project as 20260922045204. openapi.json
and skill.md document the new status and endpoint.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

45 finding(s)

HIGH/CRITICAL: 1 | MEDIUM: 8 | LOW: 36

Severity Rule Location
HIGH js-ssrf-outbound-request scripts/scan-all-skills.ts:38
MEDIUM js-open-redirect src/app/agent-login/AgentLoginForm.tsx:38
MEDIUM js-unescaped-html-sink src/app/blog/[slug]/page.tsx:79
MEDIUM js-open-redirect src/app/dashboard/subscription/page.tsx:90
MEDIUM js-open-redirect src/app/dashboard/subscription/page.tsx:113
MEDIUM js-open-redirect src/app/dashboard/subscription/page.tsx:144
MEDIUM js-open-redirect src/components/funding/FundingClient.tsx:137
MEDIUM js-dynamic-code-execution src/lib/skills/metadata-extract.ts:300
MEDIUM js-dynamic-code-execution src/lib/skills/security-scan.ts:48
LOW secret-generic-credential cli/src/commands/auth.test.ts:66
LOW secret-generic-credential cli/src/commands/auth.test.ts:85
LOW secret-generic-api-key docs/agents/integration-guide.md:893
LOW secret-generic-credential src/app/api/auth/login/route.test.ts:53
LOW secret-generic-credential src/app/api/auth/login/route.test.ts:68
LOW secret-generic-credential src/app/api/auth/login/route.test.ts:87
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:158
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:182
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:193
LOW secret-generic-credential src/app/api/auth/signup/route.test.ts:232
LOW js-dynamic-code-execution src/app/api/skills/[slug]/scan/route.test.ts:212
LOW js-dynamic-code-execution src/app/api/skills/[slug]/scan/route.test.ts:223
LOW js-dynamic-code-execution src/app/api/skills/[slug]/scan/route.test.ts:239
LOW secret-generic-credential src/lib/api.test.ts:126
LOW secret-generic-credential src/lib/api.test.ts:131
LOW js-dynamic-code-execution src/lib/skills/composite-scanner.test.ts:106
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:36
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:44
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:66
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:81
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:94
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:103
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:118
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:144
LOW js-dynamic-code-execution src/lib/skills/secureclaw-scanner.test.ts:162
LOW js-dynamic-code-execution src/lib/skills/security-scan.test.ts:28
LOW js-dynamic-code-execution src/lib/skills/url-import.test.ts:178
LOW js-dynamic-code-execution src/lib/skills/url-import.test.ts:191
LOW secret-generic-credential src/lib/validations.test.ts:148
LOW secret-generic-credential src/lib/validations.test.ts:512
LOW secret-generic-credential src/lib/validations.test.ts:523
LOW secret-generic-credential src/lib/validations.test.ts:538
LOW secret-generic-credential src/lib/validations.test.ts:548
LOW secret-generic-credential src/lib/validations.test.ts:557
LOW secret-generic-credential src/lib/validations.test.ts:567
LOW secret-generic-credential src/lib/validations.test.ts:582

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio marked this pull request as ready for review September 22, 2026 04:59
@ralyodio
ralyodio merged commit 7e3c0f1 into master Sep 22, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant