docs release evidence p13 t03b provider links - AlexandreZanata/Abastevo GitHub Wiki
Status: LOCAL_DONE on codex/phase-13-free-accounts (phase PR #27,
draft). Issue: #24 (slice 2 of 3; slice plan in
p13-t03a-oidc-verifier). No endpoints,
no OpenAPI paths yet (T03C).
-
db/migrations/000021_provider_links.sql(append-only):account_provider_links(PK(account_id, provider), UNIQUE(provider, subject), provider CHECK google/apple, non-empty issuer/subject) +account_oidc_nonces(PK nonce). Subjects only; email is display/relay, never a merge key. -
db/queries/account/accounts.sql+sqlc.yamlstanza (adds000021) + committed regeneration (sqlc vet/generateclean, stable):GetAccountByID,FindProviderOwner,Get/List,Insert/Update/DeleteProviderLink,CountAddressesByAccount,InsertNonce(ON CONFLICT DO NOTHING RETURNING). -
account/domain:ProviderLink+ValidProvider(account.go);ErrLastLoginMethod(link-last-method-refused),ErrProviderNotLinked(link-provider-not-linked),ErrAccountNotFound(account-unknown) + verdict mapping (ports.go,stdlib_test.goextended). -
account/application:Storeextended (link/unlink/list/owner/ address-count/nonce);links.goLinkProvider(verified token is the only proof; email never consulted),UnlinkProvider(atomic last-method guard),ListProviders;MemStoreparity (mutex single-step, cross-account refusal, same-account converge/ rotation, bare-account support viaaccountsByID). -
account/adapters:PGStorelink/unlink/list/owner/count/nonce (transactionalFOR UPDATE-free serial lanes: owner check, then insert/update; unique-race maps to cross-account; unlink counts providers + addresses atomically);PGNoncesDB ledger implementing the OIDCNonceStore(PK admits once, errors fail closed). - Tests:
application/links_test.go(7 suites: both-provider happy, cross-account, nonce replay + mismatch, last-method with email-remaining vs bare-account refusal, email-only never merges, rotation refusal, ledger single-use);adapters/ pglinks_integration_test.go(integrationtag, fresh DB per test,000020+000021asserted): happy both providers, cross-account, bare-account last-method, nonce replay across two verifiers sharing one DB ledger, rotation against DB nonces.
- RED proven by dropping the
bySubjectcross-account guard inMemStore.LinkProvider:TestLinkCrossAccountRefusedfails withgot <nil>+verdict "ok"and persists a second binding; GREEN on restore (unit pass). - No transport changes:
adapters/httpuntouched; OpenAPI paths stay T03C.
cd backend && sqlc vet && sqlc generate
gofmt -l internal/modules/account db/queries/account
GOTOOLCHAIN=go1.27.1 go vet ./internal/modules/account/...
GOTOOLCHAIN=go1.27.1 go test -count=1 ./internal/modules/account/...
export ANPFUEL_TEST_DATABASE_URL=postgres://anpfuel:[email protected]:5434/anpfuel?sslmode=disable
GOTOOLCHAIN=go1.27.1 go test -count=1 -race -tags=integration ./internal/modules/account/...
make quick-verify
git diff --checkOutcome: unit 6/6 packages green; integration (real disposable
PostGIS, fresh DB per test) green under -race — adapters 5/5 link
suites + 6/6 email suites, application/domain/oidc/http green;
sqlc clean + stable; gofmt/vet clean; quick-verify
selection=full ok 10s; diff --check clean; secrets scan clean.
- No link/unlink HTTP transport or OpenAPI paths (T03C); no live Google/Apple contact anywhere — sandbox evidence lands in T03C against stubs, live-provider runs stay outstanding to P13-T05/G13 device acceptance.
- Suspension/erasure enforcement is P13-T04; links persist now.
- Nonce ledger has no TTL purge yet (retention follows T04 inventory).
Append-only migration stays (never rewrite applied history); code
rollback = delete links.go, pgnonces.go, link tests, provider
methods + 000021 stanza rows (DB tables stay inert until T03C).
P13-T03C link/unlink transport + OpenAPI + sandbox evidence (#24, same branch).