Skip to content

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_idlane_ownersource_evidenceddd_aggregatecommand_querypersistencecontracte2e_proofstatus
  • 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:

    WorkstreamOwner boundaryDelegation ruleExpected output
    Hidden legacy feature mining and documentationSource evidence laneOne 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 implementationfrontend-repo Atomic 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 implementationBackend/contract feature laneDelegate 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 integrationMain migration controlNever 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_identity only 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_identity for 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 on domain.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_identity for 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 adds amount_source_label for source-amount rules.

  • Regional benefit profile metadata now belongs to backend policy data: regional_benefit_profile_key, service_day_bonus_count, and settlement_participation_code on RegionalBenefitRule. FinalizeReservationChargeWithRegionalBenefitHandler now resolves a backend-owned RegionalBenefitDecision before building ReservationPriceSummaryInput and charge snapshot evidence. HTTP/API request models accept an acceptedRegionalBenefitDecision, 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 overwriting requested_by_user_id with the mother user.

  • 2026-07-08 reservation scenario loop is now stage-smokeable beyond booking: supabase:smoke:stage:payment-continuation-after-service-delivery creates a booking, starts a paid payment workflow, observes waiting_for_financial_facts while 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-completion creates a reservation, ingests synthetic Kill Bill PAYMENT_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-visible CaregiverPayoutAcknowledgement command.

  • 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 acknowledged receipt-state projection consumed by caregiver/operator UX. The same stage smoke now asserts caregiver_payout_receipt_state=acknowledged and 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-guard after removing Supabase app_metadata role/profile authority. Stage created reservation f3423929-ad23-4129-a4b4-8f2f74d1f265 and service-balance closeout event ad2d90f2-4b61-46bd-af7d-5a7218e0a296, then advanced the financial lifecycle through branch/HQ settlement completion under backend/SpiceDB authority.

GapLegacy evidenceModern ownerRequired migration
Cancellation side effectssource-refs/sanmopia-admin/application/config/constants.php:116, source-refs/sanmopia_web/application/models/Reservation_model.php:989reservation_operations / ReservationLifecycleCommand, pricing_settlement / CancellationRefundLifecycleStatus transition, instant refund, coupon restore, Momfirst unlink, side-effect outbox, and refund/coupon ordering must be backend-owned.
Weekly/extension/weekend/holiday servicesource-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:778, source-refs/sanmopia-admin/application/models/Manage_system_model.php:51reservation_operations / ServicePeriodPlan, service_calendar / HolidayPolicyExecutionAndImpactInvalidationFreeze 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 settlementsource-refs/sanmopia-admin/application/controllers/Calculate.php:151, source-refs/sanmopia-admin/application/controllers/DataRoom.php:218pricing_settlement / SettlementActionJournal, SettlementStatementWorkflow, SettlementDataRoomArtifactRequestSeparate HQ request, branch confirmation, Danbee settlement, inter-office confirmation, export revision, signed grants, repair audit, and actor-scoped transition journal.
Custom adjustment and negative linessource-refs/sanmopia-admin/application/views/modal/modal_other_service_add.php:18, source-refs/sanmopia-admin/application/controllers/Calculate.php:184pricing_settlement / SettlementManualAdjustmentLineVersioned adjustment catalog, signed amount direction, reason, actor, statement linkage, and no freeform browser line math.
Payment change, refund, partial refundsource-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:39pricing_settlement / PaymentChangeAdjustmentAmountBreakdown, PaymentRefundIntentFreeze delta, provider context, refund quote, partial-cancel event, ledger reversal, receipt artifact, and Kill Bill-backed provider orchestration.
Caregiver matching evidencesource-refs/sanmopia-admin/application/models/Matching_model.php:44, source-refs/sanmopia-admin/application/models/Matching_model.php:724caregiver_assignment / CaregiverCandidateOrderingPolicyFreeze score components, distance/travel freshness, schedule, pet, grade/class, branch scope, and deterministic tie-breaker evidence.
Multi-caregiver payrollsource-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:8caregiver_assignment / CareTeamRosterAssignmentDecision, pricing_settlement / CaregiverPayoutPolicyProfilePersist role slots, assignment terms, payout snapshots, tax election, custom pay audit, and prevent salary evidence deletion.
Family, delegated payer, authoritysource-refs/sanmopia_web/application/views/service/step1.php:188, source-refs/sanmopia_web/application/controllers/api/Service.php:70member_management / ReservationPartyAuthoritySnapshotSeparate mother, sponsor, payer, emergency contact, contact-only viewer, refund recipient, document viewer, and delegation validity windows.
Service-area profilesource-refs/sanmopia-admin/application/models/Branch_model.php:289, source-refs/sanmopia-admin/application/models/Branch_model.php:345branch_operations / ServiceAreaDecisionSnapshotEffective-dated coverage profiles, address normalization, serviceability/counsel/impossible evidence, and booking-bound snapshots.
Branch/HQ conflict and auditsource-refs/sanmopia-admin/application/controllers/Reservation.php:651, source-refs/sanmopia-admin/application/controllers/Reservation.php:821reservation_operations / ReservationCollaborationCommand, operator_access / ActorStageCapabilityProjectionTyped 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.

