Skip to content

Family Authority, Payment, And Privacy Gap Mining

Family Authority, Payment, And Privacy Gap Mining

Section titled “Family Authority, Payment, And Privacy Gap Mining”

Family membership is not payment authority. Reservation ownership is not payer identity. Care-delivery visibility is not financial visibility. Modern commands must freeze the actor, consumed grant revision, booking, product obligation, effective interval, and decision evidence at use time.

sequenceDiagram
  participant Sponsor as Family sponsor
  participant Backend as Backend command
  participant SpiceDB as SpiceDB
  participant Supabase as Supabase

  Sponsor->>Backend: Intent plus backend-issued grant reference
  Backend->>SpiceDB: Check booking and product-scoped capability
  SpiceDB-->>Backend: Relationship decision
  Backend->>Supabase: Consume grant revision and freeze actor snapshot
  Supabase-->>Backend: Revisioned command result
  Backend-->>Sponsor: Display-ready projection

Frontend never submits allowed, isMother, capability, or visibility booleans. Supabase stores grant and use evidence; SpiceDB owns relationship decisions; backend domain/application policies own effective-time and obligation scope.

Legacy service intake declares the mother as contracting party and binds booking to authenticated profile. Spouse data is emergency contact, not booking or contract authority. Evidence:

  • source-refs/sanmopia_web/application/views/service/step1.php:74-93
  • source-refs/sanmopia_web/application/views/service/step1.php:193-209
  • source-refs/sanmopia_web/application/controllers/api/Service.php:18-59

Implementation remains partial under ADR-021. FamilySponsorshipGrantorPolicy, ReservationSponsorshipGrant, FamilySponsoredReservationDraft, SponsoredReservationContractAcceptance, and one-time acceptance consumption bind the normalized request fingerprint, contract version, sponsor and mother identities, grant revision, draft revision, and authenticated actor evidence. Backend 109a717 adds HTTP/runtime composition, Supabase transaction functions and RLS, generated database types, and SpiceDB relationship outbox convergence. The changed slice passes 233 tests plus exact Tach gates. Remaining proof is live migration application, contract/client convergence, and the positive plus denial stage matrix.

Product-scoped delegated payment capabilities

Section titled “Product-scoped delegated payment capabilities”

Legacy has distinct normal deposit, balance, pre-reservation, and payment-change routes:

  • source-refs/sanmopia_web/application/controllers/api/Payment.php:89-113
  • source-refs/sanmopia_web/application/controllers/api/Payment.php:325-372
  • source-refs/sanmopia_web/application/controllers/api/Payment.php:523-545
  • source-refs/sanmopia_web/application/controllers/api/Payment.php:681-709

One pay_pre_reservation permission cannot express product, phase, adjustment, amount ceiling, booking, grant revision, or validity window. Target DelegatedPaymentCapability values: pay_pre_reservation_deposit, pay_reservation_deposit, pay_reservation_balance, and pay_reservation_change_adjustment, consumed by AuthorizeDelegatedPaymentUseCommand and queried through GetEffectiveDelegatedPaymentDecisionQuery.

Current payment communication reconstructs payer from grants active when a later event is processed. Revocation or a new delegate can therefore rewrite historical payer and recipient meaning. Legacy also proves only owner access, then notifies mother:

  • source-refs/sanmopia_web/application/controllers/api/Payment.php:95-113
  • source-refs/sanmopia_web/application/controllers/api/Payment.php:182-193

Target PaymentActorSnapshot, DelegatedPaymentGrantUse, and PaymentCompletionRecipientDecision. Freeze payer, initiating actor, mother, recipient, consumed grant revision, and decision time at handoff.

Financial visibility separate from booking visibility

Section titled “Financial visibility separate from booking visibility”

Legacy reservation detail and receipt routes are owner-gated:

  • source-refs/sanmopia_web/application/controllers/MyReservation.php:117-175
  • source-refs/sanmopia_web/application/controllers/MyReservation.php:329-349
  • source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:121-127

Backend 871defb separates booking care visibility from financial visibility. The booking graph now has authorized_payer, view_payment, view_refund, and view_receipt; payment workflow reads and payment-change receipt/detail reads use those permissions instead of broad booking view. Stage proof preserves caregiver booking visibility while denying that caregiver payment, refund, and receipt access. Mother, authorized payer, branch finance, and HQ finance passed their respective financial checks.

Backend now exposes authenticated mother-only grant and revoke commands for a reservation-scoped PaymentDelegation. The aggregate owns payment scopes, effective interval, authority evidence, revision, and revocation reason. Service-role-only Supabase RPCs persist the lifecycle and atomically enqueue PGMQ touch/delete mutations; the bounded worker converges expiring SpiceDB authorized_payer relationships. Stage E2E proved grant/replay, permission appearance, revoke/replay, permission removal, and reaper cleanup.

