Summary#
- Adds
POST /v1/accounts— operator-authenticated endpoint that provisions a pending account slot with a 24h claim code, before any DID is assigned - V005 migration introduces
pending_accountsstaging table; email and handle uniqueness is enforced across both pending and active (accounts) tables - Three new
ErrorCodevariants:AccountExists(409),HandleTaken(409),InvalidHandle(400)
What's included#
V005__pending_accounts.sql—pending_accounts(id, email, handle, tier, claim_code FK→claim_codes, created_at)with unique indices on email and handleroutes/create_account.rs— handler + 26 tests covering happy path, DB persistence, duplicate email/handle (both tables), handle format validation, tier validation, missing fields, auth, and DB error pathbruno/create_account.bru— Bruno collection entryuuidv1 workspace dep for UUIDv4account_idgeneration
Design notes#
pending_accountsis a staging area: no DID is assigned yet. A future wave handler will promote a row toaccountsafter device binding.- Handle validation is intentionally minimal (non-empty, ASCII, no whitespace, ≤253 chars) — ATProto handle/domain policy is deferred to a later wave to avoid incorrect rejections.
- Both the
claim_codesinsert and thepending_accountsinsert happen in one transaction, preventing orphaned codes.
Test plan#
-
cargo test— 112 tests, all passing -
cargo clippy --workspace -- -D warnings— clean - Manually test via Bruno:
POST /v1/accountswith valid payload returns 201 withaccountId,claimCode,did: null,status: "pending" - Verify duplicate email returns 409
- Verify invalid handle (e.g. empty string) returns 400