Source Feature Checklist
Source Feature Checklist
Section titled “Source Feature Checklist”This checklist is source-first. A feature is not complete until contract, backend, frontend, Supabase, docs, and tests prove the modern replacement.
Source UI logic is migration evidence, not frontend behavior to preserve. Any
source view, JavaScript, or controller path that sums money, derives status,
chooses buttons, validates download readiness, or decides actor visibility must
move into backend domain policy, application commands, or versioned read models.
Modern frontend surfaces may render only backend-computed projections and submit
explicit commands; they must not recompute totals or infer workflow state from
raw rows, source status ids, payment maps, document tokens, or storage refs.
Frontend repository architecture is atomic/static-view first, not DDD feature
slice. Any frontend src/features/** directory is migration debt unless it is
pure route/view composition with no policy, money math, settlement logic,
matching logic, RBAC, audit, lifecycle transition, or Supabase authority. Shared
UI state must use Nanostores and generated contracts; durable decisions belong
to backend domain/application slices, SpiceDB/OPA/ReState gates, and Supabase
ledger/read models.
For reservation/payment/settlement flows, e2e_proven means the browser path
used backend-owned projections, commands, SpiceDB grants, Supabase/RLS reads,
and frozen financial facts. A passing browser scenario that still depends on
src/features/**, UI-side amount math, UI-side status mapping, local RBAC, or
mutable source-row interpretation stays runtime_wired at most.
Architecture and feature flow diagrams live in C4 Model. Checklist items should link back to that page when a source feature changes Context, Container, Component, or Code-level design.
Folder architecture audits: DDD Domain Folder Audit, DDD Application Contract Folder Audit, Legacy UI Business Logic Gap Mining, and Code Health Debt Map track naming, CQRS, boundary, and backend-projection debt found by CaveCrew.
Focused source-mining pages: Admin Analytics And System Gap Mining, Caregiver Matching Assignment Gap Mining, Branch Office Operations Gap Mining, Document Reporting Gap Mining, Customer Engagement Commerce Gap Mining, Notification And Document Delivery Gap Mining, Promotion Caregiver Analytics Gap Mining, Settlement Data Room Gap Mining, Partner Benefit Fulfillment Gap Mining, Customer Self-Service Workspace Gap Mining, Manager And Customer Portal Gap Mining, Operator Backend Decision Gap Mining, Status Payment Settlement Source Map, and Reservation Lifecycle Side Effect Execution. Family Authority, Payment, And Privacy Gap Mining tracks sponsor consent, delegated payer, historical authority, care-history, and financial visibility boundaries. UI-side business-rule gaps are tracked in Legacy UI Business Logic Gap Mining. Traffic-spike protection is tracked in Traffic Spike Backpressure Gap Mining. Runtime telemetry rules are tracked in Observability and Backpressure.
Status tags:
Migrated: replacement exists and is verified.Partial: modern slice exists, but source coverage or runtime workflow remains incomplete.Pending: source feature identified, no full modern replacement yet.
Machine-countable SFC rows use these statuses for new rows and touched rows:
pending: source gap only.mapped: source evidence plus DDD target named.foundation: domain/application/contract tested.runtime_wired: persistence, API, worker, or access control bound.e2e_proven: runtime path exercised end to end.migrated: legacy/UI authority removed or disabled.blocked: owner and unblock condition named.
Canonical row schema:
| feature_id | lane_owner | source_evidence | ddd_aggregate | command_query | persistence | contract | e2e_proof | status |
|---|
Delegation Control Notes
Section titled “Delegation Control Notes”-
Frontend work may use native bounded delegation. Main migration control owns backend, contracts, source evidence, docs, and PR review. Frontend must not reintroduce UI-side price, settlement, status, or region-label mapping.
-
Delegation uses native bounded subtasks. Do not maintain persistent agent ids, resume stale workers, or keep an agent registry in product documentation. Controller supplies checklist/ADR context with each task, reviews uploaded changes, then lets the worker terminate.
-
Workstream ownership describes repository boundaries, not agent identity:
Workstream Owner boundary Delegation rule Expected output Hidden legacy feature mining and documentation Source evidence lane One read-only bounded source slice per native delegation. Never repeat already documented mining. Gap rows with source path and line range, legacy behavior, modern target name, bounded context, feature slice, backend policy/contract need, and status. Frontend implementation frontend-repoAtomic UI laneDelegate disjoint production paths; controller owns bounded Playwright execution and process cleanup. Atomic-pattern UI consuming generated contracts, NanoStores presentation state, and no frontend src/features/**business logic.Backend and contract implementation Backend/contract feature lane Delegate only disjoint feature-level write sets; controller reviews architecture, migrations, and public compatibility. Domain policy, application contract, Supabase migration, colocated tests, Tach/Vulture gates, and generated contracts. Migration governance and integration Main migration control Never delegate final merge, stage mutation, E2E, process cleanup, progress accounting, or ADR/checklist truth. Reviewed commits, live stage evidence, bounded E2E, and Starlight documentation. -
Delegated workers must not launch Playwright or long-lived Serena/Tach MCP processes. Controller performs semantic review and browser proof. A worker is terminated immediately when resource limits or repository ownership are violated; its file changes remain subject to normal review.
-
Backend shared-kernel now owns stable identity predicates used by service calendar, service period, service commitment, and customer action availability slices. Bounded contexts still raise their own domain errors; duplicated lower-code/reference predicates should continue moving to
shared_kernel / stable_identityonly when focused tests cover the slice. -
2026-07-05 follow-up: caregiver matching, caregiver matching profile, care team contract, and assignment optimizer inputs now reuse
shared_kernel / stable_identityfor stable code predicates instead of local regex copies. -
2026-07-05 follow-up: payment refund and cancellation adjustment catalog code validation now also uses
shared_kernel / stable_identity, keeping refund-domain errors local while removing another regex copy. -
2026-07-05 follow-up: member privacy withdrawal lifecycle and repair-history reason/status/actor code validation now also use
shared_kernel / stable_identity; privacy-domain errors remain local, while code-shape rules stay shared. -
2026-07-05 follow-up: service-calendar holiday audit actor, provider, and reason code validation now also uses
shared_kernel / stable_identity; holiday-audit reference and fingerprint checks remain local to that slice. -
2026-07-05 follow-up: daily-care-report field, section, option, definition, and reward reason code validation now also uses
shared_kernel / stable_identity; report label checks remain local because they allow dotted display/catalog labels. -
2026-07-05 follow-up: document room, document delivery, branch resource post, branch office content, and offline reservation intake code validation now also use
shared_kernel / stable_identity; reservation change request keeps its local predicate because Tach explicitly blocks that feature from depending ondomain.shared_kernel. -
2026-07-05 follow-up: reservation payment workflow action values now live in the application payment workflow slice and are reused by Kill Bill ingestion and Supabase workflow row hydration, removing adapter-local action sets.
-
2026-07-05 follow-up: service calendar now preserves explicit substitute holiday source-date relation, applies rollback end-date policy as calendar span then rolls back to a service day, and service commitment tests cover selected extra days plus pause-suppressed coupon obligations.
-
2026-07-05 follow-up: caregiver credential dossier stable code validation now uses
shared_kernel / stable_identity; opaque storage/object ids remain local because they allow a wider character set than business codes. -
2026-07-06 follow-up: customer reservation lifecycle view and reservation actor capability projection now reuse
shared_kernel / stable_identityfor dotted stable codes instead of local regex constants. -
Regional benefit lines now require backend/contract-provided amount-source labels (
amount_component_label/amountSourceLabel) so frontend pricing views render catalog-owned labels instead of mapping amount-source keys. Supabase catalog policy addsamount_source_labelfor source-amount rules. -
Regional benefit profile metadata now belongs to backend policy data:
regional_benefit_profile_key,service_day_bonus_count, andsettlement_participation_codeonRegionalBenefitRule.FinalizeReservationChargeWithRegionalBenefitHandlernow resolves a backend-ownedRegionalBenefitDecisionbefore buildingReservationPriceSummaryInputand charge snapshot evidence. HTTP/API request models accept anacceptedRegionalBenefitDecision, Restate payload decoding can hydrate it, and charge finalization preserves profile/service-day/ settlement metadata. Remaining work: reservation entrypoints still must resolve the decision from catalog/address data before workflow start,build_reservation_booking_workflow_request()still must serialize the accepted decision into the workflow input payload, and service-calendar impact, payment-conversion, and settlement consumers still need to call/read the same frozen decision path. -
Notification obligation dispatch no longer exposes domain enum/action state through UI-shaped
api_shape()from domain. Stringification belongs in the application contract boundary. -
Supabase CLI is available through
pnpm exec supabase; local DB lint was attempted but local Postgres was not reachable, so type regeneration must run after the stage/local Supabase DB has the new migration applied. -
Supabase stage migration replay is green through
20260705171000_customer_reservation_request_workflows.sql. The 2026-07-05 replay fix shortened reservation lifecycle side-effect evidence constraint names to avoid PostgreSQL identifier truncation collisions, and preserved existing customer-inquiry/caregiver-office trigger codes when extending the communication workflow catalog constraint. -
2026-07-07 booking workflow smoke is green through backend
supabase:smoke:stage:reservation-booking: stage FastAPI accepts a real branch-operator booking request, Restate completes it, the progress endpoint returns the completed reservation, and the workflow row preserves the branch actor instead of overwritingrequested_by_user_idwith the mother user. -
2026-07-08 reservation scenario loop is now stage-smokeable beyond booking:
supabase:smoke:stage:payment-continuation-after-service-deliverycreates a booking, starts a paid payment workflow, observeswaiting_for_financial_factswhile service delivery is missing, records service delivery, prepares caregiver payout, branch settlement, and HQ settlement ledger facts with frozen closeout references, then proves the same payment workflow row starts settlement continuation instead of staying blocked on stale financial-fact state. -
2026-07-13 callback-to-settlement e2e is green on stage:
pnpm supabase:smoke:stage:killbill-callback-to-settlement-completioncreates a reservation, ingests synthetic Kill BillPAYMENT_SUCCESS, records service delivery, creates caregiver payout instruction, records branch payout deposit acknowledgement and caregiver payout receipt acknowledgement, prepares branch/HQ settlement through backend HTTP commands, starts settlement continuation, completes settlement, refreshes operator settlement boards, and reaps test data. This promoted caregiver payout receipt from a receipt-state projection only to a guard-visibleCaregiverPayoutAcknowledgementcommand. -
2026-07-13 follow-up: the same smoke now records caregiver payout receipt as the assigned caregiver actor. Backend resolves payout target profile id to the frozen
assigned_caregiver_user_id, requires SpiceDB booking view permission, and still writes the acknowledgement against the payout instruction target expected by settlement-continuation guards. -
2026-07-13 projection follow-up: the caregiver receipt acknowledgement command now also writes the
acknowledgedreceipt-state projection consumed by caregiver/operator UX. The same stage smoke now assertscaregiver_payout_receipt_state=acknowledgedand reaps receipt-state events before payout instructions, preventing test-data cleanup from hiding FK debt. -
2026-07-08 RBAC hardening follow-up re-ran
supabase:smoke:stage:financial-lifecycle-closeout-guardafter removing Supabaseapp_metadatarole/profile authority. Stage created reservationf3423929-ad23-4129-a4b4-8f2f74d1f265and service-balance closeout eventad2d90f2-4b61-46bd-af7d-5a7218e0a296, then advanced the financial lifecycle through branch/HQ settlement completion under backend/SpiceDB authority.
Newly Confirmed Unclosed Gaps
Section titled “Newly Confirmed Unclosed Gaps”| Gap | Legacy evidence | Modern owner | Required migration |
|---|---|---|---|
| Cancellation side effects | source-refs/sanmopia-admin/application/config/constants.php:116, source-refs/sanmopia_web/application/models/Reservation_model.php:989 | reservation_operations / ReservationLifecycleCommand, pricing_settlement / CancellationRefundLifecycle | Status transition, instant refund, coupon restore, Momfirst unlink, side-effect outbox, and refund/coupon ordering must be backend-owned. |
| Weekly/extension/weekend/holiday service | source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:778, source-refs/sanmopia-admin/application/models/Manage_system_model.php:51 | reservation_operations / ServicePeriodPlan, service_calendar / HolidayPolicyExecutionAndImpactInvalidation | Freeze service occurrences, holiday revisions, substitute holidays, quote/matching/report/refund/settlement invalidations, and branch-specific closure evidence. |
| Settlement data room and HQ/Danbee/inter-office settlement | source-refs/sanmopia-admin/application/controllers/Calculate.php:151, source-refs/sanmopia-admin/application/controllers/DataRoom.php:218 | pricing_settlement / SettlementActionJournal, SettlementStatementWorkflow, SettlementDataRoomArtifactRequest | Separate HQ request, branch confirmation, Danbee settlement, inter-office confirmation, export revision, signed grants, repair audit, and actor-scoped transition journal. |
| Custom adjustment and negative lines | source-refs/sanmopia-admin/application/views/modal/modal_other_service_add.php:18, source-refs/sanmopia-admin/application/controllers/Calculate.php:184 | pricing_settlement / SettlementManualAdjustmentLine | Versioned adjustment catalog, signed amount direction, reason, actor, statement linkage, and no freeform browser line math. |
| Payment change, refund, partial refund | source-refs/sanmopia_web/application/views/modal/modal_change_payment.php:3, source-refs/sanmopia_web/application/models/Payment_model.php:383, source-refs/sanmopia_web/application/libraries/Kcppayment.php:39 | pricing_settlement / PaymentChangeAdjustmentAmountBreakdown, PaymentRefundIntent | Freeze delta, provider context, refund quote, partial-cancel event, ledger reversal, receipt artifact, and Kill Bill-backed provider orchestration. |
| Caregiver matching evidence | source-refs/sanmopia-admin/application/models/Matching_model.php:44, source-refs/sanmopia-admin/application/models/Matching_model.php:724 | caregiver_assignment / CaregiverCandidateOrderingPolicy | Freeze score components, distance/travel freshness, schedule, pet, grade/class, branch scope, and deterministic tie-breaker evidence. |
| Multi-caregiver payroll | source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:45, source-refs/sanmopia-admin/application/models/Reservation_model.php:2166, source-refs/sanmopia-manager/application/helpers/salary_helper.php:8 | caregiver_assignment / CareTeamRosterAssignmentDecision, pricing_settlement / CaregiverPayoutPolicyProfile | Persist role slots, assignment terms, payout snapshots, tax election, custom pay audit, and prevent salary evidence deletion. |
| Family, delegated payer, authority | source-refs/sanmopia_web/application/views/service/step1.php:188, source-refs/sanmopia_web/application/controllers/api/Service.php:70 | member_management / ReservationPartyAuthoritySnapshot | Separate mother, sponsor, payer, emergency contact, contact-only viewer, refund recipient, document viewer, and delegation validity windows. |
| Service-area profile | source-refs/sanmopia-admin/application/models/Branch_model.php:289, source-refs/sanmopia-admin/application/models/Branch_model.php:345 | branch_operations / ServiceAreaDecisionSnapshot | Effective-dated coverage profiles, address normalization, serviceability/counsel/impossible evidence, and booking-bound snapshots. |
| Branch/HQ conflict and audit | source-refs/sanmopia-admin/application/controllers/Reservation.php:651, source-refs/sanmopia-admin/application/controllers/Reservation.php:821 | reservation_operations / ReservationCollaborationCommand, operator_access / ActorStageCapabilityProjection | Typed commands, expected revision, conflict diff, selected winner, actor capability snapshot, and append-only journal before any broad save. |
2026-07-05 Persistent Worker Legacy Mining Delta
Section titled “2026-07-05 Persistent Worker Legacy Mining Delta”This pass narrows backend-owned gaps still visible in legacy PHP/JS sources. Source paths are evidence only; the target must be policy, command, or read-model authority.
| Priority | Gap | Legacy evidence | Modern owner | Required migration |
|---|---|---|---|---|
| P0 | Service duration, holiday, extension, and local-support parity | source-refs/sanmopia_web/application/models/Reservation_model.php:463-486, source-refs/sanmopia_web/application/models/Reservation_model.php:2038-2233, source-refs/sanmopia_web/application/models/Reservation_model.php:2515-2630, source-refs/sanmopia-admin/application/controllers/Reservation.php:1740-1758, source-refs/sanmopia-admin/application/models/Reservation_model.php:5376-5418, source-refs/sanmopia-admin/application/models/Manage_system_model.php:52-181, source-refs/sanmopia-admin/static/js/manage_system/holiday_list.js:1-107 | service_calendar / ServiceCalendarCompatibilityDecision, HolidayPolicyExecution, reservation_operations / ReservationContinuationLink, pricing_settlement / RegionalBenefitDecision | Execute accepted holiday add/revise/withdraw decisions with version, scope, supersession, and audit; freeze which legacy service-end mode produced historical rows; bind extension/copy facts, branch coverage, same-caregiver availability, and local support bonus from backend decisions instead of UI locality flags. |
| P0 | Charge, discount, support-item, and custom amount hardcoding | source-refs/sanmopia_web/static/js/step3.js:198-560, source-refs/sanmopia_web/static/js/step3.js:766-831, source-refs/sanmopia_web/application/views/reservation/retc.php:1-205, source-refs/sanmopia-admin/application/views/reservation_status/pre_reservation_price_table.php:1-124, source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:927-948, source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1518-1542, source-refs/sanmopia-admin/application/config/constants.php:112-113, source-refs/sanmopia-user-old/src/data/mock/reservation.ts:395-419, source-refs/sanmopia-user-old/src/data/mock/reservation.ts:468-490, source-refs/sanmopia-user-old/src/data/mock/reservation.ts:612-644, source-refs/sanmopia-user-old/src/data/mock/reservation.ts:936-985 | pricing_settlement / ReservationChargeLineCatalogProjection, PaymentProductPlanTemplate, PaymentAdjustmentCatalog, PreReservationCreditPolicy, RegionalBenefitRule | Move delivery fee, pre-reservation credit, in-home/special voucher add-on display, weekend/holiday add-day pricing, regional discount, local support item ids/names, deposit/balance split, service-balance zero/positive cases, payment-product labels/statuses, and all display labels into backend catalog snapshots. UI and smoke/demo fixtures may only render catalog-issued frozen charge/payment templates and submit explicit adjustment commands; they must not copy TypeScript mock totals, Korean payment labels, provider refs, or hardcoded PRERESERVATION_PRICE into booking/payment fixtures. |
| P0 | Settlement data-room worklist and export workflow | source-refs/sanmopia-admin/application/controllers/DataRoom.php:30-94, source-refs/sanmopia-admin/application/controllers/DataRoom.php:218-250, source-refs/sanmopia-admin/application/controllers/DataRoom.php:268-386, source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:17-240, source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:1-260, source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:1-69, source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:1-57 | document_reporting / ReservationDocumentExportWorklist, pricing_settlement / SettlementDataRoomArtifactRequest, SettlementDataRoomCollectionExportReader | Replace PHP-memory filtering, URL hash filters, hidden iframe downloads, raw GET export parameters, and controller document-id switches with database-backed worklists, immutable selection tokens, bundle policy versions, artifact build records, signed grants, return-state tokens, and action audit. |
| P0 | Family, proxy payer, contact, refund, and document authority | source-refs/sanmopia_web/application/views/service/step1.php:91-213, source-refs/sanmopia_web/application/models/Reservation_model.php:314-374, source-refs/sanmopia_web/application/controllers/api/Service.php:67-83, source-refs/sanmopia_web/application/controllers/api/Payment.php:89-113, source-refs/sanmopia_web/application/models/Payment_model.php:570-704 | member_management / ReservationPartyAuthoritySnapshot, pricing_settlement / PayerSnapshot, document_reporting / DocumentRecipientAuthority | Separate mother, booker, payer, family sponsor, emergency-contact-only recipient, refund recipient, document viewer, and notification recipient. Relation text, phone numbers, reservation owner checks, and branch notice hardcoding are migration evidence, not modern authority. |
| P0 | Branch coverage and address profile binding | source-refs/sanmopia_web/application/models/Branch_model.php:38-144, source-refs/sanmopia-admin/application/models/Branch_model.php:288-334, source-refs/sanmopia-admin/application/models/Branch_model.php:345-426, source-refs/sanmopia-admin/application/models/Branch_model.php:591-606 | branch_operations / BranchServiceAreaDecisionSnapshot, ServiceAreaPolicyVersion | Bind first-period, second-period, extension, and continuation workflows to an effective-dated service-area decision with normalized address evidence and policy revision. Source possible/counsel/impossible rows and hard deletes must migrate as versioned profile changes and withdrawals. |
| P0 | Caregiver candidate rank, distance, and pay authority | source-refs/sanmopia-admin/application/models/Matching_model.php:44-124, source-refs/sanmopia-admin/application/models/Matching_model.php:724-862, source-refs/sanmopia-admin/application/models/Reservation_manager_trans_info_model.php:13-87, source-refs/sanmopia-manager/application/helpers/salary_helper.php:8-227, source-refs/sanmopia-manager/application/views/pay_info_detail.php:167-263 | caregiver_assignment / CaregiverCandidateOrderingPolicy, CaregiverCandidateSnapshot, pricing_settlement / CaregiverCompensationQuote, CaregiverPayoutInstruction | Freeze candidate limit, score components, pet exclusion, schedule proof, branch/class filters, deterministic tie seed, transport provider result/fallback, and score-vs-distance policy. Payout quotes must freeze role, custom pay, service-balance override, voucher add-ons, option labels, tax election, and tax cutover before manager/HQ screens render them. |
| P1 | Source string, id, amount, and date compatibility | Same rows above plus source-refs/sanmopia_web/application/views/service/step1.php:188-209 | migration_governance / SourceCompatibilityCatalog | Convert magic labels, relation ids, service item ids, amounts, date cutovers, branch ids, and source status strings into catalog rows, policy profiles, enum aliases, or import compatibility decisions with source evidence. None should leak into modern UI branching or domain invariants. |
2026-07-05 Payment/Refund Source Pass
Section titled “2026-07-05 Payment/Refund Source Pass”| Gap | Legacy evidence | Modern owner | Required migration |
|---|---|---|---|
| Provider refund and paid-row transition | source-refs/sanmopia_web/application/models/Payment_model.php:383, source-refs/sanmopia_web/application/models/Payment_model.php:416, source-refs/sanmopia_web/application/models/Payment_model.php:427, source-refs/sanmopia_web/application/models/Payment_model.php:429 | pricing_settlement / PaymentRefund, ProviderRefundPaidRowTransition | Refund must persist provider reversal and internal paid/refunded state in one idempotent ledger path. Source marks normal/voucher payment rows status 2 after KCP full cancel; modern ledger must not report paid after provider refund, nor mark refunded before provider success. 2026-07-06 backend foundation: ce59da4 records provider refund result events separately from paid-row transitions, guards expected paid-row revision, settlement lock, already-refunded rows, remaining amount, partial/full refunded target state, and keeps rejected transitions as auditable events. Backend 9cc034c adds service-role-only Supabase persistence for ProviderRefundPaidRowTransitionDecision, storing provider result event, source evidence, idempotency key, applied/rejected transition state, revision movement, and remaining paid amount in sanmopia_provider_refund_paid_row_transition_decisions with RLS and anon/authenticated revokes. Backend e038c7c adds ProviderRefundReportingInvalidationPolicy, RecordProviderRefundReportingInvalidationsHandler, and service-role-only Supabase persistence for sanmopia_provider_refund_reporting_invalidations, so provider refund results invalidate sales dashboards, branch/HQ settlement statements, settlement export artifacts, and branch/HQ operator boards with separate financial-recalculation versus operator-repair flags. Backend 8db9942 wires the invalidation policy into ProviderRefundPaidRowTransitionHandler, so configured provider-result recording persists both the transition decision and invalidation plan from the same provider event timestamp. Backend fa13ef7 adds ProviderRefundReportingProjectionRefreshRequestPlan, queues sanmopia_provider_refund_reporting_refresh PGMQ messages, and marks invalidation rows refresh_requested with request key, queue name, and timestamp. Backend c46382b consumes those queue payloads through ProviderRefundReportingProjectionRefreshHandler and records refreshed or refresh_failed status transitions. Backend ef0dade adds immutable provider-refund settlement reversal-line domain/application/adapter slices, service-role-only sanmopia_settlement_ledger_reversal_lines, and a Tach-validated application continuation from paid-row transition request to settlement reversal command. Backend ebf785d exposes /internal/provider-refund-paid-row-transitions and wires the runtime handler to transition persistence, reporting invalidation store, PGMQ refresh requester, and settlement reversal producer. Backend 6120324 adds /internal/provider-refund-results-from-ledger, ProviderRefundResultFromLedgerHandler, and a Supabase paid-row snapshot reader so workers can send only refund intent plus provider result evidence while backend derives refund amount and current paid-row revision from ledgers. Backend f391565 changes the Supabase decision store to call sanmopia_record_provider_refund_paid_row_transition_decision, which records the decision fact and advances sanmopia_payment_records.payment_status/payment_fact_revision under payment_id + payment_fact_revision guard, including full-refund refunded status. Backend 3e6d83f proves workspace-domain and contract-level artifact grant revocation on repair. Backend follow-up exposes token-gated /internal/payment-refund-repairs/provider-refund-plans and wires PaymentRefundRepairHandler to Supabase persistence. Backend follow-up also exposes /internal/payment-refund-repairs/provider-refund-executions, calls the configured billing gateway through PaymentGatewayClient.refund only for new idempotency keys, persists idempotency-keyed execution attempts in sanmopia_payment_refund_repair_execution_attempts, replays matching stored attempts into ProviderRefundResultFromLedgerHandler without a second provider call, and rejects mismatched replays. Remaining runtime work: stage provider-webhook E2E, retry backoff and operator result-history projection, full sales-dashboard fact recomputation/read APIs, Supabase/stage persistence proof for grant revocation and replacement lineage, and operator-visible artifact reissue history. |
| Pre-reservation cancellation refund | source-refs/sanmopia-admin/application/models/Reservation_model.php:5560, source-refs/sanmopia-admin/application/models/Reservation_model.php:5567, source-refs/sanmopia-admin/application/models/Reservation_model.php:5571, source-refs/sanmopia-admin/application/models/Reservation_model.php:5572, source-refs/sanmopia-admin/application/models/Reservation_model.php:5588, source-refs/sanmopia-admin/application/models/Reservation_model.php:5591, source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31, source-refs/sanmopia-admin/application/libraries/Kcppayment.php:39, source-refs/sanmopia-admin/application/libraries/Kcppayment.php:40, source-refs/sanmopia-admin/application/libraries/Kcppayment.php:42 | pricing_settlement / PreReservationCancellationRefund, reservation_operations / PreReservationCancellation, payment_processing / ProviderRefundCommandPlan | Admin cancellation selects only paid pre-reservation rows and calls provider refund, but source does not clearly persist payment refunded status. Stronger source gap: the status-save path passes PAY_METHOD and reason into a refund wrapper whose signature only accepts order id, transaction id, and mod_desc; the wrapper then sends full-cancel mod_type=STSC. Modern provider refund planning must type and persist provider method, reason, amount, idempotency key, refund capability, and provider command fields separately instead of preserving legacy argument order or treating local status write as refund authority. 2026-07-06 backend foundation: ce59da4 now selects exactly one paid pre-reservation deposit row, records reservation cancellation status, refund request, provider requested/succeeded/failed events, and payment refund-state updates; multiple paid rows are treated as ambiguous instead of guessed. Remaining runtime work: Supabase persistence, reservation status transaction binding, provider execution/webhook binding, legacy payment-row backfill, and operator projection for failed/mismatched provider command attempts. |
| Partial refund support | source-refs/sanmopia_web/application/libraries/Kcppayment.php:39, source-refs/sanmopia_web/application/libraries/Kcppayment.php:252, source-refs/sanmopia_web/application/libraries/Kcppayment.php:392, source-refs/sanmopia_web/application/libraries/Kcppayment.php:447, source-refs/sanmopia_web/application/libraries/Kcppayment.php:455, source-refs/sanmopia_web/application/libraries/Kcppayment.php:456, source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31, source-refs/sanmopia-admin/application/libraries/Kcppayment.php:39, source-refs/sanmopia-admin/application/libraries/Kcppayment.php:40 | pricing_settlement / PartialPaymentRefund, ProviderPartialRefundCapabilitySnapshot, PartialPaymentRefundProviderCommandPlan | Source KCP payment response exposes partcanc_yn as provider capability evidence, but refund command still uses full cancel mod_type=STSC; no partial-cancel request fields were found. 2026-07-06 backend foundation: backend 90e4b00, contract 75aaebe now require explicit refundAmountKrw, remaining refundable amount, provider partial-refund support decision, and append-only provider status event before any Kill Bill command can be planned. Repair execution/result-recording persistence now proves one backend Kill Bill refund execution boundary for planned repairs. Remaining runtime work: persist provider partial-refund capability from payment closeout, bind the non-repair partial-refund execution path, reconcile provider webhooks, expose operator-facing repair/read projection, and bind settlement ledger reversal. |
| Payment-change closeout | source-refs/sanmopia_web/application/views/modal/modal_change_payment.php:3-25, source-refs/sanmopia_web/static/js/mypage/reservation_changePayment.js:43, source-refs/sanmopia_web/static/js/mypage/reservation_changePayment.js:57, source-refs/sanmopia-user-old/src/design-system/ui-kit/islands/ChangePaymentModalIsland.tsx:41-70, source-refs/sanmopia-user-old/src/design-system/ui-kit/islands/ChangePaymentModalIsland.tsx:91-100, source-refs/sanmopia-user-old/src/data/mock/mypage/reservationChangePayment.ts:30-90, source-refs/sanmopia_web/application/models/Payment_model.php:856, source-refs/sanmopia_web/application/models/Payment_model.php:893, source-refs/sanmopia-admin/application/models/Payment_model.php:4507, source-refs/sanmopia-admin/application/models/Payment_model.php:4514 | pricing_settlement / PaymentChangeCloseout | UI-entered change amount creates PAYMENT_CHANGE_TB, unpaid old rows are deleted, provider context and DEPOSIT_DT are stored, and admin status 2 sets COMPLETED_DT. Legacy PHP and the old Astro customer modal both recompute convertible amount from coupon, pre-reservation, voucher add-on, service type, and hardcoded Korean copy; the old Astro fixture then copies 8400000, 2100000, and 500000 product/payment amounts into customer-visible scenarios. Modern backend owns amount validation, catalog-issued payment-change fixture templates, deposited/completed timestamps, customer-facing amount breakdown/copy, admin closeout, and audit trail. 2026-07-06 backend follow-up: payment-change pre-registration and paid verification now reject provider-returned amount drift against the frozen mother-payable adjustment before saving pre-registration, payment receipt, or settlement continuation. |
| Coupon restore and product coupon regeneration | source-refs/sanmopia_web/application/models/Coupon_model.php:529, source-refs/sanmopia_web/application/models/Coupon_model.php:541, source-refs/sanmopia-admin/application/models/Coupon_model.php:936, source-refs/sanmopia-admin/application/models/Coupon_model.php:947, source-refs/sanmopia-admin/application/models/Coupon_model.php:63, source-refs/sanmopia-admin/application/models/Coupon_model.php:151 | promotion / CouponRestoration, pricing_settlement / RefundSideEffectPlan | Source restores used coupons by resetting USE_FL/USE_DT and logs reuse; admin cancel/stop deletes/recreates product coupon from attendance days. Modern flow needs actor/reason event, entitlement restore, product coupon reset by frozen service-day policy, and repairable outbox. |
| Settlement continuation after branch deposit | source-refs/sanmopia-admin/application/controllers/Calculate.php:219, source-refs/sanmopia-admin/application/controllers/Calculate.php:248, source-refs/sanmopia-admin/application/controllers/Calculate.php:291, source-refs/sanmopia-admin/application/models/Payment_model.php:2977, source-refs/sanmopia-admin/application/models/Payment_model.php:3003, source-refs/sanmopia-admin/application/models/Payment_model.php:4265, source-refs/sanmopia-admin/application/models/Payment_model.php:4386 | pricing_settlement / SettlementContinuation | Source board status 1/3 can become settled 2 or arrears 4; detail/coupon/fee flags mark paid pieces; data-room close sets board STATUS_FL=1 and coupon PAYMENT_STATUS_FL=2. Modern continuation needs board state machine, component-level paid facts, idempotency, and closeout command. |
2026-07-05 Legacy Feature Curator Pass
Section titled “2026-07-05 Legacy Feature Curator Pass”These rows add under-described PHP-side behavior found in reservation/payment, pricing, settlement, caregiver wage, and matching sources. Source names stay adapter evidence only.
| Checklist item | Source evidence | Modern target bounded context | Modern abstraction note |
|---|---|---|---|
| Voucher support subsidy and customer charge display | source-refs/sanmopia_web/application/models/Reservation_model.php:1261-1288, source-refs/sanmopia_web/application/models/Reservation_model.php:1295-1310, source-refs/sanmopia_web/application/models/Reservation_model.php:1318-1331, source-refs/sanmopia_web/application/models/Reservation_model.php:1354-1369, source-refs/sanmopia_web/application/controllers/api/Service.php:749-755, source-refs/sanmopia_web/application/models/Reservation_model.php:3131-3136, source-refs/sanmopia-admin/application/views/reservation_status/reservation_price_table.php:26-35, source-refs/sanmopia-admin/application/views/reservation_status/reservation_price_table.php:84-99, source-refs/sanmopia-admin/application/views/reservation_status/reservation_price_table.php:191-199, source-refs/sanmopia-admin/application/views/reservation_status/reservation_price_table.php:235-240, source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:12-15, source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:81-89, source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:177-180, source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:327-332 | pricing_settlement / VoucherSupportSubsidyChargeSnapshot, pricing_settlement / VoucherServiceBalanceCustomPriceSnapshot, reservation_operations / ReservationChargeFinalization, ReservationPaymentSchedule | Backend foundation now adds VoucherSupportSubsidyChargeSnapshotPolicy, which reuses ReservationPriceSummaryPolicy and freezes service catalog price, public support subsidy, regional support discount, customer-share before credit, coupon/pre-reservation credits, voucher add-ons, deposit/balance split, service balance, customer total due, display label keys, and source evidence. Hidden source side effect: reservation apply recomputes live voucher leftPrice for in-home/special service and writes SERVICE_BALANCE_PRICE plus SERVICE_BALANCE_PRICE_USE_FL=1 back to the reservation. Remaining work: persist snapshot rows, expose generated contract/read model, bind reservation payment schedule, and make voucher service-balance custom price a backend-issued charge-finalization fact with expected reservation/price revision and reporting/settlement invalidation. |
| Product gift coupon timing and cancellation downgrade | source-refs/sanmopia-admin/application/config/constants.php:276-277, source-refs/sanmopia-admin/application/models/Coupon_model.php:72-76, source-refs/sanmopia-admin/application/models/Coupon_model.php:100-103, source-refs/sanmopia-admin/application/models/Coupon_model.php:122-136, source-refs/sanmopia-admin/application/models/Coupon_model.php:225-228, source-refs/sanmopia-admin/application/models/Coupon_model.php:265-284, source-refs/sanmopia-admin/application/models/Coupon_model.php:307-319, source-refs/sanmopia-admin/application/models/Payment_model.php:1225-1250, source-refs/sanmopia-admin/application/models/Payment_model.php:1573-1585, source-refs/sanmopia-admin/application/models/Payment_model.php:3883-3887 | promotion_entitlement / ProductGiftCouponEligibility, pricing_settlement / CancelledGiftCouponCommissionPolicy | Attendance-based actual service days choose no coupon/1-week/2-week grant, publish date uses 3-day or 8-day offset by service term and working type, and settlement uses 20,000/30,000 coupon value plus 5,000/10,000 cancelled-coupon fee. Replace with versioned entitlement and commission policies. |
| Caregiver wage helper and tax election | source-refs/sanmopia-manager/application/helpers/salary_helper.php:42-64, source-refs/sanmopia-manager/application/helpers/salary_helper.php:78-99, source-refs/sanmopia-manager/application/helpers/salary_helper.php:151-198, source-refs/sanmopia-manager/application/helpers/salary_helper.php:206-226, source-refs/sanmopia-manager/application/views/pay_info_detail.php:100-103, source-refs/sanmopia-manager/application/views/pay_info_detail.php:182-190, source-refs/sanmopia-manager/application/views/pay_info_detail.php:234-240, source-refs/sanmopia-admin/application/controllers/Manager.php:1142-1165, source-refs/sanmopia-admin/application/controllers/Manager.php:1917-1959 | pricing_settlement / CaregiverCompensationQuote, CaregiverPayoutInstruction, CaregiverTaxElection | Main/sub role, sort, custom salary, service-balance override, voucher pure additional price, in-home/special add pay, 4대보험 vs 3.3% tax election, and 2022-03-29 cutoff must be immutable payout quote inputs. Manager/caregiver portals render backend quote only. |
| Branch settlement remittance account and fee catalog | source-refs/sanmopia-admin/application/config/constants.php:286-287, source-refs/sanmopia-admin/application/views/calculate_detail.php:190-193, source-refs/sanmopia-admin/application/views/calculate_detail.php:256-283, source-refs/sanmopia-admin/application/views/calculate_detail.php:360-386, source-refs/sanmopia-admin/application/views/calculate_detail.php:941-954, source-refs/sanmopia-admin/application/models/Payment_model.php:1526, source-refs/sanmopia-admin/application/models/Payment_model.php:1550, source-refs/sanmopia-admin/application/models/Payment_model.php:2081-2088, source-refs/sanmopia-admin/application/controllers/Common.php:106 | pricing_settlement / SettlementRemittanceAccountSnapshot, SettlementPricingPolicy | Hardcoded HQ account text, normal/voucher account columns, voucher fee 15,000, manual gift-fee count/price fields, membership, delivery, and cancelled coupon fees must be effective-dated settlement policy snapshots with branch/HQ/Danbee scope. |
| Voucher price import and support catalog validation | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5028-5053, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5078-5108, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5158-5183, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5247-5252, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5353-5360, source-refs/sanmopia_web/application/controllers/api/Service.php:913-914 | pricing_settlement / VoucherPriceCatalogImport, SupportSubsidyRuleCatalog, service_calendar / ServiceCalendarOptionPriceCatalog | Spreadsheet import validates service price, government support, own price, before/after-tax caregiver pay, in-home conversion, Saturday/holiday options, and consume-type version. Modern import needs dry-run diff, validation artifact, policy version, and rollback audit before booking/payment use. |
| Customer smart matching preview and pick override | source-refs/sanmopia_web/application/controllers/Service.php:603-622, source-refs/sanmopia_web/application/controllers/api/Service.php:592-624, source-refs/sanmopia_web/application/controllers/api/Service.php:787-810, source-refs/sanmopia_web/application/models/Manager_matching_model.php:16, source-refs/sanmopia_web/application/models/Manager_matching_model.php:73-74, source-refs/sanmopia_web/application/models/Smart_matching_model.php:219-235, source-refs/sanmopia_web/application/models/Smart_matching_model.php:248-252 | caregiver_assignment / CustomerSmartMatchingPreferenceSnapshot, CandidatePreviewPolicy, CaregiverPickOverrideCommand | Customer PHP flow writes pet/religion/preference/personality facts, previews top 5 candidates with class and branch filters, then direct pick deletes matching facts and sets PICK_MANAGER_FL. Modern flow needs append-only preference revision, deterministic preview reason, override command, and no silent preference deletion. |
2026-07-05 Static JS/Admin View Curator Pass
Section titled “2026-07-05 Static JS/Admin View Curator Pass”These rows add hidden browser/admin/mobile-adjacent behavior found after the PHP pass. Source ids and app schemes are adapter evidence only.
| Checklist item | Source evidence | Modern target bounded context | Modern abstraction note |
|---|---|---|---|
| Admin reservation status command surface | source-refs/sanmopia-admin/application/config/constants.php:120-160, source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:82-147, source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:244-256, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:271-320, source-refs/sanmopia-admin/application/views/reservation_status/pre_reservation_detail.php:90-118, source-refs/sanmopia-admin/static/js/reservation_status/pre_reservation_detail.js:299-328 | reservation_operations / ReservationLifecycleCommandSurface, SourceReservationStatusTransitionCatalog, ReservationWorkspaceConflictGuard | Admin views build allowed status options from raw ids, skip 18 in one selector, post freservation-status inside broad detail forms, and gate matching UI by 15/16/9. Backend must expose command availability, expected revision, disabled reason, and side-effect plan. |
| Admin overwrite flows for branch, memo, and price version | source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:216-231, source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:1463-1478, source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:22-28, source-refs/sanmopia-admin/application/models/Branch_model.php:23-46, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:1029-1056, source-refs/sanmopia-admin/application/controllers/Reservation.php:1823-1846, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:1078-1086, source-refs/sanmopia-admin/application/models/Reservation_model.php:5252-5256 | reservation_operations / ReservationBranchHandoffCommand, ReservationPriceVersionRequoteCommand, ReservationMemoRevision; pricing_settlement / RequoteImpactPlan | Branch handoff posts only reservation/branch ids, price version JS hardcodes version labels, and memo onchange writes directly. Replace with typed commands carrying actor, reason, expected revision, before/after diff, pricing/assignment/settlement impact, and conflict UX. |
| Admin care-team matching overlay and slot rules | source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:44-53, source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:842-958, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:554-564, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:591-618, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:680-728, source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:32-42, source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:181-201 | caregiver_assignment / CareTeamSlotPolicy, AssignmentCandidateScoreProjection, AssignmentOverrideCommand, AssignmentChangeHistoryReadModel | Admin modal owns main/sub slot labels, multi-caregiver count rules, duplicate caregiver rejection, score display, religion/preference match highlights, distance/transit text, and change-history rendering. Backend must return slot policy, candidate reasons, override eligibility, and immutable assignment history. |
| Native payment/deep-link bridge catalog | source-refs/sanmopia_android/app/src/main/java/com/sanmopia/app/networks/PaymentScheme.java:7-25, source-refs/sanmopia_android/app/src/main/java/com/sanmopia/app/web/SanmopiaClient.java:33-70, source-refs/sanmopia_android/app/src/main/java/com/sanmopia/app/web/SanmopiaClient.java:73-103, source-refs/sanmopia_ios/ios_sanmopia_app/Info.plist:54-91, source-refs/sanmopia_ios/ios_sanmopia_app/ViewController.swift:43-47, source-refs/sanmopia_ios/ios_sanmopia_app/ViewController.swift:105-108, source-refs/sanmopia_ios/ios_sanmopia_app/ViewController.swift:197-202, source-refs/sanmopia_manager_android/app/src/main/java/com/sanmopia/manager/MainActivity.java:301-307 | customer_engagement / MobileAppEntryPoint; pricing_settlement / PaymentRedirectCapability; platform / NativeShellBridgePolicy | Native shells whitelist/payment-route app schemes, open market fallbacks, generic non-http URLs, web dialogs, push URLs, and tel links. Modern contracts need versioned bridge capabilities and allowlisted destinations; payment amount/purpose stays backend-frozen before any native redirect. |
2026-07-05 Coupon/Settlement Detail Addendum
Section titled “2026-07-05 Coupon/Settlement Detail Addendum”These rows narrow earlier broad coupon and settlement rows with source-specific recognition timing and fee authority.
| Checklist item | Source evidence | Modern target bounded context | Modern abstraction note |
|---|---|---|---|
| Product gift coupon settlement recognition timing | source-refs/sanmopia-admin/application/models/Coupon_model.php:263-320, source-refs/sanmopia-admin/application/models/Payment_model.php:896-916, source-refs/sanmopia-admin/application/models/Payment_model.php:918-933, source-refs/sanmopia-admin/application/models/Payment_model.php:1554-1592, source-refs/sanmopia-admin/application/views/calculate_detail.php:1091-1109, source-refs/sanmopia-admin/static/js/calculate_detail.js:1053-1080 | promotion_entitlement / ProductCouponEntitlementSchedule; pricing_settlement / PromotionalCouponCostRecognition, CancelledGiftCouponCommissionPolicy | Source creates product coupons with 3-day/8-day publish dates, but branch settlement recognizes live coupon cost by user grant month and deleted coupon commission by SERVICE_START_DT + 15 days; admin UI can still select rows and add manual cancelled-coupon totals. Freeze entitlement schedule, recognition period, line kind, rate band, paid-state revision, and manual override audit in backend. |
| Branch settlement fee catalog and client-total authority | source-refs/sanmopia-admin/application/models/Payment_model.php:838-845, source-refs/sanmopia-admin/application/models/Payment_model.php:872-893, source-refs/sanmopia-admin/application/models/Payment_model.php:941-945, source-refs/sanmopia-admin/application/models/Payment_model.php:1180-1208, source-refs/sanmopia-admin/application/models/Payment_model.php:1223-1250, source-refs/sanmopia-admin/application/views/calculate_detail.php:1183-1198, source-refs/sanmopia-admin/application/views/calculate_detail.php:1407-1424, source-refs/sanmopia-admin/static/js/calculate_detail.js:939-1047, source-refs/sanmopia-admin/static/js/calculate_detail.js:1053-1144 | pricing_settlement / SettlementPricingPolicy, BranchSettlementFeeCatalog, SettlementStatementLineProjection, SettlementCompletionReview | Source mixes monthly branch membership overrides, voucher 15,000 fee, editable delivery price, coupon/cancelled-coupon flags, manual etc rows, and JS recomputed result totals. UI must submit line acknowledgements or manual adjustment commands with expected revisions; backend owns catalog rates, eligibility, totals, paid flags, and arrears/settled review. |
2026-07-05 Data-Room/Document Export Addendum
Section titled “2026-07-05 Data-Room/Document Export Addendum”These rows add export/render-specific gaps found in settlement data room and daily-report document generation paths.
| Checklist item | Source evidence | Modern target bounded context | Modern abstraction note |
|---|---|---|---|
| Settlement workbook render-time formula authority | source-refs/sanmopia-admin/application/controllers/Calculate.php:569-577, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3750, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3792-3808, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3864-3880, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3893-3910, source-refs/sanmopia-admin/static/js/calculate_detail.js:331-336 | pricing_settlement / SettlementExportDatasetSnapshot; document_reporting / SettlementExportWorksheetPolicy, SettlementArtifactVersion | Source builds type18 settlement workbooks directly from current board/payment rows, inserts rows after template line 23, recalculates coupon payment-method fees in the renderer, and writes SUM formulas before streaming php://output. Export worker must consume frozen settlement lines, formula policy version, dataset revision, artifact checksum, and signed download grant; renderer must not create financial authority. |
| Document template slots, static PDFs, and converter boundary | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:15-39, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-4198, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4284-4430, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4434-4598, source-refs/sanmopia_web/application/controllers/api/ReservationDocument.php:21-54, source-refs/sanmopia_web/application/views/mypage/reservation_document.php:45-123 | document_reporting / PrintableTemplateRegistry, DocumentRenderProviderAdapter, StaticPdfTemplateArtifact, DocumentRenderAttempt, DocumentAccessGrant | Source mixes numeric XLSX slots, static PDF files, temp ZIP files, external XLSX-to-PDF conversion, base64/binary response shapes, token query URLs, and direct browser/app download handoff. Modern registry must version template kind/render format, isolate converter credentials in provider config, persist render attempts/artifacts, and expose only scoped signed grants. |
| Daily report finality parity across save, export, and reward | source-refs/sanmopia_web/application/models/Report_model.php:340-381, source-refs/sanmopia_web/application/models/Report_model.php:467-509, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4030-4050, source-refs/sanmopia_web/application/controllers/api/Report.php:79-109, source-refs/sanmopia_web/application/models/Report_model.php:553-615 | care_delivery / DailyCareReportServiceDatePolicy; customer_daily_report_review / ReportFinalityDecision, CustomerDailyReportReviewRewardGrant; document_reporting / DailyReportArtifactSeriesSelection | Source marks stop day as final in report lists/export templates, but customer save/rating branches only on service end date, while reward grant counts eligible report dates. One backend finality/readiness decision must drive report save, main/assistant rating requirement, stop/resume windows, artifact series, and once-per-reservation reward grant. |
2026-07-05 CaveCrew Explorer A Hidden Feature Delta
Section titled “2026-07-05 CaveCrew Explorer A Hidden Feature Delta”These rows focus on smaller legacy behaviors not fully captured by broader pricing, refund, settlement, matching, family, document, and reporting rows.
| Checklist item | Source evidence | Modern target bounded context | Modern abstraction note |
|---|---|---|---|
| Branch request notification routing and special secondary recipient | source-refs/sanmopia_web/application/controllers/api/Reservation.php:141-190, source-refs/sanmopia_web/application/controllers/api/Reservation.php:192-228 | reservation_operations / ReservationCustomerChangeRequestWorkflow; communication_delivery / BranchActionNotificationRoutingPolicy | Customer cancel, stop, and change requests are not only status changes: source sends branch AlimTalk, distinguishes instant cancel from cancel request, and special-cases branch 20 with a second phone number. Modern workflow must freeze request kind, instant-vs-approval path, branch routing recipients, notification template, actor, and idempotency before reservation/refund side effects run. |
| Pre-reservation cancellation refund tied to status write | source-refs/sanmopia-admin/application/models/Reservation_model.php:5560-5577, source-refs/sanmopia-admin/application/models/Reservation_model.php:5580-5595 | pricing_settlement / PreReservationCancellationRefundIntent; reservation_operations / PreReservationStatusTransitionCommand | Admin status save to legacy status 9 triggers KCP refund lookup for paid voucher pre-reservation payment type 6 by extracting ordr_idxx, tno, and pay method from JSON. Modern transition must create an explicit refund intent, provider context snapshot, ledger reversal, and status-transition result instead of hiding refund inside a generic status update. |
| Data-room inbox/outbox board with branch-scoped file grants | source-refs/sanmopia-admin/application/controllers/DataRoom.php:97-197, source-refs/sanmopia-admin/application/models/Data_room_model.php:22-80, source-refs/sanmopia-admin/application/models/Data_room_model.php:82-184, source-refs/sanmopia-admin/application/views/table/data_room/table_other_post_list.php:1-114 | document_reporting / BranchDocumentMailbox; document_reporting / DocumentAttachmentGrant; operator_access / BranchDocumentMailboxPermission | Legacy “other data room” is a send/receive mailbox, not plain CMS content. HQ/branch visibility depends on write branch, receive branch, 36 headquarters fallback, board type, fixed posts, and edit/delete capability. Modern model needs mailbox direction, participant branch snapshots, attachment grants, immutable file versioning, and actor-scoped edit/delete decisions. |
| All-document bundle composition by service type | source-refs/sanmopia-admin/application/controllers/DataRoom.php:311-386, source-refs/sanmopia-admin/application/views/data_room/form_reservation_list.php:130-208, source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:66-129 | document_reporting / ReservationDocumentBundlePolicy; document_reporting / ReservationDocumentSelectionToken | Legacy form id 16 composes different document id arrays for voucher vs normal service and posts selected reservation ids through a hidden iframe. Modern export must move service-type bundle rules, single-vs-multi select constraints, reservation eligibility, and selection token validation into backend before artifact rendering. |
| Caregiver one-line review visibility moderation | source-refs/sanmopia-admin/application/models/Manager_model.php:2194-2217, source-refs/sanmopia-admin/application/models/Manager_model.php:2219-2240, source-refs/sanmopia-manager/application/views/manager_info.php:433-435 | care_delivery / CaregiverReviewVisibilityDecision; customer_engagement / PublicCaregiverReviewProjection | Source lets admin hide/show customer one-line comments separately for main and sub caregivers, while manager profile renders only SHOW_FL = 1. Modern review projection needs moderation command, actor/reason/audit, primary/sub caregiver scope, and public-read projection; daily report rating and public profile display must not read raw flags directly. |
| Caregiver-to-HQ request and reply workflow | source-refs/sanmopia-manager/application/controllers/User.php:373-425, source-refs/sanmopia-manager/application/models/Request_model.php:11-52, source-refs/sanmopia-admin/application/models/Office_management_model.php:259-284, source-refs/sanmopia-admin/application/models/Faq_model.php:86-100 | caregiver_engagement / CaregiverHeadquartersRequestThread; communication_delivery / HeadquartersRequestNotificationPolicy | Manager app writes “message to HQ” rows, pushes a hardcoded phone notification, lets caregiver edit/delete own requests, and admin later stores ANSWER plus ANSWER_DATE. Modern flow needs request thread, reply state, assignee/actor audit, notification recipient policy, retention rules, and no hardcoded phone dependency. |
Legacy UI/PHP Calculation Migration Rule
Section titled “Legacy UI/PHP Calculation Migration Rule”Legacy UI/PHP calculations are source evidence only. They must migrate to backend domain policy, application commands, or backend-owned read models before frontend work is considered complete.
- Money, tax, payroll, subsidy, coupon, fee, refund, and settlement arithmetic
belongs in
pricing_settlement,reservation_operations, or the owning application command/read-model layer. - Status buttons, detail tabs, document readiness, report obligations, payment actions, and actor-visible fields belong in backend projections with disabled reasons, command targets, revision, and policy/catalog version.
- Frontend portals may render Nanostores state from generated clients and submit explicit commands. They must not recompute totals, map source status ids, infer workflow state, choose payment routes, build document URLs, or decide SpiceDB/OPA capability outcomes.
- Source terms, table names, numeric ids, and UI flags stay in adapters, source-evidence docs, or versioned compatibility catalogs. They must not name target aggregates, command payloads, or frontend state contracts.
CaveCrew Source Gap Queue
Section titled “CaveCrew Source Gap Queue”This queue comes from the 2026-07-05 legacy source pass. Source behavior here is evidence only: modern work must improve the model, move UI/PHP calculations into backend commands/projections, and keep source-era names behind adapters or source evidence.
Latest focused source-status/payment mapping lives in Status Payment Settlement Source Map. Use it to refine existing rows instead of adding duplicate checklist entries for settlement statuses, payment/refund ids, document ids, and caregiver payout or matching source terms.
Current Closeout Flow Marker
Section titled “Current Closeout Flow Marker”Actor labels in gap docs map to target role contracts: Branch Operator means
BranchOwner, HQ Admin means HeadOfficeManager, Mother means
Mother/FamilySponsor, and Caregiver means CareManager. The current
backend closeout target is one backend-owned path:
flowchart LR Booking[Booking] --> Payment[Payment closeout] Payment --> Balance[Service-balance closeout] Balance --> Receipt[Caregiver receipt] Receipt --> Settlement[Branch/HQ settlement continuation] Branch[Branch Operator] --> Balance Caregiver[Caregiver] --> Receipt HQ[HQ Admin] --> Settlement Mother[Mother] --> Booking
Persistence rule: Supabase remains the durable ledger/read/RLS layer. Service role adapters may write closeout ledgers and workflow rows; actor portals read RLS-scoped projections with caller JWTs. Use RPC for multi-table booking or closeout commits when partial Data API writes would expose mismatched payment, service-balance, receipt, or settlement state.
Remaining unchecked legacy PHP closeout gaps:
- Service-balance PHP flags and zero-balance auto-complete must be expressed
as backend
ServiceBalancePaymentCloseoutdecisions, not copied column names. - Primary/sub caregiver receipt flags must map to assignment-key recipients, caregiver role, and handoff order.
- Branch/HQ settlement continuation must consume closeout facts from the same Supabase financial lifecycle rows used by payment closeout.
- Operator repair/audit screens must cover closeout conflict, retry, and receipt correction before legacy PHP board parity is closed.
CaveCrew Reconciliation Delta 2026-07-05
Section titled “CaveCrew Reconciliation Delta 2026-07-05”This pass reconciles new legacy evidence with existing queue rows instead of adding duplicate backlog items. Treat these as strengthening requirements for the named modern slices.
| Legacy evidence | Existing modern target | Reconciliation requirement |
|---|---|---|
source-refs/sanmopia-admin/application/config/constants.php:291, source-refs/sanmopia_web/application/controllers/api/Service.php:296 | pricing_settlement / PriceCatalogVersionResolution, ReservationPriceVersionSnapshot | Freeze the resolved normal/voucher catalog version on extension and continuation flows before payment, refund, or settlement handoff. |
source-refs/sanmopia-admin/application/models/Reservation_model.php:647 | pricing_settlement / AdditionalServiceChargePolicy | Replace source string branches for Saturday, holiday, and regional add-ons with typed charge components and parity tests. |
source-refs/sanmopia-admin/application/models/Reservation_model.php:4153, source-refs/sanmopia_web/application/controllers/api/Service.php:367 | service_calendar / ServicePeriodCalendarPolicy, RegionalBenefitServiceDayBonus | Service term, weekend/holiday selection, substitute holiday, and regional service-day bonus must be one backend calendar decision that invalidates quote, matching, report, refund, and settlement projections. |
source-refs/sanmopia-admin/application/models/Reservation_model.php:5985, source-refs/sanmopia-admin/application/models/Reservation_model.php:6131, source-refs/sanmopia_web/application/controllers/api/Service.php:749 | pricing_settlement / VoucherServiceAddOnPolicy, VoucherPureAdditionalServiceBalance | Voucher in-home/special conversion and custom service-balance deltas must be typed backend decisions; Korean label maps remain source-adapter evidence only. |
source-refs/sanmopia_web/application/models/Payment_model.php:383, source-refs/sanmopia-admin/application/models/Reservation_model.php:5581, source-refs/sanmopia_web/application/models/Payment_model.php:856 | pricing_settlement / ReservationRefundCloseout, PreReservationRefundPolicy, PaymentChangeAdjustment | Refund, pre-reservation refund, payment-change, provider context, ledger reversal, and receipt artifacts must close through the Kill Bill-backed ledger path with focused KCP parity tests. |
source-refs/sanmopia-admin/application/models/Payment_model.php:96, source-refs/sanmopia-admin/application/models/Payment_model.php:828, source-refs/sanmopia-admin/application/models/Payment_model.php:4382 | pricing_settlement / ExternalCounterpartySettlementWorkflow, BranchSettlementWorkflow, HeadOfficeSettlementLedger | Keep Danbee, branch, HQ, and inter-office settlement as separate workflows with explicit completion gates, statement revisions, and actor-scoped audit. |
source-refs/sanmopia-admin/application/models/Payment_model.php:3909 | pricing_settlement / PaymentMethodFeePolicy | Compare legacy payment-version fee rates with modern payment-method fee snapshots; fees are catalog facts, not UI/view calculations. |
source-refs/sanmopia-admin/application/models/Matching_model.php:44, source-refs/sanmopia-admin/application/models/Matching_model.php:760 | caregiver_assignment / CaregiverMatchScore, CaregiverTravelTimeEstimate | Matching score must freeze preference, availability, pet exclusion, grade, branch scope, and travel-time freshness instead of recomputing opaque source ordering. |
source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:21, source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:112 | pricing_settlement / CaregiverPayoutInstruction, CaregiverTaxElection | Main/sub caregiver payout rows need role slot, tax election, memo, grade, assignment term, attendance, and confirmation evidence as immutable payout instructions. |
source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:75-138, source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:421-451, source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:458-466, source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:8-21, source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:80-95, source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:111-180, source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:186-205, source-refs/sanmopia_web/application/controllers/api/Payment.php:89-113, source-refs/sanmopia_web/application/controllers/api/Payment.php:353-382, and source-refs/sanmopia_web/application/controllers/MyReservation.php:149-158 | pricing_settlement / MotherVisibleChargeSummary, pricing_settlement / ReservationPaymentActionAvailability, pricing_settlement / CustomerPaymentInstructionProjection, pricing_settlement / VirtualAccountInstructionDisplayGrant | Mother-facing money totals, coupons, pre-reservation offsets, voucher add-on subtraction, payment button visibility, virtual-account display, and deposit/balance submit gates must be backend projections. Legacy views/controllers infer allowed payment actions from mutable PAYMENT_INFO Korean status strings, reservation status ids, service end date, local PRICE_TABLE fallback totals, and provider JSON. Modern backend must issue purpose-specific action/read-model rows with amount source, allowed methods, disabled reason, provider instruction reference, expected payment revision, and refresh/revoke facts after refund, closeout repair, virtual-account lifecycle movement, or service-balance instruction changes. Frontend remains display-only. |
source-refs/sanmopia_web/application/controllers/api/Service.php:411 | reservation_operations / ServicePeriodPlan, ServiceDayOccurrence | Voucher step3 must ignore forged browser endDate; backend recomputes from start date, regional service-day bonus, selected Saturday/holiday rows, and freezes occurrence snapshots. |
source-refs/sanmopia_web/application/models/Payment_model.php:233 | pricing_settlement / CouponPrepaymentQuote, promotion_entitlement / PromotionEntitlement | Coupon plus pre-reservation credit needs parity tests for own price greater/equal/less than prepayment, emits one entitlement fact, and prevents double discount. |
source-refs/sanmopia_web/static/js/mypage/reservation_changePayment.js:43, source-refs/sanmopia_web/application/models/Payment_model.php:856 | pricing_settlement / PaymentAdjustmentQuote, PaymentChangeAdjustment | Payment-change maximum must derive from frozen charge snapshot; reject UI amount above eligible, and superseded unpaid rows need explicit cancel event instead of silent delete. |
source-refs/sanmopia_web/application/models/Reservation_model.php:1277, source-refs/sanmopia_web/application/models/Reservation_model.php:3177 | pricing_settlement / VoucherInhomeAddOnQuote | Voucher in-home/special add-on must quote by price version, detail, baby type, delivery count, consume-type version, and service days without runtime date/label branching. |
source-refs/sanmopia-admin/application/models/Payment_model.php:4155 | pricing_settlement / ServiceBalanceOverrideDecision, VoucherPureAdditionalServiceBalance | Service-balance quote equals manager before-tax pay plus selected Saturday/holiday add-day charges plus non-extra add-ons times canonical service-day count; voucher pure-additional closeout subtracts the backend voucher add-on decision from the posted service-balance amount. |
source-refs/sanmopia_web/application/controllers/api/Payment.php:456 | pricing_settlement / PaymentProviderTemplatePayload, PaymentProductCommunicationRoute | Pre-reservation virtual-account notice must render frozen realPrePrice, never hardcoded 100000; zero amount closes out without provider wait. |
source-refs/sanmopia_web/application/models/Payment_model.php:383 | pricing_settlement / PaymentCloseout, RefundQuote, PaymentRefundIntent | No gateway context or zero paid rows still persist zero-gateway refund quote and ledger fact before coupon, benefit, or settlement unlock. |
source-refs/sanmopia-admin/application/controllers/Calculate.php:248-309, source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3011, source-refs/sanmopia-admin/application/models/Payment_model.php:3033-3051, source-refs/sanmopia-admin/application/models/Payment_model.php:4302-4308, source-refs/sanmopia-admin/application/models/Payment_model.php:4382-4419 | pricing_settlement / SettlementCompletionReview, SettlementLineAcknowledgement, SettlementComponentAcknowledgementRevision | Board status must derive from membership, delivery, cancelled coupon, detail rows, coupon rows, and manual adjustment acknowledgements into request 1, complete 2, arrears/re-request 3, idempotently and with expected statement/component revisions. Branch/HQ UI may acknowledge projected components only; mutable STATUS_FL, checkbox state, and reservation-id-only detail ids are legacy evidence. |
source-refs/sanmopia-admin/application/models/Payment_model.php:3748 | pricing_settlement / PaymentProductPlan, LegacyPaymentVersionCompatibility | Voucher payment split: version 0 and adjusted own price over 100000 creates 10% deposit/90% balance, <=100000 deposits all, version 1 creates single obligation after benefit. |
source-refs/sanmopia-admin/static/js/calculate_detail.js:769-818, source-refs/sanmopia-admin/static/js/calculate_detail.js:930-1079, source-refs/sanmopia-admin/application/controllers/Calculate.php:155-190, source-refs/sanmopia-admin/application/controllers/Calculate.php:219-240, source-refs/sanmopia-admin/application/models/Payment_model.php:534-573, source-refs/sanmopia-admin/application/models/Payment_model.php:658-723, source-refs/sanmopia-admin/application/models/Payment_model.php:2861-2878 | pricing_settlement / SettlementArithmeticDecision, SettlementManualAdjustmentLine, SettlementClientTotalComparison | Browser settlement totals, voucher 15,000 count math, delivery price, cancelled-coupon fee, monthly fee, and manual etc rows become comparison evidence only. Canonical backend must recompute statement totals from settlement ledger/component projections and reject mismatched total, fee, result, delivery, coupon-fee, or manual-adjustment payloads before mutating payment flags, coupon flags, board id, or branch/HQ request state. |
| Source evidence | Modern target | Status | Required backend replacement |
|---|---|---|---|
source-refs/sanmopia-admin/application/controllers/Reservation.php, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js | reservation_operations / reservation_collaboration | Partial | ReservationOperationWorkspace with narrow commands, expected revision, conflict log, return-state token, and no history.back() last-write-wins save. |
source-refs/sanmopia_web/application/controllers/api/Reservation.php, source-refs/sanmopia_web/application/models/Report_model.php | reservation_operations / service_suspension | Partial | Durable ServiceSuspensionInterval plus quote, assignment, coupon, report, and notification impact outbox. |
source-refs/sanmopia_web/static/js/step3.js, source-refs/sanmopia_web/application/models/Reservation_model.php | reservation_operations / service_period, reservation_operations / service_calendar | Partial | Immutable ServicePeriodPlanningRequest, ServicePeriodPlan, and ServiceDayOccurrence snapshots for weekly, extension, weekend, holiday, substitute holiday, and branch holiday rules. Domain owns service-period policy language; application contracts own incoming command payloads and legacy compatibility fields. |
source-refs/sanmopia-admin/application/models/Branch_model.php, source-refs/sanmopia_web/application/controllers/api/Service.php | branch_operations / service_area_policy | Partial | Booking-bound ServiceAreaDecisionSnapshot with address levels, serviceability, consultation-only, impossible-region, and policy evidence. |
source-refs/sanmopia_web/application/controllers/api/Payment.php, source-refs/sanmopia_web/application/models/Payment_model.php, source-refs/sanmopia_web/application/controllers/api/Payment.php:31-33 | pricing_settlement / CustomerPaymentInstruction, PaymentProviderApprovalRequest | Partial | CustomerPaymentInstruction chosen from PaymentProductPlan, not raw payment-type flags; freeze purpose, amount, allowed method, route, fee, receipt, and settlement participation before provider handoff. Source still reads KCP good_mny from request data despite the inline warning that amount/return URL should come from server session. 2026-07-05 backend follow-up: ReservationPaymentWorkflowHandler rejects verified provider results whose returned amount differs from the frozen workflow command amount, blocks approved-charge finalization, blocks settlement continuation, and records a failed workflow reason. Remaining proof: bind every pre-registration and webhook entrypoint to the frozen backend amount for deposit, balance, pre-reservation, coupon, and payment-change payments. |
source-refs/sanmopia_web/application/models/Payment_model.php legacy gateway refund/coupon paths | pricing_settlement / payment_refund | Partial | Kill Bill-backed CancellationRefundSaga linking reservation state, coupon/benefit restore, provider events, receipt artifact, ledger reversal, partial refund, and operator override. |
source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php, PAYMENT_CHANGE_TB | pricing_settlement / payment_change_adjustment | Partial | Frozen PaymentChangeAdjustmentAmountBreakdown, workflow status projection, provider event linkage, settlement continuation, and no operator-side recompute. |
source-refs/sanmopia-admin/application/controllers/Calculate.php, source-refs/sanmopia-admin/application/models/Payment_model.php | pricing_settlement / settlement_statement | Partial | SettlementStatementKind, typed line contexts, effective-dated amount/date policies for external counterparties (source evidence includes Danbi/Danbee), branch, headquarters, inter-office, and repair statements. |
source-refs/sanmopia-admin/static/js/form_reservation_list.js, source-refs/sanmopia-admin/application/controllers/DataRoom.php | pricing_settlement / settlement_data_room | Partial | Persisted ArtifactRequest, repair/download state, signed URL refresh, export audit, and no hidden iframe/raw GET download handoff. |
source-refs/sanmopia-admin/application/models/Matching_model.php | caregiver_assignment / caregiver_matching | Partial | CandidateSnapshot -> AssignmentDecision with distance, branch scope, pet, schedule, grade, workload, and deterministic tie-breaker evidence. |
source-refs/sanmopia-admin/application/models/Matching_model.php:62-118, :144-172, :724-855 | caregiver_assignment / CaregiverCandidateOrderingPolicy, CaregiverCandidateRecommendationSet | Partial | Backend commit 05832cd canonicalizes CaregiverCandidateOrderingPolicy over the older generic ranking name while keeping CandidateRankingPolicy and CandidateRankingPolicyPayload as compatibility aliases. The policy freezes score, distance, travel-duration, deterministic tie-breaker component order, source evidence keys, and replacement for source RAND(userId) / RAND(reservationId) ties. Backend commit f07313b adds CaregiverCandidateRecommendationSet, Pydantic payload roundtrip, Supabase table sanmopia_caregiver_candidate_recommendation_sets, repository save/load methods, and focused tests. Recommendation-set persistence freezes reservation revision, service dates, branch/class/search scopes, candidate limit, optimization input, optimization decision, ranked/excluded counts, and full snapshot payload. Existing CaregiverCandidateSnapshot rows keep pet fact, schedule proof, score components, distance/travel evidence, tie seed, and provider result snapshot. 2026-07-09 backend follow-up: OR-Tools assignment optimization now applies deterministic score-tie ordering by policy score, known/near distance, then caregiver id, so equal-score assignment plans no longer depend on solver tie behavior. 2026-07-09 backend follow-up 2: provider-unavailable and provider-fallback travel evidence now exclude candidates before ranking with stable provider_unavailable / provider_fallback_used reason codes; measured duration-only evidence can still rank with an explicit missing-distance penalty of zero. Remaining work: remove raw SQL search/date interpolation in adapters, persist any external provider freshness repair decisions needed by runtime, and bind final assignment API/UI to ordered recommendation sets. |
source-refs/sanmopia-manager/application/helpers/salary_helper.php | pricing_settlement / caregiver_compensation | Partial | Payout-ready CaregiverPayoutInstruction, role/handoff payout slot projection, grade snapshot, assignment term, attendance facts, and no read-time salary recompute. |
source-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:4-115, :627-639; source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:14-24, :75-86, :155-260; source-refs/sanmopia-admin/application/controllers/Manager.php:1007-1008, :1133-1183, :1225-1235, :1300-1335; source-refs/sanmopia-admin/application/models/Reservation_model.php:2453-2768, :2880-2964, :2945-3041, :3095-3147; source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:21-52, :112-170 | pricing_settlement / AdminCaregiverPayoutStatementProjection, CaregiverPayoutAdjustmentCommand, CaregiverPayoutCompletionCommand, CaregiverPayoutCompletionAmountGuard, CaregiverTaxElection, CaregiverPayoutMemoRevision, ReservationFinanceSettlementCompletionGate | Partial | Admin salary UX recomputes service weeks/days, weekend/holiday days, rental delivery fee 10000, additional service totals, voucher custom pay, service-balance overrides, before/after caregiver pay, and tax amount in PHP and JS with inconsistent rounding (round/floor). UI completion posts the visible after-salary value and tax type, but the legacy salary_complete path dispatches to a model method that only flips main/sub payout status, stamps deposit timestamps, and repair-creates a missing payout row; amount/tax changes are separate save commands and completion can auto-move the reservation from settlement to done based on raw payout/service-balance flags. Backend must own payout statement projection, adjustment/receipt commands, role slot key, tax election, completion amount guard, append-only memo/reason audit, mutation proof, idempotency, and settlement-completion gate refresh; frontend/admin-entered values are diagnostics until persisted as revisioned payout facts. |
source-refs/sanmopia-admin/application/models/Manager_model.php, source-refs/sanmopia-admin/application/models/Manager_evaluation_model.php | caregiver_performance_recognition | Partial | CaregiverGradeSnapshot linked to matching, assignment, quote, payout, effective season/window, and operator audit. |
source-refs/sanmopia-admin/application/controllers/Manager.php:174-205, :345-432, :535-542 | caregiver_profile / caregiver_credential_restriction_workflow, caregiver_assignment / caregiver_availability_exception | Pending | Admin profile edits, branch score clamping, career/education/health evidence, and denied work windows need revisioned commands with actor scope, media artifact grant, effective dates, score-cap policy, assignment invalidation, and approval/audit state. Source POST fields and mutable attachment names must not become target contracts. |
source-refs/sanmopia-admin/application/controllers/Manager.php:198-205, :234-240, :1653-1658; source-refs/sanmopia-admin/application/models/Manager_model.php:1618-1627; source-refs/sanmopia-admin/application/models/Manager_evaluation_model.php:526-528 | caregiver_performance_recognition / CaregiverProfileScoreRevisionPolicy, CaregiverProfileScoreRevisionPlan, CaregiverProfileGradeScoreRevision | Backend foundation + contract | Backend commit baa1a1a moves caregiver profile score save into caregiver_performance_recognition/features/caregiver_scorecard. CaregiverProfileScoreRevisionPolicy now freezes branch score floor -50, HQ/Danbee score floor -100, configured max-score policy snapshots, old/new caregiver grade-score basis, matching invalidation, and payout-projection invalidation. PlanCaregiverProfileScoreRevisionPayload rejects source fields such as GRADE_SCORE, ADD_SCORE, OLD_MANAGER_FL, manager_score_branch, and manager_score_danbee; UI submitted values are request facts only. Source bug where Danbee max clamp compares score_branch stays source evidence only; modern policy compares the correct HQ submitted score. Remaining work: persist score revision plan/audit with actor/reason/expected revision, add explicit CaregiverClassChangeCommand, emit matching/payout invalidation events, and bind admin profile save/runtime APIs. |
source-refs/sanmopia-admin/application/controllers/ajax/ManagerEvaluation.php:132-141, :157-190, :195-224; source-refs/sanmopia-admin/application/models/Manager_evaluation_model.php:614-724, :735-747 | caregiver_performance_recognition / CaregiverEvaluationCappedScoreLedger, CaregiverPerformanceScorecard | Backend foundation + contract | Backend commit a07cc1f adds CaregiverEvaluationCappedScoreLedger, CaregiverEvaluationCappedScoreLedgerPolicy, ProjectCaregiverEvaluationCappedScoreLedgerPayload, and CaregiverEvaluationCappedScoreLedgerReadModel. The backend now sorts evaluation score facts by applied_on then fact_code, reuses CaregiverScorecardCapPolicy for per-category and monthly-career/other-working combined caps, preserves original_score, capped_score, score_before, score_after, correction facts, source revision key, source evidence keys, and rejects legacy ajax/display fields such as SCORE, MAX_SCORE, APPLY_DT, BEFORE_SCORE, and AFTER_SCORE. Remaining work: Supabase ledger persistence, scorecard projection read API, grade/class recalculation workflow binding, and matching/payout invalidation consumers. |
source-refs/sanmopia-admin/application/models/Manager_evaluation_model.php:436-448, :458-487, :502-511; source-refs/sanmopia-admin/application/controllers/ajax/ManagerEvaluation.php:21-28, :30-47, :50-106; source-refs/sanmopia-admin/static/js/manager_evaluation/manager_evaluation.js:22-140 | caregiver_performance_recognition / RecordCaregiverEvaluationScoreCommand, CaregiverEvaluationScoreEntry, CaregiverPerformanceScorecardWorklistQuery | Backend foundation + contract | Backend commit 117a6f3 adds RecordCaregiverEvaluationScoreCommand, CaregiverEvaluationScoreEntry, RecordCaregiverEvaluationScoreDecision, CaregiverEvaluationScoreRecordingPolicy, RecordCaregiverEvaluationScorePayload, and RecordCaregiverEvaluationScoreDecisionPayload. Backend commit 200d67c adds CaregiverPerformanceScorecardWorklistQuery, typed worklist sort/search/page enums, CaregiverPerformanceScorecardWorklistSearchPolicy, CaregiverPerformanceScorecardWorklistRow, CaregiverPerformanceScorecardWorklist, CaregiverPerformanceScorecardWorklistPolicy, and Pydantic payloads. The write command freezes actor, reason, expected scorecard revision, idempotency key, source reference key/value, source evidence keys, score fact, projected capped ledger, next scorecard revision, and matching/payout projection invalidation flags. The worklist now owns backend filters, allowed sort/search fields, page offset/size, next page token, row keys, record counts, and phone-search policy. Legacy write/query/DataTables fields such as scoreType, referenceId, applyDate, draw, start, length, order, search, MANAGER_ID, SCORE, SCORE_BY_USER, and SELECT are rejected at the contract boundary. Remaining work: Supabase append-only persistence, duplicate idempotency enforcement against stored rows, SQL worklist adapter, SpiceDB read grant binding, and runtime API binding. |
source-refs/sanmopia-admin/static/js/manager_evaluation/manager_evaluation.js:142-293; source-refs/sanmopia-admin/application/controllers/cli/Manager.php:37-120, :126-237; source-refs/sanmopia-admin/application/controllers/Manager.php:1633-1698; source-refs/sanmopia-admin/application/models/Manager_model.php:2467-2475 | caregiver_performance_recognition / CaregiverScorecardDetailReadModel, CaregiverEvaluationScoreBackfillCommand, CaregiverClassChangeProposal, CaregiverGradeRecalculationWorkflow, CaregiverScoreSummarySnapshot | Pending | Admin UI parses score text, recomputes max caps, derives service-day/age/education buckets, and cron writes monthly/other-working/age rows before recalculating class thresholds while skipping premium caregivers. Modern backend must own detail read model, source-score backfill command, class-change proposal/audit, premium exclusion reason, manager-list score summary snapshot, and scheduled rerun idempotency. UI bucket parsing and direct class writes are source evidence only. |
source-refs/sanmopia_web/application/views/mypage/reservation_document.php, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php | document_reporting / printable_document | Partial | ReservationDocumentCatalog, PrintableTemplateRegistry, stored render artifacts, typed document keys, A4 HTML/PDF rendering, and no numeric document id/token URL leakage. |
source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:37-45, source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:85-103, source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:121-127, source-refs/sanmopia-admin/application/views/calculate_detail.php:560-601, source-refs/sanmopia-admin/application/views/calculate_detail.php:620-624, source-refs/sanmopia-admin/application/views/calculate_detail.php:654-703, and source-refs/sanmopia-admin/application/views/calculate_detail.php:834-883 | pricing_settlement / CustomerPaymentReceiptProjection, document_reporting / CustomerReceiptArtifact, document_reporting / CustomerReceiptArtifactRevocationAfterRefund, pricing_settlement / SettlementReceiptLinkProjectionRefresh | Partial | Legacy mother receipt and branch/HQ settlement detail screens build KCP bill URLs from mutable local payment/coupon rows, provider JSON/order ids, transaction ids, pay method, and local PRICE; the mother page even allows receipt opening for status 환불. After provider refund or paid-row transition, backend must refresh receipt-link projections, revoke/reissue stale customer receipt artifacts, and refresh branch/HQ settlement receipt links from immutable payment/refund ledger snapshots before exposing bill URLs. Remaining proof: projection refresh worker consumption after ProviderRefundResultEvent/PaymentRefundPaidRowTransitionDecision, receipt artifact revocation/read-model persistence, and settlement receipt-link refresh tied to reversal lines. |
source-refs/sanmopia_web/application/controllers/api/Service.php emergency/contact relation fallback | member_management / family_account | Partial | ReservationPartyAuthoritySnapshot for mother, sponsor, payer, emergency contact, contact-only viewer, refund authority, and document visibility. |
Legacy UI price/status flags: step3.js data-price, retc.php PRICE_TABLE, calculate_detail.js data-price, old Astro payment/report/document buckets | Backend projections across pricing_settlement, reservation_operations, document_reporting | Pending | CustomerPaymentActionProjection, MotherVisibleChargeSnapshot, CustomerReportObligationProjection, and PublicFeeGuideCatalogProjection; frontend must never sum money or infer workflow state from raw rows. |
source-refs/sanmopia_web/application/views/shop/coupon_list.php:58-76, :102-124, :155-177, :392-414 | customer_engagement / gift_coupon_offer_catalog, pricing_settlement / gift_coupon_payment_product_plan | Partial | Gift-coupon purchase offers still need backend catalog rows for free/custom amount offers and fixed service/week offers, with amount bounds, selected offer code, purchaser/recipient authority, and refund policy. Backend stage proof now freezes payment product plan, settlement line template, and fulfillment side effects before provider handoff via pnpm supabase:smoke:stage:gift-coupon-closeout-side-effects; UI custom-price and data-price buttons are source evidence only. |
pre_reservation_detail.js, pre_reservation_detail.php, source statuses 15/16/17/18 | reservation_operations / pre_reservation_conversion | Partial | PreReservationConversionWorkspace with conversion intent, payment instruction, save journal, return-state token, and stale-save conflict handling. |
feeguide.js, basePrice.js, priceCaculation.js, priceList.js, old Astro fee-guide calculator | pricing_settlement / public_fee_guide_catalog | Partial | PublicFeeGuideCatalogProjection backed by effective-dated price catalog rows; public calculators read backend projections only. |
ManageSystem.php, holiday_list.js, reservation_calendar.js, step3.js, Report_model.php holiday branches | service_calendar / holiday_policy_execution | Partial | HolidayPolicyExecutionAndImpactInvalidation covering add/revise/withdraw, substitute-of, branch closure, and quote/matching/report/settlement invalidation. |
DataRoom.php, Calculate.php, Spreadsheet_model.php:3741-3914, form_reservation_list.js | pricing_settlement / settlement_collection_export_repository | Partial | SettlementCollectionExportRepository with external-counterparty, HQ, inter-office, and reservation-document export readers, frozen dataset revision, column contract, and signed grant. |
Matching_model.php, Reservation_manager_trans_info_model.php, Manager_model.php, manager_pay_detail.js | caregiver_assignment / assignment_decision_evidence, pricing_settlement / caregiver_payout_statement | Partial | CaregiverAssignmentDecisionEvidence and CaregiverPayoutStatementProjection; separate travel/conflict/override evidence from shared payout projection. |
| Sponsor, payer, emergency-contact, refund-recipient, document-visibility source branches | member_management / reservation_party_authority, pricing_settlement / refund_side_effect_ordering | Partial | ReservationPartyAuthoritySnapshot and RefundRecipientAndSideEffectOrdering with consent, contact-only access, refund recipient, and document visibility rules. |
static/dist/excel/type*.xlsx, old PDF/static document variants, document numeric ids | document_reporting / printable_template_version_manifest | Partial | PrintableTemplateVersionManifestCompleteness mapping document kind, version, file source, service eligibility, render format, and A4 output contract. |
cli/Price.php, Spreadsheet_model.php:4807-5400, sanmopia-price-table/*.xlsx | pricing_settlement / price_catalog_import_execution_audit | Partial | PriceCatalogImportExecutionAudit with batch, dry-run issue report, rollback/repair, private-care/general coverage, and private artifact evidence. |
source-refs/sanmopia-admin/application/views/reservation_status/reservation_add.php:273, source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1519, source-refs/sanmopia_web/application/controllers/api/Service.php:346, source-refs/sanmopia_web/application/models/Reservation_model.php:2526, source-refs/sanmopia-admin/application/controllers/Reservation.php:1749, source-refs/sanmopia_web/application/models/Reservation_model.php:1181, source-refs/sanmopia-admin/application/models/Payment_model.php:436 regional/support branches | pricing_settlement / regional_benefit_policy, reservation_operations / service_calendar_quote_impact | Partial | Backend RegionalBenefitRule metadata now carries regional_benefit_profile_key, service_day_bonus_count, and settlement_participation_code so residency support profiles can drive service-day bonus and settlement participation without UI/admin string branches. FinalizeReservationChargeWithRegionalBenefitHandler now resolves and freezes the decision for price-summary charge finalization. Remaining work: runtime reservation entrypoints, service calendar, payment-conversion, and settlement must consume the same decision/snapshot path. |
source-refs/sanmopia_web/application/controllers/api/Account.php, source-refs/sanmopia_web/application/controllers/Mall.php, source-refs/sanmopia_web/application/models/User_model.php | member_management / customer_identity_profile, customer_engagement / external_commerce_member_link | Partial | Profile, security, marketing consent, FCM token, social completion, shop referral, gift-coupon claim, rollback, and privacy lifecycle must be separate backend facts. |
source-refs/sanmopia_web/application/controllers/api/Service.php service/intake paths | reservation_operations / customer_reservation_intake_draft | Partial | Revisioned intake draft, branch service-area decision, care-plan invalidation, rental selection, named-caregiver carryover, continuation, and Restate workflow state; no source PROCESS_NO or browser price/version mutation. |
source-refs/sanmopia_web/application/controllers/api/Reservation.php, source-refs/sanmopia_web/application/controllers/api/Payment.php, source-refs/sanmopia_web/application/models/User_model.php | reservation_operations / customer_reservation_intent, pricing_settlement / customer_payment_instruction, document_reporting / customer_document_download_grant | Partial | Birth/service correction, change/cancel/stop/extension, branch notification routing, deposit/balance/coupon/pre-reservation/change-payment, two-hour document-token replacement, and signed Storage grant are backend commands/projections. |
source-refs/sanmopia-manager/application/controllers/Report.php, source-refs/sanmopia-manager/application/controllers/Service.php, source-refs/sanmopia-manager/application/controllers/Attendance.php, source-refs/sanmopia-manager/application/models/Notify_model.php | care_delivery / care_delivery_obligation, customer_engagement / report_service_notification | Partial | First/progress/last reports, service records, attendance, main/sub caregiver role, duplicate guards, newborn bootstrap, dispatch attempts, and mother-visible notification audit must be durable backend obligations. |
source-refs/sanmopia-admin/application/models/Statistics_model.php, source-refs/sanmopia-admin/application/controllers/Datatable.php, source-refs/sanmopia-admin/static/js/statistics/* | business_reporting / admin_analytics_catalog | Partial | Versioned report definitions, filters, metric definitions, branch visibility, frozen totals, export artifact handoff, and operator audit; UI tables must not own metric formulas. |
source-refs/sanmopia-admin/application/controllers/OfficeManagement.php, source-refs/sanmopia-admin/application/models/Branch_model.php, branch login sources | branch_operations / office_profile, operator_access / branch_login_audit | Partial | Branch profile, lifecycle, operator credential, membership fee, settlement accounts, brand assets, service area, credential rotation, login audit, and stale-save conflict recovery need backend commands and SpiceDB/OPA gates. |
source-refs/sanmopia-admin/application/controllers/Promotion.php, source-refs/sanmopia-admin/application/models/Coupon_model.php, source-refs/sanmopia-admin/application/models/Momfirst_model.php, customer shop paths | customer_engagement / promotion_entitlement, pricing_settlement / gift_fulfillment, document_reporting / partner_benefit_result_artifact | Partial | Coupon lineage, gift fulfillment, Momfirst/Clean delivery batches, result artifacts, download grants, audience policy, suppression, retry, and repair audit need backend-owned workflow state. |
source-refs/sanmopia_web/application/controllers/MyReservation.php:21-190 | reservation_operations / CustomerReservationLifecycleSnapshot | Partial | Customer reservation lifecycle must project proceeding/history buckets, pre-reservation detail routing, report/add-date/continue/service-balance overlays, and virtual-account prompts from backend policy, not portal status/payment maps. Domain symbols now use snapshot/entry/report-obligation/care-team language; remaining gate is application path and generated contract alias migration away from view, card_display, report_presentation, and caregiver_display. |
source-refs/sanmopia_web/application/views/mypage/item/reservation_func_btn.php:1-190, source-refs/sanmopia_web/application/views/mypage/item/reservation_detail_func_btn.php:1-210 | reservation_operations / CustomerActionAvailabilityPolicy | Partial | Customer action availability must cover list/detail actions: reservation payment, delivery info input, pre-reservation conversion, report writing, cancellation, extension, rescheduling, more-info, service-end gates, 15-day extension window, stop/change/payment/report buttons, hidden states, disabled reasons, and command targets. |
source-refs/sanmopia_web/static/js/mypage/reservation.js:336-421 | reservation_operations / CustomerActionCommand | Partial | Customer action commands must own request copy, required reason validation, instant-cancel result, idempotency, and post-command navigation intent for cancel/change/stop instead of browser JS deciding success behavior. |
source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:80-270 | reservation_operations / ReservationActorCapabilityProjection | Partial | Backend foundation now splits HeadOfficeManager and BranchOwner reservation-stage capabilities, including offline cancel authority, branch-disallowed offline selection, pre-reservation status subsets, save locks, disabled reasons, and visible transition options. Remaining gates: bind Supabase Auth actor identity, SpiceDB relationship facts, OPA decisions, field visibility, command targets, audit context, and API/read adapters. |
source-refs/sanmopia-admin/application/controllers/Reservation.php:650-1020, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:270-342 | reservation_operations / ReservationCollaborationConflictLog, ReservationCollaborationWorkspace | Partial | Broad reservation detail saves must become changed-field commits with expected revision, workspace id, actor role/profile, attempted mutation groups, conflicting field paths, latest audit event, conflict diff, realtime invalidation state, resolution, backend navigation intent, and return-state token. |
source-refs/sanmopia-admin/application/models/Reservation_model.php:1768-1955 | reservation_operations / ReservationStateTransitionCatalog | Partial | Reservation state transitions must preserve side effects: confirm timestamp, settlement/pay-info creation, central-branch payment insertion, KCP refund/coupon reset on cancel, stop coupon reset only on real status change, and consult/extension notifications. |
source-refs/sanmopia-manager/application/controllers/Schedule.php:27-75, source-refs/sanmopia-manager/application/views/schedule/schedule_info.php:136-345 | care_delivery / CaregiverWorkScheduleProjection, CaregiverActionAvailabilityProjection | Partial | Caregiver schedule/action projections must enforce assignment ownership, 90-day access window, main/assistant role, delivery/preference/voucher facts, service/report task counts, payout state, balance confirmation, assistant payout confirmation, sequential service-record writing, report writing, completed states, and backend-owned route/date targets. |
source-refs/sanmopia_web/application/controllers/api/Payment.php:80-215, source-refs/sanmopia_web/application/controllers/api/Payment.php:250-320, source-refs/sanmopia_web/application/controllers/api/Payment.php:580-645 | member_management / ReservationPartyAuthoritySnapshot, pricing_settlement / PayerAndGiftRecipientProjection, PaymentCommunicationDispatchRoute | Partial | Payment recipient/routing policy must distinguish mother, payer/family sponsor, branch director, gift-coupon buyer, receiver, phone-only receiver, virtual-account completion notices, pre-reservation payment notices, SMS fallback, secondary branch contact, and branch-id exception as backend snapshots and communication routes. |
source-refs/sanmopia-admin/application/models/Data_room_model.php:25-80, source-refs/sanmopia-admin/application/controllers/DataRoom.php:119-212 | document_reporting / BranchResourcePostAudiencePolicy | Partial | Branch resource posts need backend send/receive/HQ branch-36/null visibility policy, pinned ordering, attachment-delete audit, branch filter, write/delete commands, and SpiceDB/OPA checks. |
source-refs/sanmopia-admin/application/controllers/cli/Excel.php:120-180, source-refs/sanmopia-admin/application/controllers/cli/Excel.php:405-430 | pricing_settlement / SourceExcelRepairWorkbookCommand, operator_access / BranchLoginAuditExport | Partial | Legacy Excel repair/export CLI needs typed repair/export requests with dataset revision, actor, reason, idempotency, source workbook hash, artifact grant, and audit. |
source-refs/sanmopia-admin/application/controllers/Administrator.php:174-225 | operator_access / LegacyMaintenanceCommandGate, migration_governance / SourceRepairCommandCatalog | Partial | Admin test*, branch-token, update-date, settlement-backfill, complete-backfill, and coupon-reset endpoints need protected repair commands, dry-run, expected revision, actor/reason audit, and no public test route. |
source-refs/sanmopia-admin/application/controllers/Api.php:5-43 | customer_engagement / PromotionEntitlementAdminCancellation | Partial | Admin coupon/Momfirst deletion must become entitlement cancellation command with actor, reason, linked payment/settlement/fulfillment side effects, restore, and repair ledger. |
source-refs/sanmopia_web/application/helpers/utility_helper.php:666-696, source-refs/sanmopia_web/application/helpers/utility_helper.php:703-755 | document_reporting / ArtifactDownloadResponsePolicy, platform / LegacyRealtimePushBridge | Missing | force_download_by and push_to have no confirmed call sites yet. Either mark as dead-source carryover after proof, or migrate CSV/XML header/BOM policy and region-prefixed socket publish semantics into backend document/platform policies with retry and audit. |
CaveCrew Source Gap Delta 2026-07-05
Section titled “CaveCrew Source Gap Delta 2026-07-05”The explorer pass below is not a source-code copy list. It is a source-evidence delta for backend abstractions that still need stronger modern slices.
| Priority | Source evidence | Modern target | Status | Required improvement |
|---|---|---|---|---|
| P0 | source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:86-99, :247-261; source-refs/sanmopia-admin/application/controllers/Reservation.php:420-431 | reservation_operations / ReservationActorCapabilityProjection | Partial | Backend foundation exists; next bind Supabase Auth actor, SpiceDB relation, OPA result, field visibility, command targets, and audit context. |
| P0 | source-refs/sanmopia-admin/application/models/Reservation_model.php:1769-1916; source-refs/sanmopia_web/application/models/Reservation_model.php:989-1112 | reservation_operations / ReservationStateTransitionPolicy, ReservationLifecycleSideEffectPlan, ReservationOperationFollowUpWorkflow; pricing_settlement / ReservationPromotionSideEffectPlan | Partial | Backend foundation now maps accepted transition follow-up actions into typed side-effect work items for audit, customer notification, refund closeout, refund completion barrier, benefit release, branch settlement opening, and financial lifecycle closeout. Remaining gates: persist plan snapshots, bind Restate workflow dispatch, execute pricing/customer-engagement side effects idempotently, and expose repair/read models. Source status numbers and provider-specific payment names stay in adapters/evidence, not target components. |
| P0 | source-refs/sanmopia-admin/application/models/Reservation_model.php:1769-1916; source-refs/sanmopia-admin/application/models/Reservation_model.php:1980-2140; source-refs/sanmopia_web/application/controllers/api/Reservation.php:115-239; source-refs/sanmopia_web/application/models/Payment_model.php:101-441 | reservation_orchestration / ReservationLifecycleSideEffectExecution, reservation_operations / ReservationLifecycleSideEffectPlan | Partial | Execution layer now enriches plan work items with targetFeature, commandKind, sourceEvidenceRef, persisted preconditions, compensation, execution status, retry/dead-letter/repair state, Supabase-first persistence, and Restate dispatch. Refund closeout now emits a separate payment_refund_completion_barrier execution item requiring terminal provider refund evidence or zero-refund fact before downstream benefit/settlement work can complete. Remaining gates: worker execution, provider-event ingestion binding, zero-refund fact persistence, and operator repair/read projections beyond internal provider-refund planning/execution/result-recording persistence. See Reservation Lifecycle Side Effect Execution. |
| P0 | source-refs/sanmopia_web/application/models/Payment_model.php:383-441; source-refs/sanmopia_web/application/controllers/api/Payment.php:80-215, :250-320, :537-545, :580-645; source-refs/sanmopia_web/application/models/Payment_model.php:775-843 | pricing_settlement / PaymentAdjustmentQuote, PaymentChangeRefundLink, ProviderPartialRefundCapability, PreReservationPaymentCloseout, PreReservationCouponOverCreditPolicy, PaymentCloseout; promotion_entitlement / PromotionEntitlementOutbox | Partial | Kill Bill-backed closeout must centralize refund, partial refund, custom charge, coupon restore, provider capability, zero-provider-payment closeout, and settlement continuation. 2026-07-05 backend follow-up: PaymentChangeRefundLink now enters at the Pydantic application boundary, flows into Pydantic-free PaymentRefundIntent and append-only PartialRefund, persists as queryable sanmopia_payment_refund_ledger_entries.payment_change_adjustment_id with a fallback read from historical provider-command properties, and is exposed through POST /reservation-cancellation-refunds plus TS contract validators. PreReservationCouponOverCreditPolicy now centralizes legacy realPrePrice = max(required - coupon, 0) and over-credit point/shop grant planning with a versioned rule instead of UI/controller arithmetic. 2026-07-07 sidecar: zero-payable pre-reservation must close without a provider call, virtual-account pre-reservation must stay waiting until a deposit fact, and over-credit point/shop grants must be emitted from an entitlement outbox after payment-record persistence; UI/controller realPrePrice and over-credit math are evidence only. Remaining work: provider partial-cancel capability events, zero-gateway-refund quote decisions, pre-reservation payment record persistence, pre-reservation entitlement outbox closeout, virtual-account waiting/deposit closeout, and reservation closeout workflow binding. |
| P0 | source-refs/sanmopia-admin/static/js/reservation_status/payment_change.js:93; source-refs/sanmopia-admin/application/models/Payment_model.php:4507-4511; source-refs/sanmopia-admin/application/models/Reservation_model.php:1861-1866; source-refs/sanmopia_web/static/js/mypage/reservation_changePayment.js:43; source-refs/sanmopia_web/application/views/modal/modal_change_payment.php:1-18 | pricing_settlement / PaymentChangeAdjustmentCloseout, PaymentChangeRefundLink, ChargeQuoteSnapshot, ChargeSummaryProjection | Partial | Source lets operators type closeout amount/status and lets browser/view code recompute conversion amount, coupon, and pre-reservation deduction. Backend must keep mutable operator completion, immutable paid amount, refund link, charge snapshot, and provider refund fact separate. 2026-07-07 follow-up: CloseLatestZeroPayablePaymentChangeAdjustmentCommand, POST /reservation-payment-change-adjustments/{reservationBookingId}/zero-payable-closeouts, and PaymentChangeAdjustmentZeroPayableCloseoutPayload now close zero mother-payable adjustments through a backend-owned receipt (zero_payable_closeout) without KCP/Kill Bill provider wait, reject negative refund cases, and request settlement continuation through the paid-adjustment path. Remaining work: charge-summary projection persistence plus provider/refund workflow execution for positive and credit/refund cases. |
| P0 | source-refs/sanmopia_web/application/models/Payment_model.php:861-871; source-refs/sanmopia-admin/application/models/Payment_model.php:4431-4440; source-refs/sanmopia-admin/application/models/Reservation_model.php:1861-1870; source-refs/sanmopia-admin/application/models/Payment_model.php:4451-4461 | pricing_settlement / PaymentChangeRefundEligibleAdjustmentSelectionPolicy, PaymentChangeRefundIntent | Backend foundation | Source inserts new unpaid payment-change drafts while preserving older paid rows, but cancellation refund reads only the latest row by id and refunds only when that row has provider context. A later unpaid draft can hide an older paid payment-change receipt from cancellation refund. 2026-07-07 backend follow-up: PaymentChangeRefundEligibleAdjustmentSelectionPolicy now scans all paid/completed provider-receipted payment-change adjustments by reservation, excludes unpaid drafts, zero-payable closeouts, other reservations, and already-refunded adjustment ids, and returns deterministic refund-eligible adjustment facts. Remaining work: wire Supabase selection into cancellation refund execution so one PaymentChangeRefundIntent is emitted per eligible adjustment. |
| P0 | source-refs/sanmopia-admin/application/models/Reservation_model.php:1873-1892; source-refs/sanmopia-admin/application/models/Coupon_model.php:63-157, :935-958; source-refs/sanmopia_web/application/models/Coupon_model.php:530-553 | pricing_settlement / RefundSideEffectPlan; promotion_entitlement / EntitlementRestorationPlan, ActualServiceDayCouponPolicy | Backend foundation + contract | Source cancel/stop directly reopens used coupons and hard-deletes/recreates product coupons from attendance-day bands. Backend already owns ProductCouponResetPolicy; commit 5dfff36 adds ProductCouponResetContract so stop/cancel reset is planned from actual service-day evidence, service-interruption kind, existing entitlement ids, versioned entitlement rules, and actual-service-day schedules. Contracts reject destructive source fields such as COUPON_TB, USER_COUPON_TB, COUPON_ID_PK, COUPON_TYPE_CD_FK, PRODUCT1, PRODUCT2, DELETE_FL, PRICE, MANAGER_ATTENDANCE_TB, realServiceDay, 사은품 1주 쿠폰, and 사은품 2주 쿠폰. Remaining work: persist reset plans/outbox in Supabase, bind refund/cancellation closeout workflow, map care-delivery attendance facts into actual_service_days, and expose repair/read APIs for entitlement revocation/reissue. |
| P0 | source-refs/sanmopia_web/application/models/Reservation_model.php:2526, :2546, :2577, :2627; source-refs/sanmopia_web/static/js/step3.js:477, :523, :890; source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:2155; source-refs/sanmopia-admin/application/models/Manage_system_model.php:10-63 | service_calendar / ServiceTermPolicy, HolidayCalendarRegistry, AdditionalServiceDaySelection, ServiceAreaCalendarProfile | Backend foundation + contract | Source mixes one-week/two-week service math, voucher-day math, manual holiday rows, selected Saturday/holiday dates, hidden UI end dates, and hardcoded regional day additions. Backend domain already owns ServiceTermPolicy, HolidayCalendarRegistry, AdditionalServiceDaySelection, and ServiceAreaCalendarProfile. Backend contract commit f095925 adds application/service_calendar/features/service_term_policy with strict Pydantic payloads for term planning, holiday entries, service-area profile registries, selected additional non-working days, and immutable term plan output. Contracts reject browser/PHP fields such as saturday_list[], holiday_list[], is_wanju, add_sat_date, add_holi_date, HOLIDAY_DT_PK, SERVICE_DAY, serviceDay, 토요일 추가, 휴일 추가, and 완주군. Tach now explicitly fences domain.service_calendar.features.service_term_policy and its application contract. Remaining work: persist service-term plan snapshots in Supabase, bind booking/admin quote endpoints to PlanServiceTermPayload, connect additional-day charge quote policy, and migrate frontend/admin hidden end-date fields to backend snapshots only. |
| P0 | source-refs/sanmopia_web/application/models/Reservation_model.php:2051, :2091, :2473; source-refs/sanmopia_web/application/models/Manager_model.php:176; source-refs/sanmopia-admin/application/config/constants.php:127; source-refs/sanmopia-admin/application/models/Coupon_model.php:72, :99 | reservation_operations / ReservationContinuationLink, ContinuationDraftConflictFact, ContinuationVoucherEligibilityDecision, ContinuationCaregiverCarryoverDecision; service_lifecycle / ServiceInterruptionPolicy; promotion_entitlement / ProductCouponResetPolicy | Backend foundation + contract | Source extension creates linked reservations, blocks duplicate active extensions, rejects voucher-chain extension, and conditionally reuses the manager. Stop/cancel uses actual attendance rows for benefit reset. Backend commit 7d5db21 adds continuation draft eligibility and creation planning with source-status/table-field rejection, replaceable-writing-draft tracking, active/submitted duplicate blocking, idempotency, superseded draft id, copied-fact audit key, cloned-fact keys, and first-class continuation link output. Product coupon reset contract 5dfff36 covers actual-service-day entitlement recalculation. Remaining work: persist continuation draft plans and copied-fact audit rows in Supabase, bind booking/admin extension APIs, dispatch service-period/quote/matching invalidation, persist service interruption intervals, and connect promotion entitlement outbox execution. |
| P0 | source-refs/sanmopia_web/application/controllers/api/Service.php:323-325; source-refs/sanmopia_web/application/models/Reservation_model.php:2473-2501 | reservation_operations / ContinuationVoucherEligibilityDecision | Backend-backed foundation | Continuation voucher conversion must inspect the whole ancestor reservation chain, not just the current booking. Backend now adds a chain-fact decision, Pydantic payload, Supabase query columns, and TS/schema contract so UI cannot decide voucher continuation eligibility from a single row or source status code. Remaining work: bind booking/continuation command runtime to the decision and expose operator/customer reason copy. |
| P0 | source-refs/sanmopia_web/application/controllers/api/Service.php:329-332 | reservation_operations / VoucherRecipientIdentityEligibilityDecision | Backend-backed foundation | Source rejects voucher booking from resident-number back digit parity in controller code. Backend now evaluates only first back digit evidence, stores redacted_identity_evidence_key, reason code, source rule key, Supabase backend-owned decision row, Pydantic payload, and TS/schema decision contract. Raw resident-number fragments must not be persisted or exposed in public contract. Remaining work: bind voucher booking command runtime and operator/customer reason copy. |
| P0 | source-refs/sanmopia_web/application/controllers/api/Service.php:425-440, source-refs/sanmopia_web/application/controllers/api/Service.php:548-566; source-refs/sanmopia_web/application/models/Manager_model.php:176-198 | reservation_operations / ContinuationCaregiverCarryoverDecision | Backend-backed foundation | Continuation forces consulting and tries same-caregiver carryover only when prior manager exists and schedule check passes. Backend now maps source result -1/-2/-3/manager_id into typed reason codes continuation_link_missing, prior_caregiver_missing, same_caregiver_schedule_conflict, and same_caregiver_available, persists queryable carryover columns, and exposes TS/schema contract. Remaining work: bind runtime schedule reader and operator/customer copy. |
| P0 | source-refs/sanmopia-admin/application/controllers/Calculate.php:150-312; source-refs/sanmopia-admin/static/js/calculate_detail.js:20-323; source-refs/sanmopia-admin/application/models/Payment_model.php:554-561, :2861-2878, :2977-3051, :4302-4400; source-refs/sanmopia-admin/application/controllers/DataRoom.php:237-309 | pricing_settlement / DanbiSettlementArchive, HeadquarterBranchSettlement, SettlementApprovalWorkflow, SettlementAdjustmentLine, SettlementDataRoomCollection | Partial | Source collapses Danbi archive, branch-to-HQ settlement, HQ approval, branch confirmation, checkbox-paid rows, manual gift/additional service charges, memo/message fields, and archive export into mutable board CRUD. Target must separate ledger read models, workflow state, approval tasks, manual adjustment lines, branch/HQ visibility, expected revision, and audit diff. |
| P0 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:17, :3741, :3903, :4131; source-refs/sanmopia-admin/application/views/data_room/form_reservation_list.php:123, :207; source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:225; source-refs/sanmopia-admin/application/controllers/DataRoom.php:119-212, :311 | document_reporting / SettlementStatementGeneration, MaterialRoomDocumentRequest, BranchResourcePost, ReservationDocumentExportWorklist, DocumentArtifactGrant | Partial | Source uses hardcoded XLSX template ids, hidden iframe POST downloads, temp zip/pdf/xlsx files, direct file delete/update, and weak download audit. Backend foundation now adds ReservationDocumentExportWorklist, ReservationDocumentExportSelectionToken, and Pydantic contracts so selected reservation ids, document definition keys, actor scope, and export artifact request use immutable backend fingerprints instead of mutable hidden iframe or raw GET parameters. Target still must bind DB-backed worklist queries, template eligibility, async render/export jobs, Supabase Storage signed grants, artifact checksum/retention, post attachment version history, soft delete, and download audit/rate limits. |
| P0 | source-refs/sanmopia-admin/application/models/Reservation_model.php:699-818; source-refs/sanmopia_web/application/models/Reservation_model.php:1165-1369 | pricing_settlement / RegionalBenefitDecision, ReservationPriceVersionAndSubsidyAdjustment | Partial | Subsidy, regional benefit, discount, support criteria, and price-version effects must be persisted as effective-dated decision facts. |
| P0 | source-refs/sanmopia_web/application/views/service/step1.php:188-214; source-refs/sanmopia_web/application/models/Reservation_model.php:314-374; source-refs/sanmopia_web/application/controllers/api/Service.php:70-86 | member_management / ReservationPartyAuthoritySnapshot | Backend/contract foundation | ReservationPartyAuthoritySnapshot now separates mother beneficiary, booker, payer, emergency contact, document viewer, refund recipient, and notification recipient with explicit ReservationPartyAuthorityEvidence; contact relation labels and phone-only contacts can be preserved as evidence but cannot grant document/refund/payment authority by themselves. ReservationPartyAuthoritySnapshotPayload now round-trips that vocabulary through a strict Pydantic boundary and rejects source relation text as role/authority. Remaining proof: Supabase persistence, booking/payment/refund/document command binding, public/internal API routes, and UI migration away from relation-text/phone ownership inference. |
| P0 | source-refs/sanmopia-admin/application/config/constants.php:116-137; settlement eligibility source status use in reservation and settlement source files | pricing_settlement / SettlementReservationLifecycleStatus, reservation_settlement_status_acl | Partial | Settlement domain no longer owns source numeric reservation status values; SettlementReservationLifecycleStatus is semantic and source code conversion lives in application ACL. Remaining migration must wire Supabase/adapters through the ACL and remove numeric status mapping from refund, branch-settlement, and external-counterparty domain code. |
| P1 | source-refs/sanmopia-admin/application/controllers/Reservation.php:650-720, :940-1021; source-refs/sanmopia-admin/application/models/Reservation_model.php:3728-3740; downstream consumers source-refs/sanmopia_web/application/models/Report_model.php:312-322, :439-449, source-refs/sanmopia-admin/application/models/Statistics_model.php:215-230, :2581-2587 | reservation_operations / ReservationCollaborationConflictLog, ChangedFieldCommit; business_reporting / ReservationStatusChangeFactProjection | Partial | Replace broad before/after JSON with typed changed-field commits, expected revision, conflict diff, chosen winner, realtime invalidation, and return-state token. The legacy JSON diff is also report/metrics authority through BEFORE_DATA/AFTER_DATA string matching for stop/change facts, so reporting projections must bind typed reservation status/service-term events rather than parse UI-save audit blobs. |
| P1 | source-refs/sanmopia-admin/application/controllers/DataRoom.php:215-309, :389-408; source-refs/sanmopia-admin/application/models/Data_room_model.php:12-20 | pricing_settlement / SettlementCollectionExportRepository, SettlementDataRoomArtifactBuildWorker, ExternalSettlementCounterpartyReadinessProjection | Partial | Settlement data-room exports need frozen dataset revision, external-counterparty readiness, artifact build worker, signed grant, and repair history. |
| P1 | source-refs/sanmopia-manager/application/helpers/salary_helper.php:4-228 | pricing_settlement / CaregiverPayoutStatementProjection, AdminCaregiverCompensationReadModel | Partial | Shared admin/manager payout read model must freeze role slot, grade snapshot, attendance facts, tax election, adjustment, confirmation, and receipt state. |
| P1 | source-refs/sanmopia_web/application/models/Reservation_model.php:1091-1112, :3263-3273; source-refs/sanmopia-admin/application/models/Reservation_model.php:6180-6190 | service_calendar / ServiceOccurrenceEvidenceRequirement, ServiceSuspensionInterval, ExtraServiceDateAnomalyAcknowledgement | Partial | Holiday, interruption, substitute-day, and anomaly handling need occurrence evidence, acknowledgement, and quote/matching/report/refund/settlement invalidation. |
| P1 | source-refs/sanmopia-admin/application/models/Reservation_model.php:1769-1916; source-refs/sanmopia_web/application/models/Reservation_model.php:989-1037 | pricing_settlement / ReservationPromotionSideEffectPlan, ProductCouponResetPolicy, ReservationCouponRestorePolicy, PromotionEntitlementOutbox; customer_engagement / BenefitFulfillmentCancellationOutbox | Partial | Cancel/stop/refund side effects must become explicit promotion entitlement, benefit fulfillment, payment closeout, and communication decisions with idempotent outbox repair. |
| P1 | source-refs/sanmopia-admin/application/models/Branch_model.php:289-426, :602; source-refs/sanmopia_web/application/models/Reservation_model.php:2113-2137, :2239-2302 | branch_operations / BranchServiceAreaDecisionRecorder, ServiceAreaCoverageProfile; reservation_operations / ReservationServiceAddressCoverageSnapshot | Partial | Address and coverage decisions need frozen snapshots and effective-dated coverage profiles reused by booking, extension, transfer, pricing, matching, and audit. Possible, consultation-only, and impossible area rules must not remain mutable branch table reads at decision time. |
| P1 | source-refs/sanmopia_web/application/models/Branch_model.php:45-90, source-refs/sanmopia_web/application/models/Branch_model.php:93-139; source-refs/sanmopia-admin/application/models/Branch_model.php:369-401; source-refs/sanmopia_web/application/controllers/api/Service.php:46-53 | branch_operations / BranchCoverageOverrideDecision | Backend-backed foundation | Source first finds possible/consultation area, then any impossible row vetoes. Admin allows consultation/impossible only under an existing possible area. Modern branch policy now keeps unavailable > consultation-only > available precedence and adds BranchCoverageOverrideDecision with explicit available-parent rule id/revision proof, period coverage rejection, missing-parent rejection, and public contract/schema. Remaining work: expose runtime preflight endpoint, persist override decision evidence, and route admin rule editor through this decision before publication. |
| P1 | source-refs/sanmopia-manager/application/helpers/salary_helper.php:109-214 | pricing_settlement / CaregiverPayoutPolicyProfile, CareTeamCompensationSlot | Backend-backed foundation | Weekend/holiday additions, repeating effective-day options, voucher add-ons, tax election, custom service balance, primary caregiver custom pay, and assistant caregiver custom pay are now represented by CaregiverPayoutPolicyProfile, CareTeamCompensationSlot, and CaregiverPayoutPolicyDecisionSnapshot in backend domain/application contracts plus TS/schema contracts. Slot identity is assignment_key + caregiver_role + handoff_order, and final payable amount freezes override source so manager/admin UI cannot recompute from mutable OPTION, service-balance, or salary rows. Remaining work: persist decision snapshots with payout instructions and bind admin/manager/HQ screens to the frozen read model. |
| P1 | source-refs/sanmopia-manager/application/helpers/salary_helper.php:42-99 | pricing_settlement / CaregiverVoucherAddOnTaxCutoverPolicy | Backend-backed foundation | Voucher special/live-in add-on, tax category, 3.3% style withholding, and pre-2022-03-29 after-tax cutover are now represented as a versioned policy plus frozen decision payload. Remaining work: bind runtime quote/payout statement builders to the decision and persist final statement snapshots. |
| P1 | source-refs/sanmopia-manager/application/helpers/salary_helper.php:67-160 | pricing_settlement / CaregiverAdditionalServiceDayBasis | Backend-backed foundation | Normal/customer-funded basis multiplier, voucher basis multiplier, service-day extension option lines, repeating per-effective-day option lines, voucher custom service balance override, and profile-based voucher add-on deduction are now represented as a versioned backend policy plus contract decision. Remaining work: bind quote/payout statement builders and persistence so admin/manager screens read the frozen decision instead of recalculating helper totals. |
| P1 | source-refs/sanmopia-manager/application/views/schedule/schedule_info.php:136-200, source-refs/sanmopia-manager/static/js/schedule/schedule_info.js:1-95, source-refs/sanmopia-manager/application/controllers/Reservation.php:6-77, source-refs/sanmopia-manager/application/models/Reservation_model.php:247-270, source-refs/sanmopia-manager/application/models/Reservation_model.php:351-411, source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:235-260, source-refs/sanmopia-admin/application/controllers/Manager.php:1108-1129, source-refs/sanmopia-admin/application/models/Reservation_model.php:2573-2624 | care_delivery / CaregiverServiceBalanceShareProjection, CaregiverServiceBalanceAcknowledgementCommand; pricing_settlement / CaregiverPayoutStatement | Backend-backed foundation | Caregiver schedule service-balance share is now represented by backend CaregiverServiceBalanceSharePolicy and required serviceBalanceShare contract fields on schedule items. The projection exposes exact integer share amount, role slot, confirmation state, command availability, disabled reason, statement reference, policy version, and source evidence so the portal cannot divide totals or infer main/sub payment status from source flags. Service-balance acknowledgement now has backend/application and public contract foundations that require assignment key, caregiver role, handoff order, payout statement reference, expected confirmation revision, expected payout statement revision, actor, reason, and idempotency key before state movement. 2026-07-07 source mining adds the manager portal raw PUT /reservation/data route: browser code posts type=payment or type=sub_payment plus service_type, the controller switches on that string, and the model stamps type-3 customer payment rows plus branch-manager payment flags. The sub-payment path updates SUB_PAYMENT_STATUS_ID_FK by reservation id only, so runtime writers must reject reservation-id-only acknowledgement and require assignment key/current roster revision. Backend fbc60e4 now reads the frozen closeout event, caregiver receipt state, and payout instruction into the caregiver work-schedule share projection, applies a versioned deterministic equal-slot policy across multiple caregivers, and exposes reservation-scoped lookup. Positive-balance stage reservation 0b57b5f1-12c5-42f0-bcdf-7ab90e469a8b reached settled with a frozen 25,000 KRW share. Backend 65a71ac now invokes CareTeamAssignmentProjectionWriter after accepted assignment decisions and materializes sanmopia_reservation_caregiver_assignments: candidate profile and member-to-auth binding, grade snapshot, latest occurrence-ledger service-day count, booking dates, role, handoff order, and contract assignment key are persisted; replacement and clear decisions mark prior slots replaced or removed. Stage reservation 5dd549d3-6c2c-407c-b42a-fdcd7e769c6a persisted its roster row before payout and reached settled. Remaining work: migrate runtime acknowledgement writers away from PHP/JS reservation-id-only mutation, make decision persistence plus roster projection atomic or durably replayable, repair failed projections, and backfill older accepted decisions. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4030-4050, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4058-4093 | document_reporting / DailyReportArtifactSeriesSelection | Backend-backed foundation | Customer daily-report bundle first/middle/last selection, stop-day-as-final behavior, assistant caregiver variants, caregiver question ids 1-1/2-1/3-1, and one middle artifact per caregiver CREATED_DT are now represented by backend artifact-series selection policy plus contract schema. Members carry report audience, stage, source kind, service date, assignment key, caregiver role/id, source report evidence key, source evidence set, and deterministic member key so UI/document ids cannot decide the series. Remaining work: bind runtime artifact builder/render/storage workers and persisted report readers to the selection. |
| P1 | source-refs/sanmopia-admin/application/models/Reservation_model.php:10-48, source-refs/sanmopia-admin/application/models/Reservation_model.php:160-276, source-refs/sanmopia-admin/application/models/Reservation_model.php:644-923, source-refs/sanmopia-admin/application/models/Reservation_model.php:4013-4045, source-refs/sanmopia-admin/application/models/Reservation_model.php:4110-4137, source-refs/sanmopia-admin/application/models/Reservation_model.php:4748-4764, source-refs/sanmopia-admin/application/models/Reservation_model.php:4992-5014, source-refs/sanmopia-admin/application/models/Reservation_model.php:5200-5208, source-refs/sanmopia-admin/application/models/Reservation_model.php:5455-5496, source-refs/sanmopia-admin/application/models/Reservation_model.php:5644-5658, source-refs/sanmopia-admin/application/models/Reservation_model.php:408-470, source-refs/sanmopia-admin/application/models/Reservation_model.php:938-963, source-refs/sanmopia-admin/application/models/Payment_model.php:3149-3179, source-refs/sanmopia-admin/application/models/Manager_model.php:2366-2372, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:167-376, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:629-780, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3507-3664, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-3940, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4284-4297, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4434-4450, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4511-4575, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:19-132, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:624-688 | document_reporting / ServiceUseContractEvidenceSnapshot, ServiceUseContractRenderSource, ServiceUseContractPaymentEvidenceSnapshot, BranchStampAssetSnapshot, MotherSignatureAssetSnapshot, ChargeComponentRevisionSnapshot, ServiceOccurrenceSet, CareTeamDocumentProjection, ServiceUseContractRenderRequest, StoredPrintableDocumentArtifact, ContractTemplateEffectiveVersionDecision, DocumentCenterProjection | Backend-backed foundation | Service-use contract render template selection, payment-deposited contract-date source, redacted identity birth evidence, service-period snapshot, latest caregiver-change evidence, charge component snapshot, and immutable signature/stamp asset references are now represented by backend domain/application contracts plus public TS/JSON schema. Charge components carry effect (adds_to_customer_total, deducts_from_customer_total, informational) so renderer/UI cannot recalculate totals from live reservation/payment/price rows. 2026-07-07 source mining: legacy render paths reload live reservation/payment/caregiver rows at render time, choose the service-use template by service-start year, write current/previous main caregiver from RESERVATION_MANAGER_LOG_TB or MANAGER_TB, and adjacent voucher/intake documents write provider count plus primary/sub caregiver names from MANAGER_INFO/SUB_MANAGER. Producer-side render source must freeze service period/type, mother name/contact/registered and service addresses, privacy-safe birth date derived from voucher resident-number fragments, branch legal/contact facts, branch stamp and mother signature asset references, payment deposited contract date, primary/current/previous caregiver display facts, assistant roster display facts by assignment key, manager personality text used by intake documents, service balance/custom balance, add-day facts, and price component revisions before render. Additional producer evidence must freeze source price-table outputs as ChargeComponentRevisionSnapshot and service/add-date rows as ServiceOccurrenceSet; renderers must not recompute voucher special/live-in surcharge, Saturday/holiday added-day counts, add-on multipliers, rental delivery hardcodes, or first SAT/HOLI display date from mutable rows. Admin download, customer/API, and scheduled-mail paths call the same numeric document-id renderer, upload transient XLSX files to the converter, overwrite temp filenames, and scheduled mail deletes attachments after send. Backend commit 5dd338b queues service-use contract render requests from care-team assignment changes through sanmopia_document_rendering with assignment/source evidence and render idempotency. Backend commit 3cdc86a consumes those queued requests through the document-render worker. Backend commit e7972cc records frozen ServiceUseContractEvidenceSnapshotPayload as ServiceUseContractRenderSource rows and adds readiness so incomplete rows retry instead of rendering. Backend commit 1ff144e adds the producer-side fact-reader port/projector. Contract commit d9faf9e exposes render-source readiness/missing-fact contract. Backend commit 9f16fc1 adds Supabase fact reading for service-calendar plan, paid payment, care-team assignment decision, finalized charge snapshot, and finalized charge lines. Backend commit c7ad654 projects render-source rows from care-team assignment invalidation and reads enabled document-definition active windows as the template decision. Backend commit aa92fce adds branch-stamp/mother-signature asset readiness facts and backend-owned document-center download readiness from stored artifacts. Backend commit 92aed4f reads safe redacted resident identity evidence rows into identity_evidence without raw resident-number columns. Contract commit 7cb680d exposes document-center projection and snapshot-revision-aware render request codes. Remaining work: redacted mother identity evidence producer, immutable branch stamp/mother signature asset snapshots, storage/access grants, and live E2E without live reservation/manager SQL at render. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:167-179, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:251-260, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:316-332, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4284-4297, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4434-4600, source-refs/sanmopia-admin/application/models/Reservation_model.php:938-963, source-refs/sanmopia-admin/application/models/Branch_model.php:157-166, source-refs/sanmopia-admin/application/models/Branch_model.php:481-518, source-refs/sanmopia-admin/application/models/Branch_model.php:561-586, source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:118-166, source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:270-276, source-refs/sanmopia_web/static/js/reservation_payment.js:40-66, source-refs/sanmopia_web/application/controllers/api/Service.php:869-882, source-refs/sanmopia_web/application/models/Payment_model.php:12-42, source-refs/sanmopia_web/application/controllers/MyReservation.php:352-372, source-refs/sanmopia_web/application/views/mypage/reservation_document.php:118-139, source-refs/sanmopia_web/application/models/User_model.php:461-489, source-refs/sanmopia_web/application/controllers/api/ReservationDocument.php:21-55, source-refs/sanmopia_web/application/models/Reservation_model.php:2769-2820, source-refs/sanmopia-admin/application/controllers/SanmoInterface.php:37-51, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:104-132, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:200-227, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:330-365, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:666-688 | document_reporting / RedactedMotherIdentityEvidenceSnapshot, BranchStampAssetSnapshot, MotherSignatureAssetSnapshot, StoredPrintableDocumentArtifact, PrintableDocumentAccessGrant | Partial | Post-c7ad654 producer gap evidence: backend now reads service-calendar, payment, care-team, charge, document-definition, and safe redacted identity evidence facts, but remaining facts still come from legacy live render behavior. Mother birth date is still reconstructed in legacy renderers from raw voucher resident-number fragments unless the modern producer writes sanmopia_redacted_resident_identity_evidences; branch stamp and mother signature are mutable file paths with overwrite/delete lifecycle and no version/checksum/grant; customer download uses a two-hour token plus live admin render and direct PDF byte stream; scheduled mail writes converter temp PDFs and deletes attachments after send. Next backend slices should produce the redacted identity evidence row, asset snapshots, stored artifact, and access grant facts before render. |
| P1 | source-refs/sanmopia_web/application/views/service/step3_voucher.php:70-90, source-refs/sanmopia_web/application/models/Reservation_model.php:488-510, source-refs/sanmopia_web/application/models/Reservation_model.php:2448-2458, source-refs/sanmopia-admin/application/models/Reservation_model.php:5058-5066, source-refs/sanmopia-admin/application/models/Reservation_model.php:938-963, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:251-260; backend 42f7ed0 and 92aed4f service_use_contract_evidence_snapshot_projection.py, supabase_service_use_contract_evidence_snapshot_fact_reader.py | document_reporting / RedactedMotherIdentityEvidenceSnapshot; member_management / VoucherResidentIdentityEvidence | Backend fact-reader foundation | Service-use contract mother birth date must not be produced by reopening raw voucher resident-number fragments during render. Source customer intake captures raw front/back resident-number values, stores them as USER_NUMBER1/USER_NUMBER2, admin creation writes the same raw columns, one clone path unsets those fields as sensitive, and the renderer still derives display birth date from the raw fragments. Backend now records identity_readiness from voucher recipient identity decision metadata, excludes raw resident-number and decision snapshot columns, and fills identity_evidence only when a safe sanmopia_redacted_resident_identity_evidences row supplies birth_date, evidence_kind, and redaction_profile_key. Remaining work: implement the producer that converts verified voucher identity into the redacted evidence row with display birth date, mask profile, source evidence key, source revision, and grant scope. |
| P1 | source-refs/sanmopia-admin/application/libraries/Uploadlib.php:47-90, source-refs/sanmopia-admin/application/libraries/Uploadlib.php:123-170, source-refs/sanmopia_web/application/libraries/Uploadlib.php:40-76, source-refs/sanmopia_web/application/libraries/Uploadlib.php:110-124, source-refs/sanmopia-admin/application/models/Branch_model.php:481-518, source-refs/sanmopia-admin/application/models/Branch_model.php:561-586, source-refs/sanmopia_web/application/models/Payment_model.php:12-42, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:183-207, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:316-332 | document_reporting / BranchStampAssetSnapshot, MotherSignatureAssetSnapshot; branch_operations / BrandAssetLifecycle | Partial | Legacy file handling records relative paths and original names only. Branch stamp and mother signature uploads overwrite mutable DB path columns and delete previous files; service-use contract rendering dereferences current files with file_exists. Implement asset producers with storage bucket/object key, object generation/version, sha256 checksum, byte size, media type, source row revision, actor/source command evidence, access grant reference, and readiness codes; renderer must consume asset snapshots only. |
| P1 | source-refs/sanmopia-admin/application/controllers/DataRoom.php:80-96, source-refs/sanmopia-admin/application/controllers/DataRoom.php:311-376, source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:66-86, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-3940, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4284-4423, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4434-4600, source-refs/sanmopia_web/application/controllers/MyReservation.php:352-372, source-refs/sanmopia_web/application/views/mypage/reservation_document.php:118-139, source-refs/sanmopia_web/application/models/User_model.php:461-489, source-refs/sanmopia_web/application/controllers/api/ReservationDocument.php:21-55, source-refs/sanmopia_web/application/models/Reservation_model.php:2769-2820, source-refs/sanmopia-admin/application/controllers/SanmoInterface.php:37-51, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:104-132, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:200-227, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:330-365, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:666-688 | document_reporting / StoredPrintableDocumentArtifact, PrintableDocumentAccessGrant, ServiceUseContractRenderSourceOnlyArtifactBuilder | Partial | Admin data-room and customer document flows still pass numeric document ids into live renderers. makePdfData() and makePdfDataToSendMail() reload mutable reservation/service/rental rows, write temp XLSX/PDF files named from current mother/reservation data, call the converter, and return direct bytes or temp paths; scheduled mail deletes attachments after send; customer access is a two-hour token over USER_TOKEN_TB. Implement a service-use-contract render-source-only artifact builder, persist StoredPrintableDocumentArtifact with checksum/storage-version/render-source revision, issue PrintableDocumentAccessGrant per customer/admin/mail surface, and guard or reroute legacy live-render path for document id 1. |
| P1 | source-refs/sanmopia-admin/application/controllers/DataRoom.php:80-96, source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:66-86, source-refs/sanmopia_web/application/views/mypage/reservation_document.php:118-139, source-refs/sanmopia_web/application/controllers/api/ReservationDocument.php:21-55; backend aa92fce application/document_reporting/features/document_center/project_document_center.py; backend 695943a interfaces/document_center_http.py; contract 7cb680d packages/ts-client/src/types/document-reporting.ts:806-864 | document_reporting / DocumentCenterProjection, DocumentCenterCatalogItem, DocumentCenterDownloadHandoffDescriptor, DocumentCenterBundleDownload; frontend / DocumentCenterStore | Backend API bound | Backend now projects document-center catalog eligibility, latest stored artifact metadata, per-document handoff descriptors, bundle included/missing definition keys, and bundle availability. FastAPI exposes the projection through authenticated GET /document-center-projections/{reservationBookingId} with camelCase aliases. Contract exposes the projection fields. Frontend must consume this through a Nanostores-backed document-center store and render actions from backend handoff descriptors; browser code must not compose numeric document ids, token query strings, render request codes, bundle members, missing-artifact state, or service-kind eligibility. Remaining work: signed-storage handoff implementation, frontend store/view-model integration, and legacy live-render guard/reroute for service-use contract document id 1. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:183-225, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:316-332, source-refs/sanmopia-admin/application/models/Branch_model.php:157-166, source-refs/sanmopia-admin/application/models/Branch_model.php:481-504, source-refs/sanmopia-admin/application/models/Branch_model.php:561-575, source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:118-166, source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:270-276, source-refs/sanmopia_web/static/js/reservation_payment.js:40-66, source-refs/sanmopia_web/application/controllers/api/Service.php:869-882, source-refs/sanmopia_web/application/models/Payment_model.php:12-42 | document_reporting / ServiceUseContractAssetSlotSnapshot, BranchStampAssetSnapshot, MotherSignatureAssetSnapshot, ServiceUseContractAssetReferenceSnapshot; branch_operations / BrandAssetLifecycle | Backend-backed foundation | Service-use contract places current branch stamp and mother signature into year-dependent slots P69/P66 and J69/J66. Source reads BRANCH_TB.STAMP_IMG_URL again during render, converts that mutable file to JPEG, and reads RESERVATION_TB.SIGN_IMG_URL after the customer payment-request flow overwrites the signature image and deletes the previous file. Branch stamp can also be uploaded/deleted through office-management actions without artifact versioning. Backend now models ServiceUseContractAssetSlotDefinition, ServiceUseContractAssetSlotSnapshot, immutable asset version/checksum/grant data, slot readiness, and public contract/schema so renderers do not dereference current mutable branch stamp or mother signature paths. Remaining producer work: persist BranchStampAssetSnapshot and MotherSignatureAssetSnapshot into ServiceUseContractRenderSource with storage object version/checksum/source revision/readiness, connect branch/customer media lifecycle revisions from BrandAssetLifecycle, and issue storage/access grants. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:629-636, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:644-660, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:667-699, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:711-725, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:731-779 | document_reporting / DownPaymentBreakdownArtifactLineSnapshot; pricing_settlement / ChargeComponentSnapshot | Backend-backed foundation | Down-payment artifact line projection now consumes frozen charge components and maps them to explicit slot projections, so document rendering cannot recalculate voucher surcharge, Saturday/holiday add-on, rental, pump, delivery, checkbox, quantity, or amount formulas. Public contract exposes component kind, quantity basis, unit/total amount, source price key, pricing policy version, calculation reason, included-in-total flag, display label, slot kind/key/value, and source evidence. Remaining work: bind pricing settlement quote/catalog builders and Supabase persistence to produce the frozen components. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:629-636, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:719-725, source-refs/sanmopia-admin/application/models/Reservation_model.php:5985-6012 | pricing_settlement / DownPaymentVoucherSurchargeComponentSnapshot; document_reporting / DownPaymentArtifactSlotProjection | Backend-backed foundation | Voucher 입주/스페셜 surcharge can now be represented as voucher_surcharge frozen component with source price key, pricing policy version, calculation reason, and slots such as AA10/AC12. Remaining work: bind voucher add-on price reader and price-version/service-detail basis to persisted pricing snapshot. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:647-660, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:731-779, source-refs/sanmopia-admin/application/models/Service_model.php:238-254, source-refs/sanmopia-admin/application/models/Payment_model.php:4196-4219 | pricing_settlement / AdditionalServiceChargeComponent; document_reporting / DownPaymentAdditionalServiceLineSlotProjection | Backend-backed foundation | Added-day/add-on document lines now have frozen quantity basis (effective_service_day, added_service_day, item_quantity, or source_component_total) plus slot projections, preventing duplicated renderer formulas. Remaining work: bind actual additional-service pricing policy and mismatch repair between quote path and document path. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:667-699, source-refs/sanmopia-admin/application/models/Reservation_model.php:748-770, source-refs/sanmopia-admin/application/config/constants.php:99, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:21 | pricing_settlement / RentalEquipmentChargeComponent; document_reporting / DownPaymentRentalEquipmentLineSlotProjection | Backend-backed foundation | Rental and delivery document lines now represent rental item charge, delivery fee, source price key, policy version, catalog/display label, checkbox slot, and included-in-total flag without hardcoded renderer fees. Remaining work: bind rental catalog and delivery max-once decision from pricing settlement. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3950-3953, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4307-4309, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4459-4461, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:72-95, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:182-192, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:648-653 | document_reporting / DownPaymentArtifactEligibilityProfile | Backend-backed foundation | Down-payment artifact eligibility is now a backend profile/decision with actor channel (admin_bulk_download, customer_pdf, start_mail_attachment, manual_send), service kind, start-mail payment cutover, manual-send allowance, reason code, template version, and source evidence. Remaining work: persist profile revisions, bind catalog/document-delivery routes, and remove numeric id 4 bundle arrays from callers. |
| P1 | source-refs/sanmopia-admin/application/config/constants.php:228-231, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3959-3999, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:1046-1051, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:2616-2690, source-refs/sanmopia-admin/application/models/Reservation_model.php:334-376, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:2829-2853 | document_reporting / CaregiverServiceRecordRoleScopedArtifactSeries, CaregiverServiceRecordChunkWindowSnapshot, CaregiverServiceRecordSourceReaderConsistency | Partially represented | Service-record export uses doc id 6 for primary MANAGER_SERVICE_TB, doc id 20 for assistant MANAGER_SUB_SERVICE_TB, emits artifact filenames with offset but no role marker, chunks exactly 10 rows per artifact, stops when count <= offset, and uses template 10 repeated column/signature slots. Source render ordering joins signatures by SERVICE_DT, while reset reader uses CREATED_DT without the same signature join. Backend bundle must own role-qualified artifact keys, source table/reader, assignment key, ordered record ids, chunk size/start offset/index, total source count, no-empty-overflow rule, frozen caregiver/mother signature asset refs, and missing-signature readiness reasons. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:815-837, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:844-857, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3955-3957, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4311-4313, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4463-4465, source-refs/sanmopia-admin/application/models/Payment_model.php:191-211, source-refs/sanmopia_web/application/models/Payment_model.php:12-40, source-refs/sanmopia-admin/application/controllers/SanmoInterface.php:37-51 | document_reporting / PrivacyConsentFactSnapshot, PrivacyConsentSignatureAssetSnapshot, PrivacyConsentArtifactEvidenceSnapshot | Backend-backed foundation | Privacy consent sheet legacy behavior now has backend/domain and public contract foundation: consent fact snapshot requires signer/member identity, capture source, timezone-aware consent timestamp, explicit accepted consent categories, source evidence, and payment evidence only as migration evidence for signed-source artifacts. Signature snapshot requires immutable storage object version key, checksum, signer match, grant policy, and source evidence. Artifact evidence returns channel-neutral readiness (ready, missing_consent_category, missing_signature_asset, incomplete_signature_asset), so payment DEPOSITED_DT, auto-checked boxes, current SIGN_IMG_URL, deleted previous files, or missing signature cannot silently become render authority. Remaining work: persist consent/signature snapshots in Supabase, bind customer upload migration, render worker, and access-grant workflow. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:1083-1132, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:1212-1219, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5078-5128, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5136-5144, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5211-5225, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5230-5240, source-refs/sanmopia_web/application/models/Constdata_model.php:165-216, source-refs/sanmopia-admin/application/models/Reservation_model.php:5636-5663, source-refs/sanmopia-admin/application/models/Reservation_model.php:5805-5820 | document_reporting / VoucherReceiptBenefitPeriodSnapshot, pricing_settlement / VoucherPlanCatalogRevisionSnapshot | Backend-backed foundation | Voucher receipt and catalog source behavior now has backend/domain, application contract, public TS, and JSON Schema foundation. VoucherPlanCatalogRevisionSnapshot freezes consume-type id/value/parts, positional service-day classification enum, price version, service detail, baby type, delivery count, price lines, government/customer/caregiver amounts, live-in conversion, add-option revision, and price-row evidence. VoucherConsumeTypeRemapDecision blocks price-version remap when SERVICE_DAY_LIST signature changes and carries optional compatibilityRuleKey for source catalog-transition exceptions instead of exposing numeric id formulas. VoucherReceiptBenefitPeriodSnapshot freezes branch, benefit period, consume-type parts, service-day classification, catalog/price-line keys, and receipt amounts so template/UI cannot split strings or infer list-index meaning. Backend 2c744fb persists and publishes immutable normalized voucher-plan revisions, validates the exact ordered option/price-line/entry-code bijection against a published zero-issue price batch, restores secondary caregiver net pay during import, and projects the ordered non-monetary service-day catalog through named orchestration. Backend c1937ed adds completed source revisions/slices, explicit service-detail/baby-type/delivery-count/benefit-band/day axis binding without consume_type_ prefix inference, atomic full-population publication, population-linked revision reads, and exact committed selection without caller-owned revision/batch/version keys or latest fallback. Backend b44fd49 binds the exact selector to the reservation bridge using canonical axes/date only and rejects decision drift before revision read. Backend 7a9d26e adds the active-session HQ/SpiceDB approval caller, DB-owned time and canonical manifest, approved-only RPCs, legacy-row quarantine, and immutable linkage guards. Remaining work: business selection, approval, and invocation of one exact source/version, canonical draft-axis resolution, draft prepare trigger and exact-26 snapshot refresh, receipt snapshot persistence, receipt renderer/settlement readers, and historical voucher receipt backfill. |
| P1 | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:1134-1204; source-refs/sanmopia-admin/application/models/Branch_model.php:481-513; source-refs/sanmopia-admin/application/models/Manager_model.php:1559-1593, source-refs/sanmopia-admin/application/models/Manager_model.php:1667-1684 | document_reporting / PrintableSignatureAssetSnapshot | Backend-backed foundation | Source documents dereference mutable stamp/signature file paths at render and profile updates delete previous media. Backend now adds shared PrintableSignatureAssetSnapshot and replacement planning with owner kind, role, immutable storage object version key, checksum, lifecycle state, retention policy, superseded asset pointer, and public contract/schema. Old branch/caregiver media can be marked superseded-retained instead of deleted, so historical contracts/receipts do not drift. Remaining work: persist asset snapshots in Supabase/R2, bind branch/caregiver/customer upload flows, and route render workers through snapshot references only. |
| P1 | source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:144-158 | pricing_settlement / PaymentChangeAdjustmentAmountBreakdown, MotherVisibleChargeSnapshot | Backend-backed foundation | Payment-change tables must not recompute coupon totals inside an ajax list. Backend now models approval-time PaymentChangeAdjustmentAmountBreakdownSnapshot, MotherVisibleChargeSnapshot, coupon allocation evidence, discount source, queryable Supabase snapshot columns, operator-board projection fields, and public TS/JSON schema contract so UI cannot recalculate the displayed amount from mutable coupon rows. 2026-07-06 follow-up: the backend HTTP/API request boundary now requires nested requestedAmountAuthority, converts that frozen authority into the application command, and rejects the legacy scalar customerDeltaKrw/couponAdjustmentKrw/pureCustomerAmountKrw request shape before handler execution. 2026-07-06 regional-benefit follow-up: requested amount authority now includes RegionalBenefitChargeImpactAcknowledgement; Supabase stores the acknowledged finalized charge snapshot id plus frozen impact event ids, and the handler rejects stale or missing acknowledgements before accepting payment-change amount authority. Remaining work: bind every runtime approval reader to create snapshots for payment-change paths, backfill legacy rows from source evidence, and update external clients to send authority snapshots only. |
| P1 | source-refs/sanmopia-admin/application/controllers/Reservation.php:1739-1758 | reservation_operations / ServiceAreaCalendarProfile, service_calendar / ServicePeriodPlan | Backend-backed foundation | Source locality day additions now resolve through backend-owned service-calendar policy profile rows with service_area_profile_key, optional matched service-area rule evidence, address scope, branch profile, effective dates, and policy fingerprint. SupabaseServiceCalendarPolicyProfileReader selects exact service-area/branch/rule snapshots before global fallback, and generated contracts expose frozen policy-profile evidence on service-calendar plan snapshots so UI cannot add days from source locality labels. Remaining work: bind booking/admin mutation runtime to branch service-area decisions, backfill historical profile rows, expose operator profile management, and verify pricing/matching/refund/settlement consumers read the frozen plan evidence. |
| P1 | source-refs/sanmopia-admin/application/controllers/Wintherace.php:109-130, :237-323; source-refs/sanmopia-admin/application/models/Win_the_race_model.php:8-150, :150-310; source-refs/sanmopia-admin/application/views/win_the_race/branch.php:188-228; source-refs/sanmopia-admin/static/js/win_the_race/branch.js:73-115, :240-323 | business_reporting / PerformanceRecognitionProgram, RecognitionScorecardSnapshot, RecognitionLeaderboardSnapshot; branch_operations / BranchRecognitionEligibilityProfile | Partial | Backend domain foundation now models recognition program metrics with explicit date basis, closeout as RecognitionProgramCloseoutSnapshot instead of file_exists, branch eligibility as BranchRecognitionEligibilityProfile with standard/new-branch/ineligible decisions, public TS/JSON contracts for RecognitionScorecardSnapshot plus RecognitionLeaderboardSnapshot, and Pydantic application-boundary payloads for scorecard/leaderboard snapshots. Branch scorecard contribution lines freeze YoY/count/sales/manual adjustment points and total-score equality, so view/JS cannot recompute WinTheRace totals or tied ranks. Source numeric branch ids remain evidence only; target branch profile keys own identity. Remaining work: Supabase persistence, branch/HQ approval workflow, generated artifact state, manager scorecard/recommendation scoring, sales aggregation readers, command/query handlers, and UI binding. |
Open Gap Register
Section titled “Open Gap Register”These rows keep source-backed work visible while backend workers migrate slices.
Requires source-dig means existing docs identify the gap, but exact source
parity still needs deeper source verification before marking Migrated.
| Gap area | Current status | Checklist anchors | Required migration gate |
|---|---|---|---|
| Reservation lifecycle and collaboration | Partial | reservation_operations / reservation_collaboration, service_calendar, pre_reservation_conversion, customer_reservation_intake_draft, customer_reservation_intent | Every reservation create/change/convert/cancel/extend/stop/offline path writes backend commands, expected revisions, durable state transitions, service-calendar impact facts, and actor-stage projections. |
| Pricing, quote, subsidies, and price catalog | Partial | pricing_settlement / public_fee_guide_catalog, price_catalog_import_execution_audit, regional_benefit_policy, reservation_price_version_adjustment | Price catalog, regional support/subsidy, voucher/general version policy, add-day/rental/coupon facts, and charge snapshots are effective-dated backend facts. UI calculators become diagnostics only. |
| Payment and billing through Kill Bill | Partial | customer_payment_instruction, payment_change_adjustment, PaymentProductPlan, ReservationPaymentWorkflow, Kill Bill admin operations | Backend freezes product plan, method, route, fee, amount, provider context, communication request, idempotency, and workflow state before provider handoff. No UI payment-purpose inference. Backend follow-up on 2026-07-08 moved payment-change operator board access to HQ settlement review_hq_settlement, row visibility to reservation_booking#view, and payment repair/fact-edit commands to booking-scoped finalize_charge / close_reservation_finance checks instead of Supabase role metadata. 2026-07-08 RBAC hardening now resolves OperatorPaymentFactEditCommand actor kind through SpiceDB reservation_booking#review_hq_settlement or booking-branch manage, and reads branch scope from backend booking state instead of Supabase app_metadata.branch_profile_id. |
| Refund and partial refund | Partial | payment_refund, ReservationCancellationRefundPolicy, PaymentRefundIntent, PaymentAdjustmentCatalog | Refund quotes, coupon/benefit restore, zero-gateway refunds, partial provider cancel events, operator overrides, receipt artifacts, and settlement reversals are ledger-backed. |
| Settlement: external counterparty, branch, HQ, inter-office | Partial | settlement_statement, settlement_data_room, settlement_collection_export_repository, InterOfficeSettlement, SettlementDataRoomCollection, ReservationExternalSettlementCounterpartyStatus | Branch/HQ/external-counterparty/inter-office statements, row acknowledgements, manual rows, export datasets, repair history, signed grants, and workflow states stay separate. Branch settlement board source status codes are now mapped by branch_settlement_status_acl.py, not domain enum methods. 2026-07-09 naming hardening moved board transition import repair to settlement_board_transition_provenance, ImportedSettlementBoardTransitionRow, and source_branch_marker so old-source vocabulary stays out of domain/application contracts. Reservation-scoped external counterparty source status codes are now mapped by external_settlement_counterparty_status_acl.py, not domain helpers. Source-specific API routes, Supabase table names, and external-recipient protocol require source-dig plus forward compatibility migration before final contract naming. |
| Caregiver matching and payroll | Partial | caregiver_matching, assignment_decision_evidence, caregiver_compensation, caregiver_payout_statement, CaregiverPerformanceScorecard | Candidate snapshots, policy version, optimizer input, assignment decision, grade snapshot, ordered assistant roles, payout slot, tax election, and receipt state are backend facts. Backend follow-up on 2026-07-08 moved care-team current roster, assignment history, and compensation source reads behind SpiceDB reservation_booking#view checks before any caller-scoped Supabase RLS reader/repository is opened. |
| Document generation, printing, and grants | Partial | printable_document, printable_template_version_manifest, ReservationDocumentTemplate, VoucherEndNoticeReadiness, CustomerDocumentAvailabilityProjection | Catalog, template version, A4/PDF/ZIP artifacts, start/end delivery batches, signed/revoked grants, retry ledger, and access history are persisted backend state. |
| RBAC and SpiceDB authorization | Partial | ActorStageCapabilityProjection, OperatorIdentitySession, BranchRelationshipGrant, Identity and RBAC end-to-end | Supabase Auth supplies actor identity only. Supabase app_metadata, profile member_role, and RLS predicates are non-authoritative hints/safety rails, not Sanmopia app RBAC. SpiceDB relationship checks own branch/HQ/reservation/caregiver/settlement capability decisions; OPA owns policy-context gates, field visibility, disabled reason, and audit context. Backend follow-up on 2026-07-08 centralizes HQ-scoped authority object IDs in SanmopiaSpiceDBAuthorityId and extends the SpiceDB relationship outbox so branch-to-HQ sync also queues every hq_settlement#headquarters_branch authority tuple. Same RBAC pass moves caregiver grade recalculation history to HQ_SETTLEMENT:caregiver_grade_recalculation_history#review_hq_settlement, derives workflow-status reservation capability actor kind from SpiceDB/resource ownership instead of JWT roles, resolves family-account member identity from backend-owned member profiles instead of app_metadata.member_id, removes the caregiver schedule JWT-role gate, deletes the unused settlement actor metadata helper, and revokes direct authenticated Data API reads from caregiver grade history tables so backend service-role reads happen only after SpiceDB authorization. Follow-up export pass moves reservation-history dataset/artifact reads behind SpiceDB branch/booking checks and removes direct authenticated Data API policies from reservation-history export tables. Service-calendar holiday audit writes/previews now rely on backend SpiceDB service_calendar#manage and branch#manage checks before service-role persistence, with direct authenticated Data API policies revoked/dropped from the audit tables. Payment fact edit actor resolution now ignores forged Supabase branch metadata; HQ operators require booking review_hq_settlement, branch operators require backend booking branch scope plus SpiceDB branch manage. Open RBAC audit item: platform-level active-member/session helpers still expose app-metadata role/privacy accessors until member privacy/session projection fully owns them. |
| Workflow and state management | Partial | WorkflowStatusProjection, ReservationBookingWorkflow, ReservationPaymentWorkflow, ReservationFinancialLifecycleWorkflow, MemberPrivacyLifecycleWorkflow | Restate owns durable workflow execution; Supabase owns service-role ledgers/read/RLS; portals poll filtered backend projections and never call workflow internals or infer state from raw rows. |
| Approval and settlement workflow authorization | Partial | HeadOfficeManagerOperations, BranchOwnerOperations, SettlementStatementCommandHandler, BranchSettlementReconciliationExportWorkflow | HeadOfficeManager approval and BranchOwner acknowledgement commands must share Supabase Auth identity, SpiceDB relationship checks, expected revision, idempotency fingerprint, append-only transition audit, and Restate repair/export workflows. Backend follow-up on 2026-07-08 split settlement statement, settlement data-room, and inter-office settlement actor-kind authorization from Supabase metadata: branch preparation/data-room commands require prepare_branch_settlement, HQ review/private memo/data-room and inter-office opening require review_hq_settlement, data-room workflow progress requires the workflow authority check, inter-office opening also checks both customer/service branch settle scopes, and forged/stale app metadata cannot promote a branch actor to HQ reviewer or workflow actor. Same RBAC pass now removes metadata-only workflow-status fallbacks and KillBill admin-operation role bypasses: workflow projections require same-user ownership or concrete SpiceDB resource ids, and KillBill admin operations require booking close_reservation_finance or HQ settlement close. Follow-up workspace pass now derives settlement data-room workspace actors from SpiceDB permission paths (branch#prepare_branch_settlement, branch#review_hq_settlement, HQ/workflow settlement authorities) instead of Supabase role metadata, and the relationship outbox now seeds those HQ authority resources from branch-to-HQ sync. Remaining audit: source-dig hidden authorization helpers and profile/audit enrichment paths still need removal or explicit non-authority documentation. |
| Audit and conflict resolution | Partial | ReservationCollaborationWorkspace, ReservationCollaborationConflictLog, SettlementTransitionAudit, WorkflowStatusProjection | Stale writes return conflict diffs, not silent overwrites. Reservation, payment, settlement, branch-profile, and document repair commands must persist actor, reason, expected revision, decision winner, and repair linkage before portals refresh. |
| OTel, load, and queue readiness | Partial | observability-backpressure, SupabaseQueueContract, SupabaseQueueWorker, WorkflowStatusProjection | Queue depth, oldest age, retry, dead-letter, in-flight worker, workflow-blocked, payment-provider latency, and settlement-export latency signals must be emitted through OpenTelemetry with trace context and idempotency keys. |
2026-07-06 Source-Dig Delta
Section titled “2026-07-06 Source-Dig Delta”| Priority | Status | Modern ubiquitous name | Source evidence | Migration note |
|---|---|---|---|---|
| P0 | Partial | RegionalBenefitEligibilityDecision | source-refs/sanmopia-admin/application/views/reservation_status/reservation_add.php:254-303, source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:874-948, :1231-1253, :1519-1539, source-refs/sanmopia_web/application/views/service/step3_voucher.php:142-185, source-refs/sanmopia_web/static/js/step3.js:886-942, source-refs/sanmopia_web/static/js/step3_voucher.js:80-137, :190-195, :345-379 | Source eligibility is two separate local benefits. Wanju: voucher service only, service address level 2 starts as 완주군, operator/customer must choose apply yes/no, then detail option 일반 or 50% 이하자; selected option posts add-option id/name/price and service-day bonus. Yeongdeungpo: voucher service plus service address 서울/영등포구, then explicit health-center discount apply flag; source comment marks some UI removed but model/payment paths still consume YEONGDEUNGPO_FL. 2026-07-06 backend follow-up: RegionalBenefitEligibilityDecision is now a public domain name, applied lines preserve source_evidence_key, Supabase regional-benefit rules load/persist source_evidence_key, and booking HTTP/API plus TS/JSON contracts carry nullable sourceEvidenceKey on accepted regional benefit lines. Remaining work: reservation entrypoints must resolve the decision from catalog/address/profile data before workflow start, add explicit decision ids and option/grant state, and ensure UI/admin forms render decisions without branching on raw sigungu, wanju_fl, wanju_option, or Korean region labels. |
| P0 | Partial | RegionalBenefitChargeImpactSnapshot | source-refs/sanmopia-admin/application/models/Reservation_model.php:714-816, :1498-1534, :4103-4180, :4864-5038, :5233, :5628-5642; source-refs/sanmopia-admin/application/models/Payment_model.php:436-437, :3760-3764; source-refs/sanmopia_web/application/models/Reservation_model.php:1181-1195, :1267-1274, :2523-2553, :2680-2692, :2839-2845; source-refs/sanmopia_web/application/controllers/api/Service.php:346-349 | Source charge impact spans quote, payment, service period, and persistence. Yeongdeungpo subtracts DISCOUNT_YEONGDEUNGPO_PRICE_LATEST from displayed discount and own-price/customer-fee math only when voucher + address level 1 서울 + level 2 영등포구 + flag YEONGDEUNGPO_FL == 1; admin payment also requires branch id 20 in some settlement/payment summaries. Wanju inserts voucher add-option ids 24/25 or selected option id, adds one option row, adds 5 service days/end-date days, and changes customer-visible add-price/service-period calculations. 2026-07-06 backend follow-up: domain now has RegionalBenefitChargeImpactSnapshot with eligibility_decision_id, benefit_code, profile_key, stable source_option_key, source_required_flag_key, discount/own-price/service-day/end-date deltas, settlement participation, amount source key, catalog/price version, address proof, actor/source surface, and frozen line event id. RegionalBenefitRule and Supabase policy rows carry policy_version_label, source_option_key, own_price_adjustment_krw, and service_end_date_delta_days; FinalizeReservationChargeWithRegionalBenefitHandler freezes impact snapshots into FinalizedReservationChargeSnapshot, sanmopia_finalized_charge_snapshots.regional_benefit_charge_impact_snapshots, and booking RPC payloads. Refund requotes now have RegionalBenefitRefundImpactReference, SupabaseRegionalBenefitRefundImpactReader, HTTP/API acknowledgement fields, and composition-root wiring, so cancellation refunds cannot silently requote against stale regional-benefit frozen lines. Approved-payment charge finalization now validates regional benefit summary columns against the same frozen impact rows before opening or advancing the financial lifecycle. Payment-change amount authority now requires RegionalBenefitChargeImpactAcknowledgement against the finalized charge snapshot and frozen impact event ids before accepting a customer-visible adjustment amount. Remaining work: payment conversion, service calendar, branch settlement, and HQ settlement consumers must read this frozen impact array instead of re-evaluating locality/option flags. |
| P0 | Partial | BranchCoverageAddressFallbackRule | source-refs/sanmopia_web/application/models/Branch_model.php:45-126 | Source serviceability splits composite address2 values, checks exact/parent/city-wide/fallback keys, and vetoes possible/consultation matches when an impossible-area row also matches. Backend now promotes ordered coverage lookup key generation into shared kernel so AddressAdministrativeProfile, managed service-area lookup, and BranchServiceAreaPolicy.resolve_active_policy use the same exact, parent, level-1, and composite-level-2 fallback order. BranchServiceAreaPolicyDecision now carries lookup_address_key_values, matched_lookup_address_key, matched_lookup_address_depth, and vetoed_serviceable_rule; HTTP/TS/JSON contracts expose the same evidence, and Supabase stage schema persists coverage_lookup_address_keys, resolved_lookup_address_key, resolved_lookup_address_depth, and vetoed_serviceable_policy_rule_reference on sanmopia_branch_service_area_address_evidence. Remaining migration: bind first-period, second-period, extension, and continuation reservation workflows to this frozen decision before branch ownership, pricing, matching, and transfer audit run. |
| P0 | Partial | OperatorPaymentFactEditCommand | source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:1217-1272, source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1350-1379, source-refs/sanmopia-admin/application/controllers/Reservation.php:676-687, source-refs/sanmopia-admin/application/controllers/Reservation.php:849-859, source-refs/sanmopia-admin/application/controllers/Reservation.php:1538-1616, source-refs/sanmopia-admin/application/models/Reservation_model.php:1566-1678 | Admin UI exposes deposit-date fields by service type/payment version, hardcodes offline reservation status 19 on add, posts service-balance deposit date only when browser status text is 완료, and controller writes reservation deposit, balance deposit, and service-balance deposit rows from those raw dates. Model code treats date presence as paid/unpaid, blocks only refunded rows, and recalculates payment amount from current coupon, pre-reservation, in-home surcharge, Yeongdeungpo discount, and service-balance policy while overwriting PRICE, DEPOSITED_DT, and PAYMENT_STATUS_LIST_ID_FK. 2026-07-06 backend follow-up: commit 8786359 adds pricing_settlement/features/payment/operator_payment_fact_edit with OperatorPaymentFactEditCommand, OperatorPaymentDateCorrectionPolicy, payment purpose, explicit paid/unpaid intent, recorded deposit date, expected payment revision, actor capability evidence, reason, idempotency key, immutable amount snapshot, correction audit, shared audit fingerprint helper, and projection invalidation keys. Commit 5a2ac5c adds the application handler/store port, Supabase payment-fact read adapter, idempotent correction lookup, RPC-backed persistence, sanmopia_operator_payment_fact_corrections, payment-record revision/snapshot columns, service-balance closeout RPC lint fix, and restrict FK retention guard. Commit ff4e996 adds protected HTTP/API binding, Supabase-auth actor derivation, SpiceDB-backed capability evidence, main app handler wiring, and correction response facts for audit/projection refresh. Commit 4f7b672 blocks legacy-style existing payment fact overwrite through the receipt path and points callers to OperatorPaymentFactEditCommand. Commit 9de2d68 backfills historical payment-row amount snapshots and makes new receipt/pre-registration rows write deterministic payment fact amount snapshot keys. Commit 49245dc projects payment fact amount snapshot keys onto payment-change operator board rows and invalidates settlement board read models for manual payment fact edits. Commit 183f8f4 blocks reservation collaboration payment-date broad-save, exposes payment_fact.operator_edit_targets with payment fact id/revision/amount snapshot evidence for reservation detail, and removes unsafe security-definer use from payment fact correction RPCs. 2026-07-07 debt follow-up: PaymentCorrectionAmountChange now gives payment-date correction and payment-change amount-correction audit one shared previous/corrected amount vocabulary and signed delta instead of duplicate non-negative amount guards. 2026-07-08 RBAC follow-up: ReservationPaymentRecordAuthorizationService.authorize_operator_payment_fact_edit_actor() derives HQ/branch actor kind from SpiceDB permission paths and reads booking branch scope through SupabaseReservationPaymentBookingScopeReader; Supabase app_metadata.branch_profile_id is ignored. 2026-07-13 contract/frontend boundary follow-up adds public OpenAPI and TS request/response contracts for /reservation-payment-facts/{paymentFactId}/operator-corrections, validates explicit intent, expected revision, frozen amount snapshot, paid-date consistency, audit response, and projection invalidations, and adds the authenticated frontend client adapter. Remaining migration: reservation-detail projection must render command targets and bind the admin controls to this client. Browser forms must not infer payment status, amount, or lifecycle transition from date fields or display status text. |
| P0 | Partial | PaymentProviderCloseoutCompensationSaga | source-refs/sanmopia_web/application/controllers/api/Payment.php:13-58, :150-218, :272-303, :388-413, :553-591, :720-762; source-refs/sanmopia_web/application/models/Payment_model.php:383-435, :856-900; source-refs/sanmopia_web/application/libraries/Kcppayment.php:418-475 | KCP-era closeout has provider action followed by local reservation/payment/coupon/payment-change writes. The approval-key route reads good_mny and Ret_URL from browser GET despite the inline warning that amount/return URL should come from server session; reservation deposit, gift-coupon payment, customer-share balance, pre-reservation deposit, and payment-change/card-replacement all call the provider first, then call local model writes, then attempt immediate full KCP cancel (STSC) on local DB/transaction failure. Inline compensation results are not durable: each controller path calls $kcppayment->refund() and immediately returns the original local error, while Kcppayment::refund() always returns status => false even after a provider refund request. Payment-change init accepts posted price, deletes unpaid drafts, and later stores provider context plus DEPOSIT_DT. Modern Kill Bill replacement must start from a backend CustomerPaymentInstruction/payment-change adjustment id with frozen amount, purpose, payer, return route, provider method, settlement participation, expected revision, idempotency key, and communication plan; provider success and local persistence failure must create an auditable compensation refund intent instead of an inline best-effort KCP cancel. 2026-07-08 status proof: Kill Bill webhook acceptance and processing now exist at backend-repo/src/sanmopia_modernization/interfaces/killbill_payment_event_http.py:65-96 and backend-repo/src/sanmopia_modernization/application/pricing_settlement/features/payment/killbill_payment_event.py:356-428, including paid webhook amount mismatch failure before workflow start. Remaining proof: provider-attempt persistence for every payment purpose, compensation refund retry/workflow when local persistence or workflow start fails after provider success, partial/full refund capability mapping, and tests proving browser amount/return-url tampering, payment-change stale draft supersession, provider success plus DB/workflow failure, and provider refund failure do not leave paid local state without a ledgered repair path. |
| P0 | Backend foundation | VirtualAccountDepositReservationTransition | source-refs/sanmopia_web/application/controllers/api/Payment.php:123-158, source-refs/sanmopia_web/application/controllers/api/Payment.php:421-505, source-refs/sanmopia_web/application/controllers/api/Kcp.php:18-103, source-refs/sanmopia_web/application/models/Kcp_model.php:8-13, source-refs/sanmopia_web/application/models/Payment_model.php:166-215, source-refs/sanmopia_web/application/models/Payment_model.php:353-380, source-refs/sanmopia_web/application/models/Payment_model.php:512-734, source-refs/sanmopia_web/application/controllers/cli/Reservation.php:558-600, source-refs/sanmopia_web/application/controllers/cli/Reservation.php:741-827, source-refs/sanmopia_web/application/models/Reservation_model.php:2960-3031 | Virtual-account issue, deposit callback, expiry cron, deadline reminders, and notifications are coupled to raw KCP JSON. Source issue flow detects pay_method == vcnt, formats va_date, sends account/deadline messages, stores provider context, and changes payment status to waiting; KCP notification accepts only configured provider IPs, logs raw POST, treats non-TX00 events and op_cd == 13 cancel events as acknowledged/no-op, then finds payment rows by raw order_no/tno. It reads ipgm_mnyx and noti_id but the model matches only order_no/tno; duplicate handling is payment-row-state based (already paid -> true) rather than provider-notification-id based, cancel notifications leave no lifecycle fact, and deposit amount drift relies on the provider comment instead of comparing callback amount to the frozen payment row price. Deposit processing idempotently ignores already-paid rows, updates waiting reservation 입금대기 -> 예약 or 사전예약대기 -> 사전예약, writes payment paid status and DEPOSITED_DT = now(), closes coupon virtual-account payments by issuing coupon entitlement, and sends mother/branch notices. Expiry cron queries PAYMENT_CONTEXT.va_date JSON and changes reservation status 14 -> 17 with a change-log row before a separate notice job; a different cron warns two days before expiry by re-reading bank/account/deadline/price from the same raw context. Backend foundation commit 097030f adds VirtualAccountPaymentLifecycle and VirtualAccountDepositReservationTransition: typed issue/deposit/expired events, provider-order and transaction idempotency keys, provider paid-at time, deadline clock, expected payment/reservation revisions, payment-purpose-specific reservation transition trigger keys, audit events, and notification outbox keys. Public contracts reject raw KCP/status fields such as PAYMENT_CONTEXT, ordr_idxx, tno, pay_method, RESERVATION_STATUS_LIST_ID_FK, and Korean source labels. Balance/coupon virtual-account lifecycle events intentionally do not mutate reservation state. 2026-07-09 backend follow-up adds VirtualAccountPaymentLifecycleDecisionStore, SupabaseVirtualAccountPaymentLifecycleDecisionStore, and service-role-only table sanmopia_virtual_account_payment_lifecycle_decisions, persisting decision key, payment key, lifecycle action/state, expected/next payment revision, provider order/transaction/provider, paid/deadline timestamps, purpose, notification outbox keys, audit event key, and source evidence keys with RLS enabled. Stage DB migration was applied and verified with only service-role select/insert/update. Remaining proof: persist reservation-transition decisions, bind KCP/Kill Bill notification adapters with duplicate noti_id/amount/transaction tests, record cancel/non-TX00 callbacks as ignored lifecycle facts, invoke the existing reservation state-transition engine by trigger key, dispatch Restate notification/audit workflows, replace cron JSON deadline scans with scheduled lifecycle jobs, prove reminder/expiry messages read the same frozen instruction amount and deadline that provider issue created, and cover expired-after-paid race plus reminder idempotency. |
| P1 | Pending | DocumentMailboxPostCommand | source-refs/sanmopia-admin/application/controllers/DataRoom.php:119-197, source-refs/sanmopia-admin/application/models/Data_room_model.php:25-202, source-refs/sanmopia-admin/static/js/data_room/other_post_write.js:1-108 | Data-room post/file authority is browser/controller state; backend must own branch 36/all/null recipient semantics, exclusions, attachment revisions, delete grants, and audit. |
| P1 | Pending | ReservationDocumentBundlePolicy | source-refs/sanmopia-admin/application/controllers/DataRoom.php:311-386 | Replace board-index/service-type hardcoded download bundles with versioned eligibility and item manifests. |
| P0 | Partial | CaregiverCandidateOrderingPolicy | source-refs/sanmopia-admin/application/models/Matching_model.php:31-32, :88-160, :718-847; source-refs/sanmopia_web/application/models/Manager_matching_model.php:58-151, :248-264 | Matching order differs by surface; freeze score, distance, transit, random tie seed, stale ODSAY refresh, pet exclusion, and source-surface policy inputs/results. |
Lane C Source Feature Checklist Gaps
Section titled “Lane C Source Feature Checklist Gaps”| Legacy/source evidence | Old behavior to retire | Modern bounded context / slice | Missing or partial current path | Proposed improved abstraction |
|---|---|---|---|---|
source-refs/sanmopia-admin/application/controllers/Reservation.php, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js | Broad reservation detail submit mutates profile, address, dates, caregivers, status, and memo, then tries to log after the fact. | reservation_operations / reservation_collaboration | Partial: backend-repo/src/.../features/reservation_collaboration/ has workspace, journal, conflict, and Supabase RPC support; remaining gap is full actor capability coverage and every mutation group as a typed command. | ReservationCollaborationCommand with expectedRevision, field group, actor capability snapshot, conflict diff, resolution decision, realtime invalidation, and return-state token. |
source-refs/sanmopia_web/application/controllers/api/Payment.php, source-refs/sanmopia_web/application/models/Payment_model.php | Payment-purpose, payer, coupon, provider, and refund side effects are inferred from request flags and source payment maps. | pricing_settlement / customer_payment_instruction, payment_refund | Partial: ReservationPaymentWorkflow, payment_refund, killbill_payment_event, and killbill_admin_operation exist; public completion/repair, virtual-account closeout, and receipt/refund artifact paths still need end-to-end proof. | Kill Bill PaymentInstruction and RefundLifecycle ports behind product-plan policy, with ledger-backed side effects and no PortOne-named domain/API abstraction. |
source-refs/sanmopia-admin/application/controllers/Calculate.php, source-refs/sanmopia-admin/application/controllers/DataRoom.php, Spreadsheet_model.php export readers | Settlement rows, export files, branch acknowledgements, and external-counterparty status are coupled to mutable calculation/export paths. | pricing_settlement / settlement_statement, settlement_data_room, branch_settlement_reconciliation_export | Partial: statement commands, data-room artifacts, reconciliation export workflow, and settlement status projections exist; remaining gap is complete statement-line coverage and repair history surfaced through operations contracts. | SettlementStatementWorkflow with statement kind, line context, approval/acknowledgement state machine, export dataset revision, signed artifact grant, repair command, and transition audit. |
source-refs/sanmopia-manager/application/helpers/salary_helper.php, source-refs/sanmopia-admin/application/models/Matching_model.php | Matching decisions and payroll amounts are recomputed from current read-time rows. | caregiver_assignment / assignment_decision_evidence, pricing_settlement / caregiver_compensation | Partial: candidate/evidence and payout foundations exist, but API exposure, worker persistence, and payroll statement readiness remain incomplete. | CaregiverAssignmentDecisionEvidence feeding CaregiverPayoutInstruction with grade snapshot, role slot, attendance facts, tax election, conflict evidence, and payout audit. |
source-refs/sanmopia_web/static/js/step3.js, reservation_calendar.js, holiday management sources | Weekly service, extension, weekend, holiday, substitute-holiday, and branch-closure effects are calculated in UI/PHP branches. | reservation_operations / service_calendar, service_period, holiday_policy_execution | Partial: service-calendar policy and holiday audit foundations exist; missing gate is all quote, matching, report, refund, and settlement invalidation paths using the same frozen service-period plan. | ServicePeriodPlan and HolidayPolicyExecutionAndImpactInvalidation as backend projections consumed by portals only as read models. |
source-refs/sanmopia_web/application/views/mypage/reservation_document.php, document spreadsheet/static templates | Numeric document ids, raw file paths, and direct download tokens leak document/template logic to views. | document_reporting / printable_document, printable_template_version_manifest | Partial: document catalog, Storage-backed template loading, HTML/PDF render artifacts, and signed grants exist; missing gate is complete source template manifest and bundle/ZIP artifact policy. | PrintableTemplateVersionManifest plus DocumentRenderArtifactGrant with service eligibility, template version, render request id, signed URL, revocation, and access audit. |
source-refs/sanmopia_web/application/controllers/api/Service.php, branch/address sources | Address strings, branch ids, impossible-region flags, and consultation-only fallbacks decide serviceability at UI/API edges. | branch_operations / service_area_policy | Partial: branch service-area policy APIs and Supabase persistence exist; remaining gap is every booking, quote, support, and branch handoff path consuming a booking-bound decision snapshot. | ServiceAreaDecisionSnapshot with normalized address levels, branch scope, consultation-only reason, serviceability evidence, policy version, and SpiceDB-checked branch authority. |
| Sponsor, delegated payer, emergency contact, refund recipient, and document-visibility source branches | Family authority is inferred from account/profile/payment fields at each screen or controller branch. | member_management / reservation_party_authority, pricing_settlement / refund_side_effect_ordering | Partial: family account authority and payment communication routing are modeled; missing gate is one projection reused by booking, payment, refund, receipt, and document-download flows. | ReservationPartyAuthoritySnapshot that separates mother, sponsor, delegated payer, emergency contact, contact-only viewer, refund recipient, and document viewer permissions. |
source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php, office/branch operator sources | Screen-level status rules decide what HQ and branch actors can see or mutate. | operator_access / actor_capability_projection, branch_operations / office_profile | Partial: Supabase Auth, SpiceDB relationships, OPA gates, branch service-area APIs, and identity smoke flows exist; missing gate is full BranchOwner and HeadOfficeManager command visibility through one stable projection. | ActorStageCapabilityProjection keyed by Supabase Auth actor and SpiceDB relationship facts, returning allowed commands, disabled reasons, field visibility, branch scope, and audit context. |
| Cron/download/push/export source helpers and repair scripts | Background work runs as route helpers or scripts with weak retry, visibility, and correlation. | platform / queue_workload, platform / observability_backpressure | Partial: Supabase queue contracts, queue worker, Restate workflow status, and OTel collector wiring exist; missing gate is feature-by-feature workload declarations and load tests for queue oldest-age, DLQ, and workflow-blocked alerts. | QueueWorkloadContract with idempotency key, trace context, visibility timeout, retry policy, dead-letter repair command, worker concurrency limit, and OTel metric labels. |
Architecture completion gates:
- Folder proof recorded for every
PartialorMigratedfeature: domain, application, adapters, contracts, and frontend paths match the bounded context and feature names. - No source-era flat feature folders remain, or each flat folder has a named shim owner, migration target, and cleanup condition.
- Flat adapter drift checked:
adapters/reservation,adapters/reservation_booking, andadapters/notificationare moved or documented as active anti-corruption/platform exceptions. - Adapter folder shape mirrors bounded-context and feature names, the same boundary rule enforced by Tach for domain and application slices.
-
application/shared_kernelanddomain/shared_kernelusage is reviewed as shared vocabulary/helper only, not a hidden feature bucket. - C4 Level 3/4 links are updated when folder ownership changes or a feature crosses bounded-context boundaries.
- Ubiquitous-language proof is recorded: folder, module, function, command, query, read-model, and field names use modern terms; source table/status/screen names stay only in adapters or source evidence.
- Architecture tests/manual checks cover adapter folder shape, not only domain/application shape.
- Context inventory is synchronized across bounded-context docs, backend
domain directories, and architecture tests before marking
Migrated. - Large API/facade modules have a CQRS split plan before more endpoints are
added. Current hotspots:
interfaces/reservation_payment_api.py,interfaces/reservation_payment_http.py, andapplication/pricing_settlement/features/settlement_data_room_workspace/. - Domain read models, presenter payloads, provider payloads, return-state tokens, UUID/time generation, and retry/dispatch handlers are either moved to application/adapters or explicitly documented as temporary migration debt with owner and cleanup trigger.
- High-conflict ubiquitous terms are resolved before new persistence columns
are added. Remaining known hotspots: settlement data-room collection,
branch-managed service area, and caregiver assignment role. Daily care report
review naming is split by purpose:
DailyCareReportReviewOutcomefor the reviewed caregiver report outcome andCustomerDailyReportReviewfor the customer-authored service-day review workflow. Caregiver performance scorecard naming is split by purpose:CaregiverPerformanceScorecardfor capped score rows,CaregiverPerformanceSeasonScorecardfor published season snapshots, andCareDeliveryPerformanceScorecardfor care-delivery earned points feeding grade recalculation.
Actor Feature Checklist
Section titled “Actor Feature Checklist”This actor view uses the long-term role names from the C4 Actor Capability Layer. Entries here are backend obligations unless the note explicitly says otherwise. Detailed source evidence remains in the sections below.
HeadOfficeManager
Section titled “HeadOfficeManager”-
ActorStageCapabilityProjectionfor HeadOfficeManager. Status:Partial. Required backend proof: Supabase Auth role facts, SpiceDB relationship facts, OPA policy decisions, disabled reasons, field visibility, command target, actor id, branch scope, and audit context returned through one stable read model before operations portal actions render. -
HeadOfficeOperationssettlement command surface. Status:Partial. Required backend proof: typed commands for request deposit, approve head office settlement, request arrears, close repair, and replay-safe retries with idempotency key, expected revision, actor capability snapshot, statement revision, and append-only transition audit. - Branch onboarding and office governance commands. Status:
Partial. P01 domain and provider-neutral application command/query are GREEN through backend8ac9ed9ca937e1521f984aa7de66bd7c3e64855b. The HQ authority adapter is GREEN atc4a19418109dd34ce1ba6364c8d1b4040bef9bb7with server-owned profile/membership, explicit HQ root, and SpiceDBadminister_headquartersbinding. The strict actor/HQ/command-scoped current-result adapter is GREEN at78781cff20216ebd13a0918be1319e72143b94dc; DB01-13 persistence plus the concrete four-RPC durable-store adapter are GREEN at54974c2ba4d60db26f71b1313ee3070ff45deb98. Provider effects, runtime composition, actor UI, isolated HQ execution, and full provider cleanup remain unproved. Required backend proof: HeadOfficeManager-created branch profile, operator credential lifecycle, duplicate login-id decision, active/deleted office state, membership-fee policy, bank-account snapshots, brand asset lifecycle, and login audit events exposed through command/query APIs. - Data room, document export, and repair operations. Status:
Partial. Required backend proof: configurable export templates, immutable artifacts, signed download handoffs, retry/rebuild state, repair request state, access audit, Supabase Storage/RLS binding, and no raw filesystem or query-string download path. - Policy, price, benefit, content, and analytics catalog administration.
Status:
Partial. Required backend proof: versioned catalog command APIs, authored-definition read models, activation windows, approval/audit workflow, report export projections, and runtime verification that portals consume server projections.
BranchOwner
Section titled “BranchOwner”-
ActorStageCapabilityProjectionfor BranchOwner. Status:Partial. Required backend proof: branch membership relationship, branch scope, allowed reservation/settlement/care-team commands, disabled reasons, retry/block state, and field visibility returned without portal-side status inference. - Reservation collaboration and conflict resolution. Status:
Partial. Required backend proof: branch-scoped workspace open, journal, expected revision, stale-save conflict diff, field winner command, realtime projection invalidation, presence/session recovery, and audit timeline persistence. 2026-07-06 backend delta:ResolveReservationConflictHandler, Supabase conflict-resolution decision persistence, API authorization, andPOST /reservation-collaboration-conflict-resolutions/{reservationId}now record actor, expected current revision, source audit ids, chosen winner per field, submitted/current/resolved values, and idempotency key. Remaining proof is portal wiring, realtime invalidation UX, and full audit timeline display. - CareManager assignment and availability decisioning. Status:
Partial. Required backend proof: candidate snapshot, conflict read projection, unavailable-period persistence, optimizer input persistence, replacement continuity, assistant slot invalidation, final decision audit, and generated API/client exposure. - Branch profile, service area, bank account, content, and office assets.
Status:
Partial. Required backend proof: branch profile command/query APIs, service-area policy publish/decision APIs, service-area policy persistence, settlement-account snapshots, stamp/profile asset lifecycle, office-content scope rules, Supabase Storage/RLS policies, and HeadOfficeManager oversight gates. 2026-07-04 update: backend now exposes Supabase Auth + SpiceDB protectedPOST /branch-service-area-policy-revisionsandPOST /branch-service-area-policy-decisions, and contract exports matching OpenAPI schemas plus TS helpers so branch coverage is not decided by UIAREA_ACCEPT_TYPE_ID_PKnumbers. - Branch settlement acknowledgement and operational dashboard. Status:
Partial. Required backend proof: branch deposit acknowledgement, line acknowledgement, arrears payment confirmation, status-count dashboard, signed artifact handoff, branch visibility filtering, retry state, failed export state, and repair history projection.
Mother/FamilySponsor
Section titled “Mother/FamilySponsor”-
ActorStageCapabilityProjectionfor Mother/FamilySponsor. Status:Partial. Required backend proof: family relationship facts, reservation lifecycle state, allowed next actions, disabled reasons, blocked-by-existing-reservation facts, document/payment readiness, visible charge summary, and field filtering through one customer-safe read model. - Reservation intake, care-plan, and charge freeze. Status:
Partial. Required backend proof: booking operational context persistence, stay-plan catalog persistence, service due-date policy, address-scoped benefit decision, service-calendar invalidation, immutable charge snapshot, authorization, and command/query API wiring. - Payment product plan, pre-registration, receipt, and adjustment payment.
Status:
Partial. Required backend proof: catalog-driven payment product families, allowed methods, provider route, virtual-account expiry, refund/conversion policy, settlement participation, Supabase versioned catalog rows, Novu/Strapi communication workflow catalog alignment, signed receipt handoff, adjustment paid verification, and customer-safe payment summary APIs. - Document bundle, grant, delivery attempt, and access history. Status:
Partial. Required backend proof: persisted document catalog/templates, bundle readiness, signed ZIP/artifact grants, resend/revoke controls, delivery retry state, recipient-visible access history, and customer-safe public handoff references. - Service-day review, final rating, assistant rating, and reward grant.
Status:
Partial. Required backend proof: persistence adapters, route binding, reward-ledger storage, readiness/action decisions, public/private review scope, and customer projection that does not depend on portal-only rating logic. - Partner benefit, coupon/gift shop, promotion, and campaign fulfillment.
Status:
Partial. Required backend proof: entitlement policies, purchase/payment linkage, recipient snapshots, resend/cancel state, provider delivery attempts, result artifacts, campaign audience policy, suppression/retry/dead-letter state, and repairable fulfillment audit.
CareManager
Section titled “CareManager”-
ActorStageCapabilityProjectionfor CareManager. Status:Partial. Required backend proof: assignment relationship facts, active service window, 90-day visibility policy, report/attendance obligations, payout/readiness state, blocked reasons, and field visibility returned by backend read models. - Self-service profile, credential evidence, media, account security, and
office requests. Status:
Pending. Required backend proof: credential evidence lifecycle, unavailable-period command API, profile/signature media storage, password/account hardening, branch-office request thread, bank-account handoff to payout, and RLS policies. - Matching preference profile and availability. Status:
Partial. Required backend proof: persisted matching profile, pet/service/personality answers, versioned preference mutations, compatibility-signal integration, availability conflict projection, and assignment optimizer consumption. - Schedule, attendance, service records, and daily care reports. Status:
Partial. Required backend proof: assignment-scoped schedule APIs, attendance idempotency by contract assignment key, service-record persistence/API, daily report submission persistence/API, notification outbox execution, and printable snapshot handoff. - Payout statement, tax election, bank account, and receipt acknowledgement.
Status:
Partial. Required backend proof: manager-facing payout statement API, revisioned receipt state event/projection persistence, bank-account edit proof, tax formula explainability, authorization gates, and full main/assistant operational screen support. Persistence proof now exists throughsanmopia_caregiver_payout_receipt_state_eventsandsanmopia_caregiver_payout_receipt_states; bank-account edit proof now persists asCaregiverPayoutDestinationChangeAuditwith full previous and adjusted destination snapshots, changed-field vocabulary, idempotency key, actor, target revision, participant RLS, realtime publication, FastAPI route, OpenAPI/TS contracts, and Supabase row type. Portal and admin/manager shared projection wiring remain open. - Education, notices, office request flow, news, referral, and events.
Status:
Partial. Required backend proof: caregiver content inbox, learning material state, event participation workflow, referral lead tracking, branch-scoped audience policy, notification state, request status, and repairable delivery audit.
Source Coverage
Section titled “Source Coverage”- Admin/backoffice controllers and models inventoried:
source-refs/sanmopia-admin/application/controllers/*,source-refs/sanmopia-admin/application/controllers/ajax/*,source-refs/sanmopia-admin/application/controllers/cli/*,source-refs/sanmopia-admin/application/models/*. - Mother/customer web controllers and pages inventoried:
source-refs/sanmopia_web/application/controllers/*,source-refs/sanmopia_web/application/controllers/api/*,source-refs/sanmopia_web/application/controllers/cli/*,source-refs/sanmopia-user-old/src/pages/*,source-refs/sanmopia-user/src/pages/*. - Caregiver/manager web controllers and models inventoried:
source-refs/sanmopia-manager/application/controllers/*,source-refs/sanmopia-manager/application/controllers/cli/*,source-refs/sanmopia-manager/application/models/*. - Native shell sources inventoried:
source-refs/sanmopia_android/app/src/main/*,source-refs/sanmopia_ios/ios_sanmopia_app/*,source-refs/sanmopia_manager_android/app/src/main/*. - Runtime/data support sources inventoried:
source-refs/sanmopia-docker/*,source-refs/sanmopia-price-table/*. - Kanboard renewal operations evidence inventoried through live JSON-RPC:
project
산모피아id85, Kanboardv1.2.35, cards776, comments1507, subtasks11, task files233, task links30. Summary is tracked in Kanboard Renewal Feature Improvements.
Runtime Test Data Hygiene
Section titled “Runtime Test Data Hygiene”- Stage smoke fixtures register cleanup ownership in Supabase.
sanmopia_test_data_batchesstores batch key, owner tag, source script, environment, expiry, status, and cleanup summary.sanmopia_test_data_referencesstores ordered cleanup references for public rows and Supabase Auth users.pnpm test-data:reapis a dry-run gate andpnpm test-data:reap:applyperforms explicit confirmed deletion.pnpm doctorfails when a reachable stage contains expired active test-data batches, so repeated reservation, payment, and settlement smoke runs do not quietly create long-lived fixture debt.
2026-07-03 Source Survey Delta
Section titled “2026-07-03 Source Survey Delta”Focused scan: legacy PHP and source-reference UX paths for booking/reservation, payment, settlement, caregiver matching/payroll, branch/HQ approvals, settlement data room, document/report generation, and branch/admin stale-data, history, and audit gaps. Status reflects read-only comparison against current contract/backend/frontend repo shape and this checklist; no modern code was changed.
| Legacy source path/evidence | Modern bounded context / feature name | Implementation status | Migration priority | Notes |
|---|---|---|---|---|
source-refs/sanmopia-admin/application/controllers/Reservation.php:650-880, source-refs/sanmopia-admin/application/controllers/Reservation.php:930-1014 | reservation_operations / ReservationCollaborationCommand, ReservationMutationKind | Backend-backed | P0 | Source one-submit save mutates birth data, service term, payment dates, caregiver roster, address, memo, and status, then writes a best-effort diff log after persistence. Collaboration backend now binds service term, payment date facts, service-address replacement, memo, branch handoff, service dates, and extra service days behind expectedRevision; HTTP stale-save tests prove these legacy save field groups return 409 conflict diffs instead of last-write-win. Final caregiver assignment is no longer accepted through collaboration broad-save: backend ef0a510, backend backstop 068632e, and contract 936ed47 reject mutation kind caregiver_assignment and caregiver_assignment.* change-set fields at domain, HTTP, adapter, SQL RPC, TypeScript, and JSON Schema layers so roster writes must use care-team assignment commands. |
source-refs/sanmopia-admin/application/models/Reservation_model.php:2165-2303, source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:180-208 | caregiver_assignment / CaregiverAssignmentDecision, CaregiverAssignmentTerm, AssignmentDecisionAudit | Partial | P0 | Main caregiver change sets other-area service, writes old/new manager log, and mutates reservation. Assistant caregiver replacement uses slot SORT and can delete linked sub-payout/salary rows. Modern roster persistence plus AssignCaregiverFromCandidateSnapshotCommand, ClearAssistantCaregiverSlotCommand, CareTeamAssignmentHistoryReadModel, CareTeamCurrentRosterReadModel, GET /care-team-assignment-histories/{reservationBookingId}, GET /care-team-current-rosters/{reservationBookingId}, POST /care-team-assignment-decisions/assign-from-candidate-snapshot, and POST /care-team-assignment-decisions/clear-assistant-slot now persist, read history, project active primary/assistant roster slots, and record branch/HQ assignment writes from frozen candidate or cleared assignment evidence with expected reservation/roster revisions, actor/reason/idempotency, previous assignment key, invalidation targets, Supabase RLS/service-role split, SpiceDB assign_caregiver permission, public TS/OpenAPI contract coverage, and collaboration broad-save rejection for caregiver_assignment writes through domain/adapter/SQL/contract guards. Backend 39a8eba adds standardized downstream invalidation dispatch: payout projection refresh is queued through the existing admin payout PGMQ requester, and document projection invalidation is recorded through a typed document-reporting receipt command. Backend 6758b30 binds protected FastAPI command routes and persists document-projection invalidation receipts in sanmopia_care_team_document_projection_invalidations; contract 495d5cc exposes command request/response schemas and helpers. Backend 5dd338b queues typed service-use contract document render requests to sanmopia_document_rendering, and backend 3cdc86a consumes those requests through a durable render worker that retries until the frozen render source is available and then stores the printable artifact. 2026-07-09 source guard follow-up: CareTeamRosterAssignmentDecision rejects legacy DOM authority fields data-index, fmanager-name, and input-senior-manager-name, so browser-selected roster ids cannot bypass backend candidate snapshots and assignment commands. Remaining migration: live E2E branch/HQ assignment smoke, render-source producer binding from roster/projection revisions, and storage/access grant issuance. |
source-refs/sanmopia-admin/application/models/Manager_model.php:2038-2088, source-refs/sanmopia-admin/application/models/Manager_model.php:2146-2180 | caregiver_assignment / CaregiverAvailabilityWindow, CaregiverAssignmentConflict | Partial | P0 | Source denied days are mutable rows and schedule overlap is a boolean lookup. Backend conflict policy now checks unavailable windows, overlapping assignments, and replacement continuity before final assignment. Remaining proof: durable conflict-read exposure, optimizer inputs, and portal conflict UX. |
source-refs/sanmopia-manager/application/helpers/salary_helper.php:8-227, source-refs/sanmopia-manager/application/views/pay_info_detail.php:165-263, source-refs/sanmopia-manager/application/views/schedule/schedule_info.php:136-200 | pricing_settlement / CaregiverCompensationQuote, CaregiverPayoutInstruction, CaregiverTaxElection, CaregiverVoucherAddOnTaxCutoverPolicy, CaregiverAdditionalServiceDayBasis, care_delivery / CaregiverServiceBalanceShareProjection, CaregiverPayoutAdjustmentAudit, CaregiverPayoutDestinationChangeAudit | Partial | P0 | Backend now issues payout instructions and models manager-facing payout statements plus receipt/exception/repair state commands from frozen compensation facts. Supabase persistence stores revisioned receipt-state events/current projections, append-only payout adjustment audits, and append-only payout destination change audits with idempotency keys, expected revision, full previous/adjusted payable amount or destination snapshot, changed-field vocabulary, participant RLS, and realtime publication. Public HTTP/API now records branch deposit acknowledgements, caregiver receipt acknowledgement/exception/repair commands, caregiver payout adjustment audits, and caregiver payout destination change audits through Supabase actor derivation plus SpiceDB reservation-booking permissions; contracts expose the matching paths, request/response schemas, and Supabase row types. Assistant branch-deposit acknowledgement now matches backend payout-slot identity with caregiver role and handoff order, covering source SORT > 0 assistant row collision risk. 2026-07-05 follow-up: CaregiverVoucherAddOnTaxCutoverPolicy freezes voucher add-on taxable-base removal, tax category after-tax behavior, configurable business-income basis points, and legacy cutover date; CaregiverAdditionalServiceDayBasis freezes source service-day multipliers, service-day extension options, repeating option charge basis, custom service balance override, and profile-based voucher add-on deduction; CaregiverServiceBalanceShareProjection freezes care-team service-balance share, confirmation state, command availability, disabled reason, and payout statement reference for schedule items. 2026-07-07 follow-up: admin payout statement projection persistence now has Supabase projection/row tables, participant RLS, realtime publication, deterministic latest-revision read, row upsert store, and JSONB display/action roundtrip for multiple caregiver slots; FastAPI/TS projection read routes are bound; backend commit e973097 queues admin payout projection refresh requests from branch deposit, receipt state, payout adjustment, and destination-change mutations through Supabase PGMQ queue sanmopia_admin_payout_projection_refresh. Backend commit 6e3bdfc now executes projection rebuild worker from Supabase PGMQ by reloading frozen payout facts, computing the next projection revision, and saving the rebuilt admin projection. Backend commit 39a8eba adds care-team assignment change as another projection refresh trigger, so primary/assistant assignment and assistant clear no longer leave admin payout projections stale. Remaining work: manager/branch/HQ screens without PHP/JS salary recalculation and E2E worker proof. |
source-refs/sanmopia-admin/application/controllers/Calculate.php:150-312, source-refs/sanmopia-admin/application/controllers/Calculate.php:155-190, source-refs/sanmopia-admin/static/js/calculate_detail.js:20-323, source-refs/sanmopia-admin/application/models/Payment_model.php:534-597, source-refs/sanmopia-admin/application/models/Payment_model.php:2861-2878, source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3051, source-refs/sanmopia-admin/application/models/Payment_model.php:4312-4400 | pricing_settlement / SettlementStatement, SettlementTransitionAudit, SettlementLineAcknowledgement, SettlementStatementManualRow | Partial | P0 | Command-ledger/idempotency foundation now covers HQ deposit request, branch deposit confirmation, HQ approval, arrears request, per-line acknowledgement, and HQ manual etc rows. Source UI posts one FormData blob containing selected normal/voucher rows, gift/cancelled-coupon rows, delivery flag, membership flag, manual etc names/counts/prices, actor type, board id, message, and memo, then sends it to one controller action for both HQ request and branch acknowledgement. BranchSettlementDeliveryFee now owns delivery-fee rate selection and line-item projection, but command/API binding must still route delivery acknowledgement through typed commands. Remaining migration must bind every source board mutation path to typed commands with row-level expected revision: membership due, delivery acknowledgement, cancelled gift coupon commission, selected detail rows, coupon rows, manual etc rows, message-to-branch, HQ-private memo, manual row audit, and rejection when selected row set/revision changed after page load. |
source-refs/sanmopia-admin/application/controllers/Calculate.php:337-430, source-refs/sanmopia-admin/application/controllers/Calculate.php:433-457, source-refs/sanmopia-admin/application/models/Payment_model.php:2657-2814, source-refs/sanmopia-admin/application/models/Payment_model.php:2816-2965, source-refs/sanmopia-admin/application/models/Payment_model.php:2916-2972, source-refs/sanmopia-admin/application/controllers/DataRoom.php:268-309 | pricing_settlement / InterOfficeSettlement, ServiceOfficeTransfer, CustomerHandoffOffice, ReservationExternalCounterpartySettlementStatus, SettlementStatementKind, InterOfficeSettlementAcknowledgement | Partial | P0 | Backend aggregate, lookup key, and history reader exist. Inter-office settlement now projects branch-facing inter_office_branch_share payable lines and inter_office_service_fee receivable lines from frozen settlement lines, with service/customer branch ids and charged-branch fee payloads required before branch statement projection. This replaces source RESULT_PRICE, FEE, ALL_PRICE, and PRICE * COUNT view/controller arithmetic for other-area branch settlement evidence. Branch acknowledgement now accepts typed InterOfficeSettlementAcknowledgement through application/HTTP contracts, validates service-delivery versus customer-relationship side, actor, expected revision, dataset revision, and projected line ids, then stores the evidence in transition-audit metadata instead of trusting source fbranch-type. Settlement data-room workspace backend now uses canonical collection summaries and detail lookup-key selectors for external-counterparty, branch-to-HQ, HQ, and inter-office settlement, with service office, customer handoff office, settlement owner office, branch/HQ visibility, and expected revision carried separately from source DANBEE_STATUS_FL, OTHER_OFFICE_STATUS_FL, and BRANCH_TYPE ids. Do not collapse branch settlement, headquarters approval, external-counterparty export readiness, and inter-office service/customer-relationship branch roles into one status flag or one collection. Remaining proof: live external-counterparty/operator board persistence, UI actions, and source-specific readiness projection binding. |
source-refs/sanmopia-admin/application/controllers/DataRoom.php:30-94, source-refs/sanmopia-admin/application/controllers/DataRoom.php:119-212, source-refs/sanmopia-admin/application/controllers/DataRoom.php:218-250, source-refs/sanmopia-admin/application/controllers/DataRoom.php:268-386, source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:17-240, source-refs/sanmopia-admin/application/controllers/Calculate.php:568-577, source-refs/sanmopia-admin/application/models/Data_room_model.php:25-203, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:15-58, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3911, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-4198, source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:6-47, source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:225-262, source-refs/sanmopia-admin/static/js/calculate_detail.js:297-337 | pricing_settlement / SettlementWorkspace, document_reporting / BranchResourcePost, SettlementDataRoomCollection, SettlementArtifactRequest, SettlementArtifactVersion, SettlementArtifactGrant, DownloadHandoffAudit, SettlementRepairRequest, OperatorReturnStateToken, BulkExportTemplatePolicy | Partial | P0 | Data-room backend/contracts now model request, build, ready artifact, repair, download handoff, deterministic caller-supplied ids, required grant idempotency keys with replay protection, timezone-aware domain datetimes, Pydantic application command/query DTOs, collection summary payloads, typed detail lookup-key payloads, and collection repair facts for mismatch/missing-board-row audits. Collection summaries now require dataset_revision and projection_revision, so status/count values are server/domain read-model values instead of source UI arithmetic over raw rows. Branch resource post backend now replaces other-post null-branch routing with explicit headquarters, branch, and all-branches sender/recipient scopes, revisioned attachment versions, retained/revoked post state, signed download grant commands, and audit entries for publish, supersede, revoke, retain, restore, and grant issue. New workspace tests prove no dataType switch, no source numeric status-id selection, stale expected-revision rejection, branch/HQ visibility checks, blank/missing grant idempotency rejection, naive datetime rejection, missing projection revision rejection, no raw-row summary payload, idempotency-key mismatch rejection for changed repair fact or grant intent, branch actor cannot publish as headquarters, revoked attachments cannot receive download grants, and stale workspace writes produce field-level SettlementWorkspaceRevisionConflict plus explicit operator keep_current/apply_submitted/merge_explicit decisions instead of overwrite. Public TS/JSON contracts now expose the same settlement workspace conflict response, resolution request, and resolution decision payloads. Backend workspace runtime now exposes GET /settlement-data-room-workspaces/{workspaceCode}, artifact request, repair request, grant handoff, return-state token, and conflict-resolution routes backed by SettlementDataRoomWorkspaceApi, SupabaseSettlementDataRoomWorkspaceRepository, SupabaseSettlementDataRoomWorkspaceTemplatePolicyReader, SupabaseSettlementWorkspaceConflictResolutionDecisionStore, sanmopia_settlement_data_room_workspaces, sanmopia_settlement_data_room_template_policies, and sanmopia_settlement_workspace_conflict_resolution_decisions. The runtime persists JSONB aggregate snapshots plus queryable collection/scope/revision columns, seeds a versioned BulkExportTemplatePolicy, resolves actor profile ids from backend-owned sanmopia_member_profiles, derives branch/HQ/workflow capabilities through SpiceDB, and stores idempotent explicit field-winner decisions so post-close workspace changes cannot rewrite an operator-visible stale-conflict result. 2026-07-06 follow-up: backend, Supabase migration, and TS contract now canonicalize data-room collections as external_counterparty_settlement, branch_to_headquarters_settlement, headquarters_settlement, and inter_office_settlement; source-era head_office_settlement, danbee_settlement, and inter_branch_settlement stay adapter/source evidence only. 2026-07-08 RBAC follow-up: workspace actor identity ignores Supabase app_metadata.operator_profile_id; a resolver reads member profile identity before SpiceDB authorization creates the domain actor. Source branch data-room pages still load board summaries directly, reuse mutable list filters/referrer/hash state, stream generated spreadsheets from hardcoded templates, and download completed files by raw GET redirect or hidden POST iframe. Remaining proof: browser workspace integration, Restate artifact-build worker binding to immutable templates/storage, signed Storage URL materialization behind grant references, repair/rebuild retry UX, no client-calculated status/totals, and no hidden POST-download hacks. |
source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4284-4595, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:19-132, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:140-245 | document_reporting / ReservationDocumentTemplate, ReservationDocumentDelivery, DocumentAccessGrant, DocumentDeliveryAttempt | Partial | P0 | HTML/PDF artifact foundation exists, but full start/end document parity remains open: contract/receipt templates, static PDF notices, scheduled start/end email batches, manual resend/revoke controls, persisted ZIP bundles, signed-url issuing adapter, and recipient-visible access history. |
source-refs/sanmopia_web/application/views/about/terms.php:136, source-refs/sanmopia_web/application/views/about/terms.php:229, source-refs/sanmopia_web/application/models/Reservation_model.php:989, source-refs/sanmopia_web/application/models/Payment_model.php:383, source-refs/sanmopia-admin/application/models/Reservation_model.php:1822, source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31 | pricing_settlement / ReservationCancellationRefundPolicy, RefundQuote, PaymentRefundIntent, PaymentRefundGatewayCommand, SupabasePaymentRefundLedgerStore, PaymentAdjustmentCatalog, ReservationCancellationRefundExplanationSnapshot | Partial | P0 | Source refund terms encode 14-day full refund, 24-hour full refund, 10% total-fee deduction, post-start used-fee plus 10%, gift 20k/40k, and delivery 5k deductions, while cancellation code mostly loops paid provider rows and sends KCP full-cancel requests. Backend foundation now quotes reservation cancellation refund from immutable facts, separates gift/delivery deductions from branch settlement gift fees, uses versioned adjustment catalog lines, calculates customer shortfall, blocks client-provided refund amount authority by deriving paid amount from the refund ledger, emits idempotent provider-neutral PaymentRefundGatewayCommand facts through PaymentRefundIntent, persists append-only refund ledger entries in Supabase, reads the latest active PaymentAdjustmentCatalog from sanmopia_payment_adjustment_catalog_items, exposes protected POST /reservation-cancellation-refunds, wires the runtime API through KILLBILL_API_KEY, and stores refund_explanation_snapshot JSON so the post-payment mother-visible refund result does not drift after later policy/catalog changes. 2026-07-05 follow-up: domain no longer owns KillBill HTTP method/path/body payloads; Supabase adapter maps PaymentRefundGatewayCommand into billing_gateway_refund_command, while Kill Bill request shape remains inside the provider adapter boundary. Public OpenAPI/TS contracts now include cancellation refund request/response schemas, validators, and paymentChangeAdjustmentId linking. New code cannot reintroduce provider-SDK or PG-console oriented command naming. Remaining migration: persist zero-gateway-refund quote decisions, link reservation cancellation workflow, restore coupon/benefit entitlements, notify customer/branch, and handle provider partial-cancel capability/status events. |
source-refs/sanmopia-admin/application/views/reservation_status/pre_reservation_detail.php:90-118, source-refs/sanmopia-admin/static/js/reservation_status/pre_reservation_detail.js:299-328, source-refs/sanmopia-admin/application/controllers/Reservation.php:1023-1088, source-refs/sanmopia-admin/application/models/Reservation_model.php:5559-5595, source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31-60, source-refs/sanmopia_web/application/models/Reservation_model.php:1012-1030 | pricing_settlement / PreReservationCancellationRefundCommand, reservation_operations / PreReservationDetailCommit, SourcePreReservationStatusMapping | Partial | P0 | Admin pre-reservation detail save posts one status/contact/address/service-date form, regenerates reservation dates, and triggers pre-reservation refund only when posted status is 9. The same source codebase still defines 18 사전예약취소, while the admin pre-reservation selector exposes 9, 15, 16, 17, and 19 only. The pre-reservation refund lookup hardcodes payment type 6 and paid status 1, extracts KCP context, and calls the gateway; Needs source confirmation whether any caller/library/trigger marks the payment row refunded, because the inspected path does not set status 2 while normal cancellation refund paths do. Backend foundation now removes source payment type/status ids from PreReservationRefundPolicy: source_reservation_payment_acl.py maps source payment type codes 1/2/3/6 and collection status codes 0/1 into ReservationPaymentPurpose and PreReservationPaymentCollectionState before creating PreReservationPaymentCapture; reservation payment summary projection reuses the same ACL instead of keeping a duplicate adapter dict. Remaining migration needs a dedicated pre-reservation cancel/refund command, explicit status mapping for 9 versus 18, append-only refund ledger update, and a separate detail commit command for address/service-date/date-regeneration fields. |
source-refs/sanmopia_web/application/models/Reservation_model.php:463-486, source-refs/sanmopia_web/application/models/Reservation_model.php:2515-2630, source-refs/sanmopia_web/application/models/Reservation_model.php:2710-2747, source-refs/sanmopia-admin/application/models/Manage_system_model.php:52-109, source-refs/sanmopia-admin/application/controllers/ajax/ManageSystem.php:16-32, source-refs/sanmopia-admin/application/controllers/Reservation.php:1749, source-refs/sanmopia-admin/application/models/Reservation_model.php:5376, source-refs/sanmopia_web/application/models/Report_model.php:324-339, source-refs/sanmopia_web/application/models/Report_model.php:451-466 | reservation_operations / ServicePeriodCalculationPolicy, ServiceCalendarCompatibilityDecision, ReservationServiceTermPlan, HolidayPolicyVersion, ServiceDayOccurrence, ServiceCalendarImpactPlan, SourceServiceCalendarExtraOptionDecision; pricing_settlement / ReservationServiceCalendarQuote, ServicePeriodChargeContext | Partial | P0 | Source edit and new-reservation flows disagree on legacy weekend-shift duration, newer weekday-count duration, Wanju extension math, selected Saturday/holiday quantities, and report holiday exclusion. HOLIDAY_TB plus free-text LIST_HOLIDAY_TYPE_TB can record a substitute holiday name, but not source, announcement date, substitute-of relationship, branch scope, supersession, or whether a date is skipped service time versus selected paid extra service. Modern service calendar policy now emits policy-versioned ServiceDayOccurrence snapshots, ServiceCalendarCompatibilityDecision facts, and ServiceCalendarImpactPlan consumer facts for daily report selection, charge repricing, caregiver assignment review, refund requote, and settlement recalculation, so historical source end-date drift and downstream operational impact are explicit instead of hidden in UI/PHP recalculation. Supabase now persists plan compatibility fields, per-date occurrence rows, service-calendar impact fact rows, policy profile rows, and source add-date eligibility decision rows. Backend now exposes SpiceDB-protected GET /reservation-service-calendar-impacts/{reservationBookingId} with impactKind and planCode filters, backed by the latest/selected Supabase plan rows so charge, assignment, report, refund, and settlement consumers can read frozen service-calendar impact facts instead of UI totals. Settlement financial lifecycle now reads the latest settlement-recalculation impact facts and rejects branch/HQ settlement preparation unless the command carries matching service-calendar plan id, policy fingerprint, and impact fact ids; reservation cancellation refund now does the same for refund_requote_required before quoting, through shared Pydantic application models and one Supabase impact-reference reader instead of duplicated UI/backend lookup code. Assignment optimizer now rejects optimization unless caregiver_assignment_review_required service-calendar facts are acknowledged by booking id through a Pydantic impact reference and shared Supabase impact-reference reader. Daily-care-report print-data build now rejects output unless daily_report_selection_required service-calendar facts are acknowledged by reservation id through the same shared Pydantic impact reference and Supabase impact-reference reader. 2026-07-04 follow-up: ReservationServiceCalendarQuotePolicy now converts selected Saturday/holiday charge facts into effective-dated, branch/program-specific charge lines, carries impact plan/fingerprint/fact ids, adds the total to ReservationPriceSummaryInput, and feeds ReservationPriceSummaryChargeFreezePolicy without importing reservation-operations domain types into pricing. SourceServiceCalendarExtraOptionDecision now isolates legacy source labels 토요일 추가, 휴일 추가, and legacy duration-extension tokens plus RESERVATION_ADD_DATE codes SAT/HOLI into a Python backend adapter, feeding expected counts and profile-driven duration extension days into domain ExtraServiceDaySelection without leaking region tokens or string comparisons into UI or domain rules. ExtraServiceDayReconciliationDecision now freezes expected-vs-selected Saturday/holiday count mismatch lines, reason codes, warning messages, and policy fingerprint into the service-calendar plan snapshot and Supabase RPC payload, so UI cannot recompute extra-day anomalies from raw counts. 2026-07-04 source-dig follow-up found additional gaps and backend now covers them as foundation: ExtraServiceDateEligibilityDecision validates raw RESERVATION_ADD_DATE writes against the frozen plan range, selected occurrence, policy fingerprint, and source reference; SaturdayHolidayCollisionPolicy rejects source SAT rows when the same date is a holiday and requires the HOLI bucket; SupabaseExtraServiceDateEligibilityDecisionStore persists those decisions in backend-only Supabase source-evidence rows; ServiceCalendarPolicyProfile and SourceServiceCalendarPolicyProfile move source duration-extension terms into profile data with profile key, adjustment key, and frozen duration extension days on reservation calendar plans; ReservationServiceOccurrenceObligationProjector and service_occurrence_evidence_key bind attendance/reporting to generated occurrences instead of raw date rows. 2026-07-05 follow-up: ServicePeriodChargeContext now preserves stable period_template_key, period_kind, service_calendar_policy_fingerprint, optional service_duration_profile_key, and source evidence_key inside ReservationServiceCalendarQuote, while rejecting display labels such as “2 Week Service” as keys and keeping pricing free of reservation-operations domain imports. Still-open gaps: bind profile management APIs/operator screens, require occurrence evidence in application commands, support every historical duration-mode profile from admin/web source evidence, and complete anomaly acknowledgement plus runtime API/operator UI wiring. Remaining migration: bind daily-report workflows, persist and expose service-calendar charge-rate catalogs, and keep week service, extension, weekend, holiday, sudden substitute holiday, branch-defined holiday rules, extra-date eligibility, bucket collisions, source compatibility profiles, and attendance/report obligations out of scattered UI/PHP recalculation. |
source-refs/sanmopia_web/application/models/Reservation_model.php:2039-2145, source-refs/sanmopia_web/application/controllers/api/Service.php:323-325, source-refs/sanmopia_web/application/models/Reservation_model.php:2473-2501, source-refs/sanmopia-admin/application/config/constants.php:128-129 | reservation_operations / ReservationExtensionPlan, ExtensionEligibilityDecision, ContinuationVoucherEligibilityDecision, ServicePeriodPlan.extension_of; pricing_settlement / ReservationExtensionQuote | Backend foundation + contract | P0 | Source extension copies a reservation into a linked new reservation and carries mutable address, delivery, matching, memo, and payment facts forward. Backend pricing foundation now has ReservationExtensionQuotePolicy, which preserves original/new reservation ids, extension sequence, previous service end, extension start, and a linked ReservationServiceCalendarQuote while deriving a fresh extension ReservationPriceSummaryInput instead of blindly copying mutable payment totals. 2026-07-05 follow-up: ContinuationVoucherEligibilityDecision now evaluates requested voucher service against frozen ancestor-chain facts, blocks any chain with a prior social-service voucher, persists query columns on the continuation link, and exposes TS/schema contracts so UI cannot infer voucher conversion from current-row state. 2026-07-07 follow-up: commit 7d5db21 adds ContinuationDraftConflictFact plus PlanContinuationDraftCreationPayload, so source delete-and-relink behavior is replaced by typed draft-state eligibility, idempotent planning, superseded-draft evidence, copied-fact audit references, and strict contract rejection of source table/status fields. Latest backend follow-up requires branch_service_area_decision_evidence_id when continuation copied facts include address or service-area evidence, preventing blind continuation address cloning. Modern migration must still persist immutable extension intent and copied-fact audit rows, bind extension branch coverage snapshot, charge/assignment invalidation, full command/API runtime binding, and operator/customer UX without blind row copy. |
source-refs/sanmopia_web/static/js/mypage/reservation.js:336-421, source-refs/sanmopia_web/static/js/mypage/reservation.js:515-593, source-refs/sanmopia_web/application/models/Reservation_model.php:1091-1111, source-refs/sanmopia_web/application/controllers/api/Reservation.php:86-239, source-refs/sanmopia_web/application/models/Report_model.php:267-391, source-refs/sanmopia_web/application/models/Report_model.php:394-518, source-refs/sanmopia-admin/application/models/Reservation_model.php:1768-1792, source-refs/sanmopia-admin/application/models/Reservation_model.php:1888-1892, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4040-4045, source-refs/sanmopia-admin/application/models/Statistics_model.php:875-893, source-refs/sanmopia-admin/application/models/Payment_model.php:228-231, source-refs/sanmopia-admin/application/config/constants.php:130-131 | reservation_operations / ServiceSuspension, SuspensionRequest, EffectiveStop, ResumeBoundary, ServiceSuspensionImpactPlan | Partial | P0 | Source stop behavior is customer stop request status 12, admin-confirmed stopped status 13, request rows, branch Alimtalk, and report logic that parses RESERVATION_CHANGE_LOG JSON for stop start/end. No first-class source pause/resume state was found; resume is inferred when later change-log BEFORE_DATA contains status 13. Backend foundation now models durable suspension request, approval, resume boundary, affected service dates, and impact commands for service calendar, caregiver assignment, pricing/settlement, refund quote, daily care report, customer communication, and stopped-voucher settlement eligibility using source DATEDIFF(SERVICE_END_DT, SERVICE_START_DT) >= 3 elapsed-span semantics. DailyCareReportServiceSuspensionWindowPayload now lets backend validation allow the stop day as the final report date while blocking later suspended service dates, so report eligibility no longer depends on RESERVATION_CHANGE_LOG string parsing. Remaining migration: persist interval rows, bind stop confirmation and resume as revision-checked reservation collaboration mutation kinds, make stop day the final report/export day, exclude suspended days from report selection, reset product coupons once on stop transition, wire settlement/data-room readers to ReservationSettlementEligibilityRule, and log stale stop/resume conflicts through workspace conflict events. |
source-refs/sanmopia-admin/application/models/Reservation_model.php:1873-1880, source-refs/sanmopia-admin/application/models/Reservation_model.php:1888-1892, source-refs/sanmopia-admin/application/models/Coupon_model.php:63-87, source-refs/sanmopia-admin/application/models/Coupon_model.php:97-157, source-refs/sanmopia-admin/application/models/Coupon_model.php:218-323, source-refs/sanmopia-admin/application/models/Coupon_model.php:935-958, source-refs/sanmopia_web/application/models/Reservation_model.php:989-1066, source-refs/sanmopia_web/application/models/Coupon_model.php:530-553 | pricing_settlement / ReservationPromotionSideEffectPlan, PlanReservationPromotionSideEffectHandler, ProductCouponResetPolicy, ReservationCouponRestorePolicy, PromotionEntitlementOutbox; customer_engagement / BenefitFulfillmentCancellation; pricing_settlement / RefundSideEffectPlan | Partial | P0 | Refund amount snapshot now exists, but source also couples stop/cancellation to product-entitlement hard delete/reissue, used-reservation-entitlement restore, benefit cancellation, payment refund, point/shop grant reversal, and delivery/gift side effects. On status 13 stop transition or status 9 cancellation, admin reset deletes existing product coupon rows only for normal-service reservations and republishes from MANAGER_ATTENDANCE_TB: no product coupon for <=2 attended days, one-week PRODUCT1 20,000 coupon for 3-7, and two-week PRODUCT2 30,000 coupon for >=8, with immediate USER_COUPON_TB grant and +6 month expiry. Backend domain now replaces product hard-delete/reinsert with ProductCouponResetPolicy and replaces USER_COUPON_TB.USE_FL/USE_DT flag reset with actor-aware ReservationCouponRestorePolicy commands that reuse PromotionEntitlement.restore. Backend application now adds PlanReservationPromotionSideEffectHandler, which composes product reset and cancellation-only reservation coupon restore into a persistable ReservationPromotionSideEffectPlan and rejects service-stop coupon restore ids so status 13 cannot reopen used reservation coupons. Supabase now persists plan snapshots in sanmopia_reservation_promotion_side_effect_plans and command outbox rows in sanmopia_promotion_entitlement_outbox_entries, with generated database types updated from the stage CLI. Remaining migration: ReservationOperationFollowUpWorkflow binding for stop/cancel, outbox worker execution for entitlement cancellation/issue/restore, benefit/point/shop/delivery side effects, customer-visible ledger/read models, and repair commands instead of controller-coupled deletes or flag flips. |
source-refs/sanmopia-admin/application/controllers/Reservation.php:1531-1605, source-refs/sanmopia-admin/application/models/Reservation_model.php:823-852, source-refs/sanmopia-admin/application/models/Reservation_model.php:5458-5496, source-refs/sanmopia-admin/application/models/Reservation_model.php:5560-5595, source-refs/sanmopia_web/application/models/Reservation_model.php:1295-1305, source-refs/sanmopia-admin/application/models/Payment_model.php:220-279, source-refs/sanmopia-admin/application/models/Payment_model.php:534-752, source-refs/sanmopia-admin/application/models/Payment_model.php:860-940, source-refs/sanmopia-admin/application/models/Payment_model.php:1309-1333, source-refs/sanmopia-admin/application/models/Payment_model.php:1561-1568 | pricing_settlement / PaymentProductPlan, CustomerSharePaymentSchedulePolicy, PaymentSettlementLineTemplate, PaymentProductCommunicationRoute, PaymentProviderRouteFeeSnapshot, PaymentPurpose, SettlementLineKind, SettlementParticipationPolicy | Partial | P0 | Source product behavior is hidden in payment table ids, coupon type codes, fixed voucher fee 15000, fixed coupon fee bands 5000/10000/20000/30000, payment-version customer-share splitting, notification template branches, and settlement-board/type branching. Backend now exposes a Supabase-session-protected PaymentProductPlan catalog through GET /payment-product-plans and GET /payment-product-plans/{planCode} with product family, allowed methods, obligation purposes, provider route, settlement participation, realization timing, refund/conversion policy, virtual-account expiration policy, backend-owned PaymentSettlementLineTemplate rows, and PaymentProductCommunicationRoute rows. Supabase persists versioned active/effective catalog rows in sanmopia_payment_product_plan_catalog_items; catalog v2 adds settlement_line_templates JSONB with voucher fixed commission 15000, gift-coupon commission bands 5000/10000/20000/30000, amount basis, policy reference, and applicability condition; catalog v3 adds communication_routes JSONB with trigger, recipient, provider workflow key, SMS fallback, message purpose, and optional applicability condition for customer-share, pre-reservation, service-balance, gift-coupon, and payment-change notices. The Pydantic adapter derives the same plan book used by Kill Bill pre-registration, so UI must select a backend plan instead of deriving product meaning from payment purpose, table ids, or notification string switches. 2026-07-04 follow-up: PaymentProviderRouteFeeSnapshot now binds the selected product plan, provider routing key, settlement participation, ledger recognition timing, fee recognition basis, settlement line targets, frozen customer-visible behavior, and PaymentMethodFeePolicy quote into the POST /reservation-payment-pre-registrations response. sanmopia_payment_records now stores nullable provider-route/method-fee snapshot columns for new pre-registrations, and the contract requires paymentProductPlanCode plus providerFeeSnapshot, preventing UI-side amount/fee reconstruction after catalog changes. PlanPaymentCommunicationDispatchHandler now converts payment catalog routes plus recipient facts into durable dispatch intents, and SupabaseCommunicationDispatchStore persists catalog-backed dispatch requests plus provider dispatch event audit rows. 2026-07-05 follow-up: CustomerSharePaymentSchedulePolicy now models voucher customer-share payment version 0 as >100000 deposit/balance split, <=100000 deposit-only, version >=1 single obligation, and zero-amount provider closeout; TS/Pydantic contracts expose the backend decision so UI cannot split totals. Remaining migration: bind payment workflow runtime invocation, virtual-account instruction variables, queue/provider execution, booking/settlement persistence, and hidden source payment-type adapter edges to these catalog and schedule decisions. |
source-refs/sanmopia_web/static/js/step3.js:198-474, source-refs/sanmopia_web/static/js/step3.js:766-831, source-refs/sanmopia_web/static/js/step3.js:1148-1179, source-refs/sanmopia_web/application/models/Reservation_model.php:1115-1373, source-refs/sanmopia_web/application/views/reservation/retc.php:45-200, source-refs/sanmopia_web/application/views/modal/modal_change_payment.php:1-92, source-refs/sanmopia-admin/application/views/reservation_status/pre_reservation_price_table.php:1-120, source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:142-161, source-refs/sanmopia-admin/application/models/Reservation_model.php:1579-1677, source-refs/sanmopia-admin/application/models/Reservation_model.php:1627-1652, source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1367-1373, source-refs/sanmopia-admin/application/controllers/Reservation.php:849-859, source-refs/sanmopia-admin/application/controllers/Reservation.php:1243-1251, source-refs/sanmopia-admin/application/controllers/Reservation.php:1531-1593, source-refs/sanmopia_web/application/models/Payment_model.php:383-441, source-refs/sanmopia-admin/application/models/Payment_model.php:3383-3386, source-refs/sanmopia-admin/application/models/Payment_model.php:3458-3461 | pricing_settlement / ChargeAdjustmentPolicy, PaymentAdjustmentCatalog, DiscountAdjustment, AdditionalChargeAdjustment, PartialRefund, CouponPrepaymentQuote, PreReservationCreditPolicy, ManualReceiptCloseout, ReservationPriceSummaryChargeFreezePolicy, FinalizeReservationChargeFromPriceSummaryHandler, ReservationServiceCalendarQuote, ReservationExtensionQuote | Partial | P0 | Source computes discount, coupon/pre-reservation deduction, regional support, extra-service charges, rental/delivery, service balance, payment-change amount, and refund state across browser inputList traversal, DOM data-price sums, PHP models, views, ajax controllers, and gateway loops. Modern replacement must centralize every customer-visible discount, additional charge, custom service-balance override, partial refund, and zero-gateway-refund decision in catalog-backed backend quote/ledger lines. UI may render only frozen adjustment snapshots with catalog version, source evidence key, actor/reason, idempotency key, and settlement impact; UI-observed reservation/payment totals are diagnostics only, not financial authority. 2026-07-04 follow-up: backend now freezes ReservationPriceSummaryInput through ReservationPriceSummaryChargeFreezePolicy into FinalizedReservationChargeSnapshot, with payable lines mother_user_fee_due and service_balance_due plus reference evidence for gross price, government support, regional benefit, coupon, pre-reservation payment, additional/rental charges, voucher service-balance add-on, voucher in-home user-fee change, and displayed discount. FinalizeReservationChargeFromPriceSummaryHandler opens and saves the financial lifecycle from that frozen summary, so post-payment mother-visible charge no longer replays UI/PHP arithmetic after pricing policy changes. ReservationServiceCalendarQuotePolicy now turns weekend/holiday extra-service charge facts into versioned quote lines before the summary is frozen, and ReservationExtensionQuotePolicy derives extension pricing from a new extension chain fact instead of copied payment rows. 2026-07-05 follow-up: PaymentChangeRefundLink now links payment-change adjustments to refund ledger entries through domain/application facts and a Supabase FK column. Newly strengthened remaining gaps: coupon used during pre-reservation must settle/refund in a distinct pre-reservation phase, admin manual receipt must consume frozen pre-reservation credit/coupon facts instead of raw PRERESERVATION_PRICE, refunded rows stay immutable, type 1/2/3 manual rows upsert idempotently, admin manual receipt cannot create paid rows from browser service_before_price or service_balance_price without audited expected amount, reason, and operator identity, and detail-save payment-date commands must mutate only the targeted payment type so balance cannot reuse a deposit date. Remaining abstraction gaps from source digging: CouponPrepaymentQuote, PaymentAdjustmentQuote, VoucherInhomeAddOnQuote, ServiceBalanceOverrideDecision, and PaymentCloseout. |
source-refs/sanmopia_web/application/views/service/step1.php:91-213, source-refs/sanmopia_web/application/models/Reservation_model.php:314-374, source-refs/sanmopia_web/application/controllers/api/Service.php:75-81, source-refs/sanmopia_web/application/controllers/api/Payment.php:91-92, source-refs/sanmopia_web/application/models/Payment_model.php:570-704 | member_management / FamilySponsorRelationship, reservation_operations / ReservationBookerBeneficiarySnapshot, pricing_settlement / PayerSnapshot | Partial | P0 | Source reservation intake binds reservation ownership and payment notices to USER_ID_FK, USER_NM, and CELLPHONE, while EMERGENCY_CELLPHONE, RELATION, and RELATION_ETC are contact fallback fields. Backend/contract now expose family-account authority decisions for reservation sponsor booking, delegated reservation payment, and care-history access. Supabase persistence separates sponsor_member_id, payer_member_id, grantee_member_id, and mother_member_id; API derives the acting member from Supabase Auth app_metadata.member_id and never accepts sponsor/payer/grantee ids in request bodies. Payment closeout dispatch resolution now derives delegated reservation payer recipients from active sanmopia_family_payment_delegations facts and leaves ambiguous multiple-payer grants unresolved. Catalog v4 adds payer payment-complete workflow routes for delegated reservation payment products. Gift-coupon user receivers, phone-only gift receiver contacts, and primary/secondary branch payment notice contacts now resolve from backend snapshots/policies instead of UI strings, fake user ids, branch-id hardcoding, or sorted membership selection. Phone-only receiver provider dispatch uses sanmopia_payment_direct_recipient_contact_snapshots plus contact-only sanmopia_direct_contact_communication_dispatch_requests. Remaining migration: booker/beneficiary snapshot on booking workflow, emergency contact as contact-only data, consent authority, payment liability, document visibility, and refund recipient snapshots. Do not infer sponsor authority from phone ownership or emergency-contact relation text. |
source-refs/sanmopia_web/application/models/Branch_model.php:38-144, source-refs/sanmopia-admin/application/models/Branch_model.php:288-334, source-refs/sanmopia-admin/application/models/Branch_model.php:337-426, source-refs/sanmopia-admin/application/models/Branch_model.php:590-606, source-refs/sanmopia_web/application/controllers/api/Service.php:792-811, source-refs/sanmopia_web/application/models/Reservation_model.php:2113-2137, source-refs/sanmopia_web/application/models/Reservation_model.php:2235-2255 | branch_operations / BranchCoverageDecision, AddressMatchRule, BranchServiceAreaPolicy, CoverageOverride, BranchServiceAreaDecisionSnapshot | Backend + contract | P0 | Source address matching uses fallback address depths, special split-address handling, possible/consultation/impossible rules, hard-delete service area mutation, local other-branch caregiver rejection, and continuation address copying. Backend/contract now expose branch service-area policy publication and decision APIs with Supabase actor, SpiceDB manage/view permission, rule revision, address-provider evidence, matched rule, and semantic policy kind. The decision API records BranchServiceAreaPolicyDecision snapshots into sanmopia_branch_service_area_address_evidence with booking id, decision code, address evidence, matched rule reference, coverage profile key, and service-calendar policy profile key so later policy changes do not rewrite booking-time branch ownership evidence. 2026-07-07 follow-up: reservation booking start now accepts serviceAddress, resolves the active branch policy in the backend, rejects unavailable coverage before booking, records the decision, and serializes a frozen branchCoverageDecision into Restate workflow input/contracts for replay. Continuation draft creation now rejects address/service-area copied facts without branch coverage evidence. Service-term mutation now rejects post-booking service-area profile changes unless the command carries branch_service_area_decision_evidence_id. Remaining migration: bind second-period and extension workflows to the same frozen decision path, persist continuation draft plans through runtime/API paths, add the precise reservation_service_address_id link, then route branch transfer, other-area override, pricing, matching, and conflict audit consumers through the frozen decision. |
source-refs/sanmopia-admin/application/controllers/Reservation.php:415-431 | reservation_operations / OperatorFinancialMutationLockPolicy, ActorStageCapabilityProjection, ReservationFinancialFieldLock | Partial | P0 | Backend now replaces source cantSave with field-level ReservationFinancialFieldLock decisions for price version, service balance, payment date, and reservation status. OperatorFinancialMutationLockPolicy owns service-end-plus-grace-day locking, branch final-state locking, dated waiting-deposit cancellation and stopped-status edit exceptions, stage capability checks, source anchors, and stable lock reason codes. POST /operator-financial-mutation-lock-decisions/{reservationId} derives actorKind from authenticated branch/HQ actor context instead of accepting it from the portal, and returns policyVersionLabel, required capabilities, message keys, and source evidence. Remaining migration: bind the preview and every save command to a Supabase current-state reader with expected revision, persist audit facts for overridden locks, and add branch/HQ override workflow. Portal views must not decide whether a BranchOwner can mutate price, service balance, payment date, or status. |
source-refs/sanmopia-admin/application/controllers/Administrator.php:203-219, source-refs/sanmopia-admin/application/models/Payment_model.php:2565-2654, source-refs/sanmopia-admin/application/models/Payment_model.php:2620-2642, source-refs/sanmopia-admin/application/models/Reservation_model.php:1769-1817, source-refs/sanmopia-admin/application/models/Reservation_model.php:2956-3014, source-refs/sanmopia-admin/application/models/Reservation_model.php:3030-3036 | pricing_settlement / ManualReceiptCommand, SettlementBackfillRepairCommand, SettlementPayoutBackfillCloseout | Partial | P1 | Backend now has protected repair command foundation with HQ actor enforcement, reason, idempotency replay protection, expected revision, paired before/after facts, workflow impact note, and append-only audit records. Remaining gaps: protected manual-settlement contract/UI, authorization policy binding, Supabase audit proof, and repair executors that mutate only targeted payment/settlement rows through expected-revision checks. Status transition backfill must create branch-settlement rows once with expected reservation revision and settlement-impact event; salary/payment-complete backfill must upsert payout rows idempotently and auto-complete only after revision-checked service-balance and salary facts exist. |
source-refs/sanmopia-admin/application/controllers/cli/Manager.php:126-237, source-refs/sanmopia-admin/application/models/Manager_model.php:2038-2143 | caregiver_performance_recognition / CaregiverGradeRecalculation, CaregiverCredentialEvidence | Partial | P1 | Performance-recognition contracts now have Supabase-persisted grade recalculation history plus API/HTTP reads for operator audit. Remaining gaps: scheduled recalculation runner, premium exclusion rules, score/class mismatch warning UX, credential media replacement audit, and frontend history view. |
source-refs/sanmopia-admin/application/views/local_calculate_central_history.php:31-75, source-refs/sanmopia-admin/application/views/table_local_cal_central_history.php:1-39, source-refs/sanmopia-admin/static/js/form_reservation_list.js:225-247, source-refs/sanmopia-admin/application/controllers/Calculate.php:460-578, source-refs/sanmopia-admin/application/controllers/DataRoom.php:311-386 | branch_admin_ux / ReturnStateToken, SettlementHistoryReadModel, DownloadHandoffAudit, SettlementRepairHistoryView | Partial | P1 | Reservation collaboration now handles stale-save/draft events. Branch settlement/export frontend now removes URL token coupling and uses authenticated settlement/export reads plus signed download handoffs. Remaining gaps: durable list filters, return-state tokens where still useful, repair-history UI, retry state, failed export state, signed-download expiry refresh, and branch/HQ visibility filtering. |
2026-07-05 Acceptance Vocabulary Delta
Section titled “2026-07-05 Acceptance Vocabulary Delta”Read-only follow-up mining found broad checklist rows that still need sharper acceptance vocabulary before implementation work is considered done. These are backend ownership obligations; portal/admin UI may render snapshots but must not derive the authority values.
- Service duration is profile-driven, not
weeks * 7. Status:Partial. Evidence:source-refs/sanmopia-admin/application/config/constants.php:98,source-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:16-22,source-refs/sanmopia-admin/application/controllers/Reservation.php:380-381,source-refs/sanmopia-admin/application/models/Reservation_model.php:4146-4247,source-refs/sanmopia-admin/application/models/Reservation_model.php:5379-5418, andsource-refs/sanmopia_web/static/js/step3.js:861-897. Required vocabulary:ServiceDurationProfile,VoucherWeekLength,ServiceEndDatePolicy,ExtraServiceDateSelection, andRegionalDurationBenefit. Backend domain now freezes voucher five-day week basis, service-end rollback policy, source evidence key, profile key, and regional duration extension onServiceCalendarPlan. Supabase now persistsservice_duration_profile_key,duration_profile_evidence_key, andservice_end_date_policyonsanmopia_reservation_service_calendar_plansthrough the service-calendar snapshot RPC. Acceptance proof still needs operator profile management API/UI and command binding from every reservation create/change path. - Continuation reservations are linked booking chains, not flags. Status:
Backend foundation + contract. Evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:2051-2223,source-refs/sanmopia-admin/application/models/Reservation_model.php:3690-3704,source-refs/sanmopia_web/application/models/Reservation_model.php:2431-2449,source-refs/sanmopia_web/application/controllers/api/Service.php:433-439,source-refs/sanmopia_web/application/controllers/api/Service.php:548-555, andsource-refs/sanmopia_web/application/models/Manager_model.php:176-197. Required vocabulary:ReservationContinuationLink,ContinuationEligibility,ContinuationBookingClone, andContinuationCaregiverCarryoverDecision. Backend domain now represents original booking id, continuation booking id, sequence, copied-fact audit key, continuation eligibility, same-caregiver carryover decision, and branch service-area decision evidence as first-class facts. Supabase now stores backend-ownedsanmopia_reservation_continuation_linksrows with a Pydanticlink_snapshot, original/new booking ids, copied-fact audit key, eligibility, same-caregiver carryover reason/source evidence, optional branch coverage evidence, and operator-review flag. 2026-07-07 follow-up: backend commit7d5db21addsContinuationDraftConflictFact,decide_continuation_draft_eligibility, andPlanContinuationDraftCreationPayloadso continuation draft creation distinguishes no prior link, missing linked draft, replaceable writing draft, and active/submitted duplicate blocking. The Pydantic contract records idempotency, superseded draft id, copied-fact audit key, cloned-fact keys, caregiver carryover, optional voucher eligibility, and link output only when cloning is allowed; it rejects source relink/status fields such asRESERVATION_CONTINUE_TB,ORIGINAL_RESERVATION_ID_FK,NEW_RESERVATION_ID_FK,RESERVATION_STATUS_LIST_ID_FK,PROCESS_NO,MANAGER_ID_FK,MANAGER_SCHEDULE_CHECK_FN, and예약작성중. Latest backend contract proof rejects address/service-area copied facts unless the draft carries frozen branch coverage evidence. Acceptance proof still needs collaboration command binding, persisted copied-fact audit detail rows, caregiver schedule reader integration, Supabase draft-plan persistence, and customer/admin read APIs. - Booking consultation gate is a frozen decision, not a reused
CONSULTING_FLflag. Status:Backend-backed foundation. Evidence:source-refs/sanmopia_web/application/controllers/api/Service.php:53-60,source-refs/sanmopia_web/application/models/Reservation_model.php:2235-2301,source-refs/sanmopia_web/application/controllers/api/Service.php:425-430,source-refs/sanmopia_web/application/controllers/api/Service.php:540-545,source-refs/sanmopia_web/application/controllers/api/Service.php:705-719,source-refs/sanmopia_web/application/controllers/Service.php:602-623,source-refs/sanmopia_web/application/views/service/reservation_check_data.php:22-35,source-refs/sanmopia_web/application/views/service/reservation_check_data.php:147-218, andsource-refs/sanmopia_web/static/js/step2.js:476-482. Required vocabulary:ReservationConsultationGateDecision,ReservationConsultationReason,ConsultationCustomerCopySnapshot,BookingMatchingRecommendationEligibility, andPriceVersionRolloverConsultationRule. Modern foundation now records phase-specific reason facts for consultation service area, second address, multi-baby, picked caregiver, birth-after, service-start proximity, continuation override, and price-version rollover evidence with customer-copy and matching-recommendation eligibility snapshots. Remaining work: persist the decision in Supabase and bind booking status, matching suppression, payment handoff, and customer UI to the frozen decision instead of mutable source flags. - Payment/refund authority includes custom override paths. Status:
Partial. Evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:1120-1205,source-refs/sanmopia_web/application/models/Reservation_model.php:1262,source-refs/sanmopia_web/application/models/Reservation_model.php:1348,source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:80-95,source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:335-358,source-refs/sanmopia-admin/application/controllers/Reservation.php:486-503,source-refs/sanmopia_web/application/models/Payment_model.php:383-423, andsource-refs/sanmopia_web/application/models/Payment_model.php:856-896. Required vocabulary:ReservationChargeLine,ExtraServiceChargeBasis,CustomBalanceOverride,VoucherPureAdditionalServiceBalance,PaymentChangeIntent, andRefundInstruction. Acceptance proof: discounts, surcharges, partial refunds, operator overrides, and gateway refund commands are catalog-backed ledger facts, not UI totals. - Reservation state side effects are follow-up plans, not a lifecycle
catch-all component. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:1769-1916,source-refs/sanmopia-admin/application/models/Reservation_model.php:1873-1880,source-refs/sanmopia-admin/application/models/Reservation_model.php:1888-1892,source-refs/sanmopia-admin/application/models/Coupon_model.php:63-157,source-refs/sanmopia-admin/application/models/Coupon_model.php:935-958,source-refs/sanmopia_web/application/models/Reservation_model.php:989-1112, andsource-refs/sanmopia_web/application/models/Coupon_model.php:530-553. Required vocabulary:ReservationStateTransitionPolicy,ReservationOperationPlan,ReservationLifecycleSideEffectPlan,ReservationOperationFollowUpWorkflow,ReservationPromotionSideEffectPlan,PlanReservationPromotionSideEffectHandler, andPromotionEntitlementOutbox. Acceptance proof: cancel, stop, payment, communication, settlement, and care-delivery follow-up actions are persisted with idempotency keys and workflow status; stop and cancel share product entitlement reset planning, but only cancellation restores used reservation entitlements. Source status numbers, source table flags, and provider-specific payment names stay adapter/evidence data, not public contract or component names. - Settlement data room is a workflow workspace. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/views/nav/nav_side.php:425-439,source-refs/sanmopia-admin/application/views/nav/nav_side.php:501-529,source-refs/sanmopia-admin/application/controllers/DataRoom.php:216-308,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:10-49,source-refs/sanmopia-admin/application/models/Payment_model.php:2526-2541,source-refs/sanmopia-admin/application/models/Payment_model.php:2786-2828, andsource-refs/sanmopia-admin/application/models/Payment_model.php:2891-2906. Required vocabulary:SettlementDataRoom,SettlementBoard,BranchSettlementStatement,InterOfficeSettlement,SettlementAcknowledgement, andSettlementAdjustmentLine. Acceptance proof: Danbee, branch-to-HQ, HQ, inter-office, coupon-fee split, manual ETC rows, completion state, and repair history are separate workflow facts. - Caregiver payroll, grade, and multi-caregiver contracts are separate
facts. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:38-42,source-refs/sanmopia-admin/application/models/Reservation_model.php:2245-2293,source-refs/sanmopia-admin/application/models/Reservation_model.php:2471-2561,source-refs/sanmopia-admin/application/models/Manager_model.php:399-475,source-refs/sanmopia-admin/application/models/Manager_model.php:716-725,source-refs/sanmopia-admin/application/controllers/Manager.php:1133-1178, andsource-refs/sanmopia-admin/application/controllers/Manager.php:1847-1883. Required vocabulary:CaregiverAssignmentContract,CareTeamMemberRole,CaregiverAssignmentChangeLog,CaregiverGradeSnapshot,CaregiverCompensationQuote,SubCaregiverPayoutLedger, andTaxWithholdingMode. Acceptance proof: ordered assistant caregivers, replacement logs, grade snapshots, main/sub payout ledgers, custom pay, tax mode, and receipt status no longer share mutable PHP rows. - UI-side financial and payroll calculations must be diagnostics only.
Status:
Partial. Evidence:source-refs/sanmopia_web/static/js/step3.js:24-44,source-refs/sanmopia_web/static/js/step3.js:132-149,source-refs/sanmopia_web/static/js/step3.js:199-327,source-refs/sanmopia_web/static/js/step3.js:345-383,source-refs/sanmopia_web/static/js/step3.js:477-556,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1991-2145, andsource-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:155-231. Required vocabulary:ReservationQuoteSnapshot,ChargeLineProjection,ServiceCalendarQuoteImpact,BackendOnlyCompensationQuote, andPaymentAmountAuthorization. Acceptance proof: rental, delivery, service discounts, voucher surcharges, Saturday/holiday rows, selected dates, payroll tax, and compensation totals are backend snapshots with policy versions. - Old-Astro and portal UI decision clones are backend projections. Status:
Partial. Focused page: Legacy UI Business Logic Gap Mining. Evidence:source-refs/sanmopia-user-old/src/design-system/ui-kit/templates/TemplateReservationList.astro:26-29,source-refs/sanmopia-user-old/src/design-system/ui-kit/islands/ReservationTabIsland.tsx:57-80,source-refs/sanmopia-user-old/src/design-system/ui-kit/organisms/ReservationPaymentInfo.astro:22-80,source-refs/sanmopia-user-old/src/design-system/ui-kit/molecules/ReceiptButtonGroup.astro:22-89,source-refs/sanmopia-user-old/src/design-system/ui-kit/molecules/DocumentList.astro:23-46,source-refs/sanmopia-user-old/src/design-system/ui-kit/templates/TemplateDailySubReport.astro:22-31,source-refs/sanmopia-manager/application/views/schedule/schedule_info.php:136-203,source-refs/sanmopia_web/static/js/menu/feeguide.js:1-144, andsource-refs/sanmopia-admin/static/js/manage_system/holiday_list.js:18-106. Required vocabulary:CustomerReservationListBucketProjection,CustomerPaymentActionProjection,CustomerReceiptAccessProjection,CustomerDocumentAvailabilityProjection,CustomerReportObligationProjection,CareManagerServiceBalanceAcknowledgementProjection,PublicFeeGuideCatalogProjection, andHolidayPolicyCommandProjection. Acceptance proof: customer/caregiver/admin UI renders backend projections with revision, policy/catalog version, disabled/missing reasons, and command target metadata; source status ids, Korean payment labels, numeric document ids, browser current-date checks,마지막날string matching, Saturday/holiday total math, fee-guide filename conventions, and modaldata-typecommand selection remain adapter evidence only.
2026-07-05 CaveCrew Migration Refresh
Section titled “2026-07-05 CaveCrew Migration Refresh”Read-only CaveCrew mining refreshed backend-owned migration obligations while the main track implemented the refund command contract. These are acceptance slices, not source code to copy.
- Payment product authority still needs gift-coupon offers, added service
day pricing, voucher basis, benefit over-credit, and operator correction rows
converged into versioned product/catalog facts. Status:
Partial. Evidence:source-refs/sanmopia_web/application/controllers/api/Payment.php:65-735,source-refs/sanmopia-admin/application/models/Payment_model.php:101-230, and gift-coupon list/action pages. - Cancellation refund side effects must become one backend saga. Status:
Partial. Evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:989-1065,source-refs/sanmopia_web/application/models/Payment_model.php:383-440, andsource-refs/sanmopia-admin/application/libraries/Kcppayment.php:447-456. Required proof: provider success, paid/refunded state, coupon/benefit restore, Momfirst unlink, outbox ordering, and settlement reversal are linked to the reservation operation workflow, not triggered from controller branches. Backend now splits refund closeout frompayment_refund_completion_barrierso downstream entitlement and settlement work cannot complete before terminal provider refund evidence or zero-refund facts exist. Remaining work: wire real provider-event ingestion, zero-refund persistence, and worker execution. - Danbee, branch, headquarters, and inter-office settlement exports need
separate statement/read models. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:150-578,source-refs/sanmopia-admin/application/models/Payment_model.php:828-980,source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3052, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3805. Required proof: manual/negative/component paid lines, dataset revision, export lineage, branch/HQ visibility, and acknowledgement state are typed facts, not recomputed spreadsheet rows. - Caregiver payroll must stop read-time salary recomputation. Status:
Backend-backed foundation. Evidence:source-refs/sanmopia-manager/application/helpers/salary_helper.php:8-227,source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:21-52, and manager salary/detail models. Backend now freezes versioned payout policy profile, care-team slot identity, extension/repeating option amounts, voucher add-on/tax cutover, custom service balance, primary/assistant custom pay, override source, payout instruction, receipt state, adjustment audit, and destination-change audit. Remaining proof: Supabase decision snapshot persistence and admin/manager/HQ screen binding. - Subsidy, regional duration benefit, and branch coverage decisions must
use effective-dated profiles. Status:
Partial. Evidence:source-refs/sanmopia_web/static/js/step3.js:281-293,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:927-945, and reservation model regional-support branches. Required proof: Wanju-style added days, Yeongdeungpo-style address conditions, payment conversion impact, and settlement impact are profile rows and frozen booking evidence, not hardcoded region names. - Reservation state transitions need complete follow-up binding. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/config/constants.php:116-137and cancellation/stop/change controller branches. Required proof: customer change/cancel/stop requests, broad operator edits, cron/payment callbacks, transition ledger persistence, stale-save conflict handling, and generated clients all consumeReservationLifecycleSideEffectPlan.
2026-07-03 Admin UI Decision Delta
Section titled “2026-07-03 Admin UI Decision Delta”Focused scan: source-refs/sanmopia-admin PHP and JavaScript where browser or
controller code calculates money, chooses workflow state, or selects operational
roles. These are migration obligations, not frontend behavior to preserve.
- Admin reservation intake service plan, regional benefit, and charge
freeze. Status:
Partial. Evidence:source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:927-948,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1200-1542,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1883-2124,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:2155-2204,source-refs/sanmopia-admin/application/controllers/Reservation.php:1324-1349,source-refs/sanmopia-admin/application/controllers/Reservation.php:1739-1758,source-refs/sanmopia-admin/application/models/Reservation_model.php:4093-4139,source-refs/sanmopia-admin/application/models/Reservation_model.php:4153-4181, andsource-refs/sanmopia-admin/application/models/Payment_model.php:3748-3825. Required proof:reservation_operations / ReservationAdminIntakeCommand,ReservationServiceCalendarPlan(service_days_per_week),ReservationExtraServiceSelection,pricing_settlement / RegionalBenefitDecision,CustomerSharePaymentSchedulePolicy, andReservationChargeFreezeown address-scoped benefit eligibility, service-period math, added Saturday/holiday dates, regional extra days, add-on quantity pricing, voucher deposit/balance split, zero-amount closeout, and charge freeze. UI must render backend decisions only; it must not decide benefit visibility from address strings, multiply add-on prices by client-side service period, or split customer charges from source status and version flags. - Admin payment conversion board amount and status decisions. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/views/table/reservation_status/table_payment_change.php:5-14,source-refs/sanmopia-admin/static/js/reservation_status/payment_change.js:1-180,source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:68-178, andsource-refs/sanmopia-admin/application/models/Payment_model.php:4422-4521. Required proof:pricing_settlement / PaymentChangeOperatorBoard,PaymentChangeAmountBreakdown,PaymentChangeOperatorCommand,PaymentChangeCompletionAudit, andPaymentChangeProjectionInvalidationfreeze requested amount, current reservation charge basis, prior payment timestamps, allowed operator transitions, synthetic cancellation display, completion timestamp, and audit. UI must not recompute payable amount from current reservation/coupon rows, synthesize a cancellation status id, or overwrite amount/status by raw row id. - Branch/headquarters settlement line selection, fee arithmetic, and
download handoff. Status:
Partial. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:20-225,source-refs/sanmopia-admin/static/js/calculate_detail.js:240-337,source-refs/sanmopia-admin/static/js/calculate_detail.js:342-380,source-refs/sanmopia-admin/static/js/calculate_detail.js:417-533,source-refs/sanmopia-admin/static/js/calculate_detail.js:609-900, andsource-refs/sanmopia-admin/static/js/calculate_detail.js:939-1144. Required proof:pricing_settlement / SettlementStatementCommandContext,SettlementLineAcknowledgement,SettlementManualAdjustmentPolicy,SettlementCompletionReview,SettlementArtifactRequest,SettlementArtifactGrant, andDownloadHandoffAuditown selected line membership, actor-specific command route, payment-method fee policy, membership due, delivery fee, gift-coupon commission, manual rows, completion counters, signed download, and replay/repair audit. UI must not submit a mixedFormDatablob of checked rows and client totals, calculate payment fees in JavaScript, choose completion flags from raw status ids, or download artifacts through raw query-string redirects. - Caregiver candidate snapshot and care-team role assignment. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:900-1144,source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:500-629,source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:660-740,source-refs/sanmopia-admin/application/models/Matching_model.php:44-177, andsource-refs/sanmopia-admin/application/models/Matching_model.php:724-862. Required proof:caregiver_assignment / CaregiverCandidateSnapshot,CaregiverAssignmentDecision,CaregiverAssignmentConflict,CaregiverTransportEvidence, andCareTeamContractpersist ranking policy, score components, branch scope, pet exclusion, schedule proof, deterministic tie-breaker, distance, transport provider result, selected role slot, duplicate/conflict result, actor, reason, and replacement impact. UI must not treat highlighted candidate cards, hidden input role slots, or browser-only duplicate checks as the final assignment decision. - Caregiver payout amount, tax election, and receipt state. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:101-115,source-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:462-644,source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:1-260,source-refs/sanmopia-admin/static/js/manager/manager_pay_inquiry.js:80-286,source-refs/sanmopia-admin/application/controllers/Manager.php:986-1335,source-refs/sanmopia-admin/application/models/Reservation_model.php:2453-2625,source-refs/sanmopia-admin/application/models/Reservation_model.php:2627-2935,source-refs/sanmopia-admin/application/models/Reservation_model.php:2945-3041,source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:21-52,source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:112-180, andsource-refs/sanmopia-admin/application/config/constants.php:272-274. Required proof:pricing_settlement / CaregiverCompensationQuote,CaregiverPayoutInstruction,CaregiverTaxElection,CaregiverPayoutAdjustmentAudit,CaregiverPayoutAcknowledgement, andReservationCompletionDecisionown gross/net quote, add-on basis, override amount, reset behavior, tax policy, memo, main/assistant payout status, receipt timestamp, service-balance acknowledgement, reservation completion side effect, expected revision, actor, and reason. UI must not recompute tax and final pay, post an editable amount as the payout source of truth, or mark reservation completion as an incidental payout-screen side effect. 2026-07-04 contract progress: public TS contracts now exposeCaregiverPayoutAcknowledgementCommandandCaregiverPayoutAcknowledgementReadModelwith branch deposit state, caregiver receipt state, actor, expected revision, idempotency key, and replay guard. Backend already has the corresponding caregiver payout acknowledgement domain/application/Supabase slice. Supabase now persists receipt-state events and current projections separately, so idempotent replay, revision conflict evidence, and manager-facing read state do not depend on mutable salary UI rows. 2026-07-04 follow-up: FastAPI now exposes branch deposit acknowledgement plus caregiver receipt acknowledgement, exception, repair, and read-state routes; the API derives the actor from Supabase Auth and checks SpiceDBrecord_caregiver_payoutor caregiver self-view permission before saving commands. Public TS/OpenAPI contracts now expose those paths, request/response schemas, receipt-state command kinds, and Supabase receipt event/projection table rows. 2026-07-04 adjustment follow-up: backend now recordsCaregiverPayoutAdjustmentAuditas an append-only command with Supabase actor derivation, SpiceDBrecord_caregiver_payoutpermission, idempotency replay guard, target-level expected revision, and full previous/adjusted payable amount, withholding, tax category, and memo snapshots. Supabase persistssanmopia_caregiver_payout_adjustment_auditswith participant RLS, service role upsert grants, realtime publication, and target revision indexes. Public TS/OpenAPI contracts expose/caregiver-payout-adjustment-audits, request and response schemas, changed-field vocabulary, and Supabase row types. Remaining follow-up: backend now recordsCaregiverPayoutDestinationChangeAuditas an append-only command with Supabase actor derivation, SpiceDBrecord_caregiver_payoutpermission, idempotency replay guard, target-level expected revision, full previous/adjusted bank-account and tax-evidence snapshots, changed-field vocabulary, participant RLS, service-role upsert grants, realtime publication, FastAPI route/caregiver-payout-destination-change-audits, public TS/OpenAPI schemas, and Supabase row types. Branch-deposit acknowledgement now matches backend payout-slot identity with caregiver role and handoff order for sourceSORT > 0assistant rows. 2026-07-07 backend follow-up: backend commit81719dcaddsAdminCaregiverPayoutStatementProjection,CaregiverPayoutSlot,CaregiverPayoutOperatorActionAvailability,CaregiverPayoutServiceBalanceState, andCaregiverPayoutCompletionDecision. The application contract now exposesBuildAdminCaregiverPayoutStatementProjectionResultso admin/manager screens can render frozen gross/net/tax/service-balance/deposit/receipt/completion state without PHP/JS salary recalculation. Extra evidence:source-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:4-115,:575-644,source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:14-24,:75-86,:155-231,source-refs/sanmopia-admin/static/js/manager/manager_pay_inquiry.js:183-231,source-refs/sanmopia-admin/application/models/Manager_model.php:332-516,source-refs/sanmopia-admin/application/controllers/Manager.php:1133-1236,source-refs/sanmopia-admin/application/models/Reservation_model.php:2627-2775,:2945-3041, andsource-refs/sanmopia-admin/application/config/constants.php:272-274. 2026-07-07 persistence follow-up: backend commit292f736adds Supabase-backed admin payout statement projection and row tables, participant RLS, realtime publication, deterministic projection/row ids, latest-revision reader, row upsert store, and JSONB display/action roundtrip for multiple caregiver slots on one contract. It also tightens reservation-history export RLS with an explicit signed-in guard and promotes optional integer/datetime and text-array row readers intoSupabaseRowinstead of adding feature-local coercion code. Remaining proof: FastAPI route, generated TS/OpenAPI binding, projection refresh trigger from payout-statement changes, and portal removal of UI-side payout completion logic.
2026-07-03 Notification And Document Delivery Delta
Section titled “2026-07-03 Notification And Document Delivery Delta”Focused page: Notification And Document Delivery Gap Mining.
| Legacy source path/evidence | Modern bounded context / feature name | Implementation status | Migration priority | Notes |
|---|---|---|---|---|
source-refs/sanmopia_web/application/controllers/api/Reservation.php:115-227, source-refs/sanmopia_web/static/js/mypage/reservation.js:337-421, source-refs/sanmopia_web/application/controllers/api/Menu.php:26-72, source-refs/sanmopia-admin/application/controllers/Member.php:410-446, source-refs/sanmopia-admin/application/models/Faq_model.php:65-84, source-refs/sanmopia-admin/static/js/member/faq_detail.js:22-67 | reservation_orchestration / CustomerReservationRequestIntent, customer_engagement / CustomerInquirySubmissionIntent, CustomerInquiryAnswerIntent, CommunicationDispatchRequest, BranchNotificationRoutingPolicy | Partial | P0 | Customer request and inquiry paths still mutate request/inquiry state, choose recipients, send provider messages, send customer push, and let browser callbacks choose customer-visible completion copy inline. Backend/contract foundation now freezes customer cancel/stop/change intake as CustomerReservationRequestIntentPlan: it requires expected reservation revision, profile-driven branchRoutingProfileKey, branch recipient facts, backend-owned dispatch idempotency keys, provider-neutral workflow instructions, and backend message keys such as reservation_request.cancellation.completed. Customer inquiry submission now has a separate CustomerInquirySubmissionIntentPlan in customer_engagement: it freezes inquiry persistence, submission idempotency, branch routing profile, branch recipient facts, provider-neutral dispatches, backend result route/message keys, and excludes questionBody from provider notification payloads so full inquiry text stays in persisted inquiry records. Customer inquiry answer now has CustomerInquiryAnswerIntentPlan: it replaces legacy branch isMyFaq checks and FAQ_ANSWERED insertion with branch-profile equality guards, expected inquiry revision, idempotent answer mutation facts, backend result route/message keys, and a customer_inquiry:answered_mother Novu workflow whose notification payload excludes answerBody. OSS workflow catalog/Supabase seed covers cancellation requested/completed, care-stop requested, change requested, customer-inquiry submitted, and customer-inquiry answered triggers without source branch-id or FAQ constants in new contracts. Remaining migration: persist intent plans, bind authenticated API commands and conflict handling, enqueue dispatch requests/events, wire customer/operator result projections, and remove UI callback text/recipient branching. |
source-refs/sanmopia_web/application/controllers/api/Payment.php:421-463, source-refs/sanmopia_web/application/controllers/api/Payment.php:439-491, source-refs/sanmopia_web/application/controllers/api/Payment.php:598-643, source-refs/sanmopia_web/application/controllers/api/Payment.php:740-754, source-refs/sanmopia_web/application/controllers/api/Kcp.php:75-100, source-refs/sanmopia_web/application/models/Payment_model.php:353-380, source-refs/sanmopia_web/application/models/Payment_model.php:531-567, source-refs/sanmopia_web/application/models/Payment_model.php:654-677, source-refs/sanmopia_web/application/models/Payment_model.php:708-716 | pricing_settlement / CustomerPaymentInstruction, PaymentVirtualAccountInstructionPayload, VirtualAccountPaymentLifecycle, PaymentCommunicationWorkflow, customer_engagement / CommunicationDispatchRequest | Partial | P0 | Payment controller still builds virtual-account and completion messages, selects provider template/fallback, sends branch/customer notices, and special-cases extra recipients. Backend must freeze purpose, amount, method, provider route, visible message state, recipient policy, idempotency, retry, and audit before provider handoff. Virtual-account issue notice, waiting-payment row, and deposit callback must share one frozen request amount. 2026-07-05 backend follow-up: KillBillPaymentEventIngestionHandler extracts provider paid amount candidates (amountKrw, amount, paidAmount, ipgm_mnyx, good_mny) from raw webhook payloads and rejects mismatches before starting ReservationPaymentWorkflow, so callback amount drift cannot mark paid or trigger settlement. Remaining proof: persist provider-approved amount snapshots for receipt artifacts and bind every issued-VA notice to the same frozen request. |
source-refs/sanmopia_web/application/views/mypage/reservation_document.php:45-123, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:19-129, source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:158-225, source-refs/sanmopia_web/application/controllers/Notification.php:19-27 | document_reporting / ReservationDocumentCatalog, ReservationDocumentBundle, DocumentAccessGrant, DocumentDeliveryAttempt | Partial | P0 | Customer view still chooses numeric document ids and token URLs. Backend/domain and TS/JSON contracts now require reservation/document/artifact/channel/action scoped access grants: grant history carries documentDefinitionKey, documentArtifactVersionKey, accessChannel, and allowedActionCodes, and delivery validation rejects grants that do not match the delivery document or channel. Scheduled CLI still chooses file lists from service/payment/status facts, sends email attachments, records send status, and deletes temp files. Remaining migration: Supabase persistence, signed-storage issuing route, scheduled/manual worker binding, resend/revoke operator UX, and full source attachment/template parity. |
source-refs/sanmopia_web/application/views/mypage/item/reservation_func_btn.php:1-190, source-refs/sanmopia_web/application/views/mypage/item/reservation_detail_func_btn.php:1-210, source-refs/sanmopia_web/application/views/mypage/pre_reservation_detail.php:41-90, source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:421-452, source-refs/sanmopia_web/static/js/mypage/reservation.js:337-421 | reservation_operations / CustomerActionAvailabilityPolicy, CustomerReservationStateMappingCatalog, CustomerReservationStateSnapshot, CustomerNewReservationEligibilityPolicy, CustomerReservationLifecycleSnapshot, CustomerActionCommand | Partial | P0 | Customer pages still choose payment, delivery, report, cancel, continue, reschedule, conversion, and more-info actions from raw status/payment maps; browser code chooses route and success copy after response. Backend foundation now owns policy-rule evaluation, disabled reasons, command target, descriptor message keys, idempotency scope, service-end gates, change/stop request actions, service-balance instruction readiness, and a versioned source-status mapping catalog so old reservations can project source_status_code plus catalog version into current customer lifecycle language, customer_list_bucket, detail_surface_kind, and blocks_new_reservation without frontend status switches. CustomerDetailSurfaceKind is now shared vocabulary used by state snapshot and lifecycle snapshot: 15/16 select pre-reservation detail directly, while 9/17/19 need pre_reservation_flag=true and pre_conversion_completed=false. CustomerNewReservationEligibilityPolicy now composes projected reservations and returns available or blocked_by_existing_reservation with blocker reservation ids, so the frontend does not inspect source status 8/14/16 directly. Remaining migration must persist mapping/policy catalogs, wire API/read adapters, bind actor authorization, and remove raw status branches from portal UI. |
source-refs/sanmopia_web/application/controllers/api/Shop.php:105-166, source-refs/sanmopia_web/application/controllers/management/Push.php:10-45, source-refs/sanmopia_web/application/controllers/management/Push.php:49-86, source-refs/sanmopia_web/application/models/Notification_model.php:16-68 | customer_engagement / PromotionDeliveryAttempt, CampaignDispatchSegment, NotificationInboxItem, CommunicationDispatchRequest | Partial | P1 | Customer-engagement paths still resend gift-coupon SMS, manually segment campaign push recipients by raw reservation status/token rows, and insert inbox rows from device tokens. Backend must own audience policy, recipient snapshots, inbox action projections, dispatch attempts, provider results, suppression reasons, and repairable retries. |
source-refs/sanmopia_web/application/controllers/Momfirst.php:87-145, source-refs/sanmopia_web/application/controllers/Clean.php:67-125 | customer_engagement / PartnerBenefitResultArtifact, DocumentAccessGrant, PartnerBenefitDeliveryBatch | Partial | P1 | Partner-result downloads still validate document tokens, check reservation ownership, read admin-root file paths, and stream bytes directly. Backend must expose storage-backed result artifacts with grant expiry, checksum/content metadata, provider delivery batch state, and access audit. |
Status compatibility facts found during the customer-action migration:
reservation status codes are duplicated across web/admin/manager constants and
runtime DB maps, including 0 예약, 1 상담, 2 일정미확정, 3 확정,
4 진행, 5 정산, 6 완료, 7 변경요청, 8 취소요청, 9 취소,
10 연장요청, 11 연장, 12 중단요청, 13 중단, 14 입금대기,
15 사전예약, 16 사전예약대기, 17 입금대기취소,
18 사전예약취소, and 19 오프라인. Customer tabs and actions are split
across MyReservation.php:21-90, reservation_func_btn.php:1-190,
reservation_detail_func_btn.php:1-210, reservation.js:326-560, and cron
transitions in cli/Reservation.php:12-70. Modern code must keep those numeric
source codes in status-mapping catalogs such as legacy_web:17, not in UI
conditions or action-policy branches.
Additional tab and blocking facts: MyReservation active bucket is
0,1,2,3,4,5,7,8,10,11,12,14,15,16; history bucket is 6,9,13,17; customer
tabs omit -1, 18, and offline 19. New reservation is blocked only by
existing 8 취소요청, 14 입금대기, and 16 사전예약대기; source draft
-1 작성중 is deleted/replaced on insert. 19 오프라인 remains an
admin-side projection/status dimension and must not silently enable customer
actions.
Pre-reservation admin detail has a different status surface from customer tabs:
pre_reservation_detail.php:90-118 exposes source statuses 9, 15, 16,
17, and 19, while 18 사전예약취소 remains defined in constants but is not
selectable there. Needs source confirmation: treat 18 as either legacy-data
compatibility or a separate command result only after checking production rows
or DB seed values; do not alias it to 9 in new contracts without evidence.
2026-07-03 Sidecar Feature Gap Delta
Section titled “2026-07-03 Sidecar Feature Gap Delta”Focused scan: legacy admin, manager, and customer PHP/JavaScript paths that were not yet named as feature slices in this checklist. These entries are modernization obligations only; legacy code shape must not be copied.
| Legacy source path/evidence | Modern bounded context / feature name | Implementation status | Migration priority | Notes |
|---|---|---|---|---|
source-refs/sanmopia_web/application/models/Reservation_model.php:264-306, source-refs/sanmopia_web/application/controllers/api/Reservation.php:363-405, source-refs/sanmopia-admin/application/controllers/Reservation.php:699-897, source-refs/sanmopia-admin/application/models/Reservation_model.php:6016-6032, source-refs/sanmopia-manager/application/views/schedule/schedule_info.php:557-562, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3558-3562 | reservation_operations / PostpartumCareCenterStayPlan, ServiceDueDatePolicy, ReservationDeliveryProfile | Partial | P0 | Backend foundation migrated under reservation_operations/features/postpartum_care_center_stay: versioned stay-plan catalog, delivery-method due-date rules, customer/operator command actor roles, expected revision, continuation next-weekday policy, service due-date recalculation, service-calendar/matching/pricing/payment/document invalidation targets, caregiver schedule fields, and document projection are now backend-owned. Remaining migration must persist stay-plan catalogs/profile revisions in Supabase, expose command/query APIs, bind mother/branch/HQ authorization, and wire UI without source care-center ids or UI date recomputation. |
source-refs/sanmopia-admin/application/controllers/Reservation.php:1490-1518, source-refs/sanmopia-admin/application/models/Reservation_model.php:6100-6113, source-refs/sanmopia-admin/application/controllers/Reservation.php:452, source-refs/sanmopia-admin/application/controllers/Reservation.php:632-640 | reservation_operations / OfflineReservationIntakeCommand, ReservationDuplicateGuard, ManualReservationSource | Partial | P1 | Backend foundation migrated under reservation_operations/features/offline_reservation_intake: deterministic idempotency keys, normalized customer identity, service-period overlap checks, actor/source channel, branch scope, duplicate decision audit, and explicit conflict response are now domain/application-owned instead of source status-id queries or browser retry messages. Supabase now persists backend-owned sanmopia_offline_reservation_duplicate_decision_audits rows with idempotency key, branch/customer/service-period query columns, accepted/conflict decision, reason code, existing reservation evidence, and immutable Pydantic decision snapshot. Remaining migration must expose the API command handler, bind actor authorization, and wire operator UI. |
source-refs/sanmopia-admin/application/controllers/Calculate.php:504-548, source-refs/sanmopia-admin/application/models/Service_model.php:274-319, source-refs/sanmopia-admin/static/js/calculate/other_service_management.js:1-89, source-refs/sanmopia-admin/application/views/calculate_detail.php:1214-1265 | pricing_settlement / SettlementManualAdjustmentCatalog, SettlementManualAdjustmentCatalogVersion, SettlementManualAdjustmentLine | Partial | P1 | Backend foundation migrated under pricing_settlement/features/settlement/manual_adjustment_catalog.py: source LIST_SERVICE_ETC_TB add/edit/delete is now a stable-code, revision-guarded, versioned manual-adjustment catalog; used entries deprecate instead of hard-deleting; catalog mutations require headquarters actor/reason/idempotency audit; opened branch, Danbee, and inter-office statement lines freeze catalog version, display name, unit price, quantity, direction, actor, statement revision, lineage evidence, and total amount in backend-owned snapshots so later catalog edits cannot rewrite totals. Branch-scope frozen lines now project to bidirectional branch_adjustment line items, so receivable/payable manual extra rows enter backend net-balance math instead of UI/view PRICE * COUNT. This removes source numeric row ids from contracts, UI-rendered-row edit state, and client/view authority. Remaining migration must persist catalog versions/usage snapshots/frozen lines in Supabase, expose command/query routes, bind SpiceDB/RLS, and wire operator UI. |
source-refs/sanmopia-admin/application/config/constants.php:291-313, source-refs/sanmopia-admin/application/models/Reservation_model.php:646-923, source-refs/sanmopia-admin/application/models/Reservation_model.php:2453-2535, source-refs/sanmopia-admin/application/models/Reservation_model.php:2568-2625, source-refs/sanmopia-admin/application/models/Reservation_model.php:3095-3148, source-refs/sanmopia-admin/application/models/Reservation_model.php:3507-3555, source-refs/sanmopia-admin/application/models/Reservation_model.php:3560-3642, source-refs/sanmopia-admin/application/models/Reservation_model.php:3667-3685, source-refs/sanmopia-admin/application/models/Reservation_model.php:5608-5867, source-refs/sanmopia-admin/application/controllers/Reservation.php:461-511, source-refs/sanmopia-admin/application/controllers/Reservation.php:1819-1855, source-refs/sanmopia-admin/application/controllers/Manager.php:980-1135, source-refs/sanmopia-admin/application/views/reservation_status/reservation_price_table.php:1-120, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:390-410, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:760-832, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:1031-1068 | pricing_settlement / ReservationPriceVersionAndSubsidyAdjustment, PriceCatalogVersionPolicy, ReservationServiceBalanceOverride, VoucherPureAdditionalServiceBalance, ReservationServiceBalanceConfirmation, ServiceBalancePaymentCloseout, CaregiverServiceBalanceReceiptCloseout | Partial | P1 | Backend foundation migrated under pricing_settlement/features/reservation_price_version_adjustment, pricing_settlement/features/pricing/voucher_service_add_on.py, pricing_settlement/features/settlement/service_balance.py, and pricing_settlement/features/payment/reservation_service_balance_closeout.py: PRICE_VERSION_YEAR is now dated catalog-version policy, price-version apply produces immutable before/after facts instead of mutating reservation/payment/add-option rows, voucher consume-type service-day mismatch becomes a blocked decision, subsidy/regional-support/customer-share deltas are backend facts, branch service-balance override freezes default/override amounts with actor/reason/idempotency audit, voucher pure-additional service balance subtracts frozen special/live-in voucher add-on amount from posted service-balance amount, service-balance confirmation freezes the actual /reservation/confirmServiceBalance closeout effect as SERVICE_BALANCE_PRICE, SERVICE_BALANCE_CONFIRM_FL = 1, and SERVICE_BALANCE_PRICE_USE_FL = 1 decision metadata, and service-balance payment closeout now models source branch-manager 서비스잔금 row creation plus zero-amount auto-completion as backend-owned receipt states for any number of caregiver recipients. This removes numeric price-version ids from contracts, source UI year-label hardcoding, controller row rewrite authority, UI-entered service-balance totals, confirm-only stale endpoint behavior, fixed primary/sub-only receipt modeling, and DOM-mutated add-service totals as source of truth. Service-balance closeout now has service-role Supabase RPC persistence, RLS read policies, a backend API route, and backend commit 4e4b140 requires frozen finalizedChargeSnapshotId, serviceOccurrenceLedgerKey, and serviceOccurrenceLedgerRevisionNumber on the closeout command/API/HTTP/RPC path before receipt states can be opened. Focused 2026-07-07 proof includes service-balance closeout tests, reservation smoke, HTTP booking workflow-start tests, stage Supabase migration replay, stage schema lint, regenerated Supabase types, and supabase:smoke:stage:service-balance-closeout rollback smoke. Remaining migration must persist voucher pure-additional decisions and non-closeout adjustment audits, bind SpiceDB/RLS for the remaining commands, connect price catalog read models, expose price-table and service-balance projection APIs, and wire operator UI without client-side recalculation. |
source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:254-621, source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:76-78, source-refs/sanmopia-admin/application/models/Reservation_model.php:4323-4383, source-refs/sanmopia-admin/application/models/Reservation_model.php:4388-4459, source-refs/sanmopia-admin/application/models/Reservation_model.php:6117-6127, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4104-4113, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4328-4338, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4486-4488 | document_reporting / VoucherEndNoticeReadiness, VoucherEndNoticeReadinessParity, VoucherEndNoticeDeliveryBatchReadinessDecision, VoucherEndNoticeDeliveryAttempt, DocumentArtifactReadiness | Partial | P0 | Backend foundation expanded in document_delivery: voucher end notice readiness now owns normal/stopped batch kind, voucher eligibility, reservation-status skip, customer-deposit payment confirmation, artifact readiness, signed grant state, sent-attempt duplicate suppression, failed-attempt retry planning, and customer inbox action payloads. Source still gates the same document differently across DataRoom user-level END_DOCUMENT filtering, notification DATA search by reservation id, bulk/admin silent skip, customer PDF error handling, scheduled mail batch selection, always-rendered mail PDF type 21, and mail audit flags 3/4. One backend readiness decision must bind reservation id, user id, notification/grant evidence, artifact readiness, missing reason, batch kind normal_end versus stopped_end, payment prerequisite, skip-status reason, duplicate suppression, notification/action creation, manual download, bulk bundle, scheduled mail render, resend, and access grant. This replaces source doc id 21, mail flags 3/4, END_DOCUMENT notification text search, and hardcoded /myReservation/document/{id} contract leakage. Remaining migration must persist readiness/grant/action history in Supabase, bind render worker/provider handoff, expose routes, add resend/revoke controls, wire access-history UI, and prove cross-entrypoint readiness parity. |
-
2026-07-05 source-dig addition for
ReservationServiceBalanceOverride:/reservation/serviceBalanceConfirmis stale JavaScript with no verified CodeIgniter route alias. Actual reachable path is/reservation/confirmServiceBalance, which setsSERVICE_BALANCE_PRICE,SERVICE_BALANCE_CONFIRM_FL = 1, andSERVICE_BALANCE_PRICE_USE_FL = 1. The similarly named model method only flipsSERVICE_BALANCE_CONFIRM_FL. Modern closeout commands must preserve the actual three-field effect and keep stale endpoint naming as adapter-only migration evidence. Backend now hasConfirmReservationServiceBalance/ConfirmReservationServiceBalancePayloadfoundation for the actual three-field closeout; remaining work is Supabase persistence, command API, payment-row closeout, and receipt/settlement side-effect binding. 2026-07-05 backend follow-up:ServiceBalancePaymentCloseout,CaregiverServiceBalanceReceiptCloseout, andCloseReservationServiceBalanceHandlernow cover sourceinsertServiceBalanceInfo: create a service-balance receivable, keep positive amounts waiting for branch payment and caregiver receipt confirmation, and auto-complete all caregiver receipt states when the service balance is zero. Supabase now persists this as an idempotent closeout event/current row plus caregiver receipt-state rows throughsanmopia_save_service_balance_closeout, and the backend exposesPOST /reservation-service-balance-closeouts. Backend commit4e4b140now requires the closeout request to include the finalized charge snapshot id and the service occurrence ledger key/revision, persists those frozen references in the Supabase closeout event/current row, and rejects idempotency reuse when those references drift. Focused proof on 2026-07-07 includes reservation smoke, HTTP booking workflow-start tests, andsupabase:smoke:stage:service-balance-closeout, which proves the stage DB booking RPC -> occurrence ledger -> closeout RPC path inside a rolled-back transaction. Follow-up proofsupabase:smoke:stage:financial-lifecycle-closeout-guardnow creates a real stage booking, reuses the booking-created occurrence ledger instead of inserting a duplicate revision, records service delivery and caregiver payout, rejects staleserviceBalanceCloseoutEventIdat Branch settlement, then accepts the backend-confirmed Branch/HQ settlement references throughsettled. The live proof exposed and fixed a schema drift bug: additional-service selection revision reads must derive paths from journalfield_changes, not the broadcast-onlychanged_field_pathslabel. 2026-07-08 source-dig addition: the reachable service-balance override path also records actor office facts as JSON plus the posted override amount inRESERVATION_SERVICE_CUSTOM_LOG_TBbefore applying the current balance (source-refs/sanmopia-admin/application/controllers/Reservation.php:461-511,source-refs/sanmopia-admin/application/models/Reservation_model.php:5904-5912). ModernReservationServiceBalanceOverrideAuditLedgermust make actor office, command source, previous/default amount, posted amount, derived voucher-pure additional amount, expected charge revision, and idempotency key first-class; UI-submitted balance and JSON branch labels are request evidence only. Remaining work: operator conflict/audit binding, branch/HQ repair UX, settlement-completion side-effect execution, frontend wiring, and full E2E proof through the running app container. -
2026-07-05 source-dig addition for hidden PHP/UI business logic:
ServiceTermCalendarPolicy,ReservationAddDayCommand,ProductCouponEntitlementSchedule,CustomerChargeRecomposition,VoucherServiceAdditionalPriceAdjustment,PreReservationCouponOverpayFulfillment,SettlementLineKindBook,CareTeamRoleContract,TravelEvidenceProvider,BranchCoverageDecision,RegionalBenefitRule, andDocumentSeriesPaginationPolicyare now tracked as backend-owned feature obligations. Evidence includes service duration, add-day, product coupon, price-table, voucher surcharge, pre-reservation coupon overpay, settlement line kind, care-team, distance provider, coverage, regional benefit, and document-series paths:source-refs/sanmopia-admin/application/config/constants.php:98,source-refs/sanmopia-admin/application/models/Reservation_model.php:643,source-refs/sanmopia-admin/application/controllers/Reservation.php:902,source-refs/sanmopia-admin/application/models/Reservation_model.php:1300,source-refs/sanmopia-admin/application/views/reservation_status/reservation_price_table.php:24,source-refs/sanmopia_web/application/models/Payment_model.php:758,source-refs/sanmopia-admin/application/models/Payment_model.php:1288,source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:1114,source-refs/sanmopia-admin/application/models/Matching_model.php:796,source-refs/sanmopia-admin/application/models/Branch_model.php:291,source-refs/sanmopia_web/application/controllers/api/Service.php:346, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3977. These items are not source-code-copy tasks. Each must become a versioned policy/profile/catalog/decision slice before UI or document rendering can consume it. -
2026-07-05 persistent-agent source-dig addition:
ExtraServiceBabyTypeSurchargePolicy,ReportMetricDateBasisPolicy,LegacySalesFeeMetricSnapshot,PerformanceEligibilityMetricRule, andCaregiverManualEvaluationAdjustmentPolicyare now tracked as source-parity risks. Evidence:source-refs/sanmopia-admin/application/models/Service_model.php:323-356,source-refs/sanmopia-admin/application/controllers/Reservation.php:1683-1687,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1897-1912,source-refs/sanmopia-admin/application/models/Statistics_model.php:1070-1116,source-refs/sanmopia-admin/application/models/Statistics_model.php:1155-1173,source-refs/sanmopia-admin/application/models/Statistics_model.php:794-843, andsource-refs/sanmopia-admin/application/controllers/Manager.php:194-240. Backend obligations: voucher Saturday/holiday baby-type surcharge eligibility must freeze catalog revision and not depend on UITWINS_FL; report date buckets must stop merging months/quarters across years; sales fee metrics must replaceGET_PAYMENT_FEE_RATIOwith versioned fee snapshots; performance metrics must store eligibility rule versions and branch visibility; caregiver manual score edits must carry actor, score type, min/max policy, and explicit source-compat handling for the legacy HQ max-check bug. Backend foundation now includesExtraServiceBabyTypeSurchargePolicy, which selects standard versus multiple-birth extra-service unit price from a versioned catalog row and keeps source price-version refs as evidence, not branching authority.Actor/context handoff:
flowchart LR Mother[Mother/FamilySponsor] --> Charge[pricing_settlement<br/>ExtraServiceBabyTypeSurchargePolicy] Branch[BranchOwner] --> Reports[business_reporting<br/>ReportMetricDateBasisPolicy<br/>LegacySalesFeeMetricSnapshot] HQ[HeadOfficeManager] --> Reports HQ --> Performance[caregiver_performance_recognition<br/>PerformanceEligibilityMetricRule<br/>CaregiverManualEvaluationAdjustmentPolicy] Branch --> Performance Care[CareManager] --> Performance Charge --> Docs[document_reporting<br/>frozen charge/report artifacts] Reports --> Docs Performance --> Docs
Migration gates:
-
Mother/FamilySponsorcharge projections expose baby-type surcharge eligibility from frozen catalog/service-day evidence, not browser flags. -
BranchOwnerandHeadOfficeManagerreport dashboards share one metric catalog where date basis, sales fee snapshot, branch scope, and export revision are immutable. -
CareManagerrecognition views read published scorecards only;HeadOfficeManagerand permittedBranchOwneredits create manual adjustment ledger entries with cap-policy evidence and downstream grade invalidation.
-
-
2026-07-05 source-dig addition for reporting and voucher remap edge cases:
BusinessPerformanceFunnelSnapshot,SalesRecognitionBasisReport,ScopedReportBranchVisibilityPolicy,CaregiverEvaluationCronScoreLedger,VoucherServiceBalanceOverrideFloor,ServiceBalanceAdditionalServiceChargeDecision,AdditionalServiceCatalogVersionRemap,PreReservationCouponOverCredit,ConvertedReservationOverCredit,AdminCancellationVoucherRefundStatusEdge,PaymentChangeZeroPayableCompletion, andVoucherPureAdditionalServiceBalanceare exact source-parity gaps. Evidence:source-refs/sanmopia-admin/application/controllers/Statistics.php:283-323,source-refs/sanmopia-admin/application/models/Statistics_model.php:24-62,source-refs/sanmopia-admin/application/controllers/Statistics.php:436-460,source-refs/sanmopia-admin/application/models/Statistics_model.php:1885-1930,source-refs/sanmopia-admin/application/controllers/Statistics.php:27-43,source-refs/sanmopia-admin/application/controllers/cli/Manager.php:22-100,source-refs/sanmopia-admin/application/libraries/ManagerEvaluationLib.php:76-266,source-refs/sanmopia-admin/application/controllers/Reservation.php:486-505,source-refs/sanmopia-admin/application/controllers/Reservation.php:1819-1847,source-refs/sanmopia-admin/application/models/Reservation_model.php:5623-5759,source-refs/sanmopia-admin/application/models/Reservation_model.php:5985-6012,source-refs/sanmopia-admin/application/models/Service_model.php:238-260,source-refs/sanmopia_web/application/models/Payment_model.php:232-270,source-refs/sanmopia_web/application/models/Payment_model.php:775-841,source-refs/sanmopia_web/application/models/Payment_model.php:857-896,source-refs/sanmopia-admin/application/models/Reservation_model.php:1827-1856, andsource-refs/sanmopia-admin/application/models/Payment_model.php:4155-4182. Backend obligations: funnel metric buckets, payment-date sales recognition, branch-visible report scope, score cron run ledger, voucher additional-service catalog remap, additional-service effective-day basis, pre-reservation over-credit, converted-reservation over-credit, admin refund status classification, zero-payable payment-change completion, andVoucherPureAdditionalServiceBalancemust become named policy/snapshot facts. UI filters, source branch ids, source status ids, and mutable payment row rewrites cannot be authority. Formula-level gaps: persistposted_service_balance_krw, frozen voucher additional-service amount,pure_additional_service_balance_krw, price-version evidence, reason code, and repair-required flag; route negative pure-additional edge cases through operator repair instead of silent row rewrites. Backend foundation now includesServiceBalanceAdditionalServiceChargePolicy, which reusesAdditionalServiceChargePolicyto freeze caregiver before-tax pay, base-service days, Saturday/holiday extension count, effective service days, additional-service charge amount, and final service-balance amount in one decision. 2026-07-07 naming hardening replaced backend/contractadd_option_amount_krwand publicaddOptionAmountKrwwithadditional_service_amount_krwandadditionalServiceAmountKrwin voucher catalog snapshots, keeping source add-option labels only in evidence rows. Backend foundation also includesPreReservationCouponOverCreditPolicy, which injects the required down-payment amount through a versioned rule, returns provider-payment versus zero-provider-payment closeout, and plans point plus shopping-mall-coupon over-credit grants fromsource-refs/sanmopia_web/application/models/Reservation_model.php:1401-1414,source-refs/sanmopia_web/application/models/Payment_model.php:775-841, andsource-refs/sanmopia_web/application/controllers/api/Payment.php:537-544. Backend foundation now also includesConvertedReservationOverCreditPolicy, which preserves thesource-refs/sanmopia_web/application/models/Payment_model.php:232-270three-branch point formula for converted-reservation closeout, including the extra coupon-prepayment grant when own price is below pre-reservation price. Persistence, entitlement outbox, and closeout workflow binding remain open.Actor/context handoff:
flowchart LR Branch[BranchOwner] --> Balance[pricing_settlement<br/>VoucherPureAdditionalServiceBalance] HQ[HeadOfficeManager] --> Balance Balance --> Closeout[ServiceBalancePaymentCloseout] Balance --> Payout[CaregiverPayoutStatement] Balance --> Settlement[SettlementStatementWorkflow] Balance --> Docs[document_reporting<br/>charge and receipt artifacts]
Migration gates:
- Branch/HQ service-balance projections expose posted balance, voucher add-on, pure-additional balance, reason code, and repair state from backend policy facts only.
- Service-balance closeout, caregiver payout, settlement, and receipt
artifacts consume the same
VoucherPureAdditionalServiceBalancesnapshot. - Price-table and operator repair screens submit commands with actor, reason, expected revision, and idempotency key; no portal recomputes voucher add-on subtraction.
2026-07-03 Additional Hotspot Queue
Section titled “2026-07-03 Additional Hotspot Queue”Focused page: Promotion Caregiver Analytics Gap Mining. Additional focused page: Customer Account And Reservation Intake Gap Mining. Self-service focused page: Customer Self-Service Workspace Gap Mining. Partner benefit focused page: Partner Benefit Fulfillment Gap Mining. Traffic-spike focused page: Traffic Spike Backpressure Gap Mining. Notification/document-delivery focused page: Notification And Document Delivery Gap Mining.
-
OSS load balancing, queueing, and backpressure. Status:
Partial. Evidence:assembly-repo/docker-compose.ymlalready routes browser-facing services through Traefik Docker labels with containerexpose, self-hosted Supabase services, Restate workflow state, SpiceDB authorization, and Novu notification workers. Modern foundation now adds Traefik edge limits and in-flight caps on backend/frontend/Supabase public routers, self-hosted Supabasepgmq, queue/worker env SSOT, internal OpenTelemetry Collector, and backend OTLP env wiring. Workload-specific queue names, priorities, visibility timeouts, max attempts, and dead-letter queues are now centralized in the backend Supabase queue contract and created by a Supabase CLI migration. The backend now adds a reusableSupabaseQueueWorkloadBatchDispatcher,SupabaseQueueWorkerPort, andSupabasePgmqQueueAdapterread/archive contract so success, visibility-timeout retry, max-attempt dead-letter, and source-message archive behavior are shared instead of reimplemented per feature. SpiceDB relationship sync now has a workload processor that validates queued relationship payloads, writes throughSpiceDBAuthorizationPort, and uses the shared archive/dead-letter path. An internal service-token route,POST /internal/queue-workloads/{workloadKind}/dispatches, now exposes the shared dispatcher for runtime workers without adding per-workload script entrypoints. Required proof still pending: payment/webhook/document/settlement/notification and matching processors, Restate replay binding for every provider/artifact/settlement flow, persisted idempotency rows per command, operator repair UX, Prometheus/Grafana/Tempo exporter stack, and queue-depth/oldest-age/dead-letter dashboards. Scope must cover payment pre-registration, document generation, settlement exports, notification sends, matching batch, and webhook processing. No proprietary queues, cloud-only gateway, host-port shortcut, or reuse of Novu-owned Redis as Sanmopia domain state without a separate Valkey/Redis justification. -
Promotion/shop entitlement and fulfillment. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/Promotion.php:293-564,source-refs/sanmopia-admin/application/models/Coupon_model.php:10-160,source-refs/sanmopia-admin/application/models/Coupon_model.php:240-323,source-refs/sanmopia-admin/application/models/Promotion_model.php:18-55, andsource-refs/sanmopia-admin/application/models/Momfirst_model.php:12-272. Required proof:PromotionEntitlement,GiftFulfillmentRequest, andMomfirstDeliverypreserve coupon reissue lineage, gift shipment state, Momfirst DB-send/no-send/result artifact state, customer-safe download grants, and branch/HQ visibility without hard deletes or direct filesystem downloads. Backend domain/application now has injectedPromotionEntitlementCatalog, configurable service-gift schedules, owner/recipient separation, audited entitlement transitions, generic source-to-entitlement compatibility mapping, and no production default product-code/amount catalog. Remaining proof: persistence, public/internal APIs, contract generation, Momfirst delivery batches/result artifacts, operator UI, and storage grants. -
Caregiver profile credential dossier. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/Manager.php:47-106,source-refs/sanmopia-admin/application/controllers/Manager.php:133-544,source-refs/sanmopia-admin/application/controllers/Manager.php:1378-1591,source-refs/sanmopia-admin/application/controllers/Manager.php:1981-2078,source-refs/sanmopia-admin/application/models/Manager_model.php:116-238,source-refs/sanmopia-admin/application/models/Manager_model.php:1530-2295,source-refs/sanmopia-manager/application/controllers/User.php:242-940, andsource-refs/sanmopia-manager/application/models/User_model.php:120-1005. Required proof: profile/sign assets, bank accounts, career, education, health, denied days, address coordinates, FCM token, password rotation, admin admission state, public-comment moderation, and self-service delete flows are versioned dossier/security events with Storage audit. Backend domain/application foundation exists for versioned caregiver credential/profile dossier, evidence kinds, profile/security revisions, expected_revision verification decisions, storage-object-bound attachment grants, sensitive correction audit by fingerprint/reference, idempotency, and contiguous dossier revisions. Remaining proof: Supabase persistence/storage policies, APIs/contracts generation, caregiver/admin UI, media upload replacement flow, branch/HQ approval workflows, and audit export. -
Caregiver matching optimizer and scorecard projection. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/models/Matching_model.php:752-862source-refs/sanmopia-admin/application/models/Reservation_manager_trans_info_model.php:13-87,source-refs/sanmopia-admin/application/controllers/Reservation.php:538-577,source-refs/sanmopia-admin/application/models/Reservation_model.php:2166-2303,source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:586-629, andsource-refs/sanmopia-admin/application/controllers/ajax/ManagerEvaluation.php:146-228. Backend optimizer foundation now addsCaregiverCandidateSnapshotandMatchingOptimizationInputdomain/application contracts with score components, distance, transport duration/provider evidence, pet exclusion, schedule conflict, branch scope, grade snapshot reference, tie-breaker seed, explicit ranking policy version/revision, and precomputed decision ranks so UI does not recompute candidate ranking. Profile-side preference signal export is namedMatchingProfileCompatibilityInput, separating caregiver profile compatibility facts from reservation-level optimizer inputs. Candidate evidence now persists throughsanmopia_caregiver_candidate_snapshotsandSupabaseCaregiverCandidateSnapshotRepository, including provider result snapshot and fallback reason so ODSAY/cache/fallback behavior is auditable instead of rebuilt by the modal. Assignment optimizer input proof now addsCaregiverAssignmentDemandSlot,CaregiverAssignmentOptimizerInput, and Pydantic contracts undercaregiver_assignment/features/assignment_optimizer_inputs: cached travel time freshness, fairness/rotation workload, replacement continuity, assistant slot handoff order, same-caregiver cross-slot exclusion, branch scope, and backend-owned score components are prepared before solver execution, so controller/UI code no longer owns score zeroing, travel freshness, or assistant-slot arithmetic. Scorecard proof now addsCaregiverPerformanceScorecardcap rows underbackend-repo/src/sanmopia_modernization/domain/caregiver_performance_recognition/features/caregiver_scorecard/with original score, capped score, before/after totals, cap policy, and grade snapshot links. Ubiquitous naming now reservesCaregiverPerformanceScorecardfor those capped score rows, whileCaregiverPerformanceSeasonScorecardnames published season snapshots andCareDeliveryPerformanceScorecardnames care-delivery earned points used by grade recalculation. Remaining proof: Supabase persistence/API, OR-Tools adapter ingestion of prepared inputs, server-owned slot-count/class eligibility, primary/assistant duplicate prevention across all slots, generated clients, and operator planning UI expose optimizer snapshots and scorecard history. -
Branch office profile and coverage policy commands. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:399-452,source-refs/sanmopia-admin/application/views/office_management/office_detail.php:198-217,source-refs/sanmopia-admin/application/views/office_management/office_detail.php:222-430,source-refs/sanmopia-admin/static/js/office_management/office_detail.js:167-246,source-refs/sanmopia-admin/static/js/office_management/office_detail.js:253-276, andsource-refs/sanmopia-admin/application/models/Branch_model.php:345-425. Required proof:BranchOfficeProfileCommandsplits profile, lifecycle, membership-fee, account, and credential changes into revisioned commands;BranchServiceAreaPolicyandServiceCoverageDecisionown address-depth normalization, available/consultation/unavailable priority, branch/HQ authorization, supersession, and reservation impact audit. Backend profile command/read-model foundation now exists inbackend-repo/src/sanmopia_modernization/domain/branch_operations/features/office_profile/andbackend-repo/src/sanmopia_modernization/application/branch_operations/features/office_profile/. Supabase runtime persistence now lives inbackend-repo/src/sanmopia_modernization/adapters/branch_operations/features/office_profile/and stores profile state, revisions, purpose-scoped settlement accounts, membership-fee policy versions, and credential rotations in service-role tables. 2026-07-04 update: service-area policy commands are now exposed throughbackend-repo/src/sanmopia_modernization/interfaces/branch_service_area_policy_api.pyandbackend-repo/src/sanmopia_modernization/interfaces/branch_service_area_policy_http.pywith contract pathsbranchServiceAreaPolicyRevisionsPath()andbranchServiceAreaPolicyDecisionsPath(). Generated Supabase types cover the backing tables. Snapshot write API now exists asPOST /branch-settlement-account-statement-snapshots; backend derives the actor from Supabase Auth, checks SpiceDBsettle, and writes idempotent statement-account snapshots with explicitsettlement_statement_id. Public contract follow-up now adds the OpenAPI path, request/response JSON schemas, and TS endpoint/header helpers for the snapshot API. Profile-edit follow-up now addsPOST /branch-office-profile-updateswith Supabase Auth actor derivation, SpiceDBmanage, expected-revision conflict handling, and OpenAPI/TS helpers. Lifecycle follow-up now addsPOST /branch-office-lifecycle-changeswith the same actor/permission/revision guard and ubiquitous lifecycle states instead of source delete flags. Settlement-account replacement follow-up now addsPOST /branch-settlement-account-replacementswith masked-only account facts, purpose-scoped replacement, Supabase Auth actor derivation, SpiceDBmanage, expected-revision conflict handling, and OpenAPI/TS helpers. Remaining gaps: broader authorization policy coverage, UI stale-save recovery, field-level conflict diffs, and full coverage-policy runtime binding. UI must not decide coverage, overwrite stale profile facts, or route by reload/history state. -
Regional benefit policy for reservation quote and service calendar. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/views/reservation_status/reservation_add.php:273,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1519,source-refs/sanmopia_web/application/controllers/api/Service.php:346,source-refs/sanmopia_web/application/models/Reservation_model.php:2526,source-refs/sanmopia-admin/application/controllers/Reservation.php:1749,source-refs/sanmopia_web/application/models/Reservation_model.php:1181, andsource-refs/sanmopia-admin/application/models/Payment_model.php:436. Required proof:RegionalBenefitPolicystores effective-dated criteria for region, branch, service kind, benefit kind, amount/day effect, approval, and calculation version. Reservation quote, service-calendar plan, payment conversion, and settlement read one frozenRegionalBenefitDecisioninstead of checking region names, source flags, or option-name substrings. Backend profile metadata now storesregional_benefit_profile_key,service_day_bonus_count, andsettlement_participation_codeonRegionalBenefitRule.FinalizeReservationChargeWithRegionalBenefitHandlernow resolves the regional entitlement once, buildsReservationPriceSummaryInput, and freezes the decision facts into the charge snapshot. Remaining proof: runtime reservation entrypoints and downstream service-calendar impact, payment conversion, and settlement participation must consume that same decision/snapshot path. -
Report/service/attendance notify obligations. Status:
Partial. Evidence:source-refs/sanmopia-manager/application/controllers/Report.php:1-106,source-refs/sanmopia-manager/application/models/Report_model.php:11-100,source-refs/sanmopia-manager/application/controllers/Service.php:1-254,source-refs/sanmopia-manager/application/models/Service_model.php:10-135,source-refs/sanmopia-manager/application/controllers/Attendance.php:1-80, andsource-refs/sanmopia-manager/application/models/Notify_model.php:70-448. Required proof:CareDeliveryObligationdrives first/progress/last reports, service records, main/sub caregiver role, duplicate submission guard, newborn bootstrap, symptom attestations, attendance check-in, FCM delivery, and mother-visible notification audit. Backend domain/application foundation exists for versioned effective-dated rule catalogs, service-date distinctions, primary/assistant caregiver obligations, duplicate submission/attendance suppression, scheduled/manual idempotency scopes, dispatch decision/suppression facts, notification work-queue repair actions, andCaregiverServiceRecordSubmissionwith role/handoff identity, service-date access window, duplicate replay, correction revision, sequential writable action, route date, and explicit attendance outbox key.DailyCareReportServiceDateLockPayloadnow locks caregiver-authored daily reports to the frozen reservation, caregiver, service date, sequence, handoff order, service-calendar plan id, policy fingerprint, and impact fact ids before form validation, so manager/client submissions cannot silently drift from inline PHP date math.DailyCareReportServiceSuspensionWindowPayloadnow blocks caregiver report submissions inside a service suspension interval while preserving the stop day as the final report day. Remaining proof: Supabase persistence/API, provider adapter, Supabase realtime/audit, newborn bootstrap facts, mother-visible notification history, printable document snapshots, and runtime worker. -
Analytics/admin report catalog. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/models/Statistics_model.php:10-163,source-refs/sanmopia-admin/application/models/Statistics_model.php:238-360,source-refs/sanmopia-admin/application/models/Statistics_model.php:760-1216, andsource-refs/sanmopia-admin/application/models/Statistics_model.php:1971-2137. Required proof:AdminAnalyticsCatalognames each performance/sales/user connect/evaluation/branch-connect report, filters, metric definitions, branch visibility, source facts, export columns, query version, frozen totals, artifact handoff, and operator audit. Backend domain/application foundation exists for versioned scoped report definitions, metric/filter definitions, immutable snapshot/export request, source-fact key validation that rejects table-name shaped facts, audit event code, and artifact handoff policy. Remaining proof: persistence/API, query execution adapters, Supabase policies, frontend operator report table, scheduled refresh/runtime worker, and export artifact storage grants. -
Customer identity/profile/security and external shop link. Status:
Partial. Evidence:source-refs/sanmopia_web/application/controllers/api/Account.php:31-327,source-refs/sanmopia_web/application/controllers/Mall.php:12-285,source-refs/sanmopia_web/application/models/User_model.php:22-394, andsource-refs/sanmopia_web/application/models/User_model.php:557-621. Required proof:CustomerIdentityProfile,CustomerAccountSecurityEvent, andExternalCommerceMemberLinkseparate Supabase Auth/profile facts, marketing consent evidence, social profile-completion state, FCM token lifecycle, password reset/rotation, gift-coupon claim request, external commerce referral validation, and rollback/repair. Signup/profile edit must not hide coupon registration side effects; mall delete must not hard-delete profile data outside privacy lifecycle. -
Customer reservation intake draft and care-plan invalidation. Status:
Partial. Evidence:source-refs/sanmopia_web/application/controllers/api/Service.php:12-278,source-refs/sanmopia_web/application/controllers/api/Service.php:280-576, andsource-refs/sanmopia_web/application/controllers/api/Service.php:592-868. Required proof:CustomerReservationIntakeDraft,ReservationServiceAreaDecision, andReservationCarePlanDraftreplace sourcePROCESS_NO, branch-address lookup, second-address consultation, service-type row deletes, price-version mutation, Wanju benefit, extra Saturday/holiday work, rental selection, smart-matching deletion, named caregiver grade uplift, and continuation caregiver carryover with revisioned commands, invalidation facts, and Restate workflow state. -
Customer reservation intents, notification routing, payment instruction, and document grant. Status:
Partial. Evidence:source-refs/sanmopia_web/application/controllers/api/Reservation.php:14-451,source-refs/sanmopia_web/application/controllers/api/Payment.php:66-754, andsource-refs/sanmopia_web/application/models/User_model.php:462-491. Required proof:CustomerReservationIntent,BranchNotificationRoutingPolicy,CustomerPaymentInstruction, andCustomerDocumentDownloadGrantcover birth/service-start/delivery correction, change/cancel/stop/extension, regional extra branch recipients, deposit, balance, coupon, pre-reservation, change-payment, virtual-account messages, payment-purpose delivery audit, and two-hour document-token replacement with signed Supabase Storage handoff. -
Admin/customer payment conversion projection. Status:
Implemented. Evidence:source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:68-174. Required proof:ReservationPaymentConversionProjectionfreezes converted status, original payment purpose, coupon discount, customer-share amount, deposited-at fact, and allowed follow-up command. UI/controller code must not traversePRICE_TABLE,PAYMENT_INFO, or gateway context maps to decide rows or amounts. Implementation note: backend domain/application contract slices were added atbackend-repo/src/sanmopia_modernization/{domain,application}/pricing_settlement/features/payment_conversion/with colocated tests. Persistence/API wiring remains open. -
Customer self-service workspace and action availability. Status:
Partial. Evidence:source-refs/sanmopia_web/application/controllers/MyReservation.php:22-398,source-refs/sanmopia_web/application/views/mypage/item/reservation_func_btn.php:1-190,source-refs/sanmopia_web/application/views/mypage/item/reservation_detail_report_item.php:1-155,source-refs/sanmopia_web/application/controllers/api/Report.php:11-116,source-refs/sanmopia_web/application/views/mypage/reservation_document.php:38-139,source-refs/sanmopia_web/application/controllers/api/ReservationDocument.php:9-48,source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:35-130,source-refs/sanmopia_web/application/models/Notification_model.php:16-68,source-refs/sanmopia_web/application/views/notification.php:36-140, andsource-refs/sanmopia_web/application/views/open_the_app.php:1-20. Required proof:CustomerSelfServiceWorkspace,CustomerActionAvailabilityPolicy,CustomerReservationTimelineSnapshot,CustomerReportSubmissionWindow,CustomerNotificationActionGrant,CustomerReceiptAccessGrant, andCustomerAppLaunchIntentreplace hardcoded tab/status/button/page routing with versioned policy, immutable customer-visible snapshots, signed grant handoffs, typed notification action targets, app-launch configuration, Restate state updates, Supabase RLS, and tests. Frontend must render policy output only through Nanostores-backed state; it must not recreate PHP status switches. Backend domain/application now has explicit injectedCustomerActionPolicyRuleCatalogevaluation, versioned action decisions, disabled reasons, command targets, actor relation, audit category, idempotency scope, customer presentation metadata, andCustomerReservationStateMappingCatalogprojection from versionedsource_status_codeinto current customer lifecycle stage,customer_list_bucket, shareddetail_surface_kind, source compatibility flags, andblocks_new_reservation.CustomerNewReservationEligibilityPolicycomposes those projected facts across existing reservations so only8 취소요청,14 입금대기, and16 사전예약대기block a new reservation, while history17 입금대기취소and replaceable draft-1do not. Pre-reservation detail selection is also backend projection: status15/16render pre-reservation detail; status9/17/19render it only when source pre-reservation flags say the reservation was not converted. Source status additions, old reservation compatibility, active/history tab placement, detail surface selection, and new-reservation blocking must be catalog changes, not frontend switches or new source-code branches. Runtime progress now persists customer source-state snapshots plus versioned state-mapping/action-policy catalogs in Supabase tablessanmopia_customer_reservation_action_source_states,sanmopia_customer_reservation_state_mapping_catalogs, andsanmopia_customer_action_policy_rule_catalogs, with RLS protecting customer source states by owning Supabase user. Backend exposes authenticatedGET /customer-reservation-action-availabilities/{reservation_id}andGET /customer-new-reservation-eligibility, so portal code no longer needs to inspect raw source status numbers for button availability or new-booking blocking. Remaining proof: signed document/receipt grants, notification action grants, Restate projection binding, and full UI wiring. Frontend now has a Nanostorescustomer-self-service-action-availabilitystate foundation that consumes policy output, preserves loading/ready/stale/error state, and does not infer actions from reservation status ids. -
Partner benefit application, delivery, cancellation, and result artifacts. Status:
Partial. Evidence:source-refs/sanmopia_web/application/controllers/api/Clean.php:9-128,source-refs/sanmopia_web/application/models/Clean_model.php:50-185,source-refs/sanmopia_web/application/controllers/api/Momfirst.php:10-137,source-refs/sanmopia_web/application/models/Momfirst_model.php:39-230,source-refs/sanmopia_web/application/models/Momfirst_model.php:360-550,source-refs/sanmopia_web/application/models/Momfirst_model.php:827-895,source-refs/sanmopia_web/application/controllers/cli/Momfirst.php:21-170,source-refs/sanmopia_web/application/controllers/Momfirst.php:87-146, andsource-refs/sanmopia_web/application/controllers/Clean.php:67-126. Required proof:PartnerBenefitCatalog,PartnerBenefitApplication,PartnerBenefitEligibilityDecision,PartnerDeliveryBatch,PartnerDeliverySuppressionReason,PartnerBenefitCancellationLock, andPartnerResultArtifactGrantreplace hardcoded product codes, user exceptions, regional exclusions, weekday send rules, direct provider email addresses, temporary CSV files, soft-delete cancellation, and admin-root result downloads with versioned policies, provider contact configuration, durable delivery batches, retry/audit state, Supabase Storage grants, and customer-safe disabled reasons. Backend domain/application now has configurable provider/product policies, versioned eligibility, branch/region/audience conditions, duplicate checks, delivery artifact state, suppression reasons, cancellation locks, result artifact grants, idempotency, and audit. Remaining proof: Supabase persistence, durable worker, provider handoff adapter, storage grants, public/internal APIs, and operator/customer UI. -
Campaign/event publication, placement, and content-template lifecycle. Status:
Partial. Evidence:source-refs/sanmopia_web/application/controllers/Event.php:14-179,source-refs/sanmopia_web/application/controllers/Event.php:186-227,source-refs/sanmopia_web/application/controllers/Event.php:241-258,source-refs/sanmopia_web/application/views/event/index.php:19-117,source-refs/sanmopia_web/application/views/event/index.php:118-416,source-refs/sanmopia_web/application/views/event/index.php:419-470,source-refs/sanmopia_web/application/views/event/detail/20240710_reviewevent.php:37-60,source-refs/sanmopia_web/application/views/event/detail/20240501_quiz.php:37-42,source-refs/sanmopia_web/application/views/event/delivery_event.php:40-48,source-refs/sanmopia_web/application/views/event/benefit.php:40-67,source-refs/sanmopia_web/application/views/event/addition_service.php:38-97, andsource-refs/sanmopia_web/static/js/momfirst_rumor_event.js:1-15. Required proof:CampaignPublication,CampaignContentTemplate,CampaignPublicationVersion,CampaignPlacement, andCampaignAudiencePolicyreplace controller slug switches, hardcoded banner arrays, date-window code, static image/video paths, partner/sponsor pages, delivery-event pages, and benefit pages with versioned, previewable, rollback-capable campaign content. Do not port one-off event pages 1:1. Campaign body, CTA, media, result links, deprecated/suppressed state, app-webview open behavior, moderation state, SEO/discovery metadata, and audience rules must be authored through an OSS headless CMS-compatible schema such as Directus/Strapi/Keystone/Payload class tooling, with managed storage artifact references rather than hardcoded/static/image/event/**assets. Backend foundation now covers publication/content template/version/placement and audience policy abstractions, provider-neutral media artifact validation, moderation and effective windows, and source mapping as application-boundary configuration. Remaining proof: CMS persistence, public/internal APIs, frontend/runtime preview, and storage grants. -
Campaign participation, review rewards, result publication, and fulfillment handoff. Status:
Partial. Evidence:source-refs/sanmopia_web/application/views/event/review_260601.php:4-76,source-refs/sanmopia_web/application/views/event/review_251103.php:4-80,source-refs/sanmopia_web/application/views/event/review_251103_result.php:4-76,source-refs/sanmopia_web/application/views/event/review_250701_result.php:4-84,source-refs/sanmopia_web/application/views/event/winner_event.php:38-59,source-refs/sanmopia_web/application/views/event/review_winner.php:38-55,source-refs/sanmopia-admin/application/controllers/Promotion.php:270-280,source-refs/sanmopia-admin/application/controllers/Promotion.php:486-517,source-refs/sanmopia-admin/application/models/Promotion_model.php:18-55, andsource-refs/sanmopia-admin/application/models/Coupon_model.php:888-932. Required proof:CampaignParticipation,ReviewRewardCampaign,CampaignResultPublication,CampaignFulfillmentBatch,CampaignNotificationPolicy, andCampaignExportArtifactreplace external Naver-form submission links, hardcoded review-period redirects, manual winner pages, static result images, coupon publish toggles, gift shipment field edits, Momfirst result upload notifications, and raw sponsor/result buttons with durable campaign lifecycle state. Participation intake must capture source, identity, consent, eligibility, duplicate checks, review-proof moderation, award selection, result-publication version, notification dispatch audit, export batch state, fulfillment/repair state, and customer-visible status without tying reward issuance to a static PHP page. Backend foundation now covers participation intake, review reward selection, result publication, fulfillment batch state, notification policy, and export artifact handoff. Remaining proof: persistence, public/internal APIs, CMS authoring/runtime handoff, and durable fulfillment/notification workers. -
Board and knowledge content publication workflow, audience policy, and category taxonomy. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/Board.php:18-79,source-refs/sanmopia-admin/application/controllers/ajax/CommonBoard.php:18-87,source-refs/sanmopia-admin/application/models/Board_model.php:13-69,source-refs/sanmopia-admin/application/models/Board_category_model.php:10-16,source-refs/sanmopia_web/application/controllers/Board.php:12-40,source-refs/sanmopia_web/application/models/Board_model.php:10-39,source-refs/sanmopia_web/application/models/Board_category_model.php:9-14,source-refs/sanmopia-manager/application/controllers/Other.php:448-510, andsource-refs/sanmopia-manager/application/models/Board_model.php:12-37. Required proof:ContentPublication,ContentPublicationWorkflow,ContentCategoryTaxonomy,ContentAudiencePolicy,ContentPublicationVersion,ContentDiscoveryState, andContentViewMetriccover admin-authored title/body/category, category-name public navigation, caregiver newsletter audience, customer view counts, draft/review/publish/archive states, versioned publication, durable search/filter/pagination state, and revision audit. Source slice has no password/private/reply/comment fields; modern moderation must be explicitContentModerationState, and FAQ/QnA flows stay pending for a dedicatedCustomerInquiryThreadsource pass. -
Notice publication, pinned ordering, and branch/caregiver audience dispatch. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:454-590,source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:789-922,source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:934-1066,source-refs/sanmopia-admin/application/models/Office_management_model.php:155-240,source-refs/sanmopia-admin/application/models/Office_management_model.php:342-452,source-refs/sanmopia-admin/application/models/Office_management_model.php:476-531,source-refs/sanmopia_web/application/controllers/Notice.php:11-52,source-refs/sanmopia_web/application/models/Notice_model.php:9-27,source-refs/sanmopia-manager/application/controllers/Other.php:96-197,source-refs/sanmopia-manager/application/controllers/Other.php:418-445,source-refs/sanmopia-manager/application/controllers/Home.php:8-24, andsource-refs/sanmopia-manager/application/models/Notice_model.php:12-120. Required proof:NoticePublication,NoticeAudiencePolicy,CaregiverNoticeDispatch,BranchManagerNoticeChannel,PinnedContentOrdering, andContentPublicationVersionseparate customer notice, branch notice, caregiver HQ notice, caregiver event notice, caregiver education/news, HQ/admin authoring, and branch-manager visibility. Pinning must be policy-backed ordering rather than rawFIXprecedence. Branch-specific and global visibility must become auditable audience rules, with stable filters, pagination cursors, publication windows, rollback, and moderation state. -
Content attachment storage, media rendering, retention, and notification audit. Status:
Partial foundation. Evidence:source-refs/sanmopia-admin/application/views/board/common_board_write.php:42-68,source-refs/sanmopia-admin/application/views/board/common_board_write.php:83-99,source-refs/sanmopia-admin/application/views/office_management/manager_notice_write.php:45-80,source-refs/sanmopia-admin/application/views/office_management/manager_notice_write.php:103-118,source-refs/sanmopia-admin/application/models/Office_management_model.php:70-118,source-refs/sanmopia_web/application/views/notice.php:68-79,source-refs/sanmopia_web/application/views/notice_view.php:78-89,source-refs/sanmopia_web/application/views/notice_image_enlargement.php:26-33,source-refs/sanmopia-manager/application/views/notice_view.php:42-67,source-refs/sanmopia-manager/application/views/event_notice_view.php:43-68,source-refs/sanmopia-admin/application/models/Board_model.php:65-69,source-refs/sanmopia-admin/application/models/Office_management_model.php:235-238,source-refs/sanmopia-admin/application/models/Office_management_model.php:437-450,source-refs/sanmopia-admin/application/models/Office_management_model.php:527-530,source-refs/sanmopia-admin/application/controllers/ajax/CommonBoard.php:49-74,source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:543-568,source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:1023-1050,source-refs/sanmopia-admin/application/config/constants.php:260-280, andsource-refs/sanmopia-manager/application/controllers/cli/Fcm.php:119-169. Required proof:ContentAttachmentAsset,ContentMediaRendition,ContentStorageProvider,ContentMediaAccessGrant,ContentRetentionPolicy,ContentDeletionRequest,ContentAuditEntry,ContentNotificationPolicy, andContentNotificationDeliveryturn Summernote images/video, notice image upload paths, public image enlargement, cross-application media duplication, soft board deletion, hard notice deletion, insert-only push triggers, and disabled newsletter push into a Storage-backed, versioned, observable workflow. Deletes require retention decisions and actor/reason audit. Notification side effects require delivery idempotency, branch/caregiver recipient snapshots, retry state, and operator repair history. Partial foundation:backend-repo/src/sanmopia_modernization/domain/content_management/features/content_attachment_lifecycle/content_attachment_lifecycle.pyandbackend-repo/src/sanmopia_modernization/application/content_management/features/content_attachment_lifecycle/content_attachment_lifecycle_contract.pymodel abstract private storage references, explicit rendition specs, expiring scoped access grants, retention-gated deletion audit with caller-supplied audit refs, and idempotent notification delivery retry/repair state. Remaining proof: persistence, API/CMS integration, runtime workflow wiring, storage adapter, and live storage evidence.
Mother And Public Web
Section titled “Mother And Public Web”- Public service marketing and guide pages. Status:
Pending. Evidence:sanmopia_web/application/controllers/About.php,sanmopia-user-old/src/pages/about/*,sanmopia-user-old/src/pages/menu/*. - Account signup, login, social login, password/email recovery, profile edit,
push flag edit, withdrawal. Status:
Partial. Evidence:sanmopia_web/application/controllers/api/Account.php,sanmopia_web/application/controllers/Login.php,sanmopia_web/application/controllers/Withdraw.php:18-83,sanmopia_web/application/controllers/Mall.php,sanmopia-user-old/src/pages/login/index.astro,sanmopia-user-old/src/pages/join/index.astro,sanmopia-user-old/src/pages/find/*,sanmopia_web/application/views/withdraw.php:10-55,sanmopia-user-old/src/pages/withdraw/index.astro. Modern replacement:member_privacy_lifecyclemaps source withdrawal to credential-confirmed withdrawal, auth-token invalidation, push-token revocation, profile masking, voucher resident-number redaction, retained-record snapshots, and delayed purge. Source masking strings stay adapter/evidence only; modern ubiquitous names areMemberWithdrawalRequest,RetainedRecordSnapshot,MemberProfileMasking, andMemberPrivacyPurgeTask. Kanboard evidence: #2253, #2776, #2768, #2763, #2758, #2752, #2746, #2742. Receipt/status query foundation now exposes a customer-safe withdrawal projection without purge task ids, retained snapshot payloads, or operator audit details. Operator repair-history backend foundation now covers privacy workflow repair requests and append-only repair events for masking, token revocation, retained snapshot, delayed purge, and storage cleanup failures without exposing raw personal data. Remaining work: frontend receipt/status UX, frontend/operator repair controls, runtime worker binding, and Supabase persistence. - Reservation application wizard, survey steps, childbirth information, service
type selection, smart matching, manager selection, agreement, pre-reservation.
Status:
Partial. Evidence:sanmopia_web/application/controllers/Service.php,sanmopia_web/application/controllers/Survey.php,sanmopia_web/application/controllers/api/Service.php,sanmopia_web/application/controllers/api/Reservation.php,sanmopia-user-old/src/pages/service/start.astro,sanmopia-user-old/src/pages/mypage/pre-reservation/[id].astro. Modern replacement: care service catalog now has a Supabase-backed read model for service kind, care option, eligibility, and display metadata used by reservation intake. This replaces source-era view/controller constants as the read side for branch and customer booking flows. Remaining gap: wire every wizard step to the catalog contract, preserve legacy service-detail eligibility text, and keep pricing handoff separate from care service selection. - Reservation lifecycle view: proceeding, completed, detail, change payment,
delivery data, expected end date, Saturday/holiday calculation. Status:
Partial. Evidence:sanmopia_web/application/controllers/MyReservation.php,sanmopia_web/application/controllers/MyReservation.php:21-69,sanmopia_web/application/controllers/MyReservation.php:72-113,sanmopia_web/application/controllers/MyReservation.php:116-190,sanmopia_web/application/controllers/Reservation.php,sanmopia_web/application/controllers/api/Reservation.php,sanmopia_web/application/controllers/api/Reservation.php:86-239,sanmopia_web/application/controllers/api/Reservation.php:243-289,sanmopia_web/application/models/Reservation_model.php:990-1111,sanmopia_web/application/models/Reservation_model.php:2052-2145,sanmopia-user-old/src/pages/mypage/reservation/*,sanmopia-user-old/src/pages/mypage/reservation-change-payment.astro. Modern replacement:reservation_operations/features/service_calendarnow owns versioned service period planning, national/branch holiday policy, selected extra Saturday or holiday service days, and immutable service-calendar plan snapshots. The service-calendar policy now also records holiday source kind, holiday effect, reason code, source reference/fingerprint, announcement date, superseded holiday code, and pricing/settlement impact flags, so sudden substitute holidays, emergency closures, branch-only closure days, and paid service days do not collapse into one globalHOLIDAY_TBdate row. OSS Korean public holidays are generated throughholidays, while operator and branch overrides remain explicit audited facts. Plan payloads now carrypolicyVersionLabelandpolicyFingerprint; reservation, pricing, and settlement projections must consume the captured plan result instead of recalculating from current holiday rows. Supabase migration20260703220000_service_calendar_policy_snapshots.sqladds source/effect metadata tosanmopia_service_calendar_holidaysandpolicy_fingerprinttosanmopia_reservation_service_calendar_plans. Calendar impact facts now also includecustomer_benefit_entitlement_review_required, so selected extra Saturday/holiday service days can trigger coupon/compensation review through downstream promotion/benefit consumers instead of frontend arithmetic. The service-period application contract now exposesPlanServicePeriodPayload,ServicePeriodTemplatePayload, duration, calendar-policy, and profile payloads, with matching public TSservice-periodcontracts andplan_service_period_requestschema. One-week, two-week, extension, branch-closure, and regional-duration adjustments are profile-backed facts with evidence keys instead of frontend일주/이주/연장branches or hidden service-day arithmetic. The contract also alignscustomer_benefit_entitlement_review_requiredwith the backend service-calendar impact enum so customer coupons/benefits can follow selected extra Saturday/holiday facts. The replacement keeps warnings for missing extra-day selections instead of silently trusting selected counts, and stores the captured plan so later calendar or pricing policy changes do not alter already shown reservation dates. Public reservation reads now use a separateCustomerReservationLifecycleSnapshot: show customer-actionable states such asReservationChangeRequested,ReservationCancellationRequested,ReservationExtensionRequested,ReservationExtended, andReservationStopRequested, but keep operator-only settlement board flags, internal workflow retries, payment gateway context, and compensation ledger ids out of the mother-facing projection. Customer extension is a new reservation draft linked throughReservationExtensionLink; it must block a second extension once the linked draft has moved past draft. Backend/contract progress:CustomerReservationLifecycleSnapshotnow provides customer-safeactive_journeyandservice_historybuckets, card/detail payloads, caller-supplied projection and dataset revisions, timezone-aware evaluation timestamps, composedcustomer_action_availabilitypolicy decisions for source button behavior, service-period facts, computed payable prompts with pricing projection ids/revisions, virtual account summaries without gateway context, document/receipt readiness facts without tokens or storage references, open document bundle and receipt view action intents, change-payment action/readiness, computed report-window counts/status, report presentation visibility and needed report dates, main/sub caregiver report route intents, extra Saturday/holiday selections and computed summaries, card display facts for baby count and service-week labels, caregiver card visibility and already-masked caregiver display names, birth-information prompt state, customer notice facts, pre-reservation conversion, rebooking after payment-attempt cancellation, cancellation availability for booking/consulting/schedule confirmed/pre-reservation stages, reservation-change and stop-request action intents, customer-safe detail surface kind for pre-reservation vs standard detail, and extension draft blocking when a linked draft moved past draft. Customer action contracts can now accept a versioned source reservation state and project it throughCustomerReservationStateMappingCatalog; status additions, renamed source status ids, active/history tab bucket, new-reservation blocking, and legacy reservation compatibility are handled by mapping-catalog version/effective dates before action policy runs. The lifecycle item contract requires callers to supply explicit card display, caregiver display, birth-information, change-payment, extension-link, and detail-surface facts; these are not hidden defaults on the base model. Source UI arithmetic and UI branching remain untrusted: frontend must render the projection only and must not sum payment rows, derive report/document state, or branch on source status ids. Source customer pages decide report visibility, unpaid report dates, deposit/balance/service-balance/change-payment buttons, virtual-account prompts, pre-reservation detail surface, manager-card visibility, manager-name masking after service end, and Saturday/holiday summaries inside PHP views:source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:42-139,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:197-239,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:265-330,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:421-475,source-refs/sanmopia_web/application/views/mypage/item/reservation_detail_func_btn.php:1-210,source-refs/sanmopia_web/application/views/mypage/item/reservation_func_btn.php:1-170,source-refs/sanmopia_web/application/views/mypage/pre_reservation_detail.php:41-91, andsource-refs/sanmopia_web/application/views/mypage/reservation.php:64-90,source-refs/sanmopia_web/application/views/mypage/reservation.php:125-155,source-refs/sanmopia_web/application/views/mypage/reservation.php:170-250. These become backendCustomerReservationLifecycleSnapshotfacts and action readiness entries, not frontend if-statements overSTATUS_ID,PAYMENT_INFO, or raw additional-service labels. Pricing display arithmetic fromsource-refs/sanmopia_web/application/views/reservation/retc.php:4-191and customer fee-table arithmetic fromsource-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:1-180now belongs topricing_settlementcustomer charge/payment projections: service price, regional/government support, coupon/gift credit, rental/add-on charges, additional-service effective-day extensions, reservation-level regional add-ons, rental equipment rental/delivery max-once charges, pre-reservation deduction, customer deposit, service balance, payable-now state, paid/refund-pending state, virtual-account prompt, and pricing/projection/source revisions are emitted by backend read models. Backend component-policy decision: duplicated additional-service and rental equipment arithmetic fromsource-refs/sanmopia-admin/application/models/Service_model.php:188-269,source-refs/sanmopia_web/application/models/Reservation_model.php:1120-1162,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:644-709, andsource-refs/sanmopia_web/application/models/Reservation_model.php:1231-1256is now owned bypricing_settlementpolicy components. UI and document renderers consume computed component lines; they do not repeat day-extension, reservation-level add-on, or rental delivery aggregation formulas. Lifecycle view may only link to computed pricing projections and expose final prompt/readiness facts, never rawPRICE_TABLEor payment maps. Remaining work: persist/feed the read model from Supabase queries, wire API routes and generated public contracts, connect document grants/readiness to document delivery, integrate payment prompt facts with the financial lifecycle read side, and build the customer frontend after the backend contract is stable. - Payment lifecycle: KCP approval callback, deposit, balance, coupon payment,
changed payment, virtual account cancel/end notices. Status:
Partial. Evidence:sanmopia_web/application/controllers/api/Payment.php,sanmopia_web/application/controllers/api/Kcp.php,sanmopia_web/application/controllers/api/Payment.php:700-735,sanmopia_web/application/models/Payment_model.php:856-900,sanmopia-admin/application/controllers/Reservation.php:1857-1864,sanmopia-admin/application/controllers/ajax/Reservation.php:68-120,sanmopia-admin/application/models/Payment_model.php:4422-4521,source-refs/sanmopia-admin/application/models/Reservation_model.php:776-889,source-refs/sanmopia-admin/application/views/reservation_status/reservation_price_table.php:33-91,source-refs/sanmopia-admin/application/models/Payment_model.php:3086-3210,source-refs/sanmopia-admin/application/models/Payment_model.php:3990-4042,sanmopia_web/application/controllers/cli/Reservation.php,sanmopia-admin/application/controllers/cli/Kcp.php. Modern replacement: Mother-visible payable amounts now come from immutable finalized charge snapshots and the financial lifecycle API instead of recalculating current pricing after payment close. The backend now has a Kill Bill REST HTTP adapter for paid-payment verification, cancel, and refund, andReservationPaymentWorkflowis registered on the Restate deployment so Kill Bill billing operations can use durable retry/idempotency. Public payment workflow start/progress APIs now usePOST /reservation-payment-workflow-startsandGET /reservation-payment-workflow-requests/{paymentWorkflowRequestId}, with service-role-only Supabase ledger rows insanmopia_reservation_payment_workflow_requests. Kill Bill payment event callback acceptance now usesPOST /killbill-payment-eventsto verify the provider signature and enqueuesanmopia_payment_webhook_processingthrough Supabase Queues; the backend worker validates the queue payload, recordssanmopia_killbill_payment_events, and startsReservationPaymentWorkflowfor paid-payment verification. Cancelled, partially cancelled, failed, and virtual-account-issued webhooks now synchronize the local payment record status without re-requesting a gateway cancel/refund. Successful paid-payment verification now hands off to approved payment charge finalization, validates the approved amount against the immutable finalized charge snapshot, records the handoff status onsanmopia_reservation_payment_workflow_requests, and keeps later financial lifecycle stages from regressing. Virtual-account deposit closeout is now identified on paid webhooks throughpaymentCloseoutKind = virtual_account_deposit, while card/bank paid webhooks useinstant_payment. Payment closeout context now freezespayment_closeout_kind,reservation_booking_id, andreservation_status_at_closeouton the workflow command, Restate payload, HTTP start/progress contracts, generated Supabase type, andsanmopia_reservation_payment_workflow_requests, so later reservation state transition decisions can replay the same closeout basis instead of inferring it from mutable UI rows. Approved payment closeout now requests automatic settlement continuation and records the continuation status/workflow id on the payment workflow ledger. Kill Bill payment amount pre-registration now usesPOST /reservation-payment-pre-registrationsbefore the frontend opens the payment UI, freezespaymentId, reservation booking id, payment method, payment purpose, and amount insanmopia_payment_records, and rejects reuse after the record has moved past waiting or when method, purpose, or amount changes. Direct booking writes record the initial customer-share deposit purpose and paid timestamp; Kill Bill verification writesdeposited_atwhen a record becomes approved/completed. Source-import payment rows with missing purpose are normalized at the Supabase adapter boundary as customer-share deposit compatibility facts, while new writes always persist explicit payment purpose. Payment product grouping now has backend and contract foundation:PaymentProductPlanseparates product family, allowed methods, provider route, obligation mapping, virtual-account expiry, refund/conversion policy, and settlement participation before Kill Bill pre-registration. Supabase now stores versioned active/effective catalog rows insanmopia_payment_product_plan_catalog_items; the Pydantic adapter derives the runtime plan book shared by pre-registration validation and the authenticated catalog endpointsGET /payment-product-plansandGET /payment-product-plans/{planCode}. The first catalog families cover customer-share deposit/balance, service-balance receipt, pre-reservation deposit, gift-coupon purchase, and change-payment/correction payment. 2026-07-04 follow-up: pre-registration now returns and persists aPaymentProviderRouteFeeSnapshotwith provider route, settlement participation, ledger recognition timing, fee basis, line targets, frozen customer-visible behavior, and method-fee quote. Catalog v2 now storesPaymentSettlementLineTemplaterows forcustomer_charge_payment, public-voucher fixedvoucher_service_commission15000,service_balance_receivable,pre_reservation_credit,gift_coupon_commissionbands5000/10000/20000/30000, andpayment_change_adjustment. Catalog v3 now storesPaymentProductCommunicationRouterows for virtual-account issuance, payment completion, coupon fulfillment, payment-change completion, mother/payer/coupon-receiver/branch recipients, SMS fallback policy, message purpose, and optional branch-secondary-contact conditions. Payment closeout command resolution now resolves delegated reservation payer recipients from active family payment delegation facts, and catalog v4 adds payer payment-complete workflow routes for customer-share, pre-reservation, and payment-change products. Catalog v5 links customer-share deposit and balance payment plans to the accepted reservation quote componentcare_price_catalog/accepted_reservation_quote/customer_share, so those obligations can be traced back to a frozen price-catalog quote component instead of UI payment-type/display strings. User-backed gift-coupon receiver authority now has a backend snapshot table,sanmopia_payment_coupon_receiver_snapshots, and the Supabase payment communication resolver can produce a separatecoupon_fulfilleddispatch command from that frozen snapshot instead of accepting receiver identity from UI strings. Primary and secondary branch payment notices now resolve from versionedsanmopia_branch_payment_notice_contactsrows keyed by branch, recipient kind, condition code, effective window, and user id; primary branch routes fall back to branch-operator membership only when no policy row exists. Remaining migration: bind virtual-account instruction rendering, communication workflow execution, customer/operator visibility, provider wait-state mutation, and displayed deposit amount to the frozen plan/request instead of controller branches; source hardcodes the pre-reservation virtual-account notice amount inPayment.php:456-463. Gift-coupon purchase is a separate family because successful payment issues/registers a coupon, links the gift-coupon type, notifies the receiver, and later contributes coupon fee lines in settlement; evidence:source-refs/sanmopia_web/application/controllers/api/Payment.php:222-304,source-refs/sanmopia_web/application/models/Payment_model.php:283-324, andsource-refs/sanmopia_web/application/models/Payment_model.php:707-728. Reservation booking and payment workflow/webhook stores now receive explicit clocks from composition/tests instead of owning hidden production timestamp defaults. Settlement continuation source facts now include service delivery, caregiver payout, branch settlement, and HQ settlement ledger lines from Supabase. Source전환결제table/status values map only through adapter names; modern ubiquitous names arePaymentChangeAdjustment,PaymentChangeAwaitingPayment,PaymentChangeProviderContext, andPaymentChangeOperatorCompletion. Customer-facing payment state must expose only payable/paid/refund-pending or receipt/document-ready facts fromCustomerPaymentSummaryandReservationReceiptAccess; gateway payloads, raw approval context, change-payment status codes, internal closeout handoff state, and settlement continuation ids remain service-role or operator projections. Source price tables separately calculate mother-visibleuserFeePrice, contract/balance payment rows, gateway fee estimates, and caregiver net pay, so the modern replacement must keepCustomerChargeSnapshot,SettlementCalculationLine, andCaregiverCompensationQuoteLineas separate read models even when they share the same reservation id. Customer-facing price/payment display projection now absorbsretc.phptotals,reservation_detail.phpandpre_reservation_detail.phppayment prompt/virtual-account/KCP amount decisions,reservation_fee_table.php/reservation_fee_table_old.phpvoucher service-price adjustments, coupon fallback, contract/balance split, service-balance override, and voucher special add-on balance behavior, MyReservation virtual-account selection, coupon-excluded admin reservation-price display, and price-table display categories from typed frozen charge lines plus typed payment records. The backend emits payable-now amount and purpose for customer-share deposit, customer-share balance, service balance, or pre-reservation deposit, so frontend code never chooses amount from rawPRICE_TABLEorPAYMENT_INFO. Caller/UI-observed totals are reconciled as mismatch facts and never accepted as truth. Public payloads expose safe virtual-account fields and optional public receipt refs, but not provider transaction ids, gateway approval payloads, settlement continuation ids, caregiver ledger ids, raw payment maps, or raw price-table maps. Source receipt pagesource-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:37-128decodes rawPAYMENT_INFO.paymentContext, exposes KCPordr_idxx/tno/price into browser JavaScript, and builds the external receipt URL on click. Modern receipt access must be a backend-issued receipt/readiness/action projection or signed handoff; public contracts must not expose gateway order ids, transaction ids, raw payment context, or provider receipt URL construction. Source payment APIs also choose payable amount and virtual-account messaging from mutable reservation maps:source-refs/sanmopia_web/application/controllers/api/Payment.php:89-165,source-refs/sanmopia_web/application/controllers/api/Payment.php:351-382,source-refs/sanmopia_web/application/controllers/api/Payment.php:421-464, andsource-refs/sanmopia_web/application/controllers/api/Payment.php:537-582. Modern payment pre-registration/charge summary must own these decisions: ownership, already-paid checks, deposit/balance/pre-reservation purpose, payable amount, zero-amount closeout, virtual-account notice content, and safe notification handoff. UI/controller inputs may submit intent only; backend recomputes from frozen charge/payment facts. Public API/contract handoff now exposes protected payment-change adjustment request, mother-payment pre-registration, mother-payment capture, and operator-completion endpoints with Supabase bearer auth plus the TypeScriptpaymentChangeAdjustmentRequestHeadershelper. Adjustment pre-registration freezespaymentId, provider name, timestamp, and mother-payable amount onsanmopia_payment_change_adjustments; server-side Kill Bill paid verification checks the pre-registered payment/provider and amount before freezing the provider receipt so mother-visible results do not drift after payment UI entry. Protected read projection endpoints now return the latest adjustment by reservation and durable adjustment detail by id for mother/operator re-entry without relying on command responses. Backend and contract now also exposePaymentChangeOperatorBoardfor paid/completed adjustment rows with operator-only access, booking-scoped row visibility, search text, visible row count, returned row count, deposited/completed timestamps, and completion-editable state. Board rows now include reservation/member enrichment and nullable customer-share deposit, customer-share balance, service-balance, and pre-reservation deposit milestones from purpose-tagged payment records. Backend rows also expose a manual receipt command draft for the payment-change customer-share-balance receipt path, including command availability, disabled reason, command draft id, canonical method, purpose, amount, deposited-at time, and idempotency key (4bd81e1,455f74a,858fa24,87a6e61). Operator completion and operator amount correction now appendPaymentChangeOperatorAuditfacts insanmopia_payment_change_operator_auditsthrough protected backend/contract endpoints, so paid mother-visible amounts are not rewritten after payment. Amount-correction commands now requireexpectedAdjustmentUpdatedAtfrom the board row and reject stale operator submissions before appending audit (f9ce5dc,05059a5). Frontend reservation-operation board now consumes the backend draft instead of hardcoding receipt method, purpose, amount, deposited date, or idempotency (d28ff5f). Adjustment-id settlement continuation workflow status is now exposed through the shared workflow projection endpoint shape. Remaining work is paid-row frontend board UX, forensic classification of existing null-purpose payment rows into balance/service receipt facts, frontend implementation of the new protected manual service-balance and customer-share-balance receipt command, persistence/API wiring for the customer charge/payment projection, wider settlement calculation readers, settlement dashboard/export breadth, and operator UI. - Reservation documents, receipts, daily reports, sub reports, download.
Status:
Partial. Evidence:sanmopia_web/application/controllers/MyReservation.php:194-376,sanmopia_web/application/controllers/api/Report.php:10-115,sanmopia_web/application/models/Report_model.php:47-260,sanmopia_web/application/controllers/api/ReservationDocument.php,sanmopia-admin/application/controllers/cli/ReservationDocument.php,sanmopia-admin/application/models/Spreadsheet_model.php:4284-4590,sanmopia-user-old/src/pages/mypage/daily-report/[date].astro,sanmopia-user-old/src/pages/mypage/daily-sub-report/[date].astro,sanmopia-user-old/src/pages/mypage/reservation-document/[id].astro,sanmopia-user-old/src/pages/mypage/reservation-receipt/[id].astro. Modern replacement:care_delivery/features/daily_care_reportnow owns dynamic report definitions/submissions, andcare_delivery/features/customer_record_confirmationnow owns mother confirmation for customer-facing records. One confirmation maps one care record to one signature capture id, blocking reused electronic signatures across multiple service records.document_reportingconsumes the captured report facts for A4 output instead of owning form fields or source Excel coordinates. Remaining gap: source document generation still mixes spreadsheet templates, static PDF templates, external conversion, downloadable receipts, start/end mail bundles, token download access, and retryable send attempts. Those belong inReservationDocumentTemplate,ReservationDocumentBundle,DocumentAccessGrant, andDocumentDeliveryAttemptinstead of being hidden inside one renderer. Backend/domain contract progress (2026-07-03):document_reportingnow has areservation_document_bundlereadiness slice that groups contract, fee agreement, voucher plan, deposit receipt, balance receipt, service instruction, static notice, daily report, and sub-report members by reservation. Members are catalog/template-version based, include catalog/template/source provenance and bundle/member revisions, support unbounded daily/sub report series through repeat group/member keys, and compute explicit bundle/card state in the backend/domain layer. Customer-safe projection now carries member readiness, missing reason, grant required/issued/revoked state, print/download availability, report member-count/status summary, and deposit/balance receipt version readiness. Boundary contracts reject raw token, URL, storage path, signature, provider response, internal access-grant id, KCP order/tno, and email internals; only opaque public handoff reference, grant revision, and expiry are customer visible. Readiness repair commands include idempotency intent replay/conflict checks. Source customer document listsource-refs/sanmopia_web/application/views/mypage/reservation_document.php:38-139still hardcodes service-type document sets, end-date/status visibility, numeric document ids such as1,3,4,5,8,9,15, and21, and token query-string download URLs. Modern customer document bundle/readiness projections must return typed document definitions, availability reasons, and signed access handoffs; frontend must not choose source document ids, token query params, or direct download URLs. Remaining gap: persistence tables, route binding, signed ZIP/artifact handoff integration, operational delivery retry UX, and customer frontend wiring to consume explicit bundle/card facts without client-side document counting, receipt version branching, or report date/status inference. Source mother-authored daily report, sub-manager report, final-day caregiver rating, and shopping-mall point award must not be hidden inside document rendering. Ubiquitous naming is split by purpose:daily_care_reportownsDailyCareReportReviewOutcome,DailyCareReportReviewRewardPolicy, andDailyCareReportReviewRewardGrantfor the backend outcome generated after a submitted caregiver daily report is reviewed;customer_daily_report_reviewownsCustomerDailyReportReview,CustomerDailyReportReviewSubmission,CustomerDailyReportReviewReadinessDecision, and customer-facing reward grant facts for the customer-authored service-day review workflow. Kanboard evidence: #2491, #2625, #2731, #2621. - Customer-authored service-day review, final-day caregiver rating,
assistant-caregiver rating, and completion reward. Status:
Backend policy, authenticated HTTP binding, reward worker, and customer reward-status projection complete; integration partial. Evidence:source-refs/sanmopia_web/application/views/mypage/daily_report.php:44-149,source-refs/sanmopia_web/static/js/daily_report.js:13-78,source-refs/sanmopia_web/static/js/daily_report.js:81-124,source-refs/sanmopia_web/static/js/daily_report_common.js:1-8,source-refs/sanmopia_web/application/controllers/MyReservation.php:194-326,source-refs/sanmopia_web/application/controllers/api/Report.php:11-115,source-refs/sanmopia_web/application/controllers/api/Report.php:61-109,source-refs/sanmopia_web/application/models/Report_model.php:48-647,source-refs/sanmopia_web/application/models/Report_model.php:192-265,source-refs/sanmopia_web/application/models/Report_model.php:552-624,source-refs/sanmopia-user-old/src/design-system/ui-kit/organisms/ReservationReportList.astro:21-69,source-refs/sanmopia-user-old/src/pages/mypage/daily-report/[date].astro:5-50,source-refs/sanmopia-user-old/src/pages/mypage/daily-sub-report/[date].astro:5-51. Modern replacement:customer_daily_report_reviewownsCustomerDailyReportReview,CustomerDailyReportReviewSubmission,CustomerDailyReportReviewReadinessDecision,CaregiverServiceRating, andCustomerDailyReportReviewRewardGrantin backend/contract. Current backend slice:backend-repo/src/sanmopia_modernization/domain/care_delivery/features/customer_daily_report_reviewandbackend-repo/src/sanmopia_modernization/application/care_delivery/features/customer_daily_report_review. It uses versioned question catalogs, explicit service-date/window/finality facts, main/assistant rating presentation rows, policy-owned rating scale facts, 90-day rating-window facts, comment length limits, reward amounts, and once-per-reservation reward idempotency keys. Backend-owned submission policy now covers required answers, final-day rating requirements, dynamic rating scale validation, rating-window blocking, comment length, reward-grant result, readiness/action decisions, andDailyReportCompletionRewardLedgerInstructionoutput. The reward ledger instruction decomposes the sourceCOUPON_TB/USER_COUPON_TB/USER_POINT_TB/SHOPPINGMALL_FLside effects into explicitpromotion_entitlement,point_credit, andcompletion_markerlines behind the same once-per-reservation idempotency key. Supabase persistence now records the instruction insanmopia_daily_report_completion_reward_ledgersand dispatchable line rows insanmopia_daily_report_completion_reward_ledger_linesthrough a care-delivery-owned adapter, instead of forcing daily-report rewards into the reservation-cancellation promotion outbox. It shares service-day eligibility with care delivery and document reporting, but stays separate from caregiver-authoredDailyCareReportSubmission. Backend now binds authenticated routesPOST /customer-daily-report-reviews/readinessandPOST /customer-daily-report-reviews; the submission route checks the Supabase bearer-token actor against both facts and submission actor ids before recording the reward ledger instruction through the application handler. Backend PGMQ worker contract now addsdaily_report_completion_reward/sanmopia_daily_report_completion_reward; the Supabase adapter enqueues each reward line, the worker processor validates strict Pydantic payloads, and line rows record dispatch, completion, and failure timestamps. The worker now persists idempotent service-role-only fulfillment facts insanmopia_daily_report_completion_reward_fulfillmentsforpromotion_entitlement,point_credit, andcompletion_markerlines, so the backend has an auditable reward-application fact. Backend now exposes authenticatedGET /customer-daily-report-reviews/{reservation_booking_id}/reward-statusas a customer-visible projection that returns applied reward lines and missing reward component kinds without letting the frontend infer coupon/point state. Client-side star-rating value, shopping-mall reward modal, and route return behavior must consume backend submission/readiness/reward-grant/ledger-instruction results rather than frontend-only checks. Remaining gap: external shopping-mall/coupon/point connector execution, frontend wiring to consume readiness/action/reward-status decisions, and public/private review scope for any rating reused outside the reservation detail screen. - Coupon/gift shop: coupon order, gift order, resend, cancel, sent coupon.
Status:
Partial. Evidence:sanmopia_web/application/controllers/Shop.php,sanmopia_web/application/controllers/api/Shop.php,sanmopia-user-old/src/pages/shop/*,sanmopia-user-old/src/pages/menu/mycoupon.astro,sanmopia-user-old/src/pages/menu/sentcoupon.astro. Modern replacement:pricing_settlement/features/promotion_entitlementmodels service-gift entitlements, purchased reservation credits, gift fulfillment requests, and boundary-only source code mapping forPRODUCT1/PRODUCT2. Remaining gap: gift coupon Kill Bill workflow, anonymous buyer claim, resend attempt audit, entitlement restoration on reservation cancellation, expiry ledger, and operator repair state. See Customer Engagement Commerce Gap Mining. - Event, promotion, alliance, delivery event, review event. Status:
Partial. Evidence:sanmopia_web/application/controllers/Event.php,sanmopia_web/application/views/modal/modal_start_popup.php,sanmopia-user-old/src/pages/event/*. Modern replacement:ContentPublicationstores event/campaign/alliance content.CampaignPlacementreplaces hardcoded popup/banner/event slot switches with Strapi-authored slots, dismiss keys, media references, CTA values, and active windows backed bysanmopia_content_publication_placements. - Board, notice, posts, FAQ, QnA, notifications. Status:
Partial. Evidence:sanmopia_web/application/controllers/Board.php,sanmopia_web/application/controllers/Notice.php,sanmopia_web/application/controllers/Notification.php,sanmopia_web/application/controllers/Qna.php,sanmopia-user-old/src/pages/board/*,sanmopia-user-old/src/pages/notice/index.astro,sanmopia-user-old/src/pages/notification/index.astro,sanmopia-user-old/src/pages/faq/*,sanmopia-user-old/src/pages/qna/index.astro,sanmopia-user-old/src/pages/posts/*. Modern replacement:customer_engagement/features/contentmodelsContentPublicationfor community articles, public notices, knowledge-base answers, service campaigns, alliance benefits, caregiver news, and health-education profiles, articles, videos, FAQ entries, and visit classes.customer_inquiryreplaces user FAQ/inquiry lifecycle.CampaignPlacementcovers popup/banner/event slot rules.notificationcarries visible windows, action payloads, and read state. Numbered imported health-education categories are translated only at the Pydantic/contract adapter boundary; domain values usehealth_education_*naming.communication_deliveryroutes coupon, payment-deadline, branch reminder, daily-report, and campaign triggers through Novu-backed workflow rules with dispatch idempotency and audit rows. Strapi provides OSS CMS/admin authoring on Supabase Postgres/Storage so handmade CMS CRUD is not rebuilt. - Partner benefit lead application/cancel/result/download/export scheduler.
Status:
Partial. Evidence:sanmopia_web/application/controllers/Momfirst.php,sanmopia_web/application/controllers/Clean.php,sanmopia_web/application/controllers/api/Momfirst.php,sanmopia_web/application/controllers/api/Clean.php,sanmopia_web/application/controllers/cli/Momfirst.php,sanmopia_web/application/controllers/cli/Clean.php,sanmopia_web/application/models/Momfirst_model.php,sanmopia_web/application/models/Clean_model.php,sanmopia-user-old/src/pages/momfirst/index.astro,sanmopia-user-old/src/pages/clean/*. Modern replacement:customer_engagement/features/mother_lead_intakemodels configurableMotherLeadProgramPolicy,MotherLeadRequest, eligibility, cancellation, export readiness, duplicate-export cooldown, and result attachment. Supabase tables store program versions, requests, export batches, export items, and privatemother-lead-resultsfiles. Source identifiers such asMILK,LOVEBOX, andCLEAN_TBmap only at application/contract boundaries. Remaining gap: partner export batch workflow, private artifact handoff, cancellation/anonymization policy, partner response audit, and customer status projection. See Customer Engagement Commerce Gap Mining. - Vaccination schedule and app-open/deep-link pages. Status:
Partial. Evidence:sanmopia_web/application/controllers/About.php:212,sanmopia_web/application/controllers/Opentheapp.php,sanmopia-user-old/src/pages/vaccination-schedule/index.astro,sanmopia-user-old/src/pages/open-the-app/index.astro. Modern replacement:customer_engagement/features/child_health_guidancereplaces sourcevaccination_schedule.phparrays and component default deep-link strings with versionedVaccinationSchedulePolicy,VaccinationDoseRule, previous-dose timing, andMobileAppEntryPoint. Strapi authorssanmopia_child_vaccination_schedule_policiesandsanmopia_mobile_app_entry_points; backend contracts validate stable codes, Strapi as authoring provider, HTTPS/intent destinations, and date windows. Python uses the OSSpython-dateutilmonth arithmetic for backend policy work. Frontend preview usesdate-fnsfor month/day schedule math, keeps the KDCA official schedule link visible, and modernizes/vaccination-scheduleplus/open-the-appwithout copying source PHP/React UI.
Admin And Branch Backoffice
Section titled “Admin And Branch Backoffice”- Admin authentication, home/dashboard, branch token maintenance. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/Administrator.php:109-170,source-refs/sanmopia-admin/application/core/MY_Controller.php:69-137,source-refs/sanmopia-admin/application/models/User_model.php:11-138,source-refs/sanmopia-admin/application/models/Branch_model.php:11-126, andsanmopia-admin/application/controllers/AdministratorNew.php. Required proof:OperatorIdentitySession,OperatorCapabilityPolicy,BranchRelationshipGrant, andBranchLoginAuditEventreplace sourceadmin/branch/admin_momfirstsession strings, branch auth-token lookup, random token helpers, and branch-only login log side effects with Supabase Auth identities, app metadata roles, SpiceDB relationships, OPA/status gates, short-lived sessions, token rotation audit, and per-command capability snapshots. Dashboard/home access must not infer permission from menu route or sessiontype; it must read backend authorization as SSOT. Backend foundation now exists inoperator_access/features/operator_identity_session:IdentityAuthorizationMetadataFact,AuthorizationRelationshipFact,PolicyStatusGateFact, capability snapshots, branch relationship grants, branch login audit events, and branch token rotation audit read models that expose only token reference and fingerprints with idempotency and expected-revision protection. Remaining proof: Supabase persistence/schema/RLS, SpiceDB/OPA runtime adapters, API endpoints, generated contracts/client, dashboard UI binding, and runtime verification. - Branch/headquarters profile, service area, stamps, notices, education,
office management, central notices. Status:
Partial. Evidence:sanmopia-admin/application/controllers/OfficeManagement.php,sanmopia-admin/application/models/Branch_model.php,sanmopia-admin/application/models/Office_management_model.php. Modern replacement:branch_operations/features/organizationnow owns branch managed service-area policy withservice_available,consultation_available, andservice_unavailablekinds. Address matching supports source 1/2/3-depth lookup and special city split cases such as고양시 일산동구, while unavailable areas override available areas. Consultation/unavailable areas must be registered inside an existing available area for the same branch, replacing sourcepossible/counsel/impossiblebranch switches with versioned domain policy. Matched rules now carry profile keys for coverage and service-calendar follow-up policy, so locality-specific benefits or support extensions are managed as versioned profiles instead of UI/controller string checks. Stamps, education, notices, and full office profile editing remain incomplete.branch_operations/features/office_contentnow replaces handmade OfficeManagement CRUD for branch/HQ notices, caregiver instructions, caregiver event notices, branch news, education schedules/materials, and printable branch brand assets such as official stamps and profile images. Strapi authors the content/admin UX, Supabase Storagecontent-assetsstores media, and Supabase RLS limits branch-scoped rows to target branch members or HQ. Full branch profile/account editing remains incomplete. - Branch office profile, operator credential, membership fee, bank account,
brand asset, and login audit facts. Status:
Pending. Evidence:source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:399-430,source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:407-445,source-refs/sanmopia-admin/application/models/Branch_model.php:157-287,source-refs/sanmopia-admin/application/models/Branch_model.php:435-678,source-refs/sanmopia-admin/application/controllers/Administrator.php:108-158. Modern replacement:branch_operations/features/office_profilenow ownsBranchOfficeProfile,BranchOperatorCredential,BranchMembershipFeePolicy,BranchSettlementAccount, and purpose-specific current account persistence. P01 now has a tested HQ authority resolver and current-result adapter, but no onboarding persistence, RPC, or provider-effect execution proof.BranchBrandAssetandBranchLoginAuditEventremain separate open facts. It must include HQ-created branch signup/onboarding, duplicate login-id checks, password rotation, active/deleted office state, primary and secondary settlement accounts, membership-fee monthly snapshots, profile/stamp asset lifecycle, postal address details, and login IP/device audit. Service-area and office-content slices stay separate; source password/token fields remain adapter-only evidence. See Branch Office Operations Gap Mining. - Member/customer admin, FAQ admin, member detail, email duplicate check.
Status:
Partial. Evidence:sanmopia-admin/application/controllers/Member.php,sanmopia-admin/application/models/User_model.php,sanmopia-admin/application/models/Faq_model.php. - Reservation admin: history, detail, save, pre-reservation, branch change,
memo, voucher price version, service balance, add service, delete service,
search, calendar, coupon reason, manager matching/confirmation. Status:
Partial. Evidence:sanmopia-admin/application/controllers/Reservation.php,sanmopia-admin/application/controllers/ajax/Reservation.php,sanmopia-admin/application/controllers/ajax/Reservation.php:31-66,sanmopia-admin/application/models/Reservation_model.php,sanmopia-admin/application/models/Matching_model.php:44-176,sanmopia-admin/application/models/Matching_model.php:718-862,sanmopia-admin/application/models/Manager_model.php:2146-2179,sanmopia-admin/application/models/Reservation_service_voucher_model.php,sanmopia-admin/application/models/Reservation_rental_model.php. Modern replacement: Restate-backed reservation workflows must expose operator-readable progress, not only start ids. The source admin surface mixes status mutation, branch/HQ authority, branch lockout after service end, and calendar visibility in controller/view code; the modern UI needs one workflow status read model that shows requested command, current durable step, blocked reason, retryable failure, final reservation status, and affected read-model ids. The current backend projection now carries the domainreservation_statusvalue and exposes the authenticated actor’s reservation capability snapshot for booking workflows, so branch/HQ screens do not have to infer allowed commands from copied source status ids. Contract clients now have a reservation-booking-specific projection path helper so new portal reads do not depend on the raw workflow request row. The raw row reader is gated by the same bearer-token workflow projection authorization in the composed backend app. evidence:sanmopia-admin/application/config/constants.php:116-160,sanmopia-admin/application/controllers/Reservation.php:415-431,sanmopia-admin/application/controllers/Reservation.php:632-639, andsanmopia-admin/application/views/reservation_status/reservation_detail.php:81-169. Portal implication: branch operators should see the same workflow request row as HQ, but available commands must be filtered by actor-stage capability, stage policy, SpiceDB relation, and OPA status/legal gate before rendering. Matching should be a first-classCaregiverMatchingCandidateSelectionread model: score customer preferences plus caregiver personality answers, filter by active/delete flags, branch, caregiver grade, pets, unavailable schedules, service address distance, and cached transit time. Operator confirmation then emitsCaregiverAssignmentProposed,CaregiverAssignmentConfirmed,CaregiverAssignmentDeclined, orCaregiverAssignmentWithdrawn; the old smart-matching score/table names stay adapter evidence only. Do not reproduce source ranking literally:source-refs/sanmopia-admin/application/models/Matching_model.php:194-203compares the reservation answer to itself when building matching result marks,Matching_model.php:111-115interpolates search text into SQL, andMatching_model.php:118-173mixes random tie-breaking with post-query distance sorting. Modern matching must persist a versionedCaregiverCandidateEvidencesnapshot and run deterministic ranking or OR-Tools optimization from policy weights, exclusion reasons, cached transit facts, fairness/rotation state, and operator override audit. Active matching policy is now a backend read model atGET /caregiver-matching-policies/active; clients pass optionaleffectiveOnand render the Supabase-backedCaregiverMatchingPolicysnapshot instead of branching on service-detail strings. Named caregiver selection now has backend-ownedRequestedCaregiverSelectionandRequestedCaregiverPolicyDecisioncontracts: service-grade uplift, consultation-required uncertainty, blocking codes, andaccepted_for_assignmentcome from the same matching policy instead of source survey/search UI strings. Reservation control also needs the collaboration gate documented in Reservation Control Collaboration Gap Mining. Source detail save posts status, service dates, caregiver ids, addresses, payment dates, and memo as one broad form, then the controller applies sequential service/payment/caregiver/address/memo writes without one expected-revision command boundary. Modern replacement:ReservationCollaborationCommand,ReservationChangeJournalEntry, andReservationRealtimeProjectionEventnow exist in backend/domain and application contracts. Supabase now persistsrevision_number,sanmopia_reservation_change_journal_entries, andsanmopia_reservation_realtime_projection_events; thesanmopia_commit_reservation_collaborationRPC enforces expected revision, idempotency replay, append-only journal, and private Realtime Broadcast, with generated Supabase types updated.CommitReservationCollaborationHandlernow reads current Supabase revision/current field values, commits accepted writes through the RPC, and exposesPOST /reservation-collaboration-commits/{reservationId}with structured stale-save409conflict detail. Commit-time RPC revision races are also re-read and mapped to the same409conflict response, so a concurrent branch/HQ save does not degrade into a false backend503.OpenReservationCollaborationWorkspaceHandlerandListReservationCollaborationJournalHandlernow exposePOST /reservation-collaboration-workspaces/{reservationId}andPOST /reservation-collaboration-journal/{reservationId}so branch/HQ portals can load current revision, realtime subscription metadata, return state token, coordination policy, and operator-facing audit timeline before saving. The workspace response now namescoordinationPolicy.realtimeChannelMode = private_broadcast_and_presenceandcoordinationPolicy.dirtyNavigationPolicy = require_save_discard_or_draft; Supabaserealtime.messagesRLS authorizes both Broadcast and Presence only for HQ or the owning branch. Browser-level collaboration sessions now persist assanmopia_reservation_workspace_sessions; non-mutating UX events such asworkspace_opened,navigation_blocked,draft_marked_dirty,draft_recovered,draft_discarded,commit_conflicted, andworkspace_closedpersist throughPOST /reservation-collaboration-workspace-events/{reservationId}intosanmopia_reservation_workspace_events. This keeps page 이동, history back, dirty draft, discard, and stale-save support cases searchable without overloading the domain mutation journal. Remaining work: bind every remaining branch/HQ mutation path to this handler, initial revision backfill, and a two-workspace stale-save smoke test. Contract repo now exposes OpenAPI, JSON Schema, and TypeScript helpers for workspace open, journal, commit, conflict, realtime coordination policy, draft session, workspace event, and idempotency key generation. Branch handoff, booking service date fields, extra service-day rows, and caregiver assignment roster rows are now applied mutations.transfer_reservation_branchacceptsbranch_handoff.branch_profile_id, requires target branch/audit/diff facts, and updatessanmopia_reservation_bookings.branch_profile_idinside the same expected-revision RPC that writes the journal and private Broadcast event.service_schedule.start_onandservice_schedule.end_onupdateservice_start_atandservice_end_atin the same RPC with timestamptz parsing and start/end range validation.service_schedule.extra_service_daysreplacessanmopia_reservation_extra_service_daysrows in the same transaction after the revision commit succeeds.caregiver_assignment.rosterreplacessanmopia_reservation_caregiver_assignmentsrows in the same revision-checked transaction, preserving primary/assistant roles, grade, planned service days, term dates, and contract assignment keys. Commit-time RPC revision races now raiseReservationCollaborationPersistenceConflict, re-read the latest snapshot, and return the normal stale-save409conflict contract to the portal. Service term, payment fact, address, memo, branch handoff, service dates, extra service days, and caregiver roster now share the collaboration gate. Remaining work: initial revision backfill and broader portal smoke coverage. - Branch reservation birth-profile correction and pre-service
contact/address correction. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/Reservation.php:696-720,source-refs/sanmopia-admin/application/controllers/Reservation.php:1023-1092,source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:211-224. Modern replacement:reservation_operations/features/birth_informationalready modelsReservationBirthProfileandBirthInformationReminderTask; branch admin still needsReservationBirthProfileCorrection,ReservationContactCorrection, andReservationServiceAddressCorrectioncommands with actor-stage authorization and audit. - Reservation change-request intake, operator change audit, caregiver
replacement, assistant caregiver add/remove, and multi-caregiver contract
terms. Status:
Partial. Evidence:source-refs/sanmopia_web/application/controllers/api/Reservation.php:100-230,source-refs/sanmopia_web/application/controllers/api/Reservation.php:243-289,source-refs/sanmopia_web/application/models/Reservation_model.php:990-1111,source-refs/sanmopia_web/application/models/Reservation_model.php:2052-2145,source-refs/sanmopia-admin/application/controllers/Reservation.php:650-1018,source-refs/sanmopia-admin/application/models/Reservation_model.php:1950-1977,source-refs/sanmopia-admin/application/models/Reservation_model.php:2165-2300,source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:180-208,source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:21-53,source-refs/sanmopia-admin/application/models/Reservation_manager_salary_model.php:124-181,source-refs/sanmopia-admin/application/models/Reservation_model.php:2407-2564,source-refs/sanmopia-admin/application/models/Reservation_model.php:3466-3555,source-refs/sanmopia-user-old/src/design-system/ui-kit/organisms/ReservationManagerInfo.astro:21-80. Modern replacement:reservation_operations/features/reservation_change_requestnow owns customer/operator-originatedReservationChangeRequest,ReservationChangeRequestDetail,ReservationChangeApplicationPlan,ReservationChangeEffect, andReservationChangeOperatorAuditin backend/contract. The slice covers schedule change, extension, cancellation, care stop, primary caregiver replacement, assistant caregiver add/remove, and multi-caregiver contract-term requests. Accepted requests produce explicit effects for service schedule, payment adjustment, primary caregiver term, assistant caregiver roster, caregiver compensation, mother-visible summary, and branch settlement instead of deleting linked source rows implicitly. Existingcaregiver_assignmentremains owner of date-bounded primary terms, assistant terms, contract assignment keys, and compensation seeds, so request intake does not duplicate contract-roster logic. Remaining gap: Supabase persistence, command-board API wiring, branch/HQ actor command matrix, direct extension-draft linking, and payout/settlement allocation invalidation adapters. Legacy sub-caregiver replacement deletes the slot roster and linked sub-payout rows for that reservation before inserting the new slot/log, while balance and salary closeout rows are recreated or updated from the current assignment. Modern replacement needs explicitCaregiverPayoutAllocationInvalidatedandCaregiverPayoutAllocationRecreatedevents rather than silent row delete side effects. Source main/assistant table names and numeric status ids remain adapter-only. Main and assistant caregiver assignment must also pass through the reservation collaboration gate because source assignment is applied inside reservation detail save, then writes direct old/new logs and assistant rows by reservation plus sort. Modern follow-up names:CaregiverAssignmentCommand,AssignmentConflictCheck,AssignmentDecisionAudit, andCaregiverAssignmentReadModelInvalidation. Branch handoff already uses the same collaboration gate throughtransfer_reservation_branch; caregiver assignment must follow that pattern instead of writing assignment rows from a broad reservation-detail form. - Caregiver/manager admin: profile, career, education, health, denied days,
custom prices, sign/profile image, recommendation, payment memo, attendance
setup. Status:
Partial. Evidence:sanmopia-admin/application/controllers/Manager.php,sanmopia-admin/application/controllers/ajax/Manager.php,sanmopia-admin/application/models/Manager_model.php,sanmopia-admin/application/models/Manager_class_model.php,sanmopia-admin/application/models/Manager_working_day_model.php. - Manager evaluation, score, class update, event, education video. Status:
Partial. Evidence:sanmopia-admin/application/controllers/ManagerEvaluation.php,sanmopia-admin/application/controllers/ajax/ManagerEvaluation.php,sanmopia-admin/application/controllers/ManagerEvent.php,sanmopia-admin/application/controllers/cli/Manager.php,sanmopia-admin/application/models/Manager_evaluation_model.php,sanmopia-admin/application/models/Manager_score_model.php,sanmopia-admin/application/models/Manager_event_model.php. - Settlement and calculations: central settlement, branch unit settlement,
other-office settlement, history, branch payment insert, Danbee export,
monthly statistics, Excel downloads. Status:
Partial. Evidence:sanmopia-admin/application/controllers/Calculate.php:126-315,sanmopia-admin/application/controllers/Calculate.php:335-498,source-refs/sanmopia-admin/application/controllers/Calculate.php:70-146,source-refs/sanmopia-admin/application/controllers/Calculate.php:315-430,source-refs/sanmopia-admin/application/controllers/Calculate.php:568-577,sanmopia-admin/application/controllers/ajax/Calculate.php,sanmopia-admin/application/controllers/cli/Calc.php,sanmopia-admin/application/controllers/cli/Excel.php,sanmopia-admin/application/controllers/Reservation.php:843-864,sanmopia-admin/application/controllers/Reservation.php:930-1014,sanmopia-admin/application/models/Payment_model.php:2525-3060,sanmopia-admin/application/models/Payment_model.php:2656-2816,sanmopia-admin/application/models/Payment_model.php:2975-3051,source-refs/sanmopia-admin/application/models/Payment_model.php:2657-2965,source-refs/sanmopia-admin/application/models/Payment_model.php:3086-3210,source-refs/sanmopia-admin/application/controllers/Calculate.php:552-566,source-refs/sanmopia-admin/application/models/Payment_model.php:4047-4058,source-refs/sanmopia-admin/application/views/calculate_detail.php:1204-1354. Source-dig addition: branch-to-HQ board status opening usesPayment_model::updateBoardId, arrears can move the board to status3, and automatic close to status2depends ongetCompleteFlagCountFromBoard(). That method filters detail rows byPAYMENT_TYPE_LIST_ID_FK = 0, but current writers post selected UI payment type ids and no type-0 writer was found. Modern completion must use typed board flags plus no-open-line checks; type-0 remains adapter evidence only. Monthly-statistics source-dig addition:Calculate::getStatisticsForMonth()delegates to a payment-model query that counts reservations created between fixed dates2019-11-01and2019-12-01with raw status ids[3,4,5,6]. Target names:business_reporting / SettlementPeriodStatisticsSnapshotandpricing_settlement / SettlementPeriodDatasetRevision. Backend authority must derive settlement-period metrics from versioned reservation, payment, and settlement facts, date-basis policy, status catalog, and dataset revision; PHP fixed-date/status filters are source evidence only. Modern replacement:pricing_settlement/features/financial_lifecyclenow exposes command APIs for service delivery, caregiver payout preparation, branch settlement preparation, HQ settlement preparation, and settlement completion. Supabase persists lifecycle stage and versioned ledger lines insanmopia_reservation_financial_lifecyclesandsanmopia_reservation_financial_ledger_lines.ReservationFinancialLifecycleWorkflownow starts through Restate and executes those stage commands under a stablefinancialLifecycleWorkflowRequestId. Backend progress reads useGET /reservation-financial-lifecycle-workflow-requests/{financialLifecycleWorkflowRequestId}, backed by service-role-onlysanmopia_reservation_financial_lifecycle_workflow_requestsledger rows.branch_settlementmust preserve separate HQ and branch commands from the source board:request_branch_deposit,confirm_branch_deposit,close_branch_settlement,mark_branch_arrears, andconfirm_branch_arrears_payment. SourceSTATUS_FLvalues0-4stay adapter evidence only. Source other-office settlement now maps to the modernInterOfficeSettlementaggregate instead of keeping source naming. Backend foundation addsServiceOfficeTransferandCustomerHandoffOfficesettlement kinds, service-delivery/customer-relationship branch roles, headquarters service-fee lines, customer coupon-deduction lines, versioned policy labels, frozen charge snapshot references, shape-validated export payloads, andInterOfficeSettlementLookupKey. That key prevents sourceBRANCH_TYPE-only detail lookups by requiring reservation id, customer relationship branch, service delivery branch, and settlement period before an inter-office settlement code can be built. Supabase persistence now stores the aggregate and ordered allocation lines throughsanmopia_save_inter_office_settlement, with lookup uniqueness on reservation, customer relationship branch, service delivery branch, and period. Backend now exposesOpenInterOfficeSettlementCommand,InterOfficeSettlementCommandHandler,InterOfficeSettlementQueryHandler,InterOfficeSettlementApi, and FastAPI routes forPOST /inter-office-settlements,POST /inter-office-settlement-lookups, andGET /inter-office-settlements/{interOfficeSettlementCode}. The branch history read side now addsListInterOfficeSettlementHistoryQuery,GET /inter-office-settlement-histories/{branchProfileId}, and the shared TS helperinterOfficeSettlementHistoryPath. It reads both customer-relationship and service-delivery branch roles, filters overlapping settlement periods before line hydration, and deduplicates by canonical settlement id. Opening is idempotent by the full lookup key, and exact settlement access still checkssettleon both branches while history access checks the requested branch scope. Reservation-scoped Danbee settlement status now replaces sourceDANBEE_STATUS_FLwithReservationExternalCounterpartySettlementStatus, service-role-only Supabase projection tablesanmopia_reservation_external_counterparty_settlement_statuses,GetReservationExternalCounterpartySettlementStatusQuery,GET /reservation-external-counterparty-settlement-statuses/{reservationId}, and shared TS helpersreservationExternalCounterpartySettlementStatusPath/findReservationExternalCounterpartySettlementStatusProblems. The workflow-owned update side now usesUpdateReservationExternalCounterpartySettlementStatusFromStatementCommandandPOST /internal/reservation-external-counterparty-settlement-status-updates, with dataset revision conflict checks so older statement events cannot overwrite a newer reservation projection. Frontend operator board now surfaces Danbee data-room readiness from the shared contract validator and shows operator-facing blocking facts such as missing external recipient code. Remaining work: backend-provided recipient/revision settings and submit actions for operator screens. Danbee and HQ exports must be separateSettlementExportArtifactvariants: source routes read central-to-branch, user-to-Danbee, other-office, history, and Excel download surfaces from different controller/model paths, andcalculate_detailhides add/delete/complete controls based on board close flags rather than raw reservation status alone. Reservation edits and payment edits must flow into settlement through versioned facts, not by recalculating mutable current rows in-place:ReservationServiceTermChanged,ReservationPaymentDateCorrected,PaymentChangeAdjustmentCompleted,CaregiverAssignmentChanged, andServiceOfficeChangedshould triggerFinancialLifecycleRecalculationNeededuntil the affected branch/HQ board is closed. Closed boards need explicitSettlementCorrectionEntryrows instead of mutating already exported board values. Settlement board open/acknowledgement now has backend command-ledger idempotency throughSettlementTransitionAudituniqueness,SettlementStatement.replayed_command_audit, and the contract helperfindSettlementStatementCommandReplay: source JS posts arrays of reservation/payment/coupon/manual-line ids with only client duplicate guards, while controllers update payment flags, board rows, detail rows, and acknowledgement flags directly. Remaining board-binding work must connect every source mutation path to these command concepts:BranchSettlementOpeningCommand,BranchSettlementAcknowledgement,cancelled_gift_coupon_commission_paid,SettlementLineAcknowledgement,SettlementCommandLedger, andSettlementBoardInvalidation. UI-posted settlement arithmetic is now modeled as operator-entered comparison evidence throughSettlementArithmeticDecision: Danbee, branch-to-HQ, HQ, and inter-office settlement stay separate subjects; backend line items/snapshots emit canonical amounts, discrepancy facts, policy labels,calculationRevision,datasetRevision,lineageEvidenceKeys, command readiness, and the accept/reject decision before board/status commands persist. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:139-146,source-refs/sanmopia-admin/application/controllers/Calculate.php:161-189,source-refs/sanmopia-admin/application/controllers/Calculate.php:248-309,source-refs/sanmopia-admin/application/controllers/Calculate.php:344-355, andsource-refs/sanmopia-admin/application/models/Payment_model.php:534-620. Follow-up rework (2026-07-03): settlement domain aggregates and API facades no longer mint hidden UUIDs or hidden timestamps for statement, transition-audit, data-room request/action, inter-office settlement, or Danbee projection paths; application commands, injected clocks, and fixtures must provide those stable facts explicitly. Domain/application vocabulary now uses origin/lineage,calculationRevision, anddatasetRevision; raw persisted status and column names remain isolated as adapter DB-column evidence. Arithmetic mismatch gates still block branch open/review, Danbee update, HQ statement request, and inter-office opening before mutation. 정산자료실 must be redesigned asSettlementDataRoomRequestandSettlementDataRoomArtifact, separate from genericDocumentRoom: each export stores the exact frozen dataset, filter context, policy version, operator, branch/HQ/Danbee/inter-branch collection scope, delivery target, dataset revision, lineage evidence keys, and repair reason. Browser back, list filters, hidden iframe downloads, and manual downloads cannot reconstruct state from mutable settlement rows after board close. Backend foundation now addsSettlementDataRoomCollection,SettlementDataRoomScope,SettlementDataRoomRequest,SettlementDataRoomArtifact,SettlementDataRoomActionEntry,SettlementDataRoomCommandHandler,SupabaseSettlementDataRoomRequestRepository,SettlementDataRoomApi, FastAPI routes, Supabase Storage signed download handoff, and private Supabase tablessanmopia_settlement_data_room_requests,sanmopia_settlement_data_room_artifacts, andsanmopia_settlement_data_room_actions. Contract repo exposesPOST /settlement-data-room-export-requests,GET /settlement-data-room-requests/{settlementDataRoomRequestId},POST /settlement-data-room-requests/{settlementDataRoomRequestId}/builds,POST /settlement-data-room-requests/{settlementDataRoomRequestId}/ready-artifacts,POST /settlement-data-room-requests/{settlementDataRoomRequestId}/repair-requests, andPOST /settlement-data-room-requests/{settlementDataRoomRequestId}/download-handoffs. System workflow owns build/ready actions; branch manager and headquarters administrator own export open, repair request, and signed download handoff actions with expected revision and idempotency key. Source data-room and export evidence is now pinned tosource-refs/sanmopia-admin/application/controllers/DataRoom.php:218-250,source-refs/sanmopia-admin/application/controllers/DataRoom.php:312-382,source-refs/sanmopia-admin/application/models/Payment_model.php:1595-1747,source-refs/sanmopia-admin/application/models/Payment_model.php:1750-1960,source-refs/sanmopia-admin/static/js/calculate_detail.js:81-310,source-refs/sanmopia-admin/static/js/form_reservation_list.js:225-247, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3911. Additional source evidence shows menu separation and hidden download gaps:source-refs/sanmopia-admin/application/views/nav/nav_side.php:374-442,source-refs/sanmopia-admin/application/views/nav/nav_side.php:483-540,source-refs/sanmopia-admin/application/views/local_calculate_central_history.php:31-75, andsource-refs/sanmopia-admin/application/views/table_local_cal_central_history.php:1-39. Additional source scan (2026-07-03) splits the data-room backlog intoSettlementArchive,BranchSettlementArchive,BranchSettlementWorklist,ExternalCounterpartySettlementBatch,HeadOfficeSettlementBatch,OtherAreaSettlementCase,ResourceLibrary,ReservationDocumentExport, andBranchResourcePost. Evidence:source-refs/sanmopia-admin/application/views/nav/nav_side.php:420,source-refs/sanmopia-admin/application/views/nav/nav_side.php:483,source-refs/sanmopia-admin/application/controllers/Calculate.php:72,source-refs/sanmopia-admin/application/controllers/Calculate.php:150,source-refs/sanmopia-admin/application/controllers/DataRoom.php:30,source-refs/sanmopia-admin/application/controllers/DataRoom.php:268,source-refs/sanmopia-admin/application/models/Payment_model.php:607,source-refs/sanmopia-admin/application/models/Payment_model.php:1749, andsource-refs/sanmopia-admin/application/views/form_reservation_list.php:40. Status flags such asSTATUS_FL,CENTRAL_STATUS_FL,DANBEE_STATUS_FL,PAYMENT_STATUS_LIST_ID_FK, andMONTH_DUE_STATUS_FLmust become explicitSettlementBoardStatus,ReservationExternalCounterpartySettlementStatus,SettlementLineStatus,DepositRequest,DepositConfirmation,ArrearsRequest, andSettlementTransitionAuditconcepts. Hardcoded voucher,promotional_coupon_cost, payment-method fee, and branch-exception amounts belong in versionedSettlementPricingPolicyfixtures before command migration; gift coupon settlement charges now use injected, effective-dated benefit-package rate catalogs and still post deleted-coupon charges separately ascancelled_gift_coupon_commission. Voucher fees are now modeled asVoucherServiceCommissionwith policy version, effective period, eligible-reservation count, and a receivablevoucher_service_commissionbranch settlement line item, so the sourceVOUCHER_COUNT * 15000view/model formulas remain evidence only. Branch settlement delivery fees now useBranchSettlementDeliveryFeewith a sharedSettlementPolicyEffectivePeriod; sourceDELIVERY_FEE,fdelivery-price, andDELIVERY_PRICEboard fields remain adapter evidence, not UI authority. Deeper settlement data-room/document-download extraction (updated 2026-07-04):SettlementWorkspacenow exposes separateSettlementDataRoomCollectionworklists for HQ settlement, Danbee settlement, and inter-branch settlement instead of one mutable legacy route/detail switch through backend workspace API routes and Supabase workspace snapshots.BulkExportTemplatePolicystarts replacing hardcoded workbook/static-PDF ids andLIST_DATAROOM_FORM_TBrows with configurable, versioned template eligibility by collection, branch/HQ scope, renderer key, required columns, and active revision. Remaining template expansion must add service type, report type, reservation status, and export bundle membership. Evidence:source-refs/sanmopia-admin/application/controllers/DataRoom.php:30-94,source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:17-240,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:15-58, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-4198.SettlementArtifactRequestandSettlementArtifactVersionmust persist immutable generated files from frozen settlement/document datasets, because source downloads build ZIP/XLSX/PDF output from current DB rows and temp filesystem paths at click time. Evidence:source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3911,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-4198, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4284-4601.SettlementArtifactGrantplusDownloadHandoffAuditmust replace directdocument.location.hrefGET downloads, direct attachment links, and hidden iframe POST downloads with signed, expiring, branch/HQ-scoped grants whose issue, use, expiry, retry, and denial are audited. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:297-337,source-refs/sanmopia-admin/application/controllers/Calculate.php:568-577,source-refs/sanmopia-admin/application/views/data_room/form_reservation_list.php:123-208,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:225-262, andsource-refs/sanmopia-admin/application/views/data_room/other_post_view.php:72-89. Follow-up source scan (2026-07-03) keepsReservationDocumentExportWorklist,BranchResourcePost,BranchResourceAttachmentVersion, andBranchResourceGrantas open backend gaps: DataTables search/sort/page must move from PHP-memory slicing into a database read model with template eligibility and an immutable selection token, while other-post attachments need Supabase Storage object keys, soft deletion, retention, actor audit, and signed download grants instead of hard filesystem deletes. Evidence:source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:17-240,source-refs/sanmopia-admin/application/controllers/DataRoom.php:119-212, andsource-refs/sanmopia-admin/application/models/Data_room_model.php:25-203.OperatorReturnStateTokenshould keep list filters, branch selection, and post-action return state without trusting browser hash, query rebuilding, ordocument.referrer; source uses all three. Evidence:source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:6-47,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:164-195,source-refs/sanmopia-admin/static/js/data_room/calculate_central.js:10-14,source-refs/sanmopia-admin/static/js/data_room/calculate_danvi.js:10-14, andsource-refs/sanmopia-admin/static/js/data_room/calculate_danvi_other_office.js:10-22.SettlementRepairRequestremainsPendinguntil operators can request, retry, rebuild, revoke, and supersede artifacts with expected revisions and reasons; source confirmations say settlement completion cannot be undone, mutates board/payment rows directly, and writes only narrow status logs. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:20-337,source-refs/sanmopia-admin/application/controllers/Calculate.php:150-312,source-refs/sanmopia-admin/application/models/Payment_model.php:26-32, andsource-refs/sanmopia-admin/application/models/Payment_model.php:2526-2563. Required proof staysPartial: no direct filesystem GET, no hidden POST-download hacks, no mutable-row rebuild without stored dataset revision, no branch/HQ leakage, and no artifact repair without immutable prior version, signed grant, audit entry, retry policy, and stale-save rejection. Backend foundation now addsSettlementStatement,SettlementRemittanceAccountSnapshot,SettlementTransitionAudit,SettlementStatementLineAcknowledgement,SettlementStatementManualRow,SettlementStatementCommandHandler, Supabase statement persistence, and FastAPI routes forRequestSettlementDeposit,AcknowledgeBranchSettlementDeposit,AddManualSettlementRow,ApproveHeadquartersSettlement, andRequestSettlementArrearsDeposit. Replayed branch acknowledgements, headquarters approvals, and arrears requests return the already committed statement instead of appending duplicate transition audits; reusing one idempotency key for a different command is a domain error before Supabase unique-key failure. Branch membership due now freezes monthly override/base fee evidence insanmopia_branch_membership_due_snapshotsbefore board opening, so opened boards no longer need to join mutableBRANCH_TB.MEMBERSHIP_PAY_PRICEorBRANCH_MEMBERSHIP_PAY_TB.PRICE.PromotionalCouponCostsource parity now lands insanmopia_branch_promotional_coupon_cost_snapshotsand feeds branch settlement CQRS calculation aspromotional_coupon_cost; deleted-coupon gift charges now come from versioned benefit-package rates and remaincancelled_gift_coupon_commission. Branch operator dashboard now exposessettlementStatusCounts, replacing sourcedetailStatusZero/couponStatusZerodashboard counters with domain status names. HQ branch filtering now uses theBranchProfilebranch_settlement_participationandis_activefacts instead of source branch id exclusions such as internal ids 36/37; the Supabase read adapter rejects non-participating branch profiles before returning branch operator board/dashboard projections.SettlementCompletionReviewnow consolidates membership due, delivery fee, cancelled gift coupon commission, unpaid detail rows, and unpaid coupon rows before central review closes as settled or arrears. Remaining work is automatic settlement calculation expansion, Restate export workflow worker wiring, repair-history UI, and operator UI. Implement order:HeadquartersSettlement,ExternalCounterpartySettlement, thenInterBranchSettlement. - Promotion admin: coupon, gift management/detail, partner benefit lead
admin, DB send logs, Excel download, delete lead APIs. Status:
Partial. Evidence:sanmopia-admin/application/controllers/Promotion.php,sanmopia-admin/application/controllers/Api.php,sanmopia-admin/application/models/Coupon_model.php,sanmopia-admin/application/models/Promotion_model.php,sanmopia-admin/application/models/Momfirst_model.php. Modern replacement: promotion entitlement rules/entitlements/fulfillment tables cover coupon and gift policy, issue state, and fulfillment request storage. Partner benefit leads now usesanmopia_mother_lead_*tables for policy, request, export batch, export item, and result-file tracking. Spreadsheet-style DB send screens still need the new admin UI implementation. - Data room/forms/documents/downloads/other posts/reservation Excel.
Status:
Partial. Evidence:sanmopia-admin/application/controllers/DataRoom.php,sanmopia-admin/application/controllers/ajax/DataRoom.php,sanmopia-admin/application/models/Data_room_model.php. Source-dig addition:DataRoom::downloadindex == 16expands a single selected reservation into a document bundle from hiddenreservation[service_type][id], posts throughiframe_download, deletes temp XLSX/PDF files after ZIP creation, maps voucher service to document ids1,3,4,5,6,20,7,8,9,10,11,15,17,21, and maps normal service to the same six document ids twice because raw ids and constants are both appended. Modern bundle export must derive service kind from a frozen reservation snapshot and versioned template catalog, not hidden UI input. Modern replacement:document_reporting/features/document_roomnow covers the non-reservation document room: branch/HQ post direction, target branch visibility, pinned windows, revisioned Strapi authoring, private Supabase Storagedocument-room-attachments, allowed attachment content types, retention, and parent-post RLS. Reservation document catalog/rendering remains underdocument-reporting; settlement and promotion application exports stay separate backlog slices instead of being kept inside a generic data-room bucket. - Reservation document delivery, signed download access, and
scheduled/manual document send attempts. Status:
Partial. Evidence:source-refs/sanmopia_web/application/controllers/MyReservation.php:352-372,source-refs/sanmopia_web/application/controllers/api/ReservationDocument.php:9-55,source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:19-132,source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:140-245,source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:254-621. Modern replacement:document_reporting/features/document_deliverynow owns deterministic backend domain/application coverage for reservation document delivery. Completed in this slice: signed access issuing command/use case with explicit issuer actor, recipient, render artifact id, delivery code, idempotency key, expected delivery revision, caller-supplied grant expiry, reason, abstractDocumentAccessReference, document definition key, artifact version key, delivery channel, and the mandatorydownload_document_artifactaction; scheduled start/end batch, manual resend, retry, and revoke attempt types are distinct; recipient-visible access history exposes active/expired/revoked state, document/artifact/channel/action scope, and no raw URLs or filesystem paths; delivery validation rejects mismatched reservation/document/artifact/channel grants; revoke idempotency, expected revisions, and recipient ownership guards are tested. Remaining gap: Supabase persistence/migrations for access grants, history, and expanded attempt types, signed-storage reference issuing adapter/route binding, scheduled start/end mail/Alimtalk workers, manual resend/revoke operator UX, and full source attachment/template parity. - Boards/clinic/common boards, category, posts. Status:
Partial. Evidence:sanmopia-admin/application/controllers/Board.php,sanmopia-admin/application/controllers/Clinic.php,sanmopia-admin/application/controllers/ajax/CommonBoard.php,sanmopia-admin/application/models/Board_model.php,sanmopia-admin/application/models/Board_category_model.php. Modern replacement: Admin common-board posting and health-education categories are absorbed bycustomer_engagement/features/contentandsanmopia_content_publications. Strapi supplies the OSS authoring surface, Supabase Storagecontent-assetsstores media, and the Sanmopia contract exposes stablehealth_education_expert_profile,health_education_article,health_education_video,health_education_faq, andhealth_education_visit_classkinds instead of category numbers. - Statistics and datatables: performance, sales, user connect, branch connect,
charts, table exports. Status:
Partial. Evidence:sanmopia-admin/application/controllers/Statistics.php,sanmopia-admin/application/controllers/Datatable.php,sanmopia-admin/application/models/Statistics_model.php,sanmopia-admin/application/models/Datatable_model.php,sanmopia-admin/static/js/statistics/performance.js,sanmopia-admin/static/js/statistics/sales.js,sanmopia-admin/static/js/statistics/user.js,sanmopia-admin/static/js/statistics/officeManager.js, andsanmopia-admin/static/js/datatables.js. Modern replacement:business_reporting/features/statisticsnow owns aggregate metrics and immutableBusinessReportSnapshotrows for dashboard/table readers. Supabase persistssanmopia_business_report_snapshotsplus export requests insanmopia_business_report_exports, with private artifacts inbusiness-report-exports. The replacement does not rebuild jQuery DataTables or spreadsheet controller code; frontend tables should use an OSS table layer such as TanStack Table, and file generation should read the captured snapshot so exports do not change after later policy edits. Source-mined queue: Admin Analytics And System Gap Mining. Explicit remaining feature status:BusinessReportCatalogPending,ScopedBusinessReportReadPolicyPartial,PerformanceDashboardSnapshotPending,SalesRevenueSnapshotPartial,MemberActivityAnalyticsPending,BranchAccessAnalyticsPending,CaregiverRecognitionReportPartial,OperatorReportTablePending,BusinessReportExportRequestPartial, andBusinessReportRefreshSchedulePartial(foundation only: domain schedule policy, run request contracts, idempotency, revision/window/catalog invalidation facts; persistence, API, runtime worker, and operator UI remain pending). - Price catalog workbook import: voucher/private-care price tables,
service-day rows, subsidy/customer charge/caregiver pay, additional charges,
in-home conversion, and future fee components. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/cli/Price.php:13-16passes year, consume-version, filename, type, and suffix directly into the workbook loader;source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4807-4894imports normal/private-care service price, customer share, and caregiver pay;source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4917-4974imports normal add-on option prices and per-service-day derived amounts;source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4983-5108imports voucher consume-type catalog rows;source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5136-5228validates/inserts voucher service price, government support, customer share, caregiver pay, and in-home conversion;source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5246-5330imports voucher add-on option rows; andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5337-5395creates or reuses the price-version row before dispatching normal/voucher imports. Seed workbooks still exist atsource-refs/sanmopia-admin/static/dist/excel/price/2025_normal_250121.xlsx,source-refs/sanmopia-admin/static/dist/excel/price/2025_voucher_250121.xlsx,source-refs/sanmopia-admin/static/dist/excel/price/2025_voucher_250827.xlsx,source-refs/sanmopia-admin/static/dist/excel/price/2026_normal_260119.xlsx,source-refs/sanmopia-admin/static/dist/excel/price/2026_voucher_251211.xlsx,source-refs/sanmopia-admin/static/dist/excel/price/2026_voucher_260119.xlsx, andsource-refs/sanmopia-price-table/2025년 바우처 요금 계산표_2025.01.19_입주 금액까지 모두 반영한 최종본(부가서비스 추가요금 포함) (1).xlsx. Payment-product seed evidence also crosses this catalog boundary:source-refs/sanmopia_web/application/models/Constdata_model.php:33-56maps payment type/status display strings to ids,source-refs/sanmopia_web/application/models/Payment_model.php:154-160seeds customer-share deposit, customer-share balance, and service-balance payment rows fromPRICE_TABLE, andsource-refs/sanmopia_web/application/models/Payment_model.php:772-777seeds pre-reservation payment fromPRICE_TABLE["realPrePrice"]. Modern replacement:pricing_settlement/features/price_catalog_importnow owns componentizedPriceCatalogEntryandPriceCatalogComponentvalidation. The workbook parser uses OSSopenpyxlat the adapter boundary. It reads modern open-ended headers such ascharge:<code>:<role>:<basis>and audits each voucher-care workbook independently instead of assuming one fixed entry count. Current parser results are2025_voucher_250121= 190 entries / 8 issues,2025_voucher_250827= 190 / 8,2026_voucher_251211= 154 / 0, and2026_voucher_260119= 143 / 55. The three issue-bearing workbooks are blocked. The older issue-free2026_voucher_251211workbook is not selected automatically: zero issues and recency do not establish approved source authority. Backend7a9d26eprovides the protected approval caller, but no source/version has actually been selected, approved, or invoked. Supabase stores original workbook artifacts in the privateprice-catalog-importsbucket, lifecycle rows insanmopia_price_catalog_import_batches, and immutable entries insanmopia_price_catalog_entries.price_catalog_quotenow reads only published, effective catalog entries, filters by program, service tier, day count, and criteria, then returns componentized quote lines withgross_service_priceandcustomer_sharerules that avoid double-counting the mother payable amount. Accepted quotes can now be captured into finalized charge snapshots throughPriceCatalogQuoteFinalizationPolicy; reference-only gross/subsidy lines are preserved without affecting the payable total, andMotherVisibleChargeSummaryreads the immutable snapshot after finalization. Remaining work: persist every legacy workbook variant as a Supabase catalog import batch with source filename/checksum/effective version metadata, finish private-care/general service import coverage, extend payment-product catalog references beyond customer-share deposit/balance to every production payment-product and quote component, and wire settlement readers to the Supabase catalog entries rather than PHPPRICE_TABLE-style maps. - System management: holidays, load history, cache, constants, FCM, KCP,
price-table import. Status:
Partial. Evidence:sanmopia-admin/application/controllers/ManageSystem.php,sanmopia-admin/application/controllers/ajax/ManageSystem.php,sanmopia-admin/application/controllers/cli/Cache.php,sanmopia-admin/application/controllers/cli/Fcm.php,sanmopia-admin/application/controllers/cli/Kcp.php,sanmopia-admin/application/controllers/cli/Price.php,sanmopia-admin/application/models/Manage_system_model.php,sanmopia-admin/application/models/Constdata_model.php,sanmopia-admin/application/models/Fcm_model.php. Modern replacement: System holiday management is split intoservice_calendarinstead of a generic system controller. Supabase stores national/branch holidays insanmopia_service_calendar_holidays, selected reservation extra-service dates insanmopia_reservation_extra_service_days, and immutable plan results insanmopia_reservation_service_calendar_plans. National holiday seed data can be generated through the OSSholidaysPython package, while branch-specific closures stay editable and RLS-scoped. Price-table import is now split intoprice_catalog_importwith private Supabase Storage and componentized catalog rows. Load history, cache, FCM, KCP, and remaining private-care/general price import coverage remain separate partial slices. Source holiday admin still has only global date rows; the branch-user branch is empty and the calendar Ajax endpoint returns only date strings, soBranchServiceClosurePolicymust be completed as a command/API/UI subfeature over the new source/effect/fingerprint model instead of a raw date CRUD page. Historical service-calendar compatibility is now a backend/contracted policy decision instead of a source-era duration branch: the backend exposesPOST /service-calendar-compatibility-decisions, derives the actor from Supabase Auth, requires branchviewpermission whenbranchProfileIdis supplied, and returnsuse_current_policy,preserve_source_service_end, orrequire_operator_reviewwith policy fingerprint and source reference. Stored impact projections now expose this persisted decision throughGET /reservation-service-calendar-impacts/{reservationBookingId}with optionalplanCodeandimpactKind, so pricing/report/scheduling/settlement consumers do not recalculate drift in UI code. Holiday publication and branch override impact preview is also backend-owned throughPOST /service-calendar-holiday-impact-previewsand the Supabase RPCsanmopia_list_service_calendar_holiday_impact_candidates, which lists affected reservation plan ids, branch ids, service dates, and follow-up impact kinds before operators commit or repair calendar policy. Holiday add/modify/delete intent is now normalized throughPOST /service-calendar-holiday-change-decisions, backed by activesanmopia_service_calendar_holidaysrows, so source duplicate-date alerts become backend decisions (requires_policy_revision,requires_policy_selection, accepted revision, or accepted withdrawal) with existing policy ids. Remaining calendar migration work is binding every reservation creation/change path to snapshot persistence, duration-mode evidence storage, and consumer adoption for pricing, reports, caregiver scheduling, settlement, and refund. Source-mined queue: Admin Analytics And System Gap Mining. Explicit remaining feature status:PriceCatalogImportExecutionPartial,ServiceCalendarHolidayPublicationPartial,ServiceCalendarHolidayAuditPartial(backend now models actor/reason/idempotency/expected-revision/effective-date audit revisions, branch override audit, and provider evidence reference/fingerprint without raw spreadsheet rows. Supabase runtime tablessanmopia_service_calendar_holiday_auditsandsanmopia_service_calendar_holiday_audit_revisionspersist snapshots and append-only revisions with RLS, while SpiceDB-protected APIsPOST /service-calendar-holiday-publication-decisionsandPOST /branch-service-calendar-holiday-overridesexpose headquarters publication and branch override commands through generated contract schemas. The backend composition root now wires both routes into the runtime FastAPI app. The same runtime now wiresPOST /service-calendar-holiday-impact-previews, backed by a service-role Supabase RPC that previews affected reservations and follow-up impact kinds before a holiday publication or branch closure override is committed. Duplicate-date and add/edit/delete normalization is backend-owned throughPOST /service-calendar-holiday-change-decisions, which reads activesanmopia_service_calendar_holidaysrows and returns policy-level decisions instead of allowing UI-side date CRUD or alerts to control policy. OpenAPI route proof is covered bymain_test.py, so these are not test-only interfaces. Remaining work: OSSholidaysprovider import execution, operator UI, accepted-decision execution, and publication workflow repair/replay screens), andSourceEvidencePathReconciliationPartial(foundation only: domain aggregate and application contracts now model actor/reason/idempotency, expected revision, source path fingerprints, canonical reference decisions, aliases, duplicate findings, and missing-path findings from supplied docs or source snapshots without requiring the source tree at runtime; remaining work is CLI scanner integration, generated docs wiring, and checklist/gap-mining reconciliation reports). Requested source pathsource-refs/sanmopia-admin/application/controllers/Load.phpwas not present in the evidence tree; nearby load-history evidence resolves throughManageSystem.php:33-40and price import execution. - WinTheRace branch/manager ranking, year cache, manager stop, score/class
recalculation. Status:
Partial. Modern slice:caregiver-performance-recognitionnow owns versioned performance seasons, metric rules, grade thresholds, scorecards, contribution facts, manual adjustments, competition ranking, and branch tag eligibility. Foundation update:caregiver_performance_recognition/features/performance_seasonreplaces the yearly cache/ranking concept with versionedCaregiverPerformanceSeasonandCaregiverPerformanceMetricRuleobjects, explicitCaregiverRankingTiePolicy, auditableCaregiverPerformanceManualAdjustment, immutableCaregiverPerformancePublicationsnapshots, andCaregiverVisibleSeasonHistoryscope checks. Remaining gap: Supabase persistence, API/HTTP bindings, manager/caregiver frontend, runtime authorization proof, scheduled publication workflow, and production metric threshold configuration. Evidence:sanmopia-admin/application/controllers/cli/Manager.php,sanmopia-admin/application/models/Manager_class_model.php,sanmopia-admin/application/models/Manager_event_model.php,sanmopia-manager/application/controllers/WinTheRace.php,sanmopia-manager/application/models/Win_the_race_model.php.
Caregiver Manager App
Section titled “Caregiver Manager App”- Manager login/apply/signup/profile/account/career/education/health/sign.
Status:
Partial. Evidence:sanmopia-manager/application/controllers/Login.php,sanmopia-manager/application/controllers/User.php,sanmopia-manager/application/models/Auth_model.php,sanmopia-manager/application/models/User_model.php. - Caregiver credential evidence, availability blocks, profile media, account
security, and office request intake. Status:
Pending. Evidence:source-refs/sanmopia-manager/application/controllers/User.php:242-439,source-refs/sanmopia-manager/application/controllers/User.php:442-710,source-refs/sanmopia-manager/application/controllers/User.php:716-854,source-refs/sanmopia-manager/application/models/User_model.php:290-982. Modern replacement:caregiver_profile/features/self_service_profileshould ownCaregiverCredentialEvidence,CaregiverUnavailablePeriod,CaregiverProfileMedia,CaregiverSignatureAsset,CaregiverAccountCredential, andCaregiverOfficeRequest. Bank account facts must hand off to caregiver compensation instead of remaining only profile data. The same slice should cover self-service greeting, address correction, password change, push-token registration, and account hardening; request threads still belong tocaregiver_engagement/features/caregiver_request. - Manager reservation data/detail, schedule main/info, matching data/pages.
Status:
Partial. Evidence:sanmopia-manager/application/controllers/Reservation.php,sanmopia-manager/application/controllers/Schedule.php,sanmopia-manager/application/controllers/Matching.php,sanmopia-manager/application/models/Reservation_model.php,sanmopia-manager/application/models/Matching_model.php. Modern replacement: Care-manager portal status visibility is assignment-scoped and time-bounded. The source schedule/detail flow checks assigned caregiver ownership, exposes proceeding/completed schedule tabs, blocks detail access after 90 days, and splits main-caregiver and sub-caregiver service/report data. Source evidence:sanmopia-manager/application/controllers/Schedule.php:14-24,sanmopia-manager/application/controllers/Schedule.php:33-49, andsanmopia-manager/application/controllers/Schedule.php:57-75. Modern read models must show workflow stage, service-period window, attendance/report obligations, payment/payout status, and active blocks for the signed-in caregiver role without leaking HQ/branch-only workflow detail. - Caregiver matching preference profile and personality answers. Status:
Partial. Evidence:source-refs/sanmopia-manager/application/controllers/Matching.php:43-65,source-refs/sanmopia-manager/application/controllers/Matching.php:68-134,source-refs/sanmopia-manager/application/models/Matching_model.php:11-200. Modern replacement:caregiver_assignment/features/caregiver_matching_profileshould ownCaregiverMatchingProfile,CaregiverPetCareConstraint,CaregiverServicePreference,CaregiverPersonalityAnswer, andCaregiverPreferenceVersion, then feed assignment optimization without exposing source answer ids to contracts. Backend foundation added undercaregiver_assignment/features/caregiver_matching_profilewith versioned preference mutations, pet/service/personality domain values, application payloads, stale expected-revision protection, and genericMatchingPreferenceCompatibilitySignaloptimization input. Remaining proof: persistence/import mapping and live assignment optimizer integration. - Attendance recording and service-day work report. Status:
Partial. Evidence:sanmopia-manager/application/controllers/Attendance.php,sanmopia-manager/application/controllers/Service.php,sanmopia-manager/application/models/Attendance_model.php,sanmopia-manager/application/models/Report_model.php. Modern replacement:care_delivery/features/service_day_attendancerecords attendance as a reservation/caregiver/service-date ledger.care_delivery/features/daily_care_reportreplaces caregiver daily report PHP view fields with Strapi-authored form definitions, service-date lock validation, and Supabase-backed answer submissions.care_delivery/features/service_record_submissionnow separates the service record form from daily reports and models primary vs assistant caregiver identity, source duplicate replay, respiratory/temperature attestations, service-date access window, route date, sequential write action, correction revision, and attendance outbox handoff. Source service record writer usesMANAGER_SERVICE_TBandMANAGER_SUB_SERVICE_TB; schedule read paths also reference mismatchedSUB_MANAGER_SERVICE_TB, andSUB_READ_FLhas no matching writer. Remaining gap: Supabase persistence/API, caregiver portal wiring, newborn bootstrap facts, attendance idempotency by contract assignment key, customer notification outbox execution, and printable snapshots. See Manager And Customer Portal Gap Mining. - Daily report forms, report save, notify linkage. Status:
Partial. Evidence:sanmopia-manager/application/controllers/Report.php,sanmopia-manager/application/views/service/service.php,sanmopia-manager/application/controllers/Notify.php,sanmopia-manager/application/models/Notify_model.php,sanmopia-manager/application/models/Report_model.php. Modern replacement:care_delivery/features/daily_care_reportowns report definition validation, submitted answer validation, submission identity, and Supabase RLS. Strapi authorssanmopia_daily_care_report_definitions; caregivers submitsanmopia_daily_care_report_submissions; document rendering later consumes these submissions for printable A4 report series. Remaining gap:notification_obligation_dispatchnow adds backend-owned work-queue rows with dispatch/retry/dead-letter/suppress/repair actions, attempt count, retry due time, and last provider code/status. Remaining gap: Supabase persistence, queue worker binding, first/progress/last lock policy, notification read state separation, service-record submission persistence/API, and frozen report snapshots for A4 document rendering. See Manager And Customer Portal Gap Mining. - Manager notifications, push jobs, birth-information reminders. Status:
Partial. Evidence:sanmopia-manager/application/controllers/cli/Fcm.php,sanmopia-manager/application/controllers/cli/push/Reservation_baby.php,sanmopia-manager/application/models/Fcm_model.php,sanmopia-manager/application/models/Reservation_baby_model.php. Modern replacement:customer_engagement/features/communication_deliverynow covers manager daily-report/service-record notifications and generic push delivery through Novu-backed dispatch.reservation_operations/features/birth_informationreplaces the birth-information reminder withReservationBirthProfile, unbounded child records,BirthInformationReminderPolicy, andBirthInformationReminderTaskpersistence. Supabase Cron/Queues schedule due tasks, Novu sendsbirth_information_requested, and Strapi/Novu own workflow authoring instead of handmade FCM sender code. Source FCM jobs still prove a missing backend repair model: per-token provider results were raw responses without durable attempt/dead-letter/replay state, and manual issue commands scanned missing report/service notifications up to today without pushing. Current source rules: notify generation insertsREPORT_FIRST,REPORT_PROGRESS,REPORT_LAST, andSERVICE; current first/progress/last and service-record queries include statuses0,3,4,5,6,11,12and exclude status13, while historical repair helpers include13and hardcode2021-08-31 07:00:00/2021-09-01 07:00:00. Modern backend now derives dispatch/retry/dead-letter/suppress/repair work-queue actions from domain state; remaining proof is Supabase persistence, queue worker execution, provider attempt audit storage, and operator route wiring. - Caregiver education, notices, event notices, office request flow, news,
referral, and event participation. Status:
Partial. Evidence:sanmopia-manager/application/controllers/Other.php,sanmopia-manager/application/controllers/User.php:102-160,sanmopia-manager/application/controllers/User.php:957-972,sanmopia-manager/application/controllers/Other.php:24-87,sanmopia-manager/application/controllers/Other.php:298-418,sanmopia-manager/application/models/Education_model.php,sanmopia-manager/application/models/Notice_model.php,sanmopia-manager/application/models/Request_model.php. Admin answer evidence:source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:1158-1230,source-refs/sanmopia-admin/application/models/Faq_model.php:86-112,source-refs/sanmopia-admin/static/js/manager/manager_request_view.js:20-50. Modern replacement:caregiver_engagement/features/portal_contentshould consumeCaregiverContentInbox,CaregiverLearningMaterial,CaregiverEventNotice, andCaregiverNewsPublicationfrom the branch office content catalog.caregiver_engagement/features/caregiver_requestshould ownCaregiverOfficeRequestThread,CaregiverReferralLead, andCaregiverEventParticipation. It must preserve portal UX for branch-scoped education schedules, study materials, referral entry, HQ request list/detail edit/delete, and surprise-event/event-notice participation. Admin authoring is partly covered by branch-office content; caregiver-facing inbox, request status, referral notification, and event workflow remain incomplete. The office request answer path now has a modern backend/contract slice:caregiver_engagement/features/caregiver_office_requestownsCaregiverOfficeRequestThread, andcaregiver_engagement/features/caregiver_office_request_answerplansCaregiverOfficeRequestAnswerIntentPlanwith branch-profile authorization, expected revision conflict protection, idempotent answer mutation, and provider-neutralcaregiver_office_request:answered_caregiverdispatch. This replaces legacy UI-side blank checks, ambiguousbranch_indexrequest identity, directMANAGER_REQUEST_TBmutation, and raw cURLpushRequestAnswercalls. Remaining work: Supabase table/RLS persistence, API route wiring, caregiver portal rendering, branch/HQ operator screen binding, and outbox worker execution. - Manager salary/payout/tax info and sub-manager support. Status:
Partial. Modern slice:caregiver-compensationnow quotes multiple caregivers per reservation by role, handoff order, grade, service-day source, rate rule, policy version, override, withholding, and builds payout instructions with bank-account and tax-evidence references persisted in Supabase throughIssueReservationCaregiverPayoutInstructionsHandlerandSupabaseReservationCaregiverPayoutInstructionStore; settlement continuation consumes payout instructions instead of raw quote lines.CareTeamContractnow feeds compensation quote seeds directly throughQuoteCareTeamCaregiverCompensationCommand, removing the need for UI or PHP screens to rebuild primary/sub caregiver role, handoff order, grade, and service-day facts before salary quote.SupabaseCareTeamCompensationSourceReaderreads assigned rows fromsanmopia_reservation_caregiver_assignmentsinto ordered compensation source facts and fails closed on missing grade or fractional planned days. Authenticated/care-team-compensation-sources/{reservationBookingId}now uses a caller-token reader factory so Supabase RLS scopes reads by the active user instead of backend service-role leakage. Runtime composition now attaches the route throughbuild_sanmopia_backend_app_from_env()and prefersSUPABASE_PUBLISHABLE_KEY/SUPABASE_ANON_KEYfor caller-JWT Data API reads when configured. Destination change proof now persists previous/adjusted bank-account and tax-evidence snapshots throughCaregiverPayoutDestinationChangeAudit; branch-deposit acknowledgement now uses backend payout-slot identity with caregiver role and handoff order for sourceSORT > 0assistant rows. Remaining work is manager-facing salary/payout UX, tax formula explainability, and full sub-manager operational screens. Source salary rules include voucher special/live-in additional pay, pure voucher additional service charge, Saturday/holiday options, custom service-balance-as-salary, main/sub custom salary override, four-insurance versus business-income withholding, and final-day visibility in the manager pay detail. Modern ubiquitous names areCaregiverCompensationQuote,CaregiverPayoutInstruction,CaregiverTaxElection,CaregiverSalaryOverride, andSubCaregiverCompensationShare.CaregiverPayoutStatementnow projects manager-facing salary/payout/tax lines from frozen quote and instruction facts, including ordered assignment keys, caregiver role, handoff order, grade/rate rule, service-day basis, gross pay, voucher/add-on adjustments, custom service balance, main/sub custom pay, tax election/withholding, net payable, bank-account snapshot, and receipt state. The statement also emits ordered display lines with final labels, row amounts, after-tax totals, voucher/additional totals, custom-pay rows, tax-election state, receipt/exception/repair state, and bank/tax evidence display state, so frontend clients render these rows without recomputing caregiver pay, tax, net, balance, or receipt values.CaregiverPayoutReadModelnow projects caregiver-facing rows from frozen payout statements plus branch deposit acknowledgement and receipt state, masks account display, owns available receipt actions, and rejects caregiver scope mismatch in the application query payload. This covers manager pay list and detail read behavior without calling sourcecalcSalaryin controller, PHP view, or JS.CaregiverPayoutReceiptStatecommands now cover caregiver receipt acknowledgement plus payout exception/repair with actor, idempotency key, expected revision, reason, and caller-supplied occurred-at; reused idempotency keys with changed command intent are rejected. Tax withholding rates and tax terms are supplied as explicit policy/version or assignment-key inputs rather than baked into domain defaults; absent compensation memo is represented asNone, not a domain-level empty-string constant. Compensation inputs now key recorded service days, add-ons, amount basis, overrides, terms, payout destinations, and statement joins bycontract_assignment_key, so one caregiver can have multiple contract terms without collision. Source UI arithmetic is evidence only; payout totals are projected from frozen backend facts and explicit versioned policy inputs. Application inbound commands in this slice are PydanticApplicationContractModelpayloads, while domain objects remain dataclasses. Backend persistence now records acknowledgement facts, revisioned receipt-state events, current receipt projections, append-only amount/tax/memo adjustment audits, and append-only payout destination change audits in Supabase; payout read projections now match branch-deposit acknowledgement by role-and-handoff payout slot for sourceSORT > 0assistant rows.CaregiverPayoutOperatorIntentPlannow covers branch-operator custom net-pay adjustment, custom reset, memo record, and deposit completion by freezing the adjusted amount/tax/memo snapshot before emitting branch payout-deposit acknowledgement. This moves sourcemanager_pay_detail.jsUI-side amount/tax/memo/deposit decisions andReservation_modelpayment-row mutations behind one backend-owned intent boundary with actor profile, expected adjustment revision, idempotency, and source-evidence keys. Remaining gaps are manager/branch/HQ UX, Supabase API binding for the operator intent endpoint, and full sub-manager operational screens. Hidden source rules still tracked for migration: payment type ids3and5, tax type ids0and1, JS tax rate0.033, date fork2022-03-29 00:00:00, Korean service strings, andSORT == 0parent-vs-SORT > 0assistant row split. 2026-07-05 persistent-agent salary source-dig strengthening: sourcesource-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:14-24and:155-231posts browser-calculated payout amount plus tax type, whilesource-refs/sanmopia-admin/static/js/manager/manager_pay_detail_test.js:19-35and:207-255adds a saved-custom-price completion guard that livemanager_pay_detail.php:627-644does not load. Sourcesource-refs/sanmopia-admin/application/controllers/Manager.php:1133-1182,:1225-1235, and:1300-1335forwards browser amount/tax/manager ids into payout mutation paths;source-refs/sanmopia-admin/application/models/Reservation_model.php:2627-2650,:2747-2803, and:2945-3036then performs branch ownership checks after payment-row mutation in some paths and wraps custom-price results as success. Backend command handling must validate actor/branch scope, payout-slot identity, expected revision, amount basis, tax policy version, completion prerequisite, and idempotency before any salary/custom-price/deposit mutation. Sourcesource-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:575-588andsource-refs/sanmopia-admin/application/views/manager/manager_pay_detail_test.php:523-530callrefresh()without a reservation id, whilesource-refs/sanmopia-admin/application/controllers/Manager.php:1238-1272continues from sub-caregiver reset into main reset afterupdateSubCustomPriceRefresh(). ModernCaregiverSalaryOverrideResetCommandmust target exactly one payout slot and reject missing reservation/payout statement ids instead of silently resetting aggregate payment rows. ModernCaregiverSalaryOverrideResetPlannow targets onecontract_assignment_keyplus caregiver role/handoff order and emits aCaregiverPayoutAdjustmentAuditRequestfrom current snapshot to backend default snapshot with actor profile, expected adjustment revision, idempotency, and source evidence. Contract tests reject no-op resets and prevent legacyCUSTOM_PRICE/SUB_CUSTOM_PRICE/PAYMENT_BRANCH_MANAGER_TBvocabulary from leaking into the new reset plan. Sourcesource-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:234-260andsource-refs/sanmopia-admin/application/models/Reservation_model.php:2573-2624changes sub-manager service-balance status by reservation id only and updates aggregateSUB_*flags, so modernSubCaregiverServiceBalanceAcknowledgementmust key by caregiver role, handoff order, assignment term, and payout statement revision. Sourcesource-refs/sanmopia-manager/static/js/other/pay_info.js:1-88,source-refs/sanmopia-manager/application/controllers/User.php:163-239, andsource-refs/sanmopia-manager/application/models/User_model.php:114-154show caregiver self-service bank-account writes mutate live global account rows; payout statements must keep destination snapshots and append-onlyCaregiverPayoutDestinationChangeAuditevidence instead of dereferencing the latest account row at settlement or receipt time. Settlement-overlap evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:2237-2271computes Danbee board summary counts in PHP and assignsNORMAL_COUNTfromVOUCHER_COUNT + 1, while:2317-2366uses a different count formula for branch history. ModernSettlementDataRoomCollectionSummarymust persist dataset/projection revisions and derive normal/voucher/confirmed counts from one backend read model, not per-screen PHP loops. Modern domain/application/contracts now add collection summary count facts:reservation_count,normal_service_count,voucher_service_count,settlement_confirmed_reservation_count, andsummary_formula_code. The summary invariant rejects UI-side count drift where total reservations do not equal normal plus voucher counts or confirmed reservations exceed total reservations. Contract payloads expose these backend-owned counts without legacyNORMAL_COUNT/VOUCHER_COUNT/CONFIRM_COUNTnames. Evidence:sanmopia-manager/application/helpers/salary_helper.php:8-227,sanmopia-admin/application/models/Reservation_manager_salary_model.php:21-180,sanmopia-manager/application/controllers/Other.php:223-294,sanmopia-manager/application/models/Reservation_model.php:13-78,sanmopia-manager/application/models/Reservation_model.php:352-410,sanmopia-manager/application/models/Reservation_model.php:488-516,sanmopia-admin/application/controllers/Manager.php:1133-1236,sanmopia-admin/application/controllers/Manager.php:1810-1945,sanmopia-admin/application/models/Manager_model.php:377-590,sanmopia-admin/application/models/Reservation_model.php:2945-3036,sanmopia-admin/static/js/manager/manager_pay_detail.js:1-260,sanmopia-admin/static/js/manager/manager_pay_detail_test.js:1-310,sanmopia-manager/application/views/pay_info.php:31-126,sanmopia-manager/application/views/pay_info_detail.php:165-263,sanmopia-admin/application/models/Reservation_model.php:2747-3130. - Manager WinTheRace view. Status:
Partial. Modern slice:caregiver-performance-recognitionexposes caregiver-visible performance scorecards through contracts; the performance-season foundation now defines publishedCaregiverPerformanceSeasonScorecardsnapshots, visible season history, tie-policy ranking, and manual adjustment audit without exposing raw fact references. Remaining gap: Supabase persistence, API/HTTP bindings, manager/caregiver frontend, runtime authorization proof, scheduled publication workflow, and production metric threshold configuration. Evidence:sanmopia-manager/application/controllers/WinTheRace.php,sanmopia-manager/application/models/Win_the_race_model.php.
Native Shell And Platform
Section titled “Native Shell And Platform”- Mother Android webview shell: splash, Kakao SDK, native bridge, payment
scheme, push message service. Status:
Pending. Evidence:sanmopia_android/app/src/main/java/com/sanmopia/app/*. - Mother iOS webview shell and Kakao framework integration. Status:
Pending. Evidence:sanmopia_ios/ios_sanmopia_app/*,sanmopia_ios/KakaoOpenSDK.framework/*. - Manager Android shell. Status:
Pending. Evidence:sanmopia_manager_android/app/src/main/*. - Source Docker/database/price-table import parity. Status:
Partial. Evidence:sanmopia-docker/*,sanmopia-price-table/*,sanmopia-admin/application/controllers/cli/Price.php. Modern replacement: Stage/runtime infra is managed through repo SSOT and Traefik/Mutagen development flows. The stage now includes self-hosted Supabase core services (db,auth,rest,realtime,storage,imgproxy,kong) instead of only pointing env vars at missingdb/konghosts. Price workbook import uses the Supabase-firstprice_catalog_importslice rather than PHP CLI table mutation. Supabase Postgres initialization now follows the self-hosted image contract by preserving the image defaultPOSTGRES_USER=supabase_admin; stage recovery docs explain how to reset only broken local Supabase volumes. Stage migrations now use a private migration ledger, and JWT key signatures are checked before Kong/PostgREST runtime use.
Modern Replacement Tracking
Section titled “Modern Replacement Tracking”- Identity and RBAC end-to-end: Supabase Auth, app metadata roles, branch
memberships, SpiceDB relationships, actor-stage permissions. Status:
Partial. Source gap:source-refs/sanmopia-admin/application/controllers/Administrator.php:109-170still proves legacy operator identity is only three coarse session types, whilesource-refs/sanmopia-admin/application/core/MY_Controller.php:113-116exposes that sessiontypedirectly to controllers. Modern migration must keepmother,caregiver,branch_operator,hq_admin, and partner/provider operators as capability-bearing actors, not route-level PHP session strings. Reservation authorization now exposes a backend capability snapshot that combines stage policy with SpiceDB relationship checks. The snapshot carries per-capabilitystage_allowed,relationship_allowed,allowed, andreason, whilesubmit_booking_requestchecks branchmanagebefore a reservation row exists. Shared workflow status responses now includereservationStatusandreservationCapabilityAuthorizationfor reservation booking projections. 2026-07-06 architecture-docs audit: C4 and DDD docs now require explicit actor coverage for mother, family payer, caregiver, branch manager, headquarters admin, and settlement approver. New or changed backend slices must state whether each actor can command, read, approve, or only receive notifications. Family payer remains a delegated payment-authority fact, not an emergency-contact relation; settlement approver remains a headquarters approval capability, not a separate route/login role. - Mother booking operational context. Status:
Stage smoke complete. Frontend no longer fabricates branch, caregiver, payment, or pricing facts. Contract packages now defineMotherBookingOperationalContextand/mother-booking-operational-context; backend now reads that endpoint from the versioned Supabasesanmopia_mother_booking_operational_contextsread model. Stage smoke signs in a Supabase Auth mother, branch operator, and caregiver, upserts profile identity rows and context through service-role Data API, touches the SpiceDB branch-operator relationship, verifies the backend context endpoint with the issued bearer token, startsReservationBookingWorkflow, and verifies the Supabase workflow request reachescompletedthrough the progress API. Rechecked 2026-07-07 with focused local proof:tests/integration/reservation_smoke_path_test.py,reservation_booking/booking_test.py,interfaces/reservation_booking_http_test.py,interfaces/reservation_booking_restate_service_test.py, andadapters/reservation_booking/supabase_booking_workflow_test.pyall pass. - Workflow state orchestration end-to-end: reservation lifecycle, settlement
closeout, and member withdrawal/privacy retention use Restate for orchestration,
retry, and idempotency. Supabase remains the durable ledger/read/RLS layer;
SpiceDB remains ReBAC; OPA owns legal/status/context policy gates; OpenFGA is
not part of the migration stack. Status:
Partial. Reservation booking workflow start/progress is wired to Restate, acceptsacceptedPriceCatalogQuoteplus care-environment matching facts, and recordsfinalized_charge_snapshot_idinsanmopia_reservation_booking_workflow_requests; backend exposes the Restate Python SDK deployment at/restate/v1for stage registration. Stage booking smoke now runs context read, start, Restate execution, and progress read through self-hosted Supabase, SpiceDB, and Restate; local stage uses an explicit debug payment gateway client while production remains Kill Bill-only. Booking result persistence now uses the transactional Supabase RPCsanmopia_save_reservation_booking_resultinstead of multiple Data API upserts, so reservation booking, payment record, finalized charge snapshot, charge lines, and financial lifecycle persist atomically. The latest stage smokeRBQ-SMOKE-20260704-003completed the workflow and wrotepayment_product_plan_codeintosanmopia_payment_records, closing the prior Data API 400 failure and partial-write risk from a missing required plan code. The 2026-07-07 local verification also passeduv run tach check, so the booking workflow remains inside the declared bounded-context and adapter/interface boundaries. Caregiver matching now preservescareEnvironment,acceptsPetHousehold, andpetAllergySpeciesCodesacross mother booking context, workflow start contracts, backend API mapping, and Supabase read-model parsing; selected caregivers must pass the same policy as smart-matching candidates before booking continues. Branch-wide multi-reservation optimization now has an OR-Tools CP-SAT adapter that solves primary caregiver assignment across overlapping booking demands with capacity constraints and explicit unassigned-demand reasons. The applicationOptimizeCaregiverAssignmentsHandlervalidates branch actor scope before solver execution, so branch operators cannot ask the optimizer to assign out-of-scope caregivers. Source evidence:source-refs/sanmopia-admin/application/models/Matching_model.php:45-180,source-refs/sanmopia-admin/application/models/Matching_model.php:724-850,source-refs/sanmopia-admin/application/models/Reservation_model.php:57-110,source-refs/sanmopia-admin/application/models/Reservation_model.php:2165-2300. Assignment optimizer inputs now prepare cached travel-time freshness, fairness/rotation workload, replacement continuity from primary/sub caregiver change logs, assistant caregiver slot/SORT constraints, branch scope, and backend-owned score/cost components before solver execution. Active caregiver matching policy read exposure now comes fromGET /caregiver-matching-policies/activeand the TS contract path helper. Requested named-caregiver decisions now shareCaregiverCandidateFitpolicy logic and expose uplift/consultation/reject outputs through Python and TS contracts. Remaining matching gap: persist optimizer and named-caregiver facts in Supabase, feed prepared inputs into the OR-Tools adapter, expose a branch/HQ planning API, and bind assignment commands to selected policy versions. Reservation operation command boards now have a backend foundation throughReservationOperationCommandPolicy,ReservationOperationCommandHandler, and Pydantic command/plan payloads. The policy now delegates the changing stage/condition matrix toReservationOperationCommandRuleCatalog, uses command names instead of source numeric status ids, reports missing facts before schedule confirmation, cancellation, extension, settlement, and completion, and emits follow-up actions for gift coupons, other-area refresh, mother cancellation notices, extension payment requests, branch settlement workflow opening, financial lifecycle closeout, virtual-account deposit closeout, caregiver assignment, attendance, care delivery, daily care report, service-balance receipt, and price-version changes. Supabase now stores backend-only command contexts and plan ledgers insanmopia_reservation_operation_contextsandsanmopia_reservation_operation_plans; branch/HQ APIs apply Supabase Auth plus SpiceDB command permissions. Supabase CLI is pinned in the backend repo, stage migrations are pushed throughpnpm run supabase:db:push:stage, schema lint usespnpm run supabase:db:lint:stage, andpnpm run supabase:types:stageregeneratessupabase/generated/database.types.tsso frontend/contract consumers can use generated Supabase table shapes instead of handwritten table contracts. Follow-up actions now haveReservationOperationFollowUpWorkflowon Restate, backend-only Supabase request/action ledgers, workflow status projection kindreservation_operation_follow_up, and command responses can returnfollowUpWorkflowRequestId. Shared Supabase workflow row normalization lives in the application platform helper so booking, payment, financial lifecycle, operation follow-up, and projection adapters do not duplicate status/json/date parsing. The persisted state-write layer now has a separateReservationStateTransitionPolicyand Pydantic contract slice. Customer cancel/change/stop/extension requests, deposit/pre-reservation virtual-account request/confirmation/expiry, card/deposit completion, cron auto-confirm/start/ settlement/completion, and branch/HQ approval triggers resolve through effective-datedReservationStateTransitionCatalogrules with guard facts such as manager assignment, deposit confirmation, service-schedule lock, service-start/end windows, no-unpaid-customer-payment, approval records, refund closeout, and settlement-ledger creation. Contracts expose stable state codes such aswaiting_depositandpre_reservation_waiting_depositinstead of raw status numbers, so UI/payment workers cannot choose persisted status ids locally.ReservationOperationCommandHandlernow resolves and rejects persisted-state transition decisions for schedule confirmation, virtual-account deposit/expiry, and source-request commands before recording the operation plan.stop_requestedis now a first-class lifecycle status before operator stop approval, instead of jumping straight tostopped. Remaining operation gap: expose reservation collaboration OpenAPI/TypeScript client routes, attach the frontend operation board to the generated collaboration client, wire Nanostores stale-state/conflict/Presence state, persist transition decisions in a dedicated Supabase ledger, implement every follow-up effect against its target feature slice, and feed richer pricing/ payment/matching facts into the command context. Financial lifecycle stage commands are API-backed and Supabase-persisted; settlement closeout now hasReservationFinancialLifecycleWorkflowfor Restate orchestration.ReservationPaymentWorkflownow runs Kill Bill paid-payment verification, cancel, and refund through the same Restate deployment, with public start/progress APIs and a backend-only Supabase workflow ledger. Paid-payment verification also finalizes or confirms the approved charge handoff before the workflow completes. Financial lifecycle workflow progress is now exposed through backend API and a backend-only Supabase ledger.MemberPrivacyLifecycleWorkflowis registered on the same deployment and now advancessanmopia_member_privacy_lifecyclesworkflow status, pauses for operator review, or masks both the Supabase Auth account and member profile before completing. A sharedWorkflowStatusProjectionendpoint now covers reservation booking, payment, financial lifecycle, and privacy workflows, uses Supabase bearer authentication, and filters reads through same-user ids plus SpiceDB permissions. Branch settlement now hasBranchSettlementOperatorBoardandBranchSettlementOperatorDashboardquery contracts and backend read models, plusBranchSettlementReconciliationExportexport-ready datasets and stored artifact commands, using Supabase settlement rows, financial lifecycle workflow rows, SpiceDB branchsettlechecks, business-report snapshots, business-report export metadata, private Supabase Storage objects, andBranchSettlementReconciliationExportWorkflowstarts that send frozen export datasets to Restate for delayed rendering. Export workflow requests are now persisted in the same business-report export read model and exposed through the shared workflow status projection asbranch_settlement_reconciliation_export. Backend repair endpoints now retry failed/cancelled export workflows from the frozen snapshot and cancel unfinished export workflows with Supabase repair audit fields. Frontend settlement/export reads no longer carry branch/export tokens in URLs; branch scope comes from authenticated reads and download access comes from signed handoff responses. Member withdrawal now separates statutory retained-record snapshots intosanmopia_member_retained_record_snapshotsand schedules delayed purge tasks insanmopia_member_privacy_purge_tasksbefore masking Auth/profile data.MemberPrivacyPurgeWorkflownow claims due purge tasks, redacts retained snapshot payloads, and completes or fails the purge ledger with execution summary evidence. Due purge workflow triggering is now exposed as the internal token-guarded backend routePOST /internal/member-privacy-purge-workflow-triggers; Supabase Cron binds to that route throughpg_cronandpg_net, with runtime settings configured bypnpm supabase:cron:configure. Already-issued access JWTs are rejected by backend Auth metadata checks and a restrictive Supabase RLS guard after withdrawal masking lands. Operator repair-history backend foundation now models failed masking, token revocation, retained snapshot, delayed purge scheduling, and storage cleanup repairs with actor/reason/idempotency, expected revision, append-only status transitions, result audit, and protected retention guards. Remaining work is frontend repair controls, runtime worker binding, Supabase persistence, Cron request-history smoke, and live stale-token rejection smoke. The shared projection includesworkflowRequestId, workflow kind, actor user id/role, command name, source portal, business entity id, durable step, public status, actor-stage capabilities, failure/retry state, blocked reason, started/completed timestamps, and resulting read-model ids. Mother, caregiver, branch, and HQ portals should poll filtered views of that projection instead of duplicating or depending on Restate internals. - Member privacy lifecycle end-to-end: withdrawal, active-reservation guard,
개인정보 보호법 제21조 separated retention, 전자상거래법 시행령 제6조 trade-record
retention, 국세기본법 제85조의3 tax evidence retention, 사회서비스 제공자료 5-year
retention, masking/anonymization, delayed purge, sensitive correction audit,
and retained-data export proof. Status:
Partial. Legacy evidence:source-refs/sanmopia_web/application/controllers/Withdraw.php:18-84mutatesUSER_TB, blanks voucher resident-number fields, and deletes tokens inside one controller transaction; it also reads$user->EMAILafter selecting onlyUSER_ID_PK,PASSWORD, andAUTH_TOKEN, so the source cannot be treated as correct behavior. Required proof: withdrawal must run through aMemberWithdrawalRequestandMemberRetainedRecordSnapshotworkflow with active-reservation blocking, statutory retention classification, token revocation, Supabase Auth metadata masking, voucher identifier purge, idempotent retry, and append-only audit. Direct profile mutation or hard delete must not be allowed to remove reservation/settlement/report evidence. - Reservation lifecycle end-to-end: mother request, branch admin, caregiver
assignment, service delivery, status transitions, cancellation, extension,
offline/manual cases. Status:
Partial. Service-calendar planning for end dates, holiday skips, selected extra Saturdays/holidays, and branch-specific closures is now migrated as a backend/domain/contract/Supabase foundation. Remaining work is binding it to reservation commands, generated collaboration API clients, and frontend operator flows. Source status ids cover draft/writing, reservation, consultation, date-prepared, date-confirmed, in-progress, settlement, done, change/cancel/extension/stop requests, virtual-account waiting/cancel, pre-reservation, offline, and cancellation. Modern stage names may differ, but every portal needs a stable display status plus actor-stage command list derived from the shared projection read model and modular operation-command policy, not hardcoded source ids. Stage additions such asawaiting_deposit,change_requested, andcancellation_requestedmust be introduced through the rule catalog, Supabase operation context, generated database types, and actor permission mapping together. Accepted operation plans with follow-up actions now start a Restate-backed operation follow-up workflow and persist request/action events in service-role-only Supabase tables, so branch/HQ screens can show asynchronous gift coupon, cancellation notice, extension payment, settlement, closeout, assignment, delivery, report, and price-version work without calling Restate directly. 2026-07-05 execution follow-up: reservation lifecycle side-effect execution rows now persist frozencommandPayload, provider event ordering status, provider event refs, target result refs, retry diagnostics, and explicit work-item dependencies. Refund closeout starts inawaiting_provider_command, refund completion barriers depend on closeout and wait inawaiting_provider_event, and benefit release plus branch settlement reversal depend on the barrier, so UI/controller timing cannot mark those side effects complete before provider evidence arrives. Persisted status writes are now modeled separately byReservationStateTransitionPolicy: source-mined customer request, payment callback, virtual-account deadline, cron, and approval transitions are catalog rules with guard facts, not controller/UI branches. Contract payloads use stable state codes instead of raw status numbers. Operation command responses now include accepted transition decisions for the command paths that already have guard facts; remaining proof is wiring the same transition decisions into booking/payment/cron command handlers, Supabase transition persistence, and generated clients. - Pricing and settlement end-to-end: regional benefits, yearly/versioned
policies, deposits, support amounts, fees, Kill Bill/KCP migration, payout,
branch settlement, HQ settlement. Status:
Partial. Published price catalog entries can now feedPriceCatalogQuoteread models without mutable spreadsheet or raw amount input. Accepted quotes now capture immutable reservation charge snapshots during booking workflow execution, and booking progress exposes the finalized snapshot id for later payment/settlement handoff. Finalized charge snapshots now also carry optionalservice_calendar_impact_plan_id,service_calendar_impact_policy_fingerprint, andservice_calendar_impact_fact_ids, so a paid charge can prove whichcharge_reprice_requiredservice-calendar facts were reflected before Kill Bill closeout. The approved-payment charge finalizer rejects stale snapshots when a newer reprice-impact plan exists, preventing post-payment mother-visible amount drift.ReservationServiceCalendarQuotePolicynow turns selected Saturday/holiday service-calendar charge facts into effective-dated, branch/program-specific quote lines, applies those lines toReservationPriceSummaryInput, and preserves the same impact references beforeReservationPriceSummaryChargeFreezePolicycaptures the final payable snapshot.ReservationExtensionQuotePolicynow derives extension pricing from a forward-only original/new reservation chain plus its own calendar quote, instead of copying mutable payment rows.SourceServiceCalendarExtraOptionDecisionnow translates source labels토요일 추가,휴일 추가, legacy duration-extension tokens, and source add-date type codesSAT/HOLIinto backend expected counts, profile-backed duration extension days, and domain extra-service-day selections.SupabaseServiceCalendarPolicyProfileReadernow loads active global/branch service-calendar policy profiles by effective date, and branch service-area rules now exposecoverage_profile_keyplusservice_calendar_policy_profile_key, so source locality labels stay evidence instead of becoming code branches. Daily-care printable submissions requireservice_occurrence_evidence_key, preventing document output from drifting away from frozen service-day occurrence facts. 2026-07-05 source-dig follow-up: admin UI still hardcodes locality-specific support fields and builds service bonus payloads aroundwanju_fl/wanju_optionplus display labels (source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:927-941,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1519-1539,source-refs/sanmopia-admin/application/views/reservation_status/reservation_add.php:273-303). This is not a frontend concern in the target. BackendRegionalBenefitRulemetadata now stores theResidencySupportProfilekey, service-day bonus count, and settlement participation code without city/county literals in application code. ApplicationFinalizeReservationChargeWithRegionalBenefitHandlernow freezes oneRegionalBenefitDecisionfor price-summary charge finalization. Booking HTTP/API boundaries accept anacceptedRegionalBenefitDecision,build_reservation_booking_workflow_request()serializes it into durable Restate input, and charge finalization now freezesRegionalBenefitChargeImpactSnapshotrows on both quote-backed and fallback booking charge paths. Approved-payment finalization no longer fails from a missing frozen regional-benefit impact array after a real stage booking. Remaining work is resolving that accepted decision from catalog/address data in every reservation entrypoint and binding downstream service-calendar impact, payment-conversion, and settlement participation to that same snapshot path. The financial lifecycle API now advances service delivery, caregiver payout, branch settlement, HQ settlement, and settlement completion while preserving frozen mother-visible amounts.ReservationFinancialLifecycleWorkflowcan start those transitions through Restate using one workflow request id and exposes progress reads backed bysanmopia_reservation_financial_lifecycle_workflow_requests. Kill Bill paid-payment verification, cancel, and refund now use a real V2 HTTP adapter behindReservationPaymentWorkflow, exposed through public start/progress APIs and persisted tosanmopia_reservation_payment_workflow_requests. Kill Bill webhooks now persist a backend-only event ledger and synchronize cancellation, partial cancellation, failure, and virtual-account-issued payment statuses. Paid verification now recordsapproved_charge_finalization_statusandfinalized_charge_snapshot_idon the payment workflow ledger, and paid webhooks recordpayment_closeout_kindso virtual-account deposits are distinguishable from instant payments; the payment workflow ledger now also stores the closeout reservation booking id and reservation status snapshot that were present when the paid webhook started verification. Approved payment closeout now requests settlement continuation throughReservationFinancialLifecycleWorkflow, recordssettlement_continuation_status,settlement_continuation_workflow_request_id, andsettlement_continuation_reasonon the payment workflow ledger, and waits withwaiting_for_financial_factswhen service delivery, payout, branch, or HQ ledger facts are not ready. The Supabase continuation fact reader now maps prepared HQ settlement ledger lines fromsanmopia_reservation_financial_ledger_linesintohqSettlementLines, so branch-settlement-ready reservations can advance without hand-built payloads when HQ ledger facts exist. 2026-07-08 follow-up: recordingServiceDeliveryCompletionFactnow triggers a backendResumeApprovedPaymentSettlementContinuationAfterServiceDeliveryHandlerrecheck for paid workflows that were waiting on missing financial facts. 2026-07-08 follow-up generalized the same continuation recheck for every downstream financial fact code (service_delivery,caregiver_payout_lines,branch_settlement_lines,hq_settlement_lines). Stage smoke now proves the wait reason advances linearly through service delivery, caregiver payout, branch settlement, and HQ settlement, then reachessettlement_continuation_status = workflow_startedwithout operator repair. Refund, partial refund, custom discount, and additional burden/charge handling are not allowed to stay as UI/payment-row arithmetic. Backend foundation now includesPaymentLedger,RefundQuote,ReservationCancellationRefundPolicy,PaymentRefundIntent,PartialRefund,PaymentAdjustmentCatalog,DiscountAdjustment,AdditionalChargeAdjustment, and adapter-facingPaymentRefundGatewayCommand. Kill Bill integration must use Kill Bill REST API payment lookup, void, and refund resources and preserve idempotency key, expected revision, requested amount, tax-free amount, current refundable amount, reason, requester, and provider cancellation id/status. Domain must reject refund amounts above cancellable ledger balance and keep adjustment catalog versions separate from mutable operator labels. Reservation cancellation refund commands must replace client-supplied payment totals with current ledger cancellable balance before quoting, so UI-calculated refund totals never become financial truth.SupabasePaymentRefundLedgerStorenow rebuildsPaymentLedgerfromsanmopia_payment_recordsplus append-onlysanmopia_payment_refund_ledger_entries, skips already-persisted revisions, and serializes catalog-backed discount/additional-charge rows for audit. 2026-07-05 follow-up: payment-change-linked refunds now carrypayment_change_adjustment_idthrough application boundary DTOs, Pydantic-free domain intent/refund facts, queryable Supabase FK storage, and historical provider-command JSON fallback. Stage drift fromcurrent_cancellable_amount_krwis normalized back tocurrent_refundable_amount_krwso generated Supabase types match backend adapter vocabulary. Public OpenAPI/TS contracts now exposePOST /reservation-cancellation-refundswith optionalpaymentChangeAdjustmentId, and backend HTTP/API maps that id intoPaymentChangeRefundLinkwithout accepting UI-calculated paid/refund totals. Kill Bill administrator operation parity now has a backend/contract foundation throughPOST /killbill-payment-admin-operationsandsanmopia_killbill_admin_operation_audits: branch/HQ operators can run auditedlookup_payment,search_payments,close_virtual_account,inspect_refund_status,inspect_chargeback_status, andrecord_chargebackactions with Supabase-authenticated actor identity, SpiceDB branch authorization, idempotency command fingerprints, expected revision, reason, provider status/result, and backend-only evidence fingerprint. Remaining admin-operation gaps are webhook replay, manual/API virtual-account issue, frontend repair UX, and runbook examples. Kill Bill pre-registration now freezes payment amount and local waiting payment facts throughPOST /reservation-payment-pre-registrationsbefore payment UI entry, so post-payment mother-facing amounts do not drift when pricing policies change. Payment product-plan modeling status:Supabase-backed backend foundation and public contract catalog exposed.PaymentProductPlanis the sellable or operator-billable workflow product, whileReservationPaymentPurposeremains the reservation payment ledger obligation. Pre-registration now requires a stable plan code through HTTP/API/application/Supabase storage, validates it through the latest active/effectivesanmopia_payment_product_plan_catalog_itemsrows before provider handoff, and replays only when the saved plan code still matches. The same Pydantic-derived plan book now backsGET /payment-product-plansandGET /payment-product-plans/{planCode}so frontend code renders catalog facts instead of inferring product meaning from payment purpose, source payment type ids, or hardcoded UI numbers. First-class plan families cover customer-share deposit/balance, service-balance internal/operator receipt, pre-reservation deposit, gift coupon purchase, and change-payment/correction payment. Product plans carry provider routing keys, allowed payment methods, settlement participation, realization triggers, ledger recognition timing, fee recognition basis, settlement line targets, refund policy, conversion policy, virtual-account/pre-registration expiration policy, customer/operator visibility, frozen customer-visible amount flags, catalog-change reprice protection, and post-payment correction guards. Payment communication routes now point at backend-owned Novu workflow keys, including mother, payer, coupon receiver, branch operator, and branch secondary-contact audiences; Supabase migration/seed constraints carry the same workflow trigger and audience vocabulary.PlanPaymentCommunicationDispatchHandlernow converts selected catalog routes plus recipient facts into backend-ownedCommunicationDispatchRequestobjects, so payment screens no longer decide notice targets or workflow keys.PaymentProviderTemplatePayloadrenders a policy-versionedproviderTemplatePayloadwith frozen workflow, recipient, amount, payment, subject, and message-purpose variables before provider handoff, so Novu/Strapi templates do not need PHP/UI string assembly or amount formatting.SupabaseCommunicationDispatchStorenow persistsCommunicationDispatchRequestrows by workflow-code/version lookup and inserts providerCommunicationDispatchEventaudit rows before Novu work is treated as durable. Remaining communication proof is payment-workflow runtime invocation, queue worker execution, virtual-account instruction rendering from frozen requests, and provider result reconciliation. The remaining raw-payment-type adapter boundary issource_payment_type.py; do not expand that boundary when adding new product-plan code. Historical pre-reservation refund anchoring stays in this checklist:source-refs/sanmopia-admin/application/models/Reservation_model.php:5559-5594. The customer charge/payment projection now emits backend-computed display lines and totals for source customer pricing views: service price, support/discounts, coupon/gift credits, rental/add-on charges, pre-reservation deductions, customer deposit, service balance, payable-now, paid, refund-pending, safe virtual-account prompt, revisions, and UI-observed total mismatch facts. RawPRICE_TABLE, rawPAYMENT_INFOmaps, KCP/Kill Bill approval payloads, settlement continuation ids, provider transaction ids, and caregiver ledger ids stay out of customer contracts.ReservationPriceSummaryChargeFreezePolicynow converts the legacy-compatibleReservationPriceSummaryInputresult into immutable customer-charge lines before payment/settlement handoff. Coupon, pre-reservation payment, regional benefit, voucher in-home delta, and voucher service-balance add-on remain visible reference evidence in the snapshot, but they do not become a second discount or credit after the summary has already reduced the payable amount.FinalizeReservationChargeFromPriceSummaryHandlerstores the frozen summary onReservationFinancialLifecycle, preserving the service-calendar impact references used during charge repricing. Payment-change adjustments now have a backend/domain/Supabase foundation:PaymentChangeAdjustmentkeeps customer delta, coupon adjustment, and pure customer amount as separate facts; only the owning mother can pre-register and verify the latest awaiting adjustment; paid rows freeze provider context and deposit time; and operator completion writescompleted_atonce. Supabase stores the ledger insanmopia_payment_change_adjustments, keeps superseded unpaid rows ascancelledinstead of deleting them, freezes payment-change pre-registration columns before payment UI entry, and exposes the table only to service-role adapters. Reservation/payment edits still need a preview refresh path that emits recalculation-needed facts before branch/HQ closeout: source admin saves payment dates, service term, caregiver roster, add-days, address, and memo in one reservation-detail submit, while settlement boards read mutable payment/fee flags later. Public API/contract handoff now exposes protected adjustment request, mother-payment pre-registration, mother-payment capture, and operator-completion endpoints with Supabase bearer auth and SpiceDB operator checks; server-side paid verification now uses Kill Bill before receipt capture. Protected adjustment read endpoints now support latest by reservation and detail by durable adjustment id; protectedPaymentChangeOperatorBoardnow covers paid/completed backend board rows, search, row counts, deposited/completed timestamps, completion-editable state, human reservation id, branch profile id, mother display name, reservation charge amount, purpose-tagged payment deposit milestones, and backend-owned manual receipt command drafts with command draft id, canonical payment method, payment purpose, amount, deposited-at time, disabled reason, and idempotency key (4bd81e1,455f74a,858fa24,87a6e61). Protected operator amount-correction commands now write append-onlyPaymentChangeOperatorAuditrows instead of mutating paid adjustment totals, and operator completion emits the same audit ledger with actor, reason, idempotency key, previous/new status, previous paid amount, requested amount, expected adjustment updated-at token, and recorded time. Stale amount corrections are rejected before audit append (f9ce5dc,05059a5).PaymentCorrectionAmountChangenow shares previous/corrected amount validation and signed delta naming between payment fact correction and payment-change amount-correction audit. Frontend reservation-operation board consumesmanualPaymentReceiptCommandDraftfor receipt defaults (d28ff5f). Paid adjustment payments now request settlement continuation through the shared financial lifecycle workflow source idpayment-change-adjustment:{paymentChangeAdjustmentId}, and public adjustment/board responses expose nullable settlement continuation status, workflow request id, reason, and recorded-at fields. Public backend/contract now exposeGET /reservation-payment-change-adjustments/{paymentChangeAdjustmentId}/settlement-continuation-workflow-status, which resolves an adjustment id to the sharedreservation_financial_lifecycleworkflow projection with the same bearer and booking-scoped authorization. Remaining work is settlement-preview refresh, frontend board UX, payment command purpose capture, status projection invalidation, manual settlement contract/UI, and operator UI. Branch settlement operator boards now expose period rows, directional line-derived totals, stored net balance, and reconciliation delta through protected backend reads. Caregiver payout quote lines now carrycontract_assignment_key,rate_rule_id,policy_version_label, and rate effective dates so later policy changes cannot rewrite the caregiver-facing payout basis after payment or settlement closeout. Source evidence also shows mother-facing payment rows, internal branch/HQ settlement rows, Danbee/other-office transfer rows, and caregiver payout rows use different tables and fee formulas. Remaining work is persistence/API wiring for the customer charge/payment projection, wider settlement calculation readers, other-office settlement, payment-change adjustment, settlement dashboard/export breadth, and operator UI. - Care delivery end-to-end: multiple caregivers per contract, attendance,
handoff order, daily reports, caregiver compensation facts. Status:
Partial. Reservation caregiver assignment now emits stable per-contract assignment keys for primary and assistant caregivers, preserves handoff order separately, and feeds those keys into caregiver compensation quote lines. Primary caregiver replacement now uses date-bounded primary caregiver terms within the same reservation contract; each term has its own assignment key, grade code, and planned service-day count, and service-day attendance resolves the active primary term for the requested date. Compensation quote lines snapshot the applied grade/role rate rule id, policy version, and effective date range, while Supabase enforces uniqueness by reservation, contract assignment key, and policy version. Reservation collaboration now persistscaregiver_assignment.rosterintosanmopia_reservation_caregiver_assignmentswith primary/assistant role, assigned Supabase user, grade, term dates, planned days, andcontract_assignment_key.CareTeamContractnow adds backend and TS-client contract foundations for one ordered care-team roster, provider-count basis, role labels, grade snapshot reference, effective windows, and document member projection;SupabaseCareTeamCompensationSourceReadernow reuses the persisted assignment rows for backend compensation quoting. Authenticated HTTP and TS-client path/response contracts now expose the same source through caller-JWT/RLS scope, and backend app composition attaches the route with a non-service Data API key preference when configured. Remaining exposure gap is generated OpenAPI, document/report projections, and frontend Nanostores/Supabase realtime use. Legacy evidence has separate main-caregiver and sub-caregiver service rows, ordered assistant positions, manager-change logs, sub-manager change logs, and sub payout status/custom price rows. Modern work still needs ordered assistant member-term planning and continuity rules that avoid dropping already accepted replacement terms when a later assistant member changes. Mother portal must show assigned caregiver and sub-caregiver names only when policy allows, preserve source-style masking after assignment gaps or 90-day post-service windows, and expose pending report/signature work without requiring the frontend to infer it from raw status numbers. Service-record submission rows now use backend-owned role/handoff identity and sequence actions instead of frontend rawREAD_FL/SUB_READ_FLinference; remaining proof is API/persistence and realtime projection wiring. Source evidence:sanmopia-user-old/src/design-system/ui-kit/organisms/ReservationManagerInfo.astro:21-80,sanmopia-user-old/src/design-system/ui-kit/organisms/ReservationReportList.astro:23-66, andsanmopia-manager/application/controllers/Service.php:115-124. - Document reporting end-to-end: catalog, HTML A4 print, PDF, artifacts,
daily reports, contracts, receipts, bundle downloads. Status:
Partial. Catalog, stored template loading, HTML/PDF render artifact bytes, Supabase Storage upload, andsanmopia_document_render_artifactsmetadata upsert are migrated; the Supabase Storage adapter now creates short-lived private signed URLs for single-artifact and bundle handoff, withVIEW_RESERVATIONstage and SpiceDB checks. Bundle handoff now signs catalog-valid ready members and reports missing members. A4 repeat sections are now metadata-driven: renderer expands unbounded item templates from section data paths and field bindings, so service rows/report answers can flow to later pages without fixed slots. Printable template policy now selects by typed document kind, template version, input snapshot revision, service kind, and render format, returning backend-owned renderer/page/readiness decisions while public read models hide source numeric IDs, token URLs, storage paths, gateway order IDs, transaction IDs, and provider URL construction facts. Daily report print payloads now also expose flatteneddaily_care_report_answer_rows/dailyCareReportAnswerRowswith logical answer row keys, avoiding per-template nested-loop duplication for report answer pages. Legacy evidence still requires full start/end document delivery parity: reservation contracts, fee agreements, voucher plans, deposit/receipt documents, privacy consent, static notices, customer instructions, terms, voucher completion notice, scheduled start/end email batches, manual resend, download-token expiry, customer ownership checks, and send-attempt history. Remaining work is contract/receipt templates, web framework route binding, persisted ZIP bundle artifacts, operational UX, delivery retry ledger, and recipient-visible access history. - Communication end-to-end: FCM, Kakao/Aligo messages, notices, events,
report reminders, payment reminders, birth-information reminders. Status:
Partial. - Content/community end-to-end: boards, FAQ, QnA, notices, posts, star review,
education content, branch and manager notices. Status:
Partial. - Promotion/shop end-to-end: coupons, gifts, Momfirst, clean service,
event benefits, campaign exports. Status:
Partial. - Analytics/admin end-to-end: statistics, dashboards, datatables, Excel
exports, load history, system holidays. Status:
Partial. Business-report snapshots, scoped Supabase RLS, and private export artifacts now cover the first statistics/export foundation. Remaining work is full report catalog breadth, scheduled report refresh, operator UI, export artifact repair UX, price import execution history, and service-calendar holiday audit. Detailed queue: Admin Analytics And System Gap Mining. - Migration governance and source compatibility: loose string/number
comparisons, magic ids, hardcoded dates/amounts/status ids, adapter-only
source evidence, and explicit modern rule replacement. Status:
Mapped. Source-dig evidence:source-refs/sanmopia-admin/application/controllers/Reservation.php:782,source-refs/sanmopia-admin/application/controllers/Reservation.php:870,source-refs/sanmopia-admin/static/js/reservation_status/reservation_changePayment.js:46,source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:1040-1046,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4163, andsource-refs/sanmopia-admin/application/config/constants.php:112-137. Target name isSourceCompatibilityCatalogplus owning-contextLegacyRuleAdapterentries. These facts live underdomain/migration_governance/features/source_evidence_reconciliationand adapter evidence modules; they must not become domain truth or UI control flow. 2026-07-05 persistent-agent source-dig additions:source-refs/sanmopia_web/application/controllers/MyReservation.php:352-367,source-refs/sanmopia_web/application/models/User_model.php:476-489, andsource-refs/sanmopia_web/application/controllers/api/ReservationDocument.php:21-39show the source two-hour document token is user-scoped rather than reservation/document/artifact scoped; backend and public contracts now model this asDocumentAccessGrantwith reservation id, document definition key, artifact version key, recipient, channel, expiry, revocation, audit scope, and explicitdownload_document_artifactaction.source-refs/sanmopia_web/application/controllers/Notification.php:19-27plus notification view source appends document tokens to arbitrary URL strings; modernNotificationDocumentActionGrantmust use typed action payloads and a grant-target allowlist instead of frontend URL/token concatenation.source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:86-127and admin calculation receipt links map provider bill commands and mutable localPRICEvalues in views; modernCustomerReceiptProviderCommandSnapshotmust freeze provider command, method, captured amount, order id, transaction id, refund state, and repair reason.source-refs/sanmopia_web/application/models/Payment_model.php:232-264andsource-refs/sanmopia_web/application/models/Reservation_model.php:1401-1413show coupon/pre-reservation over-credit grants split across closeout phases; modernCouponPrepaymentOverCreditEntitlementmust carry phase, own-price basis, cash-prepayment basis, coupon-prepayment basis, point amount, and idempotent closeout key.source-refs/sanmopia_web/application/models/Payment_model.php:383-417and later virtual-account callbacks show refund eligibility is provider/context dependent; modernVirtualAccountRefundEligibilityDecisionmust distinguish card/account/virtual-account capability, issued versus deposited virtual account, idempotent already-paid rows, and zero-gateway fallback. 2026-07-06 persistent-agent source-dig additions:source-refs/sanmopia-admin/application/models/Manager_working_day_model.php:9,source-refs/sanmopia-admin/application/controllers/ManagerWorkingDay.php:58,source-refs/sanmopia_web/application/controllers/api/Kcp.php:18,source-refs/sanmopia_web/application/models/Kcp_model.php:8,source-refs/sanmopia-admin/application/controllers/Reservation.php:1497,source-refs/sanmopia-admin/application/models/Reservation_model.php:5421,source-refs/sanmopia-admin/application/models/Win_the_race_model.php:31,source-refs/sanmopia-admin/application/models/Statistics_model.php:794,source-refs/sanmopia-admin/application/controllers/Reservation.php:470,source-refs/sanmopia-admin/application/models/Reservation_model.php:5856, andsource-refs/sanmopia-admin/application/models/Reservation_model.php:5903identify five unmigrated backend concepts.CaregiverWorkingDayRegisterandCaregiverAttendanceCorrectionmust preserve branch-entered monthly working-day counts and attendance corrections.PaymentProviderNotificationInboxEntry,VirtualAccountDepositNotification, andPaymentProviderNotificationAdmissionPolicymust preserve KCP raw callback evidence, IP/admission decisions, ack behavior, and virtual-account closeout/cancel semantics.ReservationCreationAuditEntry,OperatorReservationIntakeSnapshot, andDuplicateReservationIntakeGuardmust preserve operator-created reservation provenance.ReservationCancellationTimingFact,BranchPerformanceCancellationInclusionPolicy, andPerformanceRecognitionReservationEligibilitymust preserve cancellation timing rules used by branch performance recognition.ReservationServiceBalanceOverrideAudit,ReservationPriceVersionChangeAudit, andOperatorBranchSnapshotmust preserve source audit-table parity for service balance and price-version overrides. Remaining work is a repeatable source scan that turns every magic string/int/date/amount into either a policy profile, catalog row, enum alias, or import compatibility decision with evidence refs.
2026-07-06 Planck Backend Rule Mining
Section titled “2026-07-06 Planck Backend Rule Mining”These entries are source-mined backend policy gaps found in the reservation -> payment/refund -> caregiver matching/payroll -> branch/HQ settlement -> documents path. They focus on legacy UI/PHP calculations, status strings, raw ids, and branch exceptions that must move into backend domain rules or adapter evidence instead of modern frontend logic.
-
P0 Backend foundation
SFC-20260706-RES-001ReservationServiceExpectedStartState. Legacy evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:853-890,source-refs/sanmopia_web/application/controllers/api/Reservation.php:48-81, andsource-refs/sanmopia_web/application/controllers/api/Reservation.php:409-412. Suggested owner:reservation_operations/features/reservation_service_start_decisionplusreservation_operations/features/service_calendar. Missing backend rule: deleting an expected service start writes sentinel date1970-01-01, while setting a start date writes expected/start/end dates and recalculates the calendar. Modern backend needs a typed unknown/deleted expected-start state, service-start decision audit, expected revision, and service-calendar rebuild plan. UI must not infer state from a magic date. Implementation status:Backend foundation: 46d64f3. Implemented replacement:reservation_operations/features/reservation_service_start_decisionnow owns typed expected-start states (unknown,scheduled,deleted), versioned set/delete commands, idempotent retry by command key, revision-conflict rejection with current state, append-only audit events, and service-calendar rebuild/invalidation plans. Remaining adapter work must persist the audit, state revision, and calendar rebuild plan without leaking the legacy sentinel date into API or UI contracts. -
P0 Backend foundation
SFC-20260706-RES-002OperatorReservationCalendarProjection. Legacy evidence:source-refs/sanmopia-admin/application/views/reservation_status/reservation_calendar.php:63-104andsource-refs/sanmopia-admin/static/js/reservation_status/reservation_calendar.js:1-72, plussource-refs/sanmopia-admin/application/controllers/Reservation.php:610-647andsource-refs/sanmopia-admin/application/controllers/ajax/ManageSystem.php:16-30. Suggested owner:reservation_operations/features/operator_reservation_calendar. Missing backend rule: the calendar skips branch id37, maps status19to an offline label and status13to a stopped label, abbreviates Korean service labels, renders start/end events with different colors/classes, and overlays holidays from a separate AJAX call. Backend should emit a stable calendar event projection with branch visibility, event kind, lifecycle marker, label token, color/legend token, holiday overlay revision, and detail handoff target. Implementation status:Backend foundation: b174da4. Implemented replacement:reservation_operations/features/operator_reservation_calendarnow projects backend-owned start/end event pairs, status badges for offline/stopped reservations, configurable branch exclusion profiles, active calendar windows, holiday markers, display/print profile facts, and contract payloads. Remaining adapter work must source reservation facts and holiday dates from Supabase projections without reintroducing PHP view string logic. -
P0 Backend foundation
SFC-20260706-BR-001BranchOperationalExclusionPolicy. Legacy evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:94-105,source-refs/sanmopia-admin/application/controllers/Calculate.php:108-118,source-refs/sanmopia-admin/application/views/win_the_race/manager.php:48-60, andsource-refs/sanmopia-admin/application/views/statistics/supermanager.php:58-68. Suggested owner:branch_operations/features/branch_operational_exclusion_policy, with later consumers inbusiness_reporting/features/report_scopeandpricing_settlement/features/settlement_scope. Missing backend rule: headquarters/development branch ids36and37are excluded differently across settlement, competition, statistics, and calendar surfaces. Modern backend needs effective-dated branch operational profiles with actor role, surface scope, reason, and audit, not repeated view/model id checks. Implementation status:Backend foundation: b2393cb. Implemented replacement:branch_operations/features/branch_operational_exclusion_policynow owns surface-scoped exclusion rules, effective dates, exclusion kind, reason code, source evidence key, visible branch ids, and excluded branch reasons. Remaining adapters must feed branch registries and policy revisions into settlement, reporting, competition, and calendar projections instead of hardcoding branch ids in views/models. -
P0 Backend foundation
SFC-20260706-BR-002ReservationAddressAdministrativeProfileDecision. Legacy evidence:source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:83-171. Backend commit:d843b2b. Owner:branch_operations/features/address_profile_decision. Migrated rule: postcode lookup facts are normalized by backend domain policy: road/jibun choice, road-address legal-dong/building display extras,sigungufallback to provider administrative fallback, administrative level-2 source evidence, level-3 legal district, normalized address key, address depth, source evidence key, and evidence payload fingerprint. Verification: focused colocated tests,ruff check,ruff format --check,tach check --dependencies --interfaces --exact, andtach check-externalpassed on 2026-07-06. Remaining runtime migration: reservation booking, second-address, branch service-area decision snapshots, pricing, matching, settlement, and conflict-audit consumers must read this frozen profile instead of trusting UI-normalized administrative levels. -
P0 Pending
CaregiverRouteDisclosureGrant. Legacy evidence:source-refs/sanmopia-manager/application/views/pay_info_detail.php:132-154. Suggested owner:care_delivery/features/caregiver_route_disclosurewithcaregiver_assignment/features/assignment_route_evidence. Missing backend rule: caregiver portal route buttons receive full service address, caregiver address, latitude, and longitude directly from the payout detail view. Backend must issue a route-disclosure grant for the assigned caregiver/role only, with address masking level, coordinate visibility window, route-provider intent, audit, and revocation after assignment cancellation or service closure. -
P1 Partial
CaregiverPayoutPortalSurfaceProjection. Legacy evidence:source-refs/sanmopia-manager/application/controllers/Other.php:224-292,source-refs/sanmopia-manager/application/views/pay_info_detail.php:42-101, andsource-refs/sanmopia-manager/application/views/pay_info_detail.php:170-255. Suggested owner:pricing_settlement/features/caregiver_compensationpluscare_delivery/features/caregiver_portal_work_schedule. Missing backend rule: payout read-model foundation exists, but legacy portal still contains surface policies: salary recalculation per logged-in caregiver, main/sub manager rejection, status badge image, normal/voucher week display, baby-type labels, provider count, after-tax line selection, final-pay labels, and a2022-03-29view cutover. Modern backend should serve a single caregiver-facing statement surface projection with role slot, display line keys, source cutover compatibility, and document/route grants. -
SFC-20260708-CUR-090P1 PartialPaymentChangeCanceledReservationStatusProjection. Legacy evidence:source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:68-78,source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:142-170,source-refs/sanmopia-admin/application/models/Payment_model.php:4422-4521, andsource-refs/sanmopia-admin/static/js/reservation_status/payment_change.js:93-101,source-refs/sanmopia-admin/static/js/reservation_status/payment_change.js:109-149,source-refs/sanmopia-admin/static/js/reservation_status/payment_change.js:144-167. Suggested owner:pricing_settlement/features/payment_conversion. Suggested backend feature name:PaymentChangeOperatorBoardProjection, plusPaymentChangeOperatorMutationCommandandPaymentChangeStatusTransitionProjection. Missing backend rule: source appends synthetic payment-change status id0for canceled reservations, rewrites waiting rows to that status in JavaScript, blocks operators from selecting it, and recomputes the board amount from mutable reservation price/coupon rows. Browser renders editable amount input fromPRICE, then sends generic{type, value}PUTs for amount or rawPAYMENT_CHANGE_STATUS_ID_FK; PHP sanitizes amount withFILTER_SANITIZE_NUMBER_INT, writes the row directly, and setsCOMPLETED_DTwhen status value equals2(source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:167-175,source-refs/sanmopia-admin/application/models/Payment_model.php:4499-4518). Modern operator board should expose canceled-reservation projection state, charge-summary snapshot, editable transitions, disabled reason, amount-correction authority, settlement/refund visibility, and completion audit from backend status facts instead of browser-only sentinel or generictypemutation. -
SFC-20260708-CUR-091P1 PartialOperatorReservationStatusOptionProjection. Legacy evidence:source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:78-166andsource-refs/sanmopia-admin/application/views/reservation_status/pre_reservation_detail.php:90-118. Suggested owner:reservation_operations/features/reservation_admin_lifecycle. Suggested backend feature name:ReservationLifecycleCommandOptionProjection. Missing backend rule: source status selectors branch on actor type, current status, pre-reservation state, offline status, and hidden status ids. Existing transition policy foundation should add an operator option projection with allowed target statuses, disabled reasons, headquarters-only cancelability, pre-reservation compatibility (9versus18), payment/payout/settlement invalidation preview, and source-status catalog version. -
SFC-20260708-CUR-092P1 PendingSettlementDataRoomNavigationActionProjection. Legacy evidence:source-refs/sanmopia-admin/application/controllers/DataRoom.php:218-250,source-refs/sanmopia-admin/application/controllers/DataRoom.php:268-309,source-refs/sanmopia-admin/application/controllers/Common.php:28-204,source-refs/sanmopia-admin/application/controllers/Common.php:101-129,source-refs/sanmopia-admin/application/controllers/Common.php:132-153,source-refs/sanmopia-admin/application/controllers/Common.php:156-196,source-refs/sanmopia-admin/application/controllers/DataRoom.php:279-293,source-refs/sanmopia-admin/application/models/Payment_model.php:2684-2704,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:1-69,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:78-111,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:1-57,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi_other_office.php:1-70,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi_other_office.php:47-63,source-refs/sanmopia-admin/static/js/data_room/calculate_central.js:1-14,source-refs/sanmopia-admin/static/js/data_room/calculate_danvi.js:1-14, andsource-refs/sanmopia-admin/static/js/data_room/calculate_danvi_other_office.js:1-22. Suggested owner:pricing_settlement/features/settlement_data_room. Suggested backend feature name:SettlementDataRoomNavigationActionProjection. Missing backend rule: data-room board lists render current settlement board rows directly, then browser buttons build raw/common/calculateURLs from board id, reservation id,dataType, and branch-side strings. Inter-office rows decide service-office versus customer-transfer-office action visibility by comparing the logged-in branch id to source branch ids. Other-office data-room route parsesfyear/fmonthbut passesNULL, NULLinto the reader, so the branch list is unbounded by settlement period unless a backend dataset scope replaces it. Modern backend should issue actor-scoped navigation tokens with collection kind, board or reservation lookup key, canonical settlement period, dataset revision, current status label, allowed detail action, disabled reason, return-state token, and branch-side audit scope. This is separate from SFC-088 adjustment-line math and export artifact freezing. 2026-07-09 settlement/data-room follow-up: the detail controller still derives display/action state fromgetType,dataType,branchId,boardId,freservationId,fbranchType, rawSTATUS_FL, and hardcoded labels such as입금요청,입금확인,정산완료,미납상태,정산필요, and fee text like바우처 수수료(건당 15,000원). Central data-room rows also parseTHIS_DTlength in the view, render mutable money columns, status colors, and raw board ids into buttons; inter-office data-room rows decide which branch-side button appears fromOTHER_OFFICE_TYPEplusBOARD_STATUS_FL. Target extension:pricing_settlement / SettlementDataRoomDetailProjection,pricing_settlement / SettlementDataRoomActionAvailabilityProjection,pricing_settlement / SettlementDetailDisplayAmountProjection, andpricing_settlement / SettlementDataRoomDetailOpenCommand. Backend must own detail-open eligibility, status/button copy, fee-label policy, gross/fee/net amount snapshots, memo/message visibility, service-office versus customer- handoff side, period display, and disabled reason from collection/detail revisions. Frontend/admin must render backend projections only; no PHP/Astro/JS view may choose detail routes, branch side, button text, status color, fee text, period label, or settlement amounts from raw board rows or URL/query params. -
SFC-20260708-CUR-093P1 PartialPaymentChangeCompletionDispatchAndClientRefresh. Legacy evidence:source-refs/sanmopia_web/static/js/mypage/reservation_changePayment.js:116-143,source-refs/sanmopia_web/application/controllers/api/Payment.php:740-755,source-refs/sanmopia_web/application/libraries/Aligolib.php:298-331, andsource-refs/sanmopia_web/application/config/constants.php:146-147. Suggested owner:application/customer_engagement/features/communication_delivery. Backend feature name:PaymentChangeCompletionDispatchPlan. Migrated backend rule:PaymentChangeCompletionDispatchPlannow creates a typedPaymentChangeClientRefreshSignaland a versionedPlanPaymentCommunicationDispatchCommandfor mother, optional payer, branch operator, and optional secondary branch contact routes. KRW amount formatting, payment-change adjustment id, charge snapshot amount, recipient routes, idempotency key, and secondary-contact evidence are backend-owned instead of browser/controller-owned. Focused coverage lives inpayment_change_completion_dispatch_plan_test.py. The operator completion endpoint now wires this plan intoReservationPaymentApi.complete_payment_change_adjustment, persists/enqueues thePlanPaymentCommunicationDispatchCommandthrough the configured planner, and exposespaymentChangeCompletionClientRefreshSignalin the HTTP response so browser cache-clearing no longer owns payment-closeout behavior. Remaining rule: resolve optional secondary branch contact from branch profile policy instead of legacy branch-id evidence, then cover that API path. -
P1 Partial
PaymentDatedDocumentBundlePolicy. Legacy evidence:source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:64-105,source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:176-198, andsource-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:628-663. Suggested owner:document_reporting/features/document_delivery. Missing backend rule: scheduled/manual reservation-document mail chooses attachment sets from service type and the payment deposit-date cutoff2023-04-11, with separate manual-send branches. Modern document delivery needs a versioned bundle policy keyed by payment fact basis, service type, channel, effective date, artifact definitions, recipient authority, send ledger, and supersession behavior. -
P1 Partial
BirthInformationCorrectionImpactPolicy. Legacy evidence:source-refs/sanmopia-admin/application/controllers/Reservation.php:1038-1056,source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:336-418, andsource-refs/sanmopia_web/application/models/Reservation_model.php:994-1045. Suggested owner:reservation_operations/features/birth_informationplusreservation_operations/features/reservation_cancellation_disposition. Missing backend rule: branch operators can update due/birth date from the reservation detail surface, while customer cancellation disposition depends on whether the reservation is before birth or after birth/service-start. Modern birth-information commands should emit an impact plan for cancellation eligibility, service calendar, document labels, notifications, and refund quoting instead of treating birth-date correction as an isolated form save.
2026-07-06 Frontend Lane Hidden PHP/UI Delta
Section titled “2026-07-06 Frontend Lane Hidden PHP/UI Delta”This pass is docs-only. Source PHP/views remain evidence. These feature IDs mark UI-side state, authorization, and one-shot participation logic that must move to backend commands or read models before frontend implementation.
| Feature ID | Hidden source behavior | Source path evidence | Modernization target | Implementation status | Backend-owned replacement |
|---|---|---|---|---|---|
SFC-20260706-UI-001 | Reservation wizard state is carried through query strings, including contact data, delivery facts, resident-number fragments, pet/religion preferences, ranking answers, service type, extra service days, rental choices, and question answers. The old survey final/complete pages also compute visible service price, government support, customer share, additional-service totals, and service-balance text from embedded basePrice and option variables in browser script. | source-refs/sanmopia_web/application/models/Survey_model.php:8-71, source-refs/sanmopia_web/application/controllers/Survey.php:17-179, source-refs/sanmopia_web/application/views/survey/a27.php:284-331, source-refs/sanmopia_web/application/views/survey/a30.php:241-288 | reservation_operations / ReservationIntakeDraftSession, member_management / SensitiveReservationPartyDraft, pricing_settlement / IntakeQuoteContext, IntakeQuotePreviewSnapshot | Backend foundation: 5da76dd | Replace dataLink* URL state with backend draft tokens, encrypted sensitive draft fields, per-step validation, source evidence keys, expiration, explicit discard/submit commands, and catalog/version references. Frontend must not preserve PII or quote-affecting facts in URLs, and survey/booking UIs must render a backend IntakeQuotePreviewSnapshot instead of calculating support, customer-share, additional-service, or service-balance amounts from embedded price maps. |
SFC-20260706-UI-002 | Caregiver portal reservation buckets are filtered from Korean status labels plus current date, and access checks are ad hoc main/sub caregiver SQL predicates. Pay rows expose reservation/payment data from the same read path. | source-refs/sanmopia-manager/application/models/Reservation_model.php:13-47, source-refs/sanmopia-manager/application/models/Reservation_model.php:89-91, source-refs/sanmopia-manager/application/controllers/User.php:931-953, source-refs/sanmopia-manager/application/models/Reservation_model.php:414-422, source-refs/sanmopia-manager/application/controllers/Other.php:223-237, source-refs/sanmopia-manager/application/helpers/salary_helper.php:8-40 | care_delivery / CaregiverWorkReservationProjection, operator_access / CareManagerReservationAccessDecision, pricing_settlement / CaregiverPayoutReadinessProjection | Backend foundation: 1bd7e42 | Backend now has care_delivery/features/caregiver_work_reservation_projection with caregiver-scoped active_work, completed_work, and payout_ready buckets, assignment role, handoff order, service window, backend-masked mother/contact fields, payout readiness, disabled reasons, projection revision, and Pydantic boundary contracts. Runtime follow-up: Supabase projection adapter, route binding for caregiver portal lists/detail/pay screens, SpiceDB/RLS access checks, payout statement summary binding, 90-day privacy window policy, and legacy bucket adapter/disable path. |
SFC-20260706-UI-003 | Caregiver-to-HQ request edit/delete flows accept request ids from forms and model writes by request id only after the view loads with managerId; edit/delete lacks a durable expected revision or actor-scoped command. | source-refs/sanmopia-manager/application/controllers/Other.php:335-384, source-refs/sanmopia-manager/application/controllers/Other.php:574-596, source-refs/sanmopia-manager/application/models/Request_model.php:24-49 | caregiver_engagement / CaregiverOfficeRequestThread, operator_access / CaregiverRequestAuthorizer, communication_delivery / HeadquartersRequestReplyNotification | Backend foundation: 7f56280 | Backend now upgrades caregiver_engagement/features/caregiver_office_request with revisioned edit/delete mutation policy, caregiver/HQ/branch actor vocabulary, actor ownership and branch-scope checks, expected thread version, reply-state guard, soft-delete retention outcome, notification instruction, append-only audit event, and Pydantic mutation boundary contracts. Runtime follow-up: Supabase revision persistence, RLS/SpiceDB authorizer, request-thread mutation API, notification workflow binding, and legacy form adapter/disable path. |
SFC-20260706-UI-004 | Caregiver surprise-event participation is a one-shot insert keyed only by manager id; source checks whether any row already exists, hardcodes event type 1, and stores freeform title/content. | source-refs/sanmopia-manager/application/controllers/Other.php:402-413, source-refs/sanmopia-manager/application/controllers/User.php:957-981, source-refs/sanmopia-manager/application/models/User_model.php:2209-2234 | caregiver_engagement / CaregiverCampaignParticipation, customer_engagement / CampaignSubmissionPolicy, operator_access / CaregiverCampaignEligibilityProjection | Backend foundation: b54084e | Backend now has caregiver_engagement/features/caregiver_campaign_participation with campaign code/type/version instead of numeric type 1, eligibility window, one-submission rule, content validation, consent terms, prior participation fact, idempotency key, admin review instruction, audit event, and Pydantic boundary contracts. Runtime follow-up: Supabase participation/audit persistence, campaign policy snapshot adapter, SpiceDB/RLS eligibility check, admin review queue binding, and legacy surprise-event adapter/disable path. |
SFC-20260706-UI-005 | Caregiver self-service address and device-token updates are direct profile mutations; address update geocodes raw address inline, and FCM token update replaces delivery endpoint state without device/audit vocabulary. | source-refs/sanmopia-manager/application/controllers/User.php:716-813, source-refs/sanmopia-manager/application/controllers/User.php:787-797, source-refs/sanmopia-manager/application/models/User_model.php:866-917 | caregiver_management / CaregiverProfileRevision, caregiver_assignment / CaregiverTravelEvidenceInvalidation, communication_delivery / CaregiverDeviceEndpointRegistration | Backend foundation: bf38296 | Backend now has caregiver_management/features/caregiver_profile_contact_revision with expected profile revision guard, provider-neutral address-normalization evidence, coordinate freshness, profile revision instruction, assignment/travel evidence invalidation, push device endpoint registration/replacement with token hash references, retryable provider failure decisions, audit events, and Pydantic boundary contracts. Runtime follow-up: Supabase profile/audit/endpoint persistence, address-normalization adapter, matching/travel cache invalidation job, RLS/SpiceDB caregiver ownership checks, notification provider endpoint binding, and legacy type=fcm/type=address adapter/disable path. |
2026-07-08 Frontend Reservation UX Evidence
Section titled “2026-07-08 Frontend Reservation UX Evidence”| feature_id | lane_owner | source_evidence | ddd_aggregate | command_query | persistence | contract | e2e_proof | status |
|---|---|---|---|---|---|---|---|---|
SFC-20260708-UX-001 | Frontend lane | frontend-repo/src/ui/organisms/FamilyAssistedReservationFlow.tsx, frontend-repo/src/ui/templates/MotherBookingTemplate.astro, and frontend-repo/src/lib/mother-booking-operational-context-client.ts | reservation_operations / ReservationBookingOperationalContext, pricing_settlement / BookingPaymentMethodSelection, and frontend_experience / MotherBookingCardFlowEvidence | GetMotherBookingOperationalContextQuery, StartReservationBookingWorkflowCommand, GetReservationBookingWorkflowRequestQuery, and CreatePaymentProviderRoutePreRegistrationCommand | No frontend persistence; Nanostores hold card-state only while backend owns context, payment method options, quote, status, and progress projections. Frontend 8a9a6f5 removes production smoke settlement state and local ledger preparation. | /mother-booking-operational-context, /reservation-booking-workflow-starts, /reservation-booking-workflow-requests/{bookingRequestId}, and payment pre-registration route when enabled. Manual receipt command remains locked until backend draft exposes expectedPaymentRevision. | frontend-repo/output/playwright/reservation-ux-progress-neutral-20260711/desktop-summary.json, mobile-summary.json, desktop/mobile screenshots, 96 changed tests, ESLint, and Astro check prove no free-text composer, no mobile step clipping, neutral/semantic palette, no failed requests, and no production smoke endpoint. 2026-07-13 follow-up frontend-repo/output/playwright/reservation-chat-sequential-20260713/ proves desktop/mobile one-question-at-a-time advancement across all 11 cards, answer transcript, completed-only summary reveal, current-card focus/scroll, no failed HTTP responses, and preserved backend-owned final values. Current run did not submit because stage mother session was absent. | foundation: frontend remains presentation-only and fail-closed, while prior 2026-07-09 stage proof established browser booking. Refresh Supabase mother/operator sessions and rerun current commit through booking, payment, dev-smoke/backend settlement driver, and real settlement projection before e2e_proven. |
| SFC-20260711-UX-002 | Frontend lane | Legacy-like frontend debt in committed modern code inferred settlement repair actions from workflow status, warning tone from reconciliation amount, and rendered smoke-only settlement facts in production source. | frontend_experience / BackendOwnedActionDescriptor, pricing_settlement / SettlementRepairActionProjection | GetSettlementRepairActionsQuery, existing backend retry/cancel commands | No frontend persistence. Frontend 8a9a6f5 removes production smoke DTO/state/rendering and moves examples to colocated tests. | Backend projection must return allowed retry/cancel descriptors, disabled reason, expected revision, and command path/reference; frontend may not derive them from publicStatus or retryState. | Focused tests prove retry/cancel stay absent without descriptor; ESLint blocks reservation-smoke-scenarios and SmokeSettlement under src/**; Playwright desktop/mobile has zero console/network errors. | foundation | Keep controls disabled until backend repair-action descriptor exists. Playwright harness alone may invoke dev-smoke endpoint and then inspect real settlement projection. |
2026-07-06 Feature Checklist Curator Addendum
Section titled “2026-07-06 Feature Checklist Curator Addendum”These rows are narrow additions only. They avoid replacing existing broad payment, settlement, RBAC, document, service-calendar, and family-authority items, and preserve source path/function/menu hints for later implementation. This table is legacy human-readable format. Rows added or touched after 2026-07-07 should also expose the canonical machine-countable fields above or carry equivalent field values in notes until the table is mechanically split.
| Feature ID | Missing source behavior | Source path evidence | Modernization target | Implementation status | Backend-owned replacement |
|---|---|---|---|---|---|
SFC-20260706-CUR-001 | Sales/statistics screens support revenue views, but Kanboard requires self-service National Tax Service/tax-audit/payment-method evidence exports. Current checklist covers analytics and privacy retention, not an export artifact with legal/tax evidence purpose, immutable dataset revision, masked fields, and actor audit. | source-refs/sanmopia-admin/application/controllers/Statistics.php:433-507 (getStatisticForSales, getDataTableForSales), source-refs/sanmopia-admin/application/models/Statistics_model.php:1063-1098 (getSalesStatisticsForMain), source-refs/sanmopia-admin/application/models/Statistics_model.php:1786-1818 (getDataTableForSalesDetail), source-refs/sanmopia-admin/static/js/statistics/sales.js:636-652, source-refs/sanmopia-admin/static/js/statistics/sales.js:740-760, assembly-repo/apps/docs/src/content/docs/migration-source-map/kanboard-renewal-feature-improvements.md:278-309 | business_reporting / TaxEvidenceExportArtifact, pricing_settlement / SettlementEvidenceDatasetRevision, operator_access / EvidenceExportPermission | Backend foundation: e3e9ad6; Cash receipt dataset bridge: d79aeb6 | Add export request command with purpose code (national_tax_submission, tax_audit, payment_method_breakdown), source metric catalog version, settlement/payment ledger revision, branch/HQ scope, field masking profile, generated artifact grant, reviewer-visible checksum, and append-only audit. UI must not use DataTables state or chart totals as evidentiary export authority. d79aeb6 adds the cash-receipt settlement tax-evidence dataset revision bridge with checksum-verified rows, masked identity references, cash-receipt approval/reversal kind, ledger revision, source evidence keys, and Pydantic boundary payloads. |
SFC-20260706-CUR-002 | Lovebox/Momfirst DB export is split between scheduled CSV mail, hardcoded recipient constants, admin filters, and send/no-send flags. Kanboard asks for monthly extraction, daily recipient management, recipient-change history, and privacy-scoped permissions. Existing MomfirstDelivery item does not name recipient schedule/change history. | source-refs/sanmopia_web/application/controllers/cli/Clean.php:1-25 (scheduler_send_csv_data cron hint), source-refs/sanmopia_web/application/controllers/cli/Clean.php:58-125 (makeSendCsvData temp CSV/mail flow), source-refs/sanmopia_web/application/models/Momfirst_model.php:457-468 (putLogForNotSendList), source-refs/sanmopia_web/application/models/Momfirst_model.php:490-542 (CSV row build), source-refs/sanmopia-admin/application/views/promotion/momfirst.php:64-75 (Lovebox/Milk filter + download), source-refs/sanmopia-admin/application/controllers/Promotion.php:470-482, assembly-repo/apps/docs/src/content/docs/migration-source-map/kanboard-renewal-feature-improvements.md:471-491 | customer_engagement / PartnerBenefitRecurringExportSchedule, document_reporting / PartnerBenefitDatasetArtifact, operator_access / PartnerExportRecipientGrant | Backend foundation: c4d0a40 | Replace hardcoded email constants and temp CSV deletion with versioned recipient schedules, monthly/daily export plans, dataset snapshot ids, send/no-send reason events, privacy export permission, delivery attempt ledger, artifact retention, recipient change audit, and signed download/mail grants. |
SFC-20260706-CUR-003 | Printable documents copy reservation free-text/기타 요청사항 into fixed spreadsheet cells. Kanboard calls out line breaks, long text, and font-size handling for initial consultation/reservation intake documents; current template registry item does not name free-text layout policy. | source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3558-3607 (PREFERENCE_ETC->CONTENT into cell B17), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4098-4104 (DOCUMENT_DATA_ID_FIRST_CONSULT_REPORT), assembly-repo/apps/docs/src/content/docs/migration-source-map/kanboard-renewal-feature-improvements.md:250-266 | document_reporting / PrintableFreeTextLayoutPolicy, ReservationIntakeDocumentProjection, DocumentRenderAttempt | Backend foundation: a31229f | Add backend-owned free-text layout decision with source field key, max display length, wrapping/newline policy, font-size downgrade rules, overflow artifact warning, template version, and render-attempt evidence. Operators edit structured note fields; renderers receive layout decisions instead of raw text dropped into fixed cells. |
SFC-20260706-CUR-004 | Repeated Kanboard requests ask for admin-run pre-reservation transfer with target/result/failure/actor fields. Source evidence found only pre-reservation detail routing, customer conversion eligibility, and payment/check pages, not a durable operator transfer command. This is distinct from customer pre-reservation conversion. | assembly-repo/apps/docs/src/content/docs/migration-source-map/kanboard-renewal-feature-improvements.md:471-491, source-refs/sanmopia-admin/application/controllers/Reservation.php:444-455 (pre_reservation_detail routing), source-refs/sanmopia_web/application/controllers/api/Reservation.php:450-472 (isPreReservation), source-refs/sanmopia_web/application/controllers/Service.php:703-776 (preReservationPayment) | reservation_operations / PreReservationManualTransferRun, migration_governance / OperatorDataTransferAudit, operator_access / PreReservationTransferPermission | Backend foundation: 5442c31 | Add an operator command for pre-reservation transfer/backfill with source reservation id, target booking/customer/branch scope, dry-run diff, eligibility reason, failed-row reason, actor/reason, idempotency key, expected source revision, payment/coupon/document impact plan, and immutable transfer audit. Do not reuse customer conversion UI as admin migration authority. |
SFC-20260706-CUR-005 | Customer point import is a CLI spreadsheet runner that reads uploaded workbook rows, carries the previous non-empty point value forward, matches user by name/phone, and writes points inside one transaction with optional rollback. It has no workbook hash, idempotency, actor reason, row-level failure artifact, or point-ledger import run identity. | source-refs/sanmopia-admin/application/controllers/cli/Point.php:10-84, source-refs/sanmopia_web/application/models/User_point_model.php:10-25 | customer_engagement / CustomerPointBulkImportRun, pricing_settlement / CustomerPointLedgerEntry, operator_access / BulkPointImportPermission | Backend foundation: 1b36666 | Backend now has customer_engagement/features/customer_point_bulk_import with dry-run/apply plans, workbook artifact hash, source row number, normalized phone, match decision, carried-forward amount evidence, actor/reason, idempotency key, ledger-line instruction, failure reasons, and import summary. Runtime follow-up: workbook parser/import adapter, Supabase point ledger persistence, permission check, failure artifact storage, and operator UI binding. |
SFC-20260706-CUR-006 | Customer activity telemetry accumulates page dwell time and visit counts through web controllers and log models, caps detail time in PHP, and later reads aggregates for statistics. Route strings, time caps, consent, retention, and analytics projection ownership are implicit. | source-refs/sanmopia_web/application/views/nav/bottom_nav.php:83-110, source-refs/sanmopia_web/application/controllers/Common.php:10-68, source-refs/sanmopia_web/application/models/User_log_model.php:11-108, source-refs/sanmopia-admin/application/models/Statistics_model.php:2204-2224 | business_reporting / CustomerActivityTelemetrySession, customer_engagement / CustomerActivityConsentScope, platform_observability / CustomerActivityAggregateProjection | Backend foundation: 409f146 | Backend now has business_reporting/features/customer_activity_telemetry with server-issued telemetry session id, stable route catalog key/version, source URL hash reference instead of raw URL, consent and retention facts, capped event/session dwell seconds, dedupe token, connect type code, aggregate projection revision/delta, append-only audit event, and Pydantic boundary contracts. Runtime follow-up: Supabase session/detail/aggregate persistence, route catalog adapter, consent policy binding, reporting projection API, and legacy countVisit adapter/disable path. |
SFC-20260706-CUR-007 | Shopping-mall coupon batch issue is a disabled controller method with hardcoded creator, reason, user list, price, coupon type, and HTML echo output. Re-enabling it would mint coupons and user coupon links without dry-run, uploaded recipient artifact, idempotency, or entitlement ledger. | source-refs/sanmopia_web/application/controllers/management/Coupon.php:5-68 | pricing_settlement / ManualShoppingMallCouponBatchIssueRun, customer_engagement / ShoppingMallCouponEntitlement, operator_access / CouponBatchIssuePermission | Backend foundation: a85a5bb | Backend now has pricing_settlement/features/promotion_entitlement/manual_shopping_mall_coupon_batch_issue with disabled-by-default gate, uploaded recipient artifact hash/reference, dry-run/apply mode, row validation, coupon catalog/version through PromotionEntitlementRule, actor/reason, idempotency key, entitlement instruction, failed-row reason, and operator audit basis. Runtime follow-up: Supabase entitlement persistence, recipient parser, permission check, failure artifact storage, and operator UI binding. |
SFC-20260710-CUR-105 | Member-screen operators can issue a one-off gift coupon from a modal by entering free-form coupon name and discount amount. The browser posts those values to /member; the controller passes them through; the model immediately creates a gift coupon plus user-coupon grant with current publication time; coupon history then treats gift coupons as issued and exposes their mutable use/delete/refund state. This is distinct from disabled shopping-mall batch issue, product gift-coupon entitlement, and gift-coupon checkout. | source-refs/sanmopia-admin/application/views/member/member_inquiry.php:99-115, source-refs/sanmopia-admin/application/views/modal/modal_coupon_publish.php:14-25, source-refs/sanmopia-admin/static/js/member/member_inquiry.js:25-34, source-refs/sanmopia-admin/static/js/modal/modal_coupon_publish.js:33-50, source-refs/sanmopia-admin/application/controllers/Member.php:39-71, source-refs/sanmopia-admin/application/models/User_model.php:420-458, source-refs/sanmopia-admin/application/models/Coupon_model.php:503-521, source-refs/sanmopia-admin/application/models/Coupon_model.php:568-583, source-refs/sanmopia-admin/application/models/Coupon_model.php:642-693 | promotion_entitlement / OperatorIssuedGiftCouponGrant, pricing_settlement / ReservationDiscountCouponImpact, operator_access / CouponIssuancePermission | Partial | Add a backend command for one-off operator coupon grants with actor scope, recipient member snapshot, coupon catalog/rule version, amount bounds, approval/reason, idempotency key, entitlement ledger row, user-grant publication fact, and downstream payment/refund/settlement impact plan. Admin UI may request a grant and display projected state only; it must not make coupon name, amount, publication, or deletion/refund readiness authoritative from modal fields or mutable coupon rows. |
SFC-20260706-CUR-008 | Caregiver app persistent login stores encrypted AUTH_TOKEN in a 10-year stay cookie and restores CI session directly from that cookie. Password login rotates MANAGER_TB.AUTH_TOKEN, but stay-login has no backend refresh-token record, device binding, rotation-on-use, revocation ledger, or audit trail. | source-refs/sanmopia-manager/application/models/Auth_model.php:7-44, source-refs/sanmopia-manager/application/libraries/Loginlib.php:36-50, source-refs/sanmopia-manager/application/libraries/Loginlib.php:59-83, source-refs/sanmopia-manager/application/models/User_model.php:24-38 | caregiver_management / CaregiverPersistentSessionGrant, operator_access / CaregiverSessionRecoveryPolicy, security_audit / PersistentLoginAuditEvent | Backend foundation: 8d6b368 | Backend now has caregiver_management/features/caregiver_persistent_session_grant with server-side token hash references, device binding, caregiver eligibility fact, issue/use/revoke commands, rotation-on-use, logout-all scope, denied-use reasons, append-only audit event, and Pydantic boundary contracts. Runtime follow-up: Supabase grant persistence, hashed refresh-token storage, Supabase Auth actor binding, SpiceDB/OPA operator revocation checks, RLS policies, and caregiver-app session API binding. |
SFC-20260706-CUR-009 | Caregiver app sends a free-text “tell headquarters” SMS from raw request cellphone and message values. It has no authenticated caregiver actor, recipient policy, moderation/retention boundary, idempotency, provider-neutral dispatch record, delivery result, or append-only contact audit. | source-refs/sanmopia_web/application/controllers/api/Manager.php:52 (managerWriteFaq), source-refs/sanmopia_web/application/libraries/Aligolib.php:27 | caregiver_engagement / CaregiverHeadquartersContactCommand, communication_delivery / SmsDispatchRequest, operator_access / CaregiverHeadquartersContactPermission | Backend foundation: 02fb3ed + 07f6824 | Backend now has caregiver_engagement/features/caregiver_headquarters_contact with authenticated caregiver actor, branch context, headquarters recipient policy, normalized retained message body, moderation fact, provider-neutral SMS dispatch instruction without raw phone or raw message-body payload, idempotency key, append-only audit event, and Pydantic boundary contracts. Runtime follow-up: Supabase contact/audit persistence, communication workflow binding, recipient policy storage, provider delivery result projection, SpiceDB/RLS permission checks, and legacy managerWriteFaq adapter/disable path. |
SFC-20260706-CUR-010 | Reservation free-text care instruction is captured as “other service/special note” and reused for matching and caregiver schedule, but legacy deletes/reinserts one mutable row with no revision, actor, retention, masking, or instruction visibility contract. | source-refs/sanmopia_web/application/models/Smart_matching_model.php:272 (insertReservationPreferenceEtc), source-refs/sanmopia-admin/application/models/Matching_model.php:207 (loadReservationPreferenceEtcInfoByUserId), source-refs/sanmopia-manager/application/controllers/Schedule.php:29 (schedule_info loads caregiver-visible instruction), source-refs/sanmopia-manager/application/views/service/service.php:550 (기타 서비스(필요시, 직접 기재)) | care_delivery / ReservationCareInstructionSnapshot, caregiver_assignment / MatchingCarePreferenceEvidence, care_delivery/features/reservation_care_instruction | Backend foundation: 41b3913 | Backend now has care_delivery/features/reservation_care_instruction with revision-checked record command, normalized body, author actor/surface, instruction kind, sensitivity policy, matching visibility evidence, caregiver-schedule visibility window, hidden reason codes, append-only audit event, and Pydantic boundary contracts. Runtime follow-up: Supabase snapshot/audit persistence, matching read-model binding, caregiver schedule projection API, retention/masking policy storage, SpiceDB/RLS checks, and legacy preference-row import adapter. |
SFC-20260706-CUR-011 | Manager app has a hidden forceLogin support path: IP whitelist plus daily shared password plus GET id rotates the target caregiver AUTH_TOKEN and logs in as that caregiver, without operator actor, reason, approval, expiry, revocation, or audit. | source-refs/sanmopia-manager/application/controllers/Test.php:12 (forceLogin), source-refs/sanmopia-manager/application/controllers/Test.php:29 (IP whitelist), source-refs/sanmopia-manager/application/controllers/Test.php:39 (id/pwd GET gate), source-refs/sanmopia-manager/application/controllers/Test.php:57 (setAuthToken), source-refs/sanmopia-manager/application/models/User_model.php:24 (setAuthToken) | operator_access / CaregiverSupportImpersonationGrant, security_audit / SupportImpersonationAuditEvent, operator_access/features/support_impersonation | Backend foundation: adcc4cb | Backend now has operator_access/features/support_impersonation with authenticated support actor, target caregiver fact, ticket/reason, approval fact, IP/device hash-reference constraints, short-lived grant window, target-token mutation block, explicit revoke command, idempotency key, append-only audit event, branch/headquarters/security actor vocabulary, and Pydantic boundary contracts. Runtime follow-up: Supabase grant/audit persistence, SpiceDB/RLS authorization checks, support-session API binding, revocation endpoint, and legacy force-login import/disable adapter. |
SFC-20260706-CUR-012 | Customer web API has hidden forceLogin: IP whitelist plus daily shared password plus GET id logs in as any customer using existing USER_TB.AUTH_TOKEN, without support actor, ticket/reason, approval, expiry, revocation, or audit. This is distinct from caregiver support impersonation. | source-refs/sanmopia_web/application/controllers/api/Test.php:15 (forceLogin), source-refs/sanmopia_web/application/controllers/api/Test.php:32 (IP whitelist), source-refs/sanmopia_web/application/controllers/api/Test.php:41 (id/pwd GET gate), source-refs/sanmopia_web/application/controllers/api/Test.php:47 (USER_TB.AUTH_TOKEN lookup), source-refs/sanmopia_web/application/controllers/api/Test.php:52 (authlib->setLogin) | operator_access / CustomerSupportImpersonationGrant, member_management / CustomerAccountSupportSession, security_audit / CustomerSupportImpersonationAuditEvent | Backend foundation: 2ef4ce1 | Backend now has operator_access/features/support_impersonation/customer_support_impersonation with authenticated support actor, customer account target, support-session scope, ticket/reason, approval fact, IP/device hash-reference constraints, short-lived grant window, target-token mutation block, explicit revoke command, customer-named audit event, idempotency key, and Pydantic boundary contracts. Runtime follow-up: Supabase grant/audit persistence, Supabase Auth support-session binding, SpiceDB/RLS authorization checks, revoke/end endpoint, and legacy customer forceLogin adapter/disable path. |
SFC-20260706-CUR-013 | Admin reservation detail/add flows infer payment paid/unpaid state and lifecycle movement from deposit-date fields and status text, while model code recalculates amount and rewrites payment rows. | source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:1217-1272, source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1350-1379, source-refs/sanmopia-admin/application/controllers/Reservation.php:676-687, source-refs/sanmopia-admin/application/controllers/Reservation.php:849-859, source-refs/sanmopia-admin/application/controllers/Reservation.php:1538-1616, source-refs/sanmopia-admin/application/models/Reservation_model.php:1566-1678 | pricing_settlement / OperatorPaymentFactEditCommand, OperatorPaymentDateCorrectionPolicy, operator_access / OperatorPaymentFactEditPermission | Backend foundation: 8786359; Persistence: 5a2ac5c; API binding: ff4e996; Broad-save guard: 4f7b672; Amount snapshot backfill: 9de2d68; Projection refresh: 49245dc; Reservation-detail adapter facts: 183f8f4; Public contract: f230493; Frontend client: f9a14d2 | Backend now has pricing_settlement/features/payment/operator_payment_fact_edit with purpose-tagged manual payment fact edits, explicit paid/unpaid intent, recorded deposit date, expected payment revision, actor capability evidence, reason, idempotency key, immutable amount snapshot, correction audit, shared audit fingerprint helper, projection invalidation keys, Supabase handler/store port, idempotent correction lookup, RPC-backed correction persistence, payment-record revision/snapshot columns, restrict FK audit retention, protected HTTP/API contracts, backend-derived actor/capability evidence, main app handler wiring, receipt-path guard coverage that rejects legacy-style existing payment fact overwrite, historical payment-row amount snapshot backfill, new-row amount snapshot keys for receipt/pre-registration facts, payment-change board amount snapshot projection, settlement board/read-model invalidation for manual payment fact edits, reservation collaboration broad-save rejection for payment-date facts, and reservation-detail snapshot payment_fact.operator_edit_targets for command binding. Public contract now carries explicit edit intent, expected revision, frozen amount authority, date consistency, audit result, and projection invalidations; frontend client consumes that contract with authenticated transport. Runtime follow-up: bind reservation-detail command targets to the admin control organism and prove conflict/recovery behavior. |
SFC-20260706-CUR-014 | Gift-coupon checkout deletes older unpaid payment drafts for the same buyer before inserting a new payment row, so retry/idempotency, stale draft visibility, provider handoff lineage, and anonymous-buyer handling are hidden in destructive cleanup. | source-refs/sanmopia_web/application/controllers/api/Shop.php:25-47, source-refs/sanmopia_web/application/models/Coupon_model.php:280-318 (insertGiftCouponPaymentPrepare), source-refs/sanmopia_web/static/js/shop_gift.js:92-128, source-refs/sanmopia_web/application/views/shop/coupon_order.php:150-158, source-refs/sanmopia_web/application/controllers/api/Payment.php:235-296, source-refs/sanmopia_web/application/models/Payment_model.php:284-324, source-refs/sanmopia_web/application/models/Coupon_model.php:396-440, source-refs/sanmopia_web/application/libraries/Kcppayment.php:175-411, source-refs/sanmopia_web/application/libraries/Kcppayment.php:418-475, source-refs/sanmopia_web/application/controllers/api/Kcp.php:18-101, source-refs/sanmopia_web/application/models/Payment_model.php:512-734 | pricing_settlement / GiftCouponCheckoutSession, pricing_settlement / GiftCouponPaymentDraftSupersessionFact, promotion_entitlement / GiftCouponOfferSelection, pricing_settlement / GiftCouponPaymentCloseout, promotion_entitlement / GiftCouponEntitlementIssuance | Backend foundation: f6f512a; Backend runtime API: 69e78cf; Backend closeout foundation: 6aef95c; Contract checkout: 811768e; Contract closeout: 2ba20fa; OpenAPI/schema: dbf3c96 | Backend now has pricing_settlement/features/payment/gift_coupon_checkout with GiftCouponCheckoutSession, buyer/receiver snapshots, offer/catalog selection, idempotency key, stale-unpaid cutoff, append-only GiftCouponPaymentDraftSupersessionFact, Pydantic application payloads, Supabase persistence for sanmopia_gift_coupon_checkout_sessions and sanmopia_gift_coupon_payment_draft_supersession_facts, backend-only RLS/grant guard, public TS/JSON contract, OpenAPI path, and POST /gift-coupon-checkout-sessions runtime binding. The HTTP boundary accepts camelCase contract payloads, rejects UI-only amount fields, and returns the backend-owned checkout plan; replacement is explicit supersession plus status update, not source-style delete-before-insert. Closeout now has GiftCouponProviderPaymentFacts, instant-payment vs virtual-account-deposit closeout kind, amount-matched GiftCouponPaymentCloseoutPlan, entitlement issuance instruction, buyer/receiver dispatch instructions, compensation-refund intent on entitlement-store failure, Pydantic payloads, and TS contract validation so UI cannot recompute paid amount, closeout outcome, or refund amount. Backend stage proof pnpm supabase:smoke:stage:gift-coupon-closeout-side-effects now ties a paid checkout/payment to issued promotional entitlement, fulfillment request, receiver fulfillment route, and frozen gift-coupon settlement template. Remaining migration: bind live Kill Bill payment attempt and virtual-account issue, ingest provider-originated deposit notifications, persist closeout plans in Supabase, expose closeout API/workflow handoff, execute recipient auto-registration by phone idempotently, connect refund compensation to Kill Bill, handle nonmember buyer later-claim, support resend without receiver mutation, gate used-coupon refund, materialize cancelled gift/product coupon commission lines, and backfill historical gift-coupon payment facts from PAYMENT_COUPON_TB. |
SFC-20260706-CUR-015 | Gift-coupon receiver change/resend verifies the original receiver name and phone as mutation authority; the source has an actual receiver update commented out, but still sends SMS to a new receiver phone. | source-refs/sanmopia_web/application/controllers/api/Shop.php:105-109 (couponResend), source-refs/sanmopia_web/application/controllers/api/Shop.php:132-169, source-refs/sanmopia_web/application/models/Payment_model.php:451-473 (getCouponPaymentData, updateCouponPaymentInfo) | member_management / GiftCouponRecipientAuthoritySnapshot, promotion_entitlement / GiftCouponRecipientRevision, communication_delivery / GiftCouponResendDispatchRequest | Backend foundation: abba19b; Contract: 760838f | Backend now has GiftCouponRecipientAuthoritySnapshot, GiftCouponRecipientContactSnapshot, GiftCouponRecipientRevision, GiftCouponResendDispatchRequest, and GiftCouponRecipientRevisionPlan under the promotion-entitlement slice. The policy requires buyer authority, expected current revision, unused/unregistered and unrefunded entitlement state, accepted receiver snapshot, source evidence keys, and one idempotent resend dispatch bound to the accepted revision. Pydantic and TS contracts validate the same plan so UI cannot send an arbitrary new receiver SMS that diverges from stored entitlement ownership. Runtime follow-up: Supabase recipient-revision persistence, direct-contact dispatch persistence, API/workflow binding, operator repair/audit history, and legacy receiver-change import adapter. |
SFC-20260706-CUR-016 | Gift-coupon refund order differs by channel: customer cancel marks refund/delete flags before provider refund success, while admin delete-coupon refunds first and then flags refunded/deleted. | source-refs/sanmopia_web/application/controllers/api/Shop.php:178-204, source-refs/sanmopia_web/application/controllers/api/Shop.php:213-235, source-refs/sanmopia-admin/application/models/Coupon_model.php:163-186 (deleteCoupon), source-refs/sanmopia-admin/application/models/Coupon_model.php:191-195 | pricing_settlement / GiftCouponRefundSaga, pricing_settlement / PaymentRefundIntent, promotion_entitlement / GiftCouponEntitlementCancellation | Backend foundation: 8586f94; Contract: cadbb1b | Backend now has GiftCouponRefundableEntitlementSnapshot, GiftCouponRefundChannel, GiftCouponRefundSagaPlan, and GiftCouponEntitlementCancellationInstruction. The policy reuses generic PaymentRefundIntent, requires buyer authority for customer self-service, rejects used/registered, already-refunded, or already-cancelled entitlements, and gates entitlement cancellation on provider_refund_succeeded so source refund/delete flags become projections after provider success. Pydantic and TS contracts validate refund amount, expected payment revision, entitlement id matching, and provider-first cancellation ordering. Runtime follow-up: Supabase saga persistence, Kill Bill refund execution, provider result ingestion, entitlement cancellation worker, operator repair/read API, and legacy refund flag backfill. |
SFC-20260706-CUR-017 | Gift-coupon expiration inserts a separate expiration row and then sets USER_COUPON_TB.USE_FL=1, conflating expired with consumed in later reads. | source-refs/sanmopia_web/application/models/Coupon_model.php:38-40, source-refs/sanmopia_web/application/models/Coupon_model.php:216-248, source-refs/sanmopia_web/application/models/Coupon_model.php:628-653 (expireCoupon), source-refs/sanmopia-admin/application/models/Coupon_model.php:656-664 | promotion_entitlement / CouponExpirationLedger, promotion_entitlement / GiftCouponEntitlementState, pricing_settlement / ExpiredCouponSettlementVisibilityPolicy | Backend foundation: 42e4cd2; Contract: 3ab9a08 | Backend now has CouponExpirationLedgerPolicy, CouponExpirationLedgerEntry, GiftCouponEntitlementState, and ExpiredCouponSettlementVisibilityPolicy. It reuses the existing PromotionEntitlement.expire transition, records source expiration evidence separately, projects expired as not consumed, and preserves expired entitlement evidence for settlement/read models instead of reusing a consumed flag. Pydantic and TS contracts reject expired states that also claim consumed. Runtime follow-up: Supabase expiration ledger persistence, scheduled expiration worker, historical USER_COUPON_EXP_TB backfill, read-model migration away from USE_FL, and settlement visibility API binding. |
SFC-20260706-CUR-018 | Admin CLI can issue a raw KCP full refund from ordr_idxx and tno and only dumps provider response, bypassing reservation/payment-change refund intents, payment ledger state, settlement invalidation, actor reason, and repair audit. This is not covered by the partial-refund provider gate from backend 90e4b00 / contract 75aaebe, which plans provider capability for domain refunds but does not replace raw repair/refund execution. | source-refs/sanmopia-admin/application/controllers/cli/Kcp.php:12-24 (refund), source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31-60 (refund, mod_type=STSC) | pricing_settlement / PaymentRefundRepairCommand, pricing_settlement / PaymentRefundLedgerReconciliation, operator_access / ProviderRefundRepairPermission | Backend foundation: b71f600; Persistence: 5241e3c; Permission binding: 69eb6d3; Internal planning route: current; Execution-attempt route: current | Backend now has PaymentRefundRepairCase, ProviderRefundRepairPermission, ProviderRefundRepairPaymentLookup, PaymentRefundRepairPolicy, application handler/store port, and Pydantic boundary payloads, plus Supabase service-role persistence for repair cases, permission decisions, and repair plans in 5241e3c, and a SpiceDB-backed close_reservation_finance permission checker that mints ProviderRefundRepairPermission in 69eb6d3. The token-gated internal route POST /internal/payment-refund-repairs/provider-refund-plans now binds PaymentRefundRepairHandler to Supabase persistence. Repair planning must start from PaymentLedger + PaymentRefundIntent + approved repair case + non-expired provider-refund-repair permission + backend-owned provider lookup; it validates expected payment ledger revision, refund-intent revision, payment id, provider lookup match, idempotency, settlement invalidation key, and creates a normal PaymentRefundGatewayCommand through the append-only payment ledger instead of raw ordr_idxx/tno refund. The token-gated internal POST /internal/payment-refund-repairs/provider-refund-executions route now calls PaymentGatewayClient.refund only when no matching execution attempt already exists, persists idempotency-keyed execution attempts in sanmopia_payment_refund_repair_execution_attempts, replays matching stored attempts into the ledger-backed provider-result recorder, and rejects mismatched idempotency replays. Runtime follow-up: retry backoff/operator result-history projection, settlement read-model invalidation proof, customer/branch visibility policy, and legacy CLI disable/adapter path. |
SFC-20260706-CUR-019 | KCP payment flows carry cash-receipt request/result fields and virtual-account deposit callbacks carry cash-receipt approval fields, but provider closeout, customer receipt, and settlement evidence are persisted as generic provider JSON without a normalized cash-receipt snapshot. Source getResultJson() drops the cash_* values it already read, so tax/settlement evidence can diverge from provider approval. | source-refs/sanmopia_web/application/helpers/util_helper.php:70-110 (getPayResult), source-refs/sanmopia_web/application/libraries/Kcppayment.php:65-69, source-refs/sanmopia_web/application/libraries/Kcppayment.php:145-149, source-refs/sanmopia_web/application/libraries/Kcppayment.php:309-312, source-refs/sanmopia_web/application/libraries/Kcppayment.php:376-410 (cash_*, getResultJson), source-refs/sanmopia_web/application/controllers/api/Kcp.php:60-88 (putKcpNotification) | pricing_settlement / PaymentProviderCashReceiptEvidence, document_reporting / CustomerReceiptTaxEvidenceArtifact, business_reporting / SettlementTaxEvidenceDatasetRevision | Backend foundation: 098cccb; Provider closeout binding: bbe488e; Virtual-account notification adapter: 0f9c419; Customer receipt artifact projection: d247aba; Settlement tax dataset projection: d79aeb6; Visibility policy: e5a1571; Printable access handoff: 04690fa; Receipt render data: 24c5f40; Stored artifact binding: 2c0ce95; Legacy KCP backfill command: 203e179; Internal import endpoint: c48bbfc | Backend now has provider-neutral PaymentProviderCashReceiptEvidence, issue-request and approval-evidence snapshots, payment commercial context, payment ledger revision, refund/reversal linkage, export visibility policy, Pydantic boundary payloads, application handler/store port, and Supabase service-role persistence for sanmopia_payment_provider_cash_receipt_evidence. Provider closeout and virtual-account deposit can now persist cash-receipt request flag, registration purpose, masked identity reference, approval number, transaction number/date, provider notification id, and tax/export visibility as append-only evidence instead of raw KCP JSON or provider receipt URL construction. Payment event ingestion now optionally saves cash-receipt evidence from verified provider payloads in bbe488e, skips raw cash_id_info, and does not block payment workflow when only unsafe identity data exists. 0f9c419 adds the matched KCP virtual-account cash-receipt notification adapter for TX00 deposit callbacks, ignores cancel op_cd=13, requires a masked registration identity reference, and maps KCP approval/transaction numbers into append-only evidence. d247aba adds CustomerReceiptTaxEvidenceArtifactSnapshot, Pydantic boundary payloads, and the pricing-settlement projection from provider cash-receipt evidence to a customer-safe tax-evidence artifact; provider order ids, provider payment refs, and transaction refs remain backend-only evidence and settlement-only cash receipts are rejected from the customer artifact projection. d79aeb6 adds checksum-verified SettlementTaxEvidenceDatasetRevision rows and a pricing-settlement projection that rejects non-exportable/unapproved provider evidence before settlement export. e5a1571 adds branch/customer/HQ/system visibility policy and Pydantic boundary payloads with field profiles, denial reasons, reservation/customer/branch matching, and source evidence keys. 04690fa binds allowed visibility decisions to IssuePrintableDocumentAccessGrantCommand with explicit customer_receipt_tax_evidence printable template kind, so customer receipt UI can request signed document access instead of composing KCP bill URLs. 24c5f40 adds typed receipt render data and a feature-local render plan for existing printable HTML/PDF pipeline; render payload includes masked identity, approval, purpose, ledger revision, field profile, reversal status, and source evidence keys while excluding provider payment/order/transaction refs. 2c0ce95 binds rendered receipt evidence to the shared StoredPrintableDocumentArtifact contract, validating reservation, definition key, template version, byte size, storage bucket/object key, output format, and source evidence keys before document access can point at a stored artifact. 203e179 adds a legacy KCP cash-receipt backfill command that imports approved source rows into append-only provider cash-receipt evidence with deterministic idempotency, masked registration identity references only, skip reasons for unsafe rows, and shared KCP purpose mapping reused by Kill Bill event ingestion and virtual-account notifications. c48bbfc adds a batched import-run handler plus internal bearer-protected /internal/legacy-kcp-cash-receipt-backfill-imports route wired to the Supabase cash-receipt evidence store, with per-row imported/skipped results and OpenAPI coverage. Runtime follow-up: reviewed source extractor/runbook execution for historical KCP cash-receipt rows. |
SFC-20260706-CUR-020 | Sales reporting works around timeout by splitting a selected date range into 30-day browser AJAX calls, then combineData adds numeric fields and concatenates reservation-id strings client-side. Chart totals and table rows can diverge from one backend dataset revision. Source chart/table SQL also recognizes revenue from mutable paid-row status/type ids, deposit-date branches, coupon joins, and payment-fee SQL; refund, partial-refund, provider closeout repair, and settlement-fee repair can therefore leave reporting stale unless they emit revenue-dataset invalidation facts. Legacy refund flips paid rows from status 1 to status 2, while sales SQL joins status 1 rows, so refund/repair changes the source of report truth after prior snapshots. This is distinct from the tax-evidence export row: it covers operational sales dashboard/read-model authority. | source-refs/sanmopia-admin/static/js/statistics/sales.js:625-685 (getChartByFilter), source-refs/sanmopia-admin/static/js/statistics/sales.js:704-738 (setDataTable month chunk loop), source-refs/sanmopia-admin/static/js/statistics/sales.js:1146-1168 (getDatasForAMonth), source-refs/sanmopia-admin/static/js/statistics/sales.js:1181-1217 (combineData), source-refs/sanmopia-admin/application/controllers/Statistics.php:433-498 (getStatisticForSales), source-refs/sanmopia-admin/application/models/Statistics_model.php:1063-1105 (getSalesStatisticsForMain date grouping by deposit rows), source-refs/sanmopia-admin/application/models/Statistics_model.php:1118-1213 (chart revenue, government support, fee, and coupon totals from paid rows and GET_PAYMENT_FEE_RATIO), source-refs/sanmopia-admin/application/models/Statistics_model.php:1812-1856 and :1912-1930 (table revenue/fee totals from paid-row joins, status 19, work-type strings, coupons, and fee SQL), and source-refs/sanmopia_web/application/models/Payment_model.php:383-440 (provider refund then mutable normal/voucher payment status 2). | business_reporting / SalesRevenueDashboardSnapshot, pricing_settlement / RevenueMetricDatasetRevision, pricing_settlement / PaymentRefundRevenueImpact, pricing_settlement / ProviderCloseoutRevenueRecognitionSnapshot, pricing_settlement / PaymentFactReportingInvalidation, pricing_settlement / SalesRevenueDatasetInvalidationAfterPaymentRepair, operator_access / ReportingScopePermission | Backend foundation + contract: bbb6455; Provider refund reporting invalidation: e038c7c; Provider result orchestration: 8db9942; Refresh queue request: fa13ef7; Refresh queue processor: c46382b | Backend now has SalesRevenueDashboardPolicy, SalesRevenueDashboardSnapshot, chart buckets, table rows, recognized revenue totals, row counts, stable drilldown references, bucket grains, date-basis key, metric catalog version, revenue dataset revision key, checksum fingerprint, and Pydantic read payloads. Semantic product/channel/segment codes reject raw source status ids and UI labels; public payloads expose drilldown references but not raw reservation-id lists. Backend e038c7c now persists provider-refund-driven reporting invalidation instructions for sales revenue dashboards after applied, rejected, or failed provider refund results. Backend 8db9942 makes the configured provider-result handler emit those invalidations immediately after recording the paid-row transition decision. Backend fa13ef7 queues provider-refund reporting refresh requests and marks invalidation rows refresh_requested. Backend c46382b adds the typed queue processor and success/failure row transitions. Backend 4bd75d6 binds a sales-dashboard refund-impact refresh validator that marks sales_revenue_dashboard refreshed only when an existing branch sales_overview snapshot contains the affected reservation. Remaining proof: full sales-dashboard fact recomputation, snapshot writer/read API, query adapter from payment/settlement facts, event-driven invalidation from PaymentCloseoutRepairCase and settlement-fee repair facts, reporting scope permission, frontend chart/table migration, and SFC-021 signed drilldown token consumption. |
SFC-20260706-CUR-021 | Sales/performance statistics cells embed raw reservation-id lists into clickable HTML and open /reservation/historyNew/{ids}; reservation history then posts that list back as statisticsReservationId and applies where_in filtering. No signed drilldown token, source query revision, branch-scope proof, expiry, or audit separates a reporting aggregate from operational reservation access. | source-refs/sanmopia-admin/static/js/statistics/sales.js:780-866 (sales count drilldown cells), source-refs/sanmopia-admin/static/js/statistics/sales.js:697-701 (goReservationPage), source-refs/sanmopia-admin/static/js/statistics/performance.js:404-486 (performance count drilldown cells), source-refs/sanmopia-admin/static/js/statistics/performance.js:835-840 (goReservationPage), source-refs/sanmopia-admin/application/controllers/Reservation.php:198-200 (historyNew carries statistic ids), source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:236-245, source-refs/sanmopia-admin/application/models/Reservation_model.php:4621-4624 (statisticsReservationId filter) | business_reporting / ReportingDrilldownSelectionToken, reservation_operations / ReservationHistoryDrilldownReadModel, operator_access / ReportingDrilldownAccessGrant | Backend foundation + contract: d5b9c80 | Backend now has ReportingDrilldownSelectionPolicy, HMAC-signed ReportingDrilldownSelectionToken, selection criteria fingerprint, public-safe selection summary, branch-scoped ReportingDrilldownAccessGrant, actor/scope/metric/dataset checks, expiry/consume semantics, audit event key, and Pydantic payloads that reject legacy statisticsReservationId extras and raw space/comma token values. Remaining proof: Supabase token/criteria persistence, SpiceDB-backed grant issuance, reservation-history token consume query, API route, audit journal persistence, and frontend table click migration from raw ids to signed token handoff. |
SFC-20260706-CUR-022 | Settlement fee classification silently treats payment rows with missing provider context as card-fee rows: service and coupon settlement detail hydration calls getFeeData, writes derived pay method/fee onto each row, adds those fees into branch/HQ settlement totals, and separate helper paths repeat the same 5% fallback when PAYMENT_CONTEXT.pay_method is absent. This can change settlement net amounts without explicit provider evidence or repair audit. | source-refs/sanmopia-admin/application/models/Payment_model.php:418-424 (getFeeData hydrates detail rows), source-refs/sanmopia-admin/application/models/Payment_model.php:445-447 (derived fee contributes to totals), source-refs/sanmopia-admin/application/models/Payment_model.php:488-498 (coupon fee contributes to coupon/settlement totals), source-refs/sanmopia-admin/application/models/Payment_model.php:3920-3969 (getFeeData provider-method fees, missing context defaults to 5%), source-refs/sanmopia-admin/application/models/Payment_model.php:3989-4009 (getFeeForPayMethod missing context fallback), source-refs/sanmopia-admin/application/models/Payment_model.php:4022-4043 (getPayMethodAndFee row-level fallback) | pricing_settlement / SettlementPaymentMethodFeeEvidencePolicy, pricing_settlement / HistoricalPaymentFeeEvidenceBackfill, pricing_settlement / SettlementFeeClassificationRepairCase | Backend foundation | SettlementPaymentMethodFeeEvidencePolicy now classifies explicit card/bank/virtual-account provider facts into immutable fee evidence with stable fingerprints, and missing context/pay method/unsupported method becomes SettlementFeeClassificationRepairCase instead of legacy card-fee fallback. HistoricalPaymentFeeEvidenceBackfill groups deterministic evidence and repair cases for historical import. Remaining proof: persist method/fee evidence with settlement dataset revision, require actor/reason for fee repair, bind settlement projections, and invalidate branch/HQ settlement read models when fee classification changes. |
SFC-20260706-CUR-023 | Branch/HQ settlement statement XLSX export is still a render-time financial authority: the controller streams by raw board id, the spreadsheet model reloads settlement detail rows, writes payment ids, deposited dates, pay methods, customer names, paid amounts, and net deposit amounts, recomputes coupon net deposit from method-specific fee math, then places an Excel SUM formula for total deposit. The export loader also rereads live payment rows and mutable settlement flags, including payment statuses 1/2, DANBEE_STATUS_FL, provider JSON pay method, and board/detail membership/coupon/delivery flags. Refund or closeout repair after export can therefore make a downloaded statement stale unless dataset revisions, export grants, and stored artifacts are invalidated. This is distinct from ReservationDocumentExportWorklist selection/download flow and from CUR-022 provider-fee evidence; exported statement line content itself is not frozen or revisioned. | source-refs/sanmopia-admin/application/controllers/Calculate.php:568-578 (excelDownload reads boardId and streams XLSX), source-refs/sanmopia-admin/application/models/Payment_model.php:353-524 (loadPaymentUserToDanbeeDetail totals current payment rows, fees, coupons, and pay methods), source-refs/sanmopia-admin/application/models/Payment_model.php:3186-3315 (getPaymentDataForDanbee selects mutable paid/refunded statuses and settlement flags), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3772 (downloadExcelFormByPaymentCentralToBranch loads board/detail rows), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3795-3829 (service line cells and PRICE - FEE net deposit), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3834-3880 (coupon line cells and fee recomputation), and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3893-3900 (export total as spreadsheet formula) | document_reporting / SettlementStatementExportLineSnapshot, pricing_settlement / SettlementStatementDatasetRevision, pricing_settlement / SettlementStatementDatasetInvalidationAfterPaymentRepair, document_reporting / SettlementStatementExportArtifactRevocation, operator_access / SettlementStatementExportGrant | Backend foundation: e67350c; Provider refund reporting invalidation: e038c7c; Provider result orchestration: 8db9942; Refresh queue request: fa13ef7; Refresh queue processor: c46382b; Branch export refresh handler: 6bd851c; Safe refresh ids: e705d7c | Backend now has immutable SettlementStatementExportLineSnapshot and SettlementStatementDatasetRevision freezing branch/HQ statement lines, total lines, checksums, and formula-free export cells before render. The branch settlement reconciliation export builder now renders frozen dataset cells instead of recalculating Excel totals from raw board rows. Backend e038c7c now persists provider-refund-driven invalidation instructions for branch/HQ settlement statements and settlement export artifacts. Backend 8db9942 makes the configured provider-result handler emit those invalidations immediately after recording the paid-row transition decision. Backend fa13ef7 queues provider-refund reporting refresh requests and marks invalidation rows refresh_requested. Backend c46382b adds the typed queue processor and success/failure row transitions. Backend 6bd851c adds ProviderRefundSettlementExportRefreshHandler: it resolves payment id to branch profile through ReservationPaymentRecordReader, loads the branch settlement operator dashboard, rebuilds frozen CSV/XLSX/JSON branch reconciliation exports, and runs the durable export workflow for settlement_export_artifact refresh requests. Backend e705d7c hardens workflow request ids by hashing the raw invalidation key and normalizing branch profile id into report-code-safe segments, so provider evidence is not leaked into business-report export codes. Remaining proof: bind the processor to this concrete handler in runtime composition, Supabase artifact storage proof in the stage workflow, SettlementStatementExportGrant, export API/read model, explicit export artifact revocation/reissue history, invalidation/reissue flow from PaymentCloseoutRepairCase, SettlementLedgerReversalLine, and settlement-fee repair facts, and frontend/admin flow wiring. |
SFC-20260706-CUR-024 | Performance dashboard service-balance exception count is computed from raw reservation status ids and SERVICE_BALANCE_CONFIRM_FL inside the statistics model, then the controller fills missing buckets with zero and the browser renders NON_SERVICE_BALANCE_PRICE as a chart series. This creates reporting/settlement state authority outside a versioned metric catalog and can drift from backend service-balance confirmation or settlement projection revisions. | source-refs/sanmopia-admin/application/controllers/Statistics.php:306-342 (non_service_balance_price query and zero-fill), source-refs/sanmopia-admin/application/models/Statistics_model.php:46-50 (NON_SERVICE_BALANCE_PRICE rule from status ids and SERVICE_BALANCE_CONFIRM_FL), source-refs/sanmopia-admin/application/models/Statistics_model.php:165-210 (performance chart buckets grouped by created date), source-refs/sanmopia-admin/static/js/statistics/performance.js:796-806 (browser renders NON_SERVICE_BALANCE_PRICE) | business_reporting / ServiceBalanceExceptionMetricSnapshot, pricing_settlement / ServiceBalanceConfirmationDatasetRevision, operator_access / PerformanceDashboardScopeGrant | Backend foundation: 2fadc96 | Backend now has ServiceBalanceExceptionMetricPolicy, semantic ServiceBalanceExceptionMetricStatusPolicy, frozen facts, daily zero-filled buckets, dataset revision key, metric version, date-basis key, and checksum fingerprint. Raw numeric source status ids are rejected at the domain boundary. Remaining proof: Supabase snapshot persistence, Pydantic/API contracts, dashboard read model, PerformanceDashboardScopeGrant, and frontend chart migration. |
SFC-20260706-CUR-025 | Performance funnel and rebooking metrics are assembled from independent controller/model switches and browser math: source runs separate queries for default service-day, unassigned caregiver, consulting-status, change-status, rebook, and newbook buckets; consulting/change metrics read RESERVATION_CHANGE_LOG.BEFORE_DATA string fragments; newbook/rebook use raw reservation flags/count subqueries; the datatable recomputes rebooking ratio in JavaScript from returned count groups. This is distinct from CUR-024, which covers only the service-balance exception metric. | source-refs/sanmopia-admin/application/controllers/Statistics.php:294-323 (separate performance metric queries), source-refs/sanmopia-admin/application/controllers/Statistics.php:327-368 (zero-fill and max-count derivation), source-refs/sanmopia-admin/application/models/Statistics_model.php:24-62 (SERVICE_DAY_DEFAULT, NON_MANAGER, STATUS_CONSULTING, STATUS_CHANGE, REBOOK, NEWBOOK rules), source-refs/sanmopia-admin/application/models/Statistics_model.php:215-230 (change-log string matching and raw filter assembly), source-refs/sanmopia-admin/application/models/Statistics_model.php:1000-1031 (extension/rebook counts), source-refs/sanmopia-admin/static/js/statistics/performance.js:646-675 (browser rebook ratio calculation), source-refs/sanmopia-admin/static/js/statistics/performance.js:796-809 (browser chart series assembly) | business_reporting / BusinessPerformanceFunnelSnapshot, business_reporting / RebookingMetricDatasetRevision, operator_access / PerformanceDashboardScopeGrant | Backend foundation + contract: 550f3c7 | Backend now has BusinessPerformanceFunnelPolicy, BusinessPerformanceMetricCatalog, normalized BusinessPerformanceFunnelFact, daily zero-filled BusinessPerformanceFunnelBucket, RebookingMetricComponentBucket, backend-owned rebooking numerator/denominator/ratio, date-basis code, metric catalog fingerprint, dataset revision key, checksum, and strict Pydantic payloads. Contracts reject source metric labels and table shapes such as STATUS_CHANGE, STATUS_CONSULTING, REBOOK_COUNT, ALL_COUNT_1, and raw source status ids/service labels. Remaining proof: Supabase snapshot persistence, adapter from reservation/payment/continuation/status-transition facts, PerformanceDashboardScopeGrant, API/read model, and frontend chart/table migration without JavaScript ratio math or raw reservation flag inference. |
SFC-20260706-CUR-026 | Statistics report tables use the browser DataTables contract as query authority: controller reads posted draw/start/length/order/search, maps column indexes to hardcoded report columns, and routes sales/performance/user/branch table types; the generic datatable helper selects requested columns, applies browser order/search across mapped DB columns, counts filtered rows, and limits by posted offset. Sales and performance table paths also load all aggregate rows, slice them in PHP, and build all-branch totals from the full mutable result set. This is distinct from CUR-020 chart chunking and CUR-025 metric definitions; it covers report table query, sorting, filtering, pagination, and totals authority. | source-refs/sanmopia-admin/application/controllers/Statistics.php:112-123 (DataTables request fields), source-refs/sanmopia-admin/application/controllers/Statistics.php:125-168 (hardcoded report table columns), source-refs/sanmopia-admin/application/controllers/Statistics.php:216-241 (posted order/search mapping), source-refs/sanmopia-admin/application/models/Datatable_model.php:32-47 (browser-selected columns), source-refs/sanmopia-admin/application/models/Datatable_model.php:57-86 (browser order/search over mapped columns), source-refs/sanmopia-admin/application/models/Datatable_model.php:94-103 (count and limit), source-refs/sanmopia-admin/application/models/Statistics_model.php:263-269 (performance all-row load then PHP slice), source-refs/sanmopia-admin/application/models/Statistics_model.php:345-520 (performance all-branch totals), source-refs/sanmopia-admin/application/models/Statistics_model.php:1278-1291 (sales all-row load then PHP slice), source-refs/sanmopia-admin/application/models/Statistics_model.php:1293-1575 (sales all-branch totals) | business_reporting / OperatorReportTableSnapshot, business_reporting / ReportTableQueryPolicy, operator_access / ReportTableReadGrant | Backend foundation + contract: d95fdd7 | Backend now has OperatorReportTableColumnCatalog, typed sort/filter/page intents, ReportTableReadGrant, ReportTableQueryPolicy, OperatorReportTableSnapshot, totals-row policy, filtered/total row counts, page cursor, dataset revision key, checksum fingerprint, and Pydantic payloads that reject DataTables transport extras (draw, order, search) and browser column indexes. Remaining proof: Supabase snapshot/query persistence, SQL adapter from report datasets, SpiceDB-backed read grants, API route, export-artifact compatibility, and frontend table migration to typed query intents. |
SFC-20260706-CUR-027 | Visitor/user/branch access statistics derive engagement, demographic, and access-environment metrics from controller/model/browser fragments: controller merges chart/table payloads for userConnect and user; model hardcodes age bands, raw reservation status ids, browser/source TYPE labels, Edge-to-Internet-Explorer normalization, Korean pet type strings, duplicate-user subtraction, and branch exclusions; browser code computes percentages and maps pet counts into visible dog/cat slots. This is distinct from CUR-006 telemetry capture and CUR-026 table query contract; it covers operator-visible engagement metric definitions and totals authority. | source-refs/sanmopia-admin/application/controllers/Statistics.php:380-397 (getStatisticForUserConnect chart/table payload mix), source-refs/sanmopia-admin/application/controllers/Statistics.php:400-415 (getStatisticForUser age and pet payloads), source-refs/sanmopia-admin/application/models/Statistics_model.php:2114-2128 (branch access browser-type rollup and Edge fallback), source-refs/sanmopia-admin/application/models/Statistics_model.php:2194-2232 (user login-type age/device buckets), source-refs/sanmopia-admin/application/models/Statistics_model.php:2234-2258 (age-band reservation status buckets), source-refs/sanmopia-admin/application/models/Statistics_model.php:2314-2365 (pet-type string categorization), source-refs/sanmopia-admin/application/models/Statistics_model.php:2376-2447 (age bucket rollups), source-refs/sanmopia-admin/application/models/Statistics_model.php:2495-2527 (duplicate-user subtraction for new-user metric), source-refs/sanmopia-admin/static/js/statistics/visitor.js:445-546 (browser device ratios and chart percentages), source-refs/sanmopia-admin/static/js/statistics/user.js:593-621 (browser pet count/ratio rendering) | business_reporting / MemberActivityAnalyticsSnapshot, business_reporting / BranchAccessAnalyticsSnapshot, business_reporting / EngagementMetricCatalog, operator_access / EngagementReportScopeGrant | Backend foundation + contract: f5e24a1 | Backend now has EngagementAnalyticsPolicy, AgeBandCatalog, SourceDeviceNormalizationPolicy, PetTaxonomyMappingPolicy, EngagementMetricCatalog, BranchAccessAnalyticsSnapshot, MemberActivityAnalyticsSnapshot, checksum fingerprints, duplicate-user counting, excluded-branch selection, backend-owned integer ratio policy, and strict Pydantic payloads. Public payloads expose normalized age/device/lifecycle/pet taxonomy buckets and reject legacy source labels/count fields such as source_device_label, source_pet_label, DOG_COUNT, CAT_COUNT, and AGE_1_COUNT. Remaining proof: Supabase snapshot persistence, source-data adapter from visitor/user facts, EngagementReportScopeGrant, API routes/read model, and frontend chart/table migration without browser-side percentage math or pet/device relabeling. |
SFC-20260706-CUR-028 | Reservation history list XLSX export is a browser-selected artifact with raw reservation ids in a query string: the history table checkbox stores data-index, download JS joins checked ids, controller explodes reservationArray, and spreadsheet rendering reloads current reservation/payment/address/caregiver rows before streaming PII and payment dates directly to php://output. This is distinct from CUR-021 report drilldown tokens and data-room document bundles; it covers operator reservation-list export authority, privacy scope, and artifact audit. | source-refs/sanmopia-admin/application/views/reservation_status/reservation_history_new.php:127 (download button), source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:357 (row checkbox data-index), source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:708-724 (downloadReservation builds raw id query), source-refs/sanmopia-admin/application/controllers/Reservation.php:1727-1736 (excelDownloadForReservaitonHistoryNew reads reservationArray), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4604-4615 (excelDownload loads template and timestamp filename), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4616-4647 (mutable reservation/payment/address/caregiver query), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4652-4665 (PII/payment-date cells), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4668-4675 (direct XLSX stream) | document_reporting / ReservationHistoryExportSelectionCriteria, document_reporting / ReservationHistoryExportDatasetSnapshot, document_reporting / ReservationHistoryExportArtifactRequest, operator_access / ReservationHistoryExportGrant | Backend foundation + contract: 483593d | Backend now has ReservationHistoryExportSelectionCriteria, ReservationHistoryExportGrant, normalized ReservationHistoryExportSourceRow, frozen ReservationHistoryExportLineSnapshot, ReservationHistoryExportDatasetSnapshot, private ReservationHistoryExportArtifactRequest, content fingerprint, expected filter/query revision, payment-date source revision, PII mask profile, retention policy key, and strict Pydantic payloads. Contracts reject browser query-string ids (reservationArray, 123,456), raw numeric reservation ids, raw phone/address values, and legacy spreadsheet fields such as USER_CELLPHONE, ADDRESS, and BIRTH_DT. Remaining proof: Supabase selection/dataset/artifact persistence, source-row adapter from reservation/payment/address/caregiver projections, SpiceDB/RLS grant issuance, async XLSX/HTML renderer, signed storage download grant, export audit ledger, API route, and admin UI migration from checked raw ids to typed export request. |
-
2026-07-10 source-dig refinement for
SFC-20260706-CUR-020: source sales/statistics screens set the default reporting window in browser state to previous month, post those dates directly to chart/table endpoints, split data-table reads into 30-day chunks, then merge numeric fields and raw reservation-id strings client-side. PHP sales chart/table logic separately classifies offline/manual revenue by raw reservation status19, joins only paid payment rows (PAYMENT_STATUS_LIST_ID_FK = 1), excludes raw status ids[9,14,17,18]and branch id37, and has a legacy fixed March 2020 table query. Evidence:source-refs/sanmopia-admin/static/js/statistics/sales.js:20-25,source-refs/sanmopia-admin/static/js/statistics/sales.js:625-685,source-refs/sanmopia-admin/static/js/statistics/sales.js:704-738,source-refs/sanmopia-admin/static/js/statistics/sales.js:1146-1217,source-refs/sanmopia-admin/application/controllers/Statistics.php:112-123,source-refs/sanmopia-admin/application/controllers/Statistics.php:433-498,source-refs/sanmopia-admin/application/models/Statistics_model.php:1063-1213,source-refs/sanmopia-admin/application/models/Statistics_model.php:1812-1930, andsource-refs/sanmopia-admin/application/models/Statistics_model.php:2612-2627. Target refinements:business_reporting / SalesReportingDateWindowPolicy,business_reporting / RevenueRecognitionStatusCatalog,business_reporting / SalesRevenueDatasetRevision, andoperator_access / SalesReportingScopeGrant. Backend authority must freeze the date window, revenue date basis, recognized/offline/manual channel split, payment fact revision, status catalog revision, branch-scope grant, and dataset checksum before dashboards, drilldowns, or settlement-facing revenue exports render. Browser defaults, raw ids, status math, and PHP fixed-date test queries remain migration evidence only. -
2026-07-10 runtime binding update for
SFC-20260706-CUR-023: backend1a6a7ccnow wiresQueueWorkloadKind.PROVIDER_REFUND_REPORTING_REFRESHtoSupabaseProviderRefundReportingProjectionRefreshProcessorwith the concreteProviderRefundSettlementExportRefreshHandler. The older remaining-proof note about runtime composition binding is superseded. Backend follow-ups now prove reversal lines, branch/HQ statement and operator-board refresh validation, sales-dashboard snapshot coverage validation, and workspace-domain artifact grant revocation. Remaining proof is staged Supabase artifact storage, export grants/read APIs, persisted artifact revocation/reissue lineage, full sales-dashboard recomputation/read APIs, and repair-triggered invalidation. -
2026-07-14 dataset-lineage repair for
SFC-20260706-CUR-023: backendb3d3dc1now persists and rehydrates the branch reconciliation export’sdataset_revision_keyand SHA-256dataset_revision_fingerprintthrough its frozen business-report snapshot. Migration enforcement allows legacy rows with both fields null, or requires both a nonblank key and a lowercase 64-hex fingerprint; a partial pair is rejected. Focused adapter and migration checks pass, including isolated PostgreSQL acceptance of the null pair and exact pair plus rejection of partial and invalid-digest rows. This closes lineage loss in that adapter. It does not prove stage Storage, signed export grants, artifact revocation/reissue, repair-triggered invalidation, or admin UI wiring. -
2026-07-10 source-mining refinement for
SFC-20260706-CUR-003: the initial-consult workbook is also a financial consumer, not only a free-text layout. The spreadsheet builder loads a fixed consultation template, writes current government/customer/service amounts, chooses either mutableCUSTOM_SERVICE_BALANCE_PRICEor the currentPRICE_TABLE['leftPrice'], and parses Korean display labels fromadditionalServicePriceListinto fixed workbook cells. Evidence:source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3500-3509(template load),:3655-3673(current service-balance selection), and:3676-3711(label-parsed add-service amounts). Modern invariant:ReservationIntakeDocumentProjectionandReservationChargeDocumentSnapshotmust consume frozen charge, service-balance, and add-option revisions with typed component codes and integer amounts; document rendering must not read the current custom-balance flag, mutable price table, or Korean labels as financial authority. Status remainsPartial: backenda31229fcovers free-text layout policy, while frozen financial render inputs, artifact invalidation/reissue after charge or refund repair, and historical document-input backfill remain open. -
2026-07-10 source-mining refinement for
SFC-20260706-CUR-022,SFC-20260706-CUR-023, andSFC-20260708-CUR-088: legacy settlement fee rounding diverges across browser, PHP detail, and XLSX consumers. The browser appliesMath.ceilfor explicit card, account-transfer, and virtual-account methods but uses an unrounded five-percent fallback when method evidence is absent; PHP settlement detail and coupon export paths multiply rates without that ceiling. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:854-885,source-refs/sanmopia-admin/application/models/Payment_model.php:3920-3969, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3869-3880. Modern invariant:SettlementPaymentMethodFeeEvidencePolicymust freeze the method, rate, integer-KRW rounding mode, per-line versus aggregate rounding scope, computed fee, policy revision, and evidence revision. Data-room UI andSettlementStatementDatasetRevisionexports must consume that same frozen integer instead of recomputing it. Status remainsPartial: fee-policy and frozen export-line foundations exist, but source-rounding parity, historical backfill, and binding every detail/data-room/export consumer to one fee fact remain unproven. -
2026-07-10 source-mining refinement for existing document delivery owners
ReservationDocumentDelivery,DocumentDeliveryAttempt, andDocumentRecipientAuthority: scheduled system delivery and manual CLI resend capture the Gmail result but do not inspect it before recording sent-state flags, creating customer notifications, and deleting temporary attachments. Manual target/start-document paths also copy every generated attachment to a hardcoded BCC address outside reservation recipient facts. Evidence:source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:104-129,:203-225,:337-363, and:430-455(unchecked delivery result followed by sent-state/notification/temp-file effects), plus:229-243and:620-692(manual delivery with hardcoded BCC). Actors: scheduled system worker and explicitly invoked manual document operator. Backend rule: issue a versioned recipient-authority snapshot for every To/CC/BCC recipient and purpose, persist provider acceptance/failure/unknown outcome before changing delivery state, keep artifact lineage available for retry/reconciliation, and create customer inbox readiness independently from email success. Modern target:DocumentDeliveryAttempt,DocumentRecipientAuthority,DocumentDeliveryResultReconciliation, andStoredPrintableDocumentArtifact. Status remainsPartial: document readiness/artifact/delivery policy foundations exist, but scheduled/manual worker binding, recipient-policy persistence, provider-result history, retry/reconciliation, and removal of hardcoded BCC delivery remain unproven. -
2026-07-10 source-mining correction for
SFC-20260706-CUR-023andSFC-20260706-CUR-044: settlement XLSX export has neither typed collection selection nor actor-bound board scope.Calculaterequires login only, then accepts queryexcelTypeandboardId; the spreadsheet function never usesexcelType, always treats the id asDANBEE_PAYMENT_BOARD_ID_PK, loads a fixed template, and rereads that Danbee board without a branch/HQ grant check. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:4-10and:568-578, plussource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3772. Actor: any authenticated branch or headquarters session reaching the route. Backend rule: derive artifact kind and canonical collection from a typed settlement lookup, resolve board/statement revision server-side, authorize actor plus participant branch before dataset read, and bind build/download to oneSettlementStatementExportGrant; query type or numeric board id must never select collection or scope. Modern target:SettlementDataRoomArtifactRequest,SettlementStatementDatasetRevision,SettlementStatementExportGrant, andSettlementArtifactBuildRunLedger. Status remainsPartial: frozen export-line and refund-refresh foundations exist, while actor-scoped export API/grant persistence, typed artifact-kind binding, stage storage proof, and legacy route disable/adapter work remain open. -
2026-07-10 source-mining refinement for
SFC-20260706-CUR-028andSFC-20260706-CUR-035: reservation-history XLSX receipt dates use a mismatched payment predicate. The subquery tests normal-payment paid status while testing voucher payment type, prefers voucher deposited date throughIFNULL, and falls back to reservation creation time. Outer normal/voucher joins can produce duplicate rows, thenGROUP BYreservation collapses them before receipt and service-payment dates are written to the workbook. Evidence:source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4623-4628,:4642-4649, and:4664-4665. Actor: branch/HQ operator exporting selected reservation-history rows. Backend rule: select receipt date from typed payment purpose plus terminal collection status at an explicit payment-fact revision, choose a deterministic fact when multiple attempts exist, and emit a semantic missing/fallback reason instead of silently substituting booking creation time or SQL group order. Modern target:ReservationHistoryPaymentFactSummaryProjection,ReservationHistoryReceiptDateSelectionPolicy, andReservationHistoryExportDatasetSnapshot. Status remainsBackend foundation / adapter partial: summary and frozen export-dataset contracts exist, but payment-fact source adapter parity, deterministic receipt-date selection, historical discrepancy backfill, and runtime XLSX binding remain unproven.
2026-07-06 Backend Migration Follow-Up
Section titled “2026-07-06 Backend Migration Follow-Up”-
P0 Backend foundation
ReservationExternalCounterpartySettlementStatus. Source evidence:DANBEE_STATUS_FLremains source evidence only. Modern public API now usesGET /reservation-external-counterparty-settlement-statuses/{reservationId}, internal workflow updatePOST /internal/reservation-external-counterparty-settlement-status-updates,ReservationExternalCounterpartySettlementStatus, and Supabase tablesanmopia_reservation_external_counterparty_settlement_statuses. Dataset and evidence fields are nowdatasetRevisionandlineageEvidenceKeysat the public contract boundary. -
P0 Backend foundation
EnterprisePricingMaterializationRule. Pricing product lines now declare materialization target and trigger for customer invoice, caregiver wage, branch settlement, headquarters settlement, and Kill Bill invoice-item draft. This moves settlement timing out of product names, one-off attributes, and UI-calculated payment rows. -
P0 Backend foundation
ServicePauseIntervalandServiceDayCouponEntitlementDecision. Service calendar planning now models paused service intervals, excludes paused dates from billable service days, extends service duration across pauses, rejects extra service days inside pauses, and produces generic credited-service-day coupon entitlement decisions without one-week/two-week branching. -
P0 Backend foundation
ServiceWeekProfile/ServiceDurationProfile. Evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:463-485,source-refs/sanmopia_web/application/models/Reservation_model.php:2515-2630,source-refs/sanmopia-admin/application/models/Reservation_model.php:4142-4250,source-refs/sanmopia-admin/application/models/Reservation_model.php:5376-5418,source-refs/sanmopia_web/static/js/step3.js:603-642,source-refs/sanmopia_web/static/js/step3.js:861-911. Target:service_calendar / ServiceWeekProfile.service_calendaris the canonical owner for service-week length, weekend workday indices, Wanju/service-area duration extension, and legacy end-date compatibility mode. Reservation operations should consume frozen policy decisions and occurrence snapshots instead of owning separate service-week math. Backend commitfee19feaddsServiceWeekProfile,ServiceDurationProfile, and Pydantic payloads under top-levelservice_calendar; profile-backed six-day service weeks can promote Saturday into base service while Sunday stays skipped, and additional-service selections are rejected when a weekend date is already part of base service. Remaining proof: bind profile selection to reservation creation/change APIs, persist profile revisions, migrate Wanju/service-area duration extension into profile rows, and deprecate reservation-owned service-week math. -
P0 Backend foundation
ReservationServiceOccurrenceLedgerandCreditedServiceDayBenefitEntitlement. Evidence:source-refs/sanmopia_web/static/js/step3.js:477-561,source-refs/sanmopia_web/application/models/Report_model.php:324-339,source-refs/sanmopia_web/application/models/Report_model.php:451-466,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4028-4048,source-refs/sanmopia-admin/application/models/Coupon_model.php:218-323,source-refs/sanmopia_web/application/controllers/cli/Reservation.php:302-360,source-refs/sanmopia-admin/application/models/Payment_model.php:872-933,source-refs/sanmopia-admin/application/models/Payment_model.php:966-979. Target:service_calendar / ReservationServiceOccurrenceLedgerpluspricing_settlement / CreditedServiceDayBenefitEntitlement. Holiday, suspension, added Saturday/holiday, report/export, refund, settlement, and coupon issuance consumers must read one frozen occurrence ledger with skipped/added reasons, policy fingerprint, credited-service-day facts, attendance evidence, benefit eligibility, and settlement recognition period, not recalculate from browser counts, mutableHOLIDAY_TBrows, sourcediffDay == 15, or service-end-plus-one-month SQL. Backend commit2085085addsReservationServiceOccurrenceLedgerand typed Pydantic projection payloads under top-levelservice_calendar: service-term plans now project stableoccurrence_evidence_key, credited service-day sequence, skip reason, selected extra-day linkage, holiday keys, and frozen policy fingerprint. Pydantic rejects client-mutated credited counts/keys. Backend commit5108868persists the ledger throughReservationServiceOccurrenceLedgerStoreand Supabase tablessanmopia_reservation_service_occurrence_ledgers/sanmopia_reservation_service_occurrence_ledger_entries; stage Supabase migration20260707081211is applied with RLS, service-role grants, JSON snapshot checks, credited-sequence invariants, and no anon/auth table grants. Backend commitbbde5e2addsReservationServiceOccurrenceLedgerCommandHandler, so reservation creation or change services can project aServiceTermPlanand write the frozen ledger through one application command. Backend commit7289fd4wires successful booking orchestration to that command when an acceptedServiceTermPlanis supplied;booking_test.py::test_reservation_booking_success_persists_occurrence_ledgernow creates a reservation and persists its occurrence ledger at application level. Backend commit7f7e061exposesacceptedServiceTermPlanon HTTP/ReState reservation start payloads and maps it through PydanticPlanServiceTermPayloadinto the booking command, so occurrence counts are computed by backend policy instead of UI numbers. Backend commit87a3021wires the Supabase booking runtime to the occurrence-ledger store and exposesservice_occurrence_ledger_keyfrom the Python API response; runtime tests prove successful booking writes ledger and entry upserts. Backend commit26864d8adds a revisioned ledger command and shared key builder, so reservation change/admin flows can persistv2+occurrence ledgers instead of mutating the original booking snapshot. Backend commit70b4b67addsReservationServiceTermMutationCommandHandler; it requires the expected reservation revision and previous ledger, rejects stale reservation revisions when a current-revision reader is attached, rejects already-used target revisions, requires branch coverage evidence for service-area profile changes, and carries actor/reason source evidence into the revised ledger. Backend commitf3d87e5exposesPOST /reservation-service-term-mutations/{reservationBookingId}with Supabase session auth, SpiceDB reservationmanagepermission, PydanticPlanServiceTermPayloadintake, and focused API/HTTP tests; targeted booking tests also prove reservation creation can persist an occurrence ledger. Supabase runtime now bindsSupabaseReservationServiceTermMutationRevisionReader, so service-term mutation rejects stale saves againstsanmopia_reservation_bookings.revision_number. 2026-07-07 follow-up addsOperatorServiceTermMutationDraft, which converts operator source-form evidence intoApplyReservationServiceTermMutationCommandonly after proving source start/end/term/selected dates match the backend-ownedPlanServiceTermPayload; broad-save status/payment fields are rejected and must use dedicated commands. 2026-07-07 backend follow-up exposesPOST /reservation-service-term-mutations/{reservationBookingId}/operator-draft-applicationsso operator save/change adapters can submit camelCase source evidence without leaking UI authority into the ledger command; contract follow-up publishes the route builder, request/response types, and validation helpers. Remaining proof: bind concrete source save/change callers to this route, run live/stage HTTP/ReState E2E booking smoke, migrate report/export/refund/settlement/coupon readers to the ledger, and move benefit entitlement execution intopricing_settlement. 2026-07-07 sidecar: after initial booking, source still changes service dates, service term, extra Saturday/holiday dates, holiday policy, stop/resume boundaries, extension drafts, local benefit duration/discount facts, and service-balance/payment closeout through mutable admin/customer paths. Modern backlog names:ReservationServiceTermMutationCommand,AdditionalServiceDaySelectionRevision,HolidayPolicyAffectedReservationReplan,ServiceSuspensionInterval,ContinuationServiceTermPlanBinding,RegionalBenefitServiceTermImpact, andPaymentCloseoutOccurrenceLedgerGuard. Evidence:source-refs/sanmopia-admin/application/controllers/Reservation.php:676-695,source-refs/sanmopia-admin/application/controllers/Reservation.php:902-934,source-refs/sanmopia-admin/application/models/Reservation_model.php:1682-1711,source-refs/sanmopia-admin/application/models/Reservation_model.php:4089-4139,source-refs/sanmopia-admin/application/controllers/ManageSystem.php:47-63,source-refs/sanmopia_web/application/models/Report_model.php:312-349,source-refs/sanmopia_web/application/controllers/api/Reservation.php:243-289,source-refs/sanmopia-admin/application/models/Reservation_model.php:1536-1679,source-refs/sanmopia-admin/application/models/Service_model.php:71-103,source-refs/sanmopia-admin/application/models/Service_model.php:190-260, andsource-refs/sanmopia-admin/application/models/Reservation_model.php:3667-3678. Mutation API caller inventory is recorded inweekly-service-calendar-refund-gap-mining.md; source caller names to cover are/reservation/saveReservationData,/reservation/savePreReservationData,/reservation/insertAddService,/reservation/deleteService,/api/reservation/inputServiceStartDate,/api/reservation/inputDeliveryData,/api/reservation/request/{stop,change},/api/reservation/processContinue,/service/insertYeongdeungpoFl,/manageSystem/editHoliday, and/reservation/confirmServiceBalance. Required behavior: each post-booking mutation must produce or reference a backend-ownedServiceTermPlanandReservationServiceOccurrenceLedgerrevision with expected revision, actor/reason, consumer invalidation, and finalized charge/settlement links; UI math, date-array overwrite, address string matching, reservation status changes, payment date fields, and reservation-change-log JSON matching remain evidence only. Backend commita414f59implements the first application-layerPaymentCloseoutOccurrenceLedgerGuardproof: branch/HQ settlement commands can be configured to require the current frozen occurrence-ledger key/revision before settlement closeout proceeds. Backend commit777b496binds the production financial-lifecycle advancer toSupabasePaymentCloseoutOccurrenceLedgerReferenceReader, which reads the latest revision from the existingsanmopia_reservation_service_occurrence_ledgerstable. Backend commite5a4043addsPaymentCloseoutFinalizedChargeSnapshotGuardproof for branch/HQ settlement closeout, binds production toSupabasePaymentCloseoutFinalizedChargeSnapshotReferenceReader, rejects blank or stale finalized-charge snapshot ids, and proves HTTP payload passthrough. Contract commitb258745exposesserviceOccurrenceLedgerKey,serviceOccurrenceLedgerRevisionNumber, andfinalizedChargeSnapshotIdon settlement ledger-line preparation payloads. Focused proof: backendadvance_reservation_financial_lifecycle_test.py,supabase_payment_closeout_finalized_charge_snapshot_test.py,reservation_financial_lifecycle_http_test.py,main_test.py, Ruff, Tach, contract layout, ESLint, TS build, and focusedreservation-payment_test.tspass on 2026-07-07. Backend commit743976caddsPaymentCloseoutServiceBalanceConfirmationGuardproof for branch/HQ settlement closeout, binds production toSupabasePaymentCloseoutServiceBalanceConfirmationReferenceReader, reads the existingsanmopia_service_balance_payment_closeoutsbooking row, rejects blank/non-service-balance/duplicate closeout evidence, and proves HTTP payload passthrough forserviceBalanceCloseoutEventId. Contract commit3fc9a89exposesserviceBalanceCloseoutEventIdon settlement ledger-line preparation payloads. Focused proof: backendadvance_reservation_financial_lifecycle_test.py,supabase_payment_closeout_service_balance_confirmation_test.py,reservation_financial_lifecycle_http_test.py,main_test.py, Ruff, Tach, contract layout, ESLint, TS build, and focusedreservation-payment_test.tspass on 2026-07-07. Current slice addsPaymentCloseoutAdditionalServiceSelectionRevisionGuardproof for branch/HQ settlement closeout: settlement commands can require a currentadditionalServiceSelectionRevisionKeyplus revision number, production reads the revision from reservation collaboration journal rows whereservice_schedule.extra_service_dayschanged, freezes a digest of currentsanmopia_reservation_extra_service_days, and rejects stale closeout payloads so legacy/reservation/insertAddServiceand/reservation/deleteServicestyle payment rewrites stay source evidence only. Contract payloads exposeadditionalServiceSelectionRevisionKeyandadditionalServiceSelectionRevisionNumber. -
P0 Backend foundation
BranchServiceCoverageProfile. Branch coverage now has configurable serviceable, consultation-only, unsupported, and conditionally serviceable outcomes using Daum/Kakao address region attributes, effective periods, and branch override policy. Remaining proof: application/API/Supabase persistence wiring and migration from old service-area policy rows. -
P0 Backend foundation
ReservationFieldConflictComparison. Reservation collaboration conflicts now carry backend-built submitted/current field versions, actor kind, actor profile id, audit event id, operation command, revision, and available resolution choices. This replaces browser overwrite guessing with auditable branch/HQ winner selection. -
P0 Runtime proof
SFC-20260706-CUR-028ReservationHistoryExport. Supabase runtime now persists backend-owned source-row projections, selection criteria, frozen dataset snapshots, and artifact requests in SSOT tables with RLS/access-control registry entries. FastAPI exposes typed reservation-history export request/dataset/artifact routes, and the composition root wires SpiceDB branch/reservation view checks before issuing an export grant. Remaining proof: async XLSX/HTML renderer, Supabase Storage signed download handoff, artifact audit ledger, and admin UI removal of checked raw-id query strings. -
SFC-20260706-CUR-029Reservation-history worklist filter conflicts. Source filters combine browser flags and raw status ids, then build contradictory SQL (statusIndex1and selected status equality) that can silently empty a list. Evidence:source-refs/sanmopia-admin/application/views/reservation_status/reservation_history_new.php:109-116,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:241-244,source-refs/sanmopia-admin/application/models/Reservation_model.php:4597-4607,source-refs/sanmopia-admin/application/models/Reservation_model.php:4626-4641. Target:reservation_operations / ReservationHistoryWorklistFilterDecisionplusoperator_access / ReservationWorklistScopeGrant. Status:Partial actual: a885c87 + contract 18955f7 + backend c9b06d7 + frontend 1f95287. Backend owns typed status-bucket grammar, explicit conflict reason codes, and branch/query revision guards. The new query-onlyreservation_operation_worklistslice exposes a principal-scoped GET with semantic repeated statuses, search, cursor, and limit; it resolves exactly one branch-operator membership, checks SpiceDBbranch:view, and applies the server-owned branch predicate at the booking read. Frontend SSR renders explicit auth/failure states plus search/status/clear controls. Stage-data evidence observed branch operator200, mother403,501visible rows, first page50, and desktop/mobile browser success. Remaining proof: Supabase query-intent persistence, date-basis and quick-filter conflict UX, expected/actual birth and received/deposit columns, unplanned/unassigned and service-balance worklists, HQ cross-branch scope, and server-authoritative mutation conflict/replay before operation execution is enabled. -
SFC-20260706-CUR-030Service-balance follow-up worklist.잔금 미지정 진행is hidden in admin list filters with hardcoded status ids, confirmation flag, service-end grace window, and stop/done exclusions. Evidence:source-refs/sanmopia-admin/application/views/reservation_status/reservation_history_new.php:117-120,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:243,source-refs/sanmopia-admin/application/models/Reservation_model.php:4609-4619. Target:pricing_settlement / ServiceBalanceFollowUpWorklistSnapshotandreservation_operations / ServiceBalanceCompletionRiskPolicy. Status:Backend foundation: a885c87. Backend now hasServiceBalanceCompletionRiskPolicy,ServiceBalanceFollowUpReservationFact, frozen worklist snapshot, semantic reservation-state codes, confirmation revision keys, grace-window policy, and Pydantic boundary payloads rejecting raw status ids. Remaining proof: Supabase snapshot persistence, adapter from service-balance projection, operator action availability API, and frontend removal ofnonServiceBalancePricelist math. -
SFC-20260706-CUR-031Near-start unassigned caregiver queue.관리사 미지정 예약is computed fromMANAGER_ID IS NULL, cancellation exclusion, and DB-localnow()+2 daysmath in reservation-history query. Evidence:source-refs/sanmopia-admin/application/views/reservation_status/reservation_history_new.php:106-108,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:240,source-refs/sanmopia-admin/application/models/Reservation_model.php:4591-4595. Target:caregiver_assignment / UnassignedCareReservationWorklistSnapshotandreservation_operations / NearStartCoverageRiskPolicy. Status:Backend foundation: a885c87. Backend now hasNearStartCoverageRiskPolicy,UnassignedCareReservationFact, frozen near-start snapshot, assignment revision keys, deterministic business-date window, excluded-state reason codes, and Pydantic payloads that reject legacyMANAGER_IDfield authority. Remaining proof: Supabase assignment-risk projection persistence, branch timezone binding, worklist API route, assignment decision evidence panel, and frontend migration from rawnonManagerflag to typed backend projection. -
SFC-20260706-CUR-032Reservation-history date scope and return-state token. Legacy history list lets browser/hash state control date scope, default-date bypass, branch/status return behavior, and query filters across JS and SQL. Evidence:source-refs/sanmopia-admin/application/views/reservation_status/reservation_history_new.php:70-79,source-refs/sanmopia-admin/application/views/reservation_status/reservation_history_new.php:98-100,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:79-87,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:105-116,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:140-142,source-refs/sanmopia-admin/application/models/Reservation_model.php:4652-4693. Target:reservation_operations / ReservationHistoryDateScopeDecisionandoperator_access / ReservationHistoryReturnStateToken. Status:Backend foundation: 41e23fb. Backend now owns date-basis enum, max-range policy, explicit default-date bypass reason, query revision guard, typed branch/status filter snapshot, actor/branch/surface-bound return token, and Pydantic contracts rejecting legacydateType,serviceDateDefault, andbranchIdhash authority. Remaining proof: Supabase return-token persistence, reservation-history API route, branch timezone/date preset adapter, frontend replacement of location-hash state with typed return-state token, and audit linkage after detail-page return. -
SFC-20260706-CUR-033Reservation retirement command. Legacy admin UI enables physical reservation deletion from status-driven buttons and controller/model delete paths. Evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:3814-3826,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:192-204,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:593-611,source-refs/sanmopia-admin/application/controllers/Reservation.php:1108-1118,source-refs/sanmopia-admin/application/models/Reservation_model.php:3645-3655. Target:reservation_operations / ReservationRetirementCommandandoperator_access / ReservationDeletionCapability. Status:Backend foundation: 8c51885. Backend now replaces physical delete withReservationRetirementCommand,ReservationRetirementPolicy,ReservationRetirementDecision, dependency snapshots, expected revision, actor reason, idempotency key, soft-retire/review/reject outcomes, audit key, and scopedReservationDeletionCapability. Pydantic contracts reject legacyreservation-id,DELETE_FL, and raw numeric status ids. Remaining proof: Supabase soft-retire/archive columns, legal retention/RLS policy, API route, dependency collector adapter, SpiceDB-backed capability issuance, and frontend removal of irreversible delete button authority. -
SFC-20260706-CUR-034Product coupon action availability and change request. Legacy coupon actions rely on Korean status strings, role-based UI hiding, and mutable request flags. Evidence:source-refs/sanmopia-admin/application/models/Coupon_model.php:330-363,source-refs/sanmopia-admin/application/models/Reservation_model.php:3888-3916,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:145-170,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:471-512,source-refs/sanmopia-admin/application/controllers/Reservation.php:1095-1105,source-refs/sanmopia-admin/application/models/Coupon_model.php:385-406. Target:promotion_entitlement / ProductCouponActionAvailabilityandpromotion_entitlement / ProductCouponChangeRequestCommand. Status:Backend foundation: d1ef285. Backend now owns semantic publication state, branch/HQ action availability, service-day wait policy, publication-window closure, expected entitlement revision, actor-bound change request command, idempotent audit/outbox keys, and Pydantic contracts rejecting legacyfreservation-id,COUPON_STATUS,REQUEST_FL, and raw numeric ids. Remaining proof: Supabase publication snapshot/change-request persistence, API route, notification outbox dispatch, SpiceDB action grants, frontend removal of Korean-status button branching, entitlement-review workflow binding, and consumption of the frozen service occurrence ledger so coupon waits are based on backend credited-service-day facts. -
SFC-20260706-CUR-035Reservation-history payment fact summary projection. Legacy list infers visible payment dates from raw subqueries and display strings such as미입력. Evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:4514-4535,source-refs/sanmopia-admin/application/models/Reservation_model.php:3940-3988,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:334-338,source-refs/sanmopia-admin/static/js/reservation_status/reservation_history_new.js:546-551. Target:pricing_settlement / ReservationHistoryPaymentFactSummaryProjection. Status:Backend foundation: 184ce67. Backend now projects purpose-split payment date slots fromReservationPaymentSummary, freezes receipt date fallback, source revision, projection revision, payment fact keys, semantic display state, and missing-date reason codes. Pydantic contracts reject legacyBEFORE_PAYMENT_DT,AFTER_PAYMENT_DEPOSITED_DT,PAYMENT_TYPE_LIST_ID_FK,미입력, and raw numeric ids. Remaining proof: Supabase projection persistence, reservation-history API/read-model binding, payment fact adapter, branch/HQ permission scoping, and frontend migration from display strings to semantic date slots. -
SFC-20260706-CUR-036External referral export withdrawal and cancellation notice side-effect plan. Legacy cancellation flow sends hardcoded refund text and flips external export delete flags inside reservation save logic. Evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:2033-2049,source-refs/sanmopia-admin/application/models/Reservation_model.php:5876-5900. Target:document_reporting / ExternalReferralExportWithdrawalPlanandcommunication_delivery / ReservationCancellationNoticePolicy. Status:Backend foundation: 1a523ae. Backend now adds explicit cancellation side-effect follow-ups,CustomerCancellationNotice,ExternalReferralExportWithdrawal, template-driven refund-window notice variables, withdrawal/retention decisions for unsent/sent/unknown external referral exports, idempotency keys, and Pydantic contracts rejecting legacy hardcoded message fields plusMOMFIRST_ID_PK,SEND_FL, andDELETE_FL. Remaining proof: Supabase persistence for withdrawal commands/retentions, communication outbox dispatch through configured provider, external-referral adapter, workflow execution, API/read-model binding, and audit ledger persistence. -
SFC-20260706-CUR-037Branch settlement board summary projection. Legacy settlement board computes component status/totals in PHP and writes display strings into money/status meanings. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:24-39,source-refs/sanmopia-admin/application/controllers/Calculate.php:57-60,source-refs/sanmopia-admin/application/models/Payment_model.php:1098-1129,source-refs/sanmopia-admin/application/models/Payment_model.php:1137-1205,source-refs/sanmopia-admin/application/models/Payment_model.php:1210-1337,source-refs/sanmopia-admin/application/views/table/calculate/table_local_cal_central.php:42-56,source-refs/sanmopia-admin/application/views/calculate/local_calculate_central.php:71-94,source-refs/sanmopia-admin/application/views/table/calculate/table_local_cal_central.php:76-82,source-refs/sanmopia-admin/application/views/table/calculate/table_local_cal_central.php:91-92,source-refs/sanmopia-admin/application/controllers/Calculate.php:72-120,source-refs/sanmopia-admin/application/models/Payment_model.php:96-138, andsource-refs/sanmopia-admin/application/views/table/calculate/table_local_cal_danvi.php:20-29. Target:pricing_settlement / BranchSettlementBoardSummaryProjectionandpricing_settlement / SettlementComponentFollowUpState; includepricing_settlement / ExternalCounterpartySettlementBoardSummaryProjectionfor Danbee current-board counts. Backend must own component states, payable/paid/unpaid totals, current-board count buckets, line policy version, board revision, and branch/HQ/external-counterparty scope. Status:Backend foundation: f0f9997. Backend now addsBranchSettlementBoardSummaryProjection,SettlementComponentSummary, andSettlementComponentFollowUpState. Amounts, paid/unpaid totals, board revision, dataset revision, line policy version, branch/HQ scope, component evidence, and follow-up states are separated from UI display labels such as입금완료. Strict Pydantic contracts reject legacy raw status/amount keys. 2026-07-09 source-mining follow-up: the current Danbee board has the same projection gap as branch/HQ board summaries: PHP excludes branch ids36/37, counts voucher/normal/complete/unprocessed rows from mutable current payment data, and the table renders count/status cells directly. Frontend/admin must render backend projections only, not recount fromSERVICE_TYPE,PAYMENT_*, branch filters, or display strings. Remaining proof: Supabase projection persistence, branch and external-counterparty settlement board API binding, operator worklist/read-model route, SpiceDB/RLS branch/HQ grants,BranchHeadquartersSettlementCommandBindingfor HQ request, branch acknowledgement, HQ approval, Danbee acknowledgement, and arrears request commands, frontend removal of view-side money/status rendering, and runtime smoke on a real branch/HQ/Danbee settlement board. -
SFC-20260706-CUR-038External counterparty settlement worklist. Legacy Danbi-style settlement pages count service-category strings and recompute untreated rows in the view to decide정산필요/정산완료. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:72-91,source-refs/sanmopia-admin/application/controllers/Calculate.php:107-112,source-refs/sanmopia-admin/application/models/Payment_model.php:119-159,source-refs/sanmopia-admin/application/views/table/calculate/table_local_cal_danvi.php:25-29. Target:pricing_settlement / ExternalCounterpartySettlementWorklistSnapshotandpricing_settlement / SettlementReadinessDecision. Backend must own service-category counts, confirmed/residual counts, readiness reason, period revision, and detail grant. Status:Backend foundation: 86454f2. Backend now addsExternalCounterpartySettlementWorklistSnapshot,ExternalCounterpartyServiceCategoryCount, andSettlementReadinessDecision. Service-category counts use stablevoucher_care/private_caredomain values, confirmed and residual counts are backend-computed, readiness reason is derived from residual count, and a detail grant key is required before UI navigation. Strict Pydantic contracts reject legacy labels such as바우처,일반,정산필요, and rawPAYMENT_STATUS. 2026-07-10 source-mining refinement: external-counterparty settlement period scope must be explicit backend policy, not inherited from branch/HQ settlement date rules. Legacy Danbi current-board screens accept year/month filters, butgetPaymentDataForDanbee()leaves the deposited-date predicate commented out, so unprocessed Danbi rows are selected by mutable payment/external-counterparty status and branch scope rather than the visible month. Branch/HQ voucher settlement uses service-end plus one month, while coupon and normal branches use coupon publish/deposit-derived dates. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:84-120,source-refs/sanmopia-admin/application/models/Payment_model.php:96-159,source-refs/sanmopia-admin/application/models/Payment_model.php:3294-3316,source-refs/sanmopia-admin/application/models/Payment_model.php:3519-3537,source-refs/sanmopia-admin/application/models/Payment_model.php:3674-3682, andsource-refs/sanmopia-admin/application/models/Payment_model.php:3721-3729. Addpricing_settlement / ExternalCounterpartySettlementPeriodPolicyandpricing_settlement / SettlementDateBasisSnapshotso each worklist row records which date basis made it eligible. Remaining proof: Supabase worklist projection persistence, branch/HQ detail-grant issuance, API/read-model binding, DataRoom/settlement command binding separated from head-office-to-branch settlement statements, route integration, frontend removal of view-side count/status/date-scope decisions, and runtime smoke against real external-counterparty settlement rows. -
SFC-20260706-CUR-039Settlement history board summary and detail grants. Legacy settlement history pages recount branch/HQ historical board rows from PHP and navigate by raw board ids. Evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:2292-2366,source-refs/sanmopia-admin/application/models/Payment_model.php:2370-2475,source-refs/sanmopia-admin/static/js/calculate/local_cal_danvi_history.js:45-107,source-refs/sanmopia-admin/static/js/calculate/local_cal_central_history.js:18-31. Target:pricing_settlement / SettlementHistoryBoardSummarySnapshotandoperator_access / SettlementHistoryDetailAccessGrant. Backend must own frozen historical board counts/totals, source dataset revision, detail grant, and no PHP recount from service strings, status ids, or raw board navigation. Status:Backend foundation: b774b2a. Backend now addsSettlementHistoryBoardSummarySnapshot,SettlementHistoryReservationCount, andSettlementHistoryAmount. Historical reservation counts and amount buckets are frozen with source dataset revision, snapshot revision, detail access grant key, and stable board kind/category/amount enums. Strict Pydantic contracts reject legacy labels such as바우처and raw board id transport likeDANBEE_PAYMENT_BOARD_ID_PK. Remaining proof: Supabase history snapshot persistence, operator_access detail grant issuer, branch/HQ history APIs, route binding for central/external history views, frontend removal of DataTables/raw-board navigation, and runtime smoke on historical settlement rows. -
SFC-20260706-CUR-040Settlement historical fee effective-period policy. Legacy settlement history can join membership/fee rows using current month instead of the board period. Evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:843-845,source-refs/sanmopia-admin/application/models/Payment_model.php:1872-1875,source-refs/sanmopia-admin/application/models/Payment_model.php:2452-2456. Target:pricing_settlement / SettlementHistoricalFeeEffectivePeriodPolicyandpricing_settlement / SettlementMembershipDueSnapshot. Backend must own board-period fee snapshots, policy fingerprint, period key, and backfill path so historical settlement does not drift when current fee rules change. Status:Backend foundation: 58da19c. Backend now addsSettlementPeriodKey,SettlementMembershipDueSnapshot,SettlementHistoricalFeeEffectivePeriodPolicy, andSettlementHistoricalFeeEffectivePeriodDecision. Legacy raw period keysYYYYMandYYYYMMnormalize to canonicalYYYY-MM; membership due snapshots are tied to board period, effective period, policy version, policy fingerprint, source fee record, and lineage evidence. Policy detects legacy current-period drift and returns explicit backfill paths:create_board_period_membership_due_snapshotorrebuild_history_row_from_board_period_snapshot. Strict Pydantic contracts reject SQL/current-date transport such asCONCAT(YEAR(CURDATE()), MONTH(CURDATE()))and rawTHIS_DTauthority. Remaining proof: Supabase adapter forsanmopia_branch_membership_due_snapshots, historical board read-model binding, backfill runner, branch/HQ history API wiring, and runtime smoke that older boards do not change when current branch membership fee policy changes. -
SFC-20260706-CUR-041Offline reservation identity evidence policy. Legacy admin/offline voucher intake disables or bypasses resident-number checks and persists placeholder identity fragments as normal facts. Evidence:source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:858-870,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1229-1239,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1619-1623,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:2216-2268,source-refs/sanmopia-admin/application/controllers/Reservation.php:1362-1368,source-refs/sanmopia-admin/application/models/Reservation_model.php:5058-5065. Target:reservation_operations / OfflineReservationIdentityEvidencePolicyandmember_management / SensitiveIdentityPlaceholderDecision. Backend must own redacted identity evidence keys, placeholder reason, validation source, actor scope, and no normal-domain storage of placeholder resident fragments. Backend foundation:4740948.OfflineReservationIdentityEvidencePolicynow turns source placeholders, admin bypasses, and legacy imports into backend-owned placeholder/validated decisions.SensitiveIdentityPlaceholderDecisionowns member-privacy placeholder facts and always prohibits normal-domain storage of placeholder resident fragments. Pydantic contracts reject legacy raw fields such asuser_number_1/user_number_2and raw placeholder values such as000000/0000000. Remaining proof: Supabase persistence, operator/member privacy audit ledger, reservation intake API binding, and migration backfill that replacesRESERVATION_SERVICE_VOUCHER_TB.USER_NUMBER*placeholder fragments with redacted evidence keys. -
SFC-20260706-CUR-042Caregiver lifecycle state command and availability invalidation. Legacy manager admin toggles active/delete/reentry flags directly. Evidence:source-refs/sanmopia-admin/application/controllers/Manager.php:1032-1054,source-refs/sanmopia-admin/application/models/Manager_model.php:1055-1089,source-refs/sanmopia-admin/application/models/Manager_model.php:1092-1140. Target:caregiver_management / CaregiverLifecycleStateCommandandcaregiver_assignment / CaregiverAvailabilityInvalidation. Backend must own reason, effective date, expected revision, actor scope, assignment/payout invalidation facts, and audit events instead of rawACTIVE_FL,DELETE_FL, orREENTRY_FLtoggles. Backend foundation:e5d9fc4.CaregiverLifecycleStatePolicynow maps activate/deactivate/retire/reentry commands to active/retired/reentry-approved state decisions with expected profile revision, actor scope, reason code, audit event key, and assignment/payout invalidation requirements.CaregiverAvailabilityInvalidationPolicynow emits matching-cache, open-assignment, and payout-projection invalidation scopes from lifecycle decisions. Pydantic contracts reject raw source flags such asACTIVE_FL. Remaining proof: Supabase profile-state event persistence, assignment and payout projection invalidation workers, operator API binding, SpiceDB actor grant check, and migration backfill from sourceACTIVE_FL/DELETE_FL/REENTRY_FL. -
SFC-20260706-CUR-043Caregiver referral applicant case. Legacy manager referral/applicant pages mix PII, desired area, branch assignment, and memo mutation without case revision or branch-scope grants. Evidence:source-refs/sanmopia-admin/application/models/Manager_model.php:748-878,source-refs/sanmopia-admin/application/controllers/Manager.php:2056-2077,source-refs/sanmopia-admin/static/js/manager/manager_recommend_detail.js:5-24,source-refs/sanmopia-admin/application/models/Manager_model.php:2283-2301. Target:caregiver_management / CaregiverReferralApplicantCaseandoperator_access / CaregiverRecruitingCaseScopeGrant. Backend must own applicant-case commands, PII boundary, memo revision, branch assignment authority, and recruiting notification hooks. Backend foundation:1b9be8a.CaregiverReferralApplicantCasePolicynow turns profile update, branch assignment, memo revision, contact record, and withdrawal into expected-revision case decisions with private-profile keys, memo content keys, PII audit event keys, case audit event keys, branch assignment state, and recruiting notification hooks.CaregiverRecruitingCaseScopeGrantnow owns read/private-profile/branch-assignment/memo/contact capabilities, branch scope, expiry, and denial reasons. Pydantic contracts reject legacy PII/source table fields such asPHONEandMANAGER_RECOMMEND_ID_PK. Remaining proof: Supabase case/event persistence, private profile storage grants, recruiting notification outbox, operator API binding, SpiceDB grant materialization, and migration backfill fromMANAGER_RECOMMEND_TB. -
SFC-20260706-CUR-044Settlement detail actor/lookup grant. Legacy detail lookup derives actor/view authority from query params. Evidence:source-refs/sanmopia-admin/application/controllers/Common.php:15-17,source-refs/sanmopia-admin/application/controllers/Common.php:132-147,source-refs/sanmopia-admin/application/controllers/Common.php:156-196,source-refs/sanmopia-admin/static/js/calculate/local_cal_central_history.js:18-31. Branch/profile-status follow-up evidence:source-refs/sanmopia-admin/application/core/MY_Controller.php:113-116,source-refs/sanmopia-admin/application/controllers/DataRoom.php:223-227,source-refs/sanmopia-admin/application/controllers/DataRoom.php:241-245,source-refs/sanmopia-admin/application/controllers/DataRoom.php:290-304,source-refs/sanmopia-admin/application/models/Branch_model.php:76-122,source-refs/sanmopia-admin/application/models/Payment_model.php:1354-1428,source-refs/sanmopia-admin/application/models/Payment_model.php:1662-1696,source-refs/sanmopia-admin/application/models/Payment_model.php:2731-2776, andsource-refs/sanmopia-admin/application/models/Payment_model.php:2917-2962. Detail action-label and return-route evidence:source-refs/sanmopia-admin/application/controllers/Common.php:100-129,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:53-61,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:43-49,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi_other_office.php:48-63,source-refs/sanmopia-admin/static/js/data_room/calculate_danvi.js:10-13,source-refs/sanmopia-admin/static/js/data_room/calculate_central.js:10-13,source-refs/sanmopia-admin/static/js/data_room/calculate_danvi_other_office.js:10-21, andsource-refs/sanmopia-admin/static/js/calculate_detail.js:228-310. Command-side actor evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:22-65,source-refs/sanmopia-admin/static/js/calculate_detail.js:220-287,source-refs/sanmopia-admin/application/controllers/Calculate.php:151-313, andsource-refs/sanmopia-admin/application/controllers/Calculate.php:337-369. Target:pricing_settlement / SettlementDetailLookupGrantandoperator_access / SettlementDetailScopeGrant; addoperator_access / SettlementBranchActorProfileBindingandpricing_settlement / SettlementParticipantBranchRoleProjectionto cover branch profile and inter-office side mapping; addpricing_settlement / SettlementDetailActionProjectionandoperator_access / SettlementDetailReturnStateTokenfor button labels, enabled/disabled reasons, download/detail links, and post-action return routes; addoperator_access / SettlementActionCommandGrantfor branch/HQ/Danbee acknowledgement and closeout command authority. Backend must derive actor from auth, accept typed collection/detail lookup key, verify board/reservation branch scope, collection kind, participant branch role, expected projection revision, and reject browser-ownedgetType,dataType,branchId, orfbranchTypeauthority. Legacy data-room/detail pages let sessiontype,BRANCH_INDEX, rawBRANCH_ID_PK/BRANCH_ID, queryboardId/branchId,BRANCH_MANAGER_INDEX,BRANCH_SERVICE_INDEX,BRANCH_TYPE,STATUS_FL,BOARD_STATUS_FL,DANBEE_STATUS_FL, andOTHER_OFFICE_STATUS_FLdecide who can view or act; central detail reloads branch data fromboardId, and inter-office board status is selected by branch type rather than a signed reservation/branch-role grant. Legacy list/detail views also choose Korean action labels such as입금대기,입금확인,정산완료,미납상태,정산필요, and상세조회from raw board status and redirect after submit usingdocument.referreror hardcoded data-room paths. Command-side legacy JavaScript postsftype,fbranch-id,fdata-type,fboard-id, andfbranch-type; controller branches on postedftypeto choose admin-vs-branch settlement behavior, writes admin actions as branch0, and changes board status/paid flags from posted fields. SFC-088/SFC-095 cover the amount and fee calculations; this row owns the actor/action grant. Frontend must render backend projections only. Backend foundation:8561cfc.SettlementDetailLookupGrantnow binds typed external-counterparty, branch-to-headquarters, headquarters, and inter-office detail lookup keys to actor, collection, scope, expected projection revision, branch scope, idempotency, expiry, and source evidence.SettlementDetailScopeGrantnow owns branch/HQ actor permissions for settlement-detail read, closeout preparation, and export capabilities without importing pricing domain types. Pydantic contracts recursively reject legacy query-authority fields includinggetType,dataType,branchId,fbranchType,boardId, andfreservationId. Remaining proof: Supabase lookup-grant persistence, SpiceDB materialization, branch-profile binding persistence, API route binding, settlement data-room read-model adapter, conflict/audit event logging, and frontend migration from query-string detail navigation to signed lookup grant selection. -
SFC-20260706-CUR-045Settlement board transition source-log provenance. Source settlement logs lose board identity and encode admin as branch0. Evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:26-31,source-refs/sanmopia-admin/application/controllers/Calculate.php:245,source-refs/sanmopia-admin/application/controllers/Calculate.php:258-262,source-refs/sanmopia-admin/application/controllers/Calculate.php:270-275,source-refs/sanmopia-admin/application/controllers/Calculate.php:285,source-refs/sanmopia-admin/application/controllers/Calculate.php:309. Target:pricing_settlement / SettlementBoardTransitionProvenanceRepairandpricing_settlement / settlement_transition_audit_import. Backend must import source logs as low-confidence evidence with inferred actor, branch/admin marker, before/after aliases, nullable board link, repair reason, and not treat sourceinsertLog($branchId, $boardId, ...)as reliable audit. Backend foundation:ab775a2.SettlementBoardTransitionProvenanceRepairPolicynow importsLOG_BOARD_PAYMENT_ADMIN_TBrows as low-confidence provenance, maps source branch marker0to inferred headquarters administrator, keeps branch markers as inferred branch operators, separates no-op attempts from committed transitions, supports repaired effective after-state when source branch completion logged before/after incorrectly, and records board-reference repair reasons instead of trusting the dropped$boardIdargument. Pydantic contracts expose strict import/provenance payloads and reject unexpected source fields such asboardId. Remaining proof: Supabase import-run persistence, source table/schema extractor, board-reference repair adapter, transition provenance read model, operator audit display, and backfill runbook with row samples around known settlement boards. -
SFC-20260706-CUR-046Settlement period-key compatibility. Legacy settlement period identity uses rawTHIS_DTstrings such asYYYYMorYYYYMM, and some joins depend on string parsing. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:27-34,source-refs/sanmopia-admin/application/controllers/Calculate.php:171,source-refs/sanmopia-admin/application/controllers/Calculate.php:221-223,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:28-35,source-refs/sanmopia-admin/application/models/Payment_model.php:4312-4323,source-refs/sanmopia-admin/application/models/Payment_model.php:4335-4341. Target:pricing_settlement / SettlementStatementPeriodKeyCompatibilityandpricing_settlement / settlement_statement_period_identity. Backend must normalize raw period keys to canonicalYearMonth, retain raw source key, enforce branch-period uniqueness, and use normalized period for fee snapshots. Backend foundation:da8cc74.SettlementStatementPeriodIdentitynow reuses the existingSettlementPeriodKeynormalization for sourceYYYYMandYYYYMM, preservesraw_source_period_key, exposes canonicalYYYY-MM, derives branch-period identity keys, pins membership-due snapshot references, and rejects duplicate branch-period identities. Pydantic contracts expose strict normalize/result payloads and reject browser-derived ad hoc fields such asfmonth. Remaining proof: Supabase unique constraint/backfill adapter, board import using canonical period, fee snapshot adapter migration, settlement query route binding, and legacyTHIS_DTcompatibility runbook. -
SFC-20260706-CUR-047Settlement DOM row-selection integrity. Legacy settlement preparation mutates financial rows from checked DOM rows, comma arrays,data-price, and array order. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:81-165,source-refs/sanmopia-admin/static/js/calculate_detail.js:677-690,source-refs/sanmopia-admin/static/js/calculate_detail.js:763-800,source-refs/sanmopia-admin/application/views/calculate_detail.php:546-565,source-refs/sanmopia-admin/application/models/Payment_model.php:537-597,source-refs/sanmopia-admin/application/models/Payment_model.php:699-718. Target:pricing_settlement / SettlementLineSelectionSnapshotandpricing_settlement / settlement_statement_preparation. Backend must issue immutable selection tokens with line ids, row group ids, payment purpose, amount snapshot, source revision, and require commands to carry token plus expected revision only. Backend foundation:05443c5.SettlementLineSelectionSnapshotnow freezes selected line ids, row group keys, payment-purpose codes, amount snapshots, source revisions, source row references, actor, board revision, and selection-token reference.SettlementLineSelectionCommandReferenceaccepts only selection token, expected board revision, board reference, and ordered selected line keys, so legacy parallel arrays cannot drive mutation. Pydantic contracts derive totals and selected-line keys from selected rows, reject browser-side total tampering, and recursively reject DOM authority fields such asfarray-normal-id,farray-payment-type,data-price,data-id,fdelivery-price, andfresult-price. Sidecar mining also found hidden membership/delivery/ETC rows, coupon-linked row toggles, pay-method fee math, and select-all group state incalculate_detail.js; these must become backend charge inclusion and fee evidence policies. Remaining proof: Supabase selection-token persistence, statement-preparation command binding, line status mutation adapter, linked-line closure policy, fee/charge inclusion policy migration, and frontend replacement of checked DOM arrays. -
SFC-20260706-CUR-048Inter-office settlement closeout quorum. Legacy inter-office closeout depends on service/customer branch side strings,BRANCH_TYPEmagic values, and row-count equality. Evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:2731-2796,source-refs/sanmopia-admin/application/models/Payment_model.php:2917-2962,source-refs/sanmopia-admin/application/controllers/DataRoom.php:296-304,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi_other_office.php:48-63. Allocation and UI authority evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:2777-2810,source-refs/sanmopia-admin/application/models/Payment_model.php:2816-2850,source-refs/sanmopia-admin/application/models/Payment_model.php:2881-2907,source-refs/sanmopia-admin/application/views/calculate_detail.php:340-390,source-refs/sanmopia-admin/application/views/calculate_detail.php:1230-1355,source-refs/sanmopia-admin/static/js/calculate_detail.js:169-181,source-refs/sanmopia-admin/static/js/calculate_detail.js:220-285. Target:pricing_settlement / InterOfficeSettlementCloseoutQuorumandpricing_settlement / inter_office_settlement_closeout, extended bypricing_settlement / InterOfficeSettlementAllocationPolicySnapshotandpricing_settlement / InterOfficeManualAdjustmentLineCommand. Backend must derive required participant acknowledgements from frozen projected lines; service office and customer-handoff acknowledgements must reference line ids and revisions, with no hardcoded row-count closeout. Backend must also freeze the inter-office allocation inputs: coupon deduction tier from service days, service-office versus customer-handoff branch share, service-office coupon carry, settlement fee policy, manual ETC adjustment catalog/revision, and expected line revision. Frontend and admin pages must render backend projections only, never postresultPrice,feePrice,totalPrice, or branch-type strings as settlement authority. Backend foundation:202616b.InterOfficeSettlementCloseoutQuorumnow requires service-delivery and customer-relationship participant acknowledgements against the same frozen settlement-line revision set and the same expected projection revision. It reuses the existingInterOfficeSettlementAcknowledgementSidevocabulary asInterOfficeSettlementParticipantRoleto avoid duplicate side enums, rejects duplicate participant acknowledgements, participant-branch mismatch, stale projection revision, missing/extra line revisions, and legacy role strings such asserviceOffice. Pydantic contracts recursively reject legacy closeout fields includingbranchType,BRANCH_TYPE,BOARD_STATUS_FL,resultPaymentInfo,DANBEE_STATUS_FL, andOTHER_OFFICE_STATUS_FL. Sidecar mining confirmed legacy closeout’s hidden quorum wasresultPaymentInfo == 3over payment rows, not durable participant agreement. Remaining proof: Supabase quorum/ack persistence, application mapper from existing statement acknowledgements to line revisions, closeout-command handler binding, board status projection, operator audit display, and legacyBRANCH_TYPEbackfill adapter. -
SFC-20260706-CUR-049Customer voucher identity validation parity. Customer voucher booking still validates resident-number checksum and gender parity through browser scripts plus partial PHP branching, separate from the offline/admin placeholder policy. Evidence:source-refs/sanmopia_web/static/js/common/common.js:24-79,source-refs/sanmopia_web/static/js/common/common.js:107-114,source-refs/sanmopia_web/static/js/step3_voucher.js:144-171,source-refs/sanmopia_web/application/controllers/api/Service.php:329-335. Target:reservation_operations / VoucherIdentityValidationPolicyandmember_management / RedactedResidentIdentityEvidence. Backend must own checksum, foreign-number support, gender/parity eligibility, redacted evidence keys, and reason codes. Frontend must not decide voucher eligibility from resident-number fragments. Backend foundation:f88cd43. Contract foundation:3bf65b1.VoucherIdentityValidationPolicynow decides voucher identity eligibility from redacted evidence facts that carry checksum status, domestic/foreign resident-identity kind, gender parity, source evidence keys, and stable reason codes.RedactedResidentIdentityEvidencenow owns domestic and foreign resident-registration checksum classification and exposes only masked display plus evidence keys. Pydantic application contracts forbid legacy raw fields such asUSER_NUMBER1,USER_NUMBER2,reg_number_front,reg_number_back, andjumin; public TS/JSON contracts now expose checksum, identity kind, gender parity, and source evidence while rejecting raw numeric evidence keys. Verification: focused colocated pytest for member/reservation identity slices and Supabase adapter,ruff check,ruff format --check, Tach dependency/interface/external gates, Vulture confidence-100 scan, and contractpnpm check. Backend follow-up544c27fnow records voucher recipient identity evidence into service-role-ownedsanmopia_redacted_resident_identity_evidencesrows without raw resident number storage. Remaining proof: bind sensitive validation and evidence recording to the booking API/RPC, replace customer voucher UI fragment validation with backend decision reads, and backfill existing voucher rows. -
SFC-20260706-CUR-050Voucher service selection atomicity guard. Legacy voucher service update can delete/replace service rows before identity-safe validation and expected-revision checks are complete. Evidence:source-refs/sanmopia_web/application/controllers/api/Service.php:220-229,source-refs/sanmopia_web/application/controllers/api/Service.php:329-335,source-refs/sanmopia_web/application/models/Reservation_model.php:488-512. Target:reservation_operations / VoucherServiceSelectionMutationPlanandreservation_operations / SensitiveIdentityValidationAtomicityGuard. Backend must validate identity, reservation revision, service-row revision, and mutation plan before destructive row replacement. Backend foundation:9969110.VoucherServiceSelectionMutationPlannow requires matching reservation booking id, expected reservation revision, expected service-selection revision, expected service-row revision, expected add-option revision, target service profile, target price catalog version, target service period, idempotency key, source evidence keys, and a successfulVoucherRecipientIdentityEligibilityDecisionbefore any supersede/append operation can be emitted. The guard returns a rejected decision with no mutation plan for identity validation failure, reservation/service/add-option revision conflicts, and reservation mismatch. Pydantic contracts reject legacy destructive fields such asRESERVATION_SERVICE_VOUCHER_TB,RESERVATION_SERVICE_NORMAL_TB,RESERVATION_ADD_OPTION_*,USER_NUMBER1,USER_NUMBER2, andreg_number_*. Sidecar source mining also found hidden follow-up gaps in actor reservation ownership, service-type/price-version selection, birth/start-date validation, continuation eligibility, and voucher add-option/weekend/holiday collection revision handling. Verification: focused colocated pytest with voucher identity slices,ruff check,ruff format --check, Tach dependency/interface/external gates, and Vulture confidence-100 scan. Remaining proof: bind this plan to the booking API/RPC transaction, persist service-selection/add-option revisions, compose actor guard and price catalog snapshot, and replace the legacy delete-first UI/API flow. -
SFC-20260706-CUR-051Voucher sensitive identity draft projection. Customer voucher form rehydrates raw resident-number fragments from source DB into the booking screen. Evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:516-532,source-refs/sanmopia_web/application/views/service/step3_voucher.php:74-85,source-refs/sanmopia_web/application/models/Reservation_model.php:2439-2456. Target:member_management / SensitiveResidentIdentityDraftProjectionandreservation_operations / VoucherIntakeSensitiveFieldGrant. Backend must expose masked readiness state or short-lived sensitive-field grant only; rawUSER_NUMBER1/USER_NUMBER2must not return to normal UI payloads. Status:Backend foundation implementedin backend commitd4ed8d6. The migrated slices add masked readiness projections, short-lived sensitive field grants, Pydantic raw-field rejection, shared resident-identity contract guard, colocated tests,ruff, Tach dependency/interface/external gates, and Vulture confidence-100 scan. Remaining proof: bind the projection/grant to the customer voucher booking API/RPC, persist sensitive-field grant events, compose Supabase Storage/private-profile grants if raw re-entry is needed, and backfill legacy voucher identity rows into redacted evidence snapshots. -
SFC-20260706-CUR-052Operator voucher identity field visibility. Operator detail/pre-reservation screens expose raw or placeholder voucher resident-number facts. Evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:948-963,source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:290-295,source-refs/sanmopia-admin/application/views/reservation_status/pre_reservation_detail.php:140-145. Target:operator_access / VoucherIdentityFieldVisibilityDecisionandmember_management / PlaceholderResidentIdentityDisplayPolicy. Backend must decide masking, actor scope, placeholder reason visibility, and audit before any operator surface can show sensitive identity fields. Status:Backend foundation implementedin backend commit62a5070. The migrated slices add branch/HQ scoped operator visibility grants,hidden/masked_identity/placeholderdecisions for normal and pre-reservation detail screens, placeholder display codes instead of UI text hardcoding, shared masked-display contract validation, colocated tests,ruff, Tach dependency/interface/external gates, and Vulture confidence-100 scan. Runtime follow-up: bind these decisions into the operator reservation detail/pre-reservation read models, persist visibility decision events, add SpiceDB relationship materialization, and backfill blank legacy voucher rows into placeholder display reasons. -
SFC-20260706-CUR-053Voucher identity document evidence snapshot. Document rendering can derive birth/resident evidence from voucher resident fragments and fixed spreadsheet cells. Evidence:source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:254-260,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3609-3611,source-refs/sanmopia-admin/application/controllers/Reservation.php:1362-1368. Target:document_reporting / VoucherIdentityDocumentEvidenceSnapshotandmember_management / ResidentIdentityPlaceholderConsumerPolicy. Renderers must consume verified/redacted identity evidence snapshots; placeholder/raw fragments must not create document cells or birthdate facts. Status:Backend foundation implementedin backend commits37527b3and544c27f. The migrated slices add semantic document identity fields instead of fixed spreadsheet cell writes, verified evidence gating for birthdate facts, placeholder consumer denial for document renderers, raw-fragment rejection, colocated tests,ruff, Tach dependency/interface/external gates, and Vulture confidence-100 scan. Backend544c27fadds the redacted evidence producer and service-role Supabase table; invalid or ineligible identity inputs keep document evidence fields missing so render sources remain waiting. Runtime follow-up: bind printable document renderers to semantic field values, bind producer calls into voucher intake/customer/admin commands, backfill verified redacted identity evidence from legacy voucher rows, and map semantic fields to template slots per document definition. -
SFC-20260706-CUR-054Caregiver referral intake duplicate policy and notification. Legacy public/caregiver referral form collects PII, desired area, work history, and memo, normalizes phone in controller code, duplicate checks by referrer/name/phone, insertsMANAGER_RECOMMEND_TB, logs PII, and sends a hardcoded Aligo director alert. Evidence:source-refs/sanmopia-manager/application/views/manager_recommend.php:32-63,source-refs/sanmopia-manager/static/js/other/manager_recommend.js:1-7,source-refs/sanmopia-manager/application/controllers/User.php:132-158,source-refs/sanmopia-manager/application/models/User_model.php:82-111,source-refs/sanmopia-manager/application/config/constants.php:104-105. Target:caregiver_management / RegisterCaregiverReferralApplicant,caregiver_management / CaregiverReferralDuplicatePolicy, andcustomer_engagement / RecruitingNotificationRequested. Backend must own required fields, phone canonicalization, duplicate scope, PII logging policy, and notification template/outbox. Status:Backend foundation implementedin backend commitf217c7f. The migrated slice addsRegisterCaregiverReferralApplicant,CaregiverReferralDuplicatePolicy, canonical contact normalization, referrer/name/contact duplicate match keys, initial applicant-case creation, provider-agnostic recruiting notification intents, PII/case audit event keys, legacy raw-field rejection, colocated tests,ruff, Tach dependency/interface/external gates, and Vulture confidence-100 scan. Runtime follow-up: bind the public/caregiver referral endpoint, persist private profiles and duplicate match keys transactionally, map notification intents tocommunication_delivery, add idempotency/unique DB constraints, and replace legacy full-PII/token logging with redacted audit events. -
SFC-20260706-CUR-055Caregiver referral applicant detail projection. Legacy admin detail loads applicant PII, desired area, work history, mention, memo, raw table id, and branch list directly into a mutable form. Evidence:source-refs/sanmopia-admin/application/models/Manager_model.php:762-787,source-refs/sanmopia-admin/application/views/manager/manager_recommend_detail.php:52,source-refs/sanmopia-admin/application/views/manager/manager_recommend_detail.php:76-98,source-refs/sanmopia-admin/application/views/manager/manager_recommend_detail.php:115-123,source-refs/sanmopia-admin/application/views/manager/manager_recommend_detail.php:190-195,source-refs/sanmopia-admin/application/controllers/Manager.php:2016-2050. Target:caregiver_management / CaregiverReferralApplicantCaseDetailandoperator_access / RecruitingCaseViewGrant. Backend must own detail projection, field masking, raw-id lookup protection, and branch-scoped access. Status:Backend foundation implementedin backend commit25aa4f8. The migrated slice addsCaregiverReferralApplicantCaseDetailSource,CaregiverReferralApplicantCaseDetailProjection, andCaregiverReferralApplicantCaseDetailPolicy, reuses existingCaregiverRecruitingCaseScopeGrant, blocks legacy raw recommendation table id exposure, masks private profile/work history/message/memo fields unless scope allows them, rejects legacy detail raw fields, and includes colocated tests,ruff, Tach dependency/interface/external gates, and Vulture confidence-100 scan. Runtime follow-up: bind detail read model to recruiting scope decisions, hydrate private profile/content keys from Supabase storage, and replace raw id route lookup with stable applicant case ids. -
SFC-20260706-CUR-056Caregiver referral applicant worklist search policy. Legacy DataTable maps browser sort/search columns to broad SQLLIKEover PII/work fields, branch filter, date truncation, and self-referral label fallback. Evidence:source-refs/sanmopia-admin/static/js/manager/manager_recommend.js:7-80,source-refs/sanmopia-admin/application/controllers/Manager.php:678-738,source-refs/sanmopia-admin/application/models/Manager_model.php:790-878. Target:caregiver_management / CaregiverReferralApplicantWorklistandcaregiver_management / ReferralApplicantSearchPolicy. Backend must own searchable fields, sort keys, self-referral label, branch scope, PII exposure, and count semantics. Status:Backend foundation implementedin backend commitf3d671b. The migrated slice addsCaregiverReferralApplicantWorklistQuery,ReferralApplicantSearchPolicy,CaregiverReferralApplicantWorklistRow,CaregiverReferralApplicantWorklist, and strict Pydantic payloads. Backend now owns stable search-field and sort-key taxonomy, branch-scoped counts, separaterecords_total/records_filteredsemantics, self-referral label keys, private phone suppression, legacy raw recommendation id suppression, and rejection of source DataTables/raw SQL fields such asPHONE,NAME,MANAGER_RECOMMEND_INDEX,order,search, andbranch_index. Runtime follow-up: bind query execution to Supabase read models, issue recruiting-scope grants for private-profile search, and replace legacy DataTables parameters with typed worklist requests. -
SFC-20260706-CUR-057Caregiver referral applicant closure audit. Legacy recommend applicant delete action hard-deletesMANAGER_RECOMMEND_TBby raw id with no reason, expected revision, or audit. Evidence:source-refs/sanmopia-admin/static/js/manager/manager_recommend.js:73-75,source-refs/sanmopia-admin/static/js/manager/manager_recommend.js:103-121,source-refs/sanmopia-admin/application/controllers/Manager.php:1473-1485,source-refs/sanmopia-admin/application/models/Manager_model.php:1042-1052. Target:caregiver_management / CloseCaregiverReferralApplicantCaseandcaregiver_management / RecruitingCaseClosureAudit. Backend must replace hard delete with explicit closure state, reason, idempotency, branch/access guard, and audit trail. Status:Backend foundation implementedin backend commit8f9cc30. The migrated slice addsCloseCaregiverReferralApplicantCase,RecruitingCaseClosureAuthorization,RecruitingCaseClosureAudit, andCaregiverReferralApplicantCaseClosureDecision; extends recruiting access withclose_case; and keeps caregiver-management closure domain independent fromoperator_accessby consuming an authorization snapshot. Backend now requires stable applicant case ids, expected case revision, actor key, idempotency key, reason code/detail key, branch-scoped authorization, replay handling for duplicate idempotency, already-closed rejection, and aphysical_delete_performed = falseinvariant. Public contracts reject legacy raw delete fields such asMANAGER_RECOMMEND_ID_PK,MANAGER_RECOMMEND_INDEX,manager_recommend_index,type, andDELETE. Runtime follow-up: bind DELETE replacement route to typed closure command, store closure audit in Supabase, mapCaregiverRecruitingCaseScopeGrantintoRecruitingCaseClosureAuthorization, and show closed/tombstone state instead of disappearing deleted rows. -
SFC-20260706-CUR-058Caregiver referral conversion and incentive eligibility. Legacy WinTheRace SQL matches referral to hired caregiver by raw name+phone, requires service days over threshold, excludes prior-year rows, and emits fixed introduce score. Evidence:source-refs/sanmopia-admin/application/models/Win_the_race_model.php:228-252,source-refs/sanmopia-admin/application/models/Win_the_race_model.php:610-654. Target:caregiver_management / CaregiverReferralConversionMatchandcare_delivery / ReferralIncentiveEligibility. Backend must own matching evidence, service-day threshold, prior-period exclusion, score policy, and branch attribution without report SQL side effects. Status:Backend foundation implementedin backend commit86291ca. The migrated slice addsCaregiverReferralConversionMatchCandidate,CaregiverReferralConversionMatch, andCaregiverReferralConversionMatchPolicyincaregiver_management; andReferralIncentivePolicyPeriod,ReferralIncentivePriorPeriodEvidence,ReferralIncentiveEligibilityRequest, andReferralIncentiveEligibilityDecisionincare_delivery. Backend now separates conversion evidence from incentive eligibility, prohibits legacy raw name+phone matching, blocks self-referral, freezes service-day threshold, conversion window, prior-period exclusion, score points, policy version, and referred caregiver branch attribution. Public contracts reject legacy report authority fields such asMANAGER_RECOMMEND_ID_PK,RECOMMEND_INDEX,MANAGER_ID,NAME,PHONE,SERVICE_DAY, andINTRODUCE_GRADE. Runtime follow-up: persist conversion matches and incentive decisions in Supabase, source service-day units from care-delivery completion facts, map score awards into caregiver performance/settlement projections, invalidate WinTheRace-style read models from events, and replace raw SQL report authority with typed projections. -
SFC-20260707-CUR-059Admin caregiver payout statement projection persistence and read contract. Legacy admin/manager salary detail renders payout rows and then lets browser/PHP recompute editable salary, tax, service-balance, deposit, and completion state. Evidence:source-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:4-115,source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:155-231,source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:234-260,source-refs/sanmopia-admin/static/js/manager/manager_pay_inquiry.js:183-231,source-refs/sanmopia-admin/application/controllers/Manager.php:1057-1130,source-refs/sanmopia-admin/application/controllers/Manager.php:1133-1236,source-refs/sanmopia-admin/application/models/Reservation_model.php:2453-2625,source-refs/sanmopia-admin/application/models/Reservation_model.php:2627-3041, andsource-refs/sanmopia-admin/application/models/Reservation_model.php:3095-3147. Target:adapters/pricing_settlement/features/caregiver_compensation / SupabaseAdminCaregiverPayoutStatementProjectionStore,pricing_settlement / CaregiverServiceBalanceReceiptActionProjection, andreservation_operations / ReservationSettlementCompletionGateProjection. Backend commit292f736adds Supabase projection/row tables, participant RLS, realtime publication, deterministic projection and row ids, latest-revision reader, row upsert store, and JSONB display/action roundtrip for multiple caregiver slots on one contract. It also moves reusable optional integer/datetime and text-array coercion intoSupabaseRowand patches reservation-history export RLS to require an explicit signed-in guard. Backend commit33db343adds authenticatedGET /admin-caregiver-payout-statement-projections/{reservationBookingId}with Supabase Auth, SpiceDBrecord_caregiver_payoutauthorization, 404 for missing projections, and camelCase response aliases. Contract commit1082f66publishesAdminCaregiverPayoutStatementProjectionResponse,adminCaregiverPayoutStatementProjectionPath, display-line/service-balance vocabularies, response validation, and generateddistoutput. Backend commite973097addsRequestAdminCaregiverPayoutStatementProjectionRefreshCommand,SupabaseAdminCaregiverPayoutStatementProjectionRefreshRequester, Supabase PGMQ queuesanmopia_admin_payout_projection_refresh, and API hooks so branch payout deposit, caregiver receipt-state, payout adjustment, and payout destination-change mutations queue projection refresh work only after freshrecordedresults. Backend commit6e3bdfcaddsRefreshAdminCaregiverPayoutStatementProjectionHandler,SupabaseAdminCaregiverPayoutStatementProjectionSourceReader, andSupabaseAdminCaregiverPayoutStatementProjectionRefreshProcessor. The worker now consumes the refresh queue, reloads quote lines, payout instructions, receipt states, branch/caregiver acknowledgements, latest payout adjustment audits, latest payout destination-change audits, service-balance caregiver receipt states, computes the next projection revision, rebuilds the admin projection, and saves it through the existing Supabase projection store. 2026-07-08 backend follow-up: projection refresh now joins caregiver receipt states to service-balance closeout events, persistsservice_balance_closeout_event_id,finalized_charge_snapshot_id,service_occurrence_ledger_key, andservice_occurrence_ledger_revision_numberon each admin payout row, and exposes those frozen refs through Pydantic/FastAPI and the public TS contract so portals cannot infer payout readiness from mutable service-balance state alone. 2026-07-09 source-mining follow-up: legacy manager payout UI mapsSERVICE_BALANCE_FLplusBALANCE_APPROVE_FLinto select valuesrequire/check/complete; browser posts those strings to/manager, and PHP updatesPAYMENT_STATUS_ID_FK,BALANCE_PRICE_PAYMENT_FL,SUB_PAYMENT_STATUS_ID_FK, andSUB_BALANCE_PRICE_PAYMENT_FLbefore advancing reservation status between settlement and complete. Backend projection must own service-balance receipt action availability, disabled reason, caregiver slot identity, expected payout/closeout revisions, and lifecycle transition facts; no UI may infer receipt state or reservation completion from mutable payment flags. Verification: colocated adapter tests,SupabaseRowtests, focused access-control migration tests, rollback SQL syntax checks in the stage DB container, focused API/HTTP/main tests, contractpnpm check,ruff, Tach dependency/interface/external gates, Vulture confidence-100 scan, focused refresh tests, stage DB PGMQ queue creation proof, focused rebuild-worker tests, main import smoke, Vulture confidence-100 scan, and focused closeout-ref projection tests. Runtime follow-up: frontend removal of UI-side payout completion logic, assignment-variant payout slot invalidation proof for primary/replacement/clear/handoff changes,SettlementCompletionGateE2E proof, branch/HQ settlement projections consuming the same frozen closeout refs, and reservation payout refresh proof through the worker. -
SFC-20260708-CUR-060Customer service-balance instruction availability. Legacy customer/pre-reservation detail decides whether to show the direct service-balance action from local PHP time, rawPAYMENT_INFO["서비스 잔금"]status, and source status exclusions, then browser click opens an account-info popup instead of a backend payment/instruction projection. Evidence:source-refs/sanmopia_web/application/views/about/terms.php:159-164states that service balance is paid directly to the caregiver and that neither company nor caregiver receipt issuance is available;source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:77-105,source-refs/sanmopia_web/application/views/mypage/pre_reservation_detail.php:45-71,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:439-443, andsource-refs/sanmopia_web/static/js/mypage/reservation.js:713-737. Target:pricing_settlement / CustomerDirectServiceBalanceInstructionProjectionandreservation_operations / CustomerActionAvailabilityPolicy; the customer-facing instruction copy and receipt-limitation notice must be backend projection fields, not hardcoded page text. Status:Backend API/contract read binding implemented; addedCustomerDirectServiceBalanceInstructionunderpricing_settlementwith a versioned direct-instruction policy, customer-action snapshot binding, service-balance payment instruction id, statement revision key, payment-status/lifecycle/payment-component gates, instruction availability window, caregiver-account disclosure grant flow, and strict Pydantic payloads that reject legacyPAYMENT_INFO,서비스 잔금, PHP time/status fields, and inline account-popup payload keys. Backend follow-up now addsSupabaseCustomerDirectServiceBalanceInstructionProjectionStoreplussanmopia_customer_direct_service_balance_instruction_projectionswith projection-key upsert, customer/reservation query reads, RLS participant read policy, explicit Supabase Data API grants, realtime publication, and row constraints that keep unavailable instructions from exposing action target or account-disclosure fields. 2026-07-08 follow-up: backend now exposes an authenticated customer self-read API/HTTP route,GET /customer-direct-service-balance-instruction-projections/{reservationBookingId}, where the Supabase actor id becomes thecustomerActorKey; contract OpenAPI, JSON Schema, and TypeScript client helpers now publish the projection so UI can read backend-owned availability instead of checking PHP time/status or rawPAYMENT_INFOfields. Verification: focused domain/application/adapter/API/HTTP tests, contractpnpm check,ruff, and Tach dependency/interface/external gates. 2026-07-09 runtime follow-up: the browser-created reservatione4314928-0f7e-4a4e-ac29-7190b1ea6f26closed service balance throughPOST /reservation-service-balance-closeouts, and the closeout projection producer refreshedsanmopia_customer_service_balance_instruction_projectionstoavailability = availablewith frozen charge snapshot id, service occurrence ledger key/revision, statement revision key, andrawAccountFieldsVisible=falseon the customer readiness API. Remaining work: create payout instructions from care-team assignment/compensation source as part of the normal operator flow, remove frontend-side popup availability calculation, and prove the customer account-disclosure flow end to end. -
SFC-20260708-CUR-061Customer-visible caregiver account disclosure for direct service-balance payment. Legacy loads main and assistant caregiver bank accounts fromMANAGER_ACCOUNT_TB, emits raw account numbers into page JavaScript, and the popup concatenates current roster accounts without a grant, expiry, masking profile, payout-slot identity, or statement revision. Evidence:source-refs/sanmopia_web/application/models/Manager_model.php:133-147,source-refs/sanmopia_web/application/models/Reservation_model.php:1519-1529,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:545-568, andsource-refs/sanmopia_web/static/js/mypage/reservation.js:695-710. Target:pricing_settlement / ServiceBalancePaymentInstructionandoperator_access / CaregiverPaymentAccountDisclosureGrant. Status:Backend API/contract read binding implemented; added theCaregiverPaymentAccountDisclosureGrantpolicy/contract slice underoperator_access, requiring a direct service-balance payment instruction, service-balance statement revision, care-team roster revision, short-lived grant, source evidence, and account snapshot references. Backend follow-up now addsSupabaseCaregiverPaymentAccountDisclosureGrantStore,sanmopia_caregiver_payment_account_disclosure_grants, explicit Supabase Data API grants, RLS participant read policy, and authenticated customer routeGET /customer-service-balance-caregiver-account-disclosure-grants/{reservationBookingId}. The route joins the backend-ownedCustomerDirectServiceBalanceInstructionProjectionwith the matching grant, evaluatesCaregiverPaymentAccountDisclosurePolicy, and returns account snapshot references only when the current customer, instruction id, statement revision, roster revision, expiry, and capability all match. Contract OpenAPI, JSON Schema, and TypeScript client helpers publish the grant response. Legacy rawpaymentAccountInfo,subPaymentAccountInfo,BANK_NM,ACCOUNT, and account-number payload keys remain rejected before validation so customer pages cannot rebuild the old inline JavaScript account-popup contract. 2026-07-09 follow-up: backend and contract now addGET /customer-service-balance-caregiver-account-disclosure-readiness/{reservationBookingId}withinstruction_missing,instruction_unavailable,grant_missing,not_required, andreadystates, backendblockingFacts, andrawAccountFieldsVisible=false; the customer UI may call the protected grant endpoint only after readiness isready, so missing post-payment projections render as backend-owned blocked continuation instead of frontend-inferred logic. 2026-07-09 backend follow-up: service-balance closeout now triggers direct-instruction projection refresh, and the projection producer can call the source-backed disclosure-grant producer. The Supabase grant source reader loadssanmopia_caregiver_payout_instructions, validates raw account fields, emits short-lived account snapshot references only, and never exposes account numbers in readiness. Runtime proof on bookinge4314928-0f7e-4a4e-ac29-7190b1ea6f26returned readinessgrant_missingwith blockercaregiver_payment_account_disclosure_grant_missing, proving the customer path fails closed when payout instructions are absent. 2026-07-09 smoke-loop follow-up:dev_smoke_appnow produces an in-memory direct service-balance instruction projection immediately after settlement completion, and the colocated smoke test proves the reservation flow advances frominstruction_missingto the safergrant_missingreadiness blocker while preserving the frozen mother-visible charge summary after settlement. Playwright proof on booking2dad8350-e100-4a81-8424-1bdc06b0a465exercised desktop reservation submit, payment completion, settlement completion, frozen payable invariant, and readinessgrant_missingwith no console or network response errors. 2026-07-09 account-disclosure proof:dev_smoke_appnow wires the same projection producer to an in-memoryCaregiverPaymentAccountDisclosureGrantsource/store. Playwright proof on booking966c182e-1da7-40a6-b12d-43ec40f52b15exercised reservation submit, payment completion, settlement completion, frozen payable invariant, readinessready, grant responsecaregiver_payment_account_disclosure_allowed, and zero console/network response errors. The smoke grant exposes account snapshot refs only; raw account fields remain hidden. 2026-07-09 stage-smoke hardening: backendpnpm run supabase:smoke:stage:reservation-to-settlement-completionnow also asserts the post-settlement customer account-disclosure readiness projection is resolved, not staleinstruction_missing. Latest bookingcd5941c4-5ddb-44dc-89c0-03e2433f2e7ccompleted reservation, payment continuation, settlement, service-balance closeout event7ef3e74d-9b6b-4036-bfd4-c38411428e2e, and returned readinessnot_requiredwith emptyblockingFactsfor zero service-balance due. UI must render backend-owned readiness and must not invent a local account-popup state. Same-day browser proof:frontend-repo/output/playwright/reservation-card-flow-submit-smoke-settlement-20260709-final/submitted desktop bookingb232505e-8dc8-4bed-945f-116739fbc2c2from requestRBQ-f85bb9bf-5cb3-4f19-9737-4ba0d5b7ebe1, recorded zero failed requests, zero bad HTTP responses, and zero console errors, then the backend settlement driver completed the same booking tosettledwith mother-visible payable KRW 1,681,519, caregiver payout KRW 500,000, branch settlement KRW 1,181,519, HQ settlement KRW 181,519, and readinessinstruction_unavailable. 2026-07-09 correction:backend-repo/scripts/stage_reservation_settlement_e2e.pyno longer builds manual branch/HQ ledger lines or defaults caregiver payout to KRW 500,000. Direct stage driver proof booking27f69a4c-7600-4de1-b611-839d8e757b94derived caregiver payout50000from the frozen charge snapshot, produced branch settlement100000and HQ settlement50000from backend command producers, reachedsettledwithledgerLineCount=3, produced the post-settlement account-disclosure projection, and returned readinessnot_requiredwith emptyblockingFacts. 2026-07-09 source-mining follow-up: the normal legacy operator path first mutates primary and assistant assignment rows, then salary/tax rows, and only later customer pages disclose currently assigned caregiver accounts from raw roster/account joins. Evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:2166-2221,source-refs/sanmopia-admin/application/models/Reservation_model.php:2224-2303,source-refs/sanmopia-admin/application/controllers/Manager.php:1133-1183,source-refs/sanmopia-admin/application/controllers/Manager.php:1225-1235,source-refs/sanmopia-admin/application/models/Reservation_model.php:2699-2733,source-refs/sanmopia-admin/application/models/Reservation_model.php:2754-2788,source-refs/sanmopia_web/application/models/Reservation_model.php:1519-1529,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:545-568, andsource-refs/sanmopia_web/static/js/mypage/reservation.js:695-710. Target follow-up:caregiver_assignment / CareTeamAssignmentConfirmed,pricing_settlement / CaregiverCompensationQuoteFinalized,pricing_settlement / CaregiverPayoutInstructionReadinessProjection, andoperator_access / CaregiverPaymentAccountDisclosureGrant. Suggested backend feature:IssueCaregiverPayoutInstructionsAfterAssignmentCompensation. 2026-07-09 backend hardening:SupabaseCaregiverPaymentAccountDisclosureGrantSourceReadernow readsassigned_caregiver_user_idfrom payout instructions, matches closeout caregiver recipients by assigned-user id before legacy caregiver id or assignment key, and emits the assigned-user id as the customer disclosure recipient reference when available. Frontend must render backend projections only; no customer/admin UI may derive disclosure readiness or account visibility from mutable roster, salary, or account rows. Remaining proof: wire this normal-flow command before service-balance disclosure can becomeready, plus frontend popup removal and customer E2E flow. 2026-07-09 backend proof: stage reservation-to-settlement smoke now issues aCaregiverPayoutInstructionthroughIssueReservationCaregiverPayoutInstructionsHandlerandSupabaseReservationCaregiverPayoutInstructionStore, records branch payout deposit acknowledgement through the authenticated backend API, resumes waiting settlement continuation toworkflow_started, and then completes settlement with lifecycle lines sourced from the frozen payout instruction instead of a UI-hardcoded caregiver amount. Latest run booking627ef71f-6e39-4cf4-90d2-a0191b870499created payout instructioncd899555-7d88-5eaf-9172-b0888a0eeda0, recorded branch deposit acknowledgement, completed settlement, and returned customer account disclosure readinessinstruction_unavailable. Remaining implementation is the real normal-flow producer from care-team assignment/compensation facts, not the smoke-only stage fixture. 2026-07-09 normal-flow payout preparation follow-up: backend now addsIssueCaregiverPayoutAfterCareTeamAssignmentHandlerunderpricing_settlement / settlement_continuation. The coordinator readsCareTeamCompensationSourcefacts, quotes caregiver compensation from backend policy inputs, freezesCaregiverPayoutInstructionrows, maps those frozen instructions to caregiver-payout ledger lines, and advances the reservation financial lifecycle tocaregiver_payout_ready. Tach keeps this cross-feature orchestration out of the caregiver-compensation slice. Follow-up backend smoke hardening removed the stage-only assignment row upsert: stage now saves a real caregiver candidate snapshot, callsPOST /care-team-assignment-decisions/assign-from-candidate-snapshot, reads compensation source facts through the assignment-decision fallback reader, and then drives payout preparation through the coordinator instead of building a quote or caregiver-payout ledger line inside the smoke script. Latest compensation-source smoke booking16423898-1c35-4249-b157-d8e9bd61c439proved the shared candidate snapshot helper with assignment decisionstage-assignment-20260709120741107321. Latest reservation-to-settlement smoke booking85f4383c-e8a8-41bd-92e7-9ffdd943aa59created payout instructionc18e544c-025e-5fd0-abf0-eea7710b3e56, recorded branch payout deposit acknowledgement, reached settlement continuation wait reasonbranch settlement ledger lines are not ready, completed settlement, and returned account-disclosure readinessinstruction_unavailable. Remaining work: add a backend-owned payout-destination/account revision source reader, remove the stage-only destination fixture, and then prove account disclosure reachesreadyfrom the same normal operator flow. 2026-07-09 payout-destination source follow-up: backend now resolves payout destinations throughSupabaseCaregiverPayoutDestinationSource, reading the latest committedsanmopia_caregiver_bank_account_revisionsrow for each quote-line caregiver profile id and freezing the resultingcaregiver_bank_account_revision_keyinto the payout instruction. Stage setup now seeds the account revision throughSupabaseCaregiverBankAccountRevisionStoreinstead of passing literal bank details into the settlement-continuation command. Latest stage smoke bookingd33201b3-d98c-494c-b674-91775a79dd8acreated payout instruction8f65329d-8cf9-551a-b787-a24b4477c677, recorded branch payout deposit acknowledgement, completed the smoke settlement driver, returned branch settlement dashboard rows26and line items1, and still exposed the next blocker honestly as settlement continuationwaiting_for_financial_factswith reasonbranch settlement ledger lines are not ready. 2026-07-09 branch-settlement source follow-up: backend now addsIssueBranchSettlementAfterCaregiverPayoutHandlerin the financial-lifecycle application slice. The command reads the frozen financial lifecycle, finalized charge snapshot, caregiver payout ledger, and closeout references, derives a canonicalinter_office_branch_sharebranch-settlement ledger line, and advances the lifecycle throughPrepareReservationBranchSettlementCommand. The stage payment-continuation smoke no longer builds the branch settlement line or amount in the script. 2026-07-09 HQ-settlement source follow-up now addsIssueHqSettlementAfterBranchSettlementHandler, which reads the same frozen financial lifecycle and finalized charge snapshot, derives the canonicalheadquarters_platform_feeline from source-owned settlement deduction facts, and advances HQ settlement through the financial lifecycle command. The stage smoke no longer builds the HQ settlement line or amount in the script. Latest full reservation-to-settlement smoke booking521a5051-9825-44e9-bb5a-fd7d84d3981ecreated payout instruction13d0fb3d-5a9e-5e68-b833-b8f911316dd2, froze customer payable150000, settlement deduction50000, caregiver payout50000, branch settlement100000, HQ settlement50000, lifecyclesettled, branch dashboard rows32, board line items1, and passedpnpm run supabase:smoke:stage:reservation-to-settlement-completion. Same-day follow-up now treats zero service-balance due as account-disclosure readinessnot_required, notinstruction_unavailable, and direct driver booking27f69a4c-7600-4de1-b611-839d8e757b94proves the browser backend driver uses backend command producers instead of manual branch/HQ ledger payloads. Positive service-balance follow-up bookingd137de9d-ebbc-4e90-8b7a-dd3e9d39836cran the same driver with--service-balance-amount-krw 25000, produced instruction availabilityavailable,serviceBalancePaymentInstructionId, disclosure readinessready, emptyblockingFacts,rawAccountFieldsVisible=false, caregiver payout50000, branch settlement100000, HQ settlement50000, lifecyclesettled, andledgerLineCount=3. Browser-created positive-balance proof then exposed a valid zero-HQ-settlement case: booking89696822-5ff7-470d-a7fc-8b6bca848ef4came from the Astro reservation-card flow, reached payment workflowcompleted, ran the backend continuation with--service-balance-amount-krw 25000, issued caregiver payout1581519, branch settlement100000, an audited zero-amountheadquarters_service_marginHQ line, lifecyclesettled,ledgerLineCount=3, instruction availabilityavailable, disclosure readinessready, emptyblockingFacts, andrawAccountFieldsVisible=false. Stage booking smoke now buildsacceptedPriceCatalogQuotethroughstage_private_care_price_catalog_quote_payload(), which uses the domainPriceCatalogQuotePolicyover a published stage catalog entry instead of inline booking-script arithmetic. Fresh proof booking8ac3639b-f5ba-4f8d-8e48-d6239d183fd6passed booking, positive service-balance settlement, instruction availabilityavailable, disclosure readinessready, and lifecyclesettled. Follow-up bookinga97c8dfe-566f-4295-a266-3c1fa7ab0553moved that stage catalog from helper memory into Supabase persistence:stage_care_price_catalog/stage-2026.07/stage-private-one-weekis seeded throughsanmopia_price_catalog_import_batchesandsanmopia_price_catalog_entries, DB proof shows batchimport_status=published, entry service-day count5, and entrypublished_atpresent, and the same booking passed positive service-balance settlement with caregiver payout50000, branch settlement100000, HQ settlement50000, disclosure readinessready, and lifecyclesettled. Wrapper proof6f95ad57-d702-40fb-bfdb-6637a801c42ealso passedsupabase:smoke:stage:reservation-to-settlement-completion. Follow-up 2026-07-12 runtime recheck passedpnpm supabase:smoke:stage:reservation-to-settlement-completionon bookingc4540bf8-7432-456e-93a2-f5a5d843e110: stage booking, delegated family payment pre-registration, payment continuation, service delivery, caregiver payout, branch/HQ settlement completion, branch dashboard rows63, board line items1, zero service-balance readinessnot_required, and registered-batch cleanup with SpiceDB cleanup verification. Same-day positive-balance proofpnpm supabase:smoke:stage:reservation-to-settlement-positive-balanceon booking3aedc22f-72e2-4e6b-8fc8-c33e2458a016passed service-balance amount25000, instruction availabilityavailable, disclosure readinessready,rawAccountFieldsVisible=false, caregiver payout50000, branch settlement100000, HQ settlement50000, lifecyclesettled,ledgerLineCount=3, and registered-batch cleanup. Backend wrapper now reaps positive-balance stage data with the same test-data batch cleanup path as the standard flow. Follow-up Supabase migration proof applied20260709145000_payment_product_plan_price_catalog_references.sql, creating payment product catalog v5 with six rows and two explicit price-catalog references:reservation.customer_share.depositmaps tocustomer_share_deposit, andreservation.customer_share.balancemaps tocustomer_share_balance; both point atcare_price_catalog/accepted_reservation_quote/customer_share. Remaining work: import every legacy workbook/payment-product variant as versioned Supabase catalog rows and bind those rows to production quote/read-model APIs. -
SFC-20260709-CUR-102Caregiver bank-account revision handoff to payout instructions and disclosure grants. Legacy caregiver and admin profile paths mutateMANAGER_ACCOUNT_TBdirectly from profile/account forms before any reservation-scoped payout instruction exists, while payout and service-balance disclosure screens later read the current account row. Evidence:source-refs/sanmopia-manager/static/js/other/pay_info.js:1-88,source-refs/sanmopia-manager/application/controllers/User.php:176-239,source-refs/sanmopia-manager/application/models/User_model.php:114-150,source-refs/sanmopia-admin/application/controllers/Manager.php:163-190,source-refs/sanmopia-admin/application/controllers/Manager.php:296-308,source-refs/sanmopia-admin/application/models/Manager_model.php:1344-1359,source-refs/sanmopia-admin/application/models/Manager_model.php:1470-1476,source-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:212-243, andsource-refs/sanmopia-admin/application/models/Reservation_model.php:3216-3233. Current backend gap:pricing_settlement / CaregiverPayoutDestinationChangeAuditrecords reservation-scoped payout-destination corrections only after acaregiver_payout_instruction_idexists, whileoperator_access / CaregiverPaymentAccountDisclosureGrantsupportsrevoked_atbut has no profile-account revision consumer or grant-revocation command.SupabaseCaregiverPaymentAccountDisclosureGrantSourceReadercan issue disclosure grants only from existingsanmopia_caregiver_payout_instructionsrows, so a profile account change before assignment/compensation finalization or after grant issue can be missed by the normal flow. Target:caregiver_management / CaregiverBankAccountRevision,pricing_settlement / CaregiverPayoutDestinationSnapshotSource,pricing_settlement / IssueCaregiverPayoutInstructionsAfterAccountRevision, andoperator_access / CaregiverPaymentAccountDisclosureGrantRevocation. Status:Partial. 2026-07-09 backend foundation addedcaregiver_management / CaregiverBankAccountRevisionwith expected revision, idempotency, changed-field proof, account evidence references, and a command handler that hands off tooperator_access / CaregiverPaymentAccountDisclosureGrantRevocation. Customer disclosure readiness now ignores revoked or expired grants, and the Supabase grant adapter can find active grants by caregiver recipient reference before revoking stale account snapshots. 2026-07-09 follow-up: Supabase now persistssanmopia_caregiver_bank_account_revisionsthrough a dedicatedcaregiver_managementadapter with idempotent upsert, latest committed revision lookup, service-role-only RLS, and a private raw-account table that is not published to realtime. Payout instructions now carrycaregiver_bank_account_revision_key, and the admin payout projection source can surface unversioned existing rows without rewriting historical payouts. 2026-07-09 follow-up: payout issuance can now omit inline destination rows and load the latest committed account revision through a backend-owned Supabase payout-destination source. Focused tests prove latest-revision selection, missing-revision fail-closed behavior, and source-driven payout issuance. Remaining backend work: add branch/HQ SpiceDB scope to account revision commands, reissue affected grants after payout instruction refresh, invalidate admin payout projections, and promote the stage proof frominstruction_unavailabletoready. Profile writes must not mutate payout instruction rows in place or expose raw account fields to customer/operator projections. -
SFC-20260709-CUR-103Reservation-to-settlement branch/HQ approval, finance-close, payout projection, and audit proof. Legacy settlement closeout still mixes browser actor labels, posted totals, board ids, memo fields, manual etc rows, and mutable status flips: source JS postsfdata-type, selected board/detail ids,ftotal-price,ffee-price,fresult-price, and actor login type;Calculate::insertPaymentCentralToBranchaccepts those values, updates board/detail/coupon/manual rows, and recordsinsertLog(...); the payment model later flipsSTATUS_FLfor data-room completion. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:20-75,source-refs/sanmopia-admin/static/js/calculate_detail.js:250-310,source-refs/sanmopia-admin/static/js/calculate_detail.js:415-439,source-refs/sanmopia-admin/application/controllers/Calculate.php:150-245,source-refs/sanmopia-admin/application/controllers/Calculate.php:279-310,source-refs/sanmopia-admin/application/models/Payment_model.php:2525-2562,source-refs/sanmopia-admin/application/models/Payment_model.php:2861-2915, andsource-refs/sanmopia-admin/application/models/Payment_model.php:4265-4308. Target:reservation_operations / ReservationStageCapabilityPolicy,operator_access / SettlementApprovalAuthorizationEvidence,pricing_settlement / SettlementStatementApprovalCommand,pricing_settlement / SettlementCompletionProjectionInvalidation, andsecurity_audit / SettlementTransitionAudit. Required gate: source branch-manager labels map to Branch operator or explicit settlement branch actor compatibility, headquarters admin maps to HQ admin, all approval/repair/ closeout entrypoints derive actor from Supabase Auth and SpiceDB (review_hq_settlement,close_reservation_finance, and narrower branch/HQ settlement permissions), commands carry expected statement/ledger/closeout revisions plus idempotency, caregiver/admin payout projections refresh from frozen service-balance closeout refs, and historical board mutations import into append-only audit/provenance before settlement status projections change. 2026-07-09 backend follow-up addspricing_settlement / ReservationFinanceTransitionAuditand Supabase tablesanmopia_reservation_finance_transition_audits. Runtime proof: browser-started reservation2a291997-153b-497d-aa2a-5f1e66b8168ereachedsettled; the audit row froze HQ actor8ce74a90-125e-4696-9f55-58fcd06801b5,actor_role_code=headquarters_administrator,required_permission=close_reservation_finance, transitionhq_settlement_ready -> settled, and backend-derived metadatamotherVisiblePayableKrw=1681519,caregiverPayoutKrw=500000,branchSettlementKrw=1181519,hqSettlementKrw=181519,ledgerLineCount=3. 2026-07-09 backend follow-up adds admin caregiver payout projection refresh provenance: queue worker commands now require refresh idempotency key, trigger kind, source idempotency key, actor profile, reason, and requested timestamp; rebuilt admin payout projections persist those fields onsanmopia_admin_caregiver_payout_statement_projectionsand expose them in the Pydantic API payload as read-onlyrefreshProvenance. Stage proof after this migration created booking52b16699-260c-4180-972f-03ddd51a62b3, continued payment workflowRPW-STAGE-CONT-20260709091205, closed service balance eventbf871eb1-7b4e-41a5-a59a-84c9a71389a3, reached settlement completion, and returned branch-settlement dashboard/board rows. Remaining work: settlement statement approval UI binding still needs full operator smoke coverage, and source board mutation imports still need provenance backfill. -
SFC-20260709-CUR-104Settlement data-room integrated document bundle selection and artifact grant. Legacy data-room “integrated document” download is not a neutral ZIP export. Browser code posts raw reservation ids plus hidden service-type values, forces single selection only for integrated download, and submits through a hidden iframe. PHP then chooses the whole document set from the first selected reservation’s source service type, mixes spreadsheet-generated documents with static PDF template copies, writes temporary files under the Excel temp folder, adds them to a ZIP, deletes the temp files, and downloads immediately. Evidence:source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:62-86,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:219-246,source-refs/sanmopia-admin/application/controllers/DataRoom.php:312-376,source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:66-89,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-3934,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3936-4113, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4121-4198. Target:document_reporting / IntegratedReservationDocumentBundleRequest,document_reporting / DocumentBundleEligibilityPolicy,document_reporting / DocumentBundleArtifactBuild,operator_access / DocumentBundleDownloadGrant, andmigration_governance / DocumentBundleBuildLedger. Status:Mapped; existing document-center and data-room rows cover stored artifacts and broad bundle grants, but no numbered slice owns source-compatible integrated bundle membership, service-type eligibility, single-reservation selection rule, static-PDF template membership, temporary artifact lifecycle, ZIP checksum, signed download grant, or build audit. Backend must issue a bundle-selection token over reservation id, service type, document catalog revision, selected template ids, render-source revisions, actor grant, and expiry before artifact build. UI/admin must not select bundle members from hidden inputs, iframe posts, numeric document ids, or mutable source service labels.
2026-07-09 persistent legacy-gap mining refresh
Section titled “2026-07-09 persistent legacy-gap mining refresh”This pass did not create new feature ids because the affected areas already have named owners below. The added value is status/proof tightening plus precise source evidence that must stay as backend migration evidence, not UI authority.
| Area | Existing owner row(s) | Implementation/proof status after mining | Additional source evidence |
|---|---|---|---|
| Family/proxy booking, payer, notification, and document authority | High-level family authority rows P0 / Family, proxy payer, contact, refund, and document authority, ReservationPartyAuthoritySnapshot, and DocumentRecipientAuthority | Partial. Contract/domain naming exists, but booking, payment, refund, receipt, document, and notification commands still need one persisted ReservationPartyAuthoritySnapshot and grant projection. Mother-facing or operator UI must not infer authority from relation text, phone, reservation owner id, branch phone special cases, or copied mutable reservation/user rows. | source-refs/sanmopia_web/application/views/service/step1.php:90-213 (mother/contact/relation inputs), source-refs/sanmopia_web/application/controllers/api/Service.php:67-83 (relation/contact copied into user profile), source-refs/sanmopia_web/application/controllers/api/Payment.php:89-113 (owner/payment-state gate plus PRICE_TABLE amount), source-refs/sanmopia_web/application/models/Payment_model.php:101-225 (downpayment rows from live reservation price table), source-refs/sanmopia_web/application/models/Payment_model.php:570-704 (mother/branch notification routing), source-refs/sanmopia_web/application/controllers/MyReservation.php:366-370 and source-refs/sanmopia_web/application/controllers/Notification.php:21-25 (document token issuance to the logged-in user). |
| Document/archive download, scheduled delivery, and bundle grants | SFC-20260708-CUR-097, document rows P1 / StoredPrintableDocumentArtifact, PrintableDocumentAccessGrant, DocumentCenterProjection, and ReservationDocumentDelivery | Partial. Document-center projection/API is represented, but signed-storage handoff, customer token replacement, scheduled-mail delivery attempts, ZIP/bundle policy, and live-render guard remain proof gaps. UI must render backend handoff descriptors only; it must not compose numeric document ids, token query strings, bundle members, or render request codes. | source-refs/sanmopia_web/application/models/User_model.php:461-489 (two-hour documentDownload token delete/recreate/read), source-refs/sanmopia-admin/application/controllers/cli/ReservationDocument.php:104-129, :203-225, and :337-363 (scheduled PDF attachment generation, mail send, temp-file delete, send-status insert), source-refs/sanmopia-admin/application/controllers/DataRoom.php:311-376 (service-type document bundle composition and direct export call). |
| Caregiver matching candidate selection and assignment proof | SFC-20260708-CUR-089, CaregiverCandidateOrderingPolicy, CaregiverCandidateSelectionToken, and payout invalidation rows | Partial. Candidate snapshots/order policy exist, and browser authority field rejection is noted, but branch/HQ assignment E2E still needs backend-issued selection tokens, score/distance/transit evidence revisions, expected roster revision, override reason, conflict acknowledgement, and payout/document invalidation proof. | source-refs/sanmopia-admin/application/models/Matching_model.php:62-176 (score views, schedule SQL, pet exclusion, random tie, distance calculation/sort), source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:36-65 (raw candidate id, posted fmanager-score, 0점 short-circuit, distance/transit load), source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:180-208 (raw assignment history read). |
| Provider browser handoff and provider-success/local-write-failure compensation | PaymentProviderHandoffSession, PaymentProviderApprovalRequest, PaymentProviderCloseoutCompensationSaga, CustomerPaymentInstruction, PaymentProviderAttempt, CompensationRefundIntent, ProviderRefundExecutionAttempt, PaymentCloseoutRepairCase, ProviderRefundResultEvent, and PaymentCloseoutReportingInvalidation | Backend foundation / Handoff + attempt + compensation intent + repair planning + execution/result-recording persistence partial. Provider amount and frozen pre-registration guards existed; 2026-07-09 backend follow-ups add PaymentProviderHandoffSession, handoff Pydantic payloads, PaymentProviderHandoffSessionStore, SupabasePaymentProviderHandoffSessionStore, and service-role-only table sanmopia_payment_provider_handoff_sessions with RLS enabled. The session freezes amount, allowed method set, selected method, provider route, backend-owned relative return path, expected payment revision, expiry, idempotency key, source evidence, and handoff fingerprint, and rejects browser-controlled provider payload. The same follow-up adds PaymentProviderAttempt, PaymentProviderAttemptStore, provider-attempt Pydantic payload, SupabasePaymentProviderAttemptStore, and service-role-only table sanmopia_payment_provider_attempts. The attempt record captures handoff session/fingerprint, reservation/payment refs, purpose, amount, method, provider route/operation/request/transaction, provider result state, closeout write state, timestamps, failure reason, compensation intent, source evidence, requires_compensation_refund, and attempt fingerprint. Domain and DB reject browser-reported amount authority; stage DB migrations verified RLS true, anon/authenticated revoked, service_role select/insert/update only, and compensation flag must match provider-accepted failed closeout. 2026-07-09 compensation follow-up adds PaymentProviderCloseoutCompensationPolicy, PaymentProviderCloseoutCompensationHandler, Pydantic intent payload, SupabasePaymentProviderCloseoutCompensationIntentStore, and service-role-only sanmopia_payment_provider_closeout_compensation_intents; a rollback stage insert proved canonical KillBill refund-intent rows satisfy constraints without leaving test data. 2026-07-09 runtime follow-up reads the latest PaymentProviderHandoffSession during KillBill paid-webhook ingestion, persists PaymentProviderAttempt with workflow_start_failed when local workflow start fails after provider success, and creates PaymentProviderCloseoutCompensationIntent through the runtime app wiring. Current repair follow-up exposes token-gated /internal/payment-refund-repairs/provider-refund-plans, persists the repair plan through PaymentRefundRepairHandler plus SupabasePaymentRefundRepairPlanStore, exposes token-gated /internal/payment-refund-repairs/provider-refund-executions, calls PaymentGatewayClient.refund, persists execution attempts through SupabasePaymentRefundRepairExecutionAttemptStore, and records accepted/rejected repair execution results through ProviderRefundResultFromLedgerHandler. Remaining gaps: runtime KillBill approval request binding, retry/result-history hardening, operator repair/read projection, and revenue/settlement read-model invalidation proof after compensated or repaired closeout. Legacy Kcppayment::refund() can issue a KCP STSC cancel and still return a local failure payload, so modern repair must model provider-refund execution attempt, provider-result certainty, local closeout outcome, idempotency, and reporting invalidation as separate facts. UI/PHP must not decide payment amount, allowed method, return route, provider handoff params, compensation success, or repair state. | source-refs/sanmopia_web/application/views/item/kcp/order_info_form.php:35-75 (visible KCP order fields including amount, method, return URL, user/order refs), source-refs/sanmopia_web/application/views/item/kcp/pay_form.php:4-24 (provider response handoff fields), source-refs/sanmopia_web/static/js/lib/kcp/approval_key.js:55-65 (approval-key query built from browser form), source-refs/sanmopia_web/static/js/reservation_payment.js:120-183, source-refs/sanmopia_web/static/js/pre_reservation_payment.js:41-117, and source-refs/sanmopia_web/static/js/mypage/reservation_changePayment.js:43-89 (browser amount/method/return-route handoff), source-refs/sanmopia_web/application/controllers/api/Payment.php:13-58 (approval route reads good_mny and Ret_URL from browser query despite server-session warning), source-refs/sanmopia_web/application/controllers/api/Payment.php:160-180, :215-218, :272-303, :388-413, :553-591, and :720-762 (provider-first then local write then inline refund), source-refs/sanmopia_web/application/libraries/Kcppayment.php:418-437 (refund() always returns status => false after KCP cancel request), and source-refs/sanmopia_web/application/libraries/Kcppayment.php:447-475 (manual KCP full cancel command). |
| Payment record closeout overwrite guard | RecordProviderPaymentCloseoutCommand, RecordPreReservationPaymentCloseoutCommand, PaymentProviderAttempt, OperatorPaymentFactEditCommand, RecordReservationPaymentReceiptCommand, PaymentCloseoutRepairCase, and ProviderRefundResultEvent | Backend guard partial / manual receipt plus provider stale-handoff guard implemented. Legacy normal and pre-reservation customer closeout build mutable row payloads, then update an existing payment row by reservation plus payment type, so repeated provider/browser closeout can overwrite paid/refunded/settlement-bound facts. Modern backend now treats manual reservation receipts as new payment facts at expected revision 0 only, persists/returns payment_fact_revision, rejects stale existing rows with stale expected_payment_revision, and sends any existing payment fact mutation through OperatorPaymentFactEditCommand, which already requires actor, reason, idempotency key, immutable amount snapshot, expected revision, refunded guard, settlement-lock guard, audit, and projection invalidation. Backend 7eaef19 also carries payment_fact_revision into the Kill Bill paid-webhook payment snapshot; provider accepted/local workflow-start failure attempts compare the latest PaymentProviderHandoffSession.expected_payment_revision to the current payment fact revision, keep compensation-refund intent eligible, and mark stale_payment_provider_handoff_revision plus payment_fact_revision:expected:*:actual:* source evidence when the browser/provider handoff used old payment facts. Provider closeout commands still need provider_attempt_id, handoff_session_id, payment_purpose, reservation/pre-reservation id, payment type, backend charge snapshot id, provider transaction id, method, raw provider result artifact id, expected payment revision, idempotency key, occurred-at timestamp, and repair-case id when replaying. Remaining runtime work: actual provider closeout mutation must persist closeout facts with provider attempt lineage in the same revision/repair model and bind provider refund result ingestion. | source-refs/sanmopia_web/application/models/Payment_model.php:50-75 (customer closeout update path by reservation/payment type), source-refs/sanmopia_web/application/models/Payment_model.php:198-226 (normal payment-row payload and status/deposited fields), source-refs/sanmopia_web/application/models/Payment_model.php:794-819 (pre-reservation payment-row payload and status/deposited fields), source-refs/sanmopia_web/application/controllers/api/Payment.php:111-180 (normal provider result then local write/refund-on-failure), and source-refs/sanmopia_web/application/controllers/api/Payment.php:537-572 (pre-reservation zero/provider closeout then local write/refund-on-failure). |
| Payment closeout-triggered notification/document activation | PaymentCloseoutNotificationOutbox, ReservationDocumentReadinessLifecycle, ReservationDocumentReadinessRevocationAfterPaymentRepair, DocumentCenterProjectionInvalidationAfterRefund, PaymentCommunicationWorkflow, and DocumentRecipientAuthority | Partial; trigger ordering and revocation not fully owned. Legacy downpayment closeout creates promotion and reservation-document notifications inline, while document screens mint a two-hour documentDownload token and the download API only rechecks token plus reservation ownership before rendering/downloading. Controllers also send immediate customer/branch Aligo or SMS notices after the DB transaction and suppress standard completion notices for virtual-account flows. Modern closeout should emit ordered outbox facts after payment record commit and document readiness should derive from backend payment closeout, not controller side effects. Refund, paid-row repair, closeout replay, or party-authority repair must invalidate or revoke document readiness, document-center projection rows, and issued access grants before new artifacts or handoffs are exposed. Required facts: PaymentFactCommitted, VirtualAccountInstructionIssued, CustomerPaymentCompletionNoticeRequested, BranchPaymentCompletionNoticeRequested, ReservationDocumentReadinessActivated, ReservationDocumentReadinessRevoked, DocumentCenterProjectionInvalidated, recipient authority snapshot, branch recipient snapshot, and branch-special-recipient routing proof. | source-refs/sanmopia_web/application/models/Payment_model.php:126-138 (inline MOMFIRST_PROMOTION and RESERVE_DOCUMENT notification creation), source-refs/sanmopia_web/application/models/User_model.php:461-489 (document token replacement and two-hour lookup), source-refs/sanmopia_web/application/controllers/MyReservation.php:365-370 and source-refs/sanmopia_web/application/controllers/Notification.php:19-25 (logged-in document-token issuance paths), source-refs/sanmopia_web/application/controllers/api/ReservationDocument.php:21-39 (token plus reservation ownership download guard), source-refs/sanmopia_web/application/views/mypage/reservation_document.php:118-137 (browser-composed document download URL), source-refs/sanmopia_web/application/controllers/api/Payment.php:126-157 (virtual-account instruction notice before local closeout), source-refs/sanmopia_web/application/controllers/api/Payment.php:182-214 (normal downpayment customer/branch completion notices and branch-id special recipient), source-refs/sanmopia_web/application/controllers/api/Payment.php:598-645 (pre-reservation customer/branch completion notices and branch-id special recipient), and source-refs/sanmopia_web/application/controllers/api/Payment.php:740-755 (change-payment customer/branch completion notices). |
| Payment closeout occurrence-ledger materialization | MaterializeReservationServiceOccurrenceLedgerCommand, PaymentCloseoutOccurrenceLedgerGuard, ServiceOccurrenceLedger, ReservationPaymentWorkflow, ReservationDateMaterializationPolicy, and SettlementContinuationPrerequisite | Partial; customer payment closeout trigger still mapped as source evidence only. Legacy successful payment calls RESERVATION_DATE_INSERT_FN, making service occurrence materialization a hidden payment side effect. The same routine also runs from service voucher/date edits and admin service-period saves, so modern closeout must validate or idempotently create occurrence ledger facts with a source-attributed cause (payment_closeout, service_period_change, or admin_repair), expected reservation/service-period revision, service calendar policy fingerprint, payment closeout event id, idempotency key, and resulting occurrence-ledger revision before settlement, payout, calendar, or report readiness changes. | source-refs/sanmopia_web/application/models/Payment_model.php:276-278 (payment closeout triggers reservation-date insertion function), source-refs/sanmopia_web/application/controllers/api/Payment.php:160-180 (normal local closeout call site), source-refs/sanmopia_web/application/models/Reservation_model.php:510 and :539 (service voucher insert/update also call the routine), source-refs/sanmopia_web/application/models/Reservation_model.php:3170-3173 and source-refs/sanmopia_web/application/controllers/api/Reservation.php:439-444 (service-period edit wrapper), source-refs/sanmopia-admin/application/controllers/Reservation.php:1080-1088 (admin pre-reservation service save calls the routine), and source-refs/sanmopia-admin/application/models/Reservation_model.php:2017 and :5196 (admin service/payment save and admin add-reservation paths call the routine). |
| Pre-reservation conversion payment compatibility | PreReservationConversionStateProjection, PreReservationConversionPaymentCompatibility, ReservationPriceVersionAdjustment, and CancellationRefundEligibility | Partial; exact compatibility flag not yet isolated. Source PRE_CONVERT_FL changes cancellation, detail display, and price-version behavior after pre-reservation converts into a reservation. Modern backend must freeze conversion state, payment lineage, prior pre-reservation credits/coupons, and refund/price-version compatibility instead of letting UI/status queries infer it from raw flags. | source-refs/sanmopia_web/application/models/Payment_model.php:108-114, source-refs/sanmopia_web/application/models/Reservation_model.php:1537-1545, and source-refs/sanmopia-admin/application/models/Reservation_model.php:5677-5684. |
| Stopped voucher settlement seed backfill | StoppedReservationSettlementSeedBackfillCommand, SettlementStatementSeedDecision, ReservationCancellationSettlementImpact, SettlementSeedRepairAudit, and ReservationFinancialLifecycleSeedRepair | Mapped; backfill command missing. Normal legacy status save opens branch/HQ settlement rows from raw reservation status, while a separate admin repair path finds stopped voucher reservations missing those rows and would seed type 1/2 settlement rows by reservation id only. Modern backfill must be a backend repair command with expected reservation revision, frozen stopped-voucher eligibility, cancellation/refund impact proof, payment fact revision, idempotent seed decision, actor scope, and append-only audit before branch/HQ statement projections or artifact exports see repaired data. UI/admin/PHP must not infer settlement readiness from raw status 13, missing PAYMENT_ADMIN_BRANCH_TB rows, or mutable payment-row refund flags. | source-refs/sanmopia-admin/application/models/Reservation_model.php:1803-1820 (status transition opens service-balance, caregiver payout, and branch/HQ settlement seed paths), source-refs/sanmopia-admin/application/models/Payment_model.php:2619-2653 (raw branch/HQ settlement seed rows PAYMENT_TYPE_LIST_ID_FK 1/2), source-refs/sanmopia-admin/application/controllers/Administrator.php:203-210 (repair endpoint), and source-refs/sanmopia-admin/application/models/Payment_model.php:4241-4262 (stopped voucher missing-seed scan and commented row insertion). |
| Virtual-account issue, deposit callback, dedupe, and paid-after-expired race | VirtualAccountPaymentLifecycle, PaymentVirtualAccountInstructionPayload, PaymentVirtualAccountInstructionSnapshot, PaymentProviderNotificationDeduplication, and VirtualAccountDepositReservationTransition | Backend foundation / Persistence partial. Typed lifecycle/domain exists, and 2026-07-09 backend follow-up now persists VirtualAccountPaymentLifecycleDecision rows in Supabase through a service-role-only, RLS-enabled table. Runtime notification id dedupe, amount-match proof, cancel/non-TX00 lifecycle facts, reservation-transition decision persistence, and expired-after-paid race handling still need proof. Legacy code matches only order_no/tno, treats already-paid rows as success, stores raw KCP JSON, and can mutate 입금대기 -> 예약 or 사전예약대기 -> 사전예약 from a late callback without a frozen expiry decision. | source-refs/sanmopia_web/application/controllers/api/Kcp.php:18-103 (IP check, raw POST log, non-TX00/cancel ack, noti_id read but not persisted as idempotency key), source-refs/sanmopia_web/application/models/Kcp_model.php:8-13 (raw JSON log only), source-refs/sanmopia_web/application/models/Payment_model.php:166-215 and :353-380 (waiting status and raw PAYMENT_CONTEXT storage), source-refs/sanmopia_web/application/models/Payment_model.php:512-734 (deposit row lookup, already-paid shortcut, reservation status movement, paid timestamp, notices). |
| Virtual-account reminders and expiry | VirtualAccountExpiryScheduler, VirtualAccountExpiryTransitionCommand, ExpiredVirtualAccountDepositRaceDecision, ReservationStateTransitionAudit, and PaymentCommunicationWorkflow | Missing scheduler proof / Partial foundation. Existing foundation names typed expiry events, but cron replacement, scheduled lifecycle job persistence, reminder idempotency, frozen instruction amount/deadline reuse, and expiry/deposit race decision are still missing. PHP cron reads provider JSON deadline/bank/account/price and mutates reservation status directly; UI/PHP must not rebuild reminder content or expiry state from PAYMENT_CONTEXT. | source-refs/sanmopia_web/application/controllers/cli/Reservation.php:562-600 (deadline cron calls direct reservation mutation), source-refs/sanmopia_web/application/models/Reservation_model.php:2960-2993 (deadline query from PAYMENT_CONTEXT.va_date, bank, account, price), source-refs/sanmopia_web/application/models/Reservation_model.php:2998-3031 (status 14 -> 17 plus source change log), source-refs/sanmopia_web/application/controllers/cli/Reservation.php:646-735 (cancel notice), and source-refs/sanmopia_web/application/controllers/cli/Reservation.php:760-827 (two-day reminder from raw bank/account/deadline/price JSON). |
| Branch/HQ settlement mutation provenance | SFC-20260709-CUR-103, SettlementStatementApprovalCommand, SettlementBoardMutationProvenanceImport, SettlementTransitionAudit, SettlementLineAcknowledgement, SettlementStatementDatasetRevision, and SettlementStatementManualAdjustmentLineCommand | Partial; source mutation import missing. Finance transition audit and payout refresh provenance exist, but source board/detail/coupon/manual-row mutations still need import/backfill with actor, reason, expected revision, source board id, row ids, selected line set, before/after status, and recalculated total fingerprint. Legacy JS/PHP posts authoritative totals, row ids, flags, memo/message, manual etc names/counts/prices, and actor type; model paths flip board/detail/coupon/manual statuses from mutable rows. UI/PHP must not own settlement totals, row completion, membership/delivery/cancelled-coupon flags, or final branch/HQ settlement state. | source-refs/sanmopia-admin/static/js/calculate_detail.js:85-165 (selected normal/voucher/coupon ids), source-refs/sanmopia-admin/static/js/calculate_detail.js:184-249 (delivery, coupon fee, flags, ftotal-price, fresult-price, actor type), source-refs/sanmopia-admin/static/js/calculate_detail.js:930-1047 and :1053-1144 (browser recomputes delivery, membership, etc, coupon fee, result totals), source-refs/sanmopia-admin/application/controllers/Calculate.php:150-312 (controller accepts posted totals/ids/flags/memo and branches by login type), source-refs/sanmopia-admin/application/models/Payment_model.php:2525-2562, :2861-2915, :2977-3051, and :4265-4308 (board/detail/coupon/etc status mutations), source-refs/sanmopia-admin/application/models/Payment_model.php:4312-4400 (current board/detail read and completion count), and source-refs/sanmopia-admin/application/controllers/Calculate.php:568-578 (export by raw board id). |
| Branch/HQ component readiness and arrears replay | SFC-20260709-CUR-103, SFC-20260708-CUR-088, SettlementLineAcknowledgement, SettlementComponentReadinessProjection, HeadquartersSettlementCloseoutReadinessProjection, SettlementComponentReadinessInvalidationAfterPaymentRepair, and SettlementBoardRepairReadinessRefresh | Partial; backend settlement ledger work may cover line facts, but legacy compatibility still needs imported component readiness plus post-refund/repair invalidation. Source branch users acknowledge membership fee, delivery, detail rows, coupon rows, cancelled-coupon gift fee, and manual etc rows separately; HQ/admin can move board status from request/arrears to complete only after mutable board/detail/coupon/etc flags count as complete. Legacy refund flips local payment rows to refunded status without touching board component flags, so refund or closeout repair after branch acknowledgement can leave stale HQ readiness unless backend refreshes/revokes the component projection. Modern closeout must consume backend-produced ledger facts, imported source board component acknowledgements, settlement statement revision, payment fact revision, and reversal/repair invalidation outcome before final HQ closeout. | source-refs/sanmopia-admin/application/controllers/Calculate.php:206-211 (HQ zeroes cancelled-coupon fee when not requested), source-refs/sanmopia-admin/application/controllers/Calculate.php:219-277 (HQ create/confirm/arrears status path), source-refs/sanmopia-admin/application/controllers/Calculate.php:279-309 (branch component acknowledgement path), source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3011 (first deposit vs arrears replay), source-refs/sanmopia-admin/application/models/Payment_model.php:4382-4400 (completion is membership + delivery + detail + coupon flags), source-refs/sanmopia-admin/application/models/Payment_model.php:4403-4419 (complete-count helper reads mutable detail/coupon/etc rows), and source-refs/sanmopia_web/application/models/Payment_model.php:423-430 (refund only updates normal/voucher paid row status). |
| Refund and partial-refund settlement impact | RecordProviderRefundResultCommand, ProviderRefundPaidRowTransition, PartialPaymentRefund, PaymentRefundIntent, ProviderPartialRefundCapabilitySnapshot, SettlementRefundImpactProjection, SettlementLedgerReversalLine, and SettlementStatementInvalidationAfterRefund | Partial; provider/refund transition, provider-result reporting invalidation queue request, branch settlement export refresh handler, branch/HQ settlement statement and operator-board read-model refresh validation, sales-dashboard snapshot coverage validation, settlement reversal-line persistence, ledger-backed internal runtime entrypoint, workspace-domain artifact grant revocation, internal repair planning, repair execution-attempt persistence, and repair execution-to-ledger-result recording now exist; provider worker/webhook proof, artifact revocation persistence/reissue projection, full sales-dashboard fact recompute, and retry/result-history hardening remain. Legacy full refund calls KCP and then only flips normal/voucher payment rows to refunded status; it does not append settlement reversal lines, invalidate branch/HQ board component readiness, or revoke/reissue already-built settlement exports. Provider payment output exposes partcanc_yn, but partial-cancel request fields were not found, only the full-cancel STSC command. Backend 9cc034c now persists provider result plus paid-row transition decision/rejection as a durable Supabase fact before any read model can treat refund state as final. Backend e038c7c then persists provider-refund reporting invalidation instructions for sales dashboards, branch/HQ settlement statements, settlement export artifacts, and branch/HQ operator boards with explicit recalculation versus repair flags. Backend 8db9942 wires those instructions into the configured provider-result recording path instead of requiring callers to remember a second handler call. Backend fa13ef7 adds a typed projection-refresh request plan, dedicated sanmopia_provider_refund_reporting_refresh queue workload, and refresh_requested invalidation status. Backend c46382b consumes the queue payload through a target-refresh handler port and records refreshed or refresh_failed; backend 6bd851c implements the settlement_export_artifact target by resolving payment id to branch profile, loading the branch settlement dashboard, rebuilding frozen branch reconciliation CSV/XLSX/JSON exports, and running the existing durable export workflow. Backend e705d7c hashes the raw invalidation key and normalizes branch profile id before generating workflow/export codes, keeping provider evidence out of report artifact identities. Backend d478bdb adds ProviderRefundSettlementReportingRefreshDispatcher and ProviderRefundSettlementReadModelRefreshHandler, so branch/HQ settlement statement and operator-board invalidations resolve payment id to branch profile, reload the backend settlement dashboard reader, require statement projection evidence for statement targets, and keep unsupported targets explicit. Backend 4bd75d6 adds ProviderRefundSalesRevenueDashboardRefreshHandler plus SupabaseSalesRevenueDashboardRefundImpactSnapshotReader, so sales_revenue_dashboard refresh messages now resolve payment id to branch/reservation and require an existing branch sales_overview snapshot containing that reservation before the invalidation can be marked refreshed. Backend ef0dade adds SettlementLedgerReversalLine, SettlementRefundImpactPolicy, RecordSettlementLedgerReversalLinesAfterProviderRefundCommand, ProviderRefundSettlementLedgerReversalRequest, Supabase persistence for sanmopia_settlement_ledger_reversal_lines, and a boundary-safe settlement-continuation bridge that Tach validates without importing payment domain types into settlement. Backend ebf785d wires app composition and internal HTTP boundary so one provider-result command records transition decision, queues reporting refresh, and emits settlement reversal lines through Supabase-backed stores. Backend 6120324 adds ledger-backed provider-result recording: the worker route accepts payment id, refund intent, provider result id/reference/status/idempotency, then backend reads PaymentRefundLedger for the refund amount and rebuilds the current paid-row snapshot from sanmopia_provider_refund_paid_row_transition_decisions. Backend 3e6d83f adds repair-time artifact grant revocation fields to SettlementArtifactGrant, stores revoked grant ids and replacement artifact request code on SettlementRepairRequest, and proves contract round-trip. Current internal repair routes persist repair case, permission, gateway-command payload, updated refund ledger, settlement invalidation key, idempotency-keyed execution attempts from the configured billing gateway, and ledger-backed provider-result recording from accepted/rejected repair execution. Modern refund completion must still persist refund reason, original provider attempt/payment fact revision, provider partial-refund capability snapshot, settlement statement revision, full sales-dashboard fact recompute, Kill Bill/provider worker proof, Supabase/stage grant-revocation persistence, and operator-visible reissue lineage before branch/HQ statements or archive exports can be considered final. Provider-success/local-write-failure still needs retry/result-history proof, stage webhook proof, and operator projection beyond execution-to-ledger-result recording. | source-refs/sanmopia_web/application/models/Payment_model.php:383-440 (full reservation refund scans provider-context rows without a paid-status predicate, calls provider, writes status 2), source-refs/sanmopia_web/application/libraries/Kcppayment.php:39, :252, and :392 (provider partial-cancel capability evidence), source-refs/sanmopia_web/application/libraries/Kcppayment.php:447-458 (KCP full cancel command), source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31-42 (admin full cancel command), source-refs/sanmopia-admin/application/controllers/Calculate.php:248-263 (HQ settles or marks arrears from mutable board flags), source-refs/sanmopia-admin/application/models/Payment_model.php:2384-2475 (branch/HQ board totals recomputed from mutable payment/coupon/etc rows), source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3011 and :4382-4400 (board/component status determines complete vs arrears), and source-refs/sanmopia-admin/application/controllers/Calculate.php:568-578 (export streams by raw board id and would need invalidation after refund). |
| Custom discount, surcharge, and settlement adjustment catalog | SFC-20260708-CUR-088, SettlementAdjustmentLineCommand, SettlementAdjustmentCatalogRevision, SettlementManualDiscountSurchargePolicy, and RegionalBenefitSettlementImpactSnapshot | Partial; HTTP manual-adjustment contract rejects posted totals, but persisted catalog issuance and source discount parity are incomplete. Legacy lets operators create positive or negative “other service” rows, post names/counts/prices from the browser, and fold those rows into branch/HQ totals. It also applies branch/region-specific voucher discount arithmetic inside settlement data loading. Modern policy must freeze adjustment effect, reason, quantity, actor scope, catalog revision, regional-benefit revision, and settlement statement revision before recognition. | source-refs/sanmopia-admin/application/views/modal/modal_other_service_add.php:23-29 (negative price reduces branch remittance), source-refs/sanmopia-admin/static/js/calculate/other_service_management.js:43-96 (browser add/remove catalog rows), source-refs/sanmopia-admin/application/controllers/Calculate.php:184-203 and source-refs/sanmopia-admin/application/controllers/Calculate.php:240-245 (posted etc arrays saved with board log), source-refs/sanmopia-admin/application/models/Payment_model.php:2861-2908 (manual rows persisted), source-refs/sanmopia-admin/application/models/Payment_model.php:962-964 and source-refs/sanmopia-admin/application/models/Payment_model.php:2442-2475 (manual rows folded into totals), and source-refs/sanmopia-admin/application/models/Payment_model.php:3759-3767 (hardcoded Yeongdeungpo discount in voucher settlement calculation). |
| Settlement document/export UX and archive grants | SFC-20260708-CUR-088, SFC-20260708-CUR-098, SFC-20260709-CUR-103, SettlementArchiveRequest, SettlementStatementDatasetRevision, SettlementArtifactGrant, and SettlementArtifactBuildRunLedger | Partial; export-line/dataset foundations exist, but data-room handoff and grants remain missing. Legacy data-room tables navigate by raw dataType and board id, export endpoints accept excelType/boardId, spreadsheet builders reload mutable rows, recompute fees/net deposits, insert formulas, and stream the workbook directly. Modern UX needs actor-bound artifact requests, frozen dataset revisions, signed grants, build ledger rows, and no route or spreadsheet formula authority from board ids. | source-refs/sanmopia-admin/static/js/data_room/calculate_central.js:10-14 and source-refs/sanmopia-admin/static/js/data_room/calculate_danvi.js:10-14 (raw board/detail navigation), source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:43-60 and source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:29-49 (table buttons expose board ids and data type), source-refs/sanmopia-admin/application/controllers/Calculate.php:568-578 (raw export request), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3772 (reloads board/detail rows), source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3795-3880 (writes mutable service/coupon net deposit rows), and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3898-3911 (spreadsheet formula plus direct output stream). |
-
2026-07-10 runtime binding update for refund settlement impact: backend
1a6a7cccloses the runtime-processor-binding gap for export-artifact refresh by routing the provider-refund reporting queue into the concrete branch settlement export refresh handler. Backendd478bdbextends that runtime path with a dispatcher and backend read-model refresh validation for branch/HQ settlement statement plus branch/HQ operator-board targets. Backend4bd75d6routes sales-dashboard refresh messages through a backend validation handler that resolves payment to branch/reservation and requires a matchingsales_overviewsnapshot before marking the invalidation refreshed. Backendc1e0904makes data-roomrequest_repairsupersede the active artifact immediately and persist supersession reason/artifact id through the Supabase data-room request RPC. Backend3e6d83fadds workspace-domain and contract proof that repair revokes active artifact grants and records the replacement artifact request code. The internalPOST /internal/payment-refund-repairs/provider-refund-plansroute now covers provider-success/local-write-failure repair planning and Supabase persistence only. Remaining refund impact gates are full sales-dashboard fact recomputation/read API, provider worker/webhook proof, Supabase/stage persistence for grant revocation and replacement-request linkage, stage artifact-storage proof, and provider-success/local-write-failure Kill Bill execution/result ingestion. -
2026-07-10 ledger-backed provider-result boundary: backend
6120324addsProviderRefundResultFromLedgerHandler,SupabaseProviderRefundPaidRowSnapshotReader, and/internal/provider-refund-results-from-ledger. The endpoint lets a provider worker submit payment id, refund intent, provider result reference, status, occurred-at, and idempotency evidence; backend derives refund amount from the immutable refund ledger and derives current paid-row revision/state from prior applied provider-refund transition decisions. This removes the need for a worker or UI to compute refund amount, already-refunded amount, or paid-row revision. -
2026-07-10 Kill Bill ExtBusEvent payment mapping: backend
31e5d83removes inventedPAYMENT_REFUNDED,PAYMENT_VOIDED,PAYMENT_PENDING, nesteddata,tenantApiKey, and cancellation-id callback semantics. The callback ACL now accepts officialobjectType=PAYMENTevents, usesobjectIdas payment id, and parses JSONmetaDataforpaymentTransactionId,transactionType,status, amount, currency, andeffectiveDate.PURCHASE/CAPTUREsuccess starts paid verification,REFUNDsuccess/failure enters the ledger-backed provider-result recorder, andVOIDsuccess synchronizes cancellation. Missing refund-result recorder now fails closed; no legacy status-sync fallback remains. Supabase migration20260710220000_killbill_ext_bus_payment_events.sqlreplaces fictional event columns with tenant, account, operation, status, amount, and currency evidence plus an ExtBus-specific DB constraint. -
2026-07-10 Kill Bill ExtBusEvent stage probe: a synthetic official callback returned
202, queued onesanmopia_payment_webhook_processingmessage, processed one message without retry/dead-letter, and persisted akillbill_ext_bus_event_v1row withPURCHASE,SUCCESS,180000, andKRW. The nonexistent probe payment was safely recorded as ignored. An invented legacyPAYMENT_REFUNDEDpayload was rejected with400. This proves callback/API/queue/worker/Supabase wiring, not a callback emitted by a live Kill Bill deployment. -
2026-07-10 payment webhook inbox conflict probe: backend
072b2e0derives stable event identity from tenant, event, payment, transaction, operation, and effective time; canonicalizes JSON and metadata before hashing payload; and callssanmopia_register_killbill_payment_event_inbox. Stage accepted the first delivery asqueued, treated whitespace/key-order replay asduplicate, and treated the same identity with a changed amount asquarantined. Four HTTP deliveries produced one PGMQ message and one worker execution. The canonical row kept amount181000, replay count advanced, one repair-pending conflict row retained amount-drift payload evidence, repeated conflict observation count advanced, and direct canonical amount mutation failed through the DB immutability trigger. This closes inbox race/digest quarantine, not business effect-level replay. -
2026-07-10 provider refund paid-row mutation: backend
f391565records provider refund paid-row transition decisions throughsanmopia_record_provider_refund_paid_row_transition_decision, not a loose Data API upsert. The Supabase RPC inserts the provider-result decision and advancessanmopia_payment_records.payment_statuspluspayment_fact_revisionunder the expected revision guard. It maps provider-domainpartially_refundedto persistedpartial_refunded, adds full-refundrefunded, and restricts function execute access toservice_role. -
2026-07-10 provider refund internal runtime proof: stage smoke
scripts/supabase_stage_provider_refund_paid_row_transition_smoke.shnow proves the internal provider-result E2E path: paid payment row plus immutable refund ledger,/internal/provider-refund-results-from-ledger, transition decision persistence, payment-row status/revision mutation, receipt-preservingpartial_refundedconstraints, and settlement reversal-line persistence. The smoke now also verifies the six provider-refund reporting invalidation rows andrefresh_requestedqueue state for sales dashboard, branch/HQ settlement statement, settlement export artifact, and branch/HQ operator-board targets.pnpm run -s supabase:smoke:stage:reservation-to-settlement-refund-impactcomposes the same refund proof after a real positive-balance reservation is settled; 2026-07-12 proof booking6a619c99-5fcf-446b-8f30-8fd03b835636reachedsettledwith service-balance amount25000, disclosure readinessready, branch settlement100000, and HQ settlement50000, then refund eventstage-provider-refund-result-20260712121644-1a6e3fa1for paymentstage-provider-refund-payment-20260712121644-1a6e3fa1produced paid-row mutation, settlement reversal, reporting refresh fanout, and registered refund batch cleanup. The provider-refund smoke wrapper now reaps itssanmopia_test_data_batches/sanmopia_test_data_referencesbatch just like reservation settlement smokes. See ADR-027. Remaining refund workflow gates are external Kill Bill provider-webhook E2E once stageKILLBILL_*env is configured, full sales-dashboard fact recomputation/read APIs, Supabase/stage persistence proof for artifact grant revocation, durable replacement-request linkage/reissue projection, and repair retry/result-history integration beyond the existing internal planning/execution/result-recording routes. Backend3e6d83falready proves the workspace-domain and contract-level repair revocation behavior. -
2026-07-10 refinement for refund settlement dataset selection authority:
ef0dadecovers immutable settlement reversal-line persistence, but source HQ branch-settlement datasets still select from mutable payment/admin/coupon rows in ways that can keep refunded, deleted, or repaired facts visible until a backend projection revokes/reissues the dataset. Modern target names:SettlementRefundDatasetSelectionPolicy,HeadquartersBranchStatementInvalidationAfterRefund, andSettlementCouponComponentRefreshAfterDeletion. Backend responsibility: recompute branch/HQ statement membership from payment fact revision, refund transition, coupon deletion/refund, settlement component revision, and dataset revision; UI/PHP filters, source status ids, and commented payment-status guards are evidence only. Evidence:source-refs/sanmopia_web/application/models/Payment_model.php:423-430(refund only flips normal/voucher paid row status to2),source-refs/sanmopia-admin/application/models/Payment_model.php:3483-3516(HQ voucher settlement reads admin-payment status and has no active source paid-row refund filter on unprocessed rows),source-refs/sanmopia-admin/application/models/Payment_model.php:3532-3541(reservation status id gate drives voucher settlement eligibility),source-refs/sanmopia-admin/application/models/Payment_model.php:3565-3594(coupon settlement joins board/coupon flags with commented status guard),source-refs/sanmopia-admin/application/models/Payment_model.php:3604-3621(deleted or granted product coupons are selected by date/status rules), andsource-refs/sanmopia-admin/application/models/Payment_model.php:3643-3649(coupon payment status flips independently from refund/delete outcome). -
2026-07-10 source-mining correction for existing
Refund and partial-refund settlement impactowner: the inspected full-reservation refund query does not select paid rows; it selects every reservation payment row with non-null provider context and has no payment-status predicate. It then performs provider refunds sequentially and returns on the first provider or local-row update failure, after earlier external refunds may already have succeeded. The reservation cancellation caller stores the returned result array and checks only array truthiness, so a non-empty{status: false}result can still continue cancellation and coupon restoration. Evidence:source-refs/sanmopia_web/application/models/Payment_model.php:383-395(provider-context selection),:398-434(sequential refund and early return), andsource-refs/sanmopia_web/application/models/Reservation_model.php:1027-1035(truthiness gate). Modern invariant: freeze the exact eligible payment-fact set with expected status/revisions before provider calls, persist one idempotentPaymentRefundIntentand result history per row, and allow the aggregate refund/cancellation barrier to complete only when every required attempt is terminal or explicitly zero-refund. Callers must branch on typed terminal status, never context presence or array truthiness. Status remainsPartial: modern refund ledger, paid-row transition, settlement reversal, invalidation, and internal repair foundations exist; multi-payment selection snapshots, all-attempt completion/repair history, provider-worker proof, and legacy eligibility backfill remain open. -
2026-07-10 refinement for
Branch/HQ component readiness and arrears replay: legacy settlement boards also compute branch/HQ visible status labels, complete amounts, and unpaid amounts from mutable board/component flags and hardcoded voucher/coupon fees. Modern target names:SettlementBoardStatusProjection,SettlementArrearsAmountProjection, andSettlementComponentAmountSnapshot. Backend responsibility: derive the board label, arrears/complete split, fee catalog revision, component status, and invalidation/reissue decision after refund, payment closeout repair, branch acknowledgement, or HQ approval; UI/PHP labels, colors, and line arithmetic are source evidence only. Evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:1083-1307. -
SFC-20260708-CUR-062Customer service-balance receipt-progress banner. Legacy customer reservation lists call a model query per reservation and render Korean text입금확인중when reservation status is settlement, branch-manager type-3 payment status is paid, and caregiver balance receipt flag remains open. This is a customer-visible settlement status projection derived from raw branch-manager flags. Evidence:source-refs/sanmopia_web/application/controllers/MyReservation.php:56-63,source-refs/sanmopia_web/application/controllers/MyReservation.php:98-106,source-refs/sanmopia_web/application/models/User_model.php:492-510, andsource-refs/sanmopia_web/application/views/mypage/reservation.php:149-160. Target:pricing_settlement / CustomerServiceBalanceReceiptProgressProjectionandcustomer_engagement / CustomerReservationCardFinancialBadge. Status:Backend API/contract read binding plus receipt producer implemented; addedCustomerServiceBalanceReceiptProgressProjectionunderpricing_settlement. The projection converts the legacy입금확인중list banner into a backend-owned financial badge code keyed by reservation, customer actor, service-balance statement revision, and source evidence. Backend follow-up now addsSupabaseCustomerServiceBalanceReceiptProgressProjectionStore,sanmopia_customer_service_balance_receipt_progress_projections, explicit Supabase Data API grants, RLS participant read policy, realtime publication, and authenticated customer routeGET /customer-service-balance-receipt-progress-projections/{reservationBookingId}. Contract OpenAPI, JSON Schema, and TypeScript client helpers publish the projection so customer reservation cards can display backend-owned badge state instead of calling a per-card legacy query or rendering raw Korean status strings. The write side now binds manualservice_balancereceipt recording,CloseReservationServiceBalanceHandlercloseout storage, andManageCaregiverPayoutReceiptStateHandlerreceipt-state changes toProduceCustomerServiceBalanceReceiptProgressProjectionHandler, which reads direct service-balance instruction rows when present, falls back toreservation_bookings.mother_user_id, maps reservation status, financial lifecycle, and multi-caregiver receipt states into semantic projection facts, and upserts the customer reservation-card projection after branch receipt, service-balance closeout, caregiver receipt-state storage, financial lifecycle transitions, or direct service-balance instruction availability changes. Completed, cancelled, stopped, and post-settlement lifecycle states now hide stale customer receipt-progress cards from backend projection state instead of leaving old settlement cards visible. Contract payloads reject rawSTATUS_ID,PAYMENT_TYPE_ID_FK,PAYMENT_STATUS_ID_FK,BALANCE_PRICE_PAYMENT_FL,SERVICE_BALANCE_PRICE_CHECK, and numeric source state codes so customer UI cannot recalculate the banner from branch-manager flags. Remaining proof: generated frontend contract export, reservation-card wiring through Nanostores, realtime stale-state refresh, and customer list/detail E2E. Multi-caregiver aggregation must keep the badge visible while any caregiver receipt remains pending and hide it only after all actionable receipt states are confirmed or the reservation leaves settlement. -
SFC-20260708-CUR-063Service-balance reminder eligibility and dispatch. Legacy FCM job sends서비스 잔금을 입금해주세요.one day before service end, but selects rows by customer-share balance payment type/status, not the service-balance payment row, and hardcodes stopped/cancelled exclusions plus current-date SQL. The result also creates notification inbox typeDEPOSIT_SERVICE_FEE. Evidence:source-refs/sanmopia_web/application/controllers/cli/Fcm.php:165-184,source-refs/sanmopia_web/application/controllers/cli/Fcm.php:191-212, andsource-refs/sanmopia_web/application/views/test/pushtest.php:12-13. Dispatch-shape evidence:source-refs/sanmopia_web/application/models/Fcm_model.php:32-56,source-refs/sanmopia_web/application/models/Fcm_model.php:150-159, andsource-refs/sanmopia_web/application/models/Notification_model.php:42-52show push links are optional and inbox rows are type-only when no target data is supplied; the service-balance reminder insertsDEPOSIT_SERVICE_FEEwithout reservation or instruction identity. Target:customer_engagement / ServiceBalancePaymentReminderPolicyandpricing_settlement / ServiceBalancePaymentInstruction. Status:Backend foundation implemented; addedServiceBalancePaymentReminderPolicyundercustomer_engagementand a contract that builds aPlanPaymentCommunicationDispatchCommandfor the existing communication dispatch pipeline. Eligibility now uses service-end date, semantic reservation lifecycle state, semantic service-balance payment status, service-balance instruction id, statement revision, amount, and idempotency instead of FCM token SQL. LegacyPAYMENT_*table fields,TOKEN,DATE_ADD(CURDATE(), INTERVAL 1 DAY),DEPOSIT_SERVICE_FEE, Korean payment labels, and raw numeric state codes are rejected at the contract boundary. Suggested backend feature:ServiceBalanceDirectPaymentReminderDispatch. -
SFC-20260708-CUR-064Branch/HQ membership-due acknowledgement default. Legacy central-to-branch settlement form hardcodesfmembership-pay-status-fl = 1in both admin and branch browser paths because the membership checkbox was not implemented, and the controller persists that browser value ontoBOARD_PAYMENT_ADMIN_TB.MEMBERSHIP_PAY_STATUS_FL. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:240-274,source-refs/sanmopia-admin/application/controllers/Calculate.php:150-182, andsource-refs/sanmopia-admin/application/controllers/Calculate.php:296-302. Target:pricing_settlement / SettlementLineAcknowledgementandpricing_settlement / BranchMembershipDueAcknowledgementPolicy. Status:Backend foundation implemented; branch membership due snapshots exist, and backend now rejects legacy UI-defaulted membership paid flags (fmembership-pay-status-fl,fmembership-pay-status,membershipPayStatusFlag) at settlement line selection contract boundaries. Branch/HQ acknowledgement now requires an explicit membership-due line reference with source revision, source evidence key, and revision embedded in the settlement line key before a membership due acknowledgement command can be built. Remaining runtime work is adapter/API wiring for the branch/HQ screen. Suggested backend feature:BranchSettlementMembershipDueAcknowledgement. -
SFC-20260708-CUR-065Booking service-term side-effect assembly. Legacy booking creation collects extra Saturday/holiday selections, Wanju benefit choice, add-option quantities, UI end-date previews, andRESERVATION_DATE_INSERT_FNcalls across different PHP/JS stages. Customer voucher booking inserts the base service row and calls the date routine before Wanju +5 days, selected add dates, add-option rows, and final end-date update; normal booking persists extra selections before recalculating the end date. Admin manual booking posts browser-built add-date arrays and Wanju option ids, runsRESERVATION_DATE_INSERT_FN, then writesRESERVATION_ADD_DATEand add-option rows. Report consumers later choose printable service occurrences fromRESERVATION_DATE_TBplus weekend/HOLIDAY_TBexclusions, not from one immutable creation snapshot. Evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:490-511,source-refs/sanmopia_web/application/controllers/api/Service.php:335-414,source-refs/sanmopia_web/application/controllers/api/Service.php:455-521,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:1412-1541,source-refs/sanmopia-admin/static/js/reservation_status/reservation_add.js:2028-2149,source-refs/sanmopia-admin/application/controllers/Reservation.php:1320-1348,source-refs/sanmopia-admin/application/controllers/Reservation.php:1740-1756,source-refs/sanmopia-admin/application/models/Reservation_model.php:4992-5039,source-refs/sanmopia-admin/application/models/Reservation_model.php:5196-5235,source-refs/sanmopia_web/application/models/Report_model.php:324-339, andsource-refs/sanmopia_web/application/models/Report_model.php:451-466. Target:reservation_operations / BookingServiceTermCreationCommand,service_calendar / ReservationServiceOccurrenceLedger,pricing_settlement / ReservationServiceCalendarQuote, andcare_delivery / ServiceOccurrenceEvidence. Status:Partial; service-term plan and occurrence-ledger foundations exist, and 2026-07-07 stage smokeRBQ-STAGE-20260707153322proved workflow booking now freezes accepted service-term snapshots plus regional-benefit decisions into durable Restate payload and creates an occurrence ledger after the booking projection parent row exists. 2026-07-08 backend addedBookingServiceTermSideEffectAssemblyPayloadandassemble_booking_service_term_side_effects()inreservation_orchestration/features/reservation_booking/so workflow success is blocked until selected add-option rows have charge links, stale or duplicate add-option charge links are rejected, daily-report and settlement consumer impact facts exist, and report/settlement projection invalidations are grouped from immutable impact facts. The assembler carries accepted service-term snapshot refs, occurrence-ledger refs, service-calendar quote refs, finalized charge snapshot id, source evidence keys, and semantic blocked reason codes; legacy UI/PHP field names such asaddDateArray,END_DT,RESERVATION_DATE_INSERT_FN, andwanjuOptionIdare rejected at contract validation. 2026-07-08 follow-up wired the draft payload through booking API, HTTP, Restate start input, and booking workflow execution; workflow success now fails when an accepted service-term plan has no side-effect assembly, emitsbooking_service_term_side_effects_assembled, and saves through a dedicatedBookingServiceTermSideEffectAssemblyStoreport when an adapter is supplied. Contract repo now documentsacceptedServiceTermPlanplusbookingServiceTermSideEffectsin the workflow start JSON Schema, TS client, and Python Pydantic contracts, including the correctedbranchActor.actorUserIdfield. 2026-07-08 second follow-up added a Supabase persistence adapter and migration forsanmopia_booking_service_term_side_effect_assembliesplussanmopia_booking_service_term_projection_invalidation_outbox, with RLS, service-role-only grants, immutable JSON snapshots, read-by-assembly-key, and runtime composition so stage booking writes assembly/outbox rows. 2026-07-08 third follow-up added the FastAPI/API read endpoint/booking-service-term-side-effect-assemblies/{assemblyKey}, reusing the workflow-progress authorization projection through the assemblybookingRequestId, plus OpenAPI, TS client, Python Pydantic, and Starlight generated API coverage for immutable assembly reads. Restate workflow response already carriesbookingServiceTermSideEffectAssemblyKey. 2026-07-08 fourth follow-up added an idempotent operator repair command for failed projection invalidations:POST /booking-service-term-side-effect-assemblies/{assemblyKey}/projection-invalidation-repairs. The command requeues only failed outbox rows, skips non-failed or already handled rows, rejects idempotency-key reuse with a different repair intent, persists immutable repair snapshots insanmopia_booking_service_term_projection_invalidation_repairs, and records the latest repair metadata on the outbox row. OpenAPI, TS client, Python Pydantic, API/HTTP/runtime, Supabase RLS migration, and focused tests are in place. 2026-07-08 fifth follow-up addedExecuteBookingServiceTermProjectionInvalidationsHandler, strict Pydantic work-item and execution-receipt payloads, consumer/worker repository ports, Supabase service-role RPC claiming withFOR UPDATE SKIP LOCKED, completed-receipt, and failed-error updates, plus outbox audit columnslast_execution_receipt,last_execution_error_code,last_execution_error_message, andlast_executed_at. 2026-07-08 sixth follow-up bound the first concrete consumer:document_reporting / DailyReportProjectionInvalidationConsumer. Backend now records service-term daily-report invalidation receipts insanmopia_daily_report_projection_invalidationswith service-role-only Supabase access, source impact fact keys, target reference, reason code, assembly snapshot key, and idempotentinvalidation_keyupsert. 2026-07-08 seventh follow-up (backend 576f04c) bound the payout-side consumer:pricing_settlement / CaregiverPayoutProjectionInvalidationConsumermapscaregiver_payout_projectionwork items intoRequestAdminCaregiverPayoutStatementProjectionRefreshCommand, adds the semanticbooking_service_term_changedtrigger, uses the existingsanmopia_admin_payout_projection_refreshdurable queue, and returns a typed execution receipt keyed by the queued refresh idempotency key. 2026-07-08 eighth follow-up (backend 153e140) bound the settlement consumer:pricing_settlement / SettlementProjectionInvalidationConsumerrecordssettlement_projectioninvalidation receipts insanmopia_settlement_projection_invalidationswith service-role-only Supabase access, source impact fact keys, target reference, reason code, assembly snapshot key, and idempotentinvalidation_keyupsert. 2026-07-08 ninth follow-up (backend c72b0db) bound the service-calendar consumer:reservation_operations / ServiceCalendarProjectionInvalidationConsumerrecordsservice_calendar_projectioninvalidation receipts insanmopia_service_calendar_projection_invalidations, addsservice_calendarto the required service-term consumer contexts, emits the third outbox row from booking workflow fixtures, and renames the generic missing-consumer blocked reason torequired_consumer_impact_fact_missing. 2026-07-08 tenth follow-up (backend 5347571) composed the execution handler into the Supabase reservation booking runtime, passes the caregiver payout projection refresh requester into the runtime, registersbooking_service_term_projection_invalidation_executionas a standard Supabase PGMQ workload, createssanmopia_booking_service_term_projection_invalidation_executionplus its dead-letter queue, and binds the main queue dispatcher to a bounded batch processor. Invalid queue payloads dead-letter, consumer batch failures retry, and successful batches complete outbox rows with receipts. Remaining gap: live reservation smoke must enqueue the workload message and prove forced failure, repair, requeue, and completion. The source-backed consumer binding map is:document_reporting / DailyReportProjectionInvalidationConsumerfor report-date and final-report selections fromsource-refs/sanmopia_web/application/models/Report_model.php:312-391andsource-refs/sanmopia_web/application/models/Report_model.php:439-518;care_delivery / CustomerDailyReportCompletionRewardProjectionfor the report-completion coupon/point comparison atsource-refs/sanmopia_web/application/models/Report_model.php:553-620;care_delivery / CaregiverReportObligationProjectionfor notification and service-record duty scans fromsource-refs/sanmopia-manager/application/models/User_model.php:1565-1643,source-refs/sanmopia-manager/application/models/User_model.php:1729-1901,source-refs/sanmopia-manager/application/models/User_model.php:1903-1982, andsource-refs/sanmopia-manager/application/models/User_model.php:2070-2106;pricing_settlement / BranchToHeadquartersSettlementProjectionandGiftCouponSettlementPeriodProjectionfor service-start/end settlement buckets fromsource-refs/sanmopia-admin/application/models/Payment_model.php:3483-3563andsource-refs/sanmopia-admin/application/models/Payment_model.php:3565-3641;pricing_settlement / SettlementCollectionSummaryProjectionfor board totals/status and UI-posted amount distrust fromsource-refs/sanmopia-admin/application/models/Payment_model.php:1750-1960,source-refs/sanmopia-admin/application/controllers/Calculate.php:150-313, andsource-refs/sanmopia-admin/static/js/calculate_detail.js:780-1160(backend now records service-term settlement projection invalidation receipts for this grouped target);pricing_settlement / CaregiverPayoutStatementProjectionfor service-day, extra-option, custom-balance, and tax-sensitive payout math fromsource-refs/sanmopia-manager/application/helpers/salary_helper.php:67-145andsource-refs/sanmopia-manager/application/helpers/salary_helper.php:147-214(backend now queues this projection refresh from service-term invalidation work items);service_calendar / ReservationCalendarProjectionplusReservationServiceOccurrenceBoundaryProjectionfor calendar display and first/last occurrence boundaries fromsource-refs/sanmopia-admin/application/controllers/Reservation.php:609-647,source-refs/sanmopia-admin/application/views/reservation_status/reservation_calendar.php:61-110, andsource-refs/sanmopia_web/application/models/Reservation_model.php:2407-2428(backend now requires and records service-calendar projection invalidation receipts for this target);care_delivery / CaregiverAttendanceServiceOccurrenceProjectionfor additional-day attendance eligibility and attendance repair fromsource-refs/sanmopia-manager/application/models/Attendance_model.php:18-49andsource-refs/sanmopia-admin/application/models/Manager_model.php:2498-2525; andcare_delivery / CaregiverAssignmentAvailabilityProjectionfor service-term-dependent matching availability fromsource-refs/sanmopia-admin/application/models/Matching_model.php:44-145,source-refs/sanmopia_web/application/models/Manager_matching_model.php:166-228, andsource-refs/sanmopia-admin/application/models/Manager_model.php:2146-2180. 2026-07-08 source-mining follow-up adds closure/exception evidence: legacy PHP computes normal/voucher end dates by multiplying week/day catalog values, moving Saturday/Sunday end dates backward, and Wanju admin preview adds seven raw days before delegating another end-date calculation. Holiday operators can add free-form holiday types, revise/deleteHOLIDAY_TB, and the browser postsholiday-type,holiday-date, and edit/delete intent directly. Evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:463-511,source-refs/sanmopia-admin/application/controllers/Reservation.php:1739-1758,source-refs/sanmopia-admin/application/models/Manage_system_model.php:9-181, andsource-refs/sanmopia-admin/static/js/manage_system/holiday_list.js:18-107. Desired abstraction:service_calendar / ServiceTermOccurrenceRegenerationPolicy,service_calendar / HolidayClosureRevisionCommand, andservice_calendar / RegionalServiceTermExceptionProfile. Test gap: replay Wanju +7, voucher 5-day-to-7-day conversion, Saturday/Sunday rollover, free-form holiday add/edit/delete, and custom closure revision invalidating occurrence, report, settlement, coupon, payout, and matching projections. UI arrays, option labels, counts, and preview end dates must remain evidence only. 2026-07-10 backend56413fehardens revision-level occurrence lineage:service_occurrence_ledger_keyandservice_occurrence_ledger_revisionare physical non-null add-option revision columns; snapshot key presence/equality checks and validated composite booking/ledger/assembly/revision foreign keys bind the revision to its booking occurrence ledger and side-effect assembly. Revision identity now includes occurrence-ledger plus calendar-quote revisions. Assembly deletion usesNO ACTION, and an immutable trigger permits identical idempotent replay while rejecting evidence mutation. Migrations:backend-repo/supabase/migrations/20260710190000_booking_service_term_add_option_occurrence_lineage.sql:1-75,backend-repo/supabase/migrations/20260710191500_booking_service_term_occurrence_lineage_integrity.sql:1-47, andbackend-repo/supabase/migrations/20260710193000_booking_service_term_add_option_revision_immutability.sql:1-74. Stage reservationeeef7782-aff2-4065-bf9c-7ab48f7fd629reachedsettled. Migration traps/debt remain owned by thisSFC-20260708-CUR-065item:UI/calculation-derived quantity basis. Legacy browser code counts rendered Saturday/holiday elements, multiplies child/family and added-hour selections by
getServiceDay(), and totals DOMdata-pricevalues atsource-refs/sanmopia_web/static/js/step3.js:477-560and:613-832. ThegetServiceDay()selectors at:616-617even omit the class prefix used by.saturday-item/.holiday-itemelsewhere. PHP then converts posted date-array counts into option quantities atsource-refs/sanmopia_web/application/controllers/api/Service.php:358-414and:476-524. Backend4f7bebftypedquantity_basisis still a caller assertion: the stage fixture suppliesadded_service_dayplusextra/saturday/1directly atbackend-repo/scripts/supabase_stage_reservation_booking_smoke.py:176-191. Remaining gate: derive basis and evidence keys from accepted occurrence-ledger entries and charge policy, rejecting caller-calculated basis even when enum-valid.JSON-contained per-charge-link lineage. Revision-level occurrence and calendar lineage is now backed by physical constrained columns, but
add_option_charge_linksand per-link quantity/evidence detail remain JSONB atbackend-repo/supabase/migrations/20260710152000_booking_service_term_add_option_selection_revisions.sql:17-38; the reader reloads onlyrevision_snapshotatbackend-repo/src/sanmopia_modernization/adapters/reservation_booking/supabase_booking_service_term_side_effect_assembly.py:133-149. Database now proves revision ancestry and snapshot equality, but schema exposes no normalized constrained row per selection, quantity basis, occurrence evidence key, charge component, and consumer policy. Remaining gate: normalized immutable link rows with revision/selection uniqueness and indexed lineage, retaining JSON snapshots as audit envelopes rather than sole per-charge-link financial lineage.Per-charge-link integrity remains application-emulated. Pydantic enforces four basis values, positive quantity, non-empty evidence tuples, and stable-looking strings at
backend-repo/src/sanmopia_modernization/application/reservation_orchestration/features/reservation_booking/booking_service_term_side_effect_assembly.py:57-96, while database now enforces revision-level occurrence/assembly identity, snapshot equality, immutability, and deletion safety. JSON link contents still lack database-enforced per-link enum, evidence-target membership, selection-to-charge uniqueness, and consumer-policy references. Remaining gate: normalized link constraints or one revision-write RPC that validates each link atomically against accepted service-term, occurrence-ledger, quote, and finalized charge facts without weakening56413fereplay/immutability guarantees.Mutable post-payment values. Admin payment-date writes reload current price, coupon, in-home, regional-discount, and service-balance facts, block only refunded rows, then overwrite existing payment
PRICEand paid state atsource-refs/sanmopia-admin/application/models/Reservation_model.php:1566-1652. Admin reservation/document reads also rebuildPRICE_TABLEfrom current add-option rows atsource-refs/sanmopia-admin/application/models/Reservation_model.php:194-229and:643-695. Remaining gate: accepted selection/occurrence/charge revisions become append-only payment authority; later edits create explicit adjustment or repair revisions and invalidate payout, settlement, document, and refund projections instead of rewriting paid values or rerendering current formulas. Suggested backend feature:BookingServiceTermSideEffectAssembler. -
SFC-20260708-CUR-066Positive-only settlement component acknowledgements. Legacy branch/HQ settlement confirmation treats omitted or zero component flags as no-op, while selected rows and positive flags mutate board, detail, coupon, delivery, membership-due, and manual-etc state. Branch data-room close posts only board id, settlement type, and optional coupon ids; branch acknowledgement converts browser checkbox booleans into paid flags, thenupdateBoardForCentralToBranch()drops every0value before updatingBOARD_PAYMENT_ADMIN_TB. Detail, coupon, gift-fee, and manual-etc rows are marked paid only from selected ids or all-row flags, and HQ closeout later derives settled vs arrears from flag/count SQL. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:342-380,source-refs/sanmopia-admin/application/controllers/Calculate.php:289-307,source-refs/sanmopia-admin/application/models/Payment_model.php:3034-3051,source-refs/sanmopia-admin/application/models/Payment_model.php:4265-4310(detail/coupon acknowledgements are updated from reservation/coupon ids, not statement-line ids), andsource-refs/sanmopia-admin/application/models/Payment_model.php:4382-4419. Target:pricing_settlement / SettlementComponentAcknowledgementCommand,pricing_settlement / SettlementLineAcknowledgement, andoperator_access / SettlementAcknowledgementActorGrant. Backend rule: every acknowledgement, reversal, and repair must address a stable settlement statement line id with expected statement and line revisions; reservation ids, coupon ids, all-row flags, and legacy board ids are source evidence only and cannot authorize component mutation or reissue. Status:Backend API/persistence implemented; statement and line command foundations now includeSettlementComponentAcknowledgementCommandPayload, which requires explicitpaid,unpaid, orpartially_paiddecisions with expected board revision, per-line revision, evidence keys, and paid/unpaid amounts. Legacy positive-only form fields such asfis-checked-month-due,fis-checked-delivery,fmembership-pay-status-fl,fcancel-coupon-status-fl,STATUS_FL, and selected-id arrays are rejected recursively. Runtime API now exposesPOST /settlement-component-acknowledgements, authorizes the actor through SpiceDBsanmopia/branch_settlement#review, records line-decision rows insanmopia_settlement_component_acknowledgement_decisions, and replays by idempotency key instead of accepting browser checkbox math. Operator board read models now expose stable line keys plus latest backend acknowledgement snapshot per line, so frontend can render paid/unpaid/partial state without recomputing checkbox totals. Remaining runtime work: stage-smoke this endpoint against self-hosted Supabase/SpiceDB and feed recorded decisions into the branch/HQ board closeout write projection. Suggested backend feature:SettlementComponentAcknowledgementDecision. -
SFC-20260708-CUR-067Reservation lifecycle schedule financial seed. Legacy cron advances reservations from confirmed or extension to in-progress onSERVICE_START_DT = CURDATE()only when customer-share balance payment is marked paid and a primary caregiver is assigned, creates branch/HQ settlement seed rows at the same time, moves in-progress reservations to settlement at service-end minus two days, inserts caregiver service-balance and salary payout seed rows, and later marks settlement reservations complete from raw unpaid customer payment-row counts. Zero service-balance rows are auto-marked paid for both primary and assistant caregiver slots while payout seed rows are opened. Admin settlement then uses separate current-row prerequisites: central branch settlement excludes other-area reservations and service-balance payment rows, voucher branch/HQ settlement is selected by service-end-plus-one-month and stopped-service duration rules, and settlement board closeout derives complete versus arrears from component flags/counts. Manual admin status changes duplicate this seeding by inserting service-balance, caregiver-pay, and branch/HQ settlement rows when a reservation is moved to settlement or later states, and board creation can backfill missing branch/HQ rows before marking selected details paid. Caregiver portal acknowledgements mutate payment state fromtype=paymentortype=sub_payment,service_type, and reservation id rather than frozen payout slot facts. Evidence:source-refs/sanmopia_web/application/controllers/cli/Reservation.php:83-155,source-refs/sanmopia_web/application/controllers/cli/Reservation.php:160-221,source-refs/sanmopia_web/application/controllers/cli/Reservation.php:230-280,source-refs/sanmopia_web/application/controllers/cli/Reservation.php:505-545,source-refs/sanmopia-admin/application/models/Payment_model.php:2619-2643,source-refs/sanmopia-admin/application/models/Payment_model.php:3265-3298,source-refs/sanmopia-admin/application/models/Payment_model.php:3483-3536,source-refs/sanmopia-admin/application/models/Payment_model.php:3653-3725,source-refs/sanmopia-admin/application/models/Payment_model.php:4241-4263,source-refs/sanmopia-admin/application/models/Reservation_model.php:1768-1820,source-refs/sanmopia-admin/application/models/Reservation_model.php:3466-3555,source-refs/sanmopia-admin/application/controllers/Calculate.php:248-263,source-refs/sanmopia-manager/application/controllers/Reservation.php:37-77,source-refs/sanmopia-admin/application/models/Manager_model.php:380-488, andsource-refs/sanmopia-manager/application/models/Reservation_model.php:351-410. Additional completion-gate evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:2945-3041andsource-refs/sanmopia-admin/application/models/Reservation_model.php:3095-3147; admin salary-deposit completion can repair-create missing payout rows, then moves a settlement reservation to completed only when salary deposit, service-balance deposit, and main/assistant caregiver receipt flags are all proven paid. Modern completion must be a backendReservationFinanceSettlementCompletionGateover frozen payout-slot, service-balance receipt, assignment-slot, and expected reservation-revision facts; frontend/admin pages render gate projections only. Target:reservation_operations / ReservationLifecycleScheduleProjection,care_delivery / ServiceDeliveryCompletionFact,pricing_settlement / FinancialLifecycleContinuationPrerequisite,pricing_settlement / SettlementSeedInstruction,pricing_settlement / BranchHeadquartersSettlementPrerequisiteSnapshot,pricing_settlement / CaregiverPayoutSeedInstruction, andpricing_settlement / CaregiverPayoutAcknowledgementPrerequisite. Status:foundation; backend commit93c5639addsReservationLifecycleFinancialSeedPlannerand strict PydanticPlanReservationLifecycleFinancialSeedPayloadcontract. The planner emits idempotent service-start, settlement-preparation, branch/HQ settlement seed, and caregiver payout seed instructions from durable prerequisite facts. It blocks missing customer-share balance readiness, missing primary caregiver assignment, missing service-delivery completion evidence, missing branch/HQ settlement seed sources, missing caregiver payout slots, and zero service-balance auto-closeout without explicit evidence. Legacy source fields such asSERVICE_START_DT,SERVICE_END_DT,RESERVATION_STATUS_LIST_ID_FK,SERVICE_BALANCE_CONFIRM_FL,STATUS_FL,service_type,type=payment, andtype=sub_paymentare rejected at the application contract boundary. Backend financial lifecycle APIs can already advance service delivery, caregiver payout, branch settlement, HQ settlement, and settlement completion, but remaining producers/readers must supply durable completion and prerequisite facts instead of replaying source date/status/payment-row SQL. Backend commitc91bf82addsReservationLifecycleFinancialSeedScheduler, which reads due prerequisite facts through a port, runs the planner, records each plan with scheduler run key and timestamp, and reports scanned, recorded, emitted-instruction, and blocker counts without introducing source status/payment-row authority. Backend commitfb7cb70binds that scheduler to Supabase by addingSupabaseReservationLifecycleFinancialSeedSchedulerStore, service-role-only RLS tables for prerequisite snapshots and plan snapshots, and adapter tests that prove ready-prerequisite filtering, idempotent plan upsert, planned versus blocked prerequisite status updates, and noauthenticatedgrants. The physical tables are intentionally backend-only: frontend and browser clients must read generated projections/contracts, not these seed-planning tables. Supabase CLI was invoked throughpnpm exec supabase; local migration lint remains blocked by local Postgres connectivity withLegacyDbConnectError ... Failed to connect, so migration replay/typegen must run after the self-hosted local or stage Supabase database is reachable. Backend commitb8aa09dwires the scheduler into the runtime composition root with backend-only HTTP endpointPOST /internal/reservation-lifecycle-financial-seed-scheduler-runs. The route requiresSANMOPIA_INTERNAL_JOB_TOKEN, defaultsplanningOnfrom the backend clock, derives a stable dailyschedulerRunKeywhen omitted, and runsReservationLifecycleFinancialSeedScheduleragainst the Supabase prerequisite/plan store. This moves the slice toruntime_wiredfor the scheduler trigger only; it remains note2e_provenbecause branch/HQ seed persistence, caregiver payout slot persistence, service-delivery completion production, and browser-started reservation-to-settlement proof are still incomplete. Missing facts include service-delivery completion proof, customer-share balance readiness, branch/HQ settlement line readiness, other-area settlement routing, caregiver payout slot readiness, caregiver receipt acknowledgement state, and zero-amount service-balance auto-closeout with explicit evidence. OnceServiceDeliveryCompletionFactexists, the modern producer order should be: derive lifecycle continuation eligibility, idempotently open branch/HQ settlement prerequisites, open caregiver service-balance and salary payout slots, auto-close zero service-balance slots with evidence, then expose payout acknowledgement/read models. Operator repair/backfill paths are recovery only, not the normal producer for settlement readiness. SFC-065 service-term projection invalidations must refresh this schedule and seed readiness; clients and jobs must not derive lifecycle state, branch/HQ settlement prerequisites, or caregiver payout acknowledgements directly from mutable service-date SQL, raw reservation statuses, stringservice_type, or reservation-id-only payment rows. E2E cannot be marked complete until one browser-started reservation proves the backend chain from booking request through occurrence ledger, customer-share payment/pre-registration fact, lifecycle financial seed instructions, caregiver payout slot readiness/acknowledgement, branch settlement seed, HQ settlement seed, settlement acknowledgement, and closeout without frontend recomputation or repair/backfill authority. Remaining implementation slices from the SFC-067 source-mining pass:SettlementSeedInstructionpersistence for branch/HQ rows,ServiceDeliveryCompletionFactproducer for service-end-minus-two-days readiness,CaregiverPayoutSeedInstructionpersistence for salary and service-balance slots,ZeroServiceBalanceAutoCloseoutProducerwith explicit evidence,ReservationFinanceSettlementCompletionGateto replace raw unpaid payment-row counts,BranchHeadquartersSettlementPrerequisiteSnapshotfor other-area/voucher/current-row readiness, andCaregiverPayoutAcknowledgementPrerequisiteto replace caregiver portaltype=payment/type=sub_paymentmutation. Suggested backend feature:SettlementSeedInstructionPersistence. -
SFC-20260708-CUR-068Daily-report request dispatch occurrence eligibility. Legacy FCM sends daily-report requests to customers by scanningRESERVATION_DETAIL_VWfor raw statuses진행,정산, and완료, checkingSERVICE_START_DT <= now <= SERVICE_END_DT, and splitting recipients with string rules for live-in versus non-live-in service type. It writesINPUT_DAILY_REPORTnotifications and routes to proceeding or complete detail pages from the first grouped status, without occurrence-ledger, holiday, weekend, stop/resume, extra-day, final-report, or already-submitted report eligibility facts. The manual push test exposes the same function directly. Evidence:source-refs/sanmopia_web/application/controllers/cli/Fcm.php:80-130andsource-refs/sanmopia_web/application/views/test/pushtest.php:10-11. Dispatch-shape evidence:source-refs/sanmopia_web/application/models/Fcm_model.php:32-56andsource-refs/sanmopia_web/application/models/Notification_model.php:40-52show provider push and customer inbox rows are separate token-derived writes with no reservation, occurrence, report-obligation, or dispatch-attempt identity. Target:care_delivery / DailyReportRequestDispatchPolicy,customer_engagement / DailyReportCommunicationDispatch, andservice_calendar / ServiceOccurrenceReminderEligibility. Status:Backend foundation: 5a46c0f. Backend now addsDailyReportRequestDispatchPolicy,DailyReportRequestDispatchCandidate,CustomerDailyReportRecipientSnapshot,DailyReportRequestDispatchInstruction, and theScheduleDailyReportRequestDispatchesPydantic contract. The dispatch plan uses existing daily-report notification obligations and dispatch facts, emits explicit provider-attempt and inbox-record keys, and returns suppression reasons for already-submitted, already-dispatched, not-yet-due, unreachable, inactive, or cancelled obligations. Strict contracts reject source-era reservation view, service date, raw status, service-type, manager-type, FCM token, andINPUT_DAILY_REPORTfields so the frontend cannot recreate the PHP scheduler. Remaining proof: Supabase dispatch receipt persistence,CustomerNotificationDispatchOutbox, provider-attempt ledger, due-eligibility projection refresh from SFC-065 occurrence invalidations, API/worker binding, and runtime E2E proof against service-term holidays, stop/resume, extra days, final day, and already-submitted report facts. Legacy PHP CLI, not modern UI, performed the status/service-type/destination decision; the legacy test page only exposed a manual trigger and must not become frontend scheduling authority. Suggested backend feature:DailyReportRequestDispatchPolicy. -
SFC-20260708-CUR-069Voucher customer-share balance reminder eligibility. Legacy FCM sends a voucher customer-share balance reminder two days beforeSERVICE_START_DT, selecting unpaid본인부담 잔금payment rows, excluding cancelled reservations, and pushing a hardcoded proceeding-detail route plusPAY_VOUCHER_BALANCEnotification. This is distinct from SFC-063 service balance reminder, which uses end-date minus one day andDEPOSIT_SERVICE_FEE. Evidence:source-refs/sanmopia_web/application/controllers/cli/Fcm.php:133-163andsource-refs/sanmopia_web/application/views/test/pushtest.php:12-13. Dispatch-shape evidence:source-refs/sanmopia_web/application/models/Fcm_model.php:32-56,source-refs/sanmopia_web/application/models/Fcm_model.php:150-159, andsource-refs/sanmopia_web/application/models/Notification_model.php:42-52show the push link and inbox notification can diverge;PAY_VOUCHER_BALANCEis inserted without reservation, payment-row, or instruction identity. Target:pricing_settlement / CustomerShareBalanceInstruction,customer_engagement / CustomerShareBalanceReminderPolicy, andreservation_operations / CustomerReservationLifecycleSnapshot. Status:Pending; backend must own due-date policy, payment-purpose classification, reservation eligibility, idempotent dispatch key, recipient snapshot, customer-facing destination, and suppression when lifecycle or payment state changes. Frontend or cron jobs must not infer this reminder from raw payment type labels, source status ids, orDATE_ADD(CURDATE(), INTERVAL 2 DAY)comparisons. Backend slice needsIssueCustomerShareBalanceRemindercommand,CustomerShareBalanceReminderEligibilityProjectionquery/read model, andCustomerShareBalanceReminderDispatchStorepersistence keyed by reservation, customer-share obligation, payment-row evidence, due-date policy version, and dispatch attempt. Legacy PHP CLI, not modern UI, performed the due-date and unpaid-row decision; the legacy test page atsource-refs/sanmopia_web/application/views/test/pushtest.php:12-13only triggered the cron path manually. Suggested backend feature:CustomerShareBalanceReminderPolicy. -
SFC-20260708-CUR-070Caregiver report and service-record obligation dispatch. Legacy manager cron derives caregiver daily-report and service-record obligations by scanningRESERVATION_DETAIL_VW,RESERVATION_DATE_TB, mutable service start/end dates, and hardcoded source statuses0/3/4/5/6/11/12, with stopped status13explicitly excluded in current queries but still present in older repair variants. First, progress, last, and service-record obligations each use different date predicates, and manual repair inserts missing notify rows up to today without sending push attempts. Notify rows use rawREPORT_FIRST,REPORT_PROGRESS,REPORT_LAST, andSERVICEtype codes plus fixed Korean message text. Evidence:source-refs/sanmopia-manager/application/controllers/cli/Fcm.php:24-41,source-refs/sanmopia-manager/application/controllers/cli/Fcm.php:90-104,source-refs/sanmopia-manager/application/controllers/cli/Fcm.php:237-287,source-refs/sanmopia-manager/application/models/Reservation_model.php:559-580,source-refs/sanmopia-manager/application/models/User_model.php:1565-1643,source-refs/sanmopia-manager/application/models/User_model.php:1858-1901,source-refs/sanmopia-manager/application/models/User_model.php:1941-1982,source-refs/sanmopia-manager/application/models/User_model.php:2070-2106,source-refs/sanmopia-manager/application/models/Notify_model.php:263-350,source-refs/sanmopia-manager/application/models/Fcm_model.php:91-124,source-refs/sanmopia-manager/application/controllers/cli/Fcm.php:43-51, andsource-refs/sanmopia-manager/application/models/User_model.php:2184-2202. Target:care_delivery / CaregiverReportObligation,care_delivery / ServiceRecordObligation, andcustomer_engagement / CaregiverObligationDispatchPolicy. Status:Pending; backend must generate obligations from service occurrence and care-team assignment facts, freeze obligation kind, service date, caregiver role, due time, suppression reason, message key, dispatch idempotency key, provider attempt, repair/replay state, and projection invalidation reference. UI and cron must not derive obligations from source status ids, service-date string comparisons, notify type codes, or missing-row scans. Backend slice needsGenerateCaregiverObligationDispatchescommand,CaregiverObligationEligibilityProjectionquery/read model,CaregiverObligationNotificationStore,CaregiverObligationDispatchAttemptLedger, andCaregiverObligationRepairCommand. Legacy manual repair finds missing obligations by joiningMANAGER_NOTIFY_TBon Korean content strings, type codes, and created-date equality, and the legacy push-log path is commented out/unsafe; durable dispatch receipts must be backend persistence, not a cron side effect. No modern frontend should own this decision. Suggested backend feature:CaregiverObligationDispatchPolicy. -
SFC-20260708-CUR-071Caregiver attendance reminder and attendance-open side effect. Legacy manager FCM sends an attendance prompt by selecting today’s rows fromRESERVATION_DATE_TBfor reservation statuses[4, 5, 6], then sends a fixed “press attendance” message. Separately, reading a notify row can create aMANAGER_ATTENDANCE_TBrecord for the primary caregiver and also insert one for the assistant caregiver, using the notifyCREATED_DTdate as attendance evidence. Evidence:source-refs/sanmopia-manager/application/controllers/cli/Fcm.php:185-200,source-refs/sanmopia-manager/application/models/User_model.php:2305-2318,source-refs/sanmopia-manager/application/models/Notify_model.php:380-432,source-refs/sanmopia-manager/application/models/Attendance_model.php:18-89,source-refs/sanmopia-manager/application/controllers/Attendance.php:19-79,source-refs/sanmopia-manager/application/views/home/main.php:59-75,source-refs/sanmopia-manager/application/views/home/main.php:204-220, andsource-refs/sanmopia-manager/static/js/attendance.js:7-30. Target:care_delivery / CaregiverAttendanceObligation,service_calendar / ServiceOccurrenceAttendanceEligibility, andcustomer_engagement / CaregiverAttendanceReminderDispatch. Status:Pending; backend must own occurrence-based attendance eligibility, assignment role expansion, attendance-open decision, reminder idempotency, recipient snapshot, message key, and audit trail. Reading a notification must not be the authority that opens attendance rows, and clients must not infer attendance reminders from raw status ids orRESERVATION_DATE_TBscans. Backend slice needsGetCaregiverAttendanceActionProjectionquery,RecordCaregiverAttendanceCommand,CaregiverAttendanceFactStore, andCustomerAttendanceSafetyNotificationOutboxpersistence. Legacy PHP UI did perform a business decision: the manager home view rendered open/complete attendance buttons fromREAD_FL, attendance-row presence, and a hardcoded 2020-06-01 gate, while browser JavaScript posted rawreservationIdand flipped the button to complete after success. The modern UI must render only a backend-owned attendance action projection. Suggested backend feature:CaregiverAttendanceObligationPolicy. -
SFC-20260708-CUR-072Caregiver daily-report submission completion. Legacy manager report entry checks login, source notify ownership, unreadMANAGER_NOTIFY_TB.READ_FL, and a routetypestring, then chooses question rows by Korean day labels첫째날,진행중, or마지막날. Save writes objective answers toMANAGER_REPORT_TB, essay answers toMANAGER_REPORT_ANSWER_ETC_TB, and marks notify read, which can also trigger attendance side effects throughNotify_model::updateReadNotify(). Evidence:source-refs/sanmopia-manager/application/controllers/Report.php:5-59,source-refs/sanmopia-manager/application/controllers/Report.php:63-106, andsource-refs/sanmopia-manager/application/models/Report_model.php:11-100. Target:care_delivery / DailyCareReportSubmission,care_delivery / CaregiverReportQuestionSetVersion, andcustomer_engagement / CaregiverNotificationReadState. Status:Partial; backend now requires explicit obligation id, service occurrence evidence key, and idempotency key on daily-report submission contracts, rejects legacy notify/read/route spillover fields, and propagates the stable submission code into customer confirmation. Remaining work: persist submission/correction/completion facts, bind notification-read projection effects, and complete question-set runtime lookup. Notification read state is a projection effect, not canonical report submission authority; clients must not infer report kind or completion from route strings, Korean labels, raw notify rows, orREAD_FL. Suggested backend feature:DailyCareReportSubmissionCommand. -
SFC-20260708-CUR-073Caregiver service-record submission and newborn bootstrap. Legacy service-record save validates main or assistant caregiver ownership from a notify id, accepts the service date from the form route, stores health, recovery, respiratory, temperature, feeding, bath, memo, and retroactive payment fields into main or assistant service tables, silently ignores duplicate reservation/date submissions, bootstraps newborn name/weight rows when no baby rows exist, and marks the notification read only for the primary caregiver. Source writes assistant records toMANAGER_SUB_SERVICE_TB, while schedule readers look forSUB_MANAGER_SERVICE_TB/SUB_MANAGER_REPORT_TB. Evidence:source-refs/sanmopia-manager/application/controllers/Service.php:5-54,source-refs/sanmopia-manager/application/controllers/Service.php:58-253,source-refs/sanmopia-manager/application/models/Service_model.php:10-135, andsource-refs/sanmopia-manager/application/models/Reservation_model.php:539-554. Target:care_delivery / CaregiverServiceRecordSubmission,care_delivery / ServiceRecordDuplicateDecision,member_management / NewbornProfileBootstrapFromCareRecord, andcustomer_engagement / CaregiverServiceRecordCompletionProjection. Status:Partial; backend now carries service occurrence evidence through service-record submission and sequence-board contracts, uses occurrence evidence plus caregiver assignment as the duplicate/attendance request key, and rejects legacy view/table/date spillover fields. Remaining work: persist submission facts, bind newborn bootstrap decisions, connect completion/read projections, and attach printable snapshot handoff. UI and PHP controllers must not decide completion from notify read flags, table-name variants, route dates, or reservation/date-only duplicate checks. Suggested backend feature:CaregiverServiceRecordSubmissionCommand. -
SFC-20260708-CUR-074Caregiver schedule and notify action handoff projection. Legacy caregiver schedule and notification views decide available report and service-record actions from raw notify types,READ_FL/SUB_READ_FL, local counts, hardcoded sequential write rules, a hardcoded assistant visibility check against manager id1, and a 90-day post-service PHP date gate. Notify and home screens build/report/{type}/{notifyIndex}or/service/{notifyIndex}URLs, while controller routes require different shapes and schedule view passes an extra service date segment. Evidence:source-refs/sanmopia-manager/application/controllers/Schedule.php:27-77,source-refs/sanmopia-manager/application/views/schedule/schedule_info.php:210-315,source-refs/sanmopia-manager/application/views/notify/notify_main.php:36-57,source-refs/sanmopia-manager/application/views/home/main.php:238-258,source-refs/sanmopia-manager/application/config/routes.php:56-57, andsource-refs/sanmopia-manager/application/models/Reservation_model.php:222-238. Target:care_delivery / CaregiverWorkActionProjection,care_delivery / CaregiverAssignmentAccessWindow, andcustomer_engagement / CaregiverActionHandoffDescriptor. Status:Pending; backend must project action availability, disabled reasons, assignment role, sequence position, service date, report kind, expiry window, submission/read state, and a typed handoff descriptor or command target. Clients must render backend action facts instead of composing routes from notify codes, counting completed rows, applying a local 90-day rule, or special-casing assistant visibility. Suggested backend feature:CaregiverWorkActionProjection. -
SFC-20260708-CUR-075Caregiver attendance check-in command and customer notification. Legacy attendance posts only a reservation id, checks duplicates by caregiver/day, writes attendance, then attempts a mother notification through primary-manager token lookup. The source duplicate check uses onlyMANAGER_ID_FKplusDATE(CREATED_DT), while the home screen checks completion by caregiver, reservation, and date, so one same-day attendance can block another reservation for the same caregiver even though the UI is reservation-scoped. Evidence:source-refs/sanmopia-manager/application/controllers/Attendance.php:19-79,source-refs/sanmopia-manager/application/models/Attendance_model.php:97-105,source-refs/sanmopia-manager/application/models/Attendance_model.php:36-43,source-refs/sanmopia-manager/application/models/User_model.php:2281-2301, andsource-refs/sanmopia-manager/static/js/attendance.js:7-35. Target:care_delivery / CaregiverAttendanceCheckInCommandandcustomer_engagement / AttendanceAcceptedCustomerNotificationPolicy. Status:Partial; backend now records attendance with service occurrence evidence, contract assignment key, and idempotency key instead of caregiver/date-only duplicate authority, and propagates the same keys into the mother safety notice for assistant caregivers. Remaining work: persist attendance outbox attempts, bind recipient consent snapshots, and expose the command through an authenticated application/API contract. -
SFC-20260708-CUR-076Caregiver attendance action projection. Legacy home view decides whether attendance is open, completed, or hidden from a hardcoded date cutoff,READ_FL, notify rows, andRESERVATION_ADD_DATEfallback reads. Evidence:source-refs/sanmopia-manager/application/views/home/main.php:59-80,source-refs/sanmopia-manager/application/views/home/main.php:205-220, andsource-refs/sanmopia-manager/application/models/Attendance_model.php:18-89. Target:care_delivery / CaregiverAttendanceActionProjectionandservice_calendar / AttendanceEligibleOccurrence. Status:Partial; backend now has a typedCaregiverAttendanceActionProjectionwith action state, service occurrence evidence key, command target, and disabled reason codes for pending, completed, missed/excused, and closed-access cases. Remaining work: persist action rows from service-calendar occurrence facts and replace UI-derived button state. Clients must render backend-projected action availability and disabled reasons instead of deriving attendance state from notify/read flags, raw date rows, or local cutoff logic. -
SFC-20260708-CUR-077Caregiver notification recipient projection and actor-scoped inbox access. Legacy unread inbox joins only primaryrt.MANAGER_ID_FK,getByNotifyIndex()reads by notify id alone, and read mutation can trigger attendance side effects. Notify detail/read checks do not bind the actor to the notify row, and UI routes are derived from rawNOTIFY_TYPEplus notify id. Evidence:source-refs/sanmopia-manager/application/controllers/Notify.php:14-24,source-refs/sanmopia-manager/application/models/Notify_model.php:354-376,source-refs/sanmopia-manager/application/models/Notify_model.php:380-452,source-refs/sanmopia-manager/application/views/notify/notify_main.php:36-56,source-refs/sanmopia-manager/application/controllers/Report.php:89-104, andsource-refs/sanmopia-manager/application/controllers/Service.php:238-246. Target:customer_engagement / CaregiverNotificationRecipientProjectionandoperator_access / CaregiverNotificationAccessDecision. Status:Partial; backend now has actor-scopedCaregiverNotificationRecipientProjection, actor-bound read-state command, revision guard, and anotification_read_state_onlyside-effect boundary so read state cannot create attendance. Application contracts reject legacy notify id/read flag spillover. Remaining work: persist inbox rows, bind assignment-aware recipient selection from notification dispatch, expose authenticated read APIs, and connect frontend inbox to typed action targets. -
SFC-20260708-CUR-078Push delivery attempt and recipient consent snapshot. Legacy FCM sender chooses tokens inline, can bypassPUSH_FLby passingpushFlag=null, builds links throughsite_url(), and returns raw provider responses without durable attempt state. Link composition strips and prependssite_url(), while notice CLI branches hardcode route strings by notice type. Evidence:source-refs/sanmopia-manager/application/models/Fcm_model.php:60-69,source-refs/sanmopia-manager/application/models/Fcm_model.php:91-95,source-refs/sanmopia-manager/application/models/Fcm_model.php:113-188,source-refs/sanmopia-manager/application/models/User_model.php:1514-1533,source-refs/sanmopia-manager/application/controllers/cli/Fcm.php:132-182, andsource-refs/sanmopia-manager/application/models/User_model.php:2281-2300. Target:communication_delivery / PushDeliveryAttemptandcustomer_engagement / RecipientPushConsentSnapshot. Status:Partial; backend now hasRecipientPushConsentSnapshot,PushDeliveryAttempt, provider response facts, suppression reasons for disabled consent and missing endpoint, and application contracts that reject raw token/PUSH_FLspillover. Remaining work: persist attempts and endpoint snapshots, bind retry/dead-letter queues, add provider adapter workers, and route typed link targets through an allowlisted handoff catalog. -
SFC-20260708-CUR-079Coupon use status projection and deletion refund command. Legacy admin UI derives coupon status from Korean publish strings,GIFT_USE_FL,PRODUCT_USE_DT, raw reservation status13, and delete/refund buttons call KCP through rawPAYMENT_CONTEXTbefore flippingREFUND_FL/DELETE_FL. Evidence:source-refs/sanmopia-admin/application/models/Coupon_model.php:513-521,source-refs/sanmopia-admin/application/models/Coupon_model.php:590-690,source-refs/sanmopia-admin/static/js/promotion/coupon_use_history.js:220-306,source-refs/sanmopia-admin/static/js/promotion/coupon_use_history.js:327-367,source-refs/sanmopia-admin/application/models/Coupon_model.php:164-208,source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31-60, andsource-refs/sanmopia-admin/application/controllers/Api.php:11-29. Target:promotion_entitlement / CouponUseStatusProjectionandpricing_settlement / CouponDeletionRefundCommand. Status:Partial; backend now has semantic coupon publication/consumption states,CouponUseStatusProjection, stopped-reservation status reason, provider-neutralCouponDeletionRefundPlan, payment-ledger reference, revision guards, idempotency key, and application contracts rejecting raw Korean status,GIFT_USE_FL,PRODUCT_USE_DT,RESERVATION_STATUS_LIST_ID_FK,PAYMENT_CONTEXT,REFUND_FL, andDELETE_FL.2026-07-08backend bridge:CouponDeletionPaymentRefundHandoffPayloadnow converts the coupon deletion refund plan into the sharedPaymentRefundIntentPayloadwith partial refund scope, admin requester, payment expected revision, adjustment catalog version, refund amount, cancellation gate, and source evidence keys. The same change promoted genericPaymentRefundIntentPayloadso future refund flows do not copy one-off intent DTOs. Remaining work: persist projection/handoff rows, execute the Kill Bill refund adapter, consume provider terminal events before coupon delete projection, enforce operator permission, and expose admin UX from backend status labels instead of DataTables JavaScript composition. Additional failure-path evidence: legacydeleteCoupon()decodes couponPAYMENT_CONTEXT, calls KCP refund, writesREFUND_FL = 1before inspecting the returned provider status, and returns a truthy non-empty result array with the coupon delete update. The modern command must gate refund/delete projection on persisted provider terminal success or an explicit repair case. Evidence:source-refs/sanmopia-admin/application/models/Coupon_model.php:169-186andsource-refs/sanmopia-admin/application/libraries/Kcppayment.php:31-60. -
SFC-20260708-CUR-080Product-gift coupon redemption and fulfillment command. Legacy customer shop UI uses a hidden product-coupon id and-1sentinel for “no usable coupon”, posts raw product/coupon/recipient/address fields, then PHP checks ownership,PUBLISH_DT, andUSE_FLbefore inserting aPRODUCT_APPLY_TBrow and flippingUSER_COUPON_TB.USE_FL. The duplicate product-application check byPRODUCT_APPLY_TB.USER_COUPON_ID_FKexists only in commented code, so fulfillment idempotency and duplicate prevention are not durable backend invariants. Evidence:source-refs/sanmopia_web/application/views/shop/gift_order.php:35-48,source-refs/sanmopia_web/static/js/shop_product.js:24-60,source-refs/sanmopia_web/static/js/shop_product.js:164-170,source-refs/sanmopia_web/application/controllers/Shop.php:123-148,source-refs/sanmopia_web/application/controllers/api/Shop.php:72-100,source-refs/sanmopia_web/application/models/Coupon_model.php:219-276, andsource-refs/sanmopia_web/application/models/Product_model.php:40-79. Target:promotion_entitlement / ProductGiftRedemptionCommand,promotion_entitlement / ProductGiftFulfillmentRequest, andcommunication_delivery / ProductGiftFulfillmentDispatchRequest. Status:Partially implemented; backend now hasProductGiftRedemptionCommand,RedeemProductGiftHandler, typedProductGiftRedemptionDecision, and Pydantic contract rejection forUSER_COUPON_ID_FK,PRODUCT_ID,PRODUCT1/PRODUCT2,USE_FL,PUBLISH_DT, and-1-sentinel legacy coupon authority. The command delegates toGiftFulfillmentPolicy, enforces owner and entitlement revision checks, rejects product/entitlement mismatch, prevents duplicate fulfillment per entitlement, and replays the same idempotency key without writing a second request. 2026-07-08 follow-up: Supabase persistence now storessanmopia_product_gift_redemption_decisionsas the durable command audit, extends fulfillment requests with idempotency/product/recipient/address facts, updates redeemed entitlements by expected revision, and protects the new decision table with owner-or-HQ RLS plus service-role write grants. Remaining proof: customer product-gift projection API, communication dispatch request, cancellation and repair audit, and frontend wiring that renders backend-projected usable product coupons instead of posting source coupon ids as authority. -
SFC-20260708-CUR-081Product-gift coupon publication grant and dispatch workload. Legacy publication is separate from product-gift redemption: a CLI route scans product coupons, ignores their storedPUBLISH_DT, derives publication from service-start day15, excludes raw reservation status ids, insertsUSER_COUPON_TBwith a six-month expiry when no user coupon exists, then a second CLI sends push/Kakao/inbox notices by reading yesterday-created coupon rows. Evidence:source-refs/sanmopia_web/application/controllers/cli/Reservation.php:302-360,source-refs/sanmopia_web/application/controllers/cli/Reservation.php:398-441, andsource-refs/sanmopia_web/application/models/Coupon_model.php:608-620. Target:promotion_entitlement / ProductGiftCouponPublicationGrant,promotion_entitlement / ProductGiftCouponPublicationProjection, andcommunication_delivery / ProductGiftCouponPublicationDispatchAttempt. Status:Pending; backend must own publication eligibility from frozen service-calendar and entitlement policy facts, status/suspension exclusions, publication/grant idempotency, expiry policy, dispatch recipient snapshot, provider attempt ledger, retry/dead-letter/repair, and customer-visible grant state. UI and cron workers must not infer publication from service-start date, raw source status ids, yesterday-created coupon rows,PRODUCT1/PRODUCT2,USE_FL, or unversioned Kakao template constants. -
SFC-20260708-CUR-082Customer reservation creation command and draft-step authority. Legacy reservation creation spreads booking authority across PHP controllers, model defaults, view hidden fields, and browser JavaScript. Step 1 blocks new bookings from raw status ids, then creates a draft from branch/address lookup and a consultation flag. The model deletes the prior예약작성중row for the same customer, seedsRESERVATION_STATUS_LIST_ID_FK,PROCESS_NO,CONSULTING_FL,PAYMENT_VERSION, price-version id, and 90-day rebook flag. Later steps gate pre-reservation versus full booking by delivery/service-date arithmetic and temporary price-table comments, hide service types by branch id/name through a hardcoded deny list, expose dormant price-table shutdown flags such as pre-reservation-only and in-home exclusion, uplift selected service detail when a named caregiver is chosen, mutate price version from service date/session state, delete service/add-option rows when service type changes, accept browser-filled service end date and add-day arrays, and return asmart_matchingroute flag. The final review hides selected manager and coupon ids in form fields, displays pre-reservation credit, and the apply API chooses 상담/연장요청/payment handoff fromCONSULTING_FL, deletes/reinserts posted coupons, and writes voucher service-balance left price for 입주/스페셜 from the current price table. Evidence:source-refs/sanmopia_web/application/controllers/api/Service.php:24-60,source-refs/sanmopia_web/application/models/Reservation_model.php:320-362,source-refs/sanmopia_web/application/controllers/Service.php:196-231,source-refs/sanmopia_web/application/controllers/Service.php:234-263,source-refs/sanmopia_web/application/controllers/api/Service.php:146-190,source-refs/sanmopia_web/application/controllers/api/Service.php:220-266,source-refs/sanmopia_web/application/controllers/api/Service.php:302-304,source-refs/sanmopia_web/application/controllers/api/Service.php:411-454,source-refs/sanmopia_web/application/controllers/api/Service.php:540-568,source-refs/sanmopia_web/application/controllers/api/Service.php:705-759,source-refs/sanmopia_web/application/controllers/api/Service.php:792-856,source-refs/sanmopia_web/application/views/service/step3_voucher.php:663-708,source-refs/sanmopia_web/application/views/service/step3_normal.php:545-604,source-refs/sanmopia_web/static/js/step3.js:198-360,source-refs/sanmopia_web/static/js/step3.js:766-832,source-refs/sanmopia_web/static/js/step3.js:890-902,source-refs/sanmopia_web/application/views/service/reservation_check_data.php:211-218,source-refs/sanmopia_web/application/views/service/reservation_check_data.php:305-347,source-refs/sanmopia_web/static/js/reservation_check_data.js:1-47,source-refs/sanmopia_web/application/views/service/reservation_payment.php:138-145, andsource-refs/sanmopia_web/application/views/service/pre_reservation_payment.php:123-142. Target:reservation_operations / CustomerReservationCreationCommand,ReservationDraftStepAuthorityProjection,ReservationDraftSupersessionPolicy, andReservationCreationPaymentHandoff;reservation_catalog / ReservationServiceOfferingAvailabilityPolicy;pricing_settlement / ReservationCreationChargeSnapshotHandoff; andcaregiver_assignment / CaregiverRecommendationSelectionIntent. Actors: mother/customer applicant, family sponsor or delegated payer, branch operator, HQ operator, caregiver assignment reviewer, payment provider. Status:Partially implemented; backend must own draft replacement, step availability, back/forward recovery, source-status transition plan, consultation and extension routing, effective-dated branch/service offering eligibility, temporary service-offering shutdown windows, price catalog version selection, service-term/end-date/add-day validation, caregiver selection intent, coupon/pre-reservation-credit application, and payment-instruction handoff with expected revisions and idempotency. Frontend may stage field input and render backend facts only; it must not submit hidden end dates, raw manager/coupon ids, localdata-pricetotals,PROCESS_NO,CONSULTING_FL, service availability flags, branch-name deny lists, or Korean source status strings as authority. Test gap: reject unsupported service offering by branch id/name alias, prove service-type changes supersede quote/add-option/rental facts, and cover temporary pre-reservation-only or in-home-excluded catalog windows. This is distinct fromSFC-20260708-CUR-080andSFC-20260708-CUR-081, which cover product-gift entitlement redemption/publication rather than reservation creation.2026-07-13 backend authority hardening: backend
be107c7adds a forward-only migration that revokes everyauthenticatedtable privilege onsanmopia_reservation_bookingsandsanmopia_reservation_booking_workflow_requests, drops the mother/branch create, update, and participant-read policies, and leaves CRUD toservice_role. Cross-repository audit found no frontend Data API consumer for either table and no client consumer for raw workflowcommand_payload; typed backend progress/read contracts remain the supported surface. Focused access checks and 127 booking/API/runtime/main regressions pass. This closes the raw browser table-authority path only. The draft, step-option, final-review, confirmation, persistence, and canonical browser evidence named above remain required before this checklist item can be checked.2026-07-13 contract and code foundation: contract
76b779bdefines five authenticated draft routes and 26 revisioned server catalogs, including new-versus-extension source selection, three separate voucher axes, corrected reservation-wide pet separation, and standalone applicant, address, coverage, schedule, matching, quote, payment, and contract final-review evidence. JSON Schema, TypeScript, and Python validators share positive and negative fixtures; 419 Jest and 23 Python contract tests pass. Backend4fce929,9cf8718, and corrected-contract follow-upe78a3bfadds the layer-first domain/application/in-memory foundation with exact replay, CAS, supersession, all 26 catalog bindings, applicant/voucher/pet/final-review invariants, downstream invalidation, and an atomic confirmation/outbox port. Frontend4288924plus corrected-contract follow-up421fc03binds the single chat to server draft create/read/patch/review/confirm, new/extension and voucher/pet inputs, authenticated progress, edit invalidation, conflict recovery, focus, and automatic scroll. These are partial code artifacts, not production proof. Backend21ecac5adds the backend-only six-table Supabase schema and service-role-only create, patch, final-review, confirm, and outbox RPCs with exact replay snapshots and CAS. Backend0d78806closes legacy applicant and care-environment partial-shape bypasses;ae98940adds the concrete Supabase repository plus atomic confirmation/outbox adapter with exact snapshot mapping and typed fail-closed RPC errors. The full feature slice passes 91 tests plus Ruff, Tach, and Vulture confidence-100 gates. Frontend harnessb460d84records desktop and mobile 12-frame animated WebPs plus edit invalidation,409refresh, and server-validation branches. Its manifest is provisional and uses stateful local API mocks, so full-history PostgreSQL replay, populated cross-context authority projections, authenticated integrated stage proof, and the proposed ADR-032 legal acceptance gap remain open.2026-07-14 production authority bridge: backend
558510dreplaces the two unavailable production placeholders with layer-first, consumer-owned Supabase adapters. The catalog adapter rejects anything except the exact 26-key set and a matching fingerprint over its internal canonical snapshot order; that order is not a client-visible contract invariant. The final-review adapter loads one actor/draft/revision-scoped materialized projection, requires the exact 13 contract sections, verifies the requested review identity before confirmation, and keeps GET read-only. Two service-role-only projection tables and two read RPCs enforce effective/materialized/expiry windows and do not fall back from a draft scope to a global snapshot. Local, non-canonical verification reported 147 focused test passes, 13 architecture passes, zero Tach MCP exact/external diagnostics, zero Vulture MCP confidence-100 candidates, and successful use of both RPCs after applying the migration to an isolated temporary PostgreSQL database. No immutable run artifact was captured. This remains partial: no owning-context materializer yet publishes the required production rows, the smoke was not a clean replay of the complete migration history, and payable confirmation deliberately returns unavailable until ADR-020 obligation and payment handoff creation are atomic with acceptance/outbox persistence.2026-07-14 first source contribution: backend
1200f42adds an exact 26-binding registry and an immutable, service-role-only contribution inbox, but registers onlyservice_offering.offerings -> reservation_operations.service_offering_availability. Its source command carries real catalog title/version evidence, rejects mixed policy revisions, and crosses the feature boundary only through the consumer-owned contribution DTO/port. The append RPC verifies producer, owner, draft revision, current window, fingerprint, and exact replay. Public decision-set input is deliberately not wired as publication authority. This is 1/26 source evidence, not a materialized production snapshot: trusted draft/branch/pricing/birth orchestration, the remaining 25 producers, atomic exact-26 materialization, and final-review materializers remain open, so the checklist status staysPartially implemented.2026-07-14 catalog materializer prerequisites: backend
83ac5b8fixes a lossy boundary before any exact-26 materializer is allowed. The contribution adapter, expanded RPC, and immutable table now preserve catalogauthority_referenceand positiveauthority_revision; the two revision-required catalog bindings reject missing authority, and all other bindings reject forged authority. Contribution writers share one owner/draft/revision advisory lock. Directservice_roleinsert/update/delete on materialized catalog and selection-authority tables is revoked and the access-control SSOT now declares select-only access. The prior 11-argument RPC remains an invoker wrapper for database-first compatibility and can publish only catalogs that do not require authority facts. Isolated PostgreSQL proof preserved the original non-revision contribution id/fingerprint across old and new overloads, persisted revision authority, rejected missing authority, reapplied the migration, verified effective ACLs, and removed the temporary database. This closes prerequisites only. Trusted orchestration, 25 producers, Python exact-26 semantic validation, same-set SQL CAS, persisted contribution lineage, stale-snapshot freshness rejection, and canonical stage evidence are still required.2026-07-14 voucher service-day producer boundary: backend
2c744fbadds an immutable normalizedVoucherPlanCatalogRevisionSnapshotauthority, exact revision source/publisher ports, Supabase adapters, producer registration, and named reservation orchestration forservice_schedule.voucher_service_days. Legacy order comes only from the slash-delimitedSERVICE_DAY_LISTtoken positions; SQL encounter order and workbookrow_numberare never substituted. One option is deliberately normalized tostandard; two and three options preserve positional shortened/standard/extended meaning. Publication requires a published, zero-issue, complete price batch and an exact option/price-line/entry-code bijection. The parser also restores secondary caregiver net pay. Focused tests report 35 passes; Ruff, Tach, Vulture, and isolated real PostgreSQL publish/replay/conflict/order/ACL/reapply checks pass. The affected run reports 1,736 passes with the same three access-control failures reproduced at parent83ac5b8. No trusted trigger/population, exact-26 materializer, stage mutation, or browser artifact exists, so the item remainsPartially implementedand 24 catalog producers remain.2026-07-14 completed source and atomic population authority: backend
c1937ed198005ce2307dfefc4e77d882aa98abc0adds immutable completed source revisions plus ordered slices, a full published voucher price-batch reader, one domain population command, an atomic Supabase population RPC, and a committed-population exact selector. Mapping is explicit:service_type_detail_code -> service_tier_code,baby_type_code -> child_group,delivery_count_code -> delivery_order, explicitbenefit_band_code -> benefit_band, and each day token ->service_day_count; noconsume_type_prefix inference is permitted. One transaction verifies full source/price-entry coverage, component roles and bases, publishes every derived revision, records one deterministic population receipt, and links all readable revisions to that population. The selector accepts canonical axes plus quote date and returns exactly one committed revision; it accepts no catalog revision, import batch, price version, or consume-type revision key from the caller and has nolatestfallback. The revision reader also uses its own publication timestamp rather than the source price-batch publication time. Colocated domain, application, adapter, access, and migration tests plus the isolated PostgreSQL smoke script cover replay, conflict, rollback, incomplete-population invisibility, exact selection, and privilege boundaries. Atc1937ed, a trusted caller still had to complete an explicitly approved source/version and the reservation draft prepare trigger was absent. The remaining 24 catalog producers, exact-26 materializer/current-set freshness gate, stage mutation, and browser evidence remain open, so the item staysPartially implemented.Backend
b44fd49e9f3082d4affa005ecfa76128136f0804removes caller-owned revision, batch, and version selection from the voucher-day reservation bridge. The bridge accepts canonical axes and quote date, resolves an exact committed selection through the Pricing Settlement decision port, and rejects decision drift before revision read. Focused tests, Tach affected tests, Ruff, Tach exact/external, and Vulture confidence-100 pass. No draft trigger was added: without canonical draft-axis resolution, the remaining producers, and an exact-26 same-set materializer, post-PATCH publication would leave the next catalog snapshot unavailable. Stage and browser evidence remain open.Backend
7a9d26e1c1c53b928e14504cfd37152294f9a31fadds the protected HQ approved-source completion caller. Active bearer actor and SpiceDBmanageonhq_settlement:price_catalog_managementare mandatory; actor, approval time, and manifest injection fail closed. PostgreSQL owns the first approval stamp and replay, derives canonical SHA-256 from frozen header+slices+batch/workbook+ normalized entries, and requires exact workbook/catalog/version/entry equality. Unapproved completion/publication service-role execution is revoked. Existing unapproved populations are preserved but quarantined from resolve/publication; immutability, insert, and deferred linkage guards prevent drift. Focused verification is 106 passed with one warning; fresh and populated-old-schema PostgreSQL smokes pass; 13 relation-aware PL/pgSQL checks, Tach all/exact/external, and Vulture confidence-100 report zero. Tach affected is 1,880 passed with the same three unrelated baseline failures and 3,359 deselected. No source was actually selected/approved/invoked,154 / 0was not auto-selected, and no stage/browser/visual evidence was produced. The item remainsPartially implementedwith canonical resolver, draft trigger, 24 producers, exact-26/final-review materialization, payable, and A-Z gaps.2026-07-15 exact-26 materializer evidence: backend
20a79e30e36c6693002c65f8211275afbe149310addsMaterializeCustomerReservationStepOptionCatalogSnapshotHandler, the strictSupabaseCustomerReservationStepCatalogContributionSetSourceandSupabaseCustomerReservationStepCatalogSnapshotMaterializer, and production runtime composition. Migration20260715090000_customer_reservation_step_catalog_exact_set_materializer.sqladds the current-set read RPC and 11-argument expected-lineage/payload/window/ fingerprint CAS RPC, persists the exact ordered 26-row lineage, verifies idempotent replay, and changes the loader to return only a snapshot whose frozen contribution-set fingerprint and lineage still equal the current set. Application validation rejects 25 rows, duplicate ids/sequences, scope or current-window drift, conflicting source revisions, incomplete selection authority, and inconsistent persistence receipts. Focused application, adapter, and runtime verification reports193 passed; a narrower integrated materializer run reports38 passed, with Ruff andgit diff --checkpassing. Migration/SSOT contracts report14 passed. The rollback-scoped isolated Supabase PostgreSQL 17 smoke proves exact-25 atomic failure, exact-26 persistence and replay, stale CAS40001, lineageless and invalid/expired latest-row rejection, canonical hashes, RLS, and RPC-only ACL. The item remainsPartially implemented: no trusted canonical draft prepare or PATCH trigger invokes the handler, 24 producer boundaries and a complete current contribution set are absent, no real source/version was selected and approved for population, and final-review, payable, clean-replay, stage, browser-success, and A-Z proof remain open. This was backend-only; no screenshot or WebP was created or reused.2026-07-15 catalog-preparation authority staging: backend
863158c743e2bc48e3db1dbb1a1f9d65edb0892dadds a layer-first application authority DTO/port, service-role Supabase loader, dormant named preparation orchestration, and migration20260715100000_customer_reservation_catalog_prepare_authority.sql. The table and record/load RPCs accept exactly 17 preparation axes, own canonical payload and projection hashes, monotonic revision, replay, at-most-15-minute validity, newest-row no-fallback, RLS, and SELECT-only service-role table access. Python independently rechecks payload hash, projection id, scope, and current window. Service-offering rows now resolve duplicate applicable scopes as combined branch-and-region, branch, region, then global, with newest effective date and stable key ordering. The dormant handler preserves the preparation lineage in the two registered producer contributions before the existing exact-26 gate. Focused tests report65 passed; Tach affected reports1,932 passed, the same three unrelated baseline failures, and3,405 deselected; Ruff, Tach all/exact/external, Vulture confidence-100, and diff checks report zero. A disposable PostgreSQL run pinned migration SHA273c753dd2fa5f4c08a14bc2a2f65c7ed44832f25d256729c5123aa0fd4ba900, passed apply/reapply, replay1 -> 1, expiry renewal to revision2, six fail-closed cases, ACL checks, and zero PGMQ/queue/trigger objects, then removed the database with zero residual matches. The item staysPartially implemented: no source-owned resolver/recording caller derives the 17 axes, 24 producer boundaries and short-window refresh are absent, and HTTP/PATCH/queue/trigger/worker activation is intentionally zero. No deploy, browser, screenshot, or WebP was produced.2026-07-15 source-lineage binding: backend cleanup
406d56565eae8ff51a7ec354a1c68aadb11db90caligns the current-authority smoke and backend59d29eb79359018f116c0be941c6d1a288e44e5cadds draft-owned preparation derivation, five consumer-owned source contracts, a record handler, and the Supabase v2 recorder/loader. The five exact lineage keys arebranch_coverage,reservation_state,service_offering_policy,price_catalog_version, andvoucher_plan_criteria; every entry freezes owner, source reference, revision, SHA-256, and validity window. Migration20260715110000_customer_reservation_catalog_prepare_authority_v2.sql, SHA-256a980b468843ebd07d58b3952d122748d82e77dcfca9277eae210344452aa7d92, fingerprints the 17-axis compatibility payload together with lineage, uses database statement time, verifies the Asia/Seoul business date, and caps expiry by draft, 15-minute, source-window, and next-Seoul-midnight bounds. The loader accepts no caller clock and never falls back past an invalid newest row. Current pre-reservation versus historical conversion, draft extension request versus server-linked continuation, inclusive 40-day counting, actual baby count versus voucher baby classification, and source price-version identity now have distinct typed meanings. Offering contribution publication requires the exact preparation-authority catalog lineage; public availability routes remain preview-only. Focused verification reports109 passed; the full suite reports5,427 passedand one historical security-validator failure. Ruff onsrc, Tach exact, Vulture confidence-100, and the earlier disposable PostgreSQL 17 v1-to-v2 smoke pass. The item remainsPartially implemented: concrete source adapters are0/5, record-handler runtime wiring is0, runtime E2E axes are0/17, and activation surfaces are0. Booking still accepts a caller-provided decision and must rehydrate the server projection; 24 producers, refresh, deploy, stage, browser, screenshot, and WebP proof are absent.2026-07-20 integrated technical replay supersedes those historical browser/screenshot absences for the current P04 technical boundary. Backend
c6eb6f2c467c4ca1d3fd1855d2abc11b74e4416b, contract132e1a4e1077770247a17397efffceeb0699c045, and frontendffacc93939528f0e21d098d8fdf41bef3f978f07pass Supabase CLI migration321/321, actual owner desktop/mobile single-chat input, edit/reprojection,422/409/403/401, canonical PNG private upload, signature READY-to-CONSUMED, atomic confirmation, exact replay, durable evidence/consumption/command cardinality1/1/1, redaction-reviewed PNG/WebP, and disposable runtime cleanup. Evidence:apps/docs/public/evidence/mother-family-conversational-booking/p04-live-signature-c6eb6f2c-ffacc939/manifest.json. The item remainsPartially implementedand unchecked: contract publisher, approval, wording, signature duty, and retention are explicit synthetic test-owned values; actual legal approval, production source completeness, clean four-repository canonical pins, deployment, and the remaining retained PHP source-parity decisions are not closed.completionClaimremainsfalse. -
SFC-20260708-CUR-083Branch topology fixture and settlement hierarchy data-quality gate. Browser reservation smoke submitted a modern booking workflow payload withbranchContext.branchName = "테스트 지점"andbranchContext.headquartersId = null; backend correctly rejected it with409and비본사 지점은 소속 본사를 가져야 합니다.Evidence:frontend-repo/output/playwright/reservation-scenario-20260708-full-stack/events.json:342-354andfrontend-repo/output/playwright/reservation-scenario-20260708-full-stack/events.json:362. Legacy source evidence shows branch hierarchy semantics were implicit in display names and hardcoded ids:본사is sorted specially, Danbee branch settlement excludes branch ids36and37, and settlement branch filters reuse those source ids without a durable affiliated-headquarters relationship. Evidence:source-refs/sanmopia-admin/application/models/Branch_model.php:84-114,source-refs/sanmopia-admin/application/models/Payment_model.php:94-115, andsource-refs/sanmopia-admin/application/controllers/Calculate.php:108-123. Target:branch_operations / BranchTopologySnapshot,branch_operations / BranchHierarchyFixtureValidation,migration_governance / ReservationScenarioFixtureDataQualityGate, andpricing_settlement / BranchHeadquartersSettlementTopologyInvariant. Actors: branch operator, HQ settlement operator, migration fixture author, reservation workflow runner. Status:Pending; scenario fixtures, migration seed data, and booking operational context must distinguish headquarters branches from affiliated branches before booking, branch settlement, HQ settlement, inter-office settlement, or settlement data-room flows run. For legacy fixture compatibility,headquartersIdmay be null/self only for HQ-named/HQ-role branches; affiliated branches must carry a valid headquarters id. Durable model should prefer explicit branch kind plus headquarters reference instead of allowing UI fixtures to infer hierarchy from display name. Frontend smoke data should fail fast with a fixture/data-quality message instead of masking a correct backend domain rejection as generic reservation failure. -
SFC-20260708-CUR-084Caregiver eligibility context completeness for reservation assignment. After correcting branch topology, browser reservation smoke accepted the booking workflow start but the workflow read failed withfailureReason = "승인된 자격증 개수가 부족합니다."because the submitted operational context carriedcaregiverProfiles[].licenseTitles = []. Evidence:frontend-repo/output/playwright/reservation-scenario-20260708-full-stack-valid-branch/events.json:345andfrontend-repo/output/playwright/reservation-scenario-20260708-full-stack-valid-branch/events.json:354-369. Legacy source evidence shows qualification approval is mutable operator state: manager profile JavaScript toggles승인전/승인완료text intoadmission_careerandadmission_educationwrites, controller routes those strings through a generic manager update endpoint, and model methods setADMISSION_FLon career and education detail rows. Evidence:source-refs/sanmopia-admin/static/js/manager/manager_detail.js:771-845,source-refs/sanmopia-admin/application/controllers/Manager.php:1013-1020,source-refs/sanmopia-admin/application/controllers/Manager.php:1374-1435, andsource-refs/sanmopia-admin/application/models/Manager_model.php:2244-2278. Target:caregiver_assignment / CaregiverEligibilityContextSnapshot,caregiver_assignment / CaregiverQualificationFactsProjection,caregiver_assignment / ReservationAssignmentEligibilityGate, andmigration_governance / ReservationScenarioFixtureDataQualityGate. Actors: caregiver, branch/HQ caregiver-profile reviewer, reservation booking workflow, caregiver assignment service. Status:Pending; booking context must carry normalized caregiver qualification/profile facts required by matching and assignment, not only a candidate id, branch caregiver id, or selected caregiver id. Backend contracts should expose active eligibility facts such as approved qualifications, service-area coverage, unavailable windows, pet compatibility, grade/rating facts, and their freshness/revision so reservation workflow can validate assignment deterministically. Smoke fixtures should fail with caregiver eligibility context incompleteness before workflow execution, not surface a late generic reservation failure. -
SFC-20260708-CUR-085Browser-to-backend reservation scenario smoke loop. The first runnable modern reservation scenario is now smoke-proofed through a local backend app and the Astro booking page. Evidence:frontend-repo/output/playwright/reservation-scenario-20260708-full-stack-qualified/events.json,frontend-repo/output/playwright/reservation-scenario-20260708-full-stack-qualified/01-initial.png,frontend-repo/output/playwright/reservation-scenario-20260708-full-stack-qualified/03-ready-to-submit.png, andfrontend-repo/output/playwright/reservation-scenario-20260708-full-stack-qualified/04-after-submit.png. Target:reservation_orchestration / ReservationBookingWorkflowSmokeRuntime,pricing_settlement / MotherVisibleChargeSummaryReadModel, andmigration_governance / ReservationScenarioSmokeLoop. Status:Backend smoke-proofed; backend now has a dev-only smoke FastAPI app backed by in-memory runtime composition that executes the reservation booking workflow inline, persists workflow-start/progress snapshots, and exposes the frozen mother-visible charge summary by reservation booking id. The browser run postedPOST /reservation-booking-workflow-starts, read completed workflow progress fromGET /reservation-booking-workflow-requests/{bookingRequestId}, and rendered the backend-owned approved amount989,881원fromGET /reservation-financial-lifecycles/{reservationBookingId}/mother-visible-charge-summary. 2026-07-08 follow-up removed the frontend hardcodedcarddefault sopaymentMethodOptions[0].valuebecomes the authoritative initial payment method, and the smoke backend now allows local Astro ports4300-4399plus explicitSANMOPIA_RESERVATION_SMOKE_CORS_ORIGINSorigins for repeatable Playwright runs. Repeat proof artifact:frontend-repo/output/playwright/reservation-scenario-20260708-cors-repeat/events.json; it used Astro4327, kept hiddenpaymentMethod = family_bank, completed browser POST, and avoided both CORS failure and the old context-mismatch message. 2026-07-08 stage proof against the self-hosted Supabase/ReState stack completedpnpm supabase:seed:mother-booking-contextandpnpm smoke:mother-booking-workflow, producing reservation booking requeststage-booking-1783494010282, workflow statuscompleted, reservation id4b4c621d-42c6-4c98-88fd-0907c7c2754c, and invocation idinv_1keAjpRWfgmc67TkTaaIcHgKWAmLPWz2mM. The real browser submit then exposed two stage blockers: real backend composition lacked CORS forhttp://app.sanmopia.localhost:24055tohttp://api.sanmopia.localhost:24055, and after CORS was added the browser POST reached202but client-side progress polling hit401because the frontend adapter did not forward the existing Supabase access token. Backend follow-up addsSANMOPIA_CORS_ALLOW_ORIGINSwith stage SSOTSANMOPIA_BACKEND_CORS_ALLOW_ORIGINS. Frontend follow-up reads the existing Supabase access-token cookie throughsrc/lib/supabase/browser-access-token.tsfor booking submit, progress refresh, and payment pre-registration calls. The rerun artifactfrontend-repo/output/playwright/stage-submit-token-20260708161429-booking-desktop-submit-attempt.pngreachedPOST /reservation-booking-workflow-starts202,GET /reservation-booking-workflow-requests/RBQ-1e6ce816-7720-4d5a-85d0-581eb52663a5200, andGET /reservation-financial-lifecycles/5e06188f-c7af-4023-8eee-55e8e615afed/mother-visible-charge-summary200. 2026-07-08 payment-pre-registration proof found the next live blocker:POST /reservation-payment-pre-registrationsreturned503withreservation payment clock is not configuredbecause the production app composition did not passclockintoReservationPaymentApi. Backend fix wires the same app-factory clock and adds an assembly regression test. The rerun artifactfrontend-repo/output/playwright/stage-payment-pre-reg-20260708163501-booking-desktop-payment-pre-registered.pngreached booking requestRBQ-95336158-2664-4ae1-94b4-4256756afb4c, reservation idb51d0832-ca7d-4d82-809f-17f4dcbdca38, charge summary200, and payment pre-registration201 pre_registered. 2026-07-08 paid-payment workflow proof startedRPW-STAGE-20260708163933from frozen paymentPAY-STAGE-20260708163454. The first run stayedrunningbecause stage migration history had20260630114852marked applied whilesanmopia_caregiver_payout_acknowledgementswas absent from PostgREST, and pending pgmq migration used a queue name longer than Supabase pgmq’s 48-character limit. Backend repair shortens the centralized queue name tosanmopia_booking_term_invalidation_exec, adds a queue-name length guard, and adds an idempotent acknowledgement-table repair migration with explicit service-role grants, RLS, realtime publication, and participant read policy. Afterpnpm supabase:db:push:stage, the same workflow completed withgatewayCode = PAYMENT_GATEWAY_DEBUG_PAYMENT_VERIFIED,approvedChargeFinalizationStatus = already_finalized, andsettlementContinuationStatus = waiting_for_financial_factswith reasonservice delivery completion is not recorded. Follow-up proof continued reservation90ac43cf-146c-44de-adf6-ebce7e4042cd: service delivery completion was recorded, service-delivery replay workflowsettlement-continuation:RPW-STAGE-20260708163933:service-replay-20260708170535completed after the backend made matching service-delivery command replay idempotent, and the same reservation advanced through caregiver payout950000, Branch settlement1681519, HQ settlement90000, and finalsettled. Runtime blocker fixed during the proof: the customer service-balance instruction projection adapter now uses physical tablesanmopia_customer_service_balance_instruction_projections; the previous long table name exceeded PostgreSQL identifier length and was truncated in stage DB, causing PostgREST schema-cache misses. 2026-07-08 backend follow-up automated the post-service-delivery continuation recheck:supabase:smoke:stage:payment-continuation-after-service-deliverynow starts from booking/payment, observes the payment workflow waiting on missing service delivery, records service delivery, prepares caregiver payout, branch settlement, and HQ settlement lines, then verifies the same workflow row starts settlement continuation. The smoke now bootstraps real Supabase Auth users for branch and HQ actors, seeds SpiceDB branch/HQ relationships, waits for permission convergence, and submits service-occurrence/finalized-charge closeout references so the run exercises the same backend guards as runtime. 2026-07-09 proof moved the loop from backend-only smoke to a browser-started stage reservation plus real financial lifecycle commands. Playwright artifactfrontend-repo/output/playwright/reservation-card-flow-20260709-backend-e2e-script/desktop-summary.jsonsubmitted reservation75f98a31-0949-4ad6-a7f0-3a3935fd0c2b, showedcompleted · 결제 진행 완료, and rendered customer payable1,681,519원. Backend driverbackend-repo/scripts/stage_reservation_settlement_e2e.pythen seeded the SpiceDB branch/HQ actor relationships, generated the service-balance closeout reference from Supabase, and advanced the same reservation throughservice_delivered,caregiver_payout_ready,branch_settlement_ready,hq_settlement_ready, and finalsettledwith caregiver payout500000, branch settlement1181519, HQ settlement181519, andledgerLineCount=3. Runtime finding: the old frontend settlement smoke URL/reservation-smoke-scenarios/{id}/settlement-completionsis stale; frontend verification must call/reservation-financial-lifecycles/{reservationBookingId}/settlement-completionswith the HQ actor token after the branch/HQ preparation commands. Mobile artifact in the same run did not submit a booking, so mobile reservation UX is still note2e_proven. 2026-07-09 source-authority follow-up replaced the remaining hand-built branch/HQ ledger facts in this smoke with backend command producers. Reservation521a5051-9825-44e9-bb5a-fd7d84d3981efroze finalized charge linescustomer_share=150000andheadquarters_platform_fee=50000, then produced ledger lines for caregiver payout50000, branch settlement100000, and HQ settlement50000from backend-owned facts. Direct browser backend driver proof booking27f69a4c-7600-4de1-b611-839d8e757b94now uses the same producer path and reports account-disclosure readinessnot_requiredfor zero service-balance due. 2026-07-10 backend597b56droutes the local smoke settlement completion throughAdvanceReservationFinancialLifecycleHandlercommands and a versioned_SmokeReservationSettlementPolicy, replacing direct aggregate mutation and route-local split arithmetic. Remaining work: keep fixture data-quality gates fromSFC-20260708-CUR-083andSFC-20260708-CUR-084in front of every smoke run and replace the temporary stage quote fixture with catalog-owned product-plan data. 2026-07-11 frontend8a9a6f5removes this endpoint and all smoke settlement DTO/state/rendering from productionsrc/**. Playwright owns smoke orchestration: it may call the dev-smoke endpoint only when that app exposes it, otherwise uses the backend settlement driver, then opens the real branch settlement projection. Production UI never calls the smoke route. -
SFC-20260708-CUR-086Reservation workflow preflight context completeness gate. The browser-to-backend smoke loop exposed branch topology and caregiver qualification failures before a durable reservation could be created. This row records the remaining source-backed data-quality rules that should fail before workflow execution, not midway through assignment, payment, calendar, or settlement side effects. Branch topology belongs toSFC-20260708-CUR-083; caregiver qualification/license approval belongs toSFC-20260708-CUR-084. Additional evidence:source-refs/sanmopia_web/application/models/Branch_model.php:38-90andsource-refs/sanmopia_web/application/models/Branch_model.php:92-132(branch service-area match depends on normalized address levels and possible versus consultation policy, while an불가row overrides a matched serviceable row);source-refs/sanmopia-admin/application/views/office_management/office_detail.php:230-419,source-refs/sanmopia-admin/static/js/office_management/office_detail.js:170-245,source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:171-205,source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:325-342,source-refs/sanmopia-admin/application/models/Branch_model.php:291-425, andsource-refs/sanmopia-admin/application/models/Branch_model.php:597-606(operator UI maintains serviceable, consultation-only, and unserviceable Daum address-level rows, and consultation/unserviceable rows are allowed only inside an existing serviceable branch area);source-refs/sanmopia_web/application/models/Manager_matching_model.php:105-130,source-refs/sanmopia_web/application/models/Manager_matching_model.php:248-280, andsource-refs/sanmopia_web/application/models/Manager_matching_model.php:283-305(matching requires reservation address coordinates, caregiver coordinates, and distance/travel facts);source-refs/sanmopia-admin/application/models/Matching_model.php:796-808andsource-refs/sanmopia-admin/application/models/Matching_model.php:872-888(admin matching has the same missing-address and caregiver-coordinate assumptions);source-refs/sanmopia_web/application/views/service/reservation_payment.php:128-132,source-refs/sanmopia_web/application/views/service/pre_reservation_payment.php:51-55,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:431-435,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:458-479,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:545-566,source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:74-139,source-refs/sanmopia_web/application/views/modal/modal_change_payment.php:27-32,source-refs/sanmopia_web/application/views/mypage/reservation_changePayment.php:54-67,source-refs/sanmopia_web/application/views/item/kcp/order_info_form.php:35-75,source-refs/sanmopia_web/application/views/item/kcp/pay_form.php:4-24,source-refs/sanmopia_web/static/js/reservation_payment.js:179-184,source-refs/sanmopia_web/static/js/pre_reservation_payment.js:112-117,source-refs/sanmopia_web/static/js/mypage/reservation.js:608-642,source-refs/sanmopia_web/static/js/mypage/reservation.js:695-742,source-refs/sanmopia_web/static/js/mypage/reservation.js:797-802,source-refs/sanmopia_web/static/js/mypage/reservation_changePayment.js:43-75,source-refs/sanmopia_web/static/js/mypage/reservation_changePayment.js:78-124,source-refs/sanmopia_web/static/js/lib/kcp/approval_key.js:55-65,source-refs/sanmopia_web/application/controllers/api/Payment.php:24-55,source-refs/sanmopia_web/application/controllers/api/Payment.php:65-110,source-refs/sanmopia_web/application/controllers/api/Payment.php:123-151,source-refs/sanmopia_web/application/controllers/api/Payment.php:325-386,source-refs/sanmopia_web/application/controllers/api/Payment.php:417-505,source-refs/sanmopia_web/application/controllers/api/Payment.php:508-586,source-refs/sanmopia_web/application/controllers/api/Payment.php:657-756,source-refs/sanmopia_web/application/models/Payment_model.php:150-190,source-refs/sanmopia_web/application/models/Payment_model.php:327-378,source-refs/sanmopia_web/application/models/Payment_model.php:400-412,source-refs/sanmopia_web/application/models/Payment_model.php:477-525,source-refs/sanmopia_web/application/models/Payment_model.php:531-560,source-refs/sanmopia_web/application/models/Payment_model.php:856-900,source-refs/sanmopia_web/application/libraries/Kcppayment.php:12-49,source-refs/sanmopia_web/application/libraries/Kcppayment.php:92-108,source-refs/sanmopia_web/application/libraries/Kcppayment.php:210-238,source-refs/sanmopia_web/application/libraries/Kcppayment.php:245-273,source-refs/sanmopia_web/application/libraries/Kcppayment.php:326-373,source-refs/sanmopia_web/application/libraries/Kcppayment.php:376-411,source-refs/sanmopia_web/application/config/site_conf_inc.php:88-104, andsource-refs/sanmopia_web/application/config/constants.php:64-90(payment eligibility is purpose-specific: create/pre-reservation pages exposeCARD/VCNTwhileBANKis commented out, mypage own-balance exposesCARD/BANK/VCNT, service-balance uses direct caregiver account instructions, hidden JS writesActionResult/pay_methodinto the KCP form, KCP approval sends that browser value to the provider, virtual-account raw context changes payment/reservation state to waiting statuses and notice behavior, prior virtual-account reservation statuses hide payment-change entry points, payment-change copy frames the path as card replacement, the payment-change form hardcodes the KCPCARDroute, and the KCP provider route requires order id, amount, buyer, site code/key, transaction code,use_pay_method, and method-specific card/bank/virtual-account response fields before internal payment state can be trusted);source-refs/sanmopia_web/static/js/step3.js:861-906,source-refs/sanmopia_web/static/js/step3.js:1033-1085,source-refs/sanmopia_web/static/js/step3.js:1090-1135,source-refs/sanmopia_web/application/controllers/api/Service.php:300-406,source-refs/sanmopia_web/application/controllers/api/Service.php:452-514,source-refs/sanmopia_web/application/models/Reservation_model.php:463-505,source-refs/sanmopia_web/application/models/Reservation_model.php:642-663, andsource-refs/sanmopia_web/application/models/Reservation_model.php:2660-2766(service-start/end, weeks/service-day, Wanju, selected Saturday/holiday dates,RESERVATION_ADD_DATEwrites, service-start-after-delivery validation, and voucher resident-identity parity were derived from UI arrays, raw resident-number fragments, and mutable PHP recomputation). Target:reservation_orchestration / ReservationWorkflowPreflightContextGate,branch_operations / BranchTopologyContextInvariant,branch_operations / BranchServiceCoveragePolicyRevision,caregiver_assignment / CaregiverAssignmentCoverageContextInvariant,caregiver_assignment / CaregiverQualificationApprovalContextInvariant,pricing_settlement / PaymentPurposeMethodEligibilityInvariant,pricing_settlement / PaymentProviderRouteEligibilityInvariant,pricing_settlement / VirtualAccountInstructionLifecycleInvariant,pricing_settlement / DirectServiceBalanceInstructionEligibilityInvariant,pricing_settlement / PaymentChangeCardReplacementEligibilityInvariant,reservation_operations / ServiceStartAfterDeliveryInvariant,member_management / VoucherRecipientIdentityEvidenceReadinessInvariant,service_calendar / AcceptedServiceTermPlanFixtureInvariant, andmigration_governance / ReservationScenarioFixtureDataQualityGate. Actors: mother/customer applicant, branch operator, HQ operator, caregiver assignment reviewer, payment provider, migration fixture author, booking workflow runner. Status:Partial; backend now runsReservationBookingContextQualityGatebefore direct booking or durable workflow start. It rejects invalid branch topology, missing caregiver candidate/profile links, missing selected caregiver candidate, inactive caregiver profile, missing approved license titles, missing service-area facts, and missing candidate availability before workflow acceptance, so these defects no longer appear as late assignment/workflow failures. Focused API and HTTP tests covercaregiver_qualification_context_missingand prove workflow starter is not called on preflight failure. 2026-07-08 follow-up adds the first payment preflight invariant:payment_method_catalog_eligibility_invalidrejects hidden browser-only or unsupported payment method values such asfamily_bankbefore workflow acceptance by using the backendPaymentMethodCodecatalog (card,vcnt,bank) instead of UI labels. 2026-07-08 follow-up 2 wires the realPaymentProductPlanBookinto the Supabase reservation runtime and blocks canonical-but-purpose-invalid methods withpayment_purpose_method_eligibility_invalidbefore workflow acceptance (reservation.customer_share.depositis the booking-start plan). Focused proof: API/HTTP tests reject abankbooking-start request before workflow start, Supabase runtime accepts the injected resolver, and backend smokeRBQ-SCENARIO-20260708-1returns start202, workflowcompleted, frozen reservation ide32cb903-89cd-45a1-babc-da6c1ea275b5, charge summary200, customer payable150019, and one mother-visible charge line. Remaining work: enforce caregiver coverage/coordinate facts for the service address, provider-route fact completeness before payment capture, service start not preceding delivery/birth date, redacted voucher identity readiness instead of raw resident-number fragments, and accepted service-term/side-effect assembly consistency with service start, service-day/week profile, extra Saturday/holiday selections, and regional profile facts. Payment preflight must reject unsupported hidden browser values, distinguish card, virtual-account, bank/cash, pre-reservation, own-balance, and direct service-balance instructions, require KCP/provider route facts only for provider-routed payments, open virtual-account waiting instructions without marking them paid, preserve provider raw context for reconciliation, and block conversion/card-replacement paths when prior virtual-account facts make them ineligible. Current implementation has a payment product plan catalog with plan-code, purpose, allowed-method, provider routing key, virtual-account expiration, settlement, and communication-route facts (backend-repo/supabase/migrations/20260704033000_payment_product_plan_catalog.sql:206-385,backend-repo/supabase/migrations/20260704074502_payment_product_plan_settlement_line_templates.sql:48-214, andbackend-repo/supabase/migrations/20260704080443_payment_product_plan_communication_routes.sql:49-220, plusbackend-repo/supabase/migrations/20260709145000_payment_product_plan_price_catalog_references.sql); booking preflight now resolves the selected booking/payment purpose against that backend catalog before workflow acceptance. Branch coverage also still needs a backend-owned revision/freshness fact that distinguishes serviceable, consultation-only, and unserviceable address-level matches before booking starts; booking must not infer that from Daum labels or mutable branch UI rows. Test gap: address-level fallback whereADDRESS_LEVEL_2contains multiple tokens, unserviceable override over wider serviceable region, consultation-only branch routing, service-area deletion invalidating booking/matching preflight, service start before delivery/birth date, missing or ineligible redacted voucher identity evidence, and branch/HQ fixture rejection before workflow start. Frontend and smoke fixtures may stage user choices, but must not become authority for branch hierarchy, caregiver eligibility, coverage, payment method, provider route, service-term dates, extra-day buckets, charge impact, or settlement participation. 2026-07-08 follow-up 3 wires the same Supabase pre-registration store intoReservationPaymentApias the provider-route query and blocksverify_paid_paymentworkflow start when the payment id has no frozen pre-registration, no provider-route fee snapshot, a stale amount, or a different reservation booking id. Focused proof:reservation_payment_http_test.pyrejects those cases withpayment_provider_route_pre_registration_missing,payment_provider_route_snapshot_missing,payment_provider_route_amount_mismatch, and keeps the ReState workflow starter untouched; a matching frozen snapshot still returns202. 2026-07-08 follow-up 4 promotes the pre-registration query port into the application pre-registration slice and injects the same Supabase store intoKillBillPaymentEventIngestionHandler; paid webhooks now fail before ReState workflow start when frozen pre-registration is missing, route snapshot is missing, amount is stale, or booking id diverges. Focused proof:killbill_payment_event_test.pyrejectspayment_provider_route_pre_registration_missing,payment_provider_route_snapshot_missing, andpayment_provider_route_amount_mismatch, while a matching snapshot starts the verification workflow. Remaining provider work: persist route-snapshot evidence into payment workflow read models, add compensation refund saga when provider succeeds but local closeout fails, and finish virtual-account instruction/deposit plus card-replacement conversion rules. -
SFC-20260708-CUR-087Actual-service product-coupon entitlement and settlement recognition. Legacy cancellation/stop and confirmation flows decide reservation-linked product coupon entitlement from mutable service state, actual attendance count, working type, continuation type conversion, publish windows, and hardcoded coupon prices. Cancel/stop reset deletes old reservation coupons, countsMANAGER_ATTENDANCE_TB, grants no coupon under three actual service days, grantsPRODUCT1/20,000 for three-to-seven days, grantsPRODUCT2/30,000 for eight or more days, and immediately creates a six-month user coupon if published. Confirmation creates normal-service product coupons only, excludes voucher service, allows voucher-to-normal continuation but not normal-to-normal or normal-to-voucher, and sets publish date to start+3 or start+8 days by service term and working type. Admin coupon and reservation lists then derive Korean publish statuses, product labels, usage place, and publish visibility from raw flags, dates, service start, and reservation done/expired checks. Settlement later recognizes live coupon cost and deleted-coupon gift fees from coupon type and delete/payment flags. Evidence:source-refs/sanmopia-admin/application/models/Coupon_model.php:33-157,source-refs/sanmopia-admin/application/models/Coupon_model.php:211-324,source-refs/sanmopia-admin/application/models/Coupon_model.php:496-690,source-refs/sanmopia-admin/application/models/Reservation_model.php:1289-1334,source-refs/sanmopia-admin/application/models/Reservation_model.php:3877-3934,source-refs/sanmopia-admin/application/models/Payment_model.php:240-279,source-refs/sanmopia-admin/application/models/Payment_model.php:1554-1588, andsource-refs/sanmopia-admin/application/models/Payment_model.php:3837-3868. Target:promotion_entitlement / ActualServiceProductCouponEntitlement,promotion_entitlement / ProductCouponPublicationProjection,pricing_settlement / ProductCouponSettlementLineProjection, andcare_delivery / ActualServiceAttendanceCountProjection. Actors: mother/customer, branch operator, HQ promotion operator, settlement operator, caregiver attendance source. Desired abstraction: backend must calculate entitlement from the frozen service occurrence/attendance ledger, lifecycle transition reason, continuation relationship, service-type profile, working-type profile, coupon policy version, and publication/settlement recognition revisions. UI labels such as발행예정,발행완료,발행안함, “1주 사은품”, and “2주이상 사은품” become read-model labels only. Status:Pending; SFC-079/SFC-080/SFC-081 cover coupon use/delete and product-gift redemption/publication plumbing, but this reservation actual-service entitlement downgrade/regeneration and settlement-recognition rule still lacks a backend command/projection. Test gap: attendance counts 0/2/3/7/8, cancel vs stop, voucher exclusion, voucher-to-normal continuation eligibility, normal continuation exclusion, start+3/start+8 publish windows, branch-visible expired/done hiding, deleted-coupon 5,000/10,000 settlement fees, and projection invalidation when service dates or attendance rows change. -
SFC-20260708-CUR-088Settlement adjustment lines and data-room worklist projection. Legacy branch/HQ/Danbee settlement screens accept browser-posted financial totals and ad-hoc adjustment lines. JavaScript builds selected service/coupon ids, delivery, month due, product coupon/cancelled coupon counts, custometcname/count/price arrays, provider fee totals, total price, result price, and checked-line ids, then controllers pass those values directly into payment models. The UI also lets operators add/edit custom “other service” catalog rows, including negative prices described as reducing branch remittance. Payment models persistBOARD_PAYMENT_ADMIN_ETC_TB/BOARD_PAYMENT_DANBEE_ETC_TBrows and recompute board totals from current service/coupon/custom rows. Data-room settlement and form-download screens build worklists from mutable reservation status/service-type/date/branch filters and browser-selected raw reservation ids before streaming document bundles. Download readiness is only checkbox count in JavaScript, while bundle content is selected from raw hiddenreservation[service_type]values and streamed through a hidden iframe. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:150-255,source-refs/sanmopia-admin/static/js/calculate_detail.js:460-533,source-refs/sanmopia-admin/static/js/calculate_detail.js:760-1144,source-refs/sanmopia-admin/application/controllers/Calculate.php:127-146,source-refs/sanmopia-admin/application/controllers/Calculate.php:151-240,source-refs/sanmopia-admin/application/controllers/Calculate.php:502-550,source-refs/sanmopia-admin/application/views/modal/modal_other_service_add.php:23-29,source-refs/sanmopia-admin/static/js/calculate/other_service_management.js:43-96,source-refs/sanmopia-admin/application/models/Payment_model.php:2861-2908,source-refs/sanmopia-admin/application/controllers/DataRoom.php:218-250,source-refs/sanmopia-admin/application/controllers/DataRoom.php:311-375,source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:17-240,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:33-89,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:219-247,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:43-60, andsource-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:29-49. Target:pricing_settlement / SettlementAdjustmentLineCommand,pricing_settlement / SettlementStatementWorklistProjection,document_reporting / SettlementDataRoomSelectionGrant, andoperator_access / SettlementArchiveAccessGrant. Actors: branch settlement operator, HQ settlement operator, Danbee settlement operator, document/data-room operator. Desired abstraction: backend must own adjustment-line catalog version, negative surcharge/discount policy, quantity math, settlement board revision, worklist filters, selected-line tokens, download readiness, bundle service-type policy, actor grants, return-state token, and archive artifact snapshots. The browser may request acknowledgement or adjustment commands with expected revisions; it must not post authoritative totals or raw reservation-id bundles. Status:Partial; SFC-066 covers positive-only settlement acknowledgements, SFC-20260706-CUR-023 covers frozen settlement XLSX export lines, andbackend-repo/src/sanmopia_modernization/interfaces/settlement_statement_http.pynow acceptsmanualAdjustmentLinesproduced from a catalog-frozenFrozenSettlementManualAdjustmentLinePayload. That path computestotalAmountKrwbackend-side from quantity and catalog unit amount, maps the frozen line intoSettlementStatementManualRowPayload, rejects postedtotalAmountKrw, and no longer accepts legacy directmanualRowsthrough the public HTTP boundary. Focused proof:settlement_statement_api_test.py::test_settlement_statement_api_accepts_catalog_frozen_manual_adjustment_line,settlement_statement_api_test.py::test_settlement_statement_api_rejects_mixed_manual_row_sources,settlement_statement_http_test.py::test_settlement_statement_http_adds_catalog_frozen_manual_adjustment_lines,settlement_statement_http_test.py::test_settlement_statement_http_rejects_raw_manual_rows, andsettlement_statement_http_test.py::test_settlement_statement_http_rejects_catalog_line_posted_total. Remaining work: add persisted adjustment-line catalog issuance/verification, finish data-room worklist selection, and settlement archive UX projections. Test gap: reject tamperedftotal-price/ffee-price/fresult-price, persist custom positive and negative adjustment lines with actor/reason, quantity and catalog revision, branch vs HQ permissions, Danbee other-office routing, data-room status/service-type filters, raw reservation-id selection rejection, archive artifact replay from a frozen dataset, and reject client-mutated catalog unit amounts once persisted catalog-line tokens exist. -
SFC-20260708-CUR-089Caregiver assignment override, conflict decision, and matching evidence audit. Legacy matching builds candidates from preference/personality score views, schedule SQL functions, pet-allergy exclusion, branch and caregiver-class filters, optional name search, random tie-breaking by user/reservation id, local distance calculation, and ODSAY travel-time lookup/fallback. Web and admin flows differ: one path can cache ODSAY minutes and sort by travel time, while admin recommendation paths preserve score ordering and expose distance/transit as evidence. The reservation detail UI prevents duplicate main/sub caregiver slots only in JavaScript, lets operators search with temporary start/end dates that do not change service dates, states in a help alert that in-progress assignment changes must be saved at least one day before service, and displays change history from raw log tables. Persistence setsOTHER_AREA_FLwhen caregiver branch differs from reservation branch, writes old/new assignment ids to main or sub caregiver log tables, mutates current assignment rows, and deletes related payout/salary rows when a sub caregiver is removed. Evidence:source-refs/sanmopia-admin/application/models/Matching_model.php:44-124,source-refs/sanmopia-admin/application/models/Matching_model.php:724-862,source-refs/sanmopia-admin/application/models/Matching_model.php:865-907,source-refs/sanmopia_web/application/models/Manager_matching_model.php:105-163,source-refs/sanmopia_web/application/models/Manager_matching_model.php:166-228,source-refs/sanmopia_web/application/models/Manager_matching_model.php:248-306,source-refs/sanmopia-admin/application/models/Reservation_manager_trans_info_model.php:13-87,source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:585-629,source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:660-728,source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:1067-1075,source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:1105-1152,source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:31-65,source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:180-208,source-refs/sanmopia-admin/application/controllers/Reservation.php:560-576,source-refs/sanmopia-admin/application/controllers/Reservation.php:650-674,source-refs/sanmopia-admin/application/controllers/Reservation.php:930-1014,source-refs/sanmopia-admin/application/models/Reservation_model.php:2165-2221, andsource-refs/sanmopia-admin/application/models/Reservation_model.php:2224-2303. Target:caregiver_assignment / CaregiverCandidateOrderingPolicy,caregiver_assignment / CaregiverCandidateSelectionToken,caregiver_assignment / CareTeamSlotUniquenessDecision,caregiver_assignment / AssignmentTimingGuard,caregiver_assignment / AssignmentOverrideCommand,caregiver_assignment / AssignmentConflictDecision,caregiver_assignment / AssignmentChangeAuditLedger, andpricing_settlement / AssignmentPayoutImpactInvalidation. Actors: branch assignment operator, HQ assignment reviewer, caregiver, settlement operator, reservation workflow. Desired abstraction: backend must return candidate ordering plus frozen reason evidence, distinguish score, distance, and travel-time policies, enforce duplicate slot and timing rules, capture operator override reason/conflict acknowledgement, write immutable assignment history, emit cross-branch settlement implications, and invalidate availability/payout projections. Status:Pending; SFC-084/SFC-086 cover assignment context completeness and preflight facts, and SFC-065 lists assignment availability/payout invalidation consumers, but the actual override command and conflict audit remain UI/PHP-side. Test gap: main/sub duplicate rejection server-side, cross-branchOTHER_AREAsettlement impact, in-progress one-day cutoff, score-vs-distance-vs-transit sort modes, ODSAY failure fallback, temporary search dates not mutating service term, sub-caregiver removal payout impact, and replayable old/new assignment history with actor/reason.2026-07-08 source-dig addition: caregiver assignment history is also a document/reporting input, not just an operator UI table. Contract and voucher documents reload latest or ordered
RESERVATION_MANAGER_LOG_TB/RESERVATION_SUB_MANAGER_LOG_TBrows at render time to print previous/current primary caregiver names, assistant-before names, change dates, and caregiver phone numbers (source-refs/sanmopia-admin/application/models/Reservation_model.php:57-112,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:269-288,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:906-928,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:1014-1024,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3625-3633). ModernCareTeamAssignmentHistoryProjectionandCareTeamDocumentRosterSnapshotmust be produced from immutable assignment decisions with role slot, handoff order, actor/reason, old/new caregiver display facts, contact visibility policy, and projection revision before document rendering. Renderers must not query mutable assignment log tables or infer “previous caregiver” from read-time row order.2026-07-09 source-mining follow-up: reservation detail JavaScript posts
freservation-id,fmanager-score,fmanager-id, temporaryfservice-start-date, andfservice-end-dateto matching lookup, while duplicate main/sub slot prevention stays in browser DOM attributes (source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:585-629,source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.js:660-685). AJAX controller trusts raw candidate id and string score;0점short-circuits match facts before loading manager, preference, distance, and transit evidence (source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:31-65). Modern backend must issue a candidate selection token tied to candidate snapshot, assignment slot, score/distance/transit evidence revision, search-date policy, and expected roster revision. UI may submit selection token plus operator reason only; it must not post raw manager id, display score, or temporary dates as assignment authority. -
SFC-20260708-CUR-094Care-delivery notification, occurrence, and attendance repair backfill authority. Legacy manager repair helpers mutate care-delivery facts directly:temp20200522()converts already-read report notifications intoMANAGER_ATTENDANCE_TBattendance rows,temp20200528()rebinds notify rows to the current manager fromRESERVATION_DETAIL_VW,temp202005281047()inserts a one-offRESERVATION_DATE_TBservice occurrence row, and dated helpersinsertNotify20210831()/insertNotify20210901()hardcode notificationCREATED_DTvalues while generating report/service-record notify rows. The 2021-09-01 variant also inserts attendance rows from the service-record notify loop. Evidence:source-refs/sanmopia-manager/application/models/Notify_model.php:11-31,source-refs/sanmopia-manager/application/models/Notify_model.php:34-58,source-refs/sanmopia-manager/application/models/Notify_model.php:60-67,source-refs/sanmopia-manager/application/models/Notify_model.php:70-163, andsource-refs/sanmopia-manager/application/models/Notify_model.php:166-262. Target:care_delivery / CareDeliveryNotificationRepairCase,service_calendar / ServiceOccurrenceRepairCommand,customer_engagement / NotificationRecipientRepairProjection, andmigration_governance / SourceRepairRunLedger. Status:foundation; backend commitf318d9caddsCareDeliveryNotificationRepairBackfillPlannerand strict PydanticPlanCareDeliveryNotificationRepairBackfillPayloadcontract. The foundation converts source repair helpers into a replayable side-effect plan with actor, reason, dry-run mode, expected revision gates, source evidence keys, idempotency key, and explicit side-effect kinds for notification obligation upsert, notification recipient rebinding, service occurrence upsert, attendance-open upsert, and source repair ledger recording. The contract rejects source-era table/function fields such asMANAGER_ATTENDANCE_TB,NOTIFY_TB,RESERVATION_DATE_TB,RESERVATION_DETAIL_VW,CREATED_DT,temp20200522,temp20200528,temp202005281047,insertNotify20210831, andinsertNotify20210901. SFC-068 through SFC-071 cover normal scheduled eligibility, dispatch, and attendance-open behavior, but repair/backfill runtime still needs Supabase persistence, operator authorization, dry-run diff read model, and executable command handler. This was not frontend UI logic; legacy PHP repair methods performed backend business decisions with hardcoded dates and mutable notify/read state. Cron/manual repair scripts must not insert attendance, occurrence, or notification rows directly. Suggested backend feature:CareDeliveryNotificationRepairBackfillCommand. -
SFC-20260708-CUR-095Branch/HQ settlement remittance account and fee policy snapshot. Legacy settlement detail pages expose remittance and fee authority from mutable PHP/view state: branch users see hardcoded HQ deposit-account text, central-to-branch detail renders branch normal/voucher bank account columns directly, voucher settlement fees are recomputed asVOUCHER_COUNT * 15000, gift-fee count/price fields are editable in the settlement form, and browser JavaScript recomputes delivery, membership-due, manual-etc, gift-fee, card-fee, voucher-fee, and result totals from DOM flags before submit. Controller/model paths also recompute central-to-branchALL_PRICEandRESULT_PRICEfrom current branch/payment/coupon data instead of a frozen statement revision. Evidence:source-refs/sanmopia-admin/application/config/constants.php:286-287,source-refs/sanmopia-admin/application/views/calculate_detail.php:190-193,source-refs/sanmopia-admin/application/views/calculate_detail.php:256-283,source-refs/sanmopia-admin/application/views/calculate_detail.php:356-386,source-refs/sanmopia-admin/application/views/calculate_detail.php:930-955,source-refs/sanmopia-admin/static/js/calculate_detail.js:930-1047,source-refs/sanmopia-admin/static/js/calculate_detail.js:1053-1144,source-refs/sanmopia-admin/application/controllers/Common.php:93-107,source-refs/sanmopia-admin/application/models/Payment_model.php:1518-1550, andsource-refs/sanmopia-admin/application/models/Payment_model.php:2076-2088. Target:pricing_settlement / SettlementRemittanceAccountSnapshot,pricing_settlement / SettlementFeePolicySnapshot,pricing_settlement / BranchHeadquartersSettlementStatementProjection,operator_access / SettlementRemittanceVisibilityGrant, anddocument_reporting / SettlementRemittanceInstructionArtifact. Status:Backend foundation: 6b2b571. Backend now reuses existingSettlementRemittanceAccountSnapshotand addsSettlementRemittanceInstructionSnapshotProjection,SettlementFeePolicySnapshot,SettlementFeePolicyLineSnapshot,SettlementStatementResultTotalSnapshot, andIssueSettlementRemittanceInstructionSnapshotPayload. Fee totals and result totals are frozen from typed amount lines, fee catalog revision, account profile revision, statement revision, visibility grant, artifact grant, and acknowledgement state. Strict contracts reject source-era fields such asALL_PRICE,RESULT_PRICE,VOUCHER_COUNT, gift fee fields, delivery and membership fee DOM totals, bank-account raw fields, and board ids so PHP/Astro/JS cannot recompute account visibility, fee amount, or final remittance result. Remaining proof: Supabase stores for fee policy, remittance-account, and result-total snapshots; query/read API binding forGetSettlementRemittanceInstructionProjection; SpiceDB grant issuer for branch/HQ visibility; document artifact binding; branch acknowledgement, HQ approval, adjustment, and closeout command binding; runtime E2E proof on real branch/HQ settlement rows. Suggested backend feature:SettlementRemittanceInstructionSnapshotProjection. -
SFC-20260708-CUR-096Caregiver payout portal statement surface and route/document grant projection. Legacy caregiver payout detail still mixes payout readiness, statement display, route disclosure, and document/action policy in PHP views: payout detail loads role-specific pay rows from the logged-in caregiver, rejects main/sub mismatch in controller/view flow, displays status badge images and final-pay labels, switches normal/voucher week and baby/provider labels, applies after-tax and2022-03-29cutover display rules, exposes full service/caregiver addresses plus coordinates for route buttons, and renders statement action buttons from mutable payout rows instead of a frozen caregiver-facing statement projection. Evidence:source-refs/sanmopia-manager/application/controllers/Other.php:224-292,source-refs/sanmopia-manager/application/views/pay_info_detail.php:42-101,source-refs/sanmopia-manager/application/views/pay_info_detail.php:132-154, andsource-refs/sanmopia-manager/application/views/pay_info_detail.php:170-255. Target:pricing_settlement / CaregiverPayoutPortalStatementProjection,pricing_settlement / CaregiverPayoutSurfacePolicySnapshot,care_delivery / CaregiverPayoutWorkContextProjection,operator_access / CaregiverPayoutStatementAccessGrant,operator_access / CaregiverRouteDisclosureGrant, anddocument_reporting / CaregiverPayoutStatementArtifactGrant. Status:Mapped; SFC-059 covers admin payout projection persistence andCaregiverPayoutPortalSurfaceProjectionis already named in the high-level gap map, but no numbered slice owns caregiver-facing route/document grants, cutover-compatible display policy, action availability, or statement-surface persistence. Backend slice needsGetCaregiverPayoutPortalStatementProjectionquery/read model,IssueCaregiverPayoutStatementAccessGrantcommand,IssueCaregiverRouteDisclosureGrantcommand,CaregiverPayoutPortalStatementProjectionStore,CaregiverPayoutSurfacePolicySnapshotStore, andCaregiverPayoutStatementArtifactGrantStorepersistence keyed by reservation, assignment key, caregiver role, handoff order, payout statement revision, route-disclosure window, and access-grant revision. Frontend must render backend projections only: no PHP/Astro/JS view may recompute payout labels, expose addresses/coordinates, infer action availability, or choose documents from mutable salary/payment rows. Suggested backend feature:CaregiverPayoutPortalStatementProjection. -
SFC-20260708-CUR-097Branch document mailbox post, attachment, and visibility grant. Legacy settlement/data-room “other post” behavior is a branch/HQ document mailbox, not neutral board content. PHP controllers and models decide sender branch, recipient branch, headquarters fallback branch36, all-branch/null recipient semantics, fixed-post visibility, edit/delete authority, and file attachment exposure from mutable board rows and raw request fields. Browser JavaScript posts the write form and reloads list/detail state without a signed mailbox command, immutable attachment revision, visibility grant, or audit token. Evidence:source-refs/sanmopia-admin/application/controllers/DataRoom.php:97-197,source-refs/sanmopia-admin/application/models/Data_room_model.php:22-80,source-refs/sanmopia-admin/application/models/Data_room_model.php:82-184,source-refs/sanmopia-admin/application/views/table/data_room/table_other_post_list.php:1-114, andsource-refs/sanmopia-admin/static/js/data_room/other_post_write.js:1-108. Target:document_reporting / BranchDocumentMailbox,document_reporting / DocumentMailboxPostCommand,document_reporting / DocumentAttachmentGrant,operator_access / BranchDocumentMailboxPermission, andsecurity_audit / DocumentMailboxAuditEvent. Status:Mapped; high-level data-room docs already identify the mailbox, but no numbered slice owns branch/HQ participant snapshots, recipient-scope compatibility, attachment versioning, edit/delete grants, read receipts, or immutable audit for this document room path. Backend slice needsPostBranchDocumentMailboxMessagecommand,GetBranchDocumentMailboxThreadProjectionquery/read model,IssueDocumentMailboxAttachmentGrantcommand,BranchDocumentMailboxPostStore,DocumentMailboxAttachmentRevisionStore, andDocumentMailboxAuditEventStorepersistence keyed by actor, sender branch, recipient branch scope, post revision, attachment revision, and grant expiry. Frontend must render backend projections only: no PHP/Astro/JS view may decide branch visibility, expose file paths, infer edit/delete authority, or compose attachment download URLs from mutable data-room rows. Suggested backend feature:BranchDocumentMailboxPostCommand. -
SFC-20260708-CUR-098Annual branch settlement workbook artifact and fee snapshot. Legacy branch-year settlement export is a CLI/PHP financial artifact, not a neutral spreadsheet dump. The command selects branch settlement boards by mutable branch id/year, reloads current board payment rows, calls fee classification at render time, recomputes service and coupon net deposit amounts, applies hardcoded coupon fee rates by payment-method label, writes a deterministic branch/year filename underupload/excel, and reports the raw filesystem path. Re-running the export can overwrite the same artifact path without generation history, revocation, or reissue audit. Evidence:source-refs/sanmopia-admin/application/controllers/cli/Excel.php:242-263,source-refs/sanmopia-admin/application/controllers/cli/Excel.php:286-329,source-refs/sanmopia-admin/application/controllers/cli/Excel.php:333-364, andsource-refs/sanmopia-admin/application/controllers/cli/Excel.php:392-401. Target:pricing_settlement / AnnualBranchSettlementDatasetRevision,pricing_settlement / SettlementPaymentMethodFeeSnapshot,document_reporting / AnnualBranchSettlementWorkbookArtifact,document_reporting / SettlementArtifactReissueHistory,operator_access / SettlementArtifactGrant, andmigration_governance / SettlementArtifactBuildRunLedger. Status:Backend foundation: ebf6a8d; backend now addsAnnualBranchSettlementDatasetRevision,SettlementPaymentMethodFeeSnapshot,AnnualBranchSettlementWorkbookArtifact,SettlementArtifactBuildRunLedgerEntry,BuildAnnualBranchSettlementWorkbookArtifact,GetAnnualBranchSettlementDatasetRevision,AnnualBranchSettlementDatasetRevisionStore,AnnualBranchSettlementWorkbookArtifactStore, andSettlementArtifactBuildRunLedgerStore. The slice freezes branch-year rows, board statement revisions, fee evidence revision, artifact checksum, retention metadata, actor/reason, idempotency key, and source evidence before renderer execution; Pydantic contracts reject raw/upload/excelserver paths. Remaining migration: Supabase persistence/migrations, renderer worker, signed grant, cron/admin/API binding, artifact reissue history, retention/revocation controls, and historical backfill. Frontend/admin/cron/CLI must render backend projections only: no PHP/Astro/JS/CLI path may recompute card, bank, virtual-account, coupon, or net-deposit amounts from mutable payment rows or expose raw server file paths. Suggested backend feature:AnnualBranchSettlementWorkbookArtifactBuild. -
SFC-20260708-CUR-099Pre-reservation caregiver assignment draft and matching-score authority. Legacy pre-reservation detail is not only a candidate search view. The browser requests caregiver candidates with reservation id, branch id, search text, and temporary service dates, renders rounded score labels, stores the selected caregiver id in an inputdata-index, posts the selected id plus a client score string to the Ajax matching preview, highlights match facts from mutable rows, and later broad reservation save carriesfmanager-idinto service/payment/date and caregiver assignment writes. Evidence:source-refs/sanmopia-admin/static/js/reservation_status/pre_reservation_detail.js:250-266,source-refs/sanmopia-admin/static/js/reservation_status/pre_reservation_detail.js:519-553,source-refs/sanmopia-admin/static/js/reservation_status/pre_reservation_detail.js:571-581,source-refs/sanmopia-admin/static/js/reservation_status/pre_reservation_detail.js:631-676,source-refs/sanmopia-admin/application/controllers/Reservation.php:538-576,source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:31-65,source-refs/sanmopia-admin/application/controllers/Reservation.php:650-672,source-refs/sanmopia-admin/application/controllers/Reservation.php:836-865, andsource-refs/sanmopia-admin/application/models/Reservation_model.php:2165-2221. Target:caregiver_assignment / PreReservationCaregiverAssignmentDraft,caregiver_assignment / CaregiverCandidateSnapshotRevision,caregiver_assignment / AssignmentPreviewEvidence,reservation_operations / PreReservationConversionAssignmentCarryover,pricing_settlement / AssignmentPayoutImpactPreview, andsecurity_audit / AssignmentDraftDecisionAudit. Status:Backend foundation: ad17f8c; backend now addsCaregiverCandidateSnapshotRevision,PreReservationCaregiverAssignmentDraft,AssignmentPreviewEvidence,AssignmentDraftDecisionAudit,CreatePreReservationCaregiverAssignmentDraft,PreviewPreReservationCaregiverAssignmentEvidence,CommitPreReservationCaregiverAssignmentDraft,PreReservationCaregiverAssignmentDraftStore,AssignmentPreviewEvidenceStore, andAssignmentDraftDecisionAuditStore. The slice derives score display labels from backendscore_total, rejects client-posted stale candidate snapshot revisions and mismatched caregiver ids, and commits only against expected reservation revision. Remaining migration: Supabase persistence/migrations, integration with recommendation-set read model, reservation conversion carryover, payout-impact preview production, SpiceDB checks, and admin API/UI binding. Frontend/admin must render backend projections only: no PHP/Astro/JS view may calculate or round candidate scores, keep assignment authority in hidden DOM attributes, post score strings as facts, infer availability/conflict badges, or carry caregiver ids into conversion/save without a backend draft revision and command result. Suggested backend feature:PreReservationCaregiverAssignmentDraftCommand. -
SFC-20260708-CUR-100Caregiver monthly working-day register and attendance reconciliation authority. Legacy admin working-day entry is a caregiver capacity and audit fact, not a DataTables-only maintenance screen. The browser opens the edit modal from a hiddendata-manager-id, reads a freeform monthly working-day count from an<input type="number">, posts caregiver id, value, year, and month directly to/managerworkingday/update, and the controller/model upsertMANAGER_WORKING_DAY_TB.VALUEforMANAGER_ID_FK + DATEwhile the table also displays attendance-count comparison fromMANAGER_ATTENDANCE_TB. Evidence:source-refs/sanmopia-admin/application/views/manager_working_day/index.php:160-172,source-refs/sanmopia-admin/static/js/manager_working_day/index.js:140-180,source-refs/sanmopia-admin/application/controllers/ManagerWorkingDay.php:58-75,source-refs/sanmopia-admin/application/controllers/ManagerWorkingDay.php:137-174, andsource-refs/sanmopia-admin/application/models/Manager_working_day_model.php:9-11,source-refs/sanmopia-admin/application/models/Manager_working_day_model.php:121-133,source-refs/sanmopia-admin/application/models/Manager_working_day_model.php:156-180. Target:caregiver_assignment / CaregiverMonthlyWorkCapacityRegister,care_delivery / CaregiverAttendanceCountEvidence,caregiver_performance_recognition / CaregiverWorkCapacityComparisonSnapshot, andsecurity_audit / CaregiverWorkCapacityRevisionAudit. Status:Partial; backend commit0273986adds the DDD/application contract foundation forCaregiverMonthlyWorkCapacityRegister. It ownsRecordCaregiverMonthlyWorkCapacityCommand,GetCaregiverWorkCapacityComparisonQuery,CaregiverMonthlyWorkCapacityRevisionStore,CaregiverAttendanceCountEvidenceStore,CaregiverWorkCapacityComparisonSnapshotStore, andCaregiverWorkCapacityRevisionAuditStore, keyed by caregiver profile, branch profile, year-month, previous/current capacity value, attendance evidence revision, actor/reason, expected revision, and idempotency key. The contract rejects source UI fields such asmanagerId,value,yearMonth,draw, andorder; stale revisions are rejected before persistence; comparison snapshots emit assignment optimizer, caregiver payout, performance scorecard, and attendance-evidence invalidation keys. Backend commit34a747dadds runtime persistence with service-role-only Supabase tables:sanmopia_caregiver_attendance_count_evidences,sanmopia_caregiver_monthly_work_capacity_revisions,sanmopia_caregiver_work_capacity_comparison_snapshots, andsanmopia_caregiver_work_capacity_revision_audits. Adapter classes implement the four application stores with Pydantic row validation at the infrastructure boundary while the domain remains Pydantic-free. Stage verification applied migration20260708201929_caregiver_monthly_work_capacity_register_runtime.sql, confirmed all four tables have RLS enabled and grant onlyservice_role, and ran a rollback smoke through attendance evidence -> capacity revision -> comparison snapshot -> audit. Backend commit5f97948adds the operator API gate and bindsCaregiverMonthlyWorkCapacityRegisterApito Supabase Auth and SpiceDB: capacity writes require branchmanage, comparison reads require branchview, and the access-token actor must match the command actor before any store write. Backend HTTP follow-up addsPOST /caregiver-monthly-work-capacitiesandGET /caregiver-monthly-work-capacity-comparisons/{caregiverProfileId}/{year}/{month}with FastAPI OpenAPI publication, camelCase strict request payloads, bearer auth, SpiceDB permission mapping, and rejection of UI-only fields such asmanagerId. Targeted proof:caregiver_monthly_work_capacity_register_api_test.py,caregiver_monthly_work_capacity_register_http_test.py, Ruff, Tach, and Vulture high-confidence scans. Remaining work: attendance-count evidence producer integration, frontend/admin projection rendering, and reservation/settlement E2E inclusion. 2026-07-09 source-mining follow-up: no downstreamMANAGER_WORKING_DAY_TBconsumer was found outside the manager-working-day controller/model; downstream product, performance, and report paths readMANAGER_ATTENDANCE_TBindependently. Attendance rows drive product-coupon reset actual-service counts (source-refs/sanmopia-admin/application/models/Coupon_model.php:72-76), WinTheRace/recognition attendance score and referral thresholds (source-refs/sanmopia-admin/application/models/Win_the_race_model.php:184-190,source-refs/sanmopia-admin/application/models/Win_the_race_model.php:197-210,source-refs/sanmopia-admin/application/models/Win_the_race_model.php:229-263,source-refs/sanmopia-admin/application/models/Win_the_race_model.php:269-287,source-refs/sanmopia-admin/application/models/Win_the_race_model.php:500-564,source-refs/sanmopia-admin/application/models/Win_the_race_model.php:610-655), score rebuild stored-procedure replay (source-refs/sanmopia-admin/application/controllers/cli/Manager.php:269-278), manager report-date display seeding (source-refs/sanmopia-admin/application/models/Manager_model.php:970-979), and one-off attendance repair from service-date rows (source-refs/sanmopia-admin/application/models/Manager_model.php:2498-2520). Direct payout formula evidence checked insource-refs/sanmopia-manager/application/helpers/salary_helper.php:69-73andsource-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:17-22reads plannedSERVICE_DAY, notMANAGER_WORKING_DAY_TBor attendance count. Modern boundary: capacity-register writes must emit comparison and invalidation facts only;ActualServiceAttendanceCountProjection,PerformanceRecognitionAttendanceScoreSnapshot,CaregiverReportDateEvidenceProjection, andCaregiverAttendanceCorrectionown downstream attendance facts. Frontend/admin must render backend projections only: no PHP/Astro/JS view may treat hidden caregiver ids, freeform monthly counts, DataTables search/order fields, or attendance-count deltas as assignment, payout, performance, or audit authority. Suggested backend feature:CaregiverMonthlyWorkCapacityRegisterCommand. -
SFC-20260708-CUR-101Customer web session recovery and booking/payment actor binding. Legacy customer web APIs treat CodeIgniter session state and a long-lived encryptedAUTH_TOKENcookie as the actor source for reservation creation, payment, service-balance, and change-payment actions.Authlibstores short session keys (ilg,at,sy,is), restores login from thesystay cookie, looks upUSER_TB.AUTH_TOKEN, redirects when social profile data is incomplete, and booking/payment controllers compareUSER_ID_PKto mutable reservation rows before deciding whether an action may proceed. Evidence:source-refs/sanmopia_web/application/libraries/Authlib.php:7-12,source-refs/sanmopia_web/application/libraries/Authlib.php:57-72,source-refs/sanmopia_web/application/libraries/Authlib.php:75-104,source-refs/sanmopia_web/application/libraries/Authlib.php:107-129,source-refs/sanmopia_web/application/libraries/Authlib.php:140-170,source-refs/sanmopia_web/application/libraries/Authlib.php:187-192,source-refs/sanmopia_web/application/models/User_model.php:47-64,source-refs/sanmopia_web/application/core/MY_Controller.php:61-72,source-refs/sanmopia_web/application/controllers/api/Service.php:5-10,source-refs/sanmopia_web/application/controllers/api/Service.php:18-25,source-refs/sanmopia_web/application/controllers/api/Service.php:206-215,source-refs/sanmopia_web/application/controllers/api/Service.php:279-293,source-refs/sanmopia_web/application/controllers/api/Service.php:683-697,source-refs/sanmopia_web/application/controllers/api/Payment.php:79-108,source-refs/sanmopia_web/application/controllers/api/Payment.php:340-349,source-refs/sanmopia_web/application/controllers/api/Payment.php:526-532, andsource-refs/sanmopia_web/application/controllers/api/Payment.php:693-703. Target:member_management / CustomerAuthenticatedSessionProjection,member_management / CustomerAccountLinkProof,reservation_orchestration / BookingWorkflowActorContext,pricing_settlement / PaymentActorContext, andsecurity_audit / CustomerSessionRecoveryAuditEvent, andreservation_operations / ReservationBookingPartyAuthorityBinding. Status:Partialas of backend35f67ff912d32c92e4772e60895bf1da45014437. Member Management now ownsCustomerAuthenticatedSessionProjectionandCustomerAccountLinkProof; P04 reservation creation and booking identity consume that shared proof and reject member/profile drift. Pricing Settlement now resolves a typedPaymentActorContextfrom the same proof, freezes account/profile/revision lineage into the immutable payment actor snapshot, and no longer requires a mutable generic mother-role row for direct mother payment. The service-role-only Supabase RPC was applied through the repository CLI against a disposable full migration chain, returned the exact closed account link, deniedanon/authenticated, and rejectedwithdrawal_pending. Security Audit now ownsCustomerSessionRecoveryAuditEvent; P04 emits success with exact draft revision and seven closed denial reasons. The application hashes actor/draft references before persistence, and the forced-RLS append-only table contains no bearer, access token, resume key, raw actor subject, or raw draft reference. Actual disposable DB verification proved service-role exactINSERT+SELECT, update/truncate and anon/authenticated denial42501, privileged immutable trigger55000, and forbidden raw columns0. Reservation Operations now freezes the direct mother’s mother/booker/payer authority, account-link evidence, accepted draft/review lineage, and expected new-booking revision1in an append-only snapshot written atomically with booking/payment. Public input cannot submit the binding. Actual disposable DB verification proved exact replay, drift/stale40001, full rollback, immutable55000, and service-role-only ACL. Full backend regression is7028 passed; Tach exact/external are clean and Vulture confidence 100 found no changed-path candidates. This is distinct from customer support impersonation (SFC-20260706-CUR-012) and caregiver persistent session (SFC-20260706-CUR-008). Backend must derive booking/payment actor context from Supabase Auth plus a backend-owned customer account link, active profile readiness, reservation-party authority, and expected reservation revision, and must emit the backend-owned recovery audit. SourceAUTH_TOKEN, CI session keys, long-lived web cookies, rawUSER_ID_PK, social-profile redirect branches, Korean status strings, and browser hidden fields are evidence only. Frontend must render backend projections only and pass a bearer session to generated APIs; it must not decide customer ownership, social-profile completeness, reservation submit eligibility, payment eligibility, service-balance access, or settlement continuation readiness from local cookie/session state. Preview/E2E risk: browser booking can reach workflow start but fail progress/payment reads with401, or can target the wrong reservation, unless the backend owns the customer-account link and actor-context proof before reservation-to-settlement workflows start. Still missing: a current-pin browser run covering recovery and party binding plus the remaining P04 production-source, legal, readiness, and confirmation gates. No new actor browser, screenshot, animated WebP, stage, or deploy proof was produced by this increment. Suggested backend feature:CustomerBookingPaymentActorContextCommand.
2026-07-09 persistent legacy-mining status refresh
Section titled “2026-07-09 persistent legacy-mining status refresh”No new feature ids are added here; the rows below attach additional source evidence and backend-owned rules to already-listed checklist owners so the checklist does not duplicate SFC entries.
-
CaregiverMatchingProfileRevisionand matching-candidate input facts. Existing owner rows: caregiver matching preference/profile checklist row,SFC-20260708-CUR-084, andSFC-20260708-CUR-089. Status:Partial. Backend foundation exists for caregiver profiles and assignment analysis, but legacy manager self-service profile writes are not yet proven as imported, versioned, optimizer-visible profile revisions. Evidence:source-refs/sanmopia-manager/application/controllers/Matching.php:43-65posts pet allergy/type/size/count/isolation, religion, ranked service preference, and personality values;source-refs/sanmopia-manager/application/models/Matching_model.php:140-186inserts or updatesMANAGER_MATCHING_INFO_TB;source-refs/sanmopia-manager/application/models/Matching_model.php:188-260rewrites ranked service preference rows by fixed sequence; andsource-refs/sanmopia-manager/application/models/Matching_model.php:263-304deletes and reinserts personality-by-manager rows. Backend rule: these mutable manager tables are source evidence only. Modern matching must persist versioned profile revisions, catalog references, approval/source surface, and optimizer invalidation before any reservation assignment, payout, or branch coverage projection uses the data. -
ServiceSuspensionRequest/ holiday-or-service-pause financial invalidation. Existing owner rows: service suspension workflow rows plusSFC-20260708-CUR-065andSFC-20260708-CUR-067. Status:Partial. Backend-side status and projection foundations exist, but the customer web-originated stop/pause request, branch notification, and downstream refund/settlement/payout invalidation are not yet E2E-proven. Evidence:source-refs/sanmopia_web/static/js/mypage/reservation.js:326-365posts a cancel/stop/change request with reservation id and freeform reason;source-refs/sanmopia_web/application/controllers/api/Reservation.php:86-139validates the logged-in customer and dispatches the stop command branch;source-refs/sanmopia_web/application/models/Reservation_model.php:1091-1111flips reservation status toRESERVATION_STATUS_STOP_REQand writesRESERVATION_REQUEST_TB; andsource-refs/sanmopia_web/application/controllers/api/Reservation.php:192-208sends branch notifications, including a special secondary recipient branch path. Backend rule: pause/stop is not a UI status flip. It must be a command with actor proof, expected reservation revision, notification dispatch audit, and explicit recalculation/invalidation facts for refund, coupon, service occurrence, caregiver payout, branch settlement, and archive views. -
ServiceAreaCoverageDecisionand branch coverage profile import. Existing owner rows: branch service-area decision snapshot, coverage profile, and branch coverage override checklist rows. Status:Partial. Backend coverage concepts exist, but the legacy possible/consultation/impossible area precedence and special address matching still need import provenance and booking/matching E2E proof. Evidence:source-refs/sanmopia_web/application/models/Branch_model.php:38-89matches branch area by address levels and area type;source-refs/sanmopia_web/application/models/Branch_model.php:93-140applies impossible-area veto checks before returning a branch; andsource-refs/sanmopia-admin/application/models/Branch_model.php:337-425writes possible, consultation, and impossible service-area rows while requiring consultation/impossible areas to be nested under an existing possible area. Backend rule: modern booking and matching must consume a versionedServiceAreaCoverageDecisionprojection, not live branch tables or UI-side address heuristics; unavailable/impossible veto must outrank consultation and available coverage in backend policy. -
SettlementArchiveRequestand branch/head-office approval provenance. Existing owner rows:SFC-20260709-CUR-103,SFC-20260708-CUR-088, andSFC-20260708-CUR-098. Status:Partial. Branch/HQ settlement board and approval vocabulary are represented, but archive/export UX still needs frozen-dataset grants, actor-bound artifact requests, and imported mutation provenance for legacy settlement actions. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:150-312accepts posted reservation/coupon ids, totals, branch flags, membership/cancel coupon fields, and actor type for branch-to-head-office settlement actions;source-refs/sanmopia-admin/application/controllers/Calculate.php:315routes the settlement data room; andsource-refs/sanmopia-admin/application/controllers/Calculate.php:568-578exports spreadsheets from raw board id and excel type inputs. Backend rule: export/download and approval screens must be read-only artifact projections over frozen settlement statements. Posted totals, board ids, excel type, and legacy login type are migration evidence only; modern actions require SpiceDB-backed actor grants, expected statement revision, immutable action journal, and export artifact audit. -
Provider-success/local-write-failure refund repair and partial refund proof. Existing owner rows: virtual-account/payment lifecycle and provider compensation rows from the 2026-07-09 checklist refresh. Status:
Partialafter runtime KillBill paid-webhook workflow-start failure now persists a provider attempt and compensation intent, and/internal/payment-refund-repairs/provider-refund-plansnow persists the repair plan. Backend also exposes/internal/payment-refund-repairs/provider-refund-executions, calls the configured Kill Bill gateway throughPaymentGatewayClient.refund, and persists execution attempts insanmopia_payment_refund_repair_execution_attempts, then records accepted or rejected repair execution results throughProviderRefundResultFromLedgerHandler. StillMissingfor retry/result history hardening, live Kill Bill-originated callback proof, same-id conflict quarantine, and operator repair projection. Synthetic ExtBusEvent stage callback/queue/ledger wiring now passes. Backend rule remains unchanged: provider success paired with local write failure must persist a provider attempt, compensation intent, refund repair plan, execution attempts, retry/result history, and operator-visible projection before settlement can treat the reservation as financially closed. UI/PHP refund buttons, provider callbacks, Korean status strings, and manual amount fields are evidence only; backend owns refund, partial refund, custom charge, discount, and settlement impact calculation.
2026-07-10 Branch/Admin Analytics Workflow Refinement
Section titled “2026-07-10 Branch/Admin Analytics Workflow Refinement”No new SFC ids. These refine existing branch-operations and business-reporting owner rows without entering the settlement data-room lane.
-
BranchProfileRevisionand settlement-facing branch facts. Existing owner rows:branch_operations / office_profile,operator_access / branch_login_audit,BranchCoverageDecision,SettlementRemittanceAccountSnapshot, andBranchMembershipDueAcknowledgementPolicy. Status:Partial. Evidence:source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:407-432posts branch identity, membership fee, office status, password, and primary / secondary remittance accounts from one admin form;source-refs/sanmopia-admin/application/models/Branch_model.php:207-242writes the mutable branch profile, account, password, and status fields;source-refs/sanmopia-admin/application/models/Branch_model.php:261-285computes the current membership month key from server date and overwrites the branch membership fee row;source-refs/sanmopia-admin/application/models/Branch_model.php:345-426maps possible/consult/impossible area strings and rejects subordinate coverage rows when no possible area exists; andsource-refs/sanmopia-admin/application/models/Branch_model.php:435-517plussource-refs/sanmopia-admin/application/models/Branch_model.php:526-606overwrite or delete branch profile/stamp files and service-area rows. Backend rule:branch_operationsowns revisioned branch profile, service-area, and brand-asset commands;operator_accessowns credential rotation;pricing_settlementowns membership-fee schedules and remittance account snapshots;document_reportingconsumes branch brand-asset snapshots. UI/PHP must not calculate membership period keys, decide coverage hierarchy, rotate credentials, or mutate settlement-facing remittance/brand facts without expected revision, reason, and audit. -
AdminRevenueStatisticsProjectionand mutable paid-row report formulas. Existing owner row:business_reporting / admin_analytics_catalog. Status:Partial. Evidence:source-refs/sanmopia-admin/application/controllers/Statistics.php:433-453issues separate total/government-fee/coupon/offline metric requests;source-refs/sanmopia-admin/application/models/Statistics_model.php:1070-1182groups sales by deposited date and computes total, offline, government, fee, and coupon amounts with hardcoded service-type/status branches;source-refs/sanmopia-admin/application/models/Statistics_model.php:1812-1856joins mutable paid rows, coupon rows, and fee SQL functions to calculate revenue;source-refs/sanmopia-admin/application/models/Statistics_model.php:1860-1948builds branch/product/work-style counts and sums using string comparisons, status filters, and branch exclusions; andsource-refs/sanmopia-admin/static/js/statistics/sales.js:630-685plussource-refs/sanmopia-admin/static/js/statistics/sales.js:1153-1168request chart/table datasets and combine totals client-side. Backend rule:business_reportingneeds versioned metric definitions and projection refresh jobs keyed by payment/refund/closeout/settlement invalidation.pricing_settlementsupplies immutable paid-row, fee, coupon, and refund facts. UI/PHP must not infer sales eligibility, additional/offline buckets, product/work-style buckets, fee totals, or branch exclusions from mutable reservation/payment rows.
2026-07-10 Settlement/Data-Room Operator Workflow Refinement
Section titled “2026-07-10 Settlement/Data-Room Operator Workflow Refinement”No new SFC ids. These refine existing settlement/data-room owners only:
SFC-20260708-CUR-088, SFC-20260708-CUR-098,
SFC-20260709-CUR-103, settlement data-room worklist rows, and data-room
mailbox rows.
-
SettlementDataRoomWorklistSnapshot,ReservationDocumentBundleSelectionGrant, andSettlementDataRoomFilterStateToken. Status:Partial. Evidence:source-refs/sanmopia-admin/application/controllers/DataRoom.php:30-83accepts GET branch/date filters into the form-list page;source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:17-64accepts branch/date/form/table parameters;source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:91-130chooses eligible statuses and service/document filters;source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:132-240performs search, sort, and paging in PHP memory; andsource-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:1-47preserves branch filter in URL hash and posts raw filters to AJAX. Backend rule: data-room worklists need persisted filter snapshot, actor scope, SQL-backed page cursor, selected reservation tokens, and return-state token. Hash state, raw branch ids, DataTables order columns, and PHP-memory result slicing are migration evidence only. -
AllDocumentBundlePolicyandReservationDocumentSelectionConflictDecision. Status:Partial. Evidence:source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:62-87treats integrated document form16as single-select only in browser code and posts hiddenreservation[service_type];source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:219-246submits selected reservations through a hidden iframe; andsource-refs/sanmopia-admin/application/controllers/DataRoom.php:311-386trusts posted reservation ids/service type, chooses voucher vs normal bundle from the first selected reservation, then calls spreadsheet rendering. Backend rule: bundle policy must enforce single-vs-multi selection, homogeneous service type, document eligibility, expected worklist revision, and artifact request id. UI-hidden service-type values and iframe posts cannot choose printable document sets. -
BranchDocumentMailboxPostRevisionandDocumentAttachmentVersionGrant. Status:Mapped/Partial. Evidence:source-refs/sanmopia-admin/application/controllers/DataRoom.php:97-197routes other-post view/list/write/submit/delete from board type, branch ids, uploaded attachment names, and posted delete-file ids;source-refs/sanmopia-admin/application/models/Data_room_model.php:25-80applies branch-36/headquarters/null-branch send/receive visibility rules;source-refs/sanmopia-admin/application/models/Data_room_model.php:105-184updates or inserts posts, uploads files, deletes selected file rows, then deletes physical files; andsource-refs/sanmopia-admin/application/models/Data_room_model.php:189-202deletes a post and physical upload directory by post id. Backend rule: mailbox actions need post revision, participant branch snapshots, attachment version ids, delete/revoke grants, actor permission, and immutable audit. Posted branch ids, fixed-post flags, mutable file URLs, and physical delete side effects are source evidence only. -
SettlementStatementRevisionConflictDecisionandSettlementBoardActionJournal. Status:Partial. Evidence:source-refs/sanmopia-admin/application/controllers/Common.php:80-130rebuilds a branch/HQ settlement detail page from GET year/month/branch and current board status;source-refs/sanmopia-admin/static/js/calculate_detail.js:80-170collects checked normal/voucher/coupon/reservation ids into posted arrays;source-refs/sanmopia-admin/static/js/calculate_detail.js:930-1144recomputes delivery, membership, coupon-fee, manual-etc, and result totals in browser state;source-refs/sanmopia-admin/application/controllers/Calculate.php:150-272accepts posted totals, flags, board id, data type, and manual lines;source-refs/sanmopia-admin/application/controllers/Calculate.php:245-270andsource-refs/sanmopia-admin/application/controllers/Calculate.php:279-309callinsertLogduring HQ confirmation/rejection and branch acknowledgement;source-refs/sanmopia-admin/application/models/Payment_model.php:25-31logs before/after values plus branch id but ignores the passed board id; andsource-refs/sanmopia-admin/application/models/Payment_model.php:2977-3031changes board status from mutable board/component flags without expected statement revision. Backend rule: request, acknowledgement, arrears replay, and completion need expected statement revision, frozen line ids, component-level acknowledgements, actor grant, idempotency key, and conflict decision.SettlementTransitionAudit,SettlementApprovalProvenanceSnapshot, andRefundRepairSettlementImpactJournalmust link branch/HQ/Danbee approvals to the exact statement revision and downstream artifact supersession/grant revocation. Browser totals and board-id status switches are not authority. -
SettlementArtifactBuildRunLedgerandSettlementExportDatasetRevision. Status:Partial. Evidence:source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:43-60andsource-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:29-49expose board ids anddata-typethrough detail buttons;source-refs/sanmopia-admin/static/js/data_room/calculate_central.js:10-14andsource-refs/sanmopia-admin/static/js/data_room/calculate_danvi.js:10-14navigate by raw board id;source-refs/sanmopia-admin/application/controllers/Calculate.php:568-578exports by GETexcelTypeandboardId; andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3911reloads mutable board rows, recalculates coupon payment-method fees in the renderer, writes spreadsheet formulas, streams tophp://output, and exits. Backend rule: settlement exports need frozen dataset revision, formula policy version, line checksums, render attempt, artifact checksum, signed grant, and revocation/reissue history after refund or board repair. 2026-07-10 grant-linkage refinement: after refund or repair, backend3e6d83fworkspace-domainSettlementWorkspace.request_repairnow revokes activeSettlementArtifactGrantrecords for the invalidated artifact version and recordsrevoked_grant_idsplusreplacement_artifact_request_codeon the repair request. 2026-07-10 Supabase adapter follow-up proves saved workspace JSON rows round-trip grant revocation and repair lineage. Remaining migration must stage-prove that path, then operator-projectSettlementArtifactReplacementRequestLinkfrom superseded artifact id to replacement artifact request id. Source export streams directly from mutable board rows and document selections, so it has no durable artifact, grant, or replacement boundary. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:568-578,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3911,source-refs/sanmopia-admin/application/controllers/DataRoom.php:85-94, andsource-refs/sanmopia-admin/application/controllers/DataRoom.php:312-376. -
PrintableDocumentArtifactBuildRunandDocumentTemplateVersionManifest. Status:Partial. Evidence:source-refs/sanmopia-admin/application/controllers/DataRoom.php:85-95exposes rawexcelTypeand reservation-id export;source-refs/sanmopia-admin/application/controllers/DataRoom.php:311-386posts selected reservation ids into document download;source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-4198renders documents from live reservation/report rows, copies static PDFs into temp paths, writes XLSX temp files, zips them, deletes temp files, and streams output; andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4028-4050chooses daily-report first/middle/last artifacts from current report rows, service end date, and stop-day lookup. Backend rule: document generation needs template manifest version, source projection revision, report finality decision, build-run ledger, artifact retention policy, and signed download grant. Runtime temp files and live read-time document selection are source evidence only.
2026-07-10 Reservation-To-Settlement Source Authority Consolidation
Section titled “2026-07-10 Reservation-To-Settlement Source Authority Consolidation”No new SFC ids. These entries consolidate source evidence under existing owner rows instead of duplicating service-calendar, pricing, caregiver, and settlement checklist items. Each item is a backend-authority migration requirement; UI/PHP calculations are evidence only.
| Legacy evidence path | Modern ubiquitous name | Target bounded context / feature slice | Backend authority rule | Implementation status | Verification gap |
|---|---|---|---|---|---|
source-refs/sanmopia_web/static/js/basePrice.js:1-170 and source-refs/sanmopia_web/static/js/basePrice.js:185-360 hardcode service duration choices, caregiver salary, government support, and mother payable by child/service category in browser JavaScript. | ServiceOfferingCatalogRevision, CaregiverCompensationRateCatalog, MotherVisibleChargeCatalogSnapshot | pricing_settlement / product_catalog, pricing_settlement / caregiver_compensation, reservation_operations / quote_projection | Supabase-backed catalog revisions must own service duration, government support, customer-payable, and caregiver-compensation rate rows. Reservation UI and legacy import adapters may render or cite catalog snapshots, but must not embed wage/support/payable matrices. | Partial; product pricing and finalized charge snapshot foundations exist. Backend 7f8ca36 adds BasePriceCatalogMatrixParser, converting legacy basePrice.js matrix cells into versioned PriceCatalogEntry rows with canonical birth-multiplicity, child-order, benefit-type, regional-support, caregiver-compensation, government-support, and mother-visible-charge components. Supabase persistence can reuse the existing price catalog import repository. | Run/import full basePrice matrix into versioned catalog tables, quote a reservation from catalog revision only, generate caregiver payout from the same revision, and prove branch/HQ settlement consumes frozen charge and compensation lines rather than JS/PHP arrays. |
source-refs/sanmopia_web/static/js/step3_normal.js:86-110 branches a continuation booking into smart matching or review based on returned flags and routes the browser accordingly; source-refs/sanmopia_web/static/js/step3_normal.js:127-145 multiplies selected baby-option price by service day before rendering added charges. | ReservationContinuationHandoffDecision, MatchingRequirementDecision, AdditionalCareOptionChargeLine | reservation_operations / continuation_booking, caregiver_assignment / matching_requirement, pricing_settlement / reservation_charge_lines | Backend must return a frozen continuation handoff with matching requirement, copied-fact audit key, caregiver carryover decision, and charge-line snapshot. Browser route choices and option amount math are projection data only. | Partial; continuation link and service-calendar facts exist, but all customer/admin continuation paths still need binding to backend handoff and catalog-backed added-charge projection. | E2E continuation proof for same-caregiver available/unavailable, smart-matching-required, added baby-option charge line, and settlement/payout invalidation from the accepted continuation plan. |
source-refs/sanmopia-manager/application/views/schedule/schedule_info.php:136-203 lets the caregiver-facing schedule view decide service-balance command availability, recalculate Saturday/holiday/add-on balances, add normal-service balance, include voucher add price, and divide the result across assistant caregivers. | CareTeamServiceBalanceShareProjection, CareManagerServiceBalanceAcknowledgementProjection, SubCaregiverServiceBalanceReceiptSlot | pricing_settlement / service_balance_closeout, caregiver_compensation / care_team_receipts, operator_access / caregiver_account_disclosure | Backend must compute main/assistant service-balance shares from finalized charge snapshot, occurrence ledger, care-team roster revision, and receipt state. Caregiver UI may request acknowledgement/disclosure commands with grants, but must not recalculate balance shares or command availability. | Partial; backend fbc60e4 reads frozen closeout, receipt-state, and payout-instruction facts into the caregiver work-schedule projection, supports a versioned equal-slot policy for multiple caregivers, and provides reservation-scoped lookup. Stage reservation 0b57b5f1-12c5-42f0-bcdf-7ab90e469a8b reached settled with a frozen 25,000 KRW share. Backend 65a71ac materializes accepted assignment decisions into sanmopia_reservation_caregiver_assignments, including resolved profile/auth identity, grade, occurrence-ledger day count, booking dates, slot identity, and assigned/replaced/removed lifecycle. Stage reservation 5dd549d3-6c2c-407c-b42a-fdcd7e769c6a persisted the roster before payout and reached settled. | Prove decision persistence and projection cannot strand divergent state: add durable retry/repair and idempotent replay for projection failure, then backfill and reconcile older accepted decisions against materialized roster rows before downstream payout/settlement use. |
source-refs/sanmopia_web/static/js/priceList.js:8-43 hardcodes public option prices by service type; source-refs/sanmopia_web/static/js/menu/feeguide.js:1-83 hardcodes voucher fee year suffixes and image filenames; source-refs/sanmopia_web/application/views/about/fee_table.php:57-95 embeds one-week public service and Saturday prices directly in markup. | PublicFeeGuideCatalogProjection, PublicServiceFeeQuotePreview, PublicFeeGuideArtifactCatalog | pricing_settlement / public_fee_guide_catalog, pricing_settlement / product_catalog | Backend must publish effective-dated public fee rows, option prices, voucher artifact mappings, and display-period metadata. Public UI may render a catalog projection, but must not decide price/version/image path from JavaScript constants, static markup, or filename conventions. | Partial; public fee guide is listed as a migration owner, but exact legacy hardcoded option-price and image-catalog evidence still needs import/backfill proof. | Seed/import public fee guide catalog rows for normal/special/in-home and voucher image artifacts, expose a read projection for the public guide, and prove customer quote/payment uses the same catalog revision instead of separate browser constants. |
source-refs/sanmopia_web/application/views/service/step3_selecttype.php:58-94 hides or shows pre-reservation and in-home service cards from delivery timing, reservation status, baby count, and price version; source-refs/sanmopia_web/application/views/service/step3_selecttype.php:107-119 routes continuation bookings around caregiver search; source-refs/sanmopia_web/application/views/service/step3_selecttype.php:232-236 leaves a price-table-change pre-reservation shutdown alert as commented UI policy; source-refs/sanmopia_web/static/js/step3_selecttype.js:23-31 sends pre-reservation directly to a payment route with year-boundary warning copy. | ReservationServiceOfferingAvailabilityDecision, ServiceOfferingShutdownWindow, PreReservationConversionEligibilityProjection, ReservationCreationHandoffProjection | reservation_catalog / service_offering_availability, reservation_operations / reservation_creation, pricing_settlement / price_catalog_version_policy | Backend must decide service offering availability, pre-reservation-only windows, triplet/quadruplet in-home exclusion, continuation route, and year-boundary voucher ambiguity from versioned catalog/policy facts. UI may render allowed actions and message keys only; view continue, raw status ids, and ad-hoc comments are source evidence only. | Partial; backend 86b9fe9 adds ReservationServiceOfferingAvailabilityPolicy, ReservationServiceOfferingCandidate, ReservationServiceOfferingEvaluationContext, ServiceOfferingShutdownWindow, ReservationCreationHandoffKind, and Pydantic contract payloads. Backend d386524 exposes bearer-protected POST /reservation-service-offering-availability-decisions, wires it into main.py, and returns backend-owned availability state, handoff kind, unavailable reason codes, message keys, policy revision, and source evidence. Backend 77547ef adds POST /reservation-service-offering-availability-decision-sets, a Supabase-backed catalog reader over care service catalog offerings and policy attachments, and focused tests for catalog-loaded candidates and shutdown windows. Backend 3b32580 carries accepted service-offering decisions into reservation booking HTTP/API/workflow input, rejects unavailable accepted decisions before booking/payment, freezes the decision payload for workflow audit, and adds Tach module edges for the service-offering domain feature. Backend 28d858c rejects accepted price quotes whose entry code is not bound to the accepted service-offering key and rejects price-quote service_day_count when it conflicts with the accepted service-term base day count. Tests now cover birth-lead-time pre-reservation availability, after-birth rejection, voucher direct-service blocking during pre-reservation window, triplet/quadruplet in-home exclusion for catalog version 2+, continuation handoff around caregiver search, year-boundary shutdown message keys, HTTP auth, route response shape, catalog-backed decision-set response shape, command rejection of unavailable offering decisions, workflow payload freezing, quote/offering mismatch rejection, and quote/service-term day-count mismatch rejection. | Make accepted service-offering decision mandatory for booking once Astro consumes backend decision sets, bind add-option/rental selection revisions to the same accepted offering and charge snapshot, and prove Astro reservation card E2E consumes backend decision sets instead of static route/card visibility. |
source-refs/sanmopia_web/application/controllers/Service.php:370-388 chooses normal working type and loads add-option catalog rows from the reservation price version; source-refs/sanmopia_web/application/models/Reservation_model.php:1814-1838 indexes normal add-option prices by WORKING_TYPE_LIST_ID_FK; source-refs/sanmopia_web/application/views/service/step3_normal.php:521-538 renders one-hour 시간추가 quantity and price from $addOptionData["시간추가"][$workId]; source-refs/sanmopia_web/application/views/service/step3_voucher.php:591-614 hides the added-hour selector for in-home voucher service but renders it for commute voucher service; source-refs/sanmopia_web/static/js/step3.js:742-764 multiplies added-hour price by selected hour quantity and getServiceDay() in browser JavaScript. | ServiceWorkingTimeProfile, AdditionalServiceTimeChargeLine, CaregiverWorkingWindowPolicy | reservation_catalog / service_working_time_policy, pricing_settlement / reservation_charge_lines, caregiver_assignment / caregiver_availability | Backend must own working-time eligibility, added-hour quantity bounds, service-type exclusions, catalog-backed added-hour unit price, service-day multiplier, and downstream quote/payment/payout/settlement impact. UI may render backend-projected selectable quantities and charge lines only; browser timeInput.data("price") * quantity * getServiceDay() is source evidence, not authority. | Partial; service-calendar and charge-snapshot foundations exist, but added-hour working-time profile parity is not separately proven as catalog-backed backend policy. | Add tests for normal commute/in-home and voucher commute/in-home eligibility, tampered added-hour quantity rejection, added-hour charge equals backend catalog unit price times frozen service-day count, and accepted added-hour line invalidating caregiver payout plus branch/HQ settlement projections from the same frozen charge snapshot. |
source-refs/sanmopia_web/application/controllers/api/Service.php:335-414 accepts voucher add-option ids and quantities from the posted form, mutates Wanju service days by +5, counts posted Saturday/holiday arrays into option quantities, then stores browser reservation[endDate]; source-refs/sanmopia_web/application/controllers/api/Service.php:456-524 does the same for normal service and directly inserts posted add_option_baby; source-refs/sanmopia_web/application/models/Reservation_model.php:552-564 and source-refs/sanmopia_web/application/models/Reservation_model.php:698-710 insert add-option id plus quantity without proving the row belongs to the selected service offering, working type, price version, or allowed quantity set; source-refs/sanmopia_web/static/js/step3.js:613-640 computes effective service days in the browser, source-refs/sanmopia_web/static/js/step3.js:480-560 renders Saturday/holiday prices from browser-side counts, source-refs/sanmopia_web/static/js/step3.js:713-731 multiplies child-option price by selected quantity and effective service days, and source-refs/sanmopia_web/static/js/step3.js:767-832 totals those DOM rows before payment review; source-refs/sanmopia_web/application/controllers/api/Service.php:705-759 later chooses consultation/payment handoff and writes voucher live-in/special service-balance left price from the mutable current price table; source-refs/sanmopia-admin/application/models/Reservation_model.php:194-229 reattaches mutable add-option rows and derived PRICE_TABLE for admin/export use; source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:417-465 and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:728-748 render add-option charge rows into service-use/downpayment document artifacts from PRICE_TABLE strings and current option labels. | ReservationAddOptionSelectionRevision, ReservationSubmissionIntegrityGuard, ReservationPaymentSettlementHandoffSnapshot, CaregiverPayoutChargeImpactSnapshot, ReservationChargeDocumentSnapshot | reservation_operations / reservation_submission, pricing_settlement / reservation_charge_lines, caregiver_compensation / payout_projection, branch_settlement / settlement_seed_projection, document_reporting / reservation_charge_artifact_projection | Backend must validate every submitted add-option id against selected offering, working-type profile, price catalog revision, regional-benefit decision, and allowed quantity policy; recompute selected-day counts and end date from occurrence facts; freeze canonical charge lines before payment handoff; and publish the same charge-snapshot references to caregiver payout, branch/HQ settlement seeds, and document artifact build inputs. UI/PHP/renderers may submit user intents or render backend projections only, never authoritative option ids, service-day multipliers, end dates, settlement-bearing service-balance amounts, parsed display strings, or mutable option labels. | Partial; service-calendar plans, finalized charge snapshots, service-balance closeout references, and added-hour policy gaps are mapped. Backend ed16356 now rejects booking service-term side effects unless the command carries accepted price quote, accepted service-offering availability decision, and accepted service-term plan, so add-option/service-term side effects cannot enter booking from standalone UI payloads. Backend 836d3ba now rejects add-option charge links whose charge component code is absent from the accepted quote lines. Backend 06adfba now rejects selected add-option keys or add-option charge-link selection keys that are absent from the accepted backend service-term plan. Backend 6685429 now rejects side-effect assemblies that omit chargeable additional service days selected by the accepted backend service-term plan. Backend 1447053 now rejects missing, unselected, or duplicate add-option charge links at command construction before payment approval. Legacy add-option id/quantity submission integrity and direct handoff from accepted selection revision to payout/settlement/document projections still need proof. | Add tests that reject voucher/normal add-option ids from the wrong service type, working type, price version, or branch catalog; reject tampered child/hour quantities and client end date; prove Wanju, Saturday, and holiday counts are recomputed from backend occurrence and regional-benefit facts; assert payment handoff uses the accepted charge snapshot id; and assert caregiver payout, branch/HQ settlement seeds, and printable document artifacts reference the same finalized charge/selection revision after add-option acceptance or repair. |
source-refs/sanmopia_web/application/views/service/step3_normal.php:188-242 and source-refs/sanmopia_web/application/views/service/step3_voucher.php:260-314 render rental goods with posted rental[] ids, browser data-price, a hardcoded 10,000 KRW round-trip delivery notice, and a breast-pump availability warning that depends on branch circumstances; source-refs/sanmopia_web/static/js/step3.js:92-155 and source-refs/sanmopia_web/static/js/step3.js:158-195 add rental item rows and a one-time delivery fee from browser DOM state; source-refs/sanmopia_web/application/controllers/api/Service.php:416-419 and source-refs/sanmopia_web/application/controllers/api/Service.php:531-534 delete and reinsert posted rental ids for voucher/normal booking submissions; source-refs/sanmopia_web/application/models/Reservation_model.php:796-803 inserts those rental ids without catalog/branch/availability proof; source-refs/sanmopia_web/application/models/Reservation_model.php:1231-1259 sums selected rental rows plus DELIVERY_FEE, and source-refs/sanmopia_web/application/models/Reservation_model.php:1318-1348 feeds rental price into voucher service-balance or normal left-price/payment totals; source-refs/sanmopia-admin/application/models/Reservation_model.php:216-229 reattaches current rental rows before deriving PRICE_TABLE; source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:663-709 hardcodes rental item names, breast-pump price, and 10,000 KRW delivery into downpayment artifacts; source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3950-3952 loads all rental catalog rows for document rendering. | ReservationRentalSelectionRevision, RentalEquipmentAvailabilityDecision, RentalDeliveryChargeLine, RentalSettlementImpactSnapshot, RentalDocumentChargeSnapshot | reservation_catalog / rental_equipment_catalog, reservation_operations / reservation_submission, pricing_settlement / reservation_charge_lines, branch_settlement / settlement_seed_projection, document_reporting / reservation_charge_artifact_projection | Backend must validate rental selection ids against effective catalog, branch availability, delivery-fee max-once policy, price revision, and accepted service offering; freeze rental item and delivery charge lines before payment handoff; and publish rental charge references to service-balance closeout, branch/HQ settlement seeds, and document artifact build inputs. UI/PHP/renderers may render selectable rental projections and warnings, but must not decide rental availability, delivery-fee amount, document rental checkmarks, hardcoded rental item prices, or settlement-bearing rental totals from DOM fields or Korean item names. | Partial; immutable rental catalog publication/read boundary and actual HQ administration are complete. Backend 4c9dd40f plus frontend 3dd5779 prove real GoTrue HQ/unauthorized actors, accepted SpiceDB authority, production Supabase/FastAPI/Astro composition, UI publication 5 → 6, exact replay, altered replay rejection with unchanged DB, unauthorized GET/POST 403, append-only revision/supersession/evidence lineage, desktop table/mobile card replacement, and full cleanup without route interception. Backend 7f51408b adds the explicit immutable rental-selection cross-context contract and binds effective catalog facts, accepted offering, branch confirmation, max-once delivery, quote/payable, charge-handoff revisions, accepted booking command, Restate input, and finalized charge policy version. Backend 288e14a7 plus frontend 93b8c2e1 prove an authenticated mother selecting health_cushion_rental through the actual desktop/mobile chat, Supabase draft/materialization, voucher quote with KRW 0 equipment and KRW 10,000 max-once delivery, KRW 210,000 payable, immutable rental catalog/selection handoff hashes, final review 200, edit/reprojection, and actual 422/409/403/401. Unknown/out-of-catalog, duplicate, branch-unconfirmed, offering/amount/pricing-lineage drift, and public contract leakage fail closed. Full Python is 7,087 passed; frontend is 95 files / 592 tests; Tach diagnostics are 0. | Exercise confirmation-ready legal acceptance and actual Supabase booking/payment workflow; publish the frozen selection revision to service-balance closeout, caregiver payout display where applicable, branch/HQ settlement seeds, and printable document artifacts; prove every consumer rejects mutable current-catalog drift and references the same frozen selection revision. |
source-refs/sanmopia_web/application/views/service/reservation_check_data.php:304-334 renders coupon ids as hidden booking-review fields; source-refs/sanmopia_web/application/controllers/api/Service.php:735-739 deletes and reinserts posted normal-reservation coupon rows before payment handoff; source-refs/sanmopia_web/application/controllers/Service.php:721-750 mutates pre-reservation service type and coupon rows during the payment-page GET; source-refs/sanmopia_web/application/views/service/pre_reservation_payment.php:123-143 subtracts coupon prices from the pre-reservation provider amount in PHP view state; source-refs/sanmopia_web/application/models/Reservation_model.php:1990-2008 deletes coupon selections by nullable PRERESERVATION_FL; source-refs/sanmopia_web/application/models/Reservation_model.php:2013-2033 inserts coupon selection rows after a current wallet lookup; source-refs/sanmopia_web/application/models/Payment_model.php:140-152 flips user-coupon USE_FL during paid reservation closeout; source-refs/sanmopia_web/application/models/Payment_model.php:775-843 creates pre-reservation payment rows, virtual-account waiting status, and over-credit point/shop grants from current price-table coupon values; source-refs/sanmopia_web/application/models/Coupon_model.php:530-553 and source-refs/sanmopia-admin/application/models/Coupon_model.php:935-958 reopen used coupons on customer/admin cancellation by mutating USE_FL and appending a free-text reuse log; source-refs/sanmopia-admin/application/models/Reservation_model.php:184-229 and source-refs/sanmopia-admin/application/models/Reservation_model.php:731-790 reattach used coupon rows and recalculate user-fee/left-price document inputs from mutable coupon state; source-refs/sanmopia-admin/application/models/Reservation_model.php:871-916 feeds coupon-adjusted PRICE_TABLE values into service-balance and document projections. | ReservationCouponSelectionRevision, CouponUseLedgerEntry, PreReservationCouponCreditCloseout, CouponSettlementImpactSnapshot, CouponDocumentChargeSnapshot | promotion_entitlement / coupon_use_authority, pricing_settlement / reservation_charge_lines, payment_processing / payment_closeout, branch_settlement / settlement_seed_projection, document_reporting / reservation_charge_artifact_projection | Backend must separate coupon selection intent, payment-closeout consumption, pre-reservation credit/over-credit fulfillment, cancellation/refund restoration, settlement impact, and document charge impact into immutable ledger facts with actor, reason, source payment revision, charge snapshot revision, and idempotency. UI/PHP/renderers may render selectable coupon projections and submit coupon-intent tokens only; GET payment pages, hidden coupon ids, nullable pre-reservation flags, user-coupon mutable flags, and read-time PRICE_TABLE recomputation must not be booking, payment, refund, settlement, or document authority. | Partial; PreReservationCouponOverCreditPolicy, product-coupon reset, refund side-effect planning, and frozen charge snapshots exist, but coupon selection revision, closeout-use ledger, cancellation/refund restoration ledger, settlement projection invalidation, and document artifact invalidation still need end-to-end persistence proof. | Add tests that reject hidden coupon ids for another user, already-used/deleted/expired coupons, and stale pre-reservation coupon flags; prove pre-reservation payment page does not mutate coupon authority on GET; prove zero-payable and virtual-account pre-reservation closeout emit coupon-use and over-credit facts after payment persistence; prove cancellation/refund restores coupon availability through a ledger event; prove branch/HQ settlement, caregiver payout, and printable document projections consume coupon impact from the same frozen charge/payment revision. |
Downstream consumer refinement for the three selection-revision rows above:
-
ReservationAddOptionSelectionRevisionmust become the ubiquitous source name for selected additional service time, child/family add-on, Wanju, Saturday, holiday, and other extra-day charge rows. Payment handoff evidence:source-refs/sanmopia_web/application/models/Payment_model.php:50-68writes normal/voucher payment rows by service type, andsource-refs/sanmopia_web/application/models/Payment_model.php:157-226copiesPRICE_TABLE["userFeeSecurityPrice"],userFeeBalancePrice, andleftPriceintoPAYMENT_USER_RESERVATION_*_TB; those prices already include add-option and extra-day totals fromsource-refs/sanmopia_web/application/models/Reservation_model.php:1231-1369. Caregiver payout evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:3235-3264reloads rental and add-option rows for a reservation, andsource-refs/sanmopia-manager/application/helpers/salary_helper.php:102-145recomputes Saturday/holiday/service-day multipliers into caregiver added-service pay beforesource-refs/sanmopia-manager/application/views/pay_info_detail.php:201-249renders final salary. Branch/HQ settlement evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:198-278summarizes payment rows for HQ-to-branch settlement, andsource-refs/sanmopia-admin/application/models/Payment_model.php:4155-4222separately rebuilds service-balance price by joiningRESERVATION_ADD_OPTION_VOUCHER_TBandRESERVATION_ADD_OPTION_NORMAL_TB. Danbee settlement evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:3190-3232reads payment rows into Danbee settlement worklists, andsource-refs/sanmopia-admin/application/models/Payment_model.php:384-523adds their amounts and fee rows. Printable document evidence:source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:340-373,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:417-465,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:645-714, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:728-748render add-option and extra-day amounts into fee-agreement, service-use, and downpayment artifacts. Refund/repair evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:990-1035triggers refund plus coupon restore during instant cancellation, andsource-refs/sanmopia_web/application/models/Payment_model.php:383-430refunds provider payment rows then marks normal/voucher payment rows refunded. Remaining backend gap: persist oneReservationAddOptionSelectionRevisionconsumer contract throughReservationPaymentSettlementHandoffSnapshot,CaregiverPayoutChargeImpactSnapshot,BranchSettlementSeedProjection,HeadquartersSettlementSeedProjection,ReservationChargeDocumentSnapshot, andRefundRepairProjectionInvalidation; all consumers must reference the same persisted revision key, finalized charge snapshot id, payment fact revision, and repair/reissue lineage. -
ReservationRentalSelectionRevisionmust be the ubiquitous name for rental equipment and delivery-fee charge rows, withRentalDeliveryChargeLineas the single delivery-fee component. Payment handoff evidence:source-refs/sanmopia_web/application/controllers/api/Service.php:416-419andsource-refs/sanmopia_web/application/controllers/api/Service.php:531-534reinsert posted rental ids before payment handoff;source-refs/sanmopia_web/application/models/Reservation_model.php:1231-1259adds rental rows plusDELIVERY_FEE; andsource-refs/sanmopia_web/application/models/Reservation_model.php:1318-1348feeds rental totals into voucher service-balance or normal left-price payment amounts. Admin/export evidence:source-refs/sanmopia-admin/application/models/Reservation_model.php:216-229reloads rental rows beforePRICE_TABLEcalculation,source-refs/sanmopia-admin/application/models/Reservation_model.php:584-595joinsRESERVATION_RENTAL_TBtoLIST_RENTAL_TB, andsource-refs/sanmopia-admin/application/models/Reservation_model.php:748-776adds rental and delivery-fee values into admin price rows. Printable document evidence:source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:663-709hardcodes rental names, breast-pump price, and delivery price into downpayment artifacts, whilesource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-3952renders documents after loading the current rental catalog. Settlement evidence follows the same payment-row and board flow as add-options:source-refs/sanmopia-admin/application/models/Payment_model.php:198-278,source-refs/sanmopia-admin/application/models/Payment_model.php:384-523, andsource-refs/sanmopia-admin/application/models/Payment_model.php:534-744. Remaining backend gap: persistReservationRentalSelectionRevisionand exposeRentalSettlementImpactSnapshot,RentalDocumentChargeSnapshot, andRentalRefundRepairProjectionInvalidationso payment handoff, service-balance closeout, caregiver payout display, branch/HQ settlement, documents, refunds, and artifact repairs never re-read mutable rental ids, names, or delivery-fee constants. -
ReservationCouponSelectionRevisionmust be the ubiquitous name for coupon selection rows;CouponUseLedgerEntry,CouponPaymentCloseoutFact, andCouponRefundRepairLedgerEntryown consumption, restoration, provider refund, settlement, and document impact. Payment evidence:source-refs/sanmopia_web/application/models/Reservation_model.php:1990-2033deletes/reinserts coupon selections byPRERESERVATION_FL;source-refs/sanmopia_web/application/models/Payment_model.php:140-152mutatesUSER_COUPON_TB.USE_FLduring paid closeout; andsource-refs/sanmopia_web/application/models/Payment_model.php:775-843uses coupon-adjustedPRICE_TABLEvalues for pre-reservation payment, virtual account status, over-credit point grant, and shopping-mall coupon grant. Settlement evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:3340-3405joinsRESERVATION_COUPON_USED_TB,USER_COUPON_TB, andPAYMENT_COUPON_TBinto Danbee coupon payment rows;source-refs/sanmopia-admin/application/models/Payment_model.php:3410-3478does the same for HQ/branch coupon rows;source-refs/sanmopia-admin/application/views/calculate_detail.php:629-660andsource-refs/sanmopia-admin/application/views/calculate_detail.php:1091-1127render coupon payment and gift-fee checkbox lines; andsource-refs/sanmopia-admin/application/models/Payment_model.php:534-744writesBOARD_PAYMENT_*detail rows and marks coupon settlement flags. Refund evidence:source-refs/sanmopia_web/application/models/Coupon_model.php:530-553andsource-refs/sanmopia-admin/application/models/Coupon_model.php:935-958reopen used coupons by mutableUSE_FLplus free-text reuse logs;source-refs/sanmopia-admin/application/models/Coupon_model.php:164-188refunds coupon payment through KCP and setsPAYMENT_COUPON_TB.REFUND_FL; andsource-refs/sanmopia-admin/application/libraries/Kcppayment.php:31-44sends full-cancelmod_type=STSC. Printable document evidence stays tied to mutablePRICE_TABLEand reservation reloads atsource-refs/sanmopia-admin/application/models/Reservation_model.php:184-229,source-refs/sanmopia-admin/application/models/Reservation_model.php:731-790, andsource-refs/sanmopia-admin/application/models/Reservation_model.php:871-916. Remaining backend gap: close the coupon path with immutable selection, use/restore/refund ledger entries, provider-refund idempotency key, settlement reversal lines, payout/document invalidation rows, and artifact repair/reissue lineage keyed by charge snapshot revision and payment fact revision.
Implementation note: backend 0644e7f exposes
ReservationAddOptionSelectionRevisionPayload from successful
booking-service-term side-effect assembly through application, API, and HTTP
contracts. Backend e1846f8 persists that revision in
sanmopia_reservation_add_option_selection_revisions with service-role-only RLS,
direct lookup by revision key, finalized charge snapshot id, add-option charge
links, and a full revision snapshot. Backend 4f7bebf now requires every
BookingServiceTermAddOptionChargeLinkPayload to carry typed quantity_basis
(effective_service_day, added_service_day, item_quantity, or
source_component_total) plus non-empty quantity_basis_evidence_keys; revision
persistence and HTTP responses retain both fields. Stage reservation
ca44be7c-fbf3-4a4e-8e47-e27868bf2d72 reached settled with
quantity_basis=added_service_day and evidence key extra/saturday/1 persisted.
Backend 56413fe then makes occurrence ledger key/revision physical non-null
revision columns, constrains their presence/equality in the JSON snapshot, and
validates composite booking-ledger, assembly-lineage, and revision relationships.
Revision keys include both occurrence-ledger and calendar-quote revisions; assembly
delete is NO ACTION; an immutable trigger allows identical idempotent replay and
rejects mutation. Stage reservation eeef7782-aff2-4065-bf9c-7ab48f7fd629
reached settled. This proves revision-level occurrence binding and immutability,
not backend derivation of each quantity basis from ledger/policy, normalized
per-charge-link rows, consumer-specific amount policy, historical backfill,
printable document input, or refund/repair propagation. Backend 7c96fab wires
that persisted revision into reservation financial lifecycle settlement closeout:
branch/HQ
settlement preparation accepts addOptionSelectionRevisionKey and
addOptionSelectionRevisionNumber, and Supabase runtime rejects stale or missing
references before mutating settlement state. Backend 70e0abd carries the paired
revision reference through service-balance closeout command, event, current
projection, and Supabase constraints. Backend a48172b propagates that closeout
revision through caregiver payout service-balance slot state and persisted admin
caregiver payout statement rows. Backend e00810e carries the same closeout
revision into branch and HQ settlement issuance commands and validates it through
the Supabase closeout reader before financial lifecycle mutation. The guarded
positive-balance stage E2E reached settled for reservation
1a061d05-a590-4bc8-9a62-30dd03d7d9ac, proving one immutable revision across
closeout, caregiver/admin payout, branch settlement, and HQ settlement issuance.
Backend fbc60e4 now projects caregiver work-schedule service-balance shares from
the frozen closeout event, caregiver receipt state, and payout instruction. Its
versioned equal-slot policy supports multiple caregiver slots with deterministic
integer allocation, and its reader has reservation-scoped lookup. Positive-balance
stage reservation 0b57b5f1-12c5-42f0-bcdf-7ab90e469a8b reached settled with a
frozen 25,000 KRW share. Backend 65a71ac closes the missing-writer gap by
projecting accepted assignment decisions through CareTeamAssignmentProjectionWriter
into sanmopia_reservation_caregiver_assignments. The projection resolves the
candidate profile, member-to-auth binding, candidate grade, latest occurrence-ledger
service-day count, and booking dates; replacement and clear decisions mark prior
slots replaced or removed. Stage reservation
5dd549d3-6c2c-407c-b42a-fdcd7e769c6a persisted the roster row before payout and
reached settled. Remaining roster risk is non-atomic decision-save/projection
failure, durable repair or idempotent replay, and audited backfill for older
accepted decisions, not absence of a projection writer.
Contract b06f393 and backend f9f24aa now separate inbound
addOptionChargeIntents from finalized charge links. Backend derives canonical
quantity and evidence from the accepted service term, accepted price quote,
occurrence ledger, catalog entry, and finalized charge line, then persists
physical catalog/charge identifiers and child evidence rows through one atomic
Supabase RPC. Canonical rows reject mutable occurrence, catalog, finalized-charge,
and outbox changes; unresolved historical evidence is labeled
legacy_unresolved instead of being presented as canonical. Stage reservation
d1b8165d-e0da-497f-a55a-e9d6ecb6b924 reached settled with customer payable
150,000 KRW, caregiver payout 50,000 KRW, branch settlement 100,000 KRW,
headquarters settlement 50,000 KRW, and service balance 25,000 KRW.
Backend 3d411d2 then made reservation smoke cleanup repeatable without weakening
those immutable rows: a private deployment identity and backend/transaction/exact
reference guard authorize only the registered stage row. Registration-time catalog
validation removed 50 invalid legacy cleanup references. Fresh stage reservation
655b6047-bd62-4315-bc40-d8714492aae2 registered zero invalid references and was
reaped on the first attempt with 20 deleted rows; booking and workflow-request
counts both returned zero afterward.
Payment handoff, printable document, and refund/repair consumers remain open, so
the add-option row remains Partial. Modern ubiquitous names to keep stable in
backend contracts:
ReservationAddOptionSelectionRevision,
ReservationPaymentSettlementHandoffSnapshot,
CaregiverPayoutChargeImpactSnapshot,
BranchSettlementSeedProjection, HeadquartersSettlementSeedProjection,
ReservationChargeDocumentSnapshot, and
RefundRepairProjectionInvalidation.
Additional uncovered PHP consumers under the same owner rows:
-
Caregiver portal payout and service-balance receipt state need separate backend authority from settlement/payment completion. Source evidence:
source-refs/sanmopia-manager/application/controllers/Reservation.php:36-77accepts caregiverPUTrequests forpaymentandsub_payment;source-refs/sanmopia-manager/application/models/Reservation_model.php:22-24reads mutable reservation service-balance override fields into the caregiver reservation list;source-refs/sanmopia-manager/application/models/Reservation_model.php:65-69readsPAYMENT_BRANCH_MANAGER_TBtype5as reservation payout state;source-refs/sanmopia-manager/application/models/Reservation_model.php:247-270joins customer service-balance payment rows andPAYMENT_BRANCH_MANAGER_TBtype3into caregiver detail;source-refs/sanmopia-manager/application/models/Reservation_model.php:382-405lets main/sub caregiver actions mutatePAYMENT_BRANCH_MANAGER_TBpayment flags; andsource-refs/sanmopia-manager/application/models/Reservation_model.php:488-515reads main/sub salary rows fromPAYMENT_BRANCH_MANAGER_TBandPAYMENT_BRANCH_SUB_MANAGER_TB. Modern ubiquitous names:CaregiverPortalPayoutStatusSnapshot,CaregiverServiceBalanceReceiptAcknowledgement,SubCaregiverServiceBalanceReceiptAcknowledgement, andCaregiverPayoutInstructionStatusProjection. Remaining backend gap: persist caregiver-facing receipt acknowledgements as actor-scoped events keyed by care-team recipient slot, service-balance closeout revision, payout instruction revision, expected payment fact revision, and branch/HQ settlement reference. Caregiver UI must request acknowledgement/disclosure only; it must not directly complete or repairPAYMENT_BRANCH_MANAGER_TBstatus rows. -
Branch/HQ receivable settlement rows need explicit lineage from Danbee payment board facts and branch deposit acknowledgements. Source evidence:
source-refs/sanmopia-admin/application/controllers/Calculate.php:150-223posts branch/HQ settlement totals, selected reservation ids, payment types, coupon ids, membership/delivery/gift-fee flags, and free-form messages intoinsertPaymentDetail;source-refs/sanmopia-admin/application/models/Payment_model.php:575-603creates or updatesPAYMENT_ADMIN_BRANCH_TBreceivable rows per reservation and payment type;source-refs/sanmopia-admin/application/models/Payment_model.php:607-650marks normal/voucher payment rows as Danbee-settled;source-refs/sanmopia-admin/application/models/Payment_model.php:697-746writesBOARD_PAYMENT_*_DETAIL_TBrows and marks Danbee coupon settlement flags;source-refs/sanmopia-admin/application/controllers/Calculate.php:248-263turns branch deposit response into board status2complete or4arrears;source-refs/sanmopia-admin/application/models/Payment_model.php:2039-2053readsBOARD_PAYMENT_ADMIN_DETAIL_TBjoined toPAYMENT_ADMIN_BRANCH_TB;source-refs/sanmopia-admin/application/models/Payment_model.php:3339-3405andsource-refs/sanmopia-admin/application/models/Payment_model.php:3410-3478project coupon settlement separately for Danbee and HQ/branch; andsource-refs/sanmopia-admin/application/models/Payment_model.php:4241-4262exposes a repair scan for missingPAYMENT_ADMIN_BRANCH_TBrows whilesource-refs/sanmopia-admin/application/models/Payment_model.php:4265-4289mutates board detail/coupon completion flags. Modern ubiquitous names:DanbeeSettlementPaymentBoardFact,BranchSettlementReceivablePaymentState,HeadquartersSettlementDepositAcknowledgement,SettlementBoardDetailCompletionFact, andSettlementReceivableRepairDecision. Remaining backend gap: persist a single settlement board ledger that links reservation payment facts, coupon payment facts,ReservationAddOptionSelectionRevision, rental/coupon selection revisions, branch receivable rows, branch deposit acknowledgements, arrears decisions, and repair decisions. Branch/HQ/Danbee projections and printable or refund/repair consumers must reference those ledger ids instead of posted arrays, mutable board flags, or missing-row scans. -
Active data-room list, detail, and export projections need one immutable amount basis and classification snapshot. Source evidence:
source-refs/sanmopia-admin/application/models/Payment_model.php:1595-1658rebuilds archived Danbee voucher/normal/completed counts from current reservation service-type and status rows whilesource-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:29-49displays those rebuilt counts beside persisted board totals;source-refs/sanmopia-admin/application/models/Payment_model.php:1750-1912makes branch/HQALL_PRICEmean outstanding components for board statuses0/1/3/4, but all original components after status2, and also reloads the monthly membership price from mutable branch policy;source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:46-60renders both meanings under the same component and total columns;source-refs/sanmopia-admin/application/controllers/Common.php:132-150opens branch data-room detail with a board id but null period dates;source-refs/sanmopia-admin/application/models/Payment_model.php:1357-1436derives a period from those null dates, then re-joins the membership override while hydrating the historical board; andsource-refs/sanmopia-admin/application/models/Payment_model.php:1495-1551rebuilds voucher and gift-coupon subtotals from current payment/coupon rows. Danbee export then calls the same live detail loader and recalculates payment method fees atsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3900. Modern ubiquitous names:SettlementStatementAmountBasisSnapshot,SettlementArchiveClassificationSnapshot,SettlementProjectionConsistencyDecision, andSettlementProjectionDiscrepancyRepair. Status:Partial; frozen statement, dataset, and artifact foundations exist, but active data-room adapters still rebuild historical meaning from mutable rows. Invariant: each statement revision must expose separately named gross, acknowledged, outstanding, fee, and net amounts plus frozen reservation classification and component subtotal checksums. State transitions may select a displayed amount but must never change one field’s meaning. List, detail, and export must share the same statement/dataset revision and checksum; mismatch blocks artifact issuance and creates an auditable repair case that preserves source-observed values. -
Service-balance import needs formula provenance because legacy source behavior contradicts its own stated additional-service-day basis. Source evidence:
source-refs/sanmopia-admin/application/models/Payment_model.php:4196-4203adds Saturday/holiday quantities todayCountand charges those rows once;source-refs/sanmopia-admin/application/models/Payment_model.php:4205-4219then says other additional services use total days plus those added days, but resetsdayCountto voucher service days or normal weeks times five before multiplying each non-Saturday/non-holiday row, discarding the earlier added-day count;source-refs/sanmopia-admin/application/models/Reservation_model.php:1572-1575recalculates that amount from current price/add-option rows during operator payment save;source-refs/sanmopia-admin/application/models/Reservation_model.php:1641-1677writes it into the type3service-balance payment row; andsource-refs/sanmopia-admin/application/models/Reservation_model.php:3507-3545derives caregiver receipt state from that row, including automatic completion when the amount is zero. The same mutable payment amount then reaches Danbee and branch/HQ settlement readers documented above. Modern ubiquitous names:ServiceBalanceAdditionalServiceChargeDecision,ServiceBalanceSourceFormulaEvidence, andServiceBalanceCalculationDiscrepancyRepair. Status:Partial; the modern additional-service charge policy and service-balance closeout references exist, but historical type3rows do not record which source formula produced them. Import must preserve source amount, source formula variant, price/add-option revision evidence, and discrepancy amount without silently rewriting history. Canonical recomputation or an approved repair must invalidate and rebuild caregiver payout, Danbee settlement, branch settlement, HQ settlement, and printable artifact projections from one new service-balance revision.Additional active consumers prove more source formula variants. Customer and admin reservation price projections add Saturday/holiday quantities to the effective service-day multiplier but treat add-option labels containing Wanju as one-time amounts at
source-refs/sanmopia_web/application/models/Reservation_model.php:1123-1162andsource-refs/sanmopia-admin/application/models/Reservation_model.php:649-695. Caregiver reservation projection instead adds a computed week count for Saturday presence, adds holiday quantity, and still treats Wanju as one-time atsource-refs/sanmopia-manager/application/models/Reservation_model.php:185-220. Caregiver payout multiplies every non-Saturday/non-holiday option, including Wanju, by service days plus added-day quantities atsource-refs/sanmopia-manager/application/helpers/salary_helper.php:109-145. Caregiver schedule view repeats that recurring formula, adds normal base-price difference, then divides the result by caregiver count atsource-refs/sanmopia-manager/application/views/schedule/schedule_info.php:169-200. Printable downpayment rendering also multiplies every non-Saturday/non-holiday option by service days plus added days atsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:647-660. Modern invariant: everyAdditionalServiceChargeComponentinReservationAddOptionSelectionRevisionmust freeze explicitquantity_basis(effective_service_day,added_service_day,item_quantity, orsource_component_total), occurrence references, regional-benefit decision, policy revision, and consumer purpose. Customer charge, service-balance, caregiver compensation, and document lines may have distinct policy amounts, but all must reference the same accepted selection and occurrence revisions; no consumer may infer recurrence, Wanju treatment, added-day count, or care-team allocation from Korean labels. Danbee, branch, and HQ settlement consume finalized lines and closeout lineage only. Backend4f7bebfnow validates the four typed quantity bases, rejects empty basis-evidence sets, and retains both fields through selection-revision persistence and HTTP response. Stage reservationca44be7c-fbf3-4a4e-8e47-e27868bf2d72persistedadded_service_daywith evidence keyextra/saturday/1and reachedsettled. Backend56413fenow proves revision-level occurrence binding with physical non-null ledger key/revision columns, JSON equality checks, validated composite foreign keys, occurrence-plus-calendar revision identity,NO ACTIONassembly retention, and immutable idempotent replay. Stage reservationeeef7782-aff2-4065-bf9c-7ab48f7fd629reachedsettled. Status remainsPartial: basis metadata is still supplied rather than derived from ledger and policy, per-charge-link rows are not normalized, and consumer-specific amount policies remain unproven.a48172bande00810eprove closeout revision propagation through payout and branch/HQ issuance, while payment handoff, printable document input, refund/repair propagation, historical formula-variant backfill, and discrepancy repair remain unproven. Migration traps for caller-derived basis, JSON-contained per-link lineage, per-link application-emulated integrity, and mutable post-payment values remain tracked under existing ownerSFC-20260708-CUR-065. -
Add-option payment, printable, and refund consumers still lack immutable formula lineage. The customer payment action loads
userFeeSecurityPricefrom the current reservationPRICE_TABLEatsource-refs/sanmopia_web/application/controllers/Service.php:666-679, writes that amount into the KCP form atsource-refs/sanmopia_web/application/views/service/reservation_payment.php:138-145, and launches the provider from browser form state atsource-refs/sanmopia_web/static/js/reservation_payment.js:40-89; the callback then reloads the reservation and independently uses the currentuserFeeSecurityPricefor the provider command and local payment rows atsource-refs/sanmopia_web/application/controllers/api/Payment.php:89-165andsource-refs/sanmopia_web/application/models/Payment_model.php:198-226. Printable agreement/downpayment generation parses display strings and Korean labels into cells, reruns the added-day multiplier, and recomposes totals from mutable reservation rows atsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:417-465,:647-660,:711-725, and:731-779. Full cancellation scans provider-context payment rows, issues opaque full refunds, marks each successfully cancelled row refunded, and restores coupon state as a separate side effect atsource-refs/sanmopia_web/application/models/Payment_model.php:383-440andsource-refs/sanmopia_web/application/models/Reservation_model.php:989-1035; no reversed add-option component or selection revision is retained there. Admin cancellation exposes a separate failure mode: it commits reservation status before provider refund work atsource-refs/sanmopia-admin/application/models/Reservation_model.php:1769-1800, classifies every selected payment row with hardcodedIFNULL('일반', '바우처')at:1827-1835, ignores the provider refund result before marking the inferred local table row refunded at:1838-1857, then refunds one change-payment context and restores coupons at:1861-1880without add-option component, payment-fact revision, or document-artifact invalidation lineage. Modern invariant:ReservationPaymentSettlementHandoffSnapshotmust freeze the acceptedReservationAddOptionSelectionRevision, finalized charge snapshot, exact provider amount, and payment fact revision before provider launch; the callback must reject mismatched references instead of re-reading current price formulas.ReservationChargeDocumentSnapshotmust consume the same frozen component references and selection revision without label parsing or amount recomputation.RefundRepairProjectionInvalidationand existing settlement reversal lines must identify the original payment/charge revisions and exact frozen components reversed, then invalidate or reissue affected settlement and printable artifacts. Provider result must gate local refunded state, payment fact must select service type/storage target, and cancellation/coupon restoration must wait for the refund completion barrier. Status remainsPartial: none of these legacy consumers proves add-option payment handoff, printable artifact, or refund/repair lineage.
2026-07-10 persistent legacy payment miner delta
Section titled “2026-07-10 persistent legacy payment miner delta”Existing payment, refund, virtual-account, cash-receipt, and repair rows remain canonical. These rows add only source requirements not stated by those owners. Legacy controller order, array truthiness, provider payloads, and terms text are evidence; target authority stays in backend commands, ledgers, policies, and repair projections.
| feature_id | priority | lane_owner | source_evidence | ddd_aggregate | command_query | persistence | contract | e2e_proof | status | backend_owned_design |
|---|---|---|---|---|---|---|---|---|---|---|
SFC-20260710-PAY-001 | P0 | Backend / pricing_settlement | Legacy browser amount and late ownership checks at source-refs/sanmopia_web/static/js/mypage/reservation_changePayment.js:43-66, source-refs/sanmopia_web/application/controllers/api/Payment.php:657-713, and destructive unpaid replacement at source-refs/sanmopia_web/application/models/Payment_model.php:856-874. | PaymentChangeHandoffContext, PaymentChangeAdjustment, PaymentProviderHandoffSession, PaymentChangeSupersessionFact | PrepareAuthorizedPaymentChangeHandoffCommand, AuthorizeAndPreRegisterPaymentChangeCommand, atomic unpaid replacement | Atomic handoff RPC is reached by public runtime. Backend derives booking context, mother, amount, product plan, Kill Bill route, payment key, revisions, expiry, evidence, and return route. PAY_PAYMENT_CHANGE separates stage/SpiceDB policy from pre-reservation payment. Exact replay avoids duplicate provider calls. A second atomic RPC locks booking, permits replacement only while provider payment is waiting, supersedes old handoff, cancels old adjustment, inserts replacement, and appends lineage without deleting evidence. | Request accepts only selectedPaymentMethodCode; Idempotency-Key and Supabase bearer required. Contract rejects browser mother/payment/provider/amount/authority fields. | Secure handoff proof: booking 9c19e1c3-9b64-41b3-bb2b-67517e08920a, adjustment 665ff856-a041-4b51-be40-b4c12165ffac. Atomic replacement proof: booking bcf1db59-9c44-47c1-aa6e-6aacafd79cba, old c5d89751-1544-4b32-900f-86e112dedfe2, replacement e13e961e-6ab4-4245-8e1b-cf2fe8c25483; verified old-cancel/new-active, handoff supersession, lineage, retained waiting payment, and reaper. | e2e_proven | Browser selects allowed method only. Backend owns all financial and authority facts. Paid or unknown provider operations cannot be replaced here; PAY-006 reconciliation/compensation resolves them. See ADR-025. |
SFC-20260710-PAY-002 | P0 | Backend / pricing_settlement | Normal virtual-account issue sends account/deadline instructions before local payment persistence at source-refs/sanmopia_web/application/controllers/api/Payment.php:126-180. Coupon, balance, and pre-reservation issue handling mutates waiting state at source-refs/sanmopia_web/application/controllers/api/Payment.php:421-457, ignores the coupon update result from source-refs/sanmopia_web/application/models/Payment_model.php:472-475 and the unchecked balance/pre-reservation updates at source-refs/sanmopia_web/application/models/Payment_model.php:353-380, then dispatches instructions and returns success at source-refs/sanmopia_web/application/controllers/api/Payment.php:470-501. Payment-change virtual-account issue writes PAYMENT_CONTEXT, sets DEPOSIT_DT, and sends completion notices at source-refs/sanmopia_web/application/controllers/api/Payment.php:706, source-refs/sanmopia_web/application/controllers/api/Payment.php:723, source-refs/sanmopia_web/application/controllers/api/Payment.php:740, and source-refs/sanmopia_web/application/models/Payment_model.php:893. Pre-reservation issue/deposit effects mutate reservation/coupon/credit state at source-refs/sanmopia_web/application/models/Payment_model.php:745, source-refs/sanmopia_web/application/models/Payment_model.php:758, source-refs/sanmopia_web/application/models/Payment_model.php:784, and source-refs/sanmopia_web/application/models/Payment_model.php:825. Deposit completion notices fan out by product at source-refs/sanmopia_web/application/models/Payment_model.php:574, source-refs/sanmopia_web/application/models/Payment_model.php:579, source-refs/sanmopia_web/application/models/Payment_model.php:588, source-refs/sanmopia_web/application/models/Payment_model.php:597, source-refs/sanmopia_web/application/models/Payment_model.php:623, source-refs/sanmopia_web/application/models/Payment_model.php:636, and source-refs/sanmopia_web/application/models/Payment_model.php:721. | VirtualAccountIssuanceCommitBarrier, VirtualAccountPaymentLifecycle, OrphanedVirtualAccountIssueRepairCase, VirtualAccountInstructionDispatchOutbox, PaymentChangeVirtualAccountLifecycle, PreReservationPaymentCloseout, VirtualAccountDepositCompletionNotificationOutbox | CommitVirtualAccountIssueCommand, DispatchVirtualAccountInstructionCommand, ReconcileOrphanedVirtualAccountIssueCommand, CommitPaymentChangeVirtualAccountIssueCommand, MarkPaymentChangeVirtualAccountDepositedCommand, ApplyPreReservationVirtualAccountDepositEffectsCommand, DispatchVirtualAccountDepositCompletionNotificationsCommand | Backend 5c66e2d adds provider-order/deadline issue replay protection to the persisted lifecycle decision: an exact replay is non-mutating and emits no second instruction, while mismatched or post-deposit issue events are rejected. Backend 96f8849 wires KillBillPaymentEventIngestionHandler to persist a mark_deposited VirtualAccountPaymentLifecycleDecision through SupabaseVirtualAccountPaymentLifecycleDecisionStore when a paid Kill Bill callback closes a virtual-account payment. Backend eed2fe0 adds the application commit barrier: CommitVirtualAccountIssueHandler computes the lifecycle decision, builds the provider-neutral instruction outbox entry only for open_waiting_payment, and calls VirtualAccountIssueCommitStore before returning customer-instruction readiness. Backend 563e783 implements the Supabase RPC behind that port: it upserts the lifecycle decision, checks and advances sanmopia_payment_records.payment_fact_revision, inserts sanmopia_virtual_account_instruction_dispatch_outbox, rejects dispatch for non-mutating issue decisions, and was applied to stage. Backend e8b38b6 adds OrphanedVirtualAccountIssueRepairCase, planning/persistence ports, and service-role Supabase storage for provider-issued/local-write-failed, payment revision mismatch, instruction outbox rejection, and provider issue without local fact. Backend 9240cee adds VirtualAccountInstructionDispatchWork, retry result contracts, a backend worker handler, Supabase claim RPC sanmopia_claim_virtual_account_instruction_dispatches, retry timestamps, attempt count, and provider dispatch reference persistence without reissuing provider accounts. Backend 713f880 adds SupersededVirtualAccountDepositAlias, planning/persistence ports, and service-role Supabase storage for deposits reported through superseded provider orders without marking the active payment paid. Backend 3152321 wires Kill Bill virtual-account deposit callbacks to read the backend-frozen active provider order, auto-capture superseded-order deposits as aliases, and block payment workflow start for mismatched provider orders. Backend 38aac56 adds an executable orphaned-issue repair worker: open repair cases are claimed through Supabase, local commit reconciliation is run, stale provider accounts are closed or instruction dispatch is rescheduled, and terminal status plus resolution evidence is persisted. Backend 3df31d0 splits payment-change virtual-account flow: issue events persist waiting lifecycle only, deposit events mark adjustment paid, freeze provider evidence, and trigger settlement continuation; stage constraints now accept payment_change_adjustment across virtual-account lifecycle tables. Backend 60760f9 adds PreReservationDepositCloseout, ApplyPreReservationVirtualAccountDepositEffectsCommand, idempotent closeout store port, and post-commit reservation transition requester so coupon credit, reservation payment credit, over-credit grants, and reservation transition keys are backend-planned from deposited lifecycle facts. Backend 0d44d0d adds service-role Supabase persistence for sanmopia_pre_reservation_deposit_closeout_plans, RLS, append-only insert adapter, duplicate request-key guard, stage migration, and adapter tests under the payment_conversion owner slice. Backend 7edb5ea adds VirtualAccountDepositCompletionDispatchPlanCommand, mapping deposited virtual-account facts to product-specific PlanPaymentCommunicationDispatchCommand routes for pre-reservation, customer-share deposit/balance, and gift-coupon purchase. | Issue result binds payment id/revision, provider account reference, frozen amount/deadline, product purpose, recipient snapshot, provider attempt, instruction outbox key, and dispatch idempotency key before customer success. Deposit callback lifecycle facts bind provider event, provider transaction, payment revision, purpose, and backend evidence keys before payment workflow start. Orphan repair cases bind provider event, provider order, amount, deadline, failed decision/outbox keys, source evidence, reason, status, and recommended reconciliation/provider-close/dispatch-retry actions. Dispatch work binds outbox key, idempotency key, payment record, purpose, provider transaction, amount/deadline, recipient snapshot, evidence keys, attempt count, next retry time, and provider dispatch reference. Superseded alias binds active payment, optional superseded payment, active and superseded provider orders, amount, deposit time, detected time, reason, status, and evidence keys. | Colocated policy and migration tests prove replay revision and notification invariants; the stage decision constraint accepted the new replay action. Focused callback tests prove vcnt paid callbacks write a deposited lifecycle decision and production composition injects the Supabase store. Backend eed2fe0 colocated application tests prove new issue commit creates a dispatch instruction only after store commit, exact replay and stale provider-order cases commit no dispatch, non-issue events are rejected, and store failure returns no customer instruction. Backend 563e783 adapter/migration tests prove RPC payload shape, outbox table/RLS/grants, payment revision guard, and ambiguity fix. Backend e8b38b6 tests prove orphan repair reason/action selection, non-issue rejection, handler persistence, adapter row shape, service-role table grants, and stage migration 20260713001000_orphaned_virtual_account_issue_repair_cases.sql; pnpm supabase:db:lint:stage returned no schema errors. Backend 9240cee focused tests prove dispatch success, retry scheduling, mismatched dispatch result failure, Supabase RPC claim mapping, completed/failed outbox updates, retry migration FOR UPDATE SKIP LOCKED, attempt_count, and service-role execution grant. Backend 713f880 focused tests prove superseded deposit alias creation, same-order rejection, non-deposit rejection, adapter row shape, table RLS/grants, provider-order difference constraints, stage migration 20260713003000_superseded_virtual_account_deposit_aliases.sql, uv run pytest ...virtual_account_payment_lifecycle -q, Ruff, Tach, pnpm supabase:db:push:stage -- --dry-run, pnpm supabase:db:push:stage, and pnpm supabase:db:lint:stage passed. Backend 3152321 tests prove frozen active provider-order reads, superseded-order callback alias capture without lifecycle decision or workflow start, adapter active-order lookup, runtime composition wiring, uv run pytest ...killbill_payment_event_test.py ...main_test.py -q, Ruff, and Tach. Backend 38aac56 tests prove provider-close repair execution, dispatch-retry repair execution, failed-action open-case retention, Supabase claim/status mapping, migration claim RPC, focused lifecycle pytest, Ruff, Tach, stage dry-run, stage push, and stage lint. Backend 3df31d0 tests prove payment-change issue waits without paid receipt, deposit marks paid and continues settlement, replay deposit avoids rewrite, purpose catalog includes payment_change_adjustment, Supabase migration guards, focused pytest, Ruff, Tach, stage dry-run, stage push, stage lint, and direct stage constraint inspection. Backend 60760f9 tests prove pre-reservation deposit closeout plans reservation payment credit, coupon credit consumption, over-credit grant ledgers, transition request keys, idempotent replay, rejected non-pre-reservation payments, and Tach-safe payment_conversion boundaries. Backend 0d44d0d tests prove Supabase row shape, no blind upsert, existing-plan read, duplicate request-key rejection, migration columns, RLS, service-role-only write grants, focused pytest, Ruff, Tach, stage dry-run, stage push, stage lint, and direct stage table/grant inspection. Backend 7edb5ea tests prove pre-reservation mother/payer/branch/secondary-contact routes, customer-share mother/payer routes, gift-coupon payer plus receiver direct-contact routing, receiver contact validation, unsupported product rejection, focused pytest, Ruff, and Tach. Backend stage proof pnpm supabase:smoke:stage:virtual-account-product-lifecycle creates rollback-scoped waiting vcnt payments for pre-reservation, customer-share deposit, customer-share balance, gift-coupon, and payment-change products against an existing stage booking, commits each issue through sanmopia_commit_virtual_account_issue, verifies payment revision 2 plus pending instruction outbox, records deposited lifecycle decisions, advances payment facts to approved revision 3, persists the pre-reservation apply_deposit_effects closeout plan tied to its deposit decision, verifies pre-reservation, customer-share, gift-coupon, and payment-change completion workflow routes, then rolls back. | e2e_proven | Backend 5c66e2d prevents an exact accepted-issue replay from advancing payment revision or redispatching instructions. Backend 96f8849 makes virtual-account deposit callbacks produce lifecycle facts instead of only payment workflow facts. Backend eed2fe0 moves customer instruction readiness behind a backend-owned commit port. Backend 563e783 persists lifecycle decision, local waiting payment fact revision, and instruction outbox in one Supabase transaction before customer success. Backend e8b38b6 gives provider-issued/local-write-failed paths a durable repair record instead of silent best-effort close/refund behavior. Backend 9240cee makes instruction dispatch independently retryable, worker-safe, and evidence-bearing without opening another virtual account. Backend 713f880 preserves superseded-account deposit evidence instead of mutating the active payment from a mismatched provider order. Backend 3152321 enforces that rule in Kill Bill callback ingestion by consulting frozen backend lifecycle facts before workflow start. Backend 38aac56 turns orphan repair from passive evidence into an executable backend worker with Supabase claim, action ports, and resolution evidence. Backend 3df31d0 prevents payment-change virtual-account issue from being treated as paid money and moves paid transition to deposit callback. Backend 60760f9 moves pre-reservation deposit side-effect planning behind a backend command and idempotency gate instead of UI/model mutation. Backend 0d44d0d makes that closeout durable in Supabase with RLS and stage proof. Backend 7edb5ea moves product-specific deposit-completion notice fan-out into backend-owned planning over the existing communication dispatch outbox. Backend stage smoke now proves virtual-account issue, deposit, payment-fact closeout, completion-route readiness for all modeled product purposes, and gift-coupon paid-checkout side effects through issued entitlement, fulfillment request, receiver fulfillment route, and frozen settlement template without frontend authority. Remaining work is live Kill Bill-originated provider proof plus durable workflow/API execution for gift-coupon closeout and settlement invalidation. |
SFC-20260710-PAY-003 | P0 | Backend / payment_processing | The KCP callback logs raw POST, reads noti_id, and invokes deposit handling at source-refs/sanmopia_web/application/controllers/api/Kcp.php:48-100; the log has no uniqueness or decision state at source-refs/sanmopia_web/application/models/Kcp_model.php:8-13. Deposit handling dedupes only through current paid state at source-refs/sanmopia_web/application/models/Payment_model.php:532-536, while the first execution mutates payment/reservation state and sends notices at source-refs/sanmopia_web/application/models/Payment_model.php:539-651 or issues coupon entitlement and notices at source-refs/sanmopia_web/application/models/Payment_model.php:707-731. | ProviderWebhookInboxEvent, ProviderWebhookBusinessEffectDecision, ProviderWebhookConflictRepairCase | IngestProviderWebhookCommand, ApplyVirtualAccountDepositEffectsCommand, ReplayProviderWebhookEffectsCommand | Backend 31e5d83 runtime-wires official Kill Bill ExtBusEvent verification, queue processing, service-role event persistence, operation/status mapping, and strict DB evidence. Backend 072b2e0 adds canonical payment fingerprint reuse plus one atomic Supabase RPC for inbox insert and PGMQ send. Same identity plus same digest increments replay evidence without requeue; different digest appends a repair-pending quarantine row without overwriting or processing the canonical event. Per-effect replay state remains unproven. | Inbox identity is provider plus provider event id; payload digest, provider transaction, payment revision, amount, event time, and effect idempotency keys are backend-only contract fields. | Synthetic stage proof passes first-delivery queueing, formatting-only duplicate replay, changed-amount quarantine, repeated-conflict observation counting, one-message worker execution, zero-message duplicate dispatch, and canonical-row immutability. Missing live Kill Bill-originated callback and partial-effect retry E2E proof. | runtime_wired | Backend 072b2e0 durably inserts the inbox event and PGMQ message in one transaction before acknowledgement. Same identity plus same digest returns duplicate; same identity plus different digest returns quarantined, opens repair evidence, and applies nothing. Remaining work gives payment closeout, reservation transition, coupon issuance, cash-receipt evidence, and notices stable effect keys so retries resume missing effects without repeating completed ones. |
SFC-20260710-PAY-004 | P0 | Backend / pricing_settlement | Payment terms distinguish app-paid reservation/customer-share charges from service balance paid directly to the caregiver, and state that company and caregiver cannot issue a receipt for that direct service balance at source-refs/sanmopia_web/application/views/about/terms.php:159-164. Runtime UI preserves that distinction: 본인부담 잔금 uses KCP at source-refs/sanmopia_web/static/js/mypage/reservation.js:608-693, while 서비스 잔금 only displays caregiver and substitute-caregiver bank accounts at source-refs/sanmopia_web/static/js/mypage/reservation.js:695-737; reservation detail repeats direct caregiver payment by cash or transfer at source-refs/sanmopia_web/application/views/mypage/reservation_detail.php:476-480. KCP handoff applies one configured site identity and generic product name 산모피아 to provider-collected products at source-refs/sanmopia_web/application/views/item/kcp/order_info_form.php:35-55, but does not carry a frozen payment-product or merchant-of-record discriminator. Generic completion form carries only cash-receipt request flag and purpose at source-refs/sanmopia_web/application/views/item/kcp/pay_form.php:15-19; no production form supplies cash_id_info. Customer receipt UI includes only reservation/customer-share payments, then always constructs KCP card_bill URL even when stored payment used bank transfer or virtual account at source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:50-75 and source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:85-127. | PaymentProductCashReceiptPolicy, ReservationPaymentCashReceiptEligibilitySnapshot, PaymentProviderHandoffSession, PaymentProviderCashReceiptEvidence, PaymentCashReceiptTaxEvidenceTimeline | PreRegisterReservationPaymentCommand, ReservationPaymentProviderHandoffIntent, KillBillPaymentEventIngestionHandler, ProjectCurrentCustomerReceiptTaxEvidenceArtifactCommand, ProjectCurrentSettlementTaxEvidenceDatasetRevisionCommand | Versioned product catalog owns merchant, collection channel, receipt issuer, eligibility, supported purposes, and denial reason. Payment pre-registration resolves one plan, rejects requested caregiver-direct receipt before gateway call, freezes request plus decision, and requires exact replay. Supabase RPC atomically persists actor, fee, cash-receipt, and provider-handoff snapshots while independently checking product policy and frozen handoff facts. Typed reservation provider handoff carries frozen amount, method, route, expected payment revision, expiry, idempotency key, source evidence, and fingerprint. Callback parses provider evidence once and persists frozen purpose plus vault identity rather than callback authority. Missing authority or purpose/identity/approval mismatch rejects tax evidence into reconciliation_required while accepted payment closeout continues, preventing cash-evidence faults from triggering full-payment compensation. Backend evidence timeline lists all append-only evidence for a payment, selects the current customer-visible artifact source, and emits all exportable approval/reversal rows for settlement tax datasets. | Strict pre-registration accepts payment id plus request state, purpose, and vault identity reference. Contract removed browser reservation, amount, method, purpose, plan, merchant, issuer, eligibility, provider authority, return URL, and provider payload authority. Response exposes immutable actor, fee, cash-receipt decision, and backend-owned handoff session snapshots. Provider callback may add approval/transaction/order evidence only. | Backend focused 62 tests, Ruff, Tach; stage migrations via pnpm supabase:db:push:stage; stage checkout handoff smoke, hosted customer receipt smoke, hosted settlement tax-export smoke, policy smoke, atomic accepted snapshot rollback proof, forged merchant-policy rejection, transactional reconciliation-status proof, reversal lineage proof, and focused artifact/tax-evidence timeline tests. Missing live Kill Bill-originated callback and live provider-originated reversal. | runtime_wired | Checkout/plugin and callback consume frozen snapshot, never recompute catalog policy. Refund/reversal retains original merchant policy. Receipt and tax-export projections consume backend-selected evidence timeline so customer UI cannot keep exposing stale approval after reversal. See ADR-026. |
PAY-004 reversal follow-up on 2026-07-12: backend appends
provider_refund_reversal evidence only from a successful refund ledger result,
latest approved receipt evidence, frozen eligibility snapshot, and explicit
provider cash-reversal reference. Missing facts enter
cash_receipt_evidence_status=reconciliation_required; refund completion remains
recorded without inventing tax reversal. Supabase backfills eligibility snapshot
ids onto modern evidence, exposes service-role latest-approved lookup, permits
the reversal evidence source, and enforces policy-lineage presence. Production
Kill Bill composition now injects the Supabase evidence store/reader. Focused 58
tests, Ruff, Tach, main import, stage migration/lint/typegen, and rolled-back
original-to-reversal lineage proof pass. Remaining reversal gap is live provider
callback proof, not backend lineage implementation.
PAY-004 receipt/tax-export follow-up on 2026-07-12: backend added
PaymentCashReceiptTaxEvidenceTimeline, ProjectCurrentCustomerReceiptTaxEvidenceArtifactCommand,
ProjectCurrentSettlementTaxEvidenceDatasetRevisionCommand, and a Supabase
payment-scoped evidence list reader. Customer receipt artifact selection now
chooses the latest customer-visible approval/reversal evidence from all
append-only rows for the payment; settlement tax export receives all exportable
approval and reversal lines with source evidence lineage. Focused tests prove a
refund reversal replaces stale customer approval exposure and settlement export
keeps approval-plus-reversal lineage.
PAY-004 hosted receipt follow-up on 2026-07-12: backend added authenticated route
GET /customer-receipt-tax-evidence-artifacts/{reservationBookingId}. The route
requires Supabase bearer token, rejects withdrawn users, checks SpiceDB
view_receipt on the reservation booking before reading payment evidence, and
returns only customer-safe artifact fields from backend-selected evidence
timeline. Focused HTTP tests prove reversal selection, provider reference
redaction, missing bearer rejection, and SpiceDB denial before Supabase evidence
read.
PAY-004 hosted settlement tax-export follow-up on 2026-07-12: backend added
authenticated route
GET /settlement-tax-evidence-dataset-revisions/{datasetRevisionId}. The route
requires Supabase bearer token, rejects withdrawn users, checks SpiceDB settle
for branch scope or review_hq_settlement for headquarters scope before reading
payment evidence, and returns backend-selected approval plus reversal dataset
lines with checksum and source evidence lineage. UI callers cannot choose rows,
recompute export totals, or receive provider payment/order/transaction
references. Focused HTTP tests prove branch authorization, headquarters
authorization, approval-plus-reversal lineage, provider reference redaction,
missing bearer rejection, and denial before evidence read.
PAY-004 hosted settlement tax-export stage proof on 2026-07-12:
pnpm supabase:smoke:stage:settlement-tax-evidence-route created booking
f6931f0c-1eaf-4cb8-a45a-7485c47934a4, seeded payment
stage-tax-evidence-payment-20260712122749-8c31df28, called the hosted dataset
route as the branch operator and headquarters administrator, verified both
scopes returned two approval/reversal lines without provider references, and
reaped stage-reservation-booking:f6931f0c-1eaf-4cb8-a45a-7485c47934a4 with
SpiceDB cleanup verification. Remaining PAY-004 proof is hosted checkout/plugin
binding and live Kill Bill-originated callback.
PAY-004 reservation checkout handoff stage proof on 2026-07-12:
pnpm supabase:smoke:stage:reservation-payment-handoff-session created
booking 113d0182-a79d-471d-a66b-d7183b053298, pre-registered payment
113d0182a79d471da66bd7183b053298, verified response handoff
reservation-payment-handoff:113d0182-a79d-471d-a66b-d7183b053298:113d0182a79d471da66bd7183b053298:0,
verified exact replay kept the same handoff key/fingerprint, verified Supabase
persisted provider_key=killbill, state=prepared, and
expected_payment_revision=0, and reaped the stage batch with SpiceDB cleanup
verification. Remaining PAY-004 proof is live Kill Bill-originated callback
through the restricted admission route.
PAY-004 hosted Kill Bill callback stage proof on 2026-07-12:
pnpm supabase:smoke:stage:killbill-payment-event-callback created booking
06bb3c50-aca5-4ab4-97e2-fd8a955729a6, pre-registered payment
06bb3c50aca54ab497e2fd8a955729a6, posted a signed official-shape
PAYMENT_SUCCESS ExtBus callback, verified persisted inbox event
killbill-event:sha256:3af8a2681cbb1d12985bf4eda20e0ede5e162efa50e9930b5e9d66d52165d08f,
verified one queued sanmopia_payment_webhook_processing message 7, verified
duplicate replay did not requeue work, dispatched the payment-webhook worker,
verified the worker archived message 7, verified completed Restate workflow
killbill:PAYMENT_SUCCESS:06bb3c50aca54ab497e2fd8a955729a6:stage-killbill-tx-20260712131444-9f9a82b5,
verified the payment record became approved with deposited_at, and reaped
the stage batch with SpiceDB cleanup verification. Remaining PAY-004 proof is
trusted Traefik/provider-originated callback deployment and live
provider-originated reversal.
PAY-004 callback-to-settlement stage proof on 2026-07-12:
pnpm supabase:smoke:stage:killbill-callback-to-settlement-completion created
booking b681a97a-3bb9-4e00-887d-c50d3799ef23, approved payment
b681a97a3bb94e00887dc50d3799ef23 through Kill Bill callback event
killbill-event:sha256:1aef72c067a736ae2bbbd3fcdb13e0efe2bdb1c35d3234093f4f397da22d001a,
continued payment workflow
killbill:PAYMENT_SUCCESS:b681a97a3bb94e00887dc50d3799ef23:stage-killbill-tx-20260712141353-8b4ed89b,
recorded service delivery, issued caregiver payout instruction
ec4f5565-8a01-57bf-b830-35e1e0a193b6, recorded branch payout deposit,
prepared branch and headquarters settlement, completed settlement with service
balance closeout event 9f805567-b079-484e-ad60-054a53d6a9fd, verified
branch settlement dashboard rows and board line items, and reaped the stage
batch with SpiceDB cleanup verification.
PAY-004 hosted Kill Bill refund callback reversal proof on 2026-07-12:
pnpm supabase:smoke:stage:killbill-refund-callback-to-settlement-reversal
seeded paid customer-share balance payment
stage-killbill-refund-payment-20260712132758-6e829503 and refund intent
stage-killbill-refund-intent-20260712132758-6e829503, posted an
official-shape Kill Bill PAYMENT_SUCCESS / REFUND callback, verified inbox
event
killbill-event:sha256:d0eae42c9d148f6d292ef50de640cb71f631bea830fb7a961271ac823adfed2b,
verified duplicate replay did not requeue, dispatched queue message 10,
recorded provider refund result
killbill:PAYMENT_SUCCESS:stage-killbill-refund-payment-20260712132758-6e829503:stage-killbill-refund-tx-20260712132758-6e829503,
mutated the paid row to partial_refunded, persisted settlement reversal,
requested all six reporting refresh targets, and reaped
stage-killbill-refund-callback-20260712132758-6e829503. Remaining PAY-004
proof is live Kill Bill-originated delivery through the restricted Traefik
admission route.
PAY-004 multi-refund callback correlation follow-up on 2026-07-12:
backend ProviderRefundResultFromLedgerHandler now resolves provider refund
results by explicit refund intent or provider-enriched correlation key matching
the ledger refund intent/idempotency key. Kill Bill refund callback ingestion
passes this key when present in provider-enriched payload fields. If a payment
has multiple refund intents and the callback lacks a correlation key, backend
records a repairable failure instead of choosing by amount or row order.
Follow-up callback enrichment now adds a provider-neutral
ProviderRefundCorrelationLookup application port and wires the Kill Bill HTTP
adapter to recover the refund correlation key from /payments/{paymentId} by
matching the callback paymentTransactionId to a REFUND transaction and
reading its transactionExternalKey. Focused tests cover callback fallback,
adapter extraction, and non-refund transaction rejection. Remaining proof is
live Kill Bill-originated delivery through the restricted Traefik admission
route with real provider transaction lookup.
PAY-004 hosted customer receipt stage proof on 2026-07-12:
pnpm supabase:smoke:stage:customer-receipt-tax-evidence-route created booking
ba16063f-0b9c-4357-9fc4-b21a91399872, seeded payment
stage-customer-receipt-payment-20260712123232-51185685, called the hosted
customer receipt route as the mother actor, verified backend-selected reversal
artifact
customer_receipt_tax_evidence:stage-customer-receipt-payment-20260712123232-51185685:ledger-4:stage-cash-receipt-reversal-20260712123232-51185685,
verified provider references stay hidden, and reaped
stage-reservation-booking:ba16063f-0b9c-4357-9fc4-b21a91399872 with SpiceDB
cleanup verification. Remaining PAY-004 proof is live Kill Bill-originated
callback and live provider-originated reversal.
PAY-004 legacy mining follow-up on 2026-07-12 found three still-open source
features not covered by cash-receipt gateway evidence alone:
VoucherSelfPayReceiptArtifact for admin document id 7 / type7.xlsx voucher
self-pay receipts, BranchSettlementRemittanceExport with method-specific fee
rules from type18.xlsx, and SettlementArtifactCollection for branch/HQ
board-scoped settlement data-room downloads. Evidence: source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:1057,
source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741,
and source-refs/sanmopia-admin/application/controllers/DataRoom.php:86.
| SFC-20260710-PAY-005 | P0 | Backend / pricing_settlement | Admin gift-coupon deletion assigns the structured provider refund response directly to a boolean variable, then marks payment refunded and deletes the coupon regardless of nested status at source-refs/sanmopia-admin/application/models/Coupon_model.php:164-207. The provider wrapper proves the response is always a non-empty array whose actual terminal result is status at source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31-59. | GiftCouponRefundSaga, ProviderRefundResultTerminalDecision, GiftCouponRefundRepairCase | RecordGiftCouponProviderRefundResultCommand, CompleteGiftCouponEntitlementCancellationCommand | Existing gift-coupon refund policy/contract foundation is partial; this adapter result gate and repair path are not runtime-proven. | Typed provider result must carry attempt id, provider result code/reference, accepted/rejected/unknown outcome, expected payment/entitlement revisions, and idempotency key. | Missing provider-rejected and provider-unknown tests proving refund flag and entitlement remain unchanged, plus retry/reconciliation proof. | foundation | Never coerce provider response containers to success. Persist attempt/result first; only terminal provider success may transition payment refund state and release the entitlement-cancellation barrier. Rejected or unknown outcomes keep coupon/payment facts intact, block settlement completion, and open a retryable repair case. |
| SFC-20260710-PAY-006 | P0 | Backend / pricing_settlement and operator_access | Customer payment paths call inline compensation after local failure and discard its result at source-refs/sanmopia_web/application/controllers/api/Payment.php:164-180 and source-refs/sanmopia_web/application/controllers/api/Payment.php:215-218. Empty provider-module output is collapsed to generic code 9502 at source-refs/sanmopia_web/application/libraries/Kcppay.php:194-203, while automatic cancel always returns a local status => false envelope even though its provider result code may represent success at source-refs/sanmopia_web/application/libraries/Kcppayment.php:418-437. The only legacy repair surface accepts raw provider ids and dumps one response at source-refs/sanmopia-admin/application/controllers/cli/Kcp.php:12-24. | PaymentProviderOperationReconciliation, PaymentProviderAttempt, PaymentOperationRepairProjection, PaymentProviderOperationReconciliationPolicy | ReconcilePaymentProviderOperationCommand, RetryPaymentCloseoutCommand, RetryCompensationRefundCommand | Provider attempts now preserve provider_unknown; append-only reconciliation facts freeze provider evidence, payment/refund ledger revisions, retry time, settlement block, and safe next action. DB constraints prohibit unknown-result retry and permit retry only after provider not_found. Compensation intents and repair execution remain separate existing slices. | Repair query exposes provider/local states, payment and refund ledger revisions, attempt lineage, outcome certainty, retry eligibility/time, settlement block, and allowed actions. Commands require SpiceDB grant, expected revisions, reason, and idempotency. | Stage transaction proved unknown attempt plus reconciliation persistence with await_provider_certainty and settlement blocking, then rolled back all smoke data. Missing public operator query/command, repeated reconciliation history, SpiceDB runtime gate, and live Kill Bill lookup-before-retry E2E. | runtime_wired | Persist accepted, rejected, not_found, or unknown separately for every charge/refund operation. Unknown always blocks settlement and awaits certainty. Only confirmed not_found permits provider retry. Accepted provider work with missing local fact resumes local closeout; matching terminal facts record no-op reconciliation without editing ledger amounts. |
PAY-006 follow-up on 2026-07-12: backend public query
GET /reservation-bookings/{reservationBookingId}/payment-provider-operation-reconciliations
returns newest-first immutable reconciliation history. Supabase Auth supplies
actor identity and SpiceDB close_reservation_finance is the sole access
decision; application tests prove denial occurs before Supabase read. Contract
schema exposes outcome certainty, revisions, settlement block, retry time, and
safe next action without editable amounts. Code composition, HTTP behavior,
Tach, and contract gates pass. Stage route E2E remains deployment-pending, so
this evidence does not promote PAY-006 to e2e_proven.
PAY-006 command follow-up on 2026-07-12: public reconciliation mutation no
longer accepts provider outcome, provider/payment/booking context, operation
kind, request key, local-write state, or evidence from browser/operator input.
Backend resolves those facts from the provider attempt and ledgers, binds the
attempt to the SpiceDB-authorized booking, performs an audited Kill Bill lookup,
and maps official transaction type/status into the generic outcome. Exact replay
returns the existing fact without a second provider call. Supabase RPC locks the
attempt, payment record, and refund ledger rows and enforces payment/refund
revision CAS before append. Stage migration, schema lint, type generation, and
rollback-safe atomic RPC smoke pass. Live deployed HTTP-to-Kill-Bill proof remains
pending; PAY-006 stays runtime_wired rather than e2e_proven.
2026-07-11 family authority, payment, and privacy delta
Section titled “2026-07-11 family authority, payment, and privacy delta”These rows are new authority boundaries, not duplicates of generic family membership or payer-recipient rows. Detailed evidence and completion gates live in Family Authority, Payment, And Privacy Gap Mining.
| feature_id | priority | lane_owner | source_evidence | ddd_aggregate | command_query | persistence | contract | e2e_proof | status | backend_owned_design |
|---|---|---|---|---|---|---|---|---|---|---|
SFC-20260711-FAM-001 | P0 | Backend / member_management and reservation_operations | Mother-only contracting and authenticated-profile booking at source-refs/sanmopia_web/application/views/service/step1.php:74-93, source-refs/sanmopia_web/application/views/service/step1.php:193-209, and source-refs/sanmopia_web/application/controllers/api/Service.php:18-59; spouse is emergency contact, not sponsor authority. | FamilySponsorshipGrantorPolicy, FamilySponsoredReservationDraft, SponsoredReservationContractAcceptance | Grant/revoke sponsorship, submit draft, accept/decline contract, consume acceptance, and acceptance query CQRS | Backend 109a717 persists revisioned grants, drafts, immutable acceptances, one-time consumptions, idempotency, RLS, and SpiceDB relationship outbox work through Supabase transaction functions. Backend 48abf1c separates request correlation from booking UUID evidence and preserves terminal workflow rows on exact Restate replay; backend ddd1559 reuses the settlement orchestrator and verifies symmetric DB/SpiceDB cleanup. Backend 5414fa4 adds optimistic contract-catalog rollover plus complete negative-request reaper registration. Stage schema is applied through backend b0bbd21. | Contract 15b0261 publishes all six family-sponsorship routes, shared reservation-intent schemas, generated TypeScript types/validators, and optional booking-start acceptance id. Backend derives grantor, sponsor, mother, contract version, request fingerprint, grant/draft revisions, acceptance time, branch operator, address reference, and price reference; browser submits intent only. | The latest continuous stage run created replacement grant 55784662-1e77-4ceb-92b6-4d56511c2a59, booking 3130d737-d45f-41ef-a4c6-d85cdcd42783, payer snapshot 73f321bf-7914-5cab-9a2e-aba9640c3771, and closeout event bd63b47d-f2a2-49dd-9a79-e5ae6809fdc7. It passed grant and draft replay, changed-payload rejection, mother accept/query/decline, stale draft rejection, cross-intent reuse denial, revoked-and-replaced grant acceptance rejection, previous contract-version acceptance rejection, one-time consumption, exact booking replay, delegated payment, service delivery, settlement, SpiceDB permission removal, and DB reaping. | runtime_wired | Booking creation preserves sponsor actor and consumed grant revision while requiring explicit mother contract acceptance before financially binding progression. |
SFC-20260711-FAM-002 | P0 | Backend / member_management, reservation_operations, and pricing_settlement | Distinct legacy deposit, balance, pre-reservation, and payment-change routes at 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, and source-refs/sanmopia_web/application/controllers/api/Payment.php:681-709. | PaymentDelegation, ReservationPaymentActorAuthorityDecision, ReservationPaymentActorSnapshot | GrantReservationPaymentDelegationCommand, PreRegisterReservationPaymentCommand, GetReservationPaymentPreRegistrationQuery | Backend c5c69c8 adds a positive delegation amount ceiling, exact reservation and deposit/balance scope, effective interval, consumed revision, and evidence. Supabase persists the waiting obligation and atomically freezes the authorized actor; SpiceDB remains the coarse pay_pre_reservation capability while domain and DB policy enforce the exact payment obligation. | Public pre-registration accepts only paymentId, Supabase bearer identity, and Idempotency-Key. Method, purpose, product plan, amount, actor kind, delegation revision, and capability decision are backend-owned. | 2026-07-11 stage E2E denied caregiver payment, converged the family payer grant, enforced the exact amount ceiling, pre-registered the customer-share deposit, replayed the same command, and rejected a changed idempotency key. Remaining proof: balance, pre-reservation conversion, change-adjustment, expired/under-limit negative HTTP cases, and provider-live E2E. | runtime_wired | One broad SpiceDB relationship never decides product or amount. It admits the command; backend aggregate and Supabase RPC must match booking, purpose-derived scope, revision, interval, and ceiling before Kill Bill receives the backend amount. |
SFC-20260711-FAM-003 | P0 | Backend / pricing_settlement and customer_engagement | Legacy checks owner then notifies mother at source-refs/sanmopia_web/application/controllers/api/Payment.php:95-113 and source-refs/sanmopia_web/application/controllers/api/Payment.php:182-193; modern recipient code currently scans grants active at later event time. | ReservationPaymentActorSnapshot, PaymentDelegation, PaymentCompletionRecipientDecision | PreRegisterReservationPaymentCommand, GetPaymentCompletionRecipientDecisionQuery | Backend c5c69c8 persists a service-role-only immutable actor snapshot containing actor/mother ids, actor kind, branch, family account, delegation id/revision/scope/ceiling, payment purpose/product/amount, evidence, idempotency, and authorization time. DB triggers reject update/delete except registered stage reaping; mutable payment and delegation rows do not reverse-own the snapshot through FKs. | Handoff response exposes the frozen actor projection but accepts no actor fields. Historical payment facts link the snapshot id; later grant lookup is not payer identity authority. | Stage reservation 92961f7e-7896-4441-af53-8fb8825d6fe2 froze actor snapshot da2c3402-0d85-52a2-b6b4-bcf7f6c189bf, then revoked and reaped the grant while proving snapshot retention. Remaining proof: delegate replacement, payment-completion recipient routing, historical receipt/refund visibility, and provider callback consumption. | runtime_wired | Grant proves authority at handoff. The immutable snapshot proves historical payer identity and amount after current family grants change. Every completion, receipt, refund, and notification query must consume it. |
SFC-20260711-FAM-004 | P0 | Backend / pricing_settlement and operator_access | Owner-only legacy detail/receipt access at source-refs/sanmopia_web/application/controllers/MyReservation.php:117-175, source-refs/sanmopia_web/application/controllers/MyReservation.php:329-349, and source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:121-127. | PaymentParticipantVisibilityPolicy, RefundStatusVisibilityProjection, PaymentDelegation | GrantReservationPaymentDelegationCommand, RevokeReservationPaymentDelegationCommand, GetPaymentParticipantFinancialStatusQuery | Booking authorized_payer plus distinct view_payment, view_refund, and view_receipt permissions are bound to revisioned reservation-scoped delegation rows. Service-role Supabase RPCs atomically persist grant/revoke and enqueue PGMQ touch/delete; the shared worker converges expiring SpiceDB relationships. Payment pre-registration now consumes that relationship and freezes exact grant use into the actor snapshot. | Care visibility does not imply finance visibility. Mother, authorized payer, branch finance, and HQ finance use explicit financial permissions; caregiver assignment remains insufficient. | 217 changed-slice tests, Tach dependency/interface/external gates, Supabase DB lint with zero errors, authenticated grant/replay/revoke/reaper proof, and the full booking-to-settlement stage chain pass. Remaining proof: inventory and authenticate every payment/refund/receipt read projection. | runtime_wired | Persisted family payer capability now reaches a real payment instruction and survives later revocation as frozen evidence. Remaining financial reads must use explicit participant visibility rather than booking view or family membership. |
SFC-20260711-FAM-005 | P0 | Backend / member_management and care_delivery | Reservation-specific ownership checks at source-refs/sanmopia_web/application/controllers/MyReservation.php:213-222, caregiver report ownership/content at source-refs/sanmopia-manager/application/controllers/Report.php:21-74 and source-refs/sanmopia-manager/application/models/Report_model.php:44-67. | ReservationCareHistoryAccessGrant, ReservationCareHistoryContentAuthorityDecision, CustomerDailyReportReviewAuthority | Grant/revoke/access CQRS plus GetReservationCareHistoryQuery; review mutation remains separate | Backend 903e68d persists revisioned access and SpiceDB outbox. Backend a88326b adds shared scope, mother/delegate content authority, strict Pydantic projection, service-role Supabase keyset RPC, backend option-label/note projection, opaque cursor, non-enumerating HTTP boundary, and composition. Corrective stage migration normalizes RPC record contract while retaining strict CMS metadata parsing. | Contract e4cc9ed publishes grant lifecycle. Contract 0d576f2 publishes GET /family-accounts/{familyAccountId}/reservations/{reservationBookingId}/care-history, OpenAPI, JSON Schema, TypeScript projection types, path builder, and bounded query validator. Public content contains no mother/grant authority metadata. | Stage booking 9c3b61e4-e81e-424d-8d0e-a73b7f53775a, grant e3c7ef7a-51c5-47e4-90e3-9486e8915c21: service-role projection, mother/delegate read, field order, choice label, note, forged review denial, revoke, post-revoke 404, DB/SpiceDB reaper. Backend focused tests, Ruff, Tach, Supabase lint; contract 396 tests. | e2e_proven | Family read never grants review/rating mutation. Backend owns actor resolution, report interpretation, ordering, summary, and pagination. Frontend renders projection only. See ADR-024. |
SFC-20260711-FAM-006 | P0 | Backend / member_management and platform authorization | Current grant policy treated any non-null revocation as inactive even when evaluating earlier time; no operational revoke command or relationship-delete outbox existed. | FamilyAuthorityEffectiveInterval, PaymentDelegation | RevokeReservationPaymentDelegationCommand, GetFamilyAuthorityAsOfQuery | The shared effective interval remains domain authority. Reservation payment delegation now persists revision, actor, reason, evidence, idempotency keys, and timestamps through an atomic Supabase RPC and emits a PGMQ SpiceDB relationship delete. Exact replay ignores backend-generated clock drift but rejects changed actor, reason, or expected revision. Sponsorship and care-history still need equivalent persisted lifecycle wiring and a general as-of query. | Historical use remains valid only when granted_at <= used_at < revoked_at; current access stops at revocation. | Colocated tests plus authenticated stage HTTP E2E prove operational revoke, exact replay, queue dispatch, SpiceDB permission removal, and test-data cleanup. SQL smoke proves revision 2 and one delete message inside a rollback transaction. | runtime_wired | Reservation payment authority no longer requires hard delete or manual SpiceDB cleanup. Remaining work generalizes persisted as-of reads and lifecycle outbox handling to sponsor and care-history grants. |
SFC-20260711-FAM-007 | P1 | Backend / member_management and platform access | Owner-only legacy reservation lists at source-refs/sanmopia_web/application/controllers/MyReservation.php:22-48 and source-refs/sanmopia_web/application/controllers/MyReservation.php:73-98; current family-account RLS exposes authority metadata to any linked family member. | FamilyAuthorityGrantDirectoryVisibilityPolicy, FamilyAuthorityDirectoryView | GetFamilyAuthorityDirectoryQuery, GetFamilyAuthorityAdministrationProjection | Backend bb4d6ee adds a Pydantic authority-directory projection and HTTP read boundary. own view returns only the actor’s sponsorship, payment-delegation, and care-history grants; administration view requires mother domain authority plus SpiceDB administer on the family account. Backend 4477372 drops authenticated raw table read policies and revokes direct authenticated select on family authority grant tables so Supabase RLS cannot become a competing directory. Backend 13dc531 adds inactive-actor proof for withdrawn Supabase sessions and revoked family members. Backend dde8177 adds stage HTTP proof to the care-history access smoke. | HTTP response excludes authority evidence and does not let browser choose actor/member ids. Subject sees own effective grants; mother administrator sees managed family authority projection through backend permission. Service-role backend remains the raw grant reader. | Focused API/HTTP tests prove own-view filtering, admin SpiceDB denial, non-mother admin rejection, hidden authority evidence, withdrawn-member denial, and revoked-family-member denial. Lexical migration tests prove legacy policies are dropped, authenticated raw reads are revoked, service-role reads remain, and table comments point readers to backend API. Stage booking f175bd00-441f-4801-b21d-3081bfa75682, grant aecf7aa6-d034-407d-9148-74deb5f87d1c: active delegate own directory visibility, hidden evidence, non-admin administration denial, revoke, post-revoke disappearance, SpiceDB cleanup, and registered test-data reap. | e2e_proven | Family membership is not authority-directory administration. Backend query permission now owns directory visibility; raw Supabase grant rows are not browser-facing authority directory surfaces. |