Skip to content

ADR 037 Reservation Booking Party Authority Binding

The legacy customer web carries mutable numeric user and reservation identifiers through session state, hidden fields, and controller-specific comparisons. That proves legacy behavior but cannot identify the target reservation beneficiary, booker, or payer. A browser-supplied party list or revision would let stale UI state become booking authority.

ADR-035 provides one backend-owned customer account link. P04 also has an accepted draft revision, final-review projection revision, and contract-acceptance lineage. Before this decision, those facts were not frozen with the booking row.

The browser submits no party or revision authority

Section titled “The browser submits no party or revision authority”

The public reservation-start request rejects reservationPartyAuthorityBinding, including a forged object or null. Only the trusted internal workflow-start payload can carry the closed binding after orchestration resolves it.

For the current direct-mother P04 path, the backend creates one party with mother, booker, and payer roles. It binds:

  • the exact Member Management account-link proof and profile revision;
  • the accepted contract id;
  • the accepted draft and final-review projection revisions; and
  • expected reservation revision 1 for the new booking.

This decision does not invent family-sponsored party rules. A sponsored booking must later provide its own accepted authority through the same consumer contract.

Reservation Booking owns the consumer contract

Section titled “Reservation Booking owns the consumer contract”

application/reservation_operations/features/reservation_booking owns ReservationBookingPartyAuthorityBinding. Member Management remains the owner of account and family authority. The cross-context bridge belongs to orchestration/reservation_operations/features/customer_reservation_creation.

domain/member_management/features/family_account
← application/member_management/features/customer_authenticated_session
\
orchestration bridge
/
application/reservation_operations/features/reservation_booking
← adapters/reservation_operations/features/reservation_booking

The bridge fails closed when the account proof is absent or its member differs from the accepted operational mother. Feature implementations do not import one another directly, and no global command/query folder is introduced.

Booking and authority snapshot persist atomically

Section titled “Booking and authority snapshot persist atomically”

When the command has a party binding, the Supabase adapter calls sanmopia_save_reservation_booking_result_with_party_authority. The wrapper invokes the existing booking-result RPC and inserts sanmopia_reservation_party_authority_snapshots in the same PostgreSQL transaction. Other booking commands without this P04 binding continue to call the existing RPC.

The wrapper rechecks workflow request mother/branch lineage, the booking’s actual revision, and the member-profile mapping. A stale expected revision, request drift, identity drift, or non-exact replay raises SQLSTATE 40001, so the booking, payment, and snapshot roll back together.

The snapshot is private and append-only:

  • forced RLS;
  • no anon or authenticated access;
  • service_role receives only SELECT and INSERT;
  • update and delete are rejected by an immutable trigger with 55000; and
  • exact replay returns the existing booking without another mutation.
  • P04 booking parties and expected new-booking revision now have one frozen backend source.
  • The public browser contract stays actor-free.
  • Accepted draft/review/account lineage travels through Restate’s trusted internal payload and is revalidated at the database write boundary.
  • Existing non-P04 booking commands remain compatible with the previous RPC.
  • This closes the reservation-party/revision gap. It does not close P04 legal acceptance, production-source completeness, finalized booking readiness, provider payment, or current browser evidence.

Backend 35f67ff912d32c92e4772e60895bf1da45014437 implements the application contract, orchestration bridge, trusted Restate payload, conditional Supabase adapter path, append-only snapshot migration 20260718170000_customer_booking_party_authority_binding.sql, and public-input rejection.

The repository Supabase CLI replayed the complete current migration chain in a disposable tmpfs PostgreSQL container and applied the new migration. Actual SQL acceptance proved:

  • initial save and exact replay return the same booking id;
  • replay drift raises 40001 and leaves the booking amount unchanged;
  • expected revision 2 raises 40001 and rolls back booking, payment, and authority snapshot;
  • update raises the immutable-trigger 55000;
  • persisted cardinality is booking 1, payment 1, snapshot 1; and
  • anon/authenticated cannot read or execute, while service_role can read/insert and execute but cannot update/delete.

Supabase DB lint completed with no errors in the new functions. The disposable database was removed and unused images were pruned after verification.

Focused reservation, HTTP, Restate, adapter, migration, and smoke regression reports 76 passed. The complete backend suite reports 7028 passed. Tach exact dependency/interface/external checks report zero diagnostics. Vulture at confidence 100 reports zero candidates on the changed production paths. Ruff and diff checks pass.

No new Chromium, screenshot, animated WebP, stage, production database, or online deployment evidence was created. Existing P04 visual packs remain historical relative to this backend revision.

  • 2026-07-18: accepted and implemented backend-owned reservation party and expected new-booking revision binding.