PriorityGapLegacy evidenceModern ownerRequired migration
P0Service duration, holiday, extension, and local-support paritysource-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-107service_calendar / ServiceCalendarCompatibilityDecision, HolidayPolicyExecution, reservation_operations / ReservationContinuationLink, pricing_settlement / RegionalBenefitDecisionExecute 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.
P0Charge, discount, support-item, and custom amount hardcodingsource-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-985pricing_settlement / ReservationChargeLineCatalogProjection, PaymentProductPlanTemplate, PaymentAdjustmentCatalog, PreReservationCreditPolicy, RegionalBenefitRuleMove 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.
P0Settlement data-room worklist and export workflowsource-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-57document_reporting / ReservationDocumentExportWorklist, pricing_settlement / SettlementDataRoomArtifactRequest, SettlementDataRoomCollectionExportReaderReplace 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.
P0Family, proxy payer, contact, refund, and document authoritysource-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-704member_management / ReservationPartyAuthoritySnapshot, pricing_settlement / PayerSnapshot, document_reporting / DocumentRecipientAuthoritySeparate 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.
P0Branch coverage and address profile bindingsource-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-606branch_operations / BranchServiceAreaDecisionSnapshot, ServiceAreaPolicyVersionBind 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.
P0Caregiver candidate rank, distance, and pay authoritysource-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-263caregiver_assignment / CaregiverCandidateOrderingPolicy, CaregiverCandidateSnapshot, pricing_settlement / CaregiverCompensationQuote, CaregiverPayoutInstructionFreeze 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.
P1Source string, id, amount, and date compatibilitySame rows above plus source-refs/sanmopia_web/application/views/service/step1.php:188-209migration_governance / SourceCompatibilityCatalogConvert 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.
GapLegacy evidenceModern ownerRequired migration
Provider refund and paid-row transitionsource-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:429pricing_settlement / PaymentRefund, ProviderRefundPaidRowTransitionRefund 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 refundsource-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:42pricing_settlement / PreReservationCancellationRefund, reservation_operations / PreReservationCancellation, payment_processing / ProviderRefundCommandPlanAdmin 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 supportsource-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:40pricing_settlement / PartialPaymentRefund, ProviderPartialRefundCapabilitySnapshot, PartialPaymentRefundProviderCommandPlanSource 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 closeoutsource-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:4514pricing_settlement / PaymentChangeCloseoutUI-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 regenerationsource-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:151promotion / CouponRestoration, pricing_settlement / RefundSideEffectPlanSource 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 depositsource-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:4386pricing_settlement / SettlementContinuationSource 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.

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 itemSource evidenceModern target bounded contextModern abstraction note
Voucher support subsidy and customer charge displaysource-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-332pricing_settlement / VoucherSupportSubsidyChargeSnapshot, pricing_settlement / VoucherServiceBalanceCustomPriceSnapshot, reservation_operations / ReservationChargeFinalization, ReservationPaymentScheduleBackend 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 downgradesource-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-3887promotion_entitlement / ProductGiftCouponEligibility, pricing_settlement / CancelledGiftCouponCommissionPolicyAttendance-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 electionsource-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-1959pricing_settlement / CaregiverCompensationQuote, CaregiverPayoutInstruction, CaregiverTaxElectionMain/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 catalogsource-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:106pricing_settlement / SettlementRemittanceAccountSnapshot, SettlementPricingPolicyHardcoded 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 validationsource-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-914pricing_settlement / VoucherPriceCatalogImport, SupportSubsidyRuleCatalog, service_calendar / ServiceCalendarOptionPriceCatalogSpreadsheet 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 overridesource-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-252caregiver_assignment / CustomerSmartMatchingPreferenceSnapshot, CandidatePreviewPolicy, CaregiverPickOverrideCommandCustomer 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 itemSource evidenceModern target bounded contextModern abstraction note
Admin reservation status command surfacesource-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-328reservation_operations / ReservationLifecycleCommandSurface, SourceReservationStatusTransitionCatalog, ReservationWorkspaceConflictGuardAdmin 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 versionsource-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-5256reservation_operations / ReservationBranchHandoffCommand, ReservationPriceVersionRequoteCommand, ReservationMemoRevision; pricing_settlement / RequoteImpactPlanBranch 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 rulessource-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-201caregiver_assignment / CareTeamSlotPolicy, AssignmentCandidateScoreProjection, AssignmentOverrideCommand, AssignmentChangeHistoryReadModelAdmin 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 catalogsource-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-307customer_engagement / MobileAppEntryPoint; pricing_settlement / PaymentRedirectCapability; platform / NativeShellBridgePolicyNative 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 itemSource evidenceModern target bounded contextModern abstraction note
Product gift coupon settlement recognition timingsource-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-1080promotion_entitlement / ProductCouponEntitlementSchedule; pricing_settlement / PromotionalCouponCostRecognition, CancelledGiftCouponCommissionPolicySource 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 authoritysource-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-1144pricing_settlement / SettlementPricingPolicy, BranchSettlementFeeCatalog, SettlementStatementLineProjection, SettlementCompletionReviewSource 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 itemSource evidenceModern target bounded contextModern abstraction note
Settlement workbook render-time formula authoritysource-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-336pricing_settlement / SettlementExportDatasetSnapshot; document_reporting / SettlementExportWorksheetPolicy, SettlementArtifactVersionSource 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 boundarysource-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-123document_reporting / PrintableTemplateRegistry, DocumentRenderProviderAdapter, StaticPdfTemplateArtifact, DocumentRenderAttempt, DocumentAccessGrantSource 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 rewardsource-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-615care_delivery / DailyCareReportServiceDatePolicy; customer_daily_report_review / ReportFinalityDecision, CustomerDailyReportReviewRewardGrant; document_reporting / DailyReportArtifactSeriesSelectionSource 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 itemSource evidenceModern target bounded contextModern abstraction note
Branch request notification routing and special secondary recipientsource-refs/sanmopia_web/application/controllers/api/Reservation.php:141-190, source-refs/sanmopia_web/application/controllers/api/Reservation.php:192-228reservation_operations / ReservationCustomerChangeRequestWorkflow; communication_delivery / BranchActionNotificationRoutingPolicyCustomer 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 writesource-refs/sanmopia-admin/application/models/Reservation_model.php:5560-5577, source-refs/sanmopia-admin/application/models/Reservation_model.php:5580-5595pricing_settlement / PreReservationCancellationRefundIntent; reservation_operations / PreReservationStatusTransitionCommandAdmin 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 grantssource-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-114document_reporting / BranchDocumentMailbox; document_reporting / DocumentAttachmentGrant; operator_access / BranchDocumentMailboxPermissionLegacy “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 typesource-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-129document_reporting / ReservationDocumentBundlePolicy; document_reporting / ReservationDocumentSelectionTokenLegacy 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 moderationsource-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-435care_delivery / CaregiverReviewVisibilityDecision; customer_engagement / PublicCaregiverReviewProjectionSource 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 workflowsource-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-100caregiver_engagement / CaregiverHeadquartersRequestThread; communication_delivery / HeadquartersRequestNotificationPolicyManager 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 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.

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.

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 ServiceBalancePaymentCloseout decisions, 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.

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 evidenceExisting modern targetReconciliation requirement
source-refs/sanmopia-admin/application/config/constants.php:291, source-refs/sanmopia_web/application/controllers/api/Service.php:296pricing_settlement / PriceCatalogVersionResolution, ReservationPriceVersionSnapshotFreeze 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:647pricing_settlement / AdditionalServiceChargePolicyReplace 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:367service_calendar / ServicePeriodCalendarPolicy, RegionalBenefitServiceDayBonusService 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:749pricing_settlement / VoucherServiceAddOnPolicy, VoucherPureAdditionalServiceBalanceVoucher 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:856pricing_settlement / ReservationRefundCloseout, PreReservationRefundPolicy, PaymentChangeAdjustmentRefund, 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:4382pricing_settlement / ExternalCounterpartySettlementWorkflow, BranchSettlementWorkflow, HeadOfficeSettlementLedgerKeep 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:3909pricing_settlement / PaymentMethodFeePolicyCompare 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:760caregiver_assignment / CaregiverMatchScore, CaregiverTravelTimeEstimateMatching 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:112pricing_settlement / CaregiverPayoutInstruction, CaregiverTaxElectionMain/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-158pricing_settlement / MotherVisibleChargeSummary, pricing_settlement / ReservationPaymentActionAvailability, pricing_settlement / CustomerPaymentInstructionProjection, pricing_settlement / VirtualAccountInstructionDisplayGrantMother-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:411reservation_operations / ServicePeriodPlan, ServiceDayOccurrenceVoucher 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:233pricing_settlement / CouponPrepaymentQuote, promotion_entitlement / PromotionEntitlementCoupon 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:856pricing_settlement / PaymentAdjustmentQuote, PaymentChangeAdjustmentPayment-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:3177pricing_settlement / VoucherInhomeAddOnQuoteVoucher 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:4155pricing_settlement / ServiceBalanceOverrideDecision, VoucherPureAdditionalServiceBalanceService-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:456pricing_settlement / PaymentProviderTemplatePayload, PaymentProductCommunicationRoutePre-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:383pricing_settlement / PaymentCloseout, RefundQuote, PaymentRefundIntentNo 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-4419pricing_settlement / SettlementCompletionReview, SettlementLineAcknowledgement, SettlementComponentAcknowledgementRevisionBoard 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:3748pricing_settlement / PaymentProductPlan, LegacyPaymentVersionCompatibilityVoucher 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-2878pricing_settlement / SettlementArithmeticDecision, SettlementManualAdjustmentLine, SettlementClientTotalComparisonBrowser 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 evidenceModern targetStatusRequired backend replacement
source-refs/sanmopia-admin/application/controllers/Reservation.php, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.jsreservation_operations / reservation_collaborationPartialReservationOperationWorkspace 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.phpreservation_operations / service_suspensionPartialDurable 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.phpreservation_operations / service_period, reservation_operations / service_calendarPartialImmutable 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.phpbranch_operations / service_area_policyPartialBooking-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-33pricing_settlement / CustomerPaymentInstruction, PaymentProviderApprovalRequestPartialCustomerPaymentInstruction 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 pathspricing_settlement / payment_refundPartialKill 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_TBpricing_settlement / payment_change_adjustmentPartialFrozen 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.phppricing_settlement / settlement_statementPartialSettlementStatementKind, 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.phppricing_settlement / settlement_data_roomPartialPersisted 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.phpcaregiver_assignment / caregiver_matchingPartialCandidateSnapshot -> 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-855caregiver_assignment / CaregiverCandidateOrderingPolicy, CaregiverCandidateRecommendationSetPartialBackend 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.phppricing_settlement / caregiver_compensationPartialPayout-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-170pricing_settlement / AdminCaregiverPayoutStatementProjection, CaregiverPayoutAdjustmentCommand, CaregiverPayoutCompletionCommand, CaregiverPayoutCompletionAmountGuard, CaregiverTaxElection, CaregiverPayoutMemoRevision, ReservationFinanceSettlementCompletionGatePartialAdmin 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.phpcaregiver_performance_recognitionPartialCaregiverGradeSnapshot 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-542caregiver_profile / caregiver_credential_restriction_workflow, caregiver_assignment / caregiver_availability_exceptionPendingAdmin 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-528caregiver_performance_recognition / CaregiverProfileScoreRevisionPolicy, CaregiverProfileScoreRevisionPlan, CaregiverProfileGradeScoreRevisionBackend foundation + contractBackend 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-747caregiver_performance_recognition / CaregiverEvaluationCappedScoreLedger, CaregiverPerformanceScorecardBackend foundation + contractBackend 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-140caregiver_performance_recognition / RecordCaregiverEvaluationScoreCommand, CaregiverEvaluationScoreEntry, CaregiverPerformanceScorecardWorklistQueryBackend foundation + contractBackend 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-2475caregiver_performance_recognition / CaregiverScorecardDetailReadModel, CaregiverEvaluationScoreBackfillCommand, CaregiverClassChangeProposal, CaregiverGradeRecalculationWorkflow, CaregiverScoreSummarySnapshotPendingAdmin 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.phpdocument_reporting / printable_documentPartialReservationDocumentCatalog, 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-883pricing_settlement / CustomerPaymentReceiptProjection, document_reporting / CustomerReceiptArtifact, document_reporting / CustomerReceiptArtifactRevocationAfterRefund, pricing_settlement / SettlementReceiptLinkProjectionRefreshPartialLegacy 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 fallbackmember_management / family_accountPartialReservationPartyAuthoritySnapshot 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 bucketsBackend projections across pricing_settlement, reservation_operations, document_reportingPendingCustomerPaymentActionProjection, 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-414customer_engagement / gift_coupon_offer_catalog, pricing_settlement / gift_coupon_payment_product_planPartialGift-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/18reservation_operations / pre_reservation_conversionPartialPreReservationConversionWorkspace 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 calculatorpricing_settlement / public_fee_guide_catalogPartialPublicFeeGuideCatalogProjection 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 branchesservice_calendar / holiday_policy_executionPartialHolidayPolicyExecutionAndImpactInvalidation 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.jspricing_settlement / settlement_collection_export_repositoryPartialSettlementCollectionExportRepository 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.jscaregiver_assignment / assignment_decision_evidence, pricing_settlement / caregiver_payout_statementPartialCaregiverAssignmentDecisionEvidence and CaregiverPayoutStatementProjection; separate travel/conflict/override evidence from shared payout projection.
Sponsor, payer, emergency-contact, refund-recipient, document-visibility source branchesmember_management / reservation_party_authority, pricing_settlement / refund_side_effect_orderingPartialReservationPartyAuthoritySnapshot 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 idsdocument_reporting / printable_template_version_manifestPartialPrintableTemplateVersionManifestCompleteness 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/*.xlsxpricing_settlement / price_catalog_import_execution_auditPartialPriceCatalogImportExecutionAudit 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 branchespricing_settlement / regional_benefit_policy, reservation_operations / service_calendar_quote_impactPartialBackend 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.phpmember_management / customer_identity_profile, customer_engagement / external_commerce_member_linkPartialProfile, 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 pathsreservation_operations / customer_reservation_intake_draftPartialRevisioned 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.phpreservation_operations / customer_reservation_intent, pricing_settlement / customer_payment_instruction, document_reporting / customer_document_download_grantPartialBirth/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.phpcare_delivery / care_delivery_obligation, customer_engagement / report_service_notificationPartialFirst/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_catalogPartialVersioned 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 sourcesbranch_operations / office_profile, operator_access / branch_login_auditPartialBranch 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 pathscustomer_engagement / promotion_entitlement, pricing_settlement / gift_fulfillment, document_reporting / partner_benefit_result_artifactPartialCoupon 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-190reservation_operations / CustomerReservationLifecycleSnapshotPartialCustomer 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-210reservation_operations / CustomerActionAvailabilityPolicyPartialCustomer 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-421reservation_operations / CustomerActionCommandPartialCustomer 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-270reservation_operations / ReservationActorCapabilityProjectionPartialBackend 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-342reservation_operations / ReservationCollaborationConflictLog, ReservationCollaborationWorkspacePartialBroad 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-1955reservation_operations / ReservationStateTransitionCatalogPartialReservation 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-345care_delivery / CaregiverWorkScheduleProjection, CaregiverActionAvailabilityProjectionPartialCaregiver 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-645member_management / ReservationPartyAuthoritySnapshot, pricing_settlement / PayerAndGiftRecipientProjection, PaymentCommunicationDispatchRoutePartialPayment 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-212document_reporting / BranchResourcePostAudiencePolicyPartialBranch 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-430pricing_settlement / SourceExcelRepairWorkbookCommand, operator_access / BranchLoginAuditExportPartialLegacy 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-225operator_access / LegacyMaintenanceCommandGate, migration_governance / SourceRepairCommandCatalogPartialAdmin 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-43customer_engagement / PromotionEntitlementAdminCancellationPartialAdmin 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-755document_reporting / ArtifactDownloadResponsePolicy, platform / LegacyRealtimePushBridgeMissingforce_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.

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.

PrioritySource evidenceModern targetStatusRequired improvement
P0source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:86-99, :247-261; source-refs/sanmopia-admin/application/controllers/Reservation.php:420-431reservation_operations / ReservationActorCapabilityProjectionPartialBackend foundation exists; next bind Supabase Auth actor, SpiceDB relation, OPA result, field visibility, command targets, and audit context.
P0source-refs/sanmopia-admin/application/models/Reservation_model.php:1769-1916; source-refs/sanmopia_web/application/models/Reservation_model.php:989-1112reservation_operations / ReservationStateTransitionPolicy, ReservationLifecycleSideEffectPlan, ReservationOperationFollowUpWorkflow; pricing_settlement / ReservationPromotionSideEffectPlanPartialBackend 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.
P0source-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-441reservation_orchestration / ReservationLifecycleSideEffectExecution, reservation_operations / ReservationLifecycleSideEffectPlanPartialExecution 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.
P0source-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-843pricing_settlement / PaymentAdjustmentQuote, PaymentChangeRefundLink, ProviderPartialRefundCapability, PreReservationPaymentCloseout, PreReservationCouponOverCreditPolicy, PaymentCloseout; promotion_entitlement / PromotionEntitlementOutboxPartialKill 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.
P0source-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-18pricing_settlement / PaymentChangeAdjustmentCloseout, PaymentChangeRefundLink, ChargeQuoteSnapshot, ChargeSummaryProjectionPartialSource 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.
P0source-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-4461pricing_settlement / PaymentChangeRefundEligibleAdjustmentSelectionPolicy, PaymentChangeRefundIntentBackend foundationSource 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.
P0source-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-553pricing_settlement / RefundSideEffectPlan; promotion_entitlement / EntitlementRestorationPlan, ActualServiceDayCouponPolicyBackend foundation + contractSource 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.
P0source-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-63service_calendar / ServiceTermPolicy, HolidayCalendarRegistry, AdditionalServiceDaySelection, ServiceAreaCalendarProfileBackend foundation + contractSource 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.
P0source-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, :99reservation_operations / ReservationContinuationLink, ContinuationDraftConflictFact, ContinuationVoucherEligibilityDecision, ContinuationCaregiverCarryoverDecision; service_lifecycle / ServiceInterruptionPolicy; promotion_entitlement / ProductCouponResetPolicyBackend foundation + contractSource 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.
P0source-refs/sanmopia_web/application/controllers/api/Service.php:323-325; source-refs/sanmopia_web/application/models/Reservation_model.php:2473-2501reservation_operations / ContinuationVoucherEligibilityDecisionBackend-backed foundationContinuation 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.
P0source-refs/sanmopia_web/application/controllers/api/Service.php:329-332reservation_operations / VoucherRecipientIdentityEligibilityDecisionBackend-backed foundationSource 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.
P0source-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-198reservation_operations / ContinuationCaregiverCarryoverDecisionBackend-backed foundationContinuation 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.
P0source-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-309pricing_settlement / DanbiSettlementArchive, HeadquarterBranchSettlement, SettlementApprovalWorkflow, SettlementAdjustmentLine, SettlementDataRoomCollectionPartialSource 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.
P0source-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, :311document_reporting / SettlementStatementGeneration, MaterialRoomDocumentRequest, BranchResourcePost, ReservationDocumentExportWorklist, DocumentArtifactGrantPartialSource 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.
P0source-refs/sanmopia-admin/application/models/Reservation_model.php:699-818; source-refs/sanmopia_web/application/models/Reservation_model.php:1165-1369pricing_settlement / RegionalBenefitDecision, ReservationPriceVersionAndSubsidyAdjustmentPartialSubsidy, regional benefit, discount, support criteria, and price-version effects must be persisted as effective-dated decision facts.
P0source-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-86member_management / ReservationPartyAuthoritySnapshotBackend/contract foundationReservationPartyAuthoritySnapshot 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.
P0source-refs/sanmopia-admin/application/config/constants.php:116-137; settlement eligibility source status use in reservation and settlement source filespricing_settlement / SettlementReservationLifecycleStatus, reservation_settlement_status_aclPartialSettlement 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.
P1source-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-2587reservation_operations / ReservationCollaborationConflictLog, ChangedFieldCommit; business_reporting / ReservationStatusChangeFactProjectionPartialReplace 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.
P1source-refs/sanmopia-admin/application/controllers/DataRoom.php:215-309, :389-408; source-refs/sanmopia-admin/application/models/Data_room_model.php:12-20pricing_settlement / SettlementCollectionExportRepository, SettlementDataRoomArtifactBuildWorker, ExternalSettlementCounterpartyReadinessProjectionPartialSettlement data-room exports need frozen dataset revision, external-counterparty readiness, artifact build worker, signed grant, and repair history.
P1source-refs/sanmopia-manager/application/helpers/salary_helper.php:4-228pricing_settlement / CaregiverPayoutStatementProjection, AdminCaregiverCompensationReadModelPartialShared admin/manager payout read model must freeze role slot, grade snapshot, attendance facts, tax election, adjustment, confirmation, and receipt state.
P1source-refs/sanmopia_web/application/models/Reservation_model.php:1091-1112, :3263-3273; source-refs/sanmopia-admin/application/models/Reservation_model.php:6180-6190service_calendar / ServiceOccurrenceEvidenceRequirement, ServiceSuspensionInterval, ExtraServiceDateAnomalyAcknowledgementPartialHoliday, interruption, substitute-day, and anomaly handling need occurrence evidence, acknowledgement, and quote/matching/report/refund/settlement invalidation.
P1source-refs/sanmopia-admin/application/models/Reservation_model.php:1769-1916; source-refs/sanmopia_web/application/models/Reservation_model.php:989-1037pricing_settlement / ReservationPromotionSideEffectPlan, ProductCouponResetPolicy, ReservationCouponRestorePolicy, PromotionEntitlementOutbox; customer_engagement / BenefitFulfillmentCancellationOutboxPartialCancel/stop/refund side effects must become explicit promotion entitlement, benefit fulfillment, payment closeout, and communication decisions with idempotent outbox repair.
P1source-refs/sanmopia-admin/application/models/Branch_model.php:289-426, :602; source-refs/sanmopia_web/application/models/Reservation_model.php:2113-2137, :2239-2302branch_operations / BranchServiceAreaDecisionRecorder, ServiceAreaCoverageProfile; reservation_operations / ReservationServiceAddressCoverageSnapshotPartialAddress 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.
P1source-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-53branch_operations / BranchCoverageOverrideDecisionBackend-backed foundationSource 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.
P1source-refs/sanmopia-manager/application/helpers/salary_helper.php:109-214pricing_settlement / CaregiverPayoutPolicyProfile, CareTeamCompensationSlotBackend-backed foundationWeekend/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.
P1source-refs/sanmopia-manager/application/helpers/salary_helper.php:42-99pricing_settlement / CaregiverVoucherAddOnTaxCutoverPolicyBackend-backed foundationVoucher 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.
P1source-refs/sanmopia-manager/application/helpers/salary_helper.php:67-160pricing_settlement / CaregiverAdditionalServiceDayBasisBackend-backed foundationNormal/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.
P1source-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-2624care_delivery / CaregiverServiceBalanceShareProjection, CaregiverServiceBalanceAcknowledgementCommand; pricing_settlement / CaregiverPayoutStatementBackend-backed foundationCaregiver 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.
P1source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4030-4050, source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4058-4093document_reporting / DailyReportArtifactSeriesSelectionBackend-backed foundationCustomer 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.
P1source-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-688document_reporting / ServiceUseContractEvidenceSnapshot, ServiceUseContractRenderSource, ServiceUseContractPaymentEvidenceSnapshot, BranchStampAssetSnapshot, MotherSignatureAssetSnapshot, ChargeComponentRevisionSnapshot, ServiceOccurrenceSet, CareTeamDocumentProjection, ServiceUseContractRenderRequest, StoredPrintableDocumentArtifact, ContractTemplateEffectiveVersionDecision, DocumentCenterProjectionBackend-backed foundationService-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.
P1source-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-688document_reporting / RedactedMotherIdentityEvidenceSnapshot, BranchStampAssetSnapshot, MotherSignatureAssetSnapshot, StoredPrintableDocumentArtifact, PrintableDocumentAccessGrantPartialPost-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.
P1source-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.pydocument_reporting / RedactedMotherIdentityEvidenceSnapshot; member_management / VoucherResidentIdentityEvidenceBackend fact-reader foundationService-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.
P1source-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-332document_reporting / BranchStampAssetSnapshot, MotherSignatureAssetSnapshot; branch_operations / BrandAssetLifecyclePartialLegacy 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.
P1source-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-688document_reporting / StoredPrintableDocumentArtifact, PrintableDocumentAccessGrant, ServiceUseContractRenderSourceOnlyArtifactBuilderPartialAdmin 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.
P1source-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-864document_reporting / DocumentCenterProjection, DocumentCenterCatalogItem, DocumentCenterDownloadHandoffDescriptor, DocumentCenterBundleDownload; frontend / DocumentCenterStoreBackend API boundBackend 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.
P1source-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-42document_reporting / ServiceUseContractAssetSlotSnapshot, BranchStampAssetSnapshot, MotherSignatureAssetSnapshot, ServiceUseContractAssetReferenceSnapshot; branch_operations / BrandAssetLifecycleBackend-backed foundationService-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.
P1source-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-779document_reporting / DownPaymentBreakdownArtifactLineSnapshot; pricing_settlement / ChargeComponentSnapshotBackend-backed foundationDown-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.
P1source-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-6012pricing_settlement / DownPaymentVoucherSurchargeComponentSnapshot; document_reporting / DownPaymentArtifactSlotProjectionBackend-backed foundationVoucher 입주/스페셜 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.
P1source-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-4219pricing_settlement / AdditionalServiceChargeComponent; document_reporting / DownPaymentAdditionalServiceLineSlotProjectionBackend-backed foundationAdded-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.
P1source-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:21pricing_settlement / RentalEquipmentChargeComponent; document_reporting / DownPaymentRentalEquipmentLineSlotProjectionBackend-backed foundationRental 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.
P1source-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-653document_reporting / DownPaymentArtifactEligibilityProfileBackend-backed foundationDown-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.
P1source-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-2853document_reporting / CaregiverServiceRecordRoleScopedArtifactSeries, CaregiverServiceRecordChunkWindowSnapshot, CaregiverServiceRecordSourceReaderConsistencyPartially representedService-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.
P1source-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-51document_reporting / PrivacyConsentFactSnapshot, PrivacyConsentSignatureAssetSnapshot, PrivacyConsentArtifactEvidenceSnapshotBackend-backed foundationPrivacy 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.
P1source-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-5820document_reporting / VoucherReceiptBenefitPeriodSnapshot, pricing_settlement / VoucherPlanCatalogRevisionSnapshotBackend-backed foundationVoucher 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.
P1source-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-1684document_reporting / PrintableSignatureAssetSnapshotBackend-backed foundationSource 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.
P1source-refs/sanmopia-admin/application/controllers/ajax/Reservation.php:144-158pricing_settlement / PaymentChangeAdjustmentAmountBreakdown, MotherVisibleChargeSnapshotBackend-backed foundationPayment-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.
P1source-refs/sanmopia-admin/application/controllers/Reservation.php:1739-1758reservation_operations / ServiceAreaCalendarProfile, service_calendar / ServicePeriodPlanBackend-backed foundationSource 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.
P1source-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-323business_reporting / PerformanceRecognitionProgram, RecognitionScorecardSnapshot, RecognitionLeaderboardSnapshot; branch_operations / BranchRecognitionEligibilityProfilePartialBackend 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.

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 areaCurrent statusChecklist anchorsRequired migration gate
Reservation lifecycle and collaborationPartialreservation_operations / reservation_collaboration, service_calendar, pre_reservation_conversion, customer_reservation_intake_draft, customer_reservation_intentEvery 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 catalogPartialpricing_settlement / public_fee_guide_catalog, price_catalog_import_execution_audit, regional_benefit_policy, reservation_price_version_adjustmentPrice 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 BillPartialcustomer_payment_instruction, payment_change_adjustment, PaymentProductPlan, ReservationPaymentWorkflow, Kill Bill admin operationsBackend 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 refundPartialpayment_refund, ReservationCancellationRefundPolicy, PaymentRefundIntent, PaymentAdjustmentCatalogRefund 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-officePartialsettlement_statement, settlement_data_room, settlement_collection_export_repository, InterOfficeSettlement, SettlementDataRoomCollection, ReservationExternalSettlementCounterpartyStatusBranch/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 payrollPartialcaregiver_matching, assignment_decision_evidence, caregiver_compensation, caregiver_payout_statement, CaregiverPerformanceScorecardCandidate 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 grantsPartialprintable_document, printable_template_version_manifest, ReservationDocumentTemplate, VoucherEndNoticeReadiness, CustomerDocumentAvailabilityProjectionCatalog, 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 authorizationPartialActorStageCapabilityProjection, OperatorIdentitySession, BranchRelationshipGrant, Identity and RBAC end-to-endSupabase 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 managementPartialWorkflowStatusProjection, ReservationBookingWorkflow, ReservationPaymentWorkflow, ReservationFinancialLifecycleWorkflow, MemberPrivacyLifecycleWorkflowRestate 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 authorizationPartialHeadOfficeManagerOperations, BranchOwnerOperations, SettlementStatementCommandHandler, BranchSettlementReconciliationExportWorkflowHeadOfficeManager 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 resolutionPartialReservationCollaborationWorkspace, ReservationCollaborationConflictLog, SettlementTransitionAudit, WorkflowStatusProjectionStale 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 readinessPartialobservability-backpressure, SupabaseQueueContract, SupabaseQueueWorker, WorkflowStatusProjectionQueue 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.
PriorityStatusModern ubiquitous nameSource evidenceMigration note
P0PartialRegionalBenefitEligibilityDecisionsource-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-379Source 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.
P0PartialRegionalBenefitChargeImpactSnapshotsource-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-349Source 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.
P0PartialBranchCoverageAddressFallbackRulesource-refs/sanmopia_web/application/models/Branch_model.php:45-126Source 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.
P0PartialOperatorPaymentFactEditCommandsource-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-1678Admin 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.
P0PartialPaymentProviderCloseoutCompensationSagasource-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-475KCP-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.
P0Backend foundationVirtualAccountDepositReservationTransitionsource-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-3031Virtual-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.
P1PendingDocumentMailboxPostCommandsource-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-108Data-room post/file authority is browser/controller state; backend must own branch 36/all/null recipient semantics, exclusions, attachment revisions, delete grants, and audit.
P1PendingReservationDocumentBundlePolicysource-refs/sanmopia-admin/application/controllers/DataRoom.php:311-386Replace board-index/service-type hardcoded download bundles with versioned eligibility and item manifests.
P0PartialCaregiverCandidateOrderingPolicysource-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-264Matching order differs by surface; freeze score, distance, transit, random tie seed, stale ODSAY refresh, pet exclusion, and source-surface policy inputs/results.
Legacy/source evidenceOld behavior to retireModern bounded context / sliceMissing or partial current pathProposed improved abstraction
source-refs/sanmopia-admin/application/controllers/Reservation.php, source-refs/sanmopia-admin/static/js/reservation_status/reservation_detail.jsBroad reservation detail submit mutates profile, address, dates, caregivers, status, and memo, then tries to log after the fact.reservation_operations / reservation_collaborationPartial: 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.phpPayment-purpose, payer, coupon, provider, and refund side effects are inferred from request flags and source payment maps.pricing_settlement / customer_payment_instruction, payment_refundPartial: 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 readersSettlement 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_exportPartial: 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.phpMatching decisions and payroll amounts are recomputed from current read-time rows.caregiver_assignment / assignment_decision_evidence, pricing_settlement / caregiver_compensationPartial: 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 sourcesWeekly service, extension, weekend, holiday, substitute-holiday, and branch-closure effects are calculated in UI/PHP branches.reservation_operations / service_calendar, service_period, holiday_policy_executionPartial: 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 templatesNumeric document ids, raw file paths, and direct download tokens leak document/template logic to views.document_reporting / printable_document, printable_template_version_manifestPartial: 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 sourcesAddress strings, branch ids, impossible-region flags, and consultation-only fallbacks decide serviceability at UI/API edges.branch_operations / service_area_policyPartial: 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 branchesFamily authority is inferred from account/profile/payment fields at each screen or controller branch.member_management / reservation_party_authority, pricing_settlement / refund_side_effect_orderingPartial: 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 sourcesScreen-level status rules decide what HQ and branch actors can see or mutate.operator_access / actor_capability_projection, branch_operations / office_profilePartial: 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 scriptsBackground work runs as route helpers or scripts with weak retry, visibility, and correlation.platform / queue_workload, platform / observability_backpressurePartial: 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 Partial or Migrated feature: 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, and adapters/notification are 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_kernel and domain/shared_kernel usage 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, and application/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: DailyCareReportReviewOutcome for the reviewed caregiver report outcome and CustomerDailyReportReview for the customer-authored service-day review workflow. Caregiver performance scorecard naming is split by purpose: CaregiverPerformanceScorecard for capped score rows, CaregiverPerformanceSeasonScorecard for published season snapshots, and CareDeliveryPerformanceScorecard for care-delivery earned points feeding grade recalculation.

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.

  • ActorStageCapabilityProjection for 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.
  • HeadOfficeOperations settlement 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 backend 8ac9ed9ca937e1521f984aa7de66bd7c3e64855b. The HQ authority adapter is GREEN at c4a19418109dd34ce1ba6364c8d1b4040bef9bb7 with server-owned profile/membership, explicit HQ root, and SpiceDB administer_headquarters binding. The strict actor/HQ/command-scoped current-result adapter is GREEN at 78781cff20216ebd13a0918be1319e72143b94dc; DB01-13 persistence plus the concrete four-RPC durable-store adapter are GREEN at 54974c2ba4d60db26f71b1313ee3070ff45deb98. 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.
  • ActorStageCapabilityProjection for 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, and POST /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 protected POST /branch-service-area-policy-revisions and POST /branch-service-area-policy-decisions, and contract exports matching OpenAPI schemas plus TS helpers so branch coverage is not decided by UI AREA_ACCEPT_TYPE_ID_PK numbers.
  • 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.
  • ActorStageCapabilityProjection for 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.
  • ActorStageCapabilityProjection for 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 through sanmopia_caregiver_payout_receipt_state_events and sanmopia_caregiver_payout_receipt_states; bank-account edit proof now persists as CaregiverPayoutDestinationChangeAudit with 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.
  • 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 산모피아 id 85, Kanboard v1.2.35, cards 776, comments 1507, subtasks 11, task files 233, task links 30. Summary is tracked in Kanboard Renewal Feature Improvements.
  • Stage smoke fixtures register cleanup ownership in Supabase. sanmopia_test_data_batches stores batch key, owner tag, source script, environment, expiry, status, and cleanup summary. sanmopia_test_data_references stores ordered cleanup references for public rows and Supabase Auth users. pnpm test-data:reap is a dry-run gate and pnpm test-data:reap:apply performs explicit confirmed deletion. pnpm doctor fails 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.

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/evidenceModern bounded context / feature nameImplementation statusMigration priorityNotes
source-refs/sanmopia-admin/application/controllers/Reservation.php:650-880, source-refs/sanmopia-admin/application/controllers/Reservation.php:930-1014reservation_operations / ReservationCollaborationCommand, ReservationMutationKindBackend-backedP0Source 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-208caregiver_assignment / CaregiverAssignmentDecision, CaregiverAssignmentTerm, AssignmentDecisionAuditPartialP0Main 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-2180caregiver_assignment / CaregiverAvailabilityWindow, CaregiverAssignmentConflictPartialP0Source 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-200pricing_settlement / CaregiverCompensationQuote, CaregiverPayoutInstruction, CaregiverTaxElection, CaregiverVoucherAddOnTaxCutoverPolicy, CaregiverAdditionalServiceDayBasis, care_delivery / CaregiverServiceBalanceShareProjection, CaregiverPayoutAdjustmentAudit, CaregiverPayoutDestinationChangeAuditPartialP0Backend 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-4400pricing_settlement / SettlementStatement, SettlementTransitionAudit, SettlementLineAcknowledgement, SettlementStatementManualRowPartialP0Command-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-309pricing_settlement / InterOfficeSettlement, ServiceOfficeTransfer, CustomerHandoffOffice, ReservationExternalCounterpartySettlementStatus, SettlementStatementKind, InterOfficeSettlementAcknowledgementPartialP0Backend 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-337pricing_settlement / SettlementWorkspace, document_reporting / BranchResourcePost, SettlementDataRoomCollection, SettlementArtifactRequest, SettlementArtifactVersion, SettlementArtifactGrant, DownloadHandoffAudit, SettlementRepairRequest, OperatorReturnStateToken, BulkExportTemplatePolicyPartialP0Data-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-245document_reporting / ReservationDocumentTemplate, ReservationDocumentDelivery, DocumentAccessGrant, DocumentDeliveryAttemptPartialP0HTML/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:31pricing_settlement / ReservationCancellationRefundPolicy, RefundQuote, PaymentRefundIntent, PaymentRefundGatewayCommand, SupabasePaymentRefundLedgerStore, PaymentAdjustmentCatalog, ReservationCancellationRefundExplanationSnapshotPartialP0Source 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-1030pricing_settlement / PreReservationCancellationRefundCommand, reservation_operations / PreReservationDetailCommit, SourcePreReservationStatusMappingPartialP0Admin 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-466reservation_operations / ServicePeriodCalculationPolicy, ServiceCalendarCompatibilityDecision, ReservationServiceTermPlan, HolidayPolicyVersion, ServiceDayOccurrence, ServiceCalendarImpactPlan, SourceServiceCalendarExtraOptionDecision; pricing_settlement / ReservationServiceCalendarQuote, ServicePeriodChargeContextPartialP0Source 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-129reservation_operations / ReservationExtensionPlan, ExtensionEligibilityDecision, ContinuationVoucherEligibilityDecision, ServicePeriodPlan.extension_of; pricing_settlement / ReservationExtensionQuoteBackend foundation + contractP0Source 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-131reservation_operations / ServiceSuspension, SuspensionRequest, EffectiveStop, ResumeBoundary, ServiceSuspensionImpactPlanPartialP0Source 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-553pricing_settlement / ReservationPromotionSideEffectPlan, PlanReservationPromotionSideEffectHandler, ProductCouponResetPolicy, ReservationCouponRestorePolicy, PromotionEntitlementOutbox; customer_engagement / BenefitFulfillmentCancellation; pricing_settlement / RefundSideEffectPlanPartialP0Refund 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-1568pricing_settlement / PaymentProductPlan, CustomerSharePaymentSchedulePolicy, PaymentSettlementLineTemplate, PaymentProductCommunicationRoute, PaymentProviderRouteFeeSnapshot, PaymentPurpose, SettlementLineKind, SettlementParticipationPolicyPartialP0Source 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-3461pricing_settlement / ChargeAdjustmentPolicy, PaymentAdjustmentCatalog, DiscountAdjustment, AdditionalChargeAdjustment, PartialRefund, CouponPrepaymentQuote, PreReservationCreditPolicy, ManualReceiptCloseout, ReservationPriceSummaryChargeFreezePolicy, FinalizeReservationChargeFromPriceSummaryHandler, ReservationServiceCalendarQuote, ReservationExtensionQuotePartialP0Source 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-704member_management / FamilySponsorRelationship, reservation_operations / ReservationBookerBeneficiarySnapshot, pricing_settlement / PayerSnapshotPartialP0Source 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-2255branch_operations / BranchCoverageDecision, AddressMatchRule, BranchServiceAreaPolicy, CoverageOverride, BranchServiceAreaDecisionSnapshotBackend + contractP0Source 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-431reservation_operations / OperatorFinancialMutationLockPolicy, ActorStageCapabilityProjection, ReservationFinancialFieldLockPartialP0Backend 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-3036pricing_settlement / ManualReceiptCommand, SettlementBackfillRepairCommand, SettlementPayoutBackfillCloseoutPartialP1Backend 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-2143caregiver_performance_recognition / CaregiverGradeRecalculation, CaregiverCredentialEvidencePartialP1Performance-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-386branch_admin_ux / ReturnStateToken, SettlementHistoryReadModel, DownloadHandoffAudit, SettlementRepairHistoryViewPartialP1Reservation 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.

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, and source-refs/sanmopia_web/static/js/step3.js:861-897. Required vocabulary: ServiceDurationProfile, VoucherWeekLength, ServiceEndDatePolicy, ExtraServiceDateSelection, and RegionalDurationBenefit. Backend domain now freezes voucher five-day week basis, service-end rollback policy, source evidence key, profile key, and regional duration extension on ServiceCalendarPlan. Supabase now persists service_duration_profile_key, duration_profile_evidence_key, and service_end_date_policy on sanmopia_reservation_service_calendar_plans through 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, and source-refs/sanmopia_web/application/models/Manager_model.php:176-197. Required vocabulary: ReservationContinuationLink, ContinuationEligibility, ContinuationBookingClone, and ContinuationCaregiverCarryoverDecision. 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-owned sanmopia_reservation_continuation_links rows with a Pydantic link_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 commit 7d5db21 adds ContinuationDraftConflictFact, decide_continuation_draft_eligibility, and PlanContinuationDraftCreationPayload so 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 as RESERVATION_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_FL flag. 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, and source-refs/sanmopia_web/static/js/step2.js:476-482. Required vocabulary: ReservationConsultationGateDecision, ReservationConsultationReason, ConsultationCustomerCopySnapshot, BookingMatchingRecommendationEligibility, and PriceVersionRolloverConsultationRule. 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, and source-refs/sanmopia_web/application/models/Payment_model.php:856-896. Required vocabulary: ReservationChargeLine, ExtraServiceChargeBasis, CustomBalanceOverride, VoucherPureAdditionalServiceBalance, PaymentChangeIntent, and RefundInstruction. 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, and source-refs/sanmopia_web/application/models/Coupon_model.php:530-553. Required vocabulary: ReservationStateTransitionPolicy, ReservationOperationPlan, ReservationLifecycleSideEffectPlan, ReservationOperationFollowUpWorkflow, ReservationPromotionSideEffectPlan, PlanReservationPromotionSideEffectHandler, and PromotionEntitlementOutbox. 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, and source-refs/sanmopia-admin/application/models/Payment_model.php:2891-2906. Required vocabulary: SettlementDataRoom, SettlementBoard, BranchSettlementStatement, InterOfficeSettlement, SettlementAcknowledgement, and SettlementAdjustmentLine. 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, and source-refs/sanmopia-admin/application/controllers/Manager.php:1847-1883. Required vocabulary: CaregiverAssignmentContract, CareTeamMemberRole, CaregiverAssignmentChangeLog, CaregiverGradeSnapshot, CaregiverCompensationQuote, SubCaregiverPayoutLedger, and TaxWithholdingMode. 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, and source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:155-231. Required vocabulary: ReservationQuoteSnapshot, ChargeLineProjection, ServiceCalendarQuoteImpact, BackendOnlyCompensationQuote, and PaymentAmountAuthorization. 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, and source-refs/sanmopia-admin/static/js/manage_system/holiday_list.js:18-106. Required vocabulary: CustomerReservationListBucketProjection, CustomerPaymentActionProjection, CustomerReceiptAccessProjection, CustomerDocumentAvailabilityProjection, CustomerReportObligationProjection, CareManagerServiceBalanceAcknowledgementProjection, PublicFeeGuideCatalogProjection, and HolidayPolicyCommandProjection. 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 modal data-type command selection remain adapter evidence only.

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, and source-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 from payment_refund_completion_barrier so 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, and source-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-137 and 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 consume ReservationLifecycleSideEffectPlan.

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, and source-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, and ReservationChargeFreeze own 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, and source-refs/sanmopia-admin/application/models/Payment_model.php:4422-4521. Required proof: pricing_settlement / PaymentChangeOperatorBoard, PaymentChangeAmountBreakdown, PaymentChangeOperatorCommand, PaymentChangeCompletionAudit, and PaymentChangeProjectionInvalidation freeze 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, and source-refs/sanmopia-admin/static/js/calculate_detail.js:939-1144. Required proof: pricing_settlement / SettlementStatementCommandContext, SettlementLineAcknowledgement, SettlementManualAdjustmentPolicy, SettlementCompletionReview, SettlementArtifactRequest, SettlementArtifactGrant, and DownloadHandoffAudit own 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 mixed FormData blob 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, and source-refs/sanmopia-admin/application/models/Matching_model.php:724-862. Required proof: caregiver_assignment / CaregiverCandidateSnapshot, CaregiverAssignmentDecision, CaregiverAssignmentConflict, CaregiverTransportEvidence, and CareTeamContract persist 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, and source-refs/sanmopia-admin/application/config/constants.php:272-274. Required proof: pricing_settlement / CaregiverCompensationQuote, CaregiverPayoutInstruction, CaregiverTaxElection, CaregiverPayoutAdjustmentAudit, CaregiverPayoutAcknowledgement, and ReservationCompletionDecision own 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 expose CaregiverPayoutAcknowledgementCommand and CaregiverPayoutAcknowledgementReadModel with 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 SpiceDB record_caregiver_payout or 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 records CaregiverPayoutAdjustmentAudit as an append-only command with Supabase actor derivation, SpiceDB record_caregiver_payout permission, idempotency replay guard, target-level expected revision, and full previous/adjusted payable amount, withholding, tax category, and memo snapshots. Supabase persists sanmopia_caregiver_payout_adjustment_audits with 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 records CaregiverPayoutDestinationChangeAudit as an append-only command with Supabase actor derivation, SpiceDB record_caregiver_payout permission, 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 source SORT > 0 assistant rows. 2026-07-07 backend follow-up: backend commit 81719dc adds AdminCaregiverPayoutStatementProjection, CaregiverPayoutSlot, CaregiverPayoutOperatorActionAvailability, CaregiverPayoutServiceBalanceState, and CaregiverPayoutCompletionDecision. The application contract now exposes BuildAdminCaregiverPayoutStatementProjectionResult so 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, and source-refs/sanmopia-admin/application/config/constants.php:272-274. 2026-07-07 persistence follow-up: backend commit 292f736 adds 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 into SupabaseRow instead 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/evidenceModern bounded context / feature nameImplementation statusMigration priorityNotes
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-67reservation_orchestration / CustomerReservationRequestIntent, customer_engagement / CustomerInquirySubmissionIntent, CustomerInquiryAnswerIntent, CommunicationDispatchRequest, BranchNotificationRoutingPolicyPartialP0Customer 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-716pricing_settlement / CustomerPaymentInstruction, PaymentVirtualAccountInstructionPayload, VirtualAccountPaymentLifecycle, PaymentCommunicationWorkflow, customer_engagement / CommunicationDispatchRequestPartialP0Payment 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-27document_reporting / ReservationDocumentCatalog, ReservationDocumentBundle, DocumentAccessGrant, DocumentDeliveryAttemptPartialP0Customer 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-421reservation_operations / CustomerActionAvailabilityPolicy, CustomerReservationStateMappingCatalog, CustomerReservationStateSnapshot, CustomerNewReservationEligibilityPolicy, CustomerReservationLifecycleSnapshot, CustomerActionCommandPartialP0Customer 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-68customer_engagement / PromotionDeliveryAttempt, CampaignDispatchSegment, NotificationInboxItem, CommunicationDispatchRequestPartialP1Customer-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-125customer_engagement / PartnerBenefitResultArtifact, DocumentAccessGrant, PartnerBenefitDeliveryBatchPartialP1Partner-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.

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/evidenceModern bounded context / feature nameImplementation statusMigration priorityNotes
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-3562reservation_operations / PostpartumCareCenterStayPlan, ServiceDueDatePolicy, ReservationDeliveryProfilePartialP0Backend 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-640reservation_operations / OfflineReservationIntakeCommand, ReservationDuplicateGuard, ManualReservationSourcePartialP1Backend 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-1265pricing_settlement / SettlementManualAdjustmentCatalog, SettlementManualAdjustmentCatalogVersion, SettlementManualAdjustmentLinePartialP1Backend 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-1068pricing_settlement / ReservationPriceVersionAndSubsidyAdjustment, PriceCatalogVersionPolicy, ReservationServiceBalanceOverride, VoucherPureAdditionalServiceBalance, ReservationServiceBalanceConfirmation, ServiceBalancePaymentCloseout, CaregiverServiceBalanceReceiptCloseoutPartialP1Backend 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-4488document_reporting / VoucherEndNoticeReadiness, VoucherEndNoticeReadinessParity, VoucherEndNoticeDeliveryBatchReadinessDecision, VoucherEndNoticeDeliveryAttempt, DocumentArtifactReadinessPartialP0Backend 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/serviceBalanceConfirm is stale JavaScript with no verified CodeIgniter route alias. Actual reachable path is /reservation/confirmServiceBalance, which sets SERVICE_BALANCE_PRICE, SERVICE_BALANCE_CONFIRM_FL = 1, and SERVICE_BALANCE_PRICE_USE_FL = 1. The similarly named model method only flips SERVICE_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 has ConfirmReservationServiceBalance / ConfirmReservationServiceBalancePayload foundation 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, and CloseReservationServiceBalanceHandler now cover source insertServiceBalanceInfo: 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 through sanmopia_save_service_balance_closeout, and the backend exposes POST /reservation-service-balance-closeouts. Backend commit 4e4b140 now 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, and supabase:smoke:stage:service-balance-closeout, which proves the stage DB booking RPC -> occurrence ledger -> closeout RPC path inside a rolled-back transaction. Follow-up proof supabase:smoke:stage:financial-lifecycle-closeout-guard now creates a real stage booking, reuses the booking-created occurrence ledger instead of inserting a duplicate revision, records service delivery and caregiver payout, rejects stale serviceBalanceCloseoutEventId at Branch settlement, then accepts the backend-confirmed Branch/HQ settlement references through settled. The live proof exposed and fixed a schema drift bug: additional-service selection revision reads must derive paths from journal field_changes, not the broadcast-only changed_field_paths label. 2026-07-08 source-dig addition: the reachable service-balance override path also records actor office facts as JSON plus the posted override amount in RESERVATION_SERVICE_CUSTOM_LOG_TB before 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). Modern ReservationServiceBalanceOverrideAuditLedger must 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, and DocumentSeriesPaginationPolicy are 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, and source-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, and CaregiverManualEvaluationAdjustmentPolicy are 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, and source-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 UI TWINS_FL; report date buckets must stop merging months/quarters across years; sales fee metrics must replace GET_PAYMENT_FEE_RATIO with 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 includes ExtraServiceBabyTypeSurchargePolicy, 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/FamilySponsor charge projections expose baby-type surcharge eligibility from frozen catalog/service-day evidence, not browser flags.
    • BranchOwner and HeadOfficeManager report dashboards share one metric catalog where date basis, sales fee snapshot, branch scope, and export revision are immutable.
    • CareManager recognition views read published scorecards only; HeadOfficeManager and permitted BranchOwner edits 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, and VoucherPureAdditionalServiceBalance are 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, and source-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, and VoucherPureAdditionalServiceBalance must become named policy/snapshot facts. UI filters, source branch ids, source status ids, and mutable payment row rewrites cannot be authority. Formula-level gaps: persist posted_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 includes ServiceBalanceAdditionalServiceChargePolicy, which reuses AdditionalServiceChargePolicy to 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/contract add_option_amount_krw and public addOptionAmountKrw with additional_service_amount_krw and additionalServiceAmountKrw in voucher catalog snapshots, keeping source add-option labels only in evidence rows. Backend foundation also includes PreReservationCouponOverCreditPolicy, 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 from source-refs/sanmopia_web/application/models/Reservation_model.php:1401-1414, source-refs/sanmopia_web/application/models/Payment_model.php:775-841, and source-refs/sanmopia_web/application/controllers/api/Payment.php:537-544. Backend foundation now also includes ConvertedReservationOverCreditPolicy, which preserves the source-refs/sanmopia_web/application/models/Payment_model.php:232-270 three-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 VoucherPureAdditionalServiceBalance snapshot.
    • Price-table and operator repair screens submit commands with actor, reason, expected revision, and idempotency key; no portal recomputes voucher add-on subtraction.

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.yml already routes browser-facing services through Traefik Docker labels with container expose, 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 Supabase pgmq, 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 reusable SupabaseQueueWorkloadBatchDispatcher, SupabaseQueueWorkerPort, and SupabasePgmqQueueAdapter read/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 through SpiceDBAuthorizationPort, 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, and source-refs/sanmopia-admin/application/models/Momfirst_model.php:12-272. Required proof: PromotionEntitlement, GiftFulfillmentRequest, and MomfirstDelivery preserve 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 injected PromotionEntitlementCatalog, 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, and source-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-862 source-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, and source-refs/sanmopia-admin/application/controllers/ajax/ManagerEvaluation.php:146-228. Backend optimizer foundation now adds CaregiverCandidateSnapshot and MatchingOptimizationInput domain/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 named MatchingProfileCompatibilityInput, separating caregiver profile compatibility facts from reservation-level optimizer inputs. Candidate evidence now persists through sanmopia_caregiver_candidate_snapshots and SupabaseCaregiverCandidateSnapshotRepository, 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 adds CaregiverAssignmentDemandSlot, CaregiverAssignmentOptimizerInput, and Pydantic contracts under caregiver_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 adds CaregiverPerformanceScorecard cap rows under backend-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 reserves CaregiverPerformanceScorecard for those capped score rows, while CaregiverPerformanceSeasonScorecard names published season snapshots and CareDeliveryPerformanceScorecard names 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, and source-refs/sanmopia-admin/application/models/Branch_model.php:345-425. Required proof: BranchOfficeProfileCommand splits profile, lifecycle, membership-fee, account, and credential changes into revisioned commands; BranchServiceAreaPolicy and ServiceCoverageDecision own address-depth normalization, available/consultation/unavailable priority, branch/HQ authorization, supersession, and reservation impact audit. Backend profile command/read-model foundation now exists in backend-repo/src/sanmopia_modernization/domain/branch_operations/features/office_profile/ and backend-repo/src/sanmopia_modernization/application/branch_operations/features/office_profile/. Supabase runtime persistence now lives in backend-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 through backend-repo/src/sanmopia_modernization/interfaces/branch_service_area_policy_api.py and backend-repo/src/sanmopia_modernization/interfaces/branch_service_area_policy_http.py with contract paths branchServiceAreaPolicyRevisionsPath() and branchServiceAreaPolicyDecisionsPath(). Generated Supabase types cover the backing tables. Snapshot write API now exists as POST /branch-settlement-account-statement-snapshots; backend derives the actor from Supabase Auth, checks SpiceDB settle, and writes idempotent statement-account snapshots with explicit settlement_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 adds POST /branch-office-profile-updates with Supabase Auth actor derivation, SpiceDB manage, expected-revision conflict handling, and OpenAPI/TS helpers. Lifecycle follow-up now adds POST /branch-office-lifecycle-changes with the same actor/permission/revision guard and ubiquitous lifecycle states instead of source delete flags. Settlement-account replacement follow-up now adds POST /branch-settlement-account-replacements with masked-only account facts, purpose-scoped replacement, Supabase Auth actor derivation, SpiceDB manage, 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, and source-refs/sanmopia-admin/application/models/Payment_model.php:436. Required proof: RegionalBenefitPolicy stores 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 frozen RegionalBenefitDecision instead of checking region names, source flags, or option-name substrings. Backend profile metadata now stores regional_benefit_profile_key, service_day_bonus_count, and settlement_participation_code on RegionalBenefitRule. FinalizeReservationChargeWithRegionalBenefitHandler now resolves the regional entitlement once, builds ReservationPriceSummaryInput, 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, and source-refs/sanmopia-manager/application/models/Notify_model.php:70-448. Required proof: CareDeliveryObligation drives 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, and CaregiverServiceRecordSubmission with role/handoff identity, service-date access window, duplicate replay, correction revision, sequential writable action, route date, and explicit attendance outbox key. DailyCareReportServiceDateLockPayload now 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. DailyCareReportServiceSuspensionWindowPayload now 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, and source-refs/sanmopia-admin/application/models/Statistics_model.php:1971-2137. Required proof: AdminAnalyticsCatalog names 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, and source-refs/sanmopia_web/application/models/User_model.php:557-621. Required proof: CustomerIdentityProfile, CustomerAccountSecurityEvent, and ExternalCommerceMemberLink separate 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, and source-refs/sanmopia_web/application/controllers/api/Service.php:592-868. Required proof: CustomerReservationIntakeDraft, ReservationServiceAreaDecision, and ReservationCarePlanDraft replace source PROCESS_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, and source-refs/sanmopia_web/application/models/User_model.php:462-491. Required proof: CustomerReservationIntent, BranchNotificationRoutingPolicy, CustomerPaymentInstruction, and CustomerDocumentDownloadGrant cover 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: ReservationPaymentConversionProjection freezes converted status, original payment purpose, coupon discount, customer-share amount, deposited-at fact, and allowed follow-up command. UI/controller code must not traverse PRICE_TABLE, PAYMENT_INFO, or gateway context maps to decide rows or amounts. Implementation note: backend domain/application contract slices were added at backend-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, and source-refs/sanmopia_web/application/views/open_the_app.php:1-20. Required proof: CustomerSelfServiceWorkspace, CustomerActionAvailabilityPolicy, CustomerReservationTimelineSnapshot, CustomerReportSubmissionWindow, CustomerNotificationActionGrant, CustomerReceiptAccessGrant, and CustomerAppLaunchIntent replace 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 injected CustomerActionPolicyRuleCatalog evaluation, versioned action decisions, disabled reasons, command targets, actor relation, audit category, idempotency scope, customer presentation metadata, and CustomerReservationStateMappingCatalog projection from versioned source_status_code into current customer lifecycle stage, customer_list_bucket, shared detail_surface_kind, source compatibility flags, and blocks_new_reservation. CustomerNewReservationEligibilityPolicy composes those projected facts across existing reservations so only 8 취소요청, 14 입금대기, and 16 사전예약대기 block a new reservation, while history 17 입금대기취소 and replaceable draft -1 do not. Pre-reservation detail selection is also backend projection: status 15/16 render pre-reservation detail; status 9/17/19 render 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 tables sanmopia_customer_reservation_action_source_states, sanmopia_customer_reservation_state_mapping_catalogs, and sanmopia_customer_action_policy_rule_catalogs, with RLS protecting customer source states by owning Supabase user. Backend exposes authenticated GET /customer-reservation-action-availabilities/{reservation_id} and GET /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 Nanostores customer-self-service-action-availability state 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, and source-refs/sanmopia_web/application/controllers/Clean.php:67-126. Required proof: PartnerBenefitCatalog, PartnerBenefitApplication, PartnerBenefitEligibilityDecision, PartnerDeliveryBatch, PartnerDeliverySuppressionReason, PartnerBenefitCancellationLock, and PartnerResultArtifactGrant replace 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, and source-refs/sanmopia_web/static/js/momfirst_rumor_event.js:1-15. Required proof: CampaignPublication, CampaignContentTemplate, CampaignPublicationVersion, CampaignPlacement, and CampaignAudiencePolicy replace 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, and source-refs/sanmopia-admin/application/models/Coupon_model.php:888-932. Required proof: CampaignParticipation, ReviewRewardCampaign, CampaignResultPublication, CampaignFulfillmentBatch, CampaignNotificationPolicy, and CampaignExportArtifact replace 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, and source-refs/sanmopia-manager/application/models/Board_model.php:12-37. Required proof: ContentPublication, ContentPublicationWorkflow, ContentCategoryTaxonomy, ContentAudiencePolicy, ContentPublicationVersion, ContentDiscoveryState, and ContentViewMetric cover 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 explicit ContentModerationState, and FAQ/QnA flows stay pending for a dedicated CustomerInquiryThread source 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, and source-refs/sanmopia-manager/application/models/Notice_model.php:12-120. Required proof: NoticePublication, NoticeAudiencePolicy, CaregiverNoticeDispatch, BranchManagerNoticeChannel, PinnedContentOrdering, and ContentPublicationVersion separate 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 raw FIX precedence. 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, and source-refs/sanmopia-manager/application/controllers/cli/Fcm.php:119-169. Required proof: ContentAttachmentAsset, ContentMediaRendition, ContentStorageProvider, ContentMediaAccessGrant, ContentRetentionPolicy, ContentDeletionRequest, ContentAuditEntry, ContentNotificationPolicy, and ContentNotificationDelivery turn 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.py and backend-repo/src/sanmopia_modernization/application/content_management/features/content_attachment_lifecycle/content_attachment_lifecycle_contract.py model 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.

  • 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_lifecycle maps 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 are MemberWithdrawalRequest, RetainedRecordSnapshot, MemberProfileMasking, and MemberPrivacyPurgeTask. 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_calendar now 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 global HOLIDAY_TB date row. OSS Korean public holidays are generated through holidays, while operator and branch overrides remain explicit audited facts. Plan payloads now carry policyVersionLabel and policyFingerprint; reservation, pricing, and settlement projections must consume the captured plan result instead of recalculating from current holiday rows. Supabase migration 20260703220000_service_calendar_policy_snapshots.sql adds source/effect metadata to sanmopia_service_calendar_holidays and policy_fingerprint to sanmopia_reservation_service_calendar_plans. Calendar impact facts now also include customer_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 exposes PlanServicePeriodPayload, ServicePeriodTemplatePayload, duration, calendar-policy, and profile payloads, with matching public TS service-period contracts and plan_service_period_request schema. 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 aligns customer_benefit_entitlement_review_required with 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 separate CustomerReservationLifecycleSnapshot: show customer-actionable states such as ReservationChangeRequested, ReservationCancellationRequested, ReservationExtensionRequested, ReservationExtended, and ReservationStopRequested, 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 through ReservationExtensionLink; it must block a second extension once the linked draft has moved past draft. Backend/contract progress: CustomerReservationLifecycleSnapshot now provides customer-safe active_journey and service_history buckets, card/detail payloads, caller-supplied projection and dataset revisions, timezone-aware evaluation timestamps, composed customer_action_availability policy 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 through CustomerReservationStateMappingCatalog; 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, and source-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 backend CustomerReservationLifecycleSnapshot facts and action readiness entries, not frontend if-statements over STATUS_ID, PAYMENT_INFO, or raw additional-service labels. Pricing display arithmetic from source-refs/sanmopia_web/application/views/reservation/retc.php:4-191 and customer fee-table arithmetic from source-refs/sanmopia_web/application/views/mypage/item/reservation_fee_table.php:1-180 now belongs to pricing_settlement customer 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 from source-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, and source-refs/sanmopia_web/application/models/Reservation_model.php:1231-1256 is now owned by pricing_settlement policy 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 raw PRICE_TABLE or 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, and ReservationPaymentWorkflow is registered on the Restate deployment so Kill Bill billing operations can use durable retry/idempotency. Public payment workflow start/progress APIs now use POST /reservation-payment-workflow-starts and GET /reservation-payment-workflow-requests/{paymentWorkflowRequestId}, with service-role-only Supabase ledger rows in sanmopia_reservation_payment_workflow_requests. Kill Bill payment event callback acceptance now uses POST /killbill-payment-events to verify the provider signature and enqueue sanmopia_payment_webhook_processing through Supabase Queues; the backend worker validates the queue payload, records sanmopia_killbill_payment_events, and starts ReservationPaymentWorkflow for 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 on sanmopia_reservation_payment_workflow_requests, and keeps later financial lifecycle stages from regressing. Virtual-account deposit closeout is now identified on paid webhooks through paymentCloseoutKind = virtual_account_deposit, while card/bank paid webhooks use instant_payment. Payment closeout context now freezes payment_closeout_kind, reservation_booking_id, and reservation_status_at_closeout on the workflow command, Restate payload, HTTP start/progress contracts, generated Supabase type, and sanmopia_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 uses POST /reservation-payment-pre-registrations before the frontend opens the payment UI, freezes paymentId, reservation booking id, payment method, payment purpose, and amount in sanmopia_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 writes deposited_at when 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: PaymentProductPlan separates 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 in sanmopia_payment_product_plan_catalog_items; the Pydantic adapter derives the runtime plan book shared by pre-registration validation and the authenticated catalog endpoints GET /payment-product-plans and GET /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 a PaymentProviderRouteFeeSnapshot with provider route, settlement participation, ledger recognition timing, fee basis, line targets, frozen customer-visible behavior, and method-fee quote. Catalog v2 now stores PaymentSettlementLineTemplate rows for customer_charge_payment, public-voucher fixed voucher_service_commission 15000, service_balance_receivable, pre_reservation_credit, gift_coupon_commission bands 5000/10000/20000/30000, and payment_change_adjustment. Catalog v3 now stores PaymentProductCommunicationRoute rows 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 component care_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 separate coupon_fulfilled dispatch command from that frozen snapshot instead of accepting receiver identity from UI strings. Primary and secondary branch payment notices now resolve from versioned sanmopia_branch_payment_notice_contacts rows 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 in Payment.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, and source-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 are PaymentChangeAdjustment, PaymentChangeAwaitingPayment, PaymentChangeProviderContext, and PaymentChangeOperatorCompletion. Customer-facing payment state must expose only payable/paid/refund-pending or receipt/document-ready facts from CustomerPaymentSummary and ReservationReceiptAccess; 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-visible userFeePrice, contract/balance payment rows, gateway fee estimates, and caregiver net pay, so the modern replacement must keep CustomerChargeSnapshot, SettlementCalculationLine, and CaregiverCompensationQuoteLine as separate read models even when they share the same reservation id. Customer-facing price/payment display projection now absorbs retc.php totals, reservation_detail.php and pre_reservation_detail.php payment prompt/virtual-account/KCP amount decisions, reservation_fee_table.php / reservation_fee_table_old.php voucher 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 raw PRICE_TABLE or PAYMENT_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 page source-refs/sanmopia_web/application/views/mypage/reservation_receipt.php:37-128 decodes raw PAYMENT_INFO.paymentContext, exposes KCP ordr_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, and source-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 TypeScript paymentChangeAdjustmentRequestHeaders helper. Adjustment pre-registration freezes paymentId, provider name, timestamp, and mother-payable amount on sanmopia_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 expose PaymentChangeOperatorBoard for 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 append PaymentChangeOperatorAudit facts in sanmopia_payment_change_operator_audits through protected backend/contract endpoints, so paid mother-visible amounts are not rewritten after payment. Amount-correction commands now require expectedAdjustmentUpdatedAt from 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_report now owns dynamic report definitions/submissions, and care_delivery/features/customer_record_confirmation now 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_reporting consumes 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 in ReservationDocumentTemplate, ReservationDocumentBundle, DocumentAccessGrant, and DocumentDeliveryAttempt instead of being hidden inside one renderer. Backend/domain contract progress (2026-07-03): document_reporting now has a reservation_document_bundle readiness 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 list source-refs/sanmopia_web/application/views/mypage/reservation_document.php:38-139 still hardcodes service-type document sets, end-date/status visibility, numeric document ids such as 1, 3, 4, 5, 8, 9, 15, and 21, 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_report owns DailyCareReportReviewOutcome, DailyCareReportReviewRewardPolicy, and DailyCareReportReviewRewardGrant for the backend outcome generated after a submitted caregiver daily report is reviewed; customer_daily_report_review owns CustomerDailyReportReview, 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_review owns CustomerDailyReportReview, CustomerDailyReportReviewSubmission, CustomerDailyReportReviewReadinessDecision, CaregiverServiceRating, and CustomerDailyReportReviewRewardGrant in backend/contract. Current backend slice: backend-repo/src/sanmopia_modernization/domain/care_delivery/features/customer_daily_report_review and backend-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, and DailyReportCompletionRewardLedgerInstruction output. The reward ledger instruction decomposes the source COUPON_TB/USER_COUPON_TB/USER_POINT_TB/SHOPPINGMALL_FL side effects into explicit promotion_entitlement, point_credit, and completion_marker lines behind the same once-per-reservation idempotency key. Supabase persistence now records the instruction in sanmopia_daily_report_completion_reward_ledgers and dispatchable line rows in sanmopia_daily_report_completion_reward_ledger_lines through 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-authored DailyCareReportSubmission. Backend now binds authenticated routes POST /customer-daily-report-reviews/readiness and POST /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 adds daily_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 in sanmopia_daily_report_completion_reward_fulfillments for promotion_entitlement, point_credit, and completion_marker lines, so the backend has an auditable reward-application fact. Backend now exposes authenticated GET /customer-daily-report-reviews/{reservation_booking_id}/reward-status as 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_entitlement models service-gift entitlements, purchased reservation credits, gift fulfillment requests, and boundary-only source code mapping for PRODUCT1/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: ContentPublication stores event/campaign/alliance content. CampaignPlacement replaces hardcoded popup/banner/event slot switches with Strapi-authored slots, dismiss keys, media references, CTA values, and active windows backed by sanmopia_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/content models ContentPublication for 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_inquiry replaces user FAQ/inquiry lifecycle. CampaignPlacement covers popup/banner/event slot rules. notification carries visible windows, action payloads, and read state. Numbered imported health-education categories are translated only at the Pydantic/contract adapter boundary; domain values use health_education_* naming. communication_delivery routes 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_intake models configurable MotherLeadProgramPolicy, MotherLeadRequest, eligibility, cancellation, export readiness, duplicate-export cooldown, and result attachment. Supabase tables store program versions, requests, export batches, export items, and private mother-lead-results files. Source identifiers such as MILK, LOVEBOX, and CLEAN_TB map 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_guidance replaces source vaccination_schedule.php arrays and component default deep-link strings with versioned VaccinationSchedulePolicy, VaccinationDoseRule, previous-dose timing, and MobileAppEntryPoint. Strapi authors sanmopia_child_vaccination_schedule_policies and sanmopia_mobile_app_entry_points; backend contracts validate stable codes, Strapi as authoring provider, HTTPS/intent destinations, and date windows. Python uses the OSS python-dateutil month arithmetic for backend policy work. Frontend preview uses date-fns for month/day schedule math, keeps the KDCA official schedule link visible, and modernizes /vaccination-schedule plus /open-the-app without copying source PHP/React UI.
  • 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, and sanmopia-admin/application/controllers/AdministratorNew.php. Required proof: OperatorIdentitySession, OperatorCapabilityPolicy, BranchRelationshipGrant, and BranchLoginAuditEvent replace source admin/branch/admin_momfirst session 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 session type; it must read backend authorization as SSOT. Backend foundation now exists in operator_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/organization now owns branch managed service-area policy with service_available, consultation_available, and service_unavailable kinds. 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 source possible/counsel/impossible branch 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_content now 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 Storage content-assets stores 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_profile now owns BranchOfficeProfile, 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. BranchBrandAsset and BranchLoginAuditEvent remain 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 domain reservation_status value 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, and sanmopia-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-class CaregiverMatchingCandidateSelection read 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 emits CaregiverAssignmentProposed, CaregiverAssignmentConfirmed, CaregiverAssignmentDeclined, or CaregiverAssignmentWithdrawn; 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-203 compares the reservation answer to itself when building matching result marks, Matching_model.php:111-115 interpolates search text into SQL, and Matching_model.php:118-173 mixes random tie-breaking with post-query distance sorting. Modern matching must persist a versioned CaregiverCandidateEvidence snapshot 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 at GET /caregiver-matching-policies/active; clients pass optional effectiveOn and render the Supabase-backed CaregiverMatchingPolicy snapshot instead of branching on service-detail strings. Named caregiver selection now has backend-owned RequestedCaregiverSelection and RequestedCaregiverPolicyDecision contracts: service-grade uplift, consultation-required uncertainty, blocking codes, and accepted_for_assignment come 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, and ReservationRealtimeProjectionEvent now exist in backend/domain and application contracts. Supabase now persists revision_number, sanmopia_reservation_change_journal_entries, and sanmopia_reservation_realtime_projection_events; the sanmopia_commit_reservation_collaboration RPC enforces expected revision, idempotency replay, append-only journal, and private Realtime Broadcast, with generated Supabase types updated. CommitReservationCollaborationHandler now reads current Supabase revision/current field values, commits accepted writes through the RPC, and exposes POST /reservation-collaboration-commits/{reservationId} with structured stale-save 409 conflict detail. Commit-time RPC revision races are also re-read and mapped to the same 409 conflict response, so a concurrent branch/HQ save does not degrade into a false backend 503. OpenReservationCollaborationWorkspaceHandler and ListReservationCollaborationJournalHandler now expose POST /reservation-collaboration-workspaces/{reservationId} and POST /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 names coordinationPolicy.realtimeChannelMode = private_broadcast_and_presence and coordinationPolicy.dirtyNavigationPolicy = require_save_discard_or_draft; Supabase realtime.messages RLS authorizes both Broadcast and Presence only for HQ or the owning branch. Browser-level collaboration sessions now persist as sanmopia_reservation_workspace_sessions; non-mutating UX events such as workspace_opened, navigation_blocked, draft_marked_dirty, draft_recovered, draft_discarded, commit_conflicted, and workspace_closed persist through POST /reservation-collaboration-workspace-events/{reservationId} into sanmopia_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_branch accepts branch_handoff.branch_profile_id, requires target branch/audit/diff facts, and updates sanmopia_reservation_bookings.branch_profile_id inside the same expected-revision RPC that writes the journal and private Broadcast event. service_schedule.start_on and service_schedule.end_on update service_start_at and service_end_at in the same RPC with timestamptz parsing and start/end range validation. service_schedule.extra_service_days replaces sanmopia_reservation_extra_service_days rows in the same transaction after the revision commit succeeds. caregiver_assignment.roster replaces sanmopia_reservation_caregiver_assignments rows 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 raise ReservationCollaborationPersistenceConflict, re-read the latest snapshot, and return the normal stale-save 409 conflict 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_information already models ReservationBirthProfile and BirthInformationReminderTask; branch admin still needs ReservationBirthProfileCorrection, ReservationContactCorrection, and ReservationServiceAddressCorrection commands 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_request now owns customer/operator-originated ReservationChangeRequest, ReservationChangeRequestDetail, ReservationChangeApplicationPlan, ReservationChangeEffect, and ReservationChangeOperatorAudit in 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. Existing caregiver_assignment remains 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 explicit CaregiverPayoutAllocationInvalidated and CaregiverPayoutAllocationRecreated events 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, and CaregiverAssignmentReadModelInvalidation. Branch handoff already uses the same collaboration gate through transfer_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 uses Payment_model::updateBoardId, arrears can move the board to status 3, and automatic close to status 2 depends on getCompleteFlagCountFromBoard(). That method filters detail rows by PAYMENT_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 dates 2019-11-01 and 2019-12-01 with raw status ids [3,4,5,6]. Target names: business_reporting / SettlementPeriodStatisticsSnapshot and pricing_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_lifecycle now 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 in sanmopia_reservation_financial_lifecycles and sanmopia_reservation_financial_ledger_lines. ReservationFinancialLifecycleWorkflow now starts through Restate and executes those stage commands under a stable financialLifecycleWorkflowRequestId. Backend progress reads use GET /reservation-financial-lifecycle-workflow-requests/{financialLifecycleWorkflowRequestId}, backed by service-role-only sanmopia_reservation_financial_lifecycle_workflow_requests ledger rows. branch_settlement must preserve separate HQ and branch commands from the source board: request_branch_deposit, confirm_branch_deposit, close_branch_settlement, mark_branch_arrears, and confirm_branch_arrears_payment. Source STATUS_FL values 0-4 stay adapter evidence only. Source other-office settlement now maps to the modern InterOfficeSettlement aggregate instead of keeping source naming. Backend foundation adds ServiceOfficeTransfer and CustomerHandoffOffice settlement 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, and InterOfficeSettlementLookupKey. That key prevents source BRANCH_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 through sanmopia_save_inter_office_settlement, with lookup uniqueness on reservation, customer relationship branch, service delivery branch, and period. Backend now exposes OpenInterOfficeSettlementCommand, InterOfficeSettlementCommandHandler, InterOfficeSettlementQueryHandler, InterOfficeSettlementApi, and FastAPI routes for POST /inter-office-settlements, POST /inter-office-settlement-lookups, and GET /inter-office-settlements/{interOfficeSettlementCode}. The branch history read side now adds ListInterOfficeSettlementHistoryQuery, GET /inter-office-settlement-histories/{branchProfileId}, and the shared TS helper interOfficeSettlementHistoryPath. 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 checks settle on both branches while history access checks the requested branch scope. Reservation-scoped Danbee settlement status now replaces source DANBEE_STATUS_FL with ReservationExternalCounterpartySettlementStatus, service-role-only Supabase projection table sanmopia_reservation_external_counterparty_settlement_statuses, GetReservationExternalCounterpartySettlementStatusQuery, GET /reservation-external-counterparty-settlement-statuses/{reservationId}, and shared TS helpers reservationExternalCounterpartySettlementStatusPath / findReservationExternalCounterpartySettlementStatusProblems. The workflow-owned update side now uses UpdateReservationExternalCounterpartySettlementStatusFromStatementCommand and POST /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 separate SettlementExportArtifact variants: source routes read central-to-branch, user-to-Danbee, other-office, history, and Excel download surfaces from different controller/model paths, and calculate_detail hides 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, and ServiceOfficeChanged should trigger FinancialLifecycleRecalculationNeeded until the affected branch/HQ board is closed. Closed boards need explicit SettlementCorrectionEntry rows instead of mutating already exported board values. Settlement board open/acknowledgement now has backend command-ledger idempotency through SettlementTransitionAudit uniqueness, SettlementStatement.replayed_command_audit, and the contract helper findSettlementStatementCommandReplay: 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, and SettlementBoardInvalidation. UI-posted settlement arithmetic is now modeled as operator-entered comparison evidence through SettlementArithmeticDecision: 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, and source-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, and datasetRevision; 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 as SettlementDataRoomRequest and SettlementDataRoomArtifact, separate from generic DocumentRoom: 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 adds SettlementDataRoomCollection, SettlementDataRoomScope, SettlementDataRoomRequest, SettlementDataRoomArtifact, SettlementDataRoomActionEntry, SettlementDataRoomCommandHandler, SupabaseSettlementDataRoomRequestRepository, SettlementDataRoomApi, FastAPI routes, Supabase Storage signed download handoff, and private Supabase tables sanmopia_settlement_data_room_requests, sanmopia_settlement_data_room_artifacts, and sanmopia_settlement_data_room_actions. Contract repo exposes POST /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, and POST /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 to source-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, and source-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, and source-refs/sanmopia-admin/application/views/table_local_cal_central_history.php:1-39. Additional source scan (2026-07-03) splits the data-room backlog into SettlementArchive, BranchSettlementArchive, BranchSettlementWorklist, ExternalCounterpartySettlementBatch, HeadOfficeSettlementBatch, OtherAreaSettlementCase, ResourceLibrary, ReservationDocumentExport, and BranchResourcePost. 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, and source-refs/sanmopia-admin/application/views/form_reservation_list.php:40. Status flags such as STATUS_FL, CENTRAL_STATUS_FL, DANBEE_STATUS_FL, PAYMENT_STATUS_LIST_ID_FK, and MONTH_DUE_STATUS_FL must become explicit SettlementBoardStatus, ReservationExternalCounterpartySettlementStatus, SettlementLineStatus, DepositRequest, DepositConfirmation, ArrearsRequest, and SettlementTransitionAudit concepts. Hardcoded voucher, promotional_coupon_cost, payment-method fee, and branch-exception amounts belong in versioned SettlementPricingPolicy fixtures before command migration; gift coupon settlement charges now use injected, effective-dated benefit-package rate catalogs and still post deleted-coupon charges separately as cancelled_gift_coupon_commission. Voucher fees are now modeled as VoucherServiceCommission with policy version, effective period, eligible-reservation count, and a receivable voucher_service_commission branch settlement line item, so the source VOUCHER_COUNT * 15000 view/model formulas remain evidence only. Branch settlement delivery fees now use BranchSettlementDeliveryFee with a shared SettlementPolicyEffectivePeriod; source DELIVERY_FEE, fdelivery-price, and DELIVERY_PRICE board fields remain adapter evidence, not UI authority. Deeper settlement data-room/document-download extraction (updated 2026-07-04): SettlementWorkspace now exposes separate SettlementDataRoomCollection worklists 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. BulkExportTemplatePolicy starts replacing hardcoded workbook/static-PDF ids and LIST_DATAROOM_FORM_TB rows 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, and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-4198. SettlementArtifactRequest and SettlementArtifactVersion must 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, and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4284-4601. SettlementArtifactGrant plus DownloadHandoffAudit must replace direct document.location.href GET 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, and source-refs/sanmopia-admin/application/views/data_room/other_post_view.php:72-89. Follow-up source scan (2026-07-03) keeps ReservationDocumentExportWorklist, BranchResourcePost, BranchResourceAttachmentVersion, and BranchResourceGrant as 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, and source-refs/sanmopia-admin/application/models/Data_room_model.php:25-203. OperatorReturnStateToken should keep list filters, branch selection, and post-action return state without trusting browser hash, query rebuilding, or document.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, and source-refs/sanmopia-admin/static/js/data_room/calculate_danvi_other_office.js:10-22. SettlementRepairRequest remains Pending until 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, and source-refs/sanmopia-admin/application/models/Payment_model.php:2526-2563. Required proof stays Partial: 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 adds SettlementStatement, SettlementRemittanceAccountSnapshot, SettlementTransitionAudit, SettlementStatementLineAcknowledgement, SettlementStatementManualRow, SettlementStatementCommandHandler, Supabase statement persistence, and FastAPI routes for RequestSettlementDeposit, AcknowledgeBranchSettlementDeposit, AddManualSettlementRow, ApproveHeadquartersSettlement, and RequestSettlementArrearsDeposit. 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 in sanmopia_branch_membership_due_snapshots before board opening, so opened boards no longer need to join mutable BRANCH_TB.MEMBERSHIP_PAY_PRICE or BRANCH_MEMBERSHIP_PAY_TB.PRICE. PromotionalCouponCost source parity now lands in sanmopia_branch_promotional_coupon_cost_snapshots and feeds branch settlement CQRS calculation as promotional_coupon_cost; deleted-coupon gift charges now come from versioned benefit-package rates and remain cancelled_gift_coupon_commission. Branch operator dashboard now exposes settlementStatusCounts, replacing source detailStatusZero / couponStatusZero dashboard counters with domain status names. HQ branch filtering now uses the BranchProfile branch_settlement_participation and is_active facts 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. SettlementCompletionReview now 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, then InterBranchSettlement.
  • 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 use sanmopia_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::download index == 16 expands a single selected reservation into a document bundle from hidden reservation[service_type][id], posts through iframe_download, deletes temp XLSX/PDF files after ZIP creation, maps voucher service to document ids 1,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_room now covers the non-reservation document room: branch/HQ post direction, target branch visibility, pinned windows, revisioned Strapi authoring, private Supabase Storage document-room-attachments, allowed attachment content types, retention, and parent-post RLS. Reservation document catalog/rendering remains under document-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_delivery now 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, abstract DocumentAccessReference, document definition key, artifact version key, delivery channel, and the mandatory download_document_artifact action; 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 by customer_engagement/features/content and sanmopia_content_publications. Strapi supplies the OSS authoring surface, Supabase Storage content-assets stores media, and the Sanmopia contract exposes stable health_education_expert_profile, health_education_article, health_education_video, health_education_faq, and health_education_visit_class kinds 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, and sanmopia-admin/static/js/datatables.js. Modern replacement: business_reporting/features/statistics now owns aggregate metrics and immutable BusinessReportSnapshot rows for dashboard/table readers. Supabase persists sanmopia_business_report_snapshots plus export requests in sanmopia_business_report_exports, with private artifacts in business-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: BusinessReportCatalog Pending, ScopedBusinessReportReadPolicy Partial, PerformanceDashboardSnapshot Pending, SalesRevenueSnapshot Partial, MemberActivityAnalytics Pending, BranchAccessAnalytics Pending, CaregiverRecognitionReport Partial, OperatorReportTable Pending, BusinessReportExportRequest Partial, and BusinessReportRefreshSchedule Partial (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-16 passes year, consume-version, filename, type, and suffix directly into the workbook loader; source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4807-4894 imports normal/private-care service price, customer share, and caregiver pay; source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4917-4974 imports normal add-on option prices and per-service-day derived amounts; source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4983-5108 imports voucher consume-type catalog rows; source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5136-5228 validates/inserts voucher service price, government support, customer share, caregiver pay, and in-home conversion; source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5246-5330 imports voucher add-on option rows; and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:5337-5395 creates or reuses the price-version row before dispatching normal/voucher imports. Seed workbooks still exist at source-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, and source-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-56 maps payment type/status display strings to ids, source-refs/sanmopia_web/application/models/Payment_model.php:154-160 seeds customer-share deposit, customer-share balance, and service-balance payment rows from PRICE_TABLE, and source-refs/sanmopia_web/application/models/Payment_model.php:772-777 seeds pre-reservation payment from PRICE_TABLE["realPrePrice"]. Modern replacement: pricing_settlement/features/price_catalog_import now owns componentized PriceCatalogEntry and PriceCatalogComponent validation. The workbook parser uses OSS openpyxl at the adapter boundary. It reads modern open-ended headers such as charge:<code>:<role>:<basis> and audits each voucher-care workbook independently instead of assuming one fixed entry count. Current parser results are 2025_voucher_250121 = 190 entries / 8 issues, 2025_voucher_250827 = 190 / 8, 2026_voucher_251211 = 154 / 0, and 2026_voucher_260119 = 143 / 55. The three issue-bearing workbooks are blocked. The older issue-free 2026_voucher_251211 workbook is not selected automatically: zero issues and recency do not establish approved source authority. Backend 7a9d26e provides the protected approval caller, but no source/version has actually been selected, approved, or invoked. Supabase stores original workbook artifacts in the private price-catalog-imports bucket, lifecycle rows in sanmopia_price_catalog_import_batches, and immutable entries in sanmopia_price_catalog_entries. price_catalog_quote now reads only published, effective catalog entries, filters by program, service tier, day count, and criteria, then returns componentized quote lines with gross_service_price and customer_share rules that avoid double-counting the mother payable amount. Accepted quotes can now be captured into finalized charge snapshots through PriceCatalogQuoteFinalizationPolicy; reference-only gross/subsidy lines are preserved without affecting the payable total, and MotherVisibleChargeSummary reads 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 PHP PRICE_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 into service_calendar instead of a generic system controller. Supabase stores national/branch holidays in sanmopia_service_calendar_holidays, selected reservation extra-service dates in sanmopia_reservation_extra_service_days, and immutable plan results in sanmopia_reservation_service_calendar_plans. National holiday seed data can be generated through the OSS holidays Python package, while branch-specific closures stay editable and RLS-scoped. Price-table import is now split into price_catalog_import with 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, so BranchServiceClosurePolicy must 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 exposes POST /service-calendar-compatibility-decisions, derives the actor from Supabase Auth, requires branch view permission when branchProfileId is supplied, and returns use_current_policy, preserve_source_service_end, or require_operator_review with policy fingerprint and source reference. Stored impact projections now expose this persisted decision through GET /reservation-service-calendar-impacts/{reservationBookingId} with optional planCode and impactKind, so pricing/report/scheduling/settlement consumers do not recalculate drift in UI code. Holiday publication and branch override impact preview is also backend-owned through POST /service-calendar-holiday-impact-previews and the Supabase RPC sanmopia_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 through POST /service-calendar-holiday-change-decisions, backed by active sanmopia_service_calendar_holidays rows, 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: PriceCatalogImportExecution Partial, ServiceCalendarHolidayPublication Partial, ServiceCalendarHolidayAudit Partial (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 tables sanmopia_service_calendar_holiday_audits and sanmopia_service_calendar_holiday_audit_revisions persist snapshots and append-only revisions with RLS, while SpiceDB-protected APIs POST /service-calendar-holiday-publication-decisions and POST /branch-service-calendar-holiday-overrides expose 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 wires POST /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 through POST /service-calendar-holiday-change-decisions, which reads active sanmopia_service_calendar_holidays rows and returns policy-level decisions instead of allowing UI-side date CRUD or alerts to control policy. OpenAPI route proof is covered by main_test.py, so these are not test-only interfaces. Remaining work: OSS holidays provider import execution, operator UI, accepted-decision execution, and publication workflow repair/replay screens), and SourceEvidencePathReconciliation Partial (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 path source-refs/sanmopia-admin/application/controllers/Load.php was not present in the evidence tree; nearby load-history evidence resolves through ManageSystem.php:33-40 and price import execution.
  • WinTheRace branch/manager ranking, year cache, manager stop, score/class recalculation. Status: Partial. Modern slice: caregiver-performance-recognition now 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_season replaces the yearly cache/ranking concept with versioned CaregiverPerformanceSeason and CaregiverPerformanceMetricRule objects, explicit CaregiverRankingTiePolicy, auditable CaregiverPerformanceManualAdjustment, immutable CaregiverPerformancePublication snapshots, and CaregiverVisibleSeasonHistory scope 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.
  • 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_profile should own CaregiverCredentialEvidence, CaregiverUnavailablePeriod, CaregiverProfileMedia, CaregiverSignatureAsset, CaregiverAccountCredential, and CaregiverOfficeRequest. 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 to caregiver_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, and sanmopia-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_profile should own CaregiverMatchingProfile, CaregiverPetCareConstraint, CaregiverServicePreference, CaregiverPersonalityAnswer, and CaregiverPreferenceVersion, then feed assignment optimization without exposing source answer ids to contracts. Backend foundation added under caregiver_assignment/features/caregiver_matching_profile with versioned preference mutations, pet/service/personality domain values, application payloads, stale expected-revision protection, and generic MatchingPreferenceCompatibilitySignal optimization 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_attendance records attendance as a reservation/caregiver/service-date ledger. care_delivery/features/daily_care_report replaces 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_submission now 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 uses MANAGER_SERVICE_TB and MANAGER_SUB_SERVICE_TB; schedule read paths also reference mismatched SUB_MANAGER_SERVICE_TB, and SUB_READ_FL has 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_report owns report definition validation, submitted answer validation, submission identity, and Supabase RLS. Strapi authors sanmopia_daily_care_report_definitions; caregivers submit sanmopia_daily_care_report_submissions; document rendering later consumes these submissions for printable A4 report series. Remaining gap: notification_obligation_dispatch now 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_delivery now covers manager daily-report/service-record notifications and generic push delivery through Novu-backed dispatch. reservation_operations/features/birth_information replaces the birth-information reminder with ReservationBirthProfile, unbounded child records, BirthInformationReminderPolicy, and BirthInformationReminderTask persistence. Supabase Cron/Queues schedule due tasks, Novu sends birth_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 inserts REPORT_FIRST, REPORT_PROGRESS, REPORT_LAST, and SERVICE; current first/progress/last and service-record queries include statuses 0,3,4,5,6,11,12 and exclude status 13, while historical repair helpers include 13 and hardcode 2021-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_content should consume CaregiverContentInbox, CaregiverLearningMaterial, CaregiverEventNotice, and CaregiverNewsPublication from the branch office content catalog. caregiver_engagement/features/caregiver_request should own CaregiverOfficeRequestThread, CaregiverReferralLead, and CaregiverEventParticipation. 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_request owns CaregiverOfficeRequestThread, and caregiver_engagement/features/caregiver_office_request_answer plans CaregiverOfficeRequestAnswerIntentPlan with branch-profile authorization, expected revision conflict protection, idempotent answer mutation, and provider-neutral caregiver_office_request:answered_caregiver dispatch. This replaces legacy UI-side blank checks, ambiguous branch_index request identity, direct MANAGER_REQUEST_TB mutation, and raw cURL pushRequestAnswer calls. 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-compensation now 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 through IssueReservationCaregiverPayoutInstructionsHandler and SupabaseReservationCaregiverPayoutInstructionStore; settlement continuation consumes payout instructions instead of raw quote lines. CareTeamContract now feeds compensation quote seeds directly through QuoteCareTeamCaregiverCompensationCommand, removing the need for UI or PHP screens to rebuild primary/sub caregiver role, handoff order, grade, and service-day facts before salary quote. SupabaseCareTeamCompensationSourceReader reads assigned rows from sanmopia_reservation_caregiver_assignments into 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 through build_sanmopia_backend_app_from_env() and prefers SUPABASE_PUBLISHABLE_KEY/SUPABASE_ANON_KEY for caller-JWT Data API reads when configured. Destination change proof now persists previous/adjusted bank-account and tax-evidence snapshots through CaregiverPayoutDestinationChangeAudit; branch-deposit acknowledgement now uses backend payout-slot identity with caregiver role and handoff order for source SORT > 0 assistant 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 are CaregiverCompensationQuote, CaregiverPayoutInstruction, CaregiverTaxElection, CaregiverSalaryOverride, and SubCaregiverCompensationShare. CaregiverPayoutStatement now 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. CaregiverPayoutReadModel now 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 source calcSalary in controller, PHP view, or JS. CaregiverPayoutReceiptState commands 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 as None, 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 by contract_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 Pydantic ApplicationContractModel payloads, 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 source SORT > 0 assistant rows. CaregiverPayoutOperatorIntentPlan now 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 source manager_pay_detail.js UI-side amount/tax/memo/deposit decisions and Reservation_model payment-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 ids 3 and 5, tax type ids 0 and 1, JS tax rate 0.033, date fork 2022-03-29 00:00:00, Korean service strings, and SORT == 0 parent-vs-SORT > 0 assistant row split. 2026-07-05 persistent-agent salary source-dig strengthening: source source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:14-24 and :155-231 posts browser-calculated payout amount plus tax type, while source-refs/sanmopia-admin/static/js/manager/manager_pay_detail_test.js:19-35 and :207-255 adds a saved-custom-price completion guard that live manager_pay_detail.php:627-644 does not load. Source source-refs/sanmopia-admin/application/controllers/Manager.php:1133-1182, :1225-1235, and :1300-1335 forwards browser amount/tax/manager ids into payout mutation paths; source-refs/sanmopia-admin/application/models/Reservation_model.php:2627-2650, :2747-2803, and :2945-3036 then 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. Source source-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:575-588 and source-refs/sanmopia-admin/application/views/manager/manager_pay_detail_test.php:523-530 call refresh() without a reservation id, while source-refs/sanmopia-admin/application/controllers/Manager.php:1238-1272 continues from sub-caregiver reset into main reset after updateSubCustomPriceRefresh(). Modern CaregiverSalaryOverrideResetCommand must target exactly one payout slot and reject missing reservation/payout statement ids instead of silently resetting aggregate payment rows. Modern CaregiverSalaryOverrideResetPlan now targets one contract_assignment_key plus caregiver role/handoff order and emits a CaregiverPayoutAdjustmentAuditRequest from current snapshot to backend default snapshot with actor profile, expected adjustment revision, idempotency, and source evidence. Contract tests reject no-op resets and prevent legacy CUSTOM_PRICE/SUB_CUSTOM_PRICE/PAYMENT_BRANCH_MANAGER_TB vocabulary from leaking into the new reset plan. Source source-refs/sanmopia-admin/static/js/manager/manager_pay_detail.js:234-260 and source-refs/sanmopia-admin/application/models/Reservation_model.php:2573-2624 changes sub-manager service-balance status by reservation id only and updates aggregate SUB_* flags, so modern SubCaregiverServiceBalanceAcknowledgement must key by caregiver role, handoff order, assignment term, and payout statement revision. Source source-refs/sanmopia-manager/static/js/other/pay_info.js:1-88, source-refs/sanmopia-manager/application/controllers/User.php:163-239, and source-refs/sanmopia-manager/application/models/User_model.php:114-154 show caregiver self-service bank-account writes mutate live global account rows; payout statements must keep destination snapshots and append-only CaregiverPayoutDestinationChangeAudit evidence 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-2271 computes Danbee board summary counts in PHP and assigns NORMAL_COUNT from VOUCHER_COUNT + 1, while :2317-2366 uses a different count formula for branch history. Modern SettlementDataRoomCollectionSummary must 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, and summary_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 legacy NORMAL_COUNT/VOUCHER_COUNT/CONFIRM_COUNT names. 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-recognition exposes caregiver-visible performance scorecards through contracts; the performance-season foundation now defines published CaregiverPerformanceSeasonScorecard snapshots, 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.
  • 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 missing db/kong hosts. Price workbook import uses the Supabase-first price_catalog_import slice rather than PHP CLI table mutation. Supabase Postgres initialization now follows the self-hosted image contract by preserving the image default POSTGRES_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.
  • 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-170 still proves legacy operator identity is only three coarse session types, while source-refs/sanmopia-admin/application/core/MY_Controller.php:113-116 exposes that session type directly to controllers. Modern migration must keep mother, 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-capability stage_allowed, relationship_allowed, allowed, and reason, while submit_booking_request checks branch manage before a reservation row exists. Shared workflow status responses now include reservationStatus and reservationCapabilityAuthorization for 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 define MotherBookingOperationalContext and /mother-booking-operational-context; backend now reads that endpoint from the versioned Supabase sanmopia_mother_booking_operational_contexts read 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, starts ReservationBookingWorkflow, and verifies the Supabase workflow request reaches completed through 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, and adapters/reservation_booking/supabase_booking_workflow_test.py all 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, accepts acceptedPriceCatalogQuote plus care-environment matching facts, and records finalized_charge_snapshot_id in sanmopia_reservation_booking_workflow_requests; backend exposes the Restate Python SDK deployment at /restate/v1 for 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 RPC sanmopia_save_reservation_booking_result instead of multiple Data API upserts, so reservation booking, payment record, finalized charge snapshot, charge lines, and financial lifecycle persist atomically. The latest stage smoke RBQ-SMOKE-20260704-003 completed the workflow and wrote payment_product_plan_code into sanmopia_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 passed uv run tach check, so the booking workflow remains inside the declared bounded-context and adapter/interface boundaries. Caregiver matching now preserves careEnvironment, acceptsPetHousehold, and petAllergySpeciesCodes across 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 application OptimizeCaregiverAssignmentsHandler validates 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 from GET /caregiver-matching-policies/active and the TS contract path helper. Requested named-caregiver decisions now share CaregiverCandidateFit policy 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 through ReservationOperationCommandPolicy, ReservationOperationCommandHandler, and Pydantic command/plan payloads. The policy now delegates the changing stage/condition matrix to ReservationOperationCommandRuleCatalog, 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 in sanmopia_reservation_operation_contexts and sanmopia_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 through pnpm run supabase:db:push:stage, schema lint uses pnpm run supabase:db:lint:stage, and pnpm run supabase:types:stage regenerates supabase/generated/database.types.ts so frontend/contract consumers can use generated Supabase table shapes instead of handwritten table contracts. Follow-up actions now have ReservationOperationFollowUpWorkflow on Restate, backend-only Supabase request/action ledgers, workflow status projection kind reservation_operation_follow_up, and command responses can return followUpWorkflowRequestId. 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 separate ReservationStateTransitionPolicy and 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-dated ReservationStateTransitionCatalog rules 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 as waiting_deposit and pre_reservation_waiting_deposit instead of raw status numbers, so UI/payment workers cannot choose persisted status ids locally. ReservationOperationCommandHandler now resolves and rejects persisted-state transition decisions for schedule confirmation, virtual-account deposit/expiry, and source-request commands before recording the operation plan. stop_requested is now a first-class lifecycle status before operator stop approval, instead of jumping straight to stopped. 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 has ReservationFinancialLifecycleWorkflow for Restate orchestration. ReservationPaymentWorkflow now 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. MemberPrivacyLifecycleWorkflow is registered on the same deployment and now advances sanmopia_member_privacy_lifecycles workflow status, pauses for operator review, or masks both the Supabase Auth account and member profile before completing. A shared WorkflowStatusProjection endpoint 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 has BranchSettlementOperatorBoard and BranchSettlementOperatorDashboard query contracts and backend read models, plus BranchSettlementReconciliationExport export-ready datasets and stored artifact commands, using Supabase settlement rows, financial lifecycle workflow rows, SpiceDB branch settle checks, business-report snapshots, business-report export metadata, private Supabase Storage objects, and BranchSettlementReconciliationExportWorkflow starts 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 as branch_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 into sanmopia_member_retained_record_snapshots and schedules delayed purge tasks in sanmopia_member_privacy_purge_tasks before masking Auth/profile data. MemberPrivacyPurgeWorkflow now 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 route POST /internal/member-privacy-purge-workflow-triggers; Supabase Cron binds to that route through pg_cron and pg_net, with runtime settings configured by pnpm 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 includes workflowRequestId, 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-84 mutates USER_TB, blanks voucher resident-number fields, and deletes tokens inside one controller transaction; it also reads $user->EMAIL after selecting only USER_ID_PK, PASSWORD, and AUTH_TOKEN, so the source cannot be treated as correct behavior. Required proof: withdrawal must run through a MemberWithdrawalRequest and MemberRetainedRecordSnapshot workflow 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 as awaiting_deposit, change_requested, and cancellation_requested must 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 frozen commandPayload, provider event ordering status, provider event refs, target result refs, retry diagnostics, and explicit work-item dependencies. Refund closeout starts in awaiting_provider_command, refund completion barriers depend on closeout and wait in awaiting_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 by ReservationStateTransitionPolicy: 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 feed PriceCatalogQuote read 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 optional service_calendar_impact_plan_id, service_calendar_impact_policy_fingerprint, and service_calendar_impact_fact_ids, so a paid charge can prove which charge_reprice_required service-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. ReservationServiceCalendarQuotePolicy now turns selected Saturday/holiday service-calendar charge facts into effective-dated, branch/program-specific quote lines, applies those lines to ReservationPriceSummaryInput, and preserves the same impact references before ReservationPriceSummaryChargeFreezePolicy captures the final payable snapshot. ReservationExtensionQuotePolicy now derives extension pricing from a forward-only original/new reservation chain plus its own calendar quote, instead of copying mutable payment rows. SourceServiceCalendarExtraOptionDecision now translates source labels 토요일 추가, 휴일 추가, legacy duration-extension tokens, and source add-date type codes SAT/HOLI into backend expected counts, profile-backed duration extension days, and domain extra-service-day selections. SupabaseServiceCalendarPolicyProfileReader now loads active global/branch service-calendar policy profiles by effective date, and branch service-area rules now expose coverage_profile_key plus service_calendar_policy_profile_key, so source locality labels stay evidence instead of becoming code branches. Daily-care printable submissions require service_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 around wanju_fl / wanju_option plus 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. Backend RegionalBenefitRule metadata now stores the ResidencySupportProfile key, service-day bonus count, and settlement participation code without city/county literals in application code. Application FinalizeReservationChargeWithRegionalBenefitHandler now freezes one RegionalBenefitDecision for price-summary charge finalization. Booking HTTP/API boundaries accept an acceptedRegionalBenefitDecision, build_reservation_booking_workflow_request() serializes it into durable Restate input, and charge finalization now freezes RegionalBenefitChargeImpactSnapshot rows 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. ReservationFinancialLifecycleWorkflow can start those transitions through Restate using one workflow request id and exposes progress reads backed by sanmopia_reservation_financial_lifecycle_workflow_requests. Kill Bill paid-payment verification, cancel, and refund now use a real V2 HTTP adapter behind ReservationPaymentWorkflow, exposed through public start/progress APIs and persisted to sanmopia_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 records approved_charge_finalization_status and finalized_charge_snapshot_id on the payment workflow ledger, and paid webhooks record payment_closeout_kind so 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 through ReservationFinancialLifecycleWorkflow, records settlement_continuation_status, settlement_continuation_workflow_request_id, and settlement_continuation_reason on the payment workflow ledger, and waits with waiting_for_financial_facts when service delivery, payout, branch, or HQ ledger facts are not ready. The Supabase continuation fact reader now maps prepared HQ settlement ledger lines from sanmopia_reservation_financial_ledger_lines into hqSettlementLines, so branch-settlement-ready reservations can advance without hand-built payloads when HQ ledger facts exist. 2026-07-08 follow-up: recording ServiceDeliveryCompletionFact now triggers a backend ResumeApprovedPaymentSettlementContinuationAfterServiceDeliveryHandler recheck 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 reaches settlement_continuation_status = workflow_started without 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 includes PaymentLedger, RefundQuote, ReservationCancellationRefundPolicy, PaymentRefundIntent, PartialRefund, PaymentAdjustmentCatalog, DiscountAdjustment, AdditionalChargeAdjustment, and adapter-facing PaymentRefundGatewayCommand. 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. SupabasePaymentRefundLedgerStore now rebuilds PaymentLedger from sanmopia_payment_records plus append-only sanmopia_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 carry payment_change_adjustment_id through application boundary DTOs, Pydantic-free domain intent/refund facts, queryable Supabase FK storage, and historical provider-command JSON fallback. Stage drift from current_cancellable_amount_krw is normalized back to current_refundable_amount_krw so generated Supabase types match backend adapter vocabulary. Public OpenAPI/TS contracts now expose POST /reservation-cancellation-refunds with optional paymentChangeAdjustmentId, and backend HTTP/API maps that id into PaymentChangeRefundLink without accepting UI-calculated paid/refund totals. Kill Bill administrator operation parity now has a backend/contract foundation through POST /killbill-payment-admin-operations and sanmopia_killbill_admin_operation_audits: branch/HQ operators can run audited lookup_payment, search_payments, close_virtual_account, inspect_refund_status, inspect_chargeback_status, and record_chargeback actions 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 through POST /reservation-payment-pre-registrations before 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. PaymentProductPlan is the sellable or operator-billable workflow product, while ReservationPaymentPurpose remains 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/effective sanmopia_payment_product_plan_catalog_items rows before provider handoff, and replays only when the saved plan code still matches. The same Pydantic-derived plan book now backs GET /payment-product-plans and GET /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. PlanPaymentCommunicationDispatchHandler now converts selected catalog routes plus recipient facts into backend-owned CommunicationDispatchRequest objects, so payment screens no longer decide notice targets or workflow keys. PaymentProviderTemplatePayload renders a policy-versioned providerTemplatePayload with 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. SupabaseCommunicationDispatchStore now persists CommunicationDispatchRequest rows by workflow-code/version lookup and inserts provider CommunicationDispatchEvent audit 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 is source_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. Raw PRICE_TABLE, raw PAYMENT_INFO maps, KCP/Kill Bill approval payloads, settlement continuation ids, provider transaction ids, and caregiver ledger ids stay out of customer contracts. ReservationPriceSummaryChargeFreezePolicy now converts the legacy-compatible ReservationPriceSummaryInput result 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. FinalizeReservationChargeFromPriceSummaryHandler stores the frozen summary on ReservationFinancialLifecycle, preserving the service-calendar impact references used during charge repricing. Payment-change adjustments now have a backend/domain/Supabase foundation: PaymentChangeAdjustment keeps 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 writes completed_at once. Supabase stores the ledger in sanmopia_payment_change_adjustments, keeps superseded unpaid rows as cancelled instead 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; protected PaymentChangeOperatorBoard now 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-only PaymentChangeOperatorAudit rows 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). PaymentCorrectionAmountChange now shares previous/corrected amount validation and signed delta naming between payment fact correction and payment-change amount-correction audit. Frontend reservation-operation board consumes manualPaymentReceiptCommandDraft for receipt defaults (d28ff5f). Paid adjustment payments now request settlement continuation through the shared financial lifecycle workflow source id payment-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 expose GET /reservation-payment-change-adjustments/{paymentChangeAdjustmentId}/settlement-continuation-workflow-status, which resolves an adjustment id to the shared reservation_financial_lifecycle workflow 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 carry contract_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 persists caregiver_assignment.roster into sanmopia_reservation_caregiver_assignments with primary/assistant role, assigned Supabase user, grade, term dates, planned days, and contract_assignment_key. CareTeamContract now 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; SupabaseCareTeamCompensationSourceReader now 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 raw READ_FL/SUB_READ_FL inference; 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, and sanmopia-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, and sanmopia_document_render_artifacts metadata upsert are migrated; the Supabase Storage adapter now creates short-lived private signed URLs for single-artifact and bundle handoff, with VIEW_RESERVATION stage 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 flattened daily_care_report_answer_rows / dailyCareReportAnswerRows with 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, and source-refs/sanmopia-admin/application/config/constants.php:112-137. Target name is SourceCompatibilityCatalog plus owning-context LegacyRuleAdapter entries. These facts live under domain/migration_governance/features/source_evidence_reconciliation and 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, and source-refs/sanmopia_web/application/controllers/api/ReservationDocument.php:21-39 show the source two-hour document token is user-scoped rather than reservation/document/artifact scoped; backend and public contracts now model this as DocumentAccessGrant with reservation id, document definition key, artifact version key, recipient, channel, expiry, revocation, audit scope, and explicit download_document_artifact action. source-refs/sanmopia_web/application/controllers/Notification.php:19-27 plus notification view source appends document tokens to arbitrary URL strings; modern NotificationDocumentActionGrant must 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-127 and admin calculation receipt links map provider bill commands and mutable local PRICE values in views; modern CustomerReceiptProviderCommandSnapshot must 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-264 and source-refs/sanmopia_web/application/models/Reservation_model.php:1401-1413 show coupon/pre-reservation over-credit grants split across closeout phases; modern CouponPrepaymentOverCreditEntitlement must 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-417 and later virtual-account callbacks show refund eligibility is provider/context dependent; modern VirtualAccountRefundEligibilityDecision must 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, and source-refs/sanmopia-admin/application/models/Reservation_model.php:5903 identify five unmigrated backend concepts. CaregiverWorkingDayRegister and CaregiverAttendanceCorrection must preserve branch-entered monthly working-day counts and attendance corrections. PaymentProviderNotificationInboxEntry, VirtualAccountDepositNotification, and PaymentProviderNotificationAdmissionPolicy must preserve KCP raw callback evidence, IP/admission decisions, ack behavior, and virtual-account closeout/cancel semantics. ReservationCreationAuditEntry, OperatorReservationIntakeSnapshot, and DuplicateReservationIntakeGuard must preserve operator-created reservation provenance. ReservationCancellationTimingFact, BranchPerformanceCancellationInclusionPolicy, and PerformanceRecognitionReservationEligibility must preserve cancellation timing rules used by branch performance recognition. ReservationServiceBalanceOverrideAudit, ReservationPriceVersionChangeAudit, and OperatorBranchSnapshot must 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.

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-001 ReservationServiceExpectedStartState. Legacy evidence: source-refs/sanmopia_web/application/models/Reservation_model.php:853-890, source-refs/sanmopia_web/application/controllers/api/Reservation.php:48-81, and source-refs/sanmopia_web/application/controllers/api/Reservation.php:409-412. Suggested owner: reservation_operations/features/reservation_service_start_decision plus reservation_operations/features/service_calendar. Missing backend rule: deleting an expected service start writes sentinel date 1970-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_decision now 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-002 OperatorReservationCalendarProjection. Legacy evidence: source-refs/sanmopia-admin/application/views/reservation_status/reservation_calendar.php:63-104 and source-refs/sanmopia-admin/static/js/reservation_status/reservation_calendar.js:1-72, plus source-refs/sanmopia-admin/application/controllers/Reservation.php:610-647 and source-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 id 37, maps status 19 to an offline label and status 13 to 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_calendar now 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-001 BranchOperationalExclusionPolicy. 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, and source-refs/sanmopia-admin/application/views/statistics/supermanager.php:58-68. Suggested owner: branch_operations/features/branch_operational_exclusion_policy, with later consumers in business_reporting/features/report_scope and pricing_settlement/features/settlement_scope. Missing backend rule: headquarters/development branch ids 36 and 37 are 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_policy now 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-002 ReservationAddressAdministrativeProfileDecision. 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, sigungu fallback 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, and tach check-external passed 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_disclosure with caregiver_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, and source-refs/sanmopia-manager/application/views/pay_info_detail.php:170-255. Suggested owner: pricing_settlement/features/caregiver_compensation plus care_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 a 2022-03-29 view 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-090 P1 Partial PaymentChangeCanceledReservationStatusProjection. 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, and source-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, plus PaymentChangeOperatorMutationCommand and PaymentChangeStatusTransitionProjection. Missing backend rule: source appends synthetic payment-change status id 0 for 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 from PRICE, then sends generic {type, value} PUTs for amount or raw PAYMENT_CHANGE_STATUS_ID_FK; PHP sanitizes amount with FILTER_SANITIZE_NUMBER_INT, writes the row directly, and sets COMPLETED_DT when status value equals 2 (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 generic type mutation.

  • SFC-20260708-CUR-091 P1 Partial OperatorReservationStatusOptionProjection. Legacy evidence: source-refs/sanmopia-admin/application/views/reservation_status/reservation_detail.php:78-166 and source-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 (9 versus 18), payment/payout/settlement invalidation preview, and source-status catalog version.

  • SFC-20260708-CUR-092 P1 Pending SettlementDataRoomNavigationActionProjection. 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, and source-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/calculate URLs 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 parses fyear/fmonth but passes NULL, NULL into 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 from getType, dataType, branchId, boardId, freservationId, fbranchType, raw STATUS_FL, and hardcoded labels such as 입금요청, 입금확인, 정산완료, 미납상태, 정산필요, and fee text like 바우처 수수료(건당 15,000원). Central data-room rows also parse THIS_DT length 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 from OTHER_OFFICE_TYPE plus BOARD_STATUS_FL. Target extension: pricing_settlement / SettlementDataRoomDetailProjection, pricing_settlement / SettlementDataRoomActionAvailabilityProjection, pricing_settlement / SettlementDetailDisplayAmountProjection, and pricing_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-093 P1 Partial PaymentChangeCompletionDispatchAndClientRefresh. 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, and source-refs/sanmopia_web/application/config/constants.php:146-147. Suggested owner: application/customer_engagement/features/communication_delivery. Backend feature name: PaymentChangeCompletionDispatchPlan. Migrated backend rule: PaymentChangeCompletionDispatchPlan now creates a typed PaymentChangeClientRefreshSignal and a versioned PlanPaymentCommunicationDispatchCommand for 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 in payment_change_completion_dispatch_plan_test.py. The operator completion endpoint now wires this plan into ReservationPaymentApi.complete_payment_change_adjustment, persists/enqueues the PlanPaymentCommunicationDispatchCommand through the configured planner, and exposes paymentChangeCompletionClientRefreshSignal in 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, and source-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 cutoff 2023-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, and source-refs/sanmopia_web/application/models/Reservation_model.php:994-1045. Suggested owner: reservation_operations/features/birth_information plus reservation_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 IDHidden source behaviorSource path evidenceModernization targetImplementation statusBackend-owned replacement
SFC-20260706-UI-001Reservation 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-288reservation_operations / ReservationIntakeDraftSession, member_management / SensitiveReservationPartyDraft, pricing_settlement / IntakeQuoteContext, IntakeQuotePreviewSnapshotBackend foundation: 5da76ddReplace 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-002Caregiver 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-40care_delivery / CaregiverWorkReservationProjection, operator_access / CareManagerReservationAccessDecision, pricing_settlement / CaregiverPayoutReadinessProjectionBackend foundation: 1bd7e42Backend 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-003Caregiver-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-49caregiver_engagement / CaregiverOfficeRequestThread, operator_access / CaregiverRequestAuthorizer, communication_delivery / HeadquartersRequestReplyNotificationBackend foundation: 7f56280Backend 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-004Caregiver 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-2234caregiver_engagement / CaregiverCampaignParticipation, customer_engagement / CampaignSubmissionPolicy, operator_access / CaregiverCampaignEligibilityProjectionBackend foundation: b54084eBackend 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-005Caregiver 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-917caregiver_management / CaregiverProfileRevision, caregiver_assignment / CaregiverTravelEvidenceInvalidation, communication_delivery / CaregiverDeviceEndpointRegistrationBackend foundation: bf38296Backend 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_idlane_ownersource_evidenceddd_aggregatecommand_querypersistencecontracte2e_proofstatus
SFC-20260708-UX-001Frontend lanefrontend-repo/src/ui/organisms/FamilyAssistedReservationFlow.tsx, frontend-repo/src/ui/templates/MotherBookingTemplate.astro, and frontend-repo/src/lib/mother-booking-operational-context-client.tsreservation_operations / ReservationBookingOperationalContext, pricing_settlement / BookingPaymentMethodSelection, and frontend_experience / MotherBookingCardFlowEvidenceGetMotherBookingOperationalContextQuery, StartReservationBookingWorkflowCommand, GetReservationBookingWorkflowRequestQuery, and CreatePaymentProviderRoutePreRegistrationCommandNo 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 IDMissing source behaviorSource path evidenceModernization targetImplementation statusBackend-owned replacement
SFC-20260706-CUR-001Sales/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-309business_reporting / TaxEvidenceExportArtifact, pricing_settlement / SettlementEvidenceDatasetRevision, operator_access / EvidenceExportPermissionBackend foundation: e3e9ad6; Cash receipt dataset bridge: d79aeb6Add 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-002Lovebox/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-491customer_engagement / PartnerBenefitRecurringExportSchedule, document_reporting / PartnerBenefitDatasetArtifact, operator_access / PartnerExportRecipientGrantBackend foundation: c4d0a40Replace 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-003Printable 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-266document_reporting / PrintableFreeTextLayoutPolicy, ReservationIntakeDocumentProjection, DocumentRenderAttemptBackend foundation: a31229fAdd 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-004Repeated 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 / PreReservationTransferPermissionBackend foundation: 5442c31Add 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-005Customer 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-25customer_engagement / CustomerPointBulkImportRun, pricing_settlement / CustomerPointLedgerEntry, operator_access / BulkPointImportPermissionBackend foundation: 1b36666Backend 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-006Customer 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-2224business_reporting / CustomerActivityTelemetrySession, customer_engagement / CustomerActivityConsentScope, platform_observability / CustomerActivityAggregateProjectionBackend foundation: 409f146Backend 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-007Shopping-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-68pricing_settlement / ManualShoppingMallCouponBatchIssueRun, customer_engagement / ShoppingMallCouponEntitlement, operator_access / CouponBatchIssuePermissionBackend foundation: a85a5bbBackend 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-105Member-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-693promotion_entitlement / OperatorIssuedGiftCouponGrant, pricing_settlement / ReservationDiscountCouponImpact, operator_access / CouponIssuancePermissionPartialAdd 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-008Caregiver 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-38caregiver_management / CaregiverPersistentSessionGrant, operator_access / CaregiverSessionRecoveryPolicy, security_audit / PersistentLoginAuditEventBackend foundation: 8d6b368Backend 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-009Caregiver 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:27caregiver_engagement / CaregiverHeadquartersContactCommand, communication_delivery / SmsDispatchRequest, operator_access / CaregiverHeadquartersContactPermissionBackend foundation: 02fb3ed + 07f6824Backend 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-010Reservation 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_instructionBackend foundation: 41b3913Backend 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-011Manager 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_impersonationBackend foundation: adcc4cbBackend 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-012Customer 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 / CustomerSupportImpersonationAuditEventBackend foundation: 2ef4ce1Backend 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-013Admin 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-1678pricing_settlement / OperatorPaymentFactEditCommand, OperatorPaymentDateCorrectionPolicy, operator_access / OperatorPaymentFactEditPermissionBackend 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: f9a14d2Backend 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-014Gift-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-734pricing_settlement / GiftCouponCheckoutSession, pricing_settlement / GiftCouponPaymentDraftSupersessionFact, promotion_entitlement / GiftCouponOfferSelection, pricing_settlement / GiftCouponPaymentCloseout, promotion_entitlement / GiftCouponEntitlementIssuanceBackend foundation: f6f512a; Backend runtime API: 69e78cf; Backend closeout foundation: 6aef95c; Contract checkout: 811768e; Contract closeout: 2ba20fa; OpenAPI/schema: dbf3c96Backend 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-015Gift-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 / GiftCouponResendDispatchRequestBackend foundation: abba19b; Contract: 760838fBackend 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-016Gift-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-195pricing_settlement / GiftCouponRefundSaga, pricing_settlement / PaymentRefundIntent, promotion_entitlement / GiftCouponEntitlementCancellationBackend foundation: 8586f94; Contract: cadbb1bBackend 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-017Gift-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-664promotion_entitlement / CouponExpirationLedger, promotion_entitlement / GiftCouponEntitlementState, pricing_settlement / ExpiredCouponSettlementVisibilityPolicyBackend foundation: 42e4cd2; Contract: 3ab9a08Backend 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-018Admin 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 / ProviderRefundRepairPermissionBackend foundation: b71f600; Persistence: 5241e3c; Permission binding: 69eb6d3; Internal planning route: current; Execution-attempt route: currentBackend 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-019KCP 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 / SettlementTaxEvidenceDatasetRevisionBackend 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: c48bbfcBackend 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-020Sales 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 / ReportingScopePermissionBackend foundation + contract: bbb6455; Provider refund reporting invalidation: e038c7c; Provider result orchestration: 8db9942; Refresh queue request: fa13ef7; Refresh queue processor: c46382bBackend 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-021Sales/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 / ReportingDrilldownAccessGrantBackend foundation + contract: d5b9c80Backend 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-022Settlement 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 / SettlementFeeClassificationRepairCaseBackend foundationSettlementPaymentMethodFeeEvidencePolicy 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-023Branch/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 / SettlementStatementExportGrantBackend 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: e705d7cBackend 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-024Performance 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 / PerformanceDashboardScopeGrantBackend foundation: 2fadc96Backend 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-025Performance 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 / PerformanceDashboardScopeGrantBackend foundation + contract: 550f3c7Backend 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-026Statistics 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 / ReportTableReadGrantBackend foundation + contract: d95fdd7Backend 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-027Visitor/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 / EngagementReportScopeGrantBackend foundation + contract: f5e24a1Backend 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-028Reservation 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 / ReservationHistoryExportGrantBackend foundation + contract: 483593dBackend 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 status 19, joins only paid payment rows (PAYMENT_STATUS_LIST_ID_FK = 1), excludes raw status ids [9,14,17,18] and branch id 37, 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, and source-refs/sanmopia-admin/application/models/Statistics_model.php:2612-2627. Target refinements: business_reporting / SalesReportingDateWindowPolicy, business_reporting / RevenueRecognitionStatusCatalog, business_reporting / SalesRevenueDatasetRevision, and operator_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: backend 1a6a7cc now wires QueueWorkloadKind.PROVIDER_REFUND_REPORTING_REFRESH to SupabaseProviderRefundReportingProjectionRefreshProcessor with the concrete ProviderRefundSettlementExportRefreshHandler. 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: backend b3d3dc1 now persists and rehydrates the branch reconciliation export’s dataset_revision_key and SHA-256 dataset_revision_fingerprint through 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 mutable CUSTOM_SERVICE_BALANCE_PRICE or the current PRICE_TABLE['leftPrice'], and parses Korean display labels from additionalServicePriceList into 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: ReservationIntakeDocumentProjection and ReservationChargeDocumentSnapshot must 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 remains Partial: backend a31229f covers 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, and SFC-20260708-CUR-088: legacy settlement fee rounding diverges across browser, PHP detail, and XLSX consumers. The browser applies Math.ceil for 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, and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3869-3880. Modern invariant: SettlementPaymentMethodFeeEvidencePolicy must freeze the method, rate, integer-KRW rounding mode, per-line versus aggregate rounding scope, computed fee, policy revision, and evidence revision. Data-room UI and SettlementStatementDatasetRevision exports must consume that same frozen integer instead of recomputing it. Status remains Partial: 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, and DocumentRecipientAuthority: 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-243 and :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, and StoredPrintableDocumentArtifact. Status remains Partial: 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-023 and SFC-20260706-CUR-044: settlement XLSX export has neither typed collection selection nor actor-bound board scope. Calculate requires login only, then accepts query excelType and boardId; the spreadsheet function never uses excelType, always treats the id as DANBEE_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-10 and :568-578, plus source-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 one SettlementStatementExportGrant; query type or numeric board id must never select collection or scope. Modern target: SettlementDataRoomArtifactRequest, SettlementStatementDatasetRevision, SettlementStatementExportGrant, and SettlementArtifactBuildRunLedger. Status remains Partial: 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-028 and SFC-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 through IFNULL, and falls back to reservation creation time. Outer normal/voucher joins can produce duplicate rows, then GROUP BY reservation 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, and ReservationHistoryExportDatasetSnapshot. Status remains Backend 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.

  • P0 Backend foundation ReservationExternalCounterpartySettlementStatus. Source evidence: DANBEE_STATUS_FL remains source evidence only. Modern public API now uses GET /reservation-external-counterparty-settlement-statuses/{reservationId}, internal workflow update POST /internal/reservation-external-counterparty-settlement-status-updates, ReservationExternalCounterpartySettlementStatus, and Supabase table sanmopia_reservation_external_counterparty_settlement_statuses. Dataset and evidence fields are now datasetRevision and lineageEvidenceKeys at 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 ServicePauseInterval and ServiceDayCouponEntitlementDecision. 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_calendar is 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 commit fee19fe adds ServiceWeekProfile, ServiceDurationProfile, and Pydantic payloads under top-level service_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 ReservationServiceOccurrenceLedger and CreditedServiceDayBenefitEntitlement. 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 / ReservationServiceOccurrenceLedger plus pricing_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, mutable HOLIDAY_TB rows, source diffDay == 15, or service-end-plus-one-month SQL. Backend commit 2085085 adds ReservationServiceOccurrenceLedger and typed Pydantic projection payloads under top-level service_calendar: service-term plans now project stable occurrence_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 commit 5108868 persists the ledger through ReservationServiceOccurrenceLedgerStore and Supabase tables sanmopia_reservation_service_occurrence_ledgers / sanmopia_reservation_service_occurrence_ledger_entries; stage Supabase migration 20260707081211 is applied with RLS, service-role grants, JSON snapshot checks, credited-sequence invariants, and no anon/auth table grants. Backend commit bbde5e2 adds ReservationServiceOccurrenceLedgerCommandHandler, so reservation creation or change services can project a ServiceTermPlan and write the frozen ledger through one application command. Backend commit 7289fd4 wires successful booking orchestration to that command when an accepted ServiceTermPlan is supplied; booking_test.py::test_reservation_booking_success_persists_occurrence_ledger now creates a reservation and persists its occurrence ledger at application level. Backend commit 7f7e061 exposes acceptedServiceTermPlan on HTTP/ReState reservation start payloads and maps it through Pydantic PlanServiceTermPayload into the booking command, so occurrence counts are computed by backend policy instead of UI numbers. Backend commit 87a3021 wires the Supabase booking runtime to the occurrence-ledger store and exposes service_occurrence_ledger_key from the Python API response; runtime tests prove successful booking writes ledger and entry upserts. Backend commit 26864d8 adds a revisioned ledger command and shared key builder, so reservation change/admin flows can persist v2+ occurrence ledgers instead of mutating the original booking snapshot. Backend commit 70b4b67 adds ReservationServiceTermMutationCommandHandler; 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 commit f3d87e5 exposes POST /reservation-service-term-mutations/{reservationBookingId} with Supabase session auth, SpiceDB reservation manage permission, Pydantic PlanServiceTermPayload intake, and focused API/HTTP tests; targeted booking tests also prove reservation creation can persist an occurrence ledger. Supabase runtime now binds SupabaseReservationServiceTermMutationRevisionReader, so service-term mutation rejects stale saves against sanmopia_reservation_bookings.revision_number. 2026-07-07 follow-up adds OperatorServiceTermMutationDraft, which converts operator source-form evidence into ApplyReservationServiceTermMutationCommand only after proving source start/end/term/selected dates match the backend-owned PlanServiceTermPayload; broad-save status/payment fields are rejected and must use dedicated commands. 2026-07-07 backend follow-up exposes POST /reservation-service-term-mutations/{reservationBookingId}/operator-draft-applications so 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 into pricing_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, and PaymentCloseoutOccurrenceLedgerGuard. 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, and source-refs/sanmopia-admin/application/models/Reservation_model.php:3667-3678. Mutation API caller inventory is recorded in weekly-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-owned ServiceTermPlan and ReservationServiceOccurrenceLedger revision 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 commit a414f59 implements the first application-layer PaymentCloseoutOccurrenceLedgerGuard proof: branch/HQ settlement commands can be configured to require the current frozen occurrence-ledger key/revision before settlement closeout proceeds. Backend commit 777b496 binds the production financial-lifecycle advancer to SupabasePaymentCloseoutOccurrenceLedgerReferenceReader, which reads the latest revision from the existing sanmopia_reservation_service_occurrence_ledgers table. Backend commit e5a4043 adds PaymentCloseoutFinalizedChargeSnapshotGuard proof for branch/HQ settlement closeout, binds production to SupabasePaymentCloseoutFinalizedChargeSnapshotReferenceReader, rejects blank or stale finalized-charge snapshot ids, and proves HTTP payload passthrough. Contract commit b258745 exposes serviceOccurrenceLedgerKey, serviceOccurrenceLedgerRevisionNumber, and finalizedChargeSnapshotId on settlement ledger-line preparation payloads. Focused proof: backend advance_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 focused reservation-payment_test.ts pass on 2026-07-07. Backend commit 743976c adds PaymentCloseoutServiceBalanceConfirmationGuard proof for branch/HQ settlement closeout, binds production to SupabasePaymentCloseoutServiceBalanceConfirmationReferenceReader, reads the existing sanmopia_service_balance_payment_closeouts booking row, rejects blank/non-service-balance/duplicate closeout evidence, and proves HTTP payload passthrough for serviceBalanceCloseoutEventId. Contract commit 3fc9a89 exposes serviceBalanceCloseoutEventId on settlement ledger-line preparation payloads. Focused proof: backend advance_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 focused reservation-payment_test.ts pass on 2026-07-07. Current slice adds PaymentCloseoutAdditionalServiceSelectionRevisionGuard proof for branch/HQ settlement closeout: settlement commands can require a current additionalServiceSelectionRevisionKey plus revision number, production reads the revision from reservation collaboration journal rows where service_schedule.extra_service_days changed, freezes a digest of current sanmopia_reservation_extra_service_days, and rejects stale closeout payloads so legacy /reservation/insertAddService and /reservation/deleteService style payment rewrites stay source evidence only. Contract payloads expose additionalServiceSelectionRevisionKey and additionalServiceSelectionRevisionNumber.

  • 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-028 ReservationHistoryExport. 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-029 Reservation-history worklist filter conflicts. Source filters combine browser flags and raw status ids, then build contradictory SQL (statusIndex1 and 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 / ReservationHistoryWorklistFilterDecision plus operator_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-only reservation_operation_worklist slice exposes a principal-scoped GET with semantic repeated statuses, search, cursor, and limit; it resolves exactly one branch-operator membership, checks SpiceDB branch: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 operator 200, mother 403, 501 visible rows, first page 50, 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-030 Service-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 / ServiceBalanceFollowUpWorklistSnapshot and reservation_operations / ServiceBalanceCompletionRiskPolicy. Status: Backend foundation: a885c87. Backend now has ServiceBalanceCompletionRiskPolicy, 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 of nonServiceBalancePrice list math.

  • SFC-20260706-CUR-031 Near-start unassigned caregiver queue. 관리사 미지정 예약 is computed from MANAGER_ID IS NULL, cancellation exclusion, and DB-local now()+2 days math 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 / UnassignedCareReservationWorklistSnapshot and reservation_operations / NearStartCoverageRiskPolicy. Status: Backend foundation: a885c87. Backend now has NearStartCoverageRiskPolicy, UnassignedCareReservationFact, frozen near-start snapshot, assignment revision keys, deterministic business-date window, excluded-state reason codes, and Pydantic payloads that reject legacy MANAGER_ID field authority. Remaining proof: Supabase assignment-risk projection persistence, branch timezone binding, worklist API route, assignment decision evidence panel, and frontend migration from raw nonManager flag to typed backend projection.

  • SFC-20260706-CUR-032 Reservation-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 / ReservationHistoryDateScopeDecision and operator_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 legacy dateType, serviceDateDefault, and branchId hash 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-033 Reservation 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 / ReservationRetirementCommand and operator_access / ReservationDeletionCapability. Status: Backend foundation: 8c51885. Backend now replaces physical delete with ReservationRetirementCommand, ReservationRetirementPolicy, ReservationRetirementDecision, dependency snapshots, expected revision, actor reason, idempotency key, soft-retire/review/reject outcomes, audit key, and scoped ReservationDeletionCapability. Pydantic contracts reject legacy reservation-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-034 Product 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 / ProductCouponActionAvailability and promotion_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 legacy freservation-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-035 Reservation-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 from ReservationPaymentSummary, freezes receipt date fallback, source revision, projection revision, payment fact keys, semantic display state, and missing-date reason codes. Pydantic contracts reject legacy BEFORE_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-036 External 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 / ExternalReferralExportWithdrawalPlan and communication_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 plus MOMFIRST_ID_PK, SEND_FL, and DELETE_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-037 Branch 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, and source-refs/sanmopia-admin/application/views/table/calculate/table_local_cal_danvi.php:20-29. Target: pricing_settlement / BranchSettlementBoardSummaryProjection and pricing_settlement / SettlementComponentFollowUpState; include pricing_settlement / ExternalCounterpartySettlementBoardSummaryProjection for 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 adds BranchSettlementBoardSummaryProjection, SettlementComponentSummary, and SettlementComponentFollowUpState. 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 ids 36/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 from SERVICE_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, BranchHeadquartersSettlementCommandBinding for 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-038 External 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 / ExternalCounterpartySettlementWorklistSnapshot and pricing_settlement / SettlementReadinessDecision. Backend must own service-category counts, confirmed/residual counts, readiness reason, period revision, and detail grant. Status: Backend foundation: 86454f2. Backend now adds ExternalCounterpartySettlementWorklistSnapshot, ExternalCounterpartyServiceCategoryCount, and SettlementReadinessDecision. Service-category counts use stable voucher_care / private_care domain 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 raw PAYMENT_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, but getPaymentDataForDanbee() 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, and source-refs/sanmopia-admin/application/models/Payment_model.php:3721-3729. Add pricing_settlement / ExternalCounterpartySettlementPeriodPolicy and pricing_settlement / SettlementDateBasisSnapshot so 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-039 Settlement 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 / SettlementHistoryBoardSummarySnapshot and operator_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 adds SettlementHistoryBoardSummarySnapshot, SettlementHistoryReservationCount, and SettlementHistoryAmount. 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 like DANBEE_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-040 Settlement 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 / SettlementHistoricalFeeEffectivePeriodPolicy and pricing_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 adds SettlementPeriodKey, SettlementMembershipDueSnapshot, SettlementHistoricalFeeEffectivePeriodPolicy, and SettlementHistoricalFeeEffectivePeriodDecision. Legacy raw period keys YYYYM and YYYYMM normalize to canonical YYYY-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_snapshot or rebuild_history_row_from_board_period_snapshot. Strict Pydantic contracts reject SQL/current-date transport such as CONCAT(YEAR(CURDATE()), MONTH(CURDATE())) and raw THIS_DT authority. Remaining proof: Supabase adapter for sanmopia_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-041 Offline 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 / OfflineReservationIdentityEvidencePolicy and member_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. OfflineReservationIdentityEvidencePolicy now turns source placeholders, admin bypasses, and legacy imports into backend-owned placeholder/validated decisions. SensitiveIdentityPlaceholderDecision owns member-privacy placeholder facts and always prohibits normal-domain storage of placeholder resident fragments. Pydantic contracts reject legacy raw fields such as user_number_1 / user_number_2 and raw placeholder values such as 000000 / 0000000. Remaining proof: Supabase persistence, operator/member privacy audit ledger, reservation intake API binding, and migration backfill that replaces RESERVATION_SERVICE_VOUCHER_TB.USER_NUMBER* placeholder fragments with redacted evidence keys.

  • SFC-20260706-CUR-042 Caregiver 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 / CaregiverLifecycleStateCommand and caregiver_assignment / CaregiverAvailabilityInvalidation. Backend must own reason, effective date, expected revision, actor scope, assignment/payout invalidation facts, and audit events instead of raw ACTIVE_FL, DELETE_FL, or REENTRY_FL toggles. Backend foundation: e5d9fc4. CaregiverLifecycleStatePolicy now 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. CaregiverAvailabilityInvalidationPolicy now emits matching-cache, open-assignment, and payout-projection invalidation scopes from lifecycle decisions. Pydantic contracts reject raw source flags such as ACTIVE_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 source ACTIVE_FL / DELETE_FL / REENTRY_FL.

  • SFC-20260706-CUR-043 Caregiver 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 / CaregiverReferralApplicantCase and operator_access / CaregiverRecruitingCaseScopeGrant. Backend must own applicant-case commands, PII boundary, memo revision, branch assignment authority, and recruiting notification hooks. Backend foundation: 1b9be8a. CaregiverReferralApplicantCasePolicy now 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. CaregiverRecruitingCaseScopeGrant now owns read/private-profile/branch-assignment/memo/contact capabilities, branch scope, expiry, and denial reasons. Pydantic contracts reject legacy PII/source table fields such as PHONE and MANAGER_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 from MANAGER_RECOMMEND_TB.

  • SFC-20260706-CUR-044 Settlement 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, and source-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, and source-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, and source-refs/sanmopia-admin/application/controllers/Calculate.php:337-369. Target: pricing_settlement / SettlementDetailLookupGrant and operator_access / SettlementDetailScopeGrant; add operator_access / SettlementBranchActorProfileBinding and pricing_settlement / SettlementParticipantBranchRoleProjection to cover branch profile and inter-office side mapping; add pricing_settlement / SettlementDetailActionProjection and operator_access / SettlementDetailReturnStateToken for button labels, enabled/disabled reasons, download/detail links, and post-action return routes; add operator_access / SettlementActionCommandGrant for 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-owned getType, dataType, branchId, or fbranchType authority. Legacy data-room/detail pages let session type, BRANCH_INDEX, raw BRANCH_ID_PK/BRANCH_ID, query boardId/branchId, BRANCH_MANAGER_INDEX, BRANCH_SERVICE_INDEX, BRANCH_TYPE, STATUS_FL, BOARD_STATUS_FL, DANBEE_STATUS_FL, and OTHER_OFFICE_STATUS_FL decide who can view or act; central detail reloads branch data from boardId, 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 using document.referrer or hardcoded data-room paths. Command-side legacy JavaScript posts ftype, fbranch-id, fdata-type, fboard-id, and fbranch-type; controller branches on posted ftype to choose admin-vs-branch settlement behavior, writes admin actions as branch 0, 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. SettlementDetailLookupGrant now 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. SettlementDetailScopeGrant now 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 including getType, dataType, branchId, fbranchType, boardId, and freservationId. 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-045 Settlement board transition source-log provenance. Source settlement logs lose board identity and encode admin as branch 0. 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 / SettlementBoardTransitionProvenanceRepair and pricing_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 source insertLog($branchId, $boardId, ...) as reliable audit. Backend foundation: ab775a2. SettlementBoardTransitionProvenanceRepairPolicy now imports LOG_BOARD_PAYMENT_ADMIN_TB rows as low-confidence provenance, maps source branch marker 0 to 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 $boardId argument. Pydantic contracts expose strict import/provenance payloads and reject unexpected source fields such as boardId. 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-046 Settlement period-key compatibility. Legacy settlement period identity uses raw THIS_DT strings such as YYYYM or YYYYMM, 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 / SettlementStatementPeriodKeyCompatibility and pricing_settlement / settlement_statement_period_identity. Backend must normalize raw period keys to canonical YearMonth, retain raw source key, enforce branch-period uniqueness, and use normalized period for fee snapshots. Backend foundation: da8cc74. SettlementStatementPeriodIdentity now reuses the existing SettlementPeriodKey normalization for source YYYYM and YYYYMM, preserves raw_source_period_key, exposes canonical YYYY-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 as fmonth. Remaining proof: Supabase unique constraint/backfill adapter, board import using canonical period, fee snapshot adapter migration, settlement query route binding, and legacy THIS_DT compatibility runbook.

  • SFC-20260706-CUR-047 Settlement 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 / SettlementLineSelectionSnapshot and pricing_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. SettlementLineSelectionSnapshot now freezes selected line ids, row group keys, payment-purpose codes, amount snapshots, source revisions, source row references, actor, board revision, and selection-token reference. SettlementLineSelectionCommandReference accepts 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 as farray-normal-id, farray-payment-type, data-price, data-id, fdelivery-price, and fresult-price. Sidecar mining also found hidden membership/delivery/ETC rows, coupon-linked row toggles, pay-method fee math, and select-all group state in calculate_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-048 Inter-office settlement closeout quorum. Legacy inter-office closeout depends on service/customer branch side strings, BRANCH_TYPE magic 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 / InterOfficeSettlementCloseoutQuorum and pricing_settlement / inter_office_settlement_closeout, extended by pricing_settlement / InterOfficeSettlementAllocationPolicySnapshot and pricing_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 post resultPrice, feePrice, totalPrice, or branch-type strings as settlement authority. Backend foundation: 202616b. InterOfficeSettlementCloseoutQuorum now 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 existing InterOfficeSettlementAcknowledgementSide vocabulary as InterOfficeSettlementParticipantRole to avoid duplicate side enums, rejects duplicate participant acknowledgements, participant-branch mismatch, stale projection revision, missing/extra line revisions, and legacy role strings such as serviceOffice. Pydantic contracts recursively reject legacy closeout fields including branchType, BRANCH_TYPE, BOARD_STATUS_FL, resultPaymentInfo, DANBEE_STATUS_FL, and OTHER_OFFICE_STATUS_FL. Sidecar mining confirmed legacy closeout’s hidden quorum was resultPaymentInfo == 3 over 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 legacy BRANCH_TYPE backfill adapter.

  • SFC-20260706-CUR-049 Customer 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 / VoucherIdentityValidationPolicy and member_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. VoucherIdentityValidationPolicy now 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. RedactedResidentIdentityEvidence now owns domestic and foreign resident-registration checksum classification and exposes only masked display plus evidence keys. Pydantic application contracts forbid legacy raw fields such as USER_NUMBER1, USER_NUMBER2, reg_number_front, reg_number_back, and jumin; 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 contract pnpm check. Backend follow-up 544c27f now records voucher recipient identity evidence into service-role-owned sanmopia_redacted_resident_identity_evidences rows 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-050 Voucher 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 / VoucherServiceSelectionMutationPlan and reservation_operations / SensitiveIdentityValidationAtomicityGuard. Backend must validate identity, reservation revision, service-row revision, and mutation plan before destructive row replacement. Backend foundation: 9969110. VoucherServiceSelectionMutationPlan now 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 successful VoucherRecipientIdentityEligibilityDecision before 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 as RESERVATION_SERVICE_VOUCHER_TB, RESERVATION_SERVICE_NORMAL_TB, RESERVATION_ADD_OPTION_*, USER_NUMBER1, USER_NUMBER2, and reg_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-051 Voucher 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 / SensitiveResidentIdentityDraftProjection and reservation_operations / VoucherIntakeSensitiveFieldGrant. Backend must expose masked readiness state or short-lived sensitive-field grant only; raw USER_NUMBER1 / USER_NUMBER2 must not return to normal UI payloads. Status: Backend foundation implemented in backend commit d4ed8d6. 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-052 Operator 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 / VoucherIdentityFieldVisibilityDecision and member_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 implemented in backend commit 62a5070. The migrated slices add branch/HQ scoped operator visibility grants, hidden/masked_identity/placeholder decisions 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-053 Voucher 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 / VoucherIdentityDocumentEvidenceSnapshot and member_management / ResidentIdentityPlaceholderConsumerPolicy. Renderers must consume verified/redacted identity evidence snapshots; placeholder/raw fragments must not create document cells or birthdate facts. Status: Backend foundation implemented in backend commits 37527b3 and 544c27f. 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. Backend 544c27f adds 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-054 Caregiver 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, inserts MANAGER_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, and customer_engagement / RecruitingNotificationRequested. Backend must own required fields, phone canonicalization, duplicate scope, PII logging policy, and notification template/outbox. Status: Backend foundation implemented in backend commit f217c7f. The migrated slice adds RegisterCaregiverReferralApplicant, 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 to communication_delivery, add idempotency/unique DB constraints, and replace legacy full-PII/token logging with redacted audit events.

  • SFC-20260706-CUR-055 Caregiver 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 / CaregiverReferralApplicantCaseDetail and operator_access / RecruitingCaseViewGrant. Backend must own detail projection, field masking, raw-id lookup protection, and branch-scoped access. Status: Backend foundation implemented in backend commit 25aa4f8. The migrated slice adds CaregiverReferralApplicantCaseDetailSource, CaregiverReferralApplicantCaseDetailProjection, and CaregiverReferralApplicantCaseDetailPolicy, reuses existing CaregiverRecruitingCaseScopeGrant, 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-056 Caregiver referral applicant worklist search policy. Legacy DataTable maps browser sort/search columns to broad SQL LIKE over 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 / CaregiverReferralApplicantWorklist and caregiver_management / ReferralApplicantSearchPolicy. Backend must own searchable fields, sort keys, self-referral label, branch scope, PII exposure, and count semantics. Status: Backend foundation implemented in backend commit f3d671b. The migrated slice adds CaregiverReferralApplicantWorklistQuery, ReferralApplicantSearchPolicy, CaregiverReferralApplicantWorklistRow, CaregiverReferralApplicantWorklist, and strict Pydantic payloads. Backend now owns stable search-field and sort-key taxonomy, branch-scoped counts, separate records_total / records_filtered semantics, self-referral label keys, private phone suppression, legacy raw recommendation id suppression, and rejection of source DataTables/raw SQL fields such as PHONE, NAME, MANAGER_RECOMMEND_INDEX, order, search, and branch_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-057 Caregiver referral applicant closure audit. Legacy recommend applicant delete action hard-deletes MANAGER_RECOMMEND_TB by 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 / CloseCaregiverReferralApplicantCase and caregiver_management / RecruitingCaseClosureAudit. Backend must replace hard delete with explicit closure state, reason, idempotency, branch/access guard, and audit trail. Status: Backend foundation implemented in backend commit 8f9cc30. The migrated slice adds CloseCaregiverReferralApplicantCase, RecruitingCaseClosureAuthorization, RecruitingCaseClosureAudit, and CaregiverReferralApplicantCaseClosureDecision; extends recruiting access with close_case; and keeps caregiver-management closure domain independent from operator_access by 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 a physical_delete_performed = false invariant. Public contracts reject legacy raw delete fields such as MANAGER_RECOMMEND_ID_PK, MANAGER_RECOMMEND_INDEX, manager_recommend_index, type, and DELETE. Runtime follow-up: bind DELETE replacement route to typed closure command, store closure audit in Supabase, map CaregiverRecruitingCaseScopeGrant into RecruitingCaseClosureAuthorization, and show closed/tombstone state instead of disappearing deleted rows.

  • SFC-20260706-CUR-058 Caregiver 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 / CaregiverReferralConversionMatch and care_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 implemented in backend commit 86291ca. The migrated slice adds CaregiverReferralConversionMatchCandidate, CaregiverReferralConversionMatch, and CaregiverReferralConversionMatchPolicy in caregiver_management; and ReferralIncentivePolicyPeriod, ReferralIncentivePriorPeriodEvidence, ReferralIncentiveEligibilityRequest, and ReferralIncentiveEligibilityDecision in care_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 as MANAGER_RECOMMEND_ID_PK, RECOMMEND_INDEX, MANAGER_ID, NAME, PHONE, SERVICE_DAY, and INTRODUCE_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-059 Admin 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, and source-refs/sanmopia-admin/application/models/Reservation_model.php:3095-3147. Target: adapters/pricing_settlement/features/caregiver_compensation / SupabaseAdminCaregiverPayoutStatementProjectionStore, pricing_settlement / CaregiverServiceBalanceReceiptActionProjection, and reservation_operations / ReservationSettlementCompletionGateProjection. Backend commit 292f736 adds 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 into SupabaseRow and patches reservation-history export RLS to require an explicit signed-in guard. Backend commit 33db343 adds authenticated GET /admin-caregiver-payout-statement-projections/{reservationBookingId} with Supabase Auth, SpiceDB record_caregiver_payout authorization, 404 for missing projections, and camelCase response aliases. Contract commit 1082f66 publishes AdminCaregiverPayoutStatementProjectionResponse, adminCaregiverPayoutStatementProjectionPath, display-line/service-balance vocabularies, response validation, and generated dist output. Backend commit e973097 adds RequestAdminCaregiverPayoutStatementProjectionRefreshCommand, SupabaseAdminCaregiverPayoutStatementProjectionRefreshRequester, Supabase PGMQ queue sanmopia_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 fresh recorded results. Backend commit 6e3bdfc adds RefreshAdminCaregiverPayoutStatementProjectionHandler, SupabaseAdminCaregiverPayoutStatementProjectionSourceReader, and SupabaseAdminCaregiverPayoutStatementProjectionRefreshProcessor. 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, persists service_balance_closeout_event_id, finalized_charge_snapshot_id, service_occurrence_ledger_key, and service_occurrence_ledger_revision_number on 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 maps SERVICE_BALANCE_FL plus BALANCE_APPROVE_FL into select values require/check/complete; browser posts those strings to /manager, and PHP updates PAYMENT_STATUS_ID_FK, BALANCE_PRICE_PAYMENT_FL, SUB_PAYMENT_STATUS_ID_FK, and SUB_BALANCE_PRICE_PAYMENT_FL before 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, SupabaseRow tests, focused access-control migration tests, rollback SQL syntax checks in the stage DB container, focused API/HTTP/main tests, contract pnpm 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, SettlementCompletionGate E2E proof, branch/HQ settlement projections consuming the same frozen closeout refs, and reservation payout refresh proof through the worker.

  • SFC-20260708-CUR-060 Customer service-balance instruction availability. Legacy customer/pre-reservation detail decides whether to show the direct service-balance action from local PHP time, raw PAYMENT_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-164 states 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, and source-refs/sanmopia_web/static/js/mypage/reservation.js:713-737. Target: pricing_settlement / CustomerDirectServiceBalanceInstructionProjection and reservation_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; added CustomerDirectServiceBalanceInstruction under pricing_settlement with 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 legacy PAYMENT_INFO, 서비스 잔금, PHP time/status fields, and inline account-popup payload keys. Backend follow-up now adds SupabaseCustomerDirectServiceBalanceInstructionProjectionStore plus sanmopia_customer_direct_service_balance_instruction_projections with 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 the customerActorKey; 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 raw PAYMENT_INFO fields. Verification: focused domain/application/adapter/API/HTTP tests, contract pnpm check, ruff, and Tach dependency/interface/external gates. 2026-07-09 runtime follow-up: the browser-created reservation e4314928-0f7e-4a4e-ac29-7190b1ea6f26 closed service balance through POST /reservation-service-balance-closeouts, and the closeout projection producer refreshed sanmopia_customer_service_balance_instruction_projections to availability = available with frozen charge snapshot id, service occurrence ledger key/revision, statement revision key, and rawAccountFieldsVisible=false on 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-061 Customer-visible caregiver account disclosure for direct service-balance payment. Legacy loads main and assistant caregiver bank accounts from MANAGER_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, and source-refs/sanmopia_web/static/js/mypage/reservation.js:695-710. Target: pricing_settlement / ServiceBalancePaymentInstruction and operator_access / CaregiverPaymentAccountDisclosureGrant. Status: Backend API/contract read binding implemented; added the CaregiverPaymentAccountDisclosureGrant policy/contract slice under operator_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 adds SupabaseCaregiverPaymentAccountDisclosureGrantStore, sanmopia_caregiver_payment_account_disclosure_grants, explicit Supabase Data API grants, RLS participant read policy, and authenticated customer route GET /customer-service-balance-caregiver-account-disclosure-grants/{reservationBookingId}. The route joins the backend-owned CustomerDirectServiceBalanceInstructionProjection with the matching grant, evaluates CaregiverPaymentAccountDisclosurePolicy, 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 raw paymentAccountInfo, 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 add GET /customer-service-balance-caregiver-account-disclosure-readiness/{reservationBookingId} with instruction_missing, instruction_unavailable, grant_missing, not_required, and ready states, backend blockingFacts, and rawAccountFieldsVisible=false; the customer UI may call the protected grant endpoint only after readiness is ready, 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 loads sanmopia_caregiver_payout_instructions, validates raw account fields, emits short-lived account snapshot references only, and never exposes account numbers in readiness. Runtime proof on booking e4314928-0f7e-4a4e-ac29-7190b1ea6f26 returned readiness grant_missing with blocker caregiver_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_app now produces an in-memory direct service-balance instruction projection immediately after settlement completion, and the colocated smoke test proves the reservation flow advances from instruction_missing to the safer grant_missing readiness blocker while preserving the frozen mother-visible charge summary after settlement. Playwright proof on booking 2dad8350-e100-4a81-8424-1bdc06b0a465 exercised desktop reservation submit, payment completion, settlement completion, frozen payable invariant, and readiness grant_missing with no console or network response errors. 2026-07-09 account-disclosure proof: dev_smoke_app now wires the same projection producer to an in-memory CaregiverPaymentAccountDisclosureGrant source/store. Playwright proof on booking 966c182e-1da7-40a6-b12d-43ec40f52b15 exercised reservation submit, payment completion, settlement completion, frozen payable invariant, readiness ready, grant response caregiver_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: backend pnpm run supabase:smoke:stage:reservation-to-settlement-completion now also asserts the post-settlement customer account-disclosure readiness projection is resolved, not stale instruction_missing. Latest booking cd5941c4-5ddb-44dc-89c0-03e2433f2e7c completed reservation, payment continuation, settlement, service-balance closeout event 7ef3e74d-9b6b-4036-bfd4-c38411428e2e, and returned readiness not_required with empty blockingFacts for 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 booking b232505e-8dc8-4bed-945f-116739fbc2c2 from request RBQ-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 to settled with mother-visible payable KRW 1,681,519, caregiver payout KRW 500,000, branch settlement KRW 1,181,519, HQ settlement KRW 181,519, and readiness instruction_unavailable. 2026-07-09 correction: backend-repo/scripts/stage_reservation_settlement_e2e.py no longer builds manual branch/HQ ledger lines or defaults caregiver payout to KRW 500,000. Direct stage driver proof booking 27f69a4c-7600-4de1-b611-839d8e757b94 derived caregiver payout 50000 from the frozen charge snapshot, produced branch settlement 100000 and HQ settlement 50000 from backend command producers, reached settled with ledgerLineCount=3, produced the post-settlement account-disclosure projection, and returned readiness not_required with empty blockingFacts. 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, and source-refs/sanmopia_web/static/js/mypage/reservation.js:695-710. Target follow-up: caregiver_assignment / CareTeamAssignmentConfirmed, pricing_settlement / CaregiverCompensationQuoteFinalized, pricing_settlement / CaregiverPayoutInstructionReadinessProjection, and operator_access / CaregiverPaymentAccountDisclosureGrant. Suggested backend feature: IssueCaregiverPayoutInstructionsAfterAssignmentCompensation. 2026-07-09 backend hardening: SupabaseCaregiverPaymentAccountDisclosureGrantSourceReader now reads assigned_caregiver_user_id from 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 become ready, plus frontend popup removal and customer E2E flow. 2026-07-09 backend proof: stage reservation-to-settlement smoke now issues a CaregiverPayoutInstruction through IssueReservationCaregiverPayoutInstructionsHandler and SupabaseReservationCaregiverPayoutInstructionStore, records branch payout deposit acknowledgement through the authenticated backend API, resumes waiting settlement continuation to workflow_started, and then completes settlement with lifecycle lines sourced from the frozen payout instruction instead of a UI-hardcoded caregiver amount. Latest run booking 627ef71f-6e39-4cf4-90d2-a0191b870499 created payout instruction cd899555-7d88-5eaf-9172-b0888a0eeda0, recorded branch deposit acknowledgement, completed settlement, and returned customer account disclosure readiness instruction_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 adds IssueCaregiverPayoutAfterCareTeamAssignmentHandler under pricing_settlement / settlement_continuation. The coordinator reads CareTeamCompensationSource facts, quotes caregiver compensation from backend policy inputs, freezes CaregiverPayoutInstruction rows, maps those frozen instructions to caregiver-payout ledger lines, and advances the reservation financial lifecycle to caregiver_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, calls POST /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 booking 16423898-1c35-4249-b157-d8e9bd61c439 proved the shared candidate snapshot helper with assignment decision stage-assignment-20260709120741107321. Latest reservation-to-settlement smoke booking 85f4383c-e8a8-41bd-92e7-9ffdd943aa59 created payout instruction c18e544c-025e-5fd0-abf0-eea7710b3e56, recorded branch payout deposit acknowledgement, reached settlement continuation wait reason branch settlement ledger lines are not ready, completed settlement, and returned account-disclosure readiness instruction_unavailable. Remaining work: add a backend-owned payout-destination/account revision source reader, remove the stage-only destination fixture, and then prove account disclosure reaches ready from the same normal operator flow. 2026-07-09 payout-destination source follow-up: backend now resolves payout destinations through SupabaseCaregiverPayoutDestinationSource, reading the latest committed sanmopia_caregiver_bank_account_revisions row for each quote-line caregiver profile id and freezing the resulting caregiver_bank_account_revision_key into the payout instruction. Stage setup now seeds the account revision through SupabaseCaregiverBankAccountRevisionStore instead of passing literal bank details into the settlement-continuation command. Latest stage smoke booking d33201b3-d98c-494c-b674-91775a79dd8a created payout instruction 8f65329d-8cf9-551a-b787-a24b4477c677, recorded branch payout deposit acknowledgement, completed the smoke settlement driver, returned branch settlement dashboard rows 26 and line items 1, and still exposed the next blocker honestly as settlement continuation waiting_for_financial_facts with reason branch settlement ledger lines are not ready. 2026-07-09 branch-settlement source follow-up: backend now adds IssueBranchSettlementAfterCaregiverPayoutHandler in the financial-lifecycle application slice. The command reads the frozen financial lifecycle, finalized charge snapshot, caregiver payout ledger, and closeout references, derives a canonical inter_office_branch_share branch-settlement ledger line, and advances the lifecycle through PrepareReservationBranchSettlementCommand. 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 adds IssueHqSettlementAfterBranchSettlementHandler, which reads the same frozen financial lifecycle and finalized charge snapshot, derives the canonical headquarters_platform_fee line 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 booking 521a5051-9825-44e9-bb5a-fd7d84d3981e created payout instruction 13d0fb3d-5a9e-5e68-b833-b8f911316dd2, froze customer payable 150000, settlement deduction 50000, caregiver payout 50000, branch settlement 100000, HQ settlement 50000, lifecycle settled, branch dashboard rows 32, board line items 1, and passed pnpm run supabase:smoke:stage:reservation-to-settlement-completion. Same-day follow-up now treats zero service-balance due as account-disclosure readiness not_required, not instruction_unavailable, and direct driver booking 27f69a4c-7600-4de1-b611-839d8e757b94 proves the browser backend driver uses backend command producers instead of manual branch/HQ ledger payloads. Positive service-balance follow-up booking d137de9d-ebbc-4e90-8b7a-dd3e9d39836c ran the same driver with --service-balance-amount-krw 25000, produced instruction availability available, serviceBalancePaymentInstructionId, disclosure readiness ready, empty blockingFacts, rawAccountFieldsVisible=false, caregiver payout 50000, branch settlement 100000, HQ settlement 50000, lifecycle settled, and ledgerLineCount=3. Browser-created positive-balance proof then exposed a valid zero-HQ-settlement case: booking 89696822-5ff7-470d-a7fc-8b6bca848ef4 came from the Astro reservation-card flow, reached payment workflow completed, ran the backend continuation with --service-balance-amount-krw 25000, issued caregiver payout 1581519, branch settlement 100000, an audited zero-amount headquarters_service_margin HQ line, lifecycle settled, ledgerLineCount=3, instruction availability available, disclosure readiness ready, empty blockingFacts, and rawAccountFieldsVisible=false. Stage booking smoke now builds acceptedPriceCatalogQuote through stage_private_care_price_catalog_quote_payload(), which uses the domain PriceCatalogQuotePolicy over a published stage catalog entry instead of inline booking-script arithmetic. Fresh proof booking 8ac3639b-f5ba-4f8d-8e48-d6239d183fd6 passed booking, positive service-balance settlement, instruction availability available, disclosure readiness ready, and lifecycle settled. Follow-up booking a97c8dfe-566f-4295-a266-3c1fa7ab0553 moved that stage catalog from helper memory into Supabase persistence: stage_care_price_catalog / stage-2026.07 / stage-private-one-week is seeded through sanmopia_price_catalog_import_batches and sanmopia_price_catalog_entries, DB proof shows batch import_status=published, entry service-day count 5, and entry published_at present, and the same booking passed positive service-balance settlement with caregiver payout 50000, branch settlement 100000, HQ settlement 50000, disclosure readiness ready, and lifecycle settled. Wrapper proof 6f95ad57-d702-40fb-bfdb-6637a801c42e also passed supabase:smoke:stage:reservation-to-settlement-completion. Follow-up 2026-07-12 runtime recheck passed pnpm supabase:smoke:stage:reservation-to-settlement-completion on booking c4540bf8-7432-456e-93a2-f5a5d843e110: stage booking, delegated family payment pre-registration, payment continuation, service delivery, caregiver payout, branch/HQ settlement completion, branch dashboard rows 63, board line items 1, zero service-balance readiness not_required, and registered-batch cleanup with SpiceDB cleanup verification. Same-day positive-balance proof pnpm supabase:smoke:stage:reservation-to-settlement-positive-balance on booking 3aedc22f-72e2-4e6b-8fc8-c33e2458a016 passed service-balance amount 25000, instruction availability available, disclosure readiness ready, rawAccountFieldsVisible=false, caregiver payout 50000, branch settlement 100000, HQ settlement 50000, lifecycle settled, 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 applied 20260709145000_payment_product_plan_price_catalog_references.sql, creating payment product catalog v5 with six rows and two explicit price-catalog references: reservation.customer_share.deposit maps to customer_share_deposit, and reservation.customer_share.balance maps to customer_share_balance; both point at care_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-102 Caregiver bank-account revision handoff to payout instructions and disclosure grants. Legacy caregiver and admin profile paths mutate MANAGER_ACCOUNT_TB directly 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, and source-refs/sanmopia-admin/application/models/Reservation_model.php:3216-3233. Current backend gap: pricing_settlement / CaregiverPayoutDestinationChangeAudit records reservation-scoped payout-destination corrections only after a caregiver_payout_instruction_id exists, while operator_access / CaregiverPaymentAccountDisclosureGrant supports revoked_at but has no profile-account revision consumer or grant-revocation command. SupabaseCaregiverPaymentAccountDisclosureGrantSourceReader can issue disclosure grants only from existing sanmopia_caregiver_payout_instructions rows, 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, and operator_access / CaregiverPaymentAccountDisclosureGrantRevocation. Status: Partial. 2026-07-09 backend foundation added caregiver_management / CaregiverBankAccountRevision with expected revision, idempotency, changed-field proof, account evidence references, and a command handler that hands off to operator_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 persists sanmopia_caregiver_bank_account_revisions through a dedicated caregiver_management adapter 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 carry caregiver_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 from instruction_unavailable to ready. Profile writes must not mutate payout instruction rows in place or expose raw account fields to customer/operator projections.

  • SFC-20260709-CUR-103 Reservation-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 posts fdata-type, selected board/detail ids, ftotal-price, ffee-price, fresult-price, and actor login type; Calculate::insertPaymentCentralToBranch accepts those values, updates board/detail/coupon/manual rows, and records insertLog(...); the payment model later flips STATUS_FL for 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, and source-refs/sanmopia-admin/application/models/Payment_model.php:4265-4308. Target: reservation_operations / ReservationStageCapabilityPolicy, operator_access / SettlementApprovalAuthorizationEvidence, pricing_settlement / SettlementStatementApprovalCommand, pricing_settlement / SettlementCompletionProjectionInvalidation, and security_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 adds pricing_settlement / ReservationFinanceTransitionAudit and Supabase table sanmopia_reservation_finance_transition_audits. Runtime proof: browser-started reservation 2a291997-153b-497d-aa2a-5f1e66b8168e reached settled; the audit row froze HQ actor 8ce74a90-125e-4696-9f55-58fcd06801b5, actor_role_code=headquarters_administrator, required_permission=close_reservation_finance, transition hq_settlement_ready -> settled, and backend-derived metadata motherVisiblePayableKrw=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 on sanmopia_admin_caregiver_payout_statement_projections and expose them in the Pydantic API payload as read-only refreshProvenance. Stage proof after this migration created booking 52b16699-260c-4180-972f-03ddd51a62b3, continued payment workflow RPW-STAGE-CONT-20260709091205, closed service balance event bf871eb1-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-104 Settlement 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, and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4121-4198. Target: document_reporting / IntegratedReservationDocumentBundleRequest, document_reporting / DocumentBundleEligibilityPolicy, document_reporting / DocumentBundleArtifactBuild, operator_access / DocumentBundleDownloadGrant, and migration_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.

AreaExisting owner row(s)Implementation/proof status after miningAdditional source evidence
Family/proxy booking, payer, notification, and document authorityHigh-level family authority rows P0 / Family, proxy payer, contact, refund, and document authority, ReservationPartyAuthoritySnapshot, and DocumentRecipientAuthorityPartial. 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 grantsSFC-20260708-CUR-097, document rows P1 / StoredPrintableDocumentArtifact, PrintableDocumentAccessGrant, DocumentCenterProjection, and ReservationDocumentDeliveryPartial. 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 proofSFC-20260708-CUR-089, CaregiverCandidateOrderingPolicy, CaregiverCandidateSelectionToken, and payout invalidation rowsPartial. 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 compensationPaymentProviderHandoffSession, PaymentProviderApprovalRequest, PaymentProviderCloseoutCompensationSaga, CustomerPaymentInstruction, PaymentProviderAttempt, CompensationRefundIntent, ProviderRefundExecutionAttempt, PaymentCloseoutRepairCase, ProviderRefundResultEvent, and PaymentCloseoutReportingInvalidationBackend 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 guardRecordProviderPaymentCloseoutCommand, RecordPreReservationPaymentCloseoutCommand, PaymentProviderAttempt, OperatorPaymentFactEditCommand, RecordReservationPaymentReceiptCommand, PaymentCloseoutRepairCase, and ProviderRefundResultEventBackend 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 activationPaymentCloseoutNotificationOutbox, ReservationDocumentReadinessLifecycle, ReservationDocumentReadinessRevocationAfterPaymentRepair, DocumentCenterProjectionInvalidationAfterRefund, PaymentCommunicationWorkflow, and DocumentRecipientAuthorityPartial; 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 materializationMaterializeReservationServiceOccurrenceLedgerCommand, PaymentCloseoutOccurrenceLedgerGuard, ServiceOccurrenceLedger, ReservationPaymentWorkflow, ReservationDateMaterializationPolicy, and SettlementContinuationPrerequisitePartial; 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 compatibilityPreReservationConversionStateProjection, PreReservationConversionPaymentCompatibility, ReservationPriceVersionAdjustment, and CancellationRefundEligibilityPartial; 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 backfillStoppedReservationSettlementSeedBackfillCommand, SettlementStatementSeedDecision, ReservationCancellationSettlementImpact, SettlementSeedRepairAudit, and ReservationFinancialLifecycleSeedRepairMapped; 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 raceVirtualAccountPaymentLifecycle, PaymentVirtualAccountInstructionPayload, PaymentVirtualAccountInstructionSnapshot, PaymentProviderNotificationDeduplication, and VirtualAccountDepositReservationTransitionBackend 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 expiryVirtualAccountExpiryScheduler, VirtualAccountExpiryTransitionCommand, ExpiredVirtualAccountDepositRaceDecision, ReservationStateTransitionAudit, and PaymentCommunicationWorkflowMissing 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 provenanceSFC-20260709-CUR-103, SettlementStatementApprovalCommand, SettlementBoardMutationProvenanceImport, SettlementTransitionAudit, SettlementLineAcknowledgement, SettlementStatementDatasetRevision, and SettlementStatementManualAdjustmentLineCommandPartial; 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 replaySFC-20260709-CUR-103, SFC-20260708-CUR-088, SettlementLineAcknowledgement, SettlementComponentReadinessProjection, HeadquartersSettlementCloseoutReadinessProjection, SettlementComponentReadinessInvalidationAfterPaymentRepair, and SettlementBoardRepairReadinessRefreshPartial; 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 impactRecordProviderRefundResultCommand, ProviderRefundPaidRowTransition, PartialPaymentRefund, PaymentRefundIntent, ProviderPartialRefundCapabilitySnapshot, SettlementRefundImpactProjection, SettlementLedgerReversalLine, and SettlementStatementInvalidationAfterRefundPartial; 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 catalogSFC-20260708-CUR-088, SettlementAdjustmentLineCommand, SettlementAdjustmentCatalogRevision, SettlementManualDiscountSurchargePolicy, and RegionalBenefitSettlementImpactSnapshotPartial; 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 grantsSFC-20260708-CUR-088, SFC-20260708-CUR-098, SFC-20260709-CUR-103, SettlementArchiveRequest, SettlementStatementDatasetRevision, SettlementArtifactGrant, and SettlementArtifactBuildRunLedgerPartial; 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 1a6a7cc closes the runtime-processor-binding gap for export-artifact refresh by routing the provider-refund reporting queue into the concrete branch settlement export refresh handler. Backend d478bdb extends that runtime path with a dispatcher and backend read-model refresh validation for branch/HQ settlement statement plus branch/HQ operator-board targets. Backend 4bd75d6 routes sales-dashboard refresh messages through a backend validation handler that resolves payment to branch/reservation and requires a matching sales_overview snapshot before marking the invalidation refreshed. Backend c1e0904 makes data-room request_repair supersede the active artifact immediately and persist supersession reason/artifact id through the Supabase data-room request RPC. Backend 3e6d83f adds workspace-domain and contract proof that repair revokes active artifact grants and records the replacement artifact request code. The internal POST /internal/payment-refund-repairs/provider-refund-plans route 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 6120324 adds ProviderRefundResultFromLedgerHandler, 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 31e5d83 removes invented PAYMENT_REFUNDED, PAYMENT_VOIDED, PAYMENT_PENDING, nested data, tenantApiKey, and cancellation-id callback semantics. The callback ACL now accepts official objectType=PAYMENT events, uses objectId as payment id, and parses JSON metaData for paymentTransactionId, transactionType, status, amount, currency, and effectiveDate. PURCHASE/CAPTURE success starts paid verification, REFUND success/failure enters the ledger-backed provider-result recorder, and VOID success synchronizes cancellation. Missing refund-result recorder now fails closed; no legacy status-sync fallback remains. Supabase migration 20260710220000_killbill_ext_bus_payment_events.sql replaces 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 one sanmopia_payment_webhook_processing message, processed one message without retry/dead-letter, and persisted a killbill_ext_bus_event_v1 row with PURCHASE, SUCCESS, 180000, and KRW. The nonexistent probe payment was safely recorded as ignored. An invented legacy PAYMENT_REFUNDED payload was rejected with 400. 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 072b2e0 derives stable event identity from tenant, event, payment, transaction, operation, and effective time; canonicalizes JSON and metadata before hashing payload; and calls sanmopia_register_killbill_payment_event_inbox. Stage accepted the first delivery as queued, treated whitespace/key-order replay as duplicate, and treated the same identity with a changed amount as quarantined. Four HTTP deliveries produced one PGMQ message and one worker execution. The canonical row kept amount 181000, 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 f391565 records provider refund paid-row transition decisions through sanmopia_record_provider_refund_paid_row_transition_decision, not a loose Data API upsert. The Supabase RPC inserts the provider-result decision and advances sanmopia_payment_records.payment_status plus payment_fact_revision under the expected revision guard. It maps provider-domain partially_refunded to persisted partial_refunded, adds full-refund refunded, and restricts function execute access to service_role.

  • 2026-07-10 provider refund internal runtime proof: stage smoke scripts/supabase_stage_provider_refund_paid_row_transition_smoke.sh now 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-preserving partial_refunded constraints, and settlement reversal-line persistence. The smoke now also verifies the six provider-refund reporting invalidation rows and refresh_requested queue 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-impact composes the same refund proof after a real positive-balance reservation is settled; 2026-07-12 proof booking 6a619c99-5fcf-446b-8f30-8fd03b835636 reached settled with service-balance amount 25000, disclosure readiness ready, branch settlement 100000, and HQ settlement 50000, then refund event stage-provider-refund-result-20260712121644-1a6e3fa1 for payment stage-provider-refund-payment-20260712121644-1a6e3fa1 produced paid-row mutation, settlement reversal, reporting refresh fanout, and registered refund batch cleanup. The provider-refund smoke wrapper now reaps its sanmopia_test_data_batches / sanmopia_test_data_references batch just like reservation settlement smokes. See ADR-027. Remaining refund workflow gates are external Kill Bill provider-webhook E2E once stage KILLBILL_* 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. Backend 3e6d83f already proves the workspace-domain and contract-level repair revocation behavior.

  • 2026-07-10 refinement for refund settlement dataset selection authority: ef0dade covers 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, and SettlementCouponComponentRefreshAfterDeletion. 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 to 2), 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), and source-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 impact owner: 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), and source-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 idempotent PaymentRefundIntent and 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 remains Partial: 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, and SettlementComponentAmountSnapshot. 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-062 Customer 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, and source-refs/sanmopia_web/application/views/mypage/reservation.php:149-160. Target: pricing_settlement / CustomerServiceBalanceReceiptProgressProjection and customer_engagement / CustomerReservationCardFinancialBadge. Status: Backend API/contract read binding plus receipt producer implemented; added CustomerServiceBalanceReceiptProgressProjection under pricing_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 adds SupabaseCustomerServiceBalanceReceiptProgressProjectionStore, sanmopia_customer_service_balance_receipt_progress_projections, explicit Supabase Data API grants, RLS participant read policy, realtime publication, and authenticated customer route GET /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 manual service_balance receipt recording, CloseReservationServiceBalanceHandler closeout storage, and ManageCaregiverPayoutReceiptStateHandler receipt-state changes to ProduceCustomerServiceBalanceReceiptProgressProjectionHandler, which reads direct service-balance instruction rows when present, falls back to reservation_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 raw STATUS_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-063 Service-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 type DEPOSIT_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, and source-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, and source-refs/sanmopia_web/application/models/Notification_model.php:42-52 show push links are optional and inbox rows are type-only when no target data is supplied; the service-balance reminder inserts DEPOSIT_SERVICE_FEE without reservation or instruction identity. Target: customer_engagement / ServiceBalancePaymentReminderPolicy and pricing_settlement / ServiceBalancePaymentInstruction. Status: Backend foundation implemented; added ServiceBalancePaymentReminderPolicy under customer_engagement and a contract that builds a PlanPaymentCommunicationDispatchCommand for 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. Legacy PAYMENT_* 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-064 Branch/HQ membership-due acknowledgement default. Legacy central-to-branch settlement form hardcodes fmembership-pay-status-fl = 1 in both admin and branch browser paths because the membership checkbox was not implemented, and the controller persists that browser value onto BOARD_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, and source-refs/sanmopia-admin/application/controllers/Calculate.php:296-302. Target: pricing_settlement / SettlementLineAcknowledgement and pricing_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-065 Booking service-term side-effect assembly. Legacy booking creation collects extra Saturday/holiday selections, Wanju benefit choice, add-option quantities, UI end-date previews, and RESERVATION_DATE_INSERT_FN calls 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, runs RESERVATION_DATE_INSERT_FN, then writes RESERVATION_ADD_DATE and add-option rows. Report consumers later choose printable service occurrences from RESERVATION_DATE_TB plus weekend/HOLIDAY_TB exclusions, 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, and source-refs/sanmopia_web/application/models/Report_model.php:451-466. Target: reservation_operations / BookingServiceTermCreationCommand, service_calendar / ReservationServiceOccurrenceLedger, pricing_settlement / ReservationServiceCalendarQuote, and care_delivery / ServiceOccurrenceEvidence. Status: Partial; service-term plan and occurrence-ledger foundations exist, and 2026-07-07 stage smoke RBQ-STAGE-20260707153322 proved 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 added BookingServiceTermSideEffectAssemblyPayload and assemble_booking_service_term_side_effects() in reservation_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 as addDateArray, END_DT, RESERVATION_DATE_INSERT_FN, and wanjuOptionId are 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, emits booking_service_term_side_effects_assembled, and saves through a dedicated BookingServiceTermSideEffectAssemblyStore port when an adapter is supplied. Contract repo now documents acceptedServiceTermPlan plus bookingServiceTermSideEffects in the workflow start JSON Schema, TS client, and Python Pydantic contracts, including the corrected branchActor.actorUserId field. 2026-07-08 second follow-up added a Supabase persistence adapter and migration for sanmopia_booking_service_term_side_effect_assemblies plus sanmopia_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 assembly bookingRequestId, plus OpenAPI, TS client, Python Pydantic, and Starlight generated API coverage for immutable assembly reads. Restate workflow response already carries bookingServiceTermSideEffectAssemblyKey. 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 in sanmopia_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 added ExecuteBookingServiceTermProjectionInvalidationsHandler, strict Pydantic work-item and execution-receipt payloads, consumer/worker repository ports, Supabase service-role RPC claiming with FOR UPDATE SKIP LOCKED, completed-receipt, and failed-error updates, plus outbox audit columns last_execution_receipt, last_execution_error_code, last_execution_error_message, and last_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 in sanmopia_daily_report_projection_invalidations with service-role-only Supabase access, source impact fact keys, target reference, reason code, assembly snapshot key, and idempotent invalidation_key upsert. 2026-07-08 seventh follow-up (backend 576f04c) bound the payout-side consumer: pricing_settlement / CaregiverPayoutProjectionInvalidationConsumer maps caregiver_payout_projection work items into RequestAdminCaregiverPayoutStatementProjectionRefreshCommand, adds the semantic booking_service_term_changed trigger, uses the existing sanmopia_admin_payout_projection_refresh durable 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 / SettlementProjectionInvalidationConsumer records settlement_projection invalidation receipts in sanmopia_settlement_projection_invalidations with service-role-only Supabase access, source impact fact keys, target reference, reason code, assembly snapshot key, and idempotent invalidation_key upsert. 2026-07-08 ninth follow-up (backend c72b0db) bound the service-calendar consumer: reservation_operations / ServiceCalendarProjectionInvalidationConsumer records service_calendar_projection invalidation receipts in sanmopia_service_calendar_projection_invalidations, adds service_calendar to the required service-term consumer contexts, emits the third outbox row from booking workflow fixtures, and renames the generic missing-consumer blocked reason to required_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, registers booking_service_term_projection_invalidation_execution as a standard Supabase PGMQ workload, creates sanmopia_booking_service_term_projection_invalidation_execution plus 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 / DailyReportProjectionInvalidationConsumer for report-date and final-report selections from source-refs/sanmopia_web/application/models/Report_model.php:312-391 and source-refs/sanmopia_web/application/models/Report_model.php:439-518; care_delivery / CustomerDailyReportCompletionRewardProjection for the report-completion coupon/point comparison at source-refs/sanmopia_web/application/models/Report_model.php:553-620; care_delivery / CaregiverReportObligationProjection for notification and service-record duty scans from source-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, and source-refs/sanmopia-manager/application/models/User_model.php:2070-2106; pricing_settlement / BranchToHeadquartersSettlementProjection and GiftCouponSettlementPeriodProjection for service-start/end settlement buckets from source-refs/sanmopia-admin/application/models/Payment_model.php:3483-3563 and source-refs/sanmopia-admin/application/models/Payment_model.php:3565-3641; pricing_settlement / SettlementCollectionSummaryProjection for board totals/status and UI-posted amount distrust from source-refs/sanmopia-admin/application/models/Payment_model.php:1750-1960, source-refs/sanmopia-admin/application/controllers/Calculate.php:150-313, and source-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 / CaregiverPayoutStatementProjection for service-day, extra-option, custom-balance, and tax-sensitive payout math from source-refs/sanmopia-manager/application/helpers/salary_helper.php:67-145 and source-refs/sanmopia-manager/application/helpers/salary_helper.php:147-214 (backend now queues this projection refresh from service-term invalidation work items); service_calendar / ReservationCalendarProjection plus ReservationServiceOccurrenceBoundaryProjection for calendar display and first/last occurrence boundaries from source-refs/sanmopia-admin/application/controllers/Reservation.php:609-647, source-refs/sanmopia-admin/application/views/reservation_status/reservation_calendar.php:61-110, and source-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 / CaregiverAttendanceServiceOccurrenceProjection for additional-day attendance eligibility and attendance repair from source-refs/sanmopia-manager/application/models/Attendance_model.php:18-49 and source-refs/sanmopia-admin/application/models/Manager_model.php:2498-2525; and care_delivery / CaregiverAssignmentAvailabilityProjection for service-term-dependent matching availability from source-refs/sanmopia-admin/application/models/Matching_model.php:44-145, source-refs/sanmopia_web/application/models/Manager_matching_model.php:166-228, and source-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/delete HOLIDAY_TB, and the browser posts holiday-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, and source-refs/sanmopia-admin/static/js/manage_system/holiday_list.js:18-107. Desired abstraction: service_calendar / ServiceTermOccurrenceRegenerationPolicy, service_calendar / HolidayClosureRevisionCommand, and service_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 backend 56413fe hardens revision-level occurrence lineage: service_occurrence_ledger_key and service_occurrence_ledger_revision are 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 uses NO 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, and backend-repo/supabase/migrations/20260710193000_booking_service_term_add_option_revision_immutability.sql:1-74. Stage reservation eeef7782-aff2-4065-bf9c-7ab48f7fd629 reached settled. Migration traps/debt remain owned by this SFC-20260708-CUR-065 item:

    UI/calculation-derived quantity basis. Legacy browser code counts rendered Saturday/holiday elements, multiplies child/family and added-hour selections by getServiceDay(), and totals DOM data-price values at source-refs/sanmopia_web/static/js/step3.js:477-560 and :613-832. The getServiceDay() selectors at :616-617 even omit the class prefix used by .saturday-item/.holiday-item elsewhere. PHP then converts posted date-array counts into option quantities at source-refs/sanmopia_web/application/controllers/api/Service.php:358-414 and :476-524. Backend 4f7bebf typed quantity_basis is still a caller assertion: the stage fixture supplies added_service_day plus extra/saturday/1 directly at backend-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_links and per-link quantity/evidence detail remain JSONB at backend-repo/supabase/migrations/20260710152000_booking_service_term_add_option_selection_revisions.sql:17-38; the reader reloads only revision_snapshot at backend-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 weakening 56413fe replay/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 PRICE and paid state at source-refs/sanmopia-admin/application/models/Reservation_model.php:1566-1652. Admin reservation/document reads also rebuild PRICE_TABLE from current add-option rows at source-refs/sanmopia-admin/application/models/Reservation_model.php:194-229 and :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-066 Positive-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, then updateBoardForCentralToBranch() drops every 0 value before updating BOARD_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), and source-refs/sanmopia-admin/application/models/Payment_model.php:4382-4419. Target: pricing_settlement / SettlementComponentAcknowledgementCommand, pricing_settlement / SettlementLineAcknowledgement, and operator_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 include SettlementComponentAcknowledgementCommandPayload, which requires explicit paid, unpaid, or partially_paid decisions with expected board revision, per-line revision, evidence keys, and paid/unpaid amounts. Legacy positive-only form fields such as fis-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 exposes POST /settlement-component-acknowledgements, authorizes the actor through SpiceDB sanmopia/branch_settlement#review, records line-decision rows in sanmopia_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-067 Reservation lifecycle schedule financial seed. Legacy cron advances reservations from confirmed or extension to in-progress on SERVICE_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 from type=payment or type=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, and source-refs/sanmopia-manager/application/models/Reservation_model.php:351-410. Additional completion-gate evidence: source-refs/sanmopia-admin/application/models/Reservation_model.php:2945-3041 and source-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 backend ReservationFinanceSettlementCompletionGate over 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, and pricing_settlement / CaregiverPayoutAcknowledgementPrerequisite. Status: foundation; backend commit 93c5639 adds ReservationLifecycleFinancialSeedPlanner and strict Pydantic PlanReservationLifecycleFinancialSeedPayload contract. 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 as SERVICE_START_DT, SERVICE_END_DT, RESERVATION_STATUS_LIST_ID_FK, SERVICE_BALANCE_CONFIRM_FL, STATUS_FL, service_type, type=payment, and type=sub_payment are 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 commit c91bf82 adds ReservationLifecycleFinancialSeedScheduler, 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 commit fb7cb70 binds that scheduler to Supabase by adding SupabaseReservationLifecycleFinancialSeedSchedulerStore, 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 no authenticated grants. 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 through pnpm exec supabase; local migration lint remains blocked by local Postgres connectivity with LegacyDbConnectError ... Failed to connect, so migration replay/typegen must run after the self-hosted local or stage Supabase database is reachable. Backend commit b8aa09d wires the scheduler into the runtime composition root with backend-only HTTP endpoint POST /internal/reservation-lifecycle-financial-seed-scheduler-runs. The route requires SANMOPIA_INTERNAL_JOB_TOKEN, defaults planningOn from the backend clock, derives a stable daily schedulerRunKey when omitted, and runs ReservationLifecycleFinancialSeedScheduler against the Supabase prerequisite/plan store. This moves the slice to runtime_wired for the scheduler trigger only; it remains not e2e_proven because 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. Once ServiceDeliveryCompletionFact exists, 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, string service_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: SettlementSeedInstruction persistence for branch/HQ rows, ServiceDeliveryCompletionFact producer for service-end-minus-two-days readiness, CaregiverPayoutSeedInstruction persistence for salary and service-balance slots, ZeroServiceBalanceAutoCloseoutProducer with explicit evidence, ReservationFinanceSettlementCompletionGate to replace raw unpaid payment-row counts, BranchHeadquartersSettlementPrerequisiteSnapshot for other-area/voucher/current-row readiness, and CaregiverPayoutAcknowledgementPrerequisite to replace caregiver portal type=payment / type=sub_payment mutation. Suggested backend feature: SettlementSeedInstructionPersistence.

  • SFC-20260708-CUR-068 Daily-report request dispatch occurrence eligibility. Legacy FCM sends daily-report requests to customers by scanning RESERVATION_DETAIL_VW for raw statuses 진행, 정산, and 완료, checking SERVICE_START_DT <= now <= SERVICE_END_DT, and splitting recipients with string rules for live-in versus non-live-in service type. It writes INPUT_DAILY_REPORT notifications 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-130 and source-refs/sanmopia_web/application/views/test/pushtest.php:10-11. Dispatch-shape evidence: source-refs/sanmopia_web/application/models/Fcm_model.php:32-56 and source-refs/sanmopia_web/application/models/Notification_model.php:40-52 show 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, and service_calendar / ServiceOccurrenceReminderEligibility. Status: Backend foundation: 5a46c0f. Backend now adds DailyReportRequestDispatchPolicy, DailyReportRequestDispatchCandidate, CustomerDailyReportRecipientSnapshot, DailyReportRequestDispatchInstruction, and the ScheduleDailyReportRequestDispatches Pydantic 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, and INPUT_DAILY_REPORT fields 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-069 Voucher customer-share balance reminder eligibility. Legacy FCM sends a voucher customer-share balance reminder two days before SERVICE_START_DT, selecting unpaid 본인부담 잔금 payment rows, excluding cancelled reservations, and pushing a hardcoded proceeding-detail route plus PAY_VOUCHER_BALANCE notification. This is distinct from SFC-063 service balance reminder, which uses end-date minus one day and DEPOSIT_SERVICE_FEE. Evidence: source-refs/sanmopia_web/application/controllers/cli/Fcm.php:133-163 and source-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, and source-refs/sanmopia_web/application/models/Notification_model.php:42-52 show the push link and inbox notification can diverge; PAY_VOUCHER_BALANCE is inserted without reservation, payment-row, or instruction identity. Target: pricing_settlement / CustomerShareBalanceInstruction, customer_engagement / CustomerShareBalanceReminderPolicy, and reservation_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, or DATE_ADD(CURDATE(), INTERVAL 2 DAY) comparisons. Backend slice needs IssueCustomerShareBalanceReminder command, CustomerShareBalanceReminderEligibilityProjection query/read model, and CustomerShareBalanceReminderDispatchStore persistence 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 at source-refs/sanmopia_web/application/views/test/pushtest.php:12-13 only triggered the cron path manually. Suggested backend feature: CustomerShareBalanceReminderPolicy.

  • SFC-20260708-CUR-070 Caregiver report and service-record obligation dispatch. Legacy manager cron derives caregiver daily-report and service-record obligations by scanning RESERVATION_DETAIL_VW, RESERVATION_DATE_TB, mutable service start/end dates, and hardcoded source statuses 0/3/4/5/6/11/12, with stopped status 13 explicitly 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 raw REPORT_FIRST, REPORT_PROGRESS, REPORT_LAST, and SERVICE type 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, and source-refs/sanmopia-manager/application/models/User_model.php:2184-2202. Target: care_delivery / CaregiverReportObligation, care_delivery / ServiceRecordObligation, and customer_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 needs GenerateCaregiverObligationDispatches command, CaregiverObligationEligibilityProjection query/read model, CaregiverObligationNotificationStore, CaregiverObligationDispatchAttemptLedger, and CaregiverObligationRepairCommand. Legacy manual repair finds missing obligations by joining MANAGER_NOTIFY_TB on 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-071 Caregiver attendance reminder and attendance-open side effect. Legacy manager FCM sends an attendance prompt by selecting today’s rows from RESERVATION_DATE_TB for reservation statuses [4, 5, 6], then sends a fixed “press attendance” message. Separately, reading a notify row can create a MANAGER_ATTENDANCE_TB record for the primary caregiver and also insert one for the assistant caregiver, using the notify CREATED_DT date 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, and source-refs/sanmopia-manager/static/js/attendance.js:7-30. Target: care_delivery / CaregiverAttendanceObligation, service_calendar / ServiceOccurrenceAttendanceEligibility, and customer_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 or RESERVATION_DATE_TB scans. Backend slice needs GetCaregiverAttendanceActionProjection query, RecordCaregiverAttendanceCommand, CaregiverAttendanceFactStore, and CustomerAttendanceSafetyNotificationOutbox persistence. Legacy PHP UI did perform a business decision: the manager home view rendered open/complete attendance buttons from READ_FL, attendance-row presence, and a hardcoded 2020-06-01 gate, while browser JavaScript posted raw reservationId and 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-072 Caregiver daily-report submission completion. Legacy manager report entry checks login, source notify ownership, unread MANAGER_NOTIFY_TB.READ_FL, and a route type string, then chooses question rows by Korean day labels 첫째날, 진행중, or 마지막날. Save writes objective answers to MANAGER_REPORT_TB, essay answers to MANAGER_REPORT_ANSWER_ETC_TB, and marks notify read, which can also trigger attendance side effects through Notify_model::updateReadNotify(). Evidence: source-refs/sanmopia-manager/application/controllers/Report.php:5-59, source-refs/sanmopia-manager/application/controllers/Report.php:63-106, and source-refs/sanmopia-manager/application/models/Report_model.php:11-100. Target: care_delivery / DailyCareReportSubmission, care_delivery / CaregiverReportQuestionSetVersion, and customer_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, or READ_FL. Suggested backend feature: DailyCareReportSubmissionCommand.

  • SFC-20260708-CUR-073 Caregiver 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 to MANAGER_SUB_SERVICE_TB, while schedule readers look for SUB_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, and source-refs/sanmopia-manager/application/models/Reservation_model.php:539-554. Target: care_delivery / CaregiverServiceRecordSubmission, care_delivery / ServiceRecordDuplicateDecision, member_management / NewbornProfileBootstrapFromCareRecord, and customer_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-074 Caregiver 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 id 1, 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, and source-refs/sanmopia-manager/application/models/Reservation_model.php:222-238. Target: care_delivery / CaregiverWorkActionProjection, care_delivery / CaregiverAssignmentAccessWindow, and customer_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-075 Caregiver 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 only MANAGER_ID_FK plus DATE(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, and source-refs/sanmopia-manager/static/js/attendance.js:7-35. Target: care_delivery / CaregiverAttendanceCheckInCommand and customer_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-076 Caregiver attendance action projection. Legacy home view decides whether attendance is open, completed, or hidden from a hardcoded date cutoff, READ_FL, notify rows, and RESERVATION_ADD_DATE fallback reads. Evidence: source-refs/sanmopia-manager/application/views/home/main.php:59-80, source-refs/sanmopia-manager/application/views/home/main.php:205-220, and source-refs/sanmopia-manager/application/models/Attendance_model.php:18-89. Target: care_delivery / CaregiverAttendanceActionProjection and service_calendar / AttendanceEligibleOccurrence. Status: Partial; backend now has a typed CaregiverAttendanceActionProjection with 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-077 Caregiver notification recipient projection and actor-scoped inbox access. Legacy unread inbox joins only primary rt.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 raw NOTIFY_TYPE plus 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, and source-refs/sanmopia-manager/application/controllers/Service.php:238-246. Target: customer_engagement / CaregiverNotificationRecipientProjection and operator_access / CaregiverNotificationAccessDecision. Status: Partial; backend now has actor-scoped CaregiverNotificationRecipientProjection, actor-bound read-state command, revision guard, and a notification_read_state_only side-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-078 Push delivery attempt and recipient consent snapshot. Legacy FCM sender chooses tokens inline, can bypass PUSH_FL by passing pushFlag=null, builds links through site_url(), and returns raw provider responses without durable attempt state. Link composition strips and prepends site_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, and source-refs/sanmopia-manager/application/models/User_model.php:2281-2300. Target: communication_delivery / PushDeliveryAttempt and customer_engagement / RecipientPushConsentSnapshot. Status: Partial; backend now has RecipientPushConsentSnapshot, PushDeliveryAttempt, provider response facts, suppression reasons for disabled consent and missing endpoint, and application contracts that reject raw token/PUSH_FL spillover. 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-079 Coupon 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 status 13, and delete/refund buttons call KCP through raw PAYMENT_CONTEXT before flipping REFUND_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, and source-refs/sanmopia-admin/application/controllers/Api.php:11-29. Target: promotion_entitlement / CouponUseStatusProjection and pricing_settlement / CouponDeletionRefundCommand. Status: Partial; backend now has semantic coupon publication/consumption states, CouponUseStatusProjection, stopped-reservation status reason, provider-neutral CouponDeletionRefundPlan, 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, and DELETE_FL. 2026-07-08 backend bridge: CouponDeletionPaymentRefundHandoffPayload now converts the coupon deletion refund plan into the shared PaymentRefundIntentPayload with partial refund scope, admin requester, payment expected revision, adjustment catalog version, refund amount, cancellation gate, and source evidence keys. The same change promoted generic PaymentRefundIntentPayload so 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: legacy deleteCoupon() decodes coupon PAYMENT_CONTEXT, calls KCP refund, writes REFUND_FL = 1 before 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-186 and source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31-60.

  • SFC-20260708-CUR-080 Product-gift coupon redemption and fulfillment command. Legacy customer shop UI uses a hidden product-coupon id and -1 sentinel for “no usable coupon”, posts raw product/coupon/recipient/address fields, then PHP checks ownership, PUBLISH_DT, and USE_FL before inserting a PRODUCT_APPLY_TB row and flipping USER_COUPON_TB.USE_FL. The duplicate product-application check by PRODUCT_APPLY_TB.USER_COUPON_ID_FK exists 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, and source-refs/sanmopia_web/application/models/Product_model.php:40-79. Target: promotion_entitlement / ProductGiftRedemptionCommand, promotion_entitlement / ProductGiftFulfillmentRequest, and communication_delivery / ProductGiftFulfillmentDispatchRequest. Status: Partially implemented; backend now has ProductGiftRedemptionCommand, RedeemProductGiftHandler, typed ProductGiftRedemptionDecision, and Pydantic contract rejection for USER_COUPON_ID_FK, PRODUCT_ID, PRODUCT1/PRODUCT2, USE_FL, PUBLISH_DT, and -1-sentinel legacy coupon authority. The command delegates to GiftFulfillmentPolicy, 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 stores sanmopia_product_gift_redemption_decisions as 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-081 Product-gift coupon publication grant and dispatch workload. Legacy publication is separate from product-gift redemption: a CLI route scans product coupons, ignores their stored PUBLISH_DT, derives publication from service-start day 15, excludes raw reservation status ids, inserts USER_COUPON_TB with 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, and source-refs/sanmopia_web/application/models/Coupon_model.php:608-620. Target: promotion_entitlement / ProductGiftCouponPublicationGrant, promotion_entitlement / ProductGiftCouponPublicationProjection, and communication_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-082 Customer 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, seeds RESERVATION_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 a smart_matching route flag. The final review hides selected manager and coupon ids in form fields, displays pre-reservation credit, and the apply API chooses 상담/연장요청/payment handoff from CONSULTING_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, and source-refs/sanmopia_web/application/views/service/pre_reservation_payment.php:123-142. Target: reservation_operations / CustomerReservationCreationCommand, ReservationDraftStepAuthorityProjection, ReservationDraftSupersessionPolicy, and ReservationCreationPaymentHandoff; reservation_catalog / ReservationServiceOfferingAvailabilityPolicy; pricing_settlement / ReservationCreationChargeSnapshotHandoff; and caregiver_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, local data-price totals, 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 from SFC-20260708-CUR-080 and SFC-20260708-CUR-081, which cover product-gift entitlement redemption/publication rather than reservation creation.

    2026-07-13 backend authority hardening: backend be107c7 adds a forward-only migration that revokes every authenticated table privilege on sanmopia_reservation_bookings and sanmopia_reservation_booking_workflow_requests, drops the mother/branch create, update, and participant-read policies, and leaves CRUD to service_role. Cross-repository audit found no frontend Data API consumer for either table and no client consumer for raw workflow command_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 76b779b defines 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. Backend 4fce929, 9cf8718, and corrected-contract follow-up e78a3bf adds 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. Frontend 4288924 plus corrected-contract follow-up 421fc03 binds 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. Backend 21ecac5 adds 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. Backend 0d78806 closes legacy applicant and care-environment partial-shape bypasses; ae98940 adds 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 harness b460d84 records desktop and mobile 12-frame animated WebPs plus edit invalidation, 409 refresh, 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 558510d replaces 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 1200f42 adds an exact 26-binding registry and an immutable, service-role-only contribution inbox, but registers only service_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 stays Partially implemented.

    2026-07-14 catalog materializer prerequisites: backend 83ac5b8 fixes a lossy boundary before any exact-26 materializer is allowed. The contribution adapter, expanded RPC, and immutable table now preserve catalog authority_reference and positive authority_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. Direct service_role insert/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 2c744fb adds an immutable normalized VoucherPlanCatalogRevisionSnapshot authority, exact revision source/publisher ports, Supabase adapters, producer registration, and named reservation orchestration for service_schedule.voucher_service_days. Legacy order comes only from the slash-delimited SERVICE_DAY_LIST token positions; SQL encounter order and workbook row_number are never substituted. One option is deliberately normalized to standard; 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 parent 83ac5b8. No trusted trigger/population, exact-26 materializer, stage mutation, or browser artifact exists, so the item remains Partially implemented and 24 catalog producers remain.

    2026-07-14 completed source and atomic population authority: backend c1937ed198005ce2307dfefc4e77d882aa98abc0 adds 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, explicit benefit_band_code -> benefit_band, and each day token -> service_day_count; no consume_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 no latest fallback. 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. At c1937ed, 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 stays Partially implemented.

    Backend b44fd49e9f3082d4affa005ecfa76128136f0804 removes 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 7a9d26e1c1c53b928e14504cfd37152294f9a31f adds the protected HQ approved-source completion caller. Active bearer actor and SpiceDB manage on hq_settlement:price_catalog_management are 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 / 0 was not auto-selected, and no stage/browser/visual evidence was produced. The item remains Partially implemented with canonical resolver, draft trigger, 24 producers, exact-26/final-review materialization, payable, and A-Z gaps.

    2026-07-15 exact-26 materializer evidence: backend 20a79e30e36c6693002c65f8211275afbe149310 adds MaterializeCustomerReservationStepOptionCatalogSnapshotHandler, the strict SupabaseCustomerReservationStepCatalogContributionSetSource and SupabaseCustomerReservationStepCatalogSnapshotMaterializer, and production runtime composition. Migration 20260715090000_customer_reservation_step_catalog_exact_set_materializer.sql adds 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 reports 193 passed; a narrower integrated materializer run reports 38 passed, with Ruff and git diff --check passing. Migration/SSOT contracts report 14 passed. The rollback-scoped isolated Supabase PostgreSQL 17 smoke proves exact-25 atomic failure, exact-26 persistence and replay, stale CAS 40001, lineageless and invalid/expired latest-row rejection, canonical hashes, RLS, and RPC-only ACL. The item remains Partially 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 863158c743e2bc48e3db1dbb1a1f9d65edb0892d adds a layer-first application authority DTO/port, service-role Supabase loader, dormant named preparation orchestration, and migration 20260715100000_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 report 65 passed; Tach affected reports 1,932 passed, the same three unrelated baseline failures, and 3,405 deselected; Ruff, Tach all/exact/external, Vulture confidence-100, and diff checks report zero. A disposable PostgreSQL run pinned migration SHA 273c753dd2fa5f4c08a14bc2a2f65c7ed44832f25d256729c5123aa0fd4ba900, passed apply/reapply, replay 1 -> 1, expiry renewal to revision 2, six fail-closed cases, ACL checks, and zero PGMQ/queue/trigger objects, then removed the database with zero residual matches. The item stays Partially 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 406d56565eae8ff51a7ec354a1c68aadb11db90c aligns the current-authority smoke and backend 59d29eb79359018f116c0be941c6d1a288e44e5c adds draft-owned preparation derivation, five consumer-owned source contracts, a record handler, and the Supabase v2 recorder/loader. The five exact lineage keys are branch_coverage, reservation_state, service_offering_policy, price_catalog_version, and voucher_plan_criteria; every entry freezes owner, source reference, revision, SHA-256, and validity window. Migration 20260715110000_customer_reservation_catalog_prepare_authority_v2.sql, SHA-256 a980b468843ebd07d58b3952d122748d82e77dcfca9277eae210344452aa7d92, 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 reports 109 passed; the full suite reports 5,427 passed and one historical security-validator failure. Ruff on src, Tach exact, Vulture confidence-100, and the earlier disposable PostgreSQL 17 v1-to-v2 smoke pass. The item remains Partially implemented: concrete source adapters are 0/5, record-handler runtime wiring is 0, runtime E2E axes are 0/17, and activation surfaces are 0. 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, contract 132e1a4e1077770247a17397efffceeb0699c045, and frontend ffacc93939528f0e21d098d8fdf41bef3f978f07 pass Supabase CLI migration 321/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 cardinality 1/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 remains Partially implemented and 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. completionClaim remains false.

  • SFC-20260708-CUR-083 Branch topology fixture and settlement hierarchy data-quality gate. Browser reservation smoke submitted a modern booking workflow payload with branchContext.branchName = "테스트 지점" and branchContext.headquartersId = null; backend correctly rejected it with 409 and 비본사 지점은 소속 본사를 가져야 합니다. Evidence: frontend-repo/output/playwright/reservation-scenario-20260708-full-stack/events.json:342-354 and frontend-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 ids 36 and 37, 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, and source-refs/sanmopia-admin/application/controllers/Calculate.php:108-123. Target: branch_operations / BranchTopologySnapshot, branch_operations / BranchHierarchyFixtureValidation, migration_governance / ReservationScenarioFixtureDataQualityGate, and pricing_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, headquartersId may 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-084 Caregiver eligibility context completeness for reservation assignment. After correcting branch topology, browser reservation smoke accepted the booking workflow start but the workflow read failed with failureReason = "승인된 자격증 개수가 부족합니다." because the submitted operational context carried caregiverProfiles[].licenseTitles = []. Evidence: frontend-repo/output/playwright/reservation-scenario-20260708-full-stack-valid-branch/events.json:345 and frontend-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 into admission_career and admission_education writes, controller routes those strings through a generic manager update endpoint, and model methods set ADMISSION_FL on 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, and source-refs/sanmopia-admin/application/models/Manager_model.php:2244-2278. Target: caregiver_assignment / CaregiverEligibilityContextSnapshot, caregiver_assignment / CaregiverQualificationFactsProjection, caregiver_assignment / ReservationAssignmentEligibilityGate, and migration_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-085 Browser-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, and frontend-repo/output/playwright/reservation-scenario-20260708-full-stack-qualified/04-after-submit.png. Target: reservation_orchestration / ReservationBookingWorkflowSmokeRuntime, pricing_settlement / MotherVisibleChargeSummaryReadModel, and migration_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 posted POST /reservation-booking-workflow-starts, read completed workflow progress from GET /reservation-booking-workflow-requests/{bookingRequestId}, and rendered the backend-owned approved amount 989,881원 from GET /reservation-financial-lifecycles/{reservationBookingId}/mother-visible-charge-summary. 2026-07-08 follow-up removed the frontend hardcoded card default so paymentMethodOptions[0].value becomes the authoritative initial payment method, and the smoke backend now allows local Astro ports 4300-4399 plus explicit SANMOPIA_RESERVATION_SMOKE_CORS_ORIGINS origins for repeatable Playwright runs. Repeat proof artifact: frontend-repo/output/playwright/reservation-scenario-20260708-cors-repeat/events.json; it used Astro 4327, kept hidden paymentMethod = 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 completed pnpm supabase:seed:mother-booking-context and pnpm smoke:mother-booking-workflow, producing reservation booking request stage-booking-1783494010282, workflow status completed, reservation id 4b4c621d-42c6-4c98-88fd-0907c7c2754c, and invocation id inv_1keAjpRWfgmc67TkTaaIcHgKWAmLPWz2mM. The real browser submit then exposed two stage blockers: real backend composition lacked CORS for http://app.sanmopia.localhost:24055 to http://api.sanmopia.localhost:24055, and after CORS was added the browser POST reached 202 but client-side progress polling hit 401 because the frontend adapter did not forward the existing Supabase access token. Backend follow-up adds SANMOPIA_CORS_ALLOW_ORIGINS with stage SSOT SANMOPIA_BACKEND_CORS_ALLOW_ORIGINS. Frontend follow-up reads the existing Supabase access-token cookie through src/lib/supabase/browser-access-token.ts for booking submit, progress refresh, and payment pre-registration calls. The rerun artifact frontend-repo/output/playwright/stage-submit-token-20260708161429-booking-desktop-submit-attempt.png reached POST /reservation-booking-workflow-starts 202, GET /reservation-booking-workflow-requests/RBQ-1e6ce816-7720-4d5a-85d0-581eb52663a5 200, and GET /reservation-financial-lifecycles/5e06188f-c7af-4023-8eee-55e8e615afed/mother-visible-charge-summary 200. 2026-07-08 payment-pre-registration proof found the next live blocker: POST /reservation-payment-pre-registrations returned 503 with reservation payment clock is not configured because the production app composition did not pass clock into ReservationPaymentApi. Backend fix wires the same app-factory clock and adds an assembly regression test. The rerun artifact frontend-repo/output/playwright/stage-payment-pre-reg-20260708163501-booking-desktop-payment-pre-registered.png reached booking request RBQ-95336158-2664-4ae1-94b4-4256756afb4c, reservation id b51d0832-ca7d-4d82-809f-17f4dcbdca38, charge summary 200, and payment pre-registration 201 pre_registered. 2026-07-08 paid-payment workflow proof started RPW-STAGE-20260708163933 from frozen payment PAY-STAGE-20260708163454. The first run stayed running because stage migration history had 20260630114852 marked applied while sanmopia_caregiver_payout_acknowledgements was 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 to sanmopia_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. After pnpm supabase:db:push:stage, the same workflow completed with gatewayCode = PAYMENT_GATEWAY_DEBUG_PAYMENT_VERIFIED, approvedChargeFinalizationStatus = already_finalized, and settlementContinuationStatus = waiting_for_financial_facts with reason service delivery completion is not recorded. Follow-up proof continued reservation 90ac43cf-146c-44de-adf6-ebce7e4042cd: service delivery completion was recorded, service-delivery replay workflow settlement-continuation:RPW-STAGE-20260708163933:service-replay-20260708170535 completed after the backend made matching service-delivery command replay idempotent, and the same reservation advanced through caregiver payout 950000, Branch settlement 1681519, HQ settlement 90000, and final settled. Runtime blocker fixed during the proof: the customer service-balance instruction projection adapter now uses physical table sanmopia_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-delivery now 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 artifact frontend-repo/output/playwright/reservation-card-flow-20260709-backend-e2e-script/desktop-summary.json submitted reservation 75f98a31-0949-4ad6-a7f0-3a3935fd0c2b, showed completed · 결제 진행 완료, and rendered customer payable 1,681,519원. Backend driver backend-repo/scripts/stage_reservation_settlement_e2e.py then seeded the SpiceDB branch/HQ actor relationships, generated the service-balance closeout reference from Supabase, and advanced the same reservation through service_delivered, caregiver_payout_ready, branch_settlement_ready, hq_settlement_ready, and final settled with caregiver payout 500000, branch settlement 1181519, HQ settlement 181519, and ledgerLineCount=3. Runtime finding: the old frontend settlement smoke URL /reservation-smoke-scenarios/{id}/settlement-completions is stale; frontend verification must call /reservation-financial-lifecycles/{reservationBookingId}/settlement-completions with 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 not e2e_proven. 2026-07-09 source-authority follow-up replaced the remaining hand-built branch/HQ ledger facts in this smoke with backend command producers. Reservation 521a5051-9825-44e9-bb5a-fd7d84d3981e froze finalized charge lines customer_share=150000 and headquarters_platform_fee=50000, then produced ledger lines for caregiver payout 50000, branch settlement 100000, and HQ settlement 50000 from backend-owned facts. Direct browser backend driver proof booking 27f69a4c-7600-4de1-b611-839d8e757b94 now uses the same producer path and reports account-disclosure readiness not_required for zero service-balance due. 2026-07-10 backend 597b56d routes the local smoke settlement completion through AdvanceReservationFinancialLifecycleHandler commands and a versioned _SmokeReservationSettlementPolicy, replacing direct aggregate mutation and route-local split arithmetic. Remaining work: keep fixture data-quality gates from SFC-20260708-CUR-083 and SFC-20260708-CUR-084 in front of every smoke run and replace the temporary stage quote fixture with catalog-owned product-plan data. 2026-07-11 frontend 8a9a6f5 removes this endpoint and all smoke settlement DTO/state/rendering from production src/**. 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-086 Reservation 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 to SFC-20260708-CUR-083; caregiver qualification/license approval belongs to SFC-20260708-CUR-084. Additional evidence: source-refs/sanmopia_web/application/models/Branch_model.php:38-90 and source-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, and source-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, and source-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-808 and source-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, and source-refs/sanmopia_web/application/config/constants.php:64-90 (payment eligibility is purpose-specific: create/pre-reservation pages expose CARD/VCNT while BANK is commented out, mypage own-balance exposes CARD/BANK/VCNT, service-balance uses direct caregiver account instructions, hidden JS writes ActionResult/pay_method into 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 KCP CARD route, 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, and source-refs/sanmopia_web/application/models/Reservation_model.php:2660-2766 (service-start/end, weeks/service-day, Wanju, selected Saturday/holiday dates, RESERVATION_ADD_DATE writes, 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, and migration_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 runs ReservationBookingContextQualityGate before 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 cover caregiver_qualification_context_missing and prove workflow starter is not called on preflight failure. 2026-07-08 follow-up adds the first payment preflight invariant: payment_method_catalog_eligibility_invalid rejects hidden browser-only or unsupported payment method values such as family_bank before workflow acceptance by using the backend PaymentMethodCode catalog (card, vcnt, bank) instead of UI labels. 2026-07-08 follow-up 2 wires the real PaymentProductPlanBook into the Supabase reservation runtime and blocks canonical-but-purpose-invalid methods with payment_purpose_method_eligibility_invalid before workflow acceptance (reservation.customer_share.deposit is the booking-start plan). Focused proof: API/HTTP tests reject a bank booking-start request before workflow start, Supabase runtime accepts the injected resolver, and backend smoke RBQ-SCENARIO-20260708-1 returns start 202, workflow completed, frozen reservation id e32cb903-89cd-45a1-babc-da6c1ea275b5, charge summary 200, customer payable 150019, 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, and backend-repo/supabase/migrations/20260704080443_payment_product_plan_communication_routes.sql:49-220, plus backend-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 where ADDRESS_LEVEL_2 contains 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 into ReservationPaymentApi as the provider-route query and blocks verify_paid_payment workflow 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.py rejects those cases with payment_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 returns 202. 2026-07-08 follow-up 4 promotes the pre-registration query port into the application pre-registration slice and injects the same Supabase store into KillBillPaymentEventIngestionHandler; 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.py rejects payment_provider_route_pre_registration_missing, payment_provider_route_snapshot_missing, and payment_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-087 Actual-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, counts MANAGER_ATTENDANCE_TB, grants no coupon under three actual service days, grants PRODUCT1/20,000 for three-to-seven days, grants PRODUCT2/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, and source-refs/sanmopia-admin/application/models/Payment_model.php:3837-3868. Target: promotion_entitlement / ActualServiceProductCouponEntitlement, promotion_entitlement / ProductCouponPublicationProjection, pricing_settlement / ProductCouponSettlementLineProjection, and care_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-088 Settlement 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, custom etc name/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 persist BOARD_PAYMENT_ADMIN_ETC_TB / BOARD_PAYMENT_DANBEE_ETC_TB rows 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 hidden reservation[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, and source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:29-49. Target: pricing_settlement / SettlementAdjustmentLineCommand, pricing_settlement / SettlementStatementWorklistProjection, document_reporting / SettlementDataRoomSelectionGrant, and operator_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, and backend-repo/src/sanmopia_modernization/interfaces/settlement_statement_http.py now accepts manualAdjustmentLines produced from a catalog-frozen FrozenSettlementManualAdjustmentLinePayload. That path computes totalAmountKrw backend-side from quantity and catalog unit amount, maps the frozen line into SettlementStatementManualRowPayload, rejects posted totalAmountKrw, and no longer accepts legacy direct manualRows through 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, and settlement_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 tampered ftotal-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-089 Caregiver 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 sets OTHER_AREA_FL when 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, and source-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, and pricing_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-branch OTHER_AREA settlement 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_TB rows 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). Modern CareTeamAssignmentHistoryProjection and CareTeamDocumentRosterSnapshot must 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, temporary fservice-start-date, and fservice-end-date to 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-094 Care-delivery notification, occurrence, and attendance repair backfill authority. Legacy manager repair helpers mutate care-delivery facts directly: temp20200522() converts already-read report notifications into MANAGER_ATTENDANCE_TB attendance rows, temp20200528() rebinds notify rows to the current manager from RESERVATION_DETAIL_VW, temp202005281047() inserts a one-off RESERVATION_DATE_TB service occurrence row, and dated helpers insertNotify20210831() / insertNotify20210901() hardcode notification CREATED_DT values 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, and source-refs/sanmopia-manager/application/models/Notify_model.php:166-262. Target: care_delivery / CareDeliveryNotificationRepairCase, service_calendar / ServiceOccurrenceRepairCommand, customer_engagement / NotificationRecipientRepairProjection, and migration_governance / SourceRepairRunLedger. Status: foundation; backend commit f318d9c adds CareDeliveryNotificationRepairBackfillPlanner and strict Pydantic PlanCareDeliveryNotificationRepairBackfillPayload contract. 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 as MANAGER_ATTENDANCE_TB, NOTIFY_TB, RESERVATION_DATE_TB, RESERVATION_DETAIL_VW, CREATED_DT, temp20200522, temp20200528, temp202005281047, insertNotify20210831, and insertNotify20210901. 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-095 Branch/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 as VOUCHER_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-branch ALL_PRICE and RESULT_PRICE from 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, and source-refs/sanmopia-admin/application/models/Payment_model.php:2076-2088. Target: pricing_settlement / SettlementRemittanceAccountSnapshot, pricing_settlement / SettlementFeePolicySnapshot, pricing_settlement / BranchHeadquartersSettlementStatementProjection, operator_access / SettlementRemittanceVisibilityGrant, and document_reporting / SettlementRemittanceInstructionArtifact. Status: Backend foundation: 6b2b571. Backend now reuses existing SettlementRemittanceAccountSnapshot and adds SettlementRemittanceInstructionSnapshotProjection, SettlementFeePolicySnapshot, SettlementFeePolicyLineSnapshot, SettlementStatementResultTotalSnapshot, and IssueSettlementRemittanceInstructionSnapshotPayload. 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 as ALL_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 for GetSettlementRemittanceInstructionProjection; 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-096 Caregiver 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 and 2022-03-29 cutover 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, and source-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, and document_reporting / CaregiverPayoutStatementArtifactGrant. Status: Mapped; SFC-059 covers admin payout projection persistence and CaregiverPayoutPortalSurfaceProjection is 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 needs GetCaregiverPayoutPortalStatementProjection query/read model, IssueCaregiverPayoutStatementAccessGrant command, IssueCaregiverRouteDisclosureGrant command, CaregiverPayoutPortalStatementProjectionStore, CaregiverPayoutSurfacePolicySnapshotStore, and CaregiverPayoutStatementArtifactGrantStore persistence 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-097 Branch 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 branch 36, 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, and source-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, and security_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 needs PostBranchDocumentMailboxMessage command, GetBranchDocumentMailboxThreadProjection query/read model, IssueDocumentMailboxAttachmentGrant command, BranchDocumentMailboxPostStore, DocumentMailboxAttachmentRevisionStore, and DocumentMailboxAuditEventStore persistence 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-098 Annual 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 under upload/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, and source-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, and migration_governance / SettlementArtifactBuildRunLedger. Status: Backend foundation: ebf6a8d; backend now adds AnnualBranchSettlementDatasetRevision, SettlementPaymentMethodFeeSnapshot, AnnualBranchSettlementWorkbookArtifact, SettlementArtifactBuildRunLedgerEntry, BuildAnnualBranchSettlementWorkbookArtifact, GetAnnualBranchSettlementDatasetRevision, AnnualBranchSettlementDatasetRevisionStore, AnnualBranchSettlementWorkbookArtifactStore, and SettlementArtifactBuildRunLedgerStore. 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/excel server 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-099 Pre-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 input data-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 carries fmanager-id into 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, and source-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, and security_audit / AssignmentDraftDecisionAudit. Status: Backend foundation: ad17f8c; backend now adds CaregiverCandidateSnapshotRevision, PreReservationCaregiverAssignmentDraft, AssignmentPreviewEvidence, AssignmentDraftDecisionAudit, CreatePreReservationCaregiverAssignmentDraft, PreviewPreReservationCaregiverAssignmentEvidence, CommitPreReservationCaregiverAssignmentDraft, PreReservationCaregiverAssignmentDraftStore, AssignmentPreviewEvidenceStore, and AssignmentDraftDecisionAuditStore. The slice derives score display labels from backend score_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-100 Caregiver 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 hidden data-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 upsert MANAGER_WORKING_DAY_TB.VALUE for MANAGER_ID_FK + DATE while the table also displays attendance-count comparison from MANAGER_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, and source-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, and security_audit / CaregiverWorkCapacityRevisionAudit. Status: Partial; backend commit 0273986 adds the DDD/application contract foundation for CaregiverMonthlyWorkCapacityRegister. It owns RecordCaregiverMonthlyWorkCapacityCommand, GetCaregiverWorkCapacityComparisonQuery, CaregiverMonthlyWorkCapacityRevisionStore, CaregiverAttendanceCountEvidenceStore, CaregiverWorkCapacityComparisonSnapshotStore, and CaregiverWorkCapacityRevisionAuditStore, 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 as managerId, value, yearMonth, draw, and order; stale revisions are rejected before persistence; comparison snapshots emit assignment optimizer, caregiver payout, performance scorecard, and attendance-evidence invalidation keys. Backend commit 34a747d adds 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, and sanmopia_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 migration 20260708201929_caregiver_monthly_work_capacity_register_runtime.sql, confirmed all four tables have RLS enabled and grant only service_role, and ran a rollback smoke through attendance evidence -> capacity revision -> comparison snapshot -> audit. Backend commit 5f97948 adds the operator API gate and binds CaregiverMonthlyWorkCapacityRegisterApi to Supabase Auth and SpiceDB: capacity writes require branch manage, comparison reads require branch view, and the access-token actor must match the command actor before any store write. Backend HTTP follow-up adds POST /caregiver-monthly-work-capacities and GET /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 as managerId. 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 downstream MANAGER_WORKING_DAY_TB consumer was found outside the manager-working-day controller/model; downstream product, performance, and report paths read MANAGER_ATTENDANCE_TB independently. 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 in source-refs/sanmopia-manager/application/helpers/salary_helper.php:69-73 and source-refs/sanmopia-admin/application/views/manager/manager_pay_detail.php:17-22 reads planned SERVICE_DAY, not MANAGER_WORKING_DAY_TB or attendance count. Modern boundary: capacity-register writes must emit comparison and invalidation facts only; ActualServiceAttendanceCountProjection, PerformanceRecognitionAttendanceScoreSnapshot, CaregiverReportDateEvidenceProjection, and CaregiverAttendanceCorrection own 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-101 Customer web session recovery and booking/payment actor binding. Legacy customer web APIs treat CodeIgniter session state and a long-lived encrypted AUTH_TOKEN cookie as the actor source for reservation creation, payment, service-balance, and change-payment actions. Authlib stores short session keys (ilg, at, sy, is), restores login from the sy stay cookie, looks up USER_TB.AUTH_TOKEN, redirects when social profile data is incomplete, and booking/payment controllers compare USER_ID_PK to 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, and source-refs/sanmopia_web/application/controllers/api/Payment.php:693-703. Target: member_management / CustomerAuthenticatedSessionProjection, member_management / CustomerAccountLinkProof, reservation_orchestration / BookingWorkflowActorContext, pricing_settlement / PaymentActorContext, and security_audit / CustomerSessionRecoveryAuditEvent, and reservation_operations / ReservationBookingPartyAuthorityBinding. Status: Partial as of backend 35f67ff912d32c92e4772e60895bf1da45014437. Member Management now owns CustomerAuthenticatedSessionProjection and CustomerAccountLinkProof; P04 reservation creation and booking identity consume that shared proof and reject member/profile drift. Pricing Settlement now resolves a typed PaymentActorContext from 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, denied anon/authenticated, and rejected withdrawal_pending. Security Audit now owns CustomerSessionRecoveryAuditEvent; 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 exact INSERT+SELECT, update/truncate and anon/authenticated denial 42501, privileged immutable trigger 55000, and forbidden raw columns 0. Reservation Operations now freezes the direct mother’s mother/booker/payer authority, account-link evidence, accepted draft/review lineage, and expected new-booking revision 1 in an append-only snapshot written atomically with booking/payment. Public input cannot submit the binding. Actual disposable DB verification proved exact replay, drift/stale 40001, full rollback, immutable 55000, and service-role-only ACL. Full backend regression is 7028 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. Source AUTH_TOKEN, CI session keys, long-lived web cookies, raw USER_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 with 401, 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.

  • CaregiverMatchingProfileRevision and matching-candidate input facts. Existing owner rows: caregiver matching preference/profile checklist row, SFC-20260708-CUR-084, and SFC-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-65 posts pet allergy/type/size/count/isolation, religion, ranked service preference, and personality values; source-refs/sanmopia-manager/application/models/Matching_model.php:140-186 inserts or updates MANAGER_MATCHING_INFO_TB; source-refs/sanmopia-manager/application/models/Matching_model.php:188-260 rewrites ranked service preference rows by fixed sequence; and source-refs/sanmopia-manager/application/models/Matching_model.php:263-304 deletes 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 plus SFC-20260708-CUR-065 and SFC-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-365 posts a cancel/stop/change request with reservation id and freeform reason; source-refs/sanmopia_web/application/controllers/api/Reservation.php:86-139 validates the logged-in customer and dispatches the stop command branch; source-refs/sanmopia_web/application/models/Reservation_model.php:1091-1111 flips reservation status to RESERVATION_STATUS_STOP_REQ and writes RESERVATION_REQUEST_TB; and source-refs/sanmopia_web/application/controllers/api/Reservation.php:192-208 sends 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.

  • ServiceAreaCoverageDecision and 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-89 matches branch area by address levels and area type; source-refs/sanmopia_web/application/models/Branch_model.php:93-140 applies impossible-area veto checks before returning a branch; and source-refs/sanmopia-admin/application/models/Branch_model.php:337-425 writes 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 versioned ServiceAreaCoverageDecision projection, not live branch tables or UI-side address heuristics; unavailable/impossible veto must outrank consultation and available coverage in backend policy.

  • SettlementArchiveRequest and branch/head-office approval provenance. Existing owner rows: SFC-20260709-CUR-103, SFC-20260708-CUR-088, and SFC-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-312 accepts 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:315 routes the settlement data room; and source-refs/sanmopia-admin/application/controllers/Calculate.php:568-578 exports 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: Partial after runtime KillBill paid-webhook workflow-start failure now persists a provider attempt and compensation intent, and /internal/payment-refund-repairs/provider-refund-plans now persists the repair plan. Backend also exposes /internal/payment-refund-repairs/provider-refund-executions, calls the configured Kill Bill gateway through PaymentGatewayClient.refund, and persists execution attempts in sanmopia_payment_refund_repair_execution_attempts, then records accepted or rejected repair execution results through ProviderRefundResultFromLedgerHandler. Still Missing for 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.

  • BranchProfileRevision and settlement-facing branch facts. Existing owner rows: branch_operations / office_profile, operator_access / branch_login_audit, BranchCoverageDecision, SettlementRemittanceAccountSnapshot, and BranchMembershipDueAcknowledgementPolicy. Status: Partial. Evidence: source-refs/sanmopia-admin/application/controllers/OfficeManagement.php:407-432 posts 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-242 writes the mutable branch profile, account, password, and status fields; source-refs/sanmopia-admin/application/models/Branch_model.php:261-285 computes 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-426 maps possible/consult/impossible area strings and rejects subordinate coverage rows when no possible area exists; and source-refs/sanmopia-admin/application/models/Branch_model.php:435-517 plus source-refs/sanmopia-admin/application/models/Branch_model.php:526-606 overwrite or delete branch profile/stamp files and service-area rows. Backend rule: branch_operations owns revisioned branch profile, service-area, and brand-asset commands; operator_access owns credential rotation; pricing_settlement owns membership-fee schedules and remittance account snapshots; document_reporting consumes 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.

  • AdminRevenueStatisticsProjection and 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-453 issues separate total/government-fee/coupon/offline metric requests; source-refs/sanmopia-admin/application/models/Statistics_model.php:1070-1182 groups 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-1856 joins mutable paid rows, coupon rows, and fee SQL functions to calculate revenue; source-refs/sanmopia-admin/application/models/Statistics_model.php:1860-1948 builds branch/product/work-style counts and sums using string comparisons, status filters, and branch exclusions; and source-refs/sanmopia-admin/static/js/statistics/sales.js:630-685 plus source-refs/sanmopia-admin/static/js/statistics/sales.js:1153-1168 request chart/table datasets and combine totals client-side. Backend rule: business_reporting needs versioned metric definitions and projection refresh jobs keyed by payment/refund/closeout/settlement invalidation. pricing_settlement supplies 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, and SettlementDataRoomFilterStateToken. Status: Partial. Evidence: source-refs/sanmopia-admin/application/controllers/DataRoom.php:30-83 accepts GET branch/date filters into the form-list page; source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:17-64 accepts branch/date/form/table parameters; source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:91-130 chooses eligible statuses and service/document filters; source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:132-240 performs search, sort, and paging in PHP memory; and source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:1-47 preserves 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.

  • AllDocumentBundlePolicy and ReservationDocumentSelectionConflictDecision. Status: Partial. Evidence: source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:62-87 treats integrated document form 16 as single-select only in browser code and posts hidden reservation[service_type]; source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:219-246 submits selected reservations through a hidden iframe; and source-refs/sanmopia-admin/application/controllers/DataRoom.php:311-386 trusts 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.

  • BranchDocumentMailboxPostRevision and DocumentAttachmentVersionGrant. Status: Mapped/Partial. Evidence: source-refs/sanmopia-admin/application/controllers/DataRoom.php:97-197 routes 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-80 applies branch-36/headquarters/null-branch send/receive visibility rules; source-refs/sanmopia-admin/application/models/Data_room_model.php:105-184 updates or inserts posts, uploads files, deletes selected file rows, then deletes physical files; and source-refs/sanmopia-admin/application/models/Data_room_model.php:189-202 deletes 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.

  • SettlementStatementRevisionConflictDecision and SettlementBoardActionJournal. Status: Partial. Evidence: source-refs/sanmopia-admin/application/controllers/Common.php:80-130 rebuilds 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-170 collects checked normal/voucher/coupon/reservation ids into posted arrays; source-refs/sanmopia-admin/static/js/calculate_detail.js:930-1144 recomputes delivery, membership, coupon-fee, manual-etc, and result totals in browser state; source-refs/sanmopia-admin/application/controllers/Calculate.php:150-272 accepts posted totals, flags, board id, data type, and manual lines; source-refs/sanmopia-admin/application/controllers/Calculate.php:245-270 and source-refs/sanmopia-admin/application/controllers/Calculate.php:279-309 call insertLog during HQ confirmation/rejection and branch acknowledgement; source-refs/sanmopia-admin/application/models/Payment_model.php:25-31 logs before/after values plus branch id but ignores the passed board id; and source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3031 changes 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, and RefundRepairSettlementImpactJournal must 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.

  • SettlementArtifactBuildRunLedger and SettlementExportDatasetRevision. Status: Partial. Evidence: 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 expose board ids and data-type through detail buttons; 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 navigate by raw board id; source-refs/sanmopia-admin/application/controllers/Calculate.php:568-578 exports by GET excelType and boardId; and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3911 reloads mutable board rows, recalculates coupon payment-method fees in the renderer, writes spreadsheet formulas, streams to php://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, backend 3e6d83f workspace-domain SettlementWorkspace.request_repair now revokes active SettlementArtifactGrant records for the invalidated artifact version and records revoked_grant_ids plus replacement_artifact_request_code on 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-project SettlementArtifactReplacementRequestLink from 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, and source-refs/sanmopia-admin/application/controllers/DataRoom.php:312-376.

  • PrintableDocumentArtifactBuildRun and DocumentTemplateVersionManifest. Status: Partial. Evidence: source-refs/sanmopia-admin/application/controllers/DataRoom.php:85-95 exposes raw excelType and reservation-id export; source-refs/sanmopia-admin/application/controllers/DataRoom.php:311-386 posts selected reservation ids into document download; source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-4198 renders documents from live reservation/report rows, copies static PDFs into temp paths, writes XLSX temp files, zips them, deletes temp files, and streams output; and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4028-4050 chooses 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 pathModern ubiquitous nameTarget bounded context / feature sliceBackend authority ruleImplementation statusVerification 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, MotherVisibleChargeCatalogSnapshotpricing_settlement / product_catalog, pricing_settlement / caregiver_compensation, reservation_operations / quote_projectionSupabase-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, AdditionalCareOptionChargeLinereservation_operations / continuation_booking, caregiver_assignment / matching_requirement, pricing_settlement / reservation_charge_linesBackend 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, SubCaregiverServiceBalanceReceiptSlotpricing_settlement / service_balance_closeout, caregiver_compensation / care_team_receipts, operator_access / caregiver_account_disclosureBackend 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, PublicFeeGuideArtifactCatalogpricing_settlement / public_fee_guide_catalog, pricing_settlement / product_catalogBackend 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, ReservationCreationHandoffProjectionreservation_catalog / service_offering_availability, reservation_operations / reservation_creation, pricing_settlement / price_catalog_version_policyBackend 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, CaregiverWorkingWindowPolicyreservation_catalog / service_working_time_policy, pricing_settlement / reservation_charge_lines, caregiver_assignment / caregiver_availabilityBackend 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, ReservationChargeDocumentSnapshotreservation_operations / reservation_submission, pricing_settlement / reservation_charge_lines, caregiver_compensation / payout_projection, branch_settlement / settlement_seed_projection, document_reporting / reservation_charge_artifact_projectionBackend 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, RentalDocumentChargeSnapshotreservation_catalog / rental_equipment_catalog, reservation_operations / reservation_submission, pricing_settlement / reservation_charge_lines, branch_settlement / settlement_seed_projection, document_reporting / reservation_charge_artifact_projectionBackend 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, CouponDocumentChargeSnapshotpromotion_entitlement / coupon_use_authority, pricing_settlement / reservation_charge_lines, payment_processing / payment_closeout, branch_settlement / settlement_seed_projection, document_reporting / reservation_charge_artifact_projectionBackend 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:

  • ReservationAddOptionSelectionRevision must 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-68 writes normal/voucher payment rows by service type, and source-refs/sanmopia_web/application/models/Payment_model.php:157-226 copies PRICE_TABLE["userFeeSecurityPrice"], userFeeBalancePrice, and leftPrice into PAYMENT_USER_RESERVATION_*_TB; those prices already include add-option and extra-day totals from source-refs/sanmopia_web/application/models/Reservation_model.php:1231-1369. Caregiver payout evidence: source-refs/sanmopia-admin/application/models/Reservation_model.php:3235-3264 reloads rental and add-option rows for a reservation, and source-refs/sanmopia-manager/application/helpers/salary_helper.php:102-145 recomputes Saturday/holiday/service-day multipliers into caregiver added-service pay before source-refs/sanmopia-manager/application/views/pay_info_detail.php:201-249 renders final salary. Branch/HQ settlement evidence: source-refs/sanmopia-admin/application/models/Payment_model.php:198-278 summarizes payment rows for HQ-to-branch settlement, and source-refs/sanmopia-admin/application/models/Payment_model.php:4155-4222 separately rebuilds service-balance price by joining RESERVATION_ADD_OPTION_VOUCHER_TB and RESERVATION_ADD_OPTION_NORMAL_TB. Danbee settlement evidence: source-refs/sanmopia-admin/application/models/Payment_model.php:3190-3232 reads payment rows into Danbee settlement worklists, and source-refs/sanmopia-admin/application/models/Payment_model.php:384-523 adds 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, and source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:728-748 render 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-1035 triggers refund plus coupon restore during instant cancellation, and source-refs/sanmopia_web/application/models/Payment_model.php:383-430 refunds provider payment rows then marks normal/voucher payment rows refunded. Remaining backend gap: persist one ReservationAddOptionSelectionRevision consumer contract through ReservationPaymentSettlementHandoffSnapshot, CaregiverPayoutChargeImpactSnapshot, BranchSettlementSeedProjection, HeadquartersSettlementSeedProjection, ReservationChargeDocumentSnapshot, and RefundRepairProjectionInvalidation; all consumers must reference the same persisted revision key, finalized charge snapshot id, payment fact revision, and repair/reissue lineage.

  • ReservationRentalSelectionRevision must be the ubiquitous name for rental equipment and delivery-fee charge rows, with RentalDeliveryChargeLine as the single delivery-fee component. Payment handoff evidence: source-refs/sanmopia_web/application/controllers/api/Service.php:416-419 and source-refs/sanmopia_web/application/controllers/api/Service.php:531-534 reinsert posted rental ids before payment handoff; source-refs/sanmopia_web/application/models/Reservation_model.php:1231-1259 adds rental rows plus DELIVERY_FEE; and source-refs/sanmopia_web/application/models/Reservation_model.php:1318-1348 feeds 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-229 reloads rental rows before PRICE_TABLE calculation, source-refs/sanmopia-admin/application/models/Reservation_model.php:584-595 joins RESERVATION_RENTAL_TB to LIST_RENTAL_TB, and source-refs/sanmopia-admin/application/models/Reservation_model.php:748-776 adds rental and delivery-fee values into admin price rows. Printable document evidence: source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:663-709 hardcodes rental names, breast-pump price, and delivery price into downpayment artifacts, while source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-3952 renders 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, and source-refs/sanmopia-admin/application/models/Payment_model.php:534-744. Remaining backend gap: persist ReservationRentalSelectionRevision and expose RentalSettlementImpactSnapshot, RentalDocumentChargeSnapshot, and RentalRefundRepairProjectionInvalidation so 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.

  • ReservationCouponSelectionRevision must be the ubiquitous name for coupon selection rows; CouponUseLedgerEntry, CouponPaymentCloseoutFact, and CouponRefundRepairLedgerEntry own consumption, restoration, provider refund, settlement, and document impact. Payment evidence: source-refs/sanmopia_web/application/models/Reservation_model.php:1990-2033 deletes/reinserts coupon selections by PRERESERVATION_FL; source-refs/sanmopia_web/application/models/Payment_model.php:140-152 mutates USER_COUPON_TB.USE_FL during paid closeout; and source-refs/sanmopia_web/application/models/Payment_model.php:775-843 uses coupon-adjusted PRICE_TABLE values 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-3405 joins RESERVATION_COUPON_USED_TB, USER_COUPON_TB, and PAYMENT_COUPON_TB into Danbee coupon payment rows; source-refs/sanmopia-admin/application/models/Payment_model.php:3410-3478 does the same for HQ/branch coupon rows; source-refs/sanmopia-admin/application/views/calculate_detail.php:629-660 and source-refs/sanmopia-admin/application/views/calculate_detail.php:1091-1127 render coupon payment and gift-fee checkbox lines; and source-refs/sanmopia-admin/application/models/Payment_model.php:534-744 writes BOARD_PAYMENT_* detail rows and marks coupon settlement flags. Refund evidence: 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 by mutable USE_FL plus free-text reuse logs; source-refs/sanmopia-admin/application/models/Coupon_model.php:164-188 refunds coupon payment through KCP and sets PAYMENT_COUPON_TB.REFUND_FL; and source-refs/sanmopia-admin/application/libraries/Kcppayment.php:31-44 sends full-cancel mod_type=STSC. Printable document evidence stays tied to mutable PRICE_TABLE and reservation reloads at source-refs/sanmopia-admin/application/models/Reservation_model.php:184-229, source-refs/sanmopia-admin/application/models/Reservation_model.php:731-790, and source-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-77 accepts caregiver PUT requests for payment and sub_payment; source-refs/sanmopia-manager/application/models/Reservation_model.php:22-24 reads mutable reservation service-balance override fields into the caregiver reservation list; source-refs/sanmopia-manager/application/models/Reservation_model.php:65-69 reads PAYMENT_BRANCH_MANAGER_TB type 5 as reservation payout state; source-refs/sanmopia-manager/application/models/Reservation_model.php:247-270 joins customer service-balance payment rows and PAYMENT_BRANCH_MANAGER_TB type 3 into caregiver detail; source-refs/sanmopia-manager/application/models/Reservation_model.php:382-405 lets main/sub caregiver actions mutate PAYMENT_BRANCH_MANAGER_TB payment flags; and source-refs/sanmopia-manager/application/models/Reservation_model.php:488-515 reads main/sub salary rows from PAYMENT_BRANCH_MANAGER_TB and PAYMENT_BRANCH_SUB_MANAGER_TB. Modern ubiquitous names: CaregiverPortalPayoutStatusSnapshot, CaregiverServiceBalanceReceiptAcknowledgement, SubCaregiverServiceBalanceReceiptAcknowledgement, and CaregiverPayoutInstructionStatusProjection. 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 repair PAYMENT_BRANCH_MANAGER_TB status 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-223 posts branch/HQ settlement totals, selected reservation ids, payment types, coupon ids, membership/delivery/gift-fee flags, and free-form messages into insertPaymentDetail; source-refs/sanmopia-admin/application/models/Payment_model.php:575-603 creates or updates PAYMENT_ADMIN_BRANCH_TB receivable rows per reservation and payment type; source-refs/sanmopia-admin/application/models/Payment_model.php:607-650 marks normal/voucher payment rows as Danbee-settled; source-refs/sanmopia-admin/application/models/Payment_model.php:697-746 writes BOARD_PAYMENT_*_DETAIL_TB rows and marks Danbee coupon settlement flags; source-refs/sanmopia-admin/application/controllers/Calculate.php:248-263 turns branch deposit response into board status 2 complete or 4 arrears; source-refs/sanmopia-admin/application/models/Payment_model.php:2039-2053 reads BOARD_PAYMENT_ADMIN_DETAIL_TB joined to PAYMENT_ADMIN_BRANCH_TB; source-refs/sanmopia-admin/application/models/Payment_model.php:3339-3405 and source-refs/sanmopia-admin/application/models/Payment_model.php:3410-3478 project coupon settlement separately for Danbee and HQ/branch; and source-refs/sanmopia-admin/application/models/Payment_model.php:4241-4262 exposes a repair scan for missing PAYMENT_ADMIN_BRANCH_TB rows while source-refs/sanmopia-admin/application/models/Payment_model.php:4265-4289 mutates board detail/coupon completion flags. Modern ubiquitous names: DanbeeSettlementPaymentBoardFact, BranchSettlementReceivablePaymentState, HeadquartersSettlementDepositAcknowledgement, SettlementBoardDetailCompletionFact, and SettlementReceivableRepairDecision. 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-1658 rebuilds archived Danbee voucher/normal/completed counts from current reservation service-type and status rows while source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:29-49 displays those rebuilt counts beside persisted board totals; source-refs/sanmopia-admin/application/models/Payment_model.php:1750-1912 makes branch/HQ ALL_PRICE mean outstanding components for board statuses 0/1/3/4, but all original components after status 2, 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-60 renders both meanings under the same component and total columns; source-refs/sanmopia-admin/application/controllers/Common.php:132-150 opens branch data-room detail with a board id but null period dates; source-refs/sanmopia-admin/application/models/Payment_model.php:1357-1436 derives a period from those null dates, then re-joins the membership override while hydrating the historical board; and source-refs/sanmopia-admin/application/models/Payment_model.php:1495-1551 rebuilds voucher and gift-coupon subtotals from current payment/coupon rows. Danbee export then calls the same live detail loader and recalculates payment method fees at source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3900. Modern ubiquitous names: SettlementStatementAmountBasisSnapshot, SettlementArchiveClassificationSnapshot, SettlementProjectionConsistencyDecision, and SettlementProjectionDiscrepancyRepair. 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-4203 adds Saturday/holiday quantities to dayCount and charges those rows once; source-refs/sanmopia-admin/application/models/Payment_model.php:4205-4219 then says other additional services use total days plus those added days, but resets dayCount to 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-1575 recalculates that amount from current price/add-option rows during operator payment save; source-refs/sanmopia-admin/application/models/Reservation_model.php:1641-1677 writes it into the type 3 service-balance payment row; and source-refs/sanmopia-admin/application/models/Reservation_model.php:3507-3545 derives 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, and ServiceBalanceCalculationDiscrepancyRepair. Status: Partial; the modern additional-service charge policy and service-balance closeout references exist, but historical type 3 rows 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-1162 and source-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 at source-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 at source-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 at source-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 at source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:647-660. Modern invariant: every AdditionalServiceChargeComponent in ReservationAddOptionSelectionRevision must freeze explicit quantity_basis (effective_service_day, added_service_day, item_quantity, or source_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. Backend 4f7bebf now validates the four typed quantity bases, rejects empty basis-evidence sets, and retains both fields through selection-revision persistence and HTTP response. Stage reservation ca44be7c-fbf3-4a4e-8e47-e27868bf2d72 persisted added_service_day with evidence key extra/saturday/1 and reached settled. Backend 56413fe now 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 ACTION assembly retention, and immutable idempotent replay. Stage reservation eeef7782-aff2-4065-bf9c-7ab48f7fd629 reached settled. Status remains Partial: 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. a48172b and e00810e prove 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 owner SFC-20260708-CUR-065.

  • Add-option payment, printable, and refund consumers still lack immutable formula lineage. The customer payment action loads userFeeSecurityPrice from the current reservation PRICE_TABLE at source-refs/sanmopia_web/application/controllers/Service.php:666-679, writes that amount into the KCP form at source-refs/sanmopia_web/application/views/service/reservation_payment.php:138-145, and launches the provider from browser form state at source-refs/sanmopia_web/static/js/reservation_payment.js:40-89; the callback then reloads the reservation and independently uses the current userFeeSecurityPrice for the provider command and local payment rows at source-refs/sanmopia_web/application/controllers/api/Payment.php:89-165 and source-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 at source-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 at source-refs/sanmopia_web/application/models/Payment_model.php:383-440 and source-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 at source-refs/sanmopia-admin/application/models/Reservation_model.php:1769-1800, classifies every selected payment row with hardcoded IFNULL('일반', '바우처') 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-1880 without add-option component, payment-fact revision, or document-artifact invalidation lineage. Modern invariant: ReservationPaymentSettlementHandoffSnapshot must freeze the accepted ReservationAddOptionSelectionRevision, 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. ReservationChargeDocumentSnapshot must consume the same frozen component references and selection revision without label parsing or amount recomputation. RefundRepairProjectionInvalidation and 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 remains Partial: 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_idprioritylane_ownersource_evidenceddd_aggregatecommand_querypersistencecontracte2e_proofstatusbackend_owned_design
SFC-20260710-PAY-001P0Backend / pricing_settlementLegacy 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, PaymentChangeSupersessionFactPrepareAuthorizedPaymentChangeHandoffCommand, AuthorizeAndPreRegisterPaymentChangeCommand, atomic unpaid replacementAtomic 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_provenBrowser 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-002P0Backend / pricing_settlementNormal 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, VirtualAccountDepositCompletionNotificationOutboxCommitVirtualAccountIssueCommand, DispatchVirtualAccountInstructionCommand, ReconcileOrphanedVirtualAccountIssueCommand, CommitPaymentChangeVirtualAccountIssueCommand, MarkPaymentChangeVirtualAccountDepositedCommand, ApplyPreReservationVirtualAccountDepositEffectsCommand, DispatchVirtualAccountDepositCompletionNotificationsCommandBackend 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_provenBackend 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-003P0Backend / payment_processingThe 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, ProviderWebhookConflictRepairCaseIngestProviderWebhookCommand, ApplyVirtualAccountDepositEffectsCommand, ReplayProviderWebhookEffectsCommandBackend 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_wiredBackend 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-004P0Backend / pricing_settlementPayment 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, PaymentCashReceiptTaxEvidenceTimelinePreRegisterReservationPaymentCommand, ReservationPaymentProviderHandoffIntent, KillBillPaymentEventIngestionHandler, ProjectCurrentCustomerReceiptTaxEvidenceArtifactCommand, ProjectCurrentSettlementTaxEvidenceDatasetRevisionCommandVersioned 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_wiredCheckout/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_idprioritylane_ownersource_evidenceddd_aggregatecommand_querypersistencecontracte2e_proofstatusbackend_owned_design
SFC-20260711-FAM-001P0Backend / member_management and reservation_operationsMother-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, SponsoredReservationContractAcceptanceGrant/revoke sponsorship, submit draft, accept/decline contract, consume acceptance, and acceptance query CQRSBackend 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_wiredBooking creation preserves sponsor actor and consumed grant revision while requiring explicit mother contract acceptance before financially binding progression.
SFC-20260711-FAM-002P0Backend / member_management, reservation_operations, and pricing_settlementDistinct 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, ReservationPaymentActorSnapshotGrantReservationPaymentDelegationCommand, PreRegisterReservationPaymentCommand, GetReservationPaymentPreRegistrationQueryBackend 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_wiredOne 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-003P0Backend / pricing_settlement and customer_engagementLegacy 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, PaymentCompletionRecipientDecisionPreRegisterReservationPaymentCommand, GetPaymentCompletionRecipientDecisionQueryBackend 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_wiredGrant 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-004P0Backend / pricing_settlement and operator_accessOwner-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, PaymentDelegationGrantReservationPaymentDelegationCommand, RevokeReservationPaymentDelegationCommand, GetPaymentParticipantFinancialStatusQueryBooking 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_wiredPersisted 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-005P0Backend / member_management and care_deliveryReservation-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, CustomerDailyReportReviewAuthorityGrant/revoke/access CQRS plus GetReservationCareHistoryQuery; review mutation remains separateBackend 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_provenFamily 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-006P0Backend / member_management and platform authorizationCurrent grant policy treated any non-null revocation as inactive even when evaluating earlier time; no operational revoke command or relationship-delete outbox existed.FamilyAuthorityEffectiveInterval, PaymentDelegationRevokeReservationPaymentDelegationCommand, GetFamilyAuthorityAsOfQueryThe 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_wiredReservation 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-007P1Backend / member_management and platform accessOwner-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, FamilyAuthorityDirectoryViewGetFamilyAuthorityDirectoryQuery, GetFamilyAuthorityAdministrationProjectionBackend 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_provenFamily membership is not authority-directory administration. Backend query permission now owns directory visibility; raw Supabase grant rows are not browser-facing authority directory surfaces.