Remaining gap: consume a product/phase/amount-scoped grant revision when a real payment instruction is created and freeze that use into PaymentActorSnapshot. Inventory every financial projection and prove authenticated HTTP reads; family directory lifecycle proof alone does not complete participant visibility.

Legacy validates ownership for each reservation and report:

  • source-refs/sanmopia_web/application/controllers/MyReservation.php:213-222
  • source-refs/sanmopia_web/application/controllers/api/Report.php:40-52

Backend 903e68d now persists a booking-scoped ReservationCareHistoryAccessGrant with revision, scopes, effective interval, authority evidence, revocation actor and reason, and separate grant/revoke idempotency keys. Service-role-only Supabase RPCs atomically write the lifecycle and enqueue PGMQ touch or delete work; the worker converges the exact SpiceDB care_history_viewer relationship.

Contract e4cc9ed publishes exact read, grant, and revoke routes. Public read decision derives the grantee from the authenticated member profile and derives the account mother from Supabase. Grant/revoke commands derive the acting mother from the authenticated session. None of those request bodies accepts motherMemberId. Daily-report review and rating mutation use a separate submit_mother_daily_report_review permission plus a backend-owned booking-to-mother authority reader. Legacy actor_is_reservation_mother, actor, mother, and rating identities are canonicalized only after both checks pass; they are never authorization evidence.

The 2026-07-12 authenticated stage smoke proved exact grant replay, delegated read, cross-booking denial, rejection of a browser-supplied mother field, mother readiness, forged family-delegate review/rating denial, exact revoke replay, SpiceDB permission removal, post-revocation denial, and registered DB plus SpiceDB cleanup. Booking 81af6692-7703-4da4-89cb-9300bfb5b769 used grant b7d413de-894e-4ada-894a-457823e79815.

Backend a88326b and contract 0d576f2 now complete the content read boundary described in ADR-024. A later stage run created booking 9c3b61e4-e81e-424d-8d0e-a73b7f53775a and grant e3c7ef7a-51c5-47e4-90e3-9486e8915c21, then proved mother and delegate content reads, backend-resolved labels and notes, review-mutation denial, revoke, post-revoke denial, and complete registered-data cleanup.

Current policy treats any non-null revoked_at as inactive even when evaluating a time before revocation. It has no operational revoke command or relationship delete outbox. Target FamilyAuthorityEffectiveInterval, FamilyAuthorityGrantLifecycle, RevokeFamilyAuthorityGrantCommand, FamilyAuthorityGrantRevoked, and GetFamilyAuthorityAsOfQuery with invariant granted_at <= used_at < revoked_at when revocation exists.

Backend 83fe291 establishes FamilyAuthorityEffectiveInterval as shared domain authority for sponsor, delegated-payment, and care-history grants. Payment communication evaluates delegation at payment event time, so later revocation no longer changes historical payer resolution. The reservation payment-delegation slice now persists lifecycle revisions, exposes an operational revoke command, and retries the SpiceDB relationship-delete outbox. Exact replay ignores the newly generated backend clock while rejecting changed actor, reason, or revision facts. Remaining work is a persisted general family-authority as-of query and equivalent lifecycle wiring for sponsorship and care-history grants.

Current family-account RLS allows a linked family member to list unrelated payment-delegation and care-history grant metadata. Legacy lists reservations by owner only:

  • source-refs/sanmopia_web/application/controllers/MyReservation.php:22-48
  • source-refs/sanmopia_web/application/controllers/MyReservation.php:73-98

Target FamilyAuthorityGrantDirectoryVisibilityPolicy, GetFamilyAuthorityDirectoryQuery, and mother-only GetFamilyAuthorityAdministrationProjection. Backend bb4d6ee creates the first projection boundary: own view returns only the authenticated member’s grants, while administration requires mother domain authority and SpiceDB administer on the family account. Direct Supabase family membership must not imply authority-directory access. Backend 4477372 removes authenticated raw grant-table reads for sponsorship, payment-delegation, legacy care-history, and reservation care-history authority facts, leaving service-role backend reads. Backend 13dc531 proves withdrawn Supabase member sessions and revoked family members are denied at API/HTTP boundaries. Backend dde8177 closes the stage HTTP proof by extending the care-history access smoke: booking f175bd00-441f-4801-b21d-3081bfa75682 and grant aecf7aa6-d034-407d-9148-74deb5f87d1c prove active own directory visibility, hidden authority evidence, non-admin administration denial, revoke, and post-revoke disappearance from the delegate’s own directory.

This slice remains incomplete until:

  • SpiceDB has product-scoped delegated-payer and financial-view relations;
  • backend consumes a revisioned grant and freezes payer evidence atomically;
  • care-history content reads continue consuming booking-scoped authorization while review mutation stays mother-only;
  • payment-delegation and sponsorship revocation preserve historical facts and emit relationship outbox work;
  • Supabase RLS no longer exposes unrelated family authority rows;
  • stage E2E proves sponsor booking, mother acceptance, delegated payment, revocation, historical receipt visibility, and denied caregiver finance read.