Summary#
- POST /v1/handles: New endpoint for initial handle creation on promoted accounts. Validates handle format
(
<name>.<available_domain>), enforces uniqueness (409), optionally calls aDnsProviderif configured (dns_status: "propagating"), and inserts into thehandlestable. - V009 migration: Rebuilds
sessionstable with nullabledevice_id(devices are deleted at DID promotion) and addstoken_hash UNIQUEcolumn for Bearer token authentication. - Session auth from POST /v1/dids: MM-90's promotion transaction now generates a session token and returns it in the response
(
session_tokenfield), replacing the shortcut handle insertion. Clients use this token to authenticate the subsequentPOST /v1/handlescall. - DnsProvider trait (
dns.rs): Object-safe async abstraction (Pin<Box<dyn Future>>).AppStatecarriesOption<Arc<dyn DnsProvider>>, alwaysNonefor v0.1 — MM-142 wires in real provider implementations. - New error codes:
HandleAlreadyExists(409),DnsError(502).
Design decisions#
- Handle insertion removed from MM-90 (it was a shortcut bypassing format validation and DNS).
POST /v1/handlesis now the canonical path. DnsProvidertrait is v0.1-ready (no implementations yet); MM-142 adds Cloudflare/Route53 without changing the handler.- Session token uses the same SHA-256 hex storage pattern as
pending_sessions.
Test plan#
-
cargo test— 201 tests pass, 0 failures -
POST /v1/didsresponse now includessession_token(non-empty base64url string) -
POST /v1/handleswith valid session token + valid handle → 200,dns_status: "not_configured", handle row in DB -
POST /v1/handlesduplicate handle → 409HANDLE_ALREADY_EXISTS -
POST /v1/handlesinvalid format (no dot, wrong domain, leading hyphen) → 400INVALID_HANDLE -
POST /v1/handlesmissing/expired session token → 401UNAUTHORIZED -
POST /v1/handlesaccount_id mismatch → 401UNAUTHORIZED