Skip to content

Add DELETE /developers/me for self-service profile deletion - #158

Merged
admdly merged 2 commits into
mainfrom
feat/developer-profile-deletion
Jul 26, 2026
Merged

Add DELETE /developers/me for self-service profile deletion#158
admdly merged 2 commits into
mainfrom
feat/developer-profile-deletion

Conversation

@admdly

@admdly admdly commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds DELETE /extensions/v2/developers/me, letting a developer permanently delete their own publisher profile — part of a privacy-focused account-deletion flow being added on the extensions site.
  • Refuses (409, CONFLICT) while the profile still has published extensions or a pending submission; 404s (NOT_FOUND) if the caller has no profile. Error codes match the rest of v2's convention (generic code + a specific message), rather than introducing resource-specific codes.
  • On success, deletes any transfer token and claims for the profile, then the profile row itself, in a single batch. developer_history rows are deliberately left alone — it's an append-only, moderator-only audit log that's never rendered publicly.

Lets a developer permanently delete their own publisher profile, for
the privacy-focused account-deletion flow being added on the
extensions site. Refuses (409) while the profile still has published
extensions or a pending submission, 404s (developer_not_found) if the
caller has no profile, and otherwise deletes any transfer token and
claims for it before deleting the profile row itself. developer_history
rows are deliberately kept — it's an append-only, moderator-only audit
log that's never rendered publicly.

Keeping history required a schema change: developer_history.developer_id
had a hard FK to developers(id) with no ON DELETE action, and D1
enforces foreign keys, so hard-deleting a developers row with any
history (i.e. every developer, since every write logs one) failed
outright — confirmed empirically against local D1 before writing the
fix. 0009 rebuilds developer_history without that FK (SQLite can't
ALTER one away), preserving existing rows and the append-only triggers.

Claude-Session: https://claude.ai/code/session_01Co1bu2gU5kEHN65KooNUHN
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 26, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
api 41c5f89 Commit Preview URL

Branch Preview URL
Jul 26 2026, 07:49 PM

@admdly admdly self-assigned this Jul 26, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/services/extensions/v2/developers-database.ts Outdated
Comment thread src/services/extensions/v2/developers-database.ts Outdated
- P0: deleteOwn() authenticated ownership only in its initial lookup,
  then deleted by id alone — a transfer/claim landing in between could
  move the profile to someone else, and the original caller's delete
  would still go through and remove it out from under the new owner.
  Fixed by re-checking owner_user_id in the delete's own WHERE clause,
  atomically, rather than trusting the earlier read.
- P1: the extensions/pending-submission counts were checked separately
  from the delete, so either could appear in between and slip through.
  Fixed by folding both checks into the same guarded DELETE (via
  correlated NOT EXISTS subqueries) instead of a separate check-then-act
  step — there's no window left for anything to appear in.

Both guards are repeated identically across all three deletes (transfer
tokens, claims, the profile row) so they stay all-or-nothing: if the
guard fails, nothing in the batch is touched, rather than transfers/
claims being deleted while the profile deletion itself gets blocked.
Verified the guarded SQL directly against local D1 (eligible case
deletes correctly; ownership-changed case leaves all three rows
untouched) before wiring it into deleteOwn(). Added a regression test
simulating the ownership-race window via a new mock-only seam.

Claude-Session: https://claude.ai/code/session_01Co1bu2gU5kEHN65KooNUHN

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0 issues found across 3 files (changes from recent commits).

Auto-approved: Adds a self-service DELETE endpoint for developer profile deletion, with proper guards against conflicts. Migration drops FK to keep audit history; tests cover success and error paths.

Re-trigger cubic

@admdly
admdly merged commit 42bd553 into main Jul 26, 2026
9 checks passed
@admdly
admdly deleted the feat/developer-profile-deletion branch July 26, 2026 19:54
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