This repository was archived by the owner on Aug 12, 2026. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
feat: account deletion (barrier, teardown, tombstones) + subscription reclaim #374
Open
lourou
wants to merge
50
commits into
otr-dev
Choose a base branch
from
feature/delete-account-impl
base: otr-dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 43 commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
54d0b92
docs: add delete-my-account plan
lourou 4020335
docs(delete-account): link tombstone gate to subscription ownership r…
lourou 1971741
docs(delete-account): address review findings
lourou aeeaea1
docs(delete-account): serialize account-linked writers via parent-row…
lourou ac86f51
feat(deletion): add barrier, deletion-record, outbox, and tombstone m…
lourou 4f0fffb
feat(deletion): barrier at token mint, fail-closed requireAccount, li…
lourou f791707
feat(deletion): honor subscription tombstones in verify and store web…
lourou e9f01f4
feat(deletion): DELETE /v2/accounts/me with single-transaction teardown
lourou 9e505d1
feat(deletion): outbox drain worker and external purge executors
lourou ff1c55f
feat(claim): subscription lineage, custody escrow, and the claim endp…
lourou e56591a
test(deletion): adversarial invariants, schema guards, and spec amend…
lourou ce9179b
fix(db): make reclaim migrations additive and database-enforce money …
lourou c2e8cec
fix(subscriptions): order-identity Google accounting, atomic lineage …
lourou d6db53a
fix(deletion): co-serialize barrier with mint, fence every account ro…
lourou 9a364bc
fix(claim): fail-closed attestation flag, real pending-transfer push,…
lourou f725250
test(deletion): round-3 adversarial invariants, router fencing audit,…
lourou 3727d99
fix(claim): exact funding-event restoration, keyless claim fail-close…
lourou 2bc0935
fix(subscriptions): atomic tombstone rotation absorption, fail-closed…
lourou 2ce3974
fix(auth): lossless activity veto, exact delete-replay carve-out, fai…
lourou 5ee7214
feat(subscriptions): reclaim reconciliation sweep (quarantine drain +…
lourou 2e028a3
test(deletion): round-4 invariants — exact-key restoration, veto race…
lourou 3464e24
fix(auth): fail closed when the activity stamp cannot be written
lourou c673617
feat(subscriptions): durable reconciliation progress state
lourou 296142e
fix(claim): fail closed when restoration finds no funding-event custody
lourou 90a316c
feat(subscriptions): rework reconciliation sweep - retry state, drift…
lourou 98f4de5
test(deletion): round-5 invariants - veto fail-close, drift cursor, f…
lourou e415a82
fix(reconciliation): composite drift cursor, DB-owned commit time, ro…
lourou 53e389e
test(deletion): cover drift cursor boundaries and mint-stamp failure
lourou a302528
fix(reconciliation): durable per-lineage drift scheduling, rolling-sa…
lourou 6f3b657
test(deletion): cover drift scheduling fairness, escalation, and back…
lourou 4c4ab71
fix(reconciliation): final provider check at drift deadline and bound…
lourou 4c343ab
fix(migrations): normalize all committed transfer timestamps and free…
lourou 6226698
refactor(subscriptions): defer live transfer, Google claim proof, and…
lourou 6524bb6
test(deletion): retarget the suite at the launch scope and consolidat…
lourou 827f717
fix(deletion): harden purge executors, claim contract, and outbox dra…
lourou f4788ba
fix(deletion): close purge and fencing gaps from adversarial review
lourou 1cf9743
fix(deletion): fence outbox claim generations and multi-owner notific…
lourou 4678ba1
test(deletion): describe the replay diagnostics in current-behavior t…
lourou 90b578d
fix(deletion): bound and fence remote notification mutations across t…
lourou d0f3d85
fix(migration): canonicalize Google lineage backfill to chain roots a…
lourou 944cb5e
fix(subscriptions): keep keyless-void quarantine rows operator-owned
lourou ee946f6
fix(subscriptions): seed billing-grace claims from the status item's …
lourou d6918d4
feat(deletion): gate the endpoint by ACCOUNT_DELETION_ENABLED env var
lourou 1a9f19d
Merge remote-tracking branch 'origin/otr-dev' into feature/delete-acc…
lourou 37540e6
fix(deletion): report drain counts when only the advisory-lease close…
lourou c255695
chore(env): order deletion-section keys per dotenv-linter
lourou 45cd889
fix(deletion): silence false-positive narrowing lint on the lease-clo…
lourou 1a02af5
Merge remote-tracking branch 'origin/otr-dev' into feature/delete-acc…
lourou b735eb2
Merge remote-tracking branch 'origin/otr-dev' into feature/delete-acc…
lourou 24e65af
fix(deletion): complete posthog_person purge as an explicit skip when…
lourou File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
80 changes: 80 additions & 0 deletions
80
prisma/migrations/20260715094310_add_account_deletion/migration.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| -- Account deletion: barrier, deletion record, purge outbox, billing | ||
| -- tombstones, and the lastAuthAt activity stamp. Purely additive. | ||
|
|
||
| -- AlterTable | ||
| ALTER TABLE "Account" ADD COLUMN "lastAuthAt" TIMESTAMP(3); | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "DeletedIdentity" ( | ||
| "identityHash" TEXT NOT NULL, | ||
| "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
|
|
||
| CONSTRAINT "DeletedIdentity_pkey" PRIMARY KEY ("identityHash") | ||
| ); | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "DeletionRecord" ( | ||
| "operationId" UUID NOT NULL, | ||
| "accountRef" TEXT NOT NULL, | ||
| "status" TEXT NOT NULL DEFAULT 'purging', | ||
| "requestedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| "completedAt" TIMESTAMP(3), | ||
| "expiresAt" TIMESTAMP(3), | ||
| "updatedAt" TIMESTAMP(3) NOT NULL, | ||
|
|
||
| CONSTRAINT "DeletionRecord_pkey" PRIMARY KEY ("operationId") | ||
| ); | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "DeletionTask" ( | ||
| "id" UUID NOT NULL DEFAULT gen_random_uuid(), | ||
| "operationId" UUID NOT NULL, | ||
| "kind" TEXT NOT NULL, | ||
| "payload" JSONB NOT NULL, | ||
| "status" TEXT NOT NULL DEFAULT 'pending', | ||
| "attempts" INTEGER NOT NULL DEFAULT 0, | ||
| "nextAttemptAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| "lastError" TEXT, | ||
| "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| "updatedAt" TIMESTAMP(3) NOT NULL, | ||
| "completedAt" TIMESTAMP(3), | ||
|
|
||
| CONSTRAINT "DeletionTask_pkey" PRIMARY KEY ("id") | ||
| ); | ||
|
|
||
| -- CreateTable | ||
| CREATE TABLE "SubscriptionTombstone" ( | ||
| "id" UUID NOT NULL DEFAULT gen_random_uuid(), | ||
| "provider" "BillingProvider" NOT NULL, | ||
| "providerKey" TEXT NOT NULL, | ||
| "accountRef" TEXT NOT NULL, | ||
| "deletedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
|
|
||
| CONSTRAINT "SubscriptionTombstone_pkey" PRIMARY KEY ("id") | ||
| ); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "DeletionRecord_accountRef_idx" ON "DeletionRecord"("accountRef"); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "DeletionRecord_status_requestedAt_idx" ON "DeletionRecord"("status", "requestedAt"); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "DeletionRecord_expiresAt_idx" ON "DeletionRecord"("expiresAt"); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "DeletionTask_status_nextAttemptAt_idx" ON "DeletionTask"("status", "nextAttemptAt"); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "DeletionTask_operationId_idx" ON "DeletionTask"("operationId"); | ||
|
|
||
| -- CreateIndex | ||
| CREATE INDEX "SubscriptionTombstone_accountRef_idx" ON "SubscriptionTombstone"("accountRef"); | ||
|
|
||
| -- CreateIndex | ||
| CREATE UNIQUE INDEX "SubscriptionTombstone_provider_providerKey_key" ON "SubscriptionTombstone"("provider", "providerKey"); | ||
|
|
||
| -- Backfill: existing accounts start their activity clock at migration time. | ||
| -- A null lastAuthAt must never read as "inactive/no veto"; after this | ||
| -- backfill, null only ever means a brand-new account that has not minted yet. | ||
| UPDATE "Account" SET "lastAuthAt" = CURRENT_TIMESTAMP WHERE "lastAuthAt" IS NULL; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.