Skip to content

feat(web): creator dashboard with visibility, soft delete and restore - #162

Merged
mrgoonie merged 2 commits into
mainfrom
feat/creator-dashboard
Oct 29, 2026
Merged

mrgoonie merged 2 commits into
mainfrom
feat/creator-dashboard

Conversation

@mrgoonie

Copy link
Copy Markdown
Contributor

Part of #107.

What

A creator dashboard at /dashboard (navbar link, session only) where an owner manages what they publish:

  • Packages: every release with its state, including quarantined ones (owner only), channels and dates. Yank uses the existing state API.
  • Visibility: private, unlisted (new) and public.
    • Making a package public needs a signed-in session and approve: true. API keys get 403 visibility.approval_required.
    • Confirmation dialogs follow SX-D02: going private does not claim existing copies are deleted, and going public asks for the license/derivative check.
  • Delete: soft delete, confirmed by typing the name. Restore is possible for 30 days. After that, restore answers 410 restore_window_expired; the tombstone stays and nothing is hard-purged.
  • Personal kits: listed with their visibility shown read-only, plus delete and restore.
  • Publishing: a CLI command panel only. Session publishing stays refused on purpose (release-auth.ts). Releases are free; there is no pricing UI.

API

  • POST /api/v1/packages/:scope/:slug/visibility with {from,to,approve?}. It is a compare-and-set, so a stale from answers 409 visibility_conflict.
  • POST /api/v1/packages/:scope/:slug/delete and /restore, and the same pair for kits under /api/v1/kits/:scope/:name/.

Who may call them:

  • Only the owner may act. Non-owners get 404, the admin may delete and restore only, and scoped keys get 401.
  • Every change is audited in the append-only package_audit table.
  • Cookie requests from another origin are refused.

Deleted packages and kits are hidden from every read path, including download URLs already minted. Publishing to a deleted package answers 409 package.deleted, and reusing a deleted kit name answers 409 kit.deleted.

Migration

0022_creator_dashboard is additive. Rollback SQL is in the file header. Apply it to remote D1 before deploying, because the new code reads deleted_at on every release, library and kit query.

Known limits

  • The published CLI 0.8.0 rejects --visibility unlisted until the next CLI release. Until then, owners can switch a package to unlisted from the dashboard.
  • Un-yank stays admin-only. Kit visibility changes are not part of this PR.

Tests

  • pnpm typecheck passes.
  • pnpm exec vitest run: 149 files, 2773 passed, 3 skipped. This includes 42 new tests under apps/web/tests/creator/.

🤖 Generated with Claude Code

mrgoonie and others added 2 commits October 30, 2026 01:44
…tore

Owners get /dashboard listing their packages, release history (including
quarantined releases), personal kits, and actions: change visibility
(private/unlisted/public, public needs session approval), yank, soft delete
with a 30-day restore window, and restore. Publishing stays CLI-only.

- contracts: add the unlisted visibility; only private is protected
- migration 0022: deleted_at on packages and personal_kits, append-only
  package_audit table
- deleted packages and kits are hidden from every read path; publishing to
  a deleted package answers 409 package.deleted, reusing a deleted kit name
  answers 409 kit.deleted
- POST /api/v1/packages/:scope/:slug/{visibility,delete,restore} and kit
  delete/restore, owner or admin only, audited, same-origin checked

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… owner-proof

Unlisted packages are readable anonymously by name, so moving a package out
of private now needs a signed-in web session and approve: true, like a change
to public; the dashboard shows the same two-step approval for it.

An owner can no longer restore a package or kit the admin deleted: restore
reads the latest delete in package_audit and refuses with 403
restore.admin_deleted, re-checked inside the guarded batch. Release state
changes and promotions also re-check that the package is not deleted, and
the delete dialog says new requests stop being served instead of implying
existing copies disappear.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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