ADR 020 Reservation Payment Obligation And Actor Snapshot
Context
Section titled “Context”Legacy payment pages supplied reservation identifiers, payment kinds, methods, amounts, and mutable status facts. The previous migration path also completed a reservation and payment inside booking, before a provider-confirmed payment existed. Current family grants could prove access but could not identify who historically initiated a payment after a grant changed or was revoked.
Decision
Section titled “Decision”Booking creates three distinct facts:
- a
scheduledreservation; - an immutable finalized charge snapshot; and
- a
waitingreservation payment obligation bound to a payment product plan.
POST /reservation-payment-pre-registrations accepts only paymentId in the
body. Supabase bearer identity supplies the actor and Idempotency-Key supplies
replay identity. The backend loads booking, method, purpose, product plan, and
amount from the waiting obligation. Browser-supplied financial facts are not
accepted.
Before Kill Bill handoff, the backend resolves authority from:
- the authenticated Supabase member profile;
- SpiceDB
pay_pre_reservationor finance-operator capability; and - for a family payer, the active reservation-scoped
PaymentDelegation, exact payment scope, consumed revision, effective interval, and amount ceiling.
The accepted decision becomes one immutable ReservationPaymentActorSnapshot.
It freezes actor and mother identities, actor kind, branch, delegation facts,
payment purpose, product plan, amount, authority evidence, authorization time,
and idempotency key. A service-role-only Supabase RPC validates current backend
facts and atomically links that snapshot to the payment obligation. Snapshot
rows cannot be updated or normally deleted. Mutable payment/delegation rows do
not own the snapshot through reverse foreign keys; historical evidence remains
independent after delegation cleanup or revocation.
Kill Bill receives only the payment id and backend-owned amount. Provider success is still a later payment workflow event; pre-registration does not mark the obligation paid and does not complete the reservation.
CQRS Boundary
Section titled “CQRS Boundary”The command side authorizes and freezes one obligation. Query-side payment and settlement projections render the frozen result. Frontend code may display the returned amount, fee snapshot, and actor kind but cannot derive or override them.
Runtime Evidence
Section titled “Runtime Evidence”On 2026-07-11 the bounded stage command
pnpm supabase:smoke:stage:reservation-to-settlement-completion passed without
Playwright. Reservation 92961f7e-7896-4441-af53-8fb8825d6fe2 proved:
- scheduled booking plus waiting payment obligation;
- caregiver denial before delegated authorization;
- family grant/replay, SpiceDB convergence, exact amount ceiling, and immutable
actor snapshot
da2c3402-0d85-52a2-b6b4-bcf7f6c189bf; - pre-registration replay and conflicting-idempotency rejection;
- grant revocation and cleanup without loss of historical actor evidence;
- paid-payment workflow, service delivery, caregiver payout instruction,
branch settlement, headquarters settlement, and final
settledstate.
Pinned implementation:
- Backend payment authority and stage proof
- Public payment contract
- Pre-registration application slice
- Supabase actor snapshot migration
- Bounded reservation-to-settlement smoke
Known Gaps
Section titled “Known Gaps”- The runtime proof covers the customer-share deposit plan. Balance, pre-reservation conversion, change adjustment, refund recipient, and receipt visibility paths must consume the same actor-snapshot pattern.
- Live Kill Bill provider-originated callbacks remain separate from the stage debug-gateway proof.
- Payment-completion communication must always consume the frozen actor and recipient decision instead of rescanning currently active family grants.
Consequences
Section titled “Consequences”Missing backend obligations or authorization evidence block payment UI entry. Reservation booking no longer implies payment completion. Family grant changes after handoff cannot rewrite historical payer identity or customer-visible amounts.
Revision History
Section titled “Revision History”- 2026-07-11: accepted backend-owned payment obligation and immutable actor snapshot boundary with bounded stage reservation-to-settlement proof.