Files
NianAIGC/.project-docs/30-worklog/tasks/20260813-go-identity-vertical-c4e91a72.md
T

8.5 KiB

Task: Implement Go identity authorization vertical slice

Identity

  • Task ID: 20260813-go-identity-vertical-c4e91a72
  • Mode: Feature
  • Branch: codex/20260813-go-identity-vertical-c4e91a72-go-identity-vertical
  • Worktree: /Users/brother7/Documents/AI/NianAIGC-go-identity-c4e91a72
  • Base commit: 716a8031b1
  • Owner: codex
  • Status: Ready for Integration

Scope

  • Add a language-neutral platform-session authorization matrix that fixes the per-request account, organization, role, client, and sessionVersion contract shared by TypeScript and Go.
  • Add a deep Go Identity Module whose external seam resolves a signed legacy Cookie into a database-refreshed current session or a typed unauthenticated rejection.
  • Add a PostgreSQL Adapter that loads the complete authorization snapshot in one parameterized account/organization query.
  • Keep login, password changes, HTTP identity routes, middleware replacement, Docker/ACK manifests, and production traffic ownership outside this slice.

Intent And Constraints

  • Follow vertical red-green TDD at the existing signed-session/Identity seam and PostgreSQL Adapter seam.
  • Treat Cookie data only as authenticated input; database account role, profile, status, organization state, and session version are authoritative for every resolved request.
  • Preserve current legacy compatibility where an absent or zero sessionVersion is accepted, while any nonzero mismatch is rejected; the refreshed result always carries the current database version.
  • Require every non-super-admin account to belong to an active existing organization; allow an unbound super-admin as the current billing/administration model requires.
  • Collapse authentication denials for callers while retaining typed internal rejection reasons for tests and diagnostics; propagate database failures separately.
  • Do not expose or route a Go identity endpoint and do not change ACK-001 production behavior in this task.

Outcome

  • Added contracts/auth/platform-session-authorization-v1.json, a language-neutral 14-case matrix covering database-authoritative claim refresh, platform-client enforcement, active/disabled accounts, exact platform roles, legacy missing/zero sessionVersion, nonzero version mismatch, rejection precedence, organization requirements, and super-admin organization compatibility.
  • Added the Go Identity Resolver as one deep external seam from a signed legacy Cookie to a database-refreshed Session. Authentication denials collapse through ErrUnauthenticated while retaining stable internal rejection reasons; persistence failures remain distinct and propagate to the caller.
  • Added a Go PostgreSQL authorization-snapshot Adapter that implements the Resolver's single persistence Interface with one explicit-column, parameterized LEFT JOIN over public.platform_users and public.platform_organizations. It deliberately returns disabled/missing organization state to the Identity Module instead of hiding policy in SQL.
  • Added the equivalent TypeScript authorization seam and PostgreSQL snapshot store, then changed getOptionalAuthSession to use them. PostgreSQL request revalidation now uses one joined query rather than separate account and organization reads; the local development path projects the same narrow snapshot without exposing password storage fields.
  • Closed the existing authorization gap that accepted non-super-admin accounts with no organization. All non-super-admin accounts now require a matching, active organization; an unbound super-admin remains valid.
  • Kept login, password changes, Middleware, Go identity HTTP routes, Docker/ACK manifests, Ingress paths, and production traffic ownership unchanged. The Go Resolver is implemented and tested but remains intentionally unrouted.

Verification

  • Vertical TDD RED evidence was captured independently before the Go Resolver, Go PostgreSQL Adapter, TypeScript authorization seam, and TypeScript snapshot store implementations existed. Intermediate RED assertions also exposed missing organization-admin claim reconstruction and local snapshot leakage before those paths reached GREEN.
  • npm test -- --reporter=dot: 36 test files and 135 tests passed, including both consumers of the shared authorization matrix and the PostgreSQL/local snapshot-store contract.
  • npx tsc --noEmit --incremental false: passed.
  • npm run build: Next.js 15.5.18 production build completed for all current routes; the pre-existing multiple-lockfile workspace-root warning remains.
  • npm run go:test: all five Go packages passed.
  • npm run go:vet: passed.
  • npm run go:build: built cmd/zhinian-api successfully through the repository's cross-platform runner.
  • npm run deploy:check: all 8 ACK manifest assertions passed, confirming that production routing and workload ownership were not changed.
  • git diff --check and gofmt -d over all changed Go files: passed with no output.
  • The independent Sol review found one cross-language composite-failure ordering mismatch. A fixture case was strengthened to combine an unknown database role with a nonzero version mismatch, producing the expected TypeScript RED (invalid_role versus session_version_mismatch); TypeScript was then aligned with Go so version mismatch has stable precedence. A second review caught that this temporarily removed standalone invalid_role coverage, so a redundant standalone version-mismatch case was converted to preserve both reasons while retaining all organization cases and the 14-case total. Both focused contracts and all verification above passed again.

Follow-ups

  • Add the first Go current-user/authentication HTTP Adapter only after its response, 401/403/500 mapping, Cookie transport, and black-box parity contracts are frozen; this task does not claim /api/auth/me or another identity path.
  • Move or duplicate database-refreshed authorization at the routing boundary before any protected route cutover. The current Next.js Middleware still performs signed-Cookie-only gating, while server Route Handlers perform the authoritative database refresh.
  • Add a Go local-development authorization snapshot Adapter before expecting the unrouted Go process to serve identity flows with ZHINIAN_DATA_BACKEND=local.
  • Exercise the joined identity query against the production-like RDS role, verified-CA TLS, schema privileges, disabled accounts, deleted organizations, and concurrent account mutations before cutover.
  • Migrate login/logout/password and lockout mutation flows as separate vertical slices so session-version invalidation and single-writer ownership can be reviewed independently.

Promotion Candidates

  • Target: .project-docs/30-worklog/current-state.md, .project-docs/20-architecture/module-map.md, and .project-docs/20-architecture/data-flow.md. Proposal: after integration, record the implemented but unrouted Go Identity Resolver, its single PostgreSQL authorization-snapshot seam, and the shared TypeScript/Go authorization contract. Evidence: the 14-case shared fixture, both language implementations, exact joined-query tests, and complete Node/Go/build/ACK verification in this task. Future impact: later HTTP slices can consume one current-session result instead of reimplementing Cookie parsing, account/organization lookup order, or role/session-version rules. Semantic conflicts: canonical documents still describe the Go backend as a foundation with no identity authorization slice; they should change only when this feature is integrated. ACK-001 and Next.js route ownership remain unchanged. Human confirmation required: no new architecture direction is required; promotion still belongs to the serialized Integration Gate.

  • Target: .project-docs/40-domain/business-rules.md. Proposal: record that every active non-super-admin platform account must reference the same active organization returned by the authorization snapshot, while a super-admin may be unbound; missing/zero legacy session versions are temporarily accepted and refreshed, while nonzero mismatches revoke the session. Evidence: the shared authorization matrix and both TypeScript/Go Resolver contract suites. Future impact: account deletion, organization archival, role changes, session invalidation, and future authorization Adapters must preserve this rule. Semantic conflicts: this deliberately closes a prior TypeScript conditional gap and aligns runtime authorization with the existing account mutation/domain constraints. Human confirmation required: no; the task scope explicitly selected this security rule and no production route ownership changed.