Aller au contenu

Story AUTH-008: BYO-DB readiness — cross-DB agency-scope write validation

Module: identity Slice: arch §0.1 AUTH-004 (BYO branch) + arch §4.3 (agency scope validation) Side: [BACKEND] Version target: V0 — v0.0.4 Priority: 8 Depends on: AUTH-003; TENANT TenantAwareDataSourceResolver BYO branch (anchor D2) Can develop concurrently with: AUTH-009 Merge order: After AUTH-003 Estimated complexity: S PRD User Stories: AUTH-OP-09 (role/scope), R-ADM-009 / AUTH-TV-07 (cross-DB agency-scope integrity) Wireframe: N/A — backend only


Objective

v0.0.4 introduces BYO-DB tenants (enterprise customers who host their business data in their own PostgreSQL). AUTH itself does NOT move — all auth tables stay on the platform DB (ADR-AUTH-01). What AUTH must prove here is that when an operator's agency_scope is set, each agency UUID is validated against the correct database (the tenant's own DB if BYO, the shared DB otherwise) via TenantConfigService, and that AUTH's own auth queries keep working unchanged on the platform DB regardless of the tenant's DB profile.


Backend Scope

Entities

Reads users.agency_scope. No new tables. No AUTH table moves to BYO (ADR-AUTH-01).

Service Layer

  • Agency-scope write validation (R-ADM-009 / AUTH-TV-07, arch §4.3): when agency_scope is assigned or modified for an OPERATOR, resolve each agency UUID through TenantConfigService.resolveAgency(tenantId, agencyId). This call transparently routes to the tenant's BYO DB or the shared tenant DB through the TenantAwareDataSourceResolver. Reject any UUID that does not exist or whose status != ACTIVEInvalidAgencyScopeException (HTTP 422).
  • Write-time only: AUTH does NOT re-validate agency_scope on each token refresh in V1 (AUTH-TV-07).
  • Confirm AUTH's own reads/writes (login, signed-link verify, user lookup) always use platformJdbcClient and are unaffected by the tenant's DB profile (arch §4.2).

API Endpoints

None new. This validation runs inside the user create/edit path (the operator user-management API is V1; in v0.0.4 the validation primitive must exist and be exercised by the bootstrap/admin path that sets scope).

Validation Rules

  • Every agency UUID in a scope assignment must exist AND be ACTIVE in the resolving tenant DB.
  • Validation occurs at write time; not on refresh.
  • A disabled agency already present in a scope array is NOT mutated by AUTH (R-OP-018 handled elsewhere); this story only validates new/changed assignments.

Multi-Tenant Considerations

This is the core of the story. agency_scope (on the platform-DB users row) references agency.id which lives in the tenant DB (shared or BYO). There is no DDL FK across DBs (arch §2.1); integrity is enforced here at the application layer. The validation must produce the same outcome for a shared-DB tenant and a BYO-DB tenant — the only difference is which datasource TenantConfigService routes to. AUTH stays on the platform DB throughout.

Audit & Logging

  • operator_role_changed (when scope changes accompany a role/scope edit) — target_user_id, old_agency_scope, new_agency_scope (this event is fully exercised in the V1 user-management story; in v0.0.4 only the validation primitive is required).

Frontend Scope

N/A — backend only.

UI States (ALL REQUIRED)

N/A — backend only.


Acceptance Criteria

AC-001: Unknown or inactive agency UUID is rejected
Given a BYO-DB tenant
When an agency_scope assignment references a UUID that does not exist or whose status != ACTIVE in the tenant's DB
Then the write is rejected with 422 InvalidAgencyScope
AC-002: Valid agency UUID is accepted on both DB profiles
Given a valid ACTIVE agency UUID
When agency_scope is assigned for an OPERATOR
Then the write succeeds for a shared-DB tenant AND for a BYO-DB tenant (TenantConfigService routes to the correct DB)
AC-003: AUTH auth queries stay on the platform DB
Given a BYO-DB tenant
When the operator logs in and a signed link is verified
Then all AUTH reads/writes use the platform datasource (no BYO routing for auth primitives)
And login + verification behave identically to a shared-DB tenant

Compliance Rules

  • No new compliance article. Data-separation posture (auth data under platform custody) supports the DPA positioning (ADR-AUTH-01).

Standards & Conventions

  • docs/standards/multi-datasource.md (TenantAwareDataSourceResolver, routing).
  • docs/standards/multi-tenant-model.md (DB profile taxonomy SHARED / BYO).
  • docs/standards/java-spring-guidelines.md, docs/standards/critical-rules.md (tenant isolation).

Testing Requirements

Unit Tests

  • InvalidAgencyScopeException thrown for unknown / inactive agency UUID.
  • Validation is write-time only (no call on token refresh).

Integration Tests

  • Two-profile test: same scope assignment validated against a shared-DB tenant and a BYO-DB tenant (Testcontainers second Postgres for BYO), both behaving correctly.
  • Login + signed-link verify for a BYO-DB tenant use only the platform datasource (assert no BYO query on the auth hot path).

What QA Will Validate

  • Agency-scope assignments are validated against the right DB; bad UUIDs are rejected; auth itself never touches the BYO DB; behaviour is identical across DB profiles.

Out of Scope

  • The full operator user-management UI (invite / role edit / deactivate) — V1 (AUTH-ADM-01/02, AUTH-OP-07).
  • Moving any AUTH table to a BYO DB — never (ADR-AUTH-01).
  • Tenant SHARED→BYO migration — V2.
  • The TenantAwareDataSourceResolver BYO branch itself — owned by the TENANT module (anchor D2); this story consumes it.

Definition of Done

  • [ ] Agency-scope write validation rejects unknown/inactive UUIDs (422)
  • [ ] Validation works identically for shared-DB and BYO-DB tenants
  • [ ] AUTH auth queries remain on the platform datasource for BYO tenants
  • [ ] Validation is write-time only (not on refresh)
  • [ ] Unit + integration tests written and passing (both DB profiles)
  • [ ] Tenant isolation verified (platform DB for auth; cross-DB validation via TenantConfigService)
  • [ ] No silent failures on TenantConfigService routing errors