ADR 016 Branch Settlement Board Projection
Context
Section titled “Context”The migrated reservation flow could advance a real booking through service
delivery, caregiver payout, branch settlement, HQ settlement, and settlement
completion, but the branch settlement operator dashboard still showed no rows.
The source problem was not UI layout: Supabase had
sanmopia_reservation_financial_ledger_lines with ledger_bucket = branch_settlement, while sanmopia_branch_settlements and
sanmopia_branch_settlement_lines had no producer.
Letting Astro total ledger rows or invent a dashboard row would repeat the legacy PHP failure mode where screens owned money facts.
Decision
Section titled “Decision”SupabaseReservationFinancialLifecycleStore.save_financial_lifecycle() now
materializes deterministic branch settlement board projections whenever a
financial lifecycle contains branch-settlement ledger lines.
The projection rules are:
branch_settlement_idis deterministic per reservation booking.- Header period comes from care delivery dates, then recognized ledger dates.
- Line kind is mapped from the versioned ledger
line_type_code. - Direction comes from payer/payee party roles, not UI text.
- Net balance uses central-office perspective: receivable is positive, payable is negative.
- Supabase storage uses the actual
source_reference_keycolumn; application contracts may expose the clearerlineageReferenceKey. - Financial lifecycle adapters must not import settlement-domain aggregates directly. They may depend on settlement-domain vocabulary codecs when they write branch-settlement projection rows. Tach declares that boundary explicitly.
Frontend pages may only consume branch dashboard/detail contracts. They must not calculate branch settlement totals or synthesize line items from raw rows.
Implementation Evidence
Section titled “Implementation Evidence”- Financial-lifecycle Supabase projection writer
- Branch settlement board domain model
- Supabase board repository
- Public board schema
Consequences
Section titled “Consequences”Historical stage evidence recorded 2026-07-09:
pnpm run -s supabase:smoke:stage:reservation-to-settlement-completion- Booking
038a8647-01c2-4a8a-930c-1db29636e9a8 - Payment workflow
RPW-STAGE-CONT-20260709034950 - Service balance closeout event
e6953362-25ad-40a2-aeb3-3a95be457f3a - Branch settlement dashboard rows:
3 - Branch settlement board line items:
1
The same proof now fails if the dashboard has only an empty header row.
This audit did not rerun stage proof. Repository evidence confirms projection code, not current runtime health.
2026-07-09 Follow-Up
Section titled “2026-07-09 Follow-Up”The board command path now carries settlement_period_start from CQRS command
to BranchSettlementBoard, while settlement_date remains the period end.
SupabaseBranchSettlementBoardRepository persists and reloads board headers and
line items through sanmopia_branch_settlements and
sanmopia_branch_settlement_lines. The migration adds settlement_scope so
existing per-booking projections remain booking_projection, while monthly
board openings are stored as period_statement. The unique branch-period index
applies only to period_statement rows, so per-booking demo projections cannot
block each other.
Line-kind mapping is now fail-closed through the shared
BranchSettlementLineKindCodec. Unknown source buckets raise before projection
write instead of silently becoming branch_adjustment.
Remaining work is full monthly/periodic branch settlement opening policy: fact link-back, source revision tracking, component acknowledgement projection, and repair/recalculation audit. The current state is strong enough for a backend-owned reservation-to-settlement demo because totals and line kinds are frozen in Supabase instead of recomputed by UI.
2026-07-09 operator UI polish keeps the same boundary. The branch settlement surface now hides branch/export/workflow/storage ids behind collapsed operator details and keeps the visible dashboard focused on backend projection counts, status labels, and returned KRW values. The page still consumes backend contracts only; it does not calculate branch settlement money in Astro.
2026-07-09 source-backed payout smoke booking
d33201b3-d98c-494c-b674-91775a79dd8a returned branch settlement dashboard
rows 26 and board line items 1 after freezing caregiver payout from the
latest bank-account revision source. The same smoke still reported settlement
continuation waiting_for_financial_facts with reason
branch settlement ledger lines are not ready; therefore board projection
availability is not the same as full branch settlement ledger readiness. The
next backend gate is a branch-settlement ledger producer/source reader that can
feed settlement continuation without UI-computed totals.
2026-07-09 backend follow-up closes that narrow readiness gap for the stage
reservation-to-settlement path. IssueBranchSettlementAfterCaregiverPayout
lives in the financial-lifecycle application slice, reads the frozen lifecycle,
finalized charge snapshot, caregiver payout ledger, and closeout references,
then emits a canonical inter_office_branch_share branch-settlement ledger
line through PrepareReservationBranchSettlementCommand. The stage payment
continuation script no longer calculates the branch settlement amount or builds
the branch-settlement line payload. Stage proof:
pnpm run supabase:smoke:stage:reservation-to-settlement-completion, booking
b0060d1a-7bcd-42a5-aaa3-866042644318, payout instruction
cee6722b-7df4-56b2-b9a5-cb9a5f7e9f7d, branch settlement dashboard rows 29,
board line items 1.
2026-07-09 HQ follow-up applies the same source-authority rule to the next
settlement hop. IssueHqSettlementAfterBranchSettlement derives HQ settlement
from the finalized charge snapshot’s settlement-deduction facts after branch
settlement readiness; smoke scripts no longer build the HQ amount or line.
Latest stage proof booking 521a5051-9825-44e9-bb5a-fd7d84d3981e produced
branch settlement 100000, HQ settlement 50000, dashboard rows 32, and
board line items 1. Direct browser backend driver proof booking
27f69a4c-7600-4de1-b611-839d8e757b94 now uses the same source-owned branch/HQ
line producers and returns account-disclosure readiness not_required instead
of stale instruction_unavailable for zero service-balance due. Remaining board
risk is broader period statement, component-acknowledgement parity, and
catalog-owned fixture replacement, not the narrow per-booking branch/HQ source
lines.
2026-07-12 runtime recheck passed both narrow stage paths. Standard
pnpm supabase:smoke:stage:reservation-to-settlement-completion created booking
c4540bf8-7432-456e-93a2-f5a5d843e110, proved family payment delegation,
payment continuation, service delivery, caregiver payout, branch/HQ settlement
completion, branch dashboard rows 63, board line items 1, zero service
balance readiness not_required, and registered-batch cleanup with SpiceDB
cleanup verification. Positive-balance
pnpm supabase:smoke:stage:reservation-to-settlement-positive-balance created
booking 3aedc22f-72e2-4e6b-8fc8-c33e2458a016, proved service-balance amount
25000, customer disclosure readiness ready, rawAccountFieldsVisible=false,
caregiver payout 50000, branch settlement 100000, HQ settlement 50000,
financial stage settled, ledger line count 3, and registered-batch cleanup.
The positive-balance wrapper now uses the same cleanup reaper as the standard
flow, so stage data and SpiceDB grants are not left behind after proof.
Revision History
Section titled “Revision History”- 2026-07-09: accepted backend-owned branch settlement projection.
- 2026-07-10: marked runtime snapshots historical and implementation partial pending period-statement completion.
- 2026-07-12: refreshed standard and positive-balance reservation-to-settlement stage proof; fixed positive-balance smoke cleanup.