docs release evidence p13 t02b pgstore - AlexandreZanata/Abastevo GitHub Wiki
P13-T02B — Postgres store + migration + real-DB integration
Status: LOCAL_DONE on codex/phase-13-free-accounts (phase PR #27,
draft). Issue: #23 (slice 2 of 3; slice plan in
p13-t02a-account-service). No endpoints,
no mail delivery yet (T02C).
What changed
db/migrations/000020_accounts.sql(append-only):accounts,account_addresses,account_email_codes,account_session_familieswith status CHECK, alias uniqueness and address/issued/account indexes. Hashes and salts only; codes/tokens never persist.db/queries/account/accounts.sql+sqlc.yamlstanza (owner-scoped schema list) + committed generated package (sqlc vet/generateclean, re-generate stable, no drift in other packages).account/adapters/pgstore.go—PGStoreimplementing the applicationStore: generated queries for CRUD, one transaction withFOR UPDATErow locks for consume/rotate. Consume matches by hash across the address rows (newest-first, stable id tiebreak); rotation is compare-and-swap on the verified refresh hash plus revoked check.Storeinterface + both stores hardened (T02A follow-up inside this slice):TryConsumenow takes the plaintext code + hasher and matches across rows;Rotatetakes the expected hash (CAS);CreateAccountreportsErrAddressLinkedso parallel signups log into the winner.domain.EqualHashshared by both paths; memstore updated identically.- Integration
pgstore_integration_test.go(integrationtag, fresh database per test, migration000020asserted): round trip, 16-way concurrent consume (exactly one), expiry/attempts/enumeration/ quota, refresh reuse→revoke + 30-day expiry, replay-superseded, and parallel signup linking one account.
Bug found and fixed in-task
Same-second issuance made ORDER BY issued_at DESC nondeterministic:
the service salted with the wrong row and Postgres picked either sibling.
Fixed by hash-match-first with deterministic fallback in both stores
(plus two regression tests); the memstore parity gap closed the same way.
Validation (exact commands, this host)
docker compose -f infra/compose.dev.yml up -d db
cd backend && sqlc vet && sqlc generate
gofmt -l ./... && go vet ./internal/modules/account/...
go test -count=1 ./internal/modules/account/...
go test -count=1 -race -tags=integration ./internal/modules/account/...
make quick-verify
git diff --check
Outcome: unit suites pass; integration (real disposable PostGIS,
fresh DB per test) passes under -race — adapters 6/6, application
and domain green; sqlc clean + stable; gofmt/vet clean;
quick-verify ok; diff --check clean; secrets scan clean.
Limits (not claimed)
- HTTP transport, route wiring, mail delivery and OpenAPI paths are T02C. SMTP stays out (local deterministic adapter only, per A02).
- Concurrent same-address signup resolves to one account via
ErrAddressLinkedretry-as-login; cross-family races fail closed.
Rollback
Append-only migration stays (never rewrite applied history); disabling
is a forward DROP-free no-op since nothing else reads these tables.
Code rollback = delete the account module + stanza + queries.
Next
P13-T02C transport + mail + redaction + paths (#23, same branch). Then P13-T03 provider verification (#24).