Skip to content

ADR 035 Customer Authenticated Session and Account-Link Proof

The legacy customer web restores login from CodeIgniter session keys and a long-lived encrypted AUTH_TOKEN cookie, then compares USER_ID_PK with mutable reservation rows inside booking, service-balance, and payment controllers. That behavior is source evidence, not a target authority model. Copying it would make cookie state, numeric database identifiers, and controller-specific ownership checks competing sources of truth.

ADR-034 makes Supabase Auth the native identity owner and Member Management the mother-profile owner. Reservation creation and booking still need one explicit, reusable proof that the verified bearer subject maps to the active mother and member records being used by the workflow. Without that proof, each adapter can reconstruct a different actor from mutable rows.

Resolve the session once through Member Management

Section titled “Resolve the session once through Member Management”

application/member_management/features/customer_authenticated_session owns CustomerAuthenticatedSessionProjection. Its query handler accepts only an already verified Supabase Auth subject and resolves a CustomerAccountLinkProof through a port. The projection contains the authenticated subject, mother account/profile identity, member profile/member identity, and profile revision required by downstream orchestration.

The bearer token remains transport input. It is verified by the existing HTTP Auth boundary and is never persisted in this projection, command fingerprint, audit, log, or browser evidence. The browser cannot submit internal profile, member, role, account, or revision identifiers as actor authority.

Section titled “Keep account-link proof backend-owned and fail closed”

The Supabase adapter reads one exact account link through sanmopia_get_customer_account_link_proof(text). The database function:

  1. joins the authenticated subject to exactly one mother profile and member profile;
  2. requires a complete profile and an active or authorization-pending account with an applied authorization relationship receipt;
  3. returns a closed six-field proof including the profile revision;
  4. denies anon and authenticated execution and grants only service_role; and
  5. rejects withdrawn or privacy-lifecycle accounts.

Missing, ambiguous, stale, cross-member, or privacy-ineligible rows are authority failures. No adapter may fall back to a cookie, caller-supplied member id, role, hidden field, Korean status string, or the first matching row.

Compose cross-context consumers in orchestration

Section titled “Compose cross-context consumers in orchestration”

Reservation Operations does not import the Member Management adapter directly. orchestration/reservation_operations/features/customer_reservation_creation contains the bridge from the session projection to the existing reservation actor contract. Booking identity resolution consumes the same account-link proof port and rejects a member profile whose member_id differs from the proof.

This is a Layer-first boundary:

application/member_management/features/customer_authenticated_session
← adapters/member_management/features/customer_authenticated_session
← orchestration/reservation_operations/features/customer_reservation_creation

CQRS is feature-local. This read-only feature has queries/ and no empty commands/ directory.

Do not overclaim booking and payment completion

Section titled “Do not overclaim booking and payment completion”

The payment pre-registration boundary resolves a typed PaymentActorContext from the same account-link proof. ADR-036 now supplies the durable CustomerSessionRecoveryAuditEvent. ADR-037 now freezes the resolved reservation parties, accepted review lineage, and expected new-booking revision with the booking transaction. Frontend session recovery against the new audit runtime, provider payment, and production deployment are not proved by these backend increments.

  • One Member Management feature is the SSOT for authenticated customer account-link resolution.
  • P04 and booking reuse the same proof instead of rebuilding ownership in each adapter.
  • Direct feature-to-feature implementation imports remain forbidden; the cross-context bridge stays in orchestration.
  • Any future payment consumer must use an explicit application contract and cannot infer actor authority from reservation rows.
  • P04 remains RED/partial until its separate legal, production-source, finalized-booking, readiness, and current browser gates close.

Backend 01ce8a5742691118cebeb9b2c2d1cf92fb7e1639 implements the application query, Supabase adapter, reservation orchestration bridge, booking identity reuse, migration 20260718162556_customer_account_link_proof.sql, and Tach declarations.

A disposable database was advanced through the complete current migration chain with the repository-owned Supabase CLI. The service-role RPC returned the exact closed proof for fake test-owned rows; grant inspection returned anon=false, authenticated=false, and service_role=true; changing the account to withdrawal_pending failed closed with SQLSTATE 42501. The container, image attempt, temporary build file, and Tach cache were removed after verification.

Backend b699f9b1376a0369f67fb8734c9e97416b41a575 adds the typed PaymentActorContext. It carries the mother account, mother profile, member profile, member, and profile revision from the exact account-link proof. Direct mother payment no longer needs a mutable generic member_role row. Family and operator payment paths also fail closed when the obligation’s mother account is inactive. The immutable payment actor snapshot retains account/profile/revision lineage in authority_evidence.

The resolver moved from adapters/member_management/features/family_account to the owning adapters/pricing_settlement/features/payment slice. It consumes Member Management only through the account-link proof and family-account application contracts. No schema migration was added for this increment.

The true full backend suite with the Tach cache disabled reports 6997 passed. Tach MCP’s cache-disabled affected suite reports 6696 passed / 279 deselected; exact dependency/interface/external gates report zero diagnostics and the architecture suite reports 13 passed. Vulture at confidence 100 reports six Pydantic-validator or Protocol-parameter false positives, all retained after live-reference verification. No new Chromium, screenshot, animated WebP, stage, or production deployment evidence was produced by this backend-only increment.

Backend 7e2b86db9d21c8d483957f0888620b06b1eb03ad closes the customer-session recovery-audit gap through ADR-036. Backend 35f67ff912d32c92e4772e60895bf1da45014437 closes the remaining reservation-party/expected-revision gap through ADR-037. This ADR’s scoped account-link consumers are now implemented; P04 remains RED for its separate legal, source-completeness, readiness, and browser gates.

  • 2026-07-18: accepted the backend-owned customer session and account-link proof; payment, recovery-audit, and frozen reservation-party/revision binding were initially open.
  • 2026-07-18: bound typed payment actor context and immutable payment lineage to the account-link proof; recovery audit and reservation-party/revision binding remain open.
  • 2026-07-18: ADR-036 implemented the durable recovery audit; frozen reservation-party/expected-revision binding remains open.
  • 2026-07-18: ADR-037 froze reservation parties and expected new-booking revision in the booking transaction; the scoped ADR-035 implementation moved to implemented.