Settlement Data Room Gap Mining
Settlement Data Room Gap Mining
Section titled “Settlement Data Room Gap Mining”Scope: settlement data-room UX and backend contract for BranchOperator, HeadquartersOperator, and system workflow actors. This is not the generic document room. Settlement data room owns export request state, artifact readiness, download handoff, repair audit, and statement scope visibility. Settlement math remains in pricing/settlement ledgers.
Source Failure Shape
Section titled “Source Failure Shape”-
Settlement surfaces are different concepts. Status:
Contracted as collection scope. Evidence:source-refs/sanmopia-admin/application/views/nav/nav_side.php:374-442andsource-refs/sanmopia-admin/application/views/nav/nav_side.php:483-540. Source behavior: branch document room exposes정산 자료실(본사),정산 자료실(단비), and정산 자료실(단비) - 타 지역; HQ menu exposes지사별 정산(본사/단비),정산내역, and타 지역 서비스 정산. Modern replacement:SettlementDataRoomCollectionseparatesexternal_counterparty_settlement,branch_to_headquarters_settlement,headquarters_settlement, andinter_office_settlement. Source-era labels stay adapter evidence; they are not one screen with actor if-statements. -
Settlement statement commands are still too broad. Status:
Backend foundation contracted. Evidence:source-refs/sanmopia-admin/application/controllers/Common.php:9-204,source-refs/sanmopia-admin/application/controllers/Calculate.php:150-331,source-refs/sanmopia-admin/static/js/calculate_detail.js:20-323,source-refs/sanmopia-admin/application/models/Payment_model.php:2526-2562,source-refs/sanmopia-admin/application/models/Payment_model.php:2861-2915,source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3025, andsource-refs/sanmopia-admin/application/models/Payment_model.php:4382-4400. Source behavior: one detail surface switches bydataTypeand actor; branch acknowledgement can also update coupon payment state. The sourceSTATUS_FLvalues mean0awaiting branch deposit,1awaiting HQ confirmation after branch deposit,2settled,3awaiting HQ confirmation after arrears deposit, and4arrears. Modern replacement:RequestSettlementDeposit,AcknowledgeBranchSettlementDeposit,ApproveHeadquartersSettlement, andRequestSettlementArrearsDepositare separate commands with actor kind, expected revision, idempotency key, andSettlementTransitionAudit.SettlementActorKindis now a shared settlement vocabulary used by statement and data-room commands. Supabase tokens without an explicit settlement actor role fail closed instead of defaulting to branch manager visibility. Remaining gap: source row command context must be preserved, not flattened. The browser posts selected normal/voucher payment row ids, reservation ids, payment type ids, coupon ids, cancelled gift coupon ids, delivery and membership flags, manual etc content, board id, current branch, actor type, message, memo, and settlement month in oneFormDatapayload. Modern commands need typed command contexts for each source row group so a repair can replay or reject only the affected line without changing unrelated settlement rows. -
Private memo can leak through actor flip. Status:
Backend foundation contracted. Evidence:source-refs/sanmopia-admin/application/views/calculate_detail.php:64-70source-refs/sanmopia-admin/application/views/calculate_detail.php:188-220, andsource-refs/sanmopia-admin/application/views/calculate_detail.php:1404-1405. Source behavior: completed state can flip$typetoadmin, changing memo visibility. Modern replacement:messageToBranchandheadOfficePrivateMemoare separate statement fields.visible_head_office_private_memo()returns the private memo only for HQ or system actors; branch-facing contracts must omit it. -
Hardcoded amount/date policy. Status:
Pending. Evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:892-894,source-refs/sanmopia-admin/application/models/Payment_model.php:918-933,source-refs/sanmopia-admin/application/models/Payment_model.php:2120-2128,source-refs/sanmopia-admin/application/models/Payment_model.php:3910-4045,source-refs/sanmopia-admin/static/js/calculate_detail.js:808-884,source-refs/sanmopia-admin/application/models/Payment_model.php:4312-4324, andsource-refs/sanmopia-admin/application/models/Payment_model.php:2452-2458. Source behavior: voucher fee,promotional_coupon_cost, PG fee, default fee, and period join rules are embedded in model/JS. Modern gap:SettlementFeePolicy,PromotionalCouponCostPolicy, andSettlementPeriodPolicymust be versioned policy fixtures before command migration, while deleted product coupon 5,000/10,000 rows stay separate ascancelled_gift_coupon_commission. Voucher fee migration has started:VoucherServiceCommissionCatalogselects an effective-dated policy version and emits the receivablevoucher_service_commissionline item; source aliases such asvoucher_settlement_chargestay adapter-only normalization keys for imported rows. Branch delivery fee migration has started:BranchSettlementDeliveryFeeCatalogselects an effective-dated policy version and emits the receivabledelivery_feeline item; sourcefdelivery-priceremains adapter evidence only. -
Hidden iframe download has no enterprise retry/audit UX. Status:
Backend handoff hardened. Evidence:source-refs/sanmopia-admin/application/views/form_reservation_list.php:123-132,source-refs/sanmopia-admin/application/views/form_reservation_list.php:207-208,source-refs/sanmopia-admin/static/js/form_reservation_list.js:225-247,source-refs/sanmopia-admin/static/js/calculate_detail.js:329-337,source-refs/sanmopia-admin/application/controllers/DataRoom.php:218-250,source-refs/sanmopia-admin/application/controllers/DataRoom.php:268-309, andsource-refs/sanmopia-admin/application/controllers/DataRoom.php:311-386. Source behavior: generic document download uses hidden iframe POST and settlement detail export uses raw GET navigation byexcelType/boardId; branch settlement data-room pages load current board summaries directly from settlement tables. Failure, retry, repair, dataset revision, supersession, and operator audit are weak. Modern replacement:SettlementDataRoomRequesttracksrequested,building,ready,failed,superseded, andcancelled;SettlementDataRoomActionEntryrecords export request, build, ready, repair, and download-link handoff with revision and idempotency key. Artifacts live inbusiness-report-exportswith bucket relative keys, hash, file metadata, dataset revision, lineage evidence keys, and supersession history. Backend now rejects ready-artifact handoffs whosedatasetRevisiondiffers from the frozen request scope, creates the signed Storage URL before journaling a successful download handoff, and keeps storage object identity in the action metadata while omitting storage keys from the portal handoff payload. Remaining gap: portal must expose repair history and signed-download state from persistence: request status, artifact revision, failed build reason, repair reason, previous artifact supersession, signed URL expiry, and last actor. It must not use raw storage object keys, browser URL board tokens, or direct Excel controller redirects as durable state. -
Settlement table display still mutates financial meaning in PHP views. Status:
Mapped, backend projection gap remains. Evidence:source-refs/sanmopia-admin/application/views/table/calculate/table_local_cal_central.php:42-64,source-refs/sanmopia-admin/application/views/table/calculate/table_local_cal_central.php:76-82,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:46-52, andsource-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:17-41. Source behavior: settlement totals are accumulated in the view, then amount columns are overwritten with display strings such as입금완료based on status flags. Modern replacement:SettlementLineProjectionandSettlementCollectionSummarymust compute line totals, status labels, payable/paid/reconciled state, and display-ready amount text from backend ledger rows. Portal tables render projection fields only; they must not sum, compare, or replace money columns with status text. -
Refund/adjustment visibility crosses settlement data-room scope. Status:
Pending. Evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:3186-3337,source-refs/sanmopia-admin/application/models/Payment_model.php:3484-3563,source-refs/sanmopia-admin/application/models/Payment_model.php:3566-3641,source-refs/sanmopia-admin/application/models/Payment_model.php:1750-1960,source-refs/sanmopia-admin/application/models/Payment_model.php:4265-4310, andsource-refs/sanmopia-admin/application/controllers/Calculate.php:151-313. Source behavior: Danbee settlement readers include payment status1and2, so paid and refunded rows can both enter statement/data-room datasets. Central-to-branch readers use board id branches,STATUS_FLrow flags, and reservation status filters; completed boards show rows differently than pending boards. Branch acknowledgement flips detail, coupon, cancelled-coupon, delivery, membership, and manual-etc flags in one request. Modern gap:SettlementRefundAdjustmentVisibilityPolicymust decide whether refund, stop, cancellation, payment-change refund, deleted coupon, and reissued coupon facts produce reversal lines, superseded lines, hidden rows, or operator repair tasks.SettlementLineLifecycleStatemust preserve paid, refunded, reversed, settled, superseded, and adjustment-pending states separately from sourcePAYMENT_STATUS_LIST_ID_FKandSTATUS_FLintegers.RefundAdjustedSettlementDatasetRevisionmust bump data-room request/artifact revision whenever a refund or adjustment changes any included line after board creation. -
Settlement data-room export grants are not refund-adjustment aware. Status:
Pending. Evidence:source-refs/sanmopia-admin/application/controllers/DataRoom.php:215-309,source-refs/sanmopia-admin/application/controllers/DataRoom.php:312-386,source-refs/sanmopia-admin/application/controllers/Calculate.php:569-579, andsource-refs/sanmopia-admin/application/models/Payment_model.php:2292-2523. Source behavior: data-room pages scope by logged-in branch id and board lists, other-office rows markserviceOfficeversusotherOfficein controller code, generic form export trusts posted reservation ids, and settlement Excel export trusts rawexcelTypeplusboardId. Modern gap:SettlementDataRoomExportGrantmust bind actor, branch side, collection scope, board id, row ids, dataset revision, refund/adjustment watermark, file type, expiry, and download audit.SettlementDataRoomRequestandSettlementDataRoomDownloadHandoffmust refuse stale artifacts when refund or payment-change adjustment facts supersede the frozen dataset. Naming follow-up: target ubiquitous language should beSettlementArtifactCollection,SettlementCollectionExportGrant, andBranchSettlementWorkspacebecause legacy behavior is board/collection download management, not a generic data room. -
Settlement remittance export formulas not modeled. Status:
Pending. Evidence:source-refs/sanmopia-admin/application/config/constants.php:255,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3814,source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3869, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3903. Source behavior:type18.xlsxexports board id, message, memo, settlement completion date, payment id, service type/detail, reservation id, deposited date, mother name, pay method, payment amount, deposit amount, coupon rows, and method-specific fee formulas. Modern target:BranchSettlementRemittanceExport,SettlementRemittanceLine, andPaymentMethodFeeRuleSnapshotmust freeze row schema, fee rule id, policy version, and dataset revision before artifact grant. -
Transition audit misses board id. Status:
Backend foundation contracted. Evidence:source-refs/sanmopia-admin/application/models/Payment_model.php:25-32,source-refs/sanmopia-admin/static/js/calculate_detail.js:77-79,source-refs/sanmopia-admin/application/controllers/Calculate.php:187, andsource-refs/sanmopia-admin/application/controllers/Calculate.php:257-262. Source behavior:insertLog($branchId,$boardId,...)accepts board id but does not persist it. Branch acknowledgement can log before and after as the same value while the actual transition is computed insideupdateBoardId(). Modern replacement: everySettlementTransitionAuditcarries command kind, actor, expected revision, committed revision, before status, after status, reason, idempotency key, and metadata for legacy board id/source references. -
Inter-branch lookup can mix records. Status:
Backend and contract invariant added. Evidence: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/controllers/DataRoom.php:268-309,source-refs/sanmopia-admin/application/models/Payment_model.php:2731-2771,source-refs/sanmopia-admin/application/models/Payment_model.php:2816-2840, andsource-refs/sanmopia-admin/application/models/Payment_model.php:2656-2695. Source behavior: other-office detail first loads reservation context, but the board lookup then filters only byBRANCH_TYPEbeforefirst_row(). Source insert rows already carryRESERVATION_ID_FK; list queries reveal the intended split between customer relationship branch and service delivery branch. Branch data-room UI marks each row asserviceOfficeorotherOfficefrom the logged-in branch id, while HQ list and branch history have separate Danbee routes. Modern replacement:InterOfficeSettlementLookupKeyis the canonical lookup and code source: reservation id, customer relationship branch, service delivery branch, settlement period start, and settlement period end. Branch side/status is line or workflow state, never the sole lookup predicate.
2026-07-05 CaveCrew Explorer A Data-Room Navigation Delta
Section titled “2026-07-05 CaveCrew Explorer A Data-Room Navigation Delta”These rows avoid duplicating artifact/export rows above. They isolate hidden data-room UI navigation and actor-side decisions that still need backend names.
| Missing backend policy | Source evidence | Source behavior | Modern target |
|---|---|---|---|
| Settlement board list navigation projection | source-refs/sanmopia-admin/application/controllers/DataRoom.php:218-250, source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:1-69, source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:1-57, 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 | Branch settlement data-room pages render current board rows directly, then browser constructs /common/calculate?dataType=...&boardId=... from button attributes. Data-room board open is raw URL navigation, not a backend-issued view grant with request scope. | SettlementDataRoomBoardListProjection, SettlementDataRoomBoardAccessDecision, and SettlementCollectionNavigationToken must bind actor, branch, collection, board id, display totals, current status label, dataset revision, and next allowed detail action. |
| Inter-office branch-side action projection | source-refs/sanmopia-admin/application/controllers/DataRoom.php:268-308, source-refs/sanmopia-admin/application/views/data_room/calculate_danvi_other_office.php:68-72, source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi_other_office.php:1-70, source-refs/sanmopia-admin/static/js/data_room/calculate_danvi_other_office.js:1-22, source-refs/sanmopia-admin/application/models/Payment_model.php:2684-2704 | Controller marks each row as serviceOffice or otherOffice by comparing logged-in branch id to service/customer-transfer branch ids; view renders only one side’s action button and JS passes reservation id plus branch-side string. The route parses fyear/fmonth, but period bounds are commented out and the reader is called with NULL, NULL, so the branch data-room list is not a frozen settlement-period dataset. Modern lookup key exists, but action availability and period scope still need their own projection. | InterOfficeSettlementSideActionProjection, InterOfficeSettlementBranchSideDecision, and InterOfficeSettlementDataRoomPeriodScope must expose service-side/customer-relationship-side role, row status, allowed detail command, disabled reason, reservation lookup key, canonical settlement period, dataset revision, and branch-side audit scope. |
2026-07-06 Explorer A Detail-Journey Delta
Section titled “2026-07-06 Explorer A Detail-Journey Delta”| Priority | Status | Modern ubiquitous name | Hidden source evidence | Feature gap |
|---|---|---|---|---|
| P0 | Partial | SettlementDataRoomDetailActionProjection | source-refs/sanmopia-admin/application/controllers/Common.php:28-204, source-refs/sanmopia-admin/application/views/calculate_detail.php:113-124, source-refs/sanmopia-admin/application/views/calculate_detail.php:1298-1360, source-refs/sanmopia-admin/static/js/calculate_detail.js:22-323, source-refs/sanmopia-admin/static/js/calculate_detail.js:342-380 | The detail page decides journey state from actor type, dataType, board status flags, and branch-side strings: it changes button text, shows Danbee download only for userToDanbee, hides branch inter-office buttons in comments, hardcodes irreversible confirm copy, and picks post-command return routes in JavaScript. Modern data-room detail reads need a backend-owned action projection with current statement revision, allowed command, disabled reason, irreversible warning copy key, download readiness, return-state token, and actor-specific next action. |
Actor And Container Flow
Section titled “Actor And Container Flow”flowchart LR BranchOperator[BranchOperator / BranchOwner] HeadquartersOperator[HeadquartersOperator / HeadOfficeManager] Workflow[Export workflow] Portal[Operator portal] Api[Settlement API] Statement[(Settlement statement ledger)] DataRoom[(Settlement data-room requests)] Storage[(business-report-exports)] HeadquartersOperator -->|request deposit, approve HQ settlement| Portal BranchOperator -->|acknowledge lines, download, request repair| Portal Portal -->|typed commands with expectedRevision| Api Api -->|manual rows, line acknowledgements, transition audit| Statement Api -->|request/build/ready/repair/download actions| DataRoom Workflow -->|build and mark ready| Api Workflow -->|write artifact| Storage Api -->|signed URL handoff only| Portal DataRoom -. collection .-> ExternalCounterpartyScope[external_counterparty_settlement] DataRoom -. collection .-> BranchToHeadquartersScope[branch_to_headquarters_settlement] DataRoom -. collection .-> HQScope[headquarters_settlement] DataRoom -. collection .-> InterOfficeScope[inter_office_settlement]
Design rule: external-counterparty settlement, branch-to-headquarters settlement, headquarters settlement, and inter-office settlement share command/audit vocabulary, but each keeps separate collection scope, dataset revision, lineage evidence, actor visibility, and export reader.
Feature-Level Implementation Plan
Section titled “Feature-Level Implementation Plan”This plan extends the settlement rows above; it does not add duplicate source coverage.
- Canonicalize settlement collection vocabulary in the pricing-settlement
domain. Use
ExternalCounterpartySettlement,BranchToHeadquartersSettlement,HeadquartersSettlement, andInterOfficeSettlementas feature names across commands, query models, archive scopes, and adapter mappings. Keep source/vendor labels as adapter-only evidence. Backend/contract data-room drift retired on 2026-07-06 includeshead_office_settlementversusheadquarters_settlement,inter_branch_settlementversusinter_office_settlement, and vendor-specific names leaking into domain enum values. - Keep settlement computation in canonical ledger/read-model features, not in
archive or portal code. The owning domain vocabulary should expose
SettlementStatementLine,SettlementLineLifecycleState,SettlementCollectionSummary, andSettlementLineProjectionfor branch membership, voucher commission, promotional coupon cost, cancelled benefit commission, delivery fee, inter-office share/service fee, refund adjustment, and manual adjustment lines. - Bind approval flows through command handlers with explicit actor and revision
controls:
RequestSettlementDeposit,AcknowledgeBranchSettlementDeposit,ApproveHeadquartersSettlement, andRequestSettlementArrearsDeposit. Every command needs actor kind, branch scope, expected revision, idempotency key, line acknowledgement context when applicable, and a persistedSettlementTransitionAuditentry. - Split CQRS surfaces by responsibility. Command handlers mutate
SettlementStatement,SettlementDataRoomRequest, andSettlementWorkspaceaggregates. Query handlers publishSettlementOperatorBoardProjection,SettlementDataRoomBoardListProjection,SettlementDataRoomDetailActionProjection, andSettlementCollectionSummaryProjection. Portal routes should render these projections without recalculating amounts, dates, row ownership, or status transitions. - Model the settlement archive/material room as a separate workspace feature.
SettlementWorkspace,SettlementArtifactRequest,SettlementArtifactVersion,SettlementArtifactGrant,DownloadHandoffAudit,SettlementRepairRequest, andBulkExportTemplatePolicyown export request state, signed download handoff, repair/rebuild state, template selection, dataset revision, and refund/repair watermarks. They must not own ledger math. - Make conflict resolution and audit first-class. Use
SettlementWorkspaceRevisionConflict,SettlementWorkspaceConflictResolutionDecision, and a settlementDomainChangeJournal/audit stream for stale operator edits, artifact repair retries, status-transition refusals, and bulk export rebuild decisions. - Implement incrementally: first normalize value vocabulary beside the owning
domain enum/value objects; then update application contracts and interface
DTOs; then adapt Supabase row mappings; finally refresh targeted domain,
adapter, and HTTP tests with
uv,ruff, andtach. Avoid full pytest runs for this lane.
2026-07-06 Implementation Delta
Section titled “2026-07-06 Implementation Delta”backend-reponow exposes canonical data-room collection values:external_counterparty_settlement,branch_to_headquarters_settlement,headquarters_settlement, andinter_office_settlement.- Supabase migration
20260706021241_canonical_settlement_data_room_collections.sqlconverts existing request/workspace/conflict rows and JSON payloads from source-era collection names, then adds named check constraints for the canonical set. contract-repoTS client now exposes the same canonical collection union; source/vendor names remain source evidence only.
Backend Foundation
Section titled “Backend Foundation”- Domain:
backend-repo/src/sanmopia_modernization/domain/pricing_settlement/features/settlement/settlement_data_room.pyandbackend-repo/src/sanmopia_modernization/domain/pricing_settlement/features/settlement/settlement_statement.py - Application handler:
backend-repo/src/sanmopia_modernization/application/pricing_settlement/features/settlement/settlement_data_room.pyandbackend-repo/src/sanmopia_modernization/application/pricing_settlement/features/settlement/settlement_statement.py - Pydantic contract:
backend-repo/src/sanmopia_modernization/application/pricing_settlement/features/settlement/settlement_data_room_contract.pyandbackend-repo/src/sanmopia_modernization/application/pricing_settlement/features/settlement/settlement_statement_contract.py - Other-post resource board foundation:
backend-repo/src/sanmopia_modernization/domain/document_reporting/features/branch_resource_post/branch_resource_post.pyandbackend-repo/src/sanmopia_modernization/application/document_reporting/features/branch_resource_post/branch_resource_post_contract.py - Contract repo:
contract-repo/packages/ts-client/src/types/settlement-data-room.tscontract-repo/packages/ts-client/src/types/settlement-statement.tscontract-repo/schemas/reservation-settlement/settlement_data_room_request.schema.json,contract-repo/schemas/reservation-settlement/settlement_workspace_revision_conflict.schema.json,contract-repo/schemas/reservation-settlement/settlement_workspace_conflict_resolution_request.schema.json, andcontract-repo/schemas/reservation-settlement/settlement_workspace_conflict_resolution_decision.schema.json - Supabase persistence and HTTP runtime:
backend-repo/src/sanmopia_modernization/adapters/pricing_settlement/features/settlement/supabase_settlement_data_room.py,backend-repo/src/sanmopia_modernization/interfaces/settlement_data_room_api.py,backend-repo/src/sanmopia_modernization/interfaces/settlement_data_room_http.py, andbackend-repo/supabase/migrations/20260702211000_settlement_data_room_persistence.sql - Workspace runtime:
backend-repo/src/sanmopia_modernization/domain/pricing_settlement/features/settlement_data_room_workspace/settlement_data_room_workspace.py,backend-repo/src/sanmopia_modernization/application/pricing_settlement/features/settlement_data_room_workspace/settlement_data_room_workspace.py,backend-repo/src/sanmopia_modernization/interfaces/settlement_data_room_workspace_api.py,backend-repo/src/sanmopia_modernization/interfaces/settlement_data_room_workspace_http.py,backend-repo/src/sanmopia_modernization/adapters/pricing_settlement/features/settlement_data_room_workspace/supabase_settlement_data_room_workspace.py, andbackend-repo/supabase/migrations/20260703201935_settlement_data_room_workspace_runtime.sql. This runtime addssanmopia_settlement_data_room_workspacesandsanmopia_settlement_data_room_template_policiesas backend-owned Supabase tables with explicit service-role grants, RLS, JSONB aggregate snapshots, and queryable collection/scope/revision columns. - Workspace conflict proof:
SettlementWorkspaceRevisionConflictexposes stale field diffs with latest actor/audit evidence, whileSettlementWorkspaceConflictResolutionRequestandSettlementWorkspaceConflictResolutionDecisionforce branch/HQ operators to choosekeep_current,apply_submitted, ormerge_explicit. System workflow cannot silently resolve stale UI writes, and public TS/JSON contracts expose the same shape for frontend conflict UX. - Workspace conflict runtime binding:
SettlementWorkspaceConflictResolutionHandler,SettlementDataRoomWorkspaceApi.resolve_conflict,POST /settlement-data-room-workspaces/{workspaceCode}/conflict-resolutions,SupabaseSettlementWorkspaceConflictResolutionDecisionStore, andsanmopia_settlement_workspace_conflict_resolution_decisionsnow persist explicit branch/HQ field-winner decisions by idempotency key. The table is service-role-only, RLS-enabled, and stores queryable workspace/collection, actor, before/after revision, reason, source audit references, field paths, and immutable decision JSONB so later workspace changes do not rewrite the operator-visible resolution. - Hardened proof:
ready artifact handoff must match the request’s frozen
datasetRevision; failed Storage signing does not appendissue_download_link; successful download actions journalexpiresAt,storageBucket,storageObjectKey, anddownloadNamewhile response payload exposes only the signed URL and file/hash metadata.
Current boundary:
SettlementDataRoomCollectionSettlementDataRoomScopeSettlementDataRoomRequestSettlementDataRoomArtifactSettlementDataRoomActionEntrySettlementDataRoomCommandHandlerOpenSettlementDataRoomExportRequestCommandStartSettlementDataRoomBuildCommandMarkSettlementDataRoomArtifactReadyCommandRequestSettlementDataRoomRepairCommandIssueSettlementDataRoomDownloadLinkCommandPOST /settlement-data-room-export-requestsGET /settlement-data-room-requests/{settlementDataRoomRequestId}POST /settlement-data-room-requests/{settlementDataRoomRequestId}/buildsPOST /settlement-data-room-requests/{settlementDataRoomRequestId}/ready-artifactsPOST /settlement-data-room-requests/{settlementDataRoomRequestId}/repair-requestsPOST /settlement-data-room-requests/{settlementDataRoomRequestId}/download-handoffsSupabaseSettlementDataRoomRequestRepositorySettlementDataRoomApiSettlementDataRoomAuthorizationServicesanmopia_settlement_data_room_requestssanmopia_settlement_data_room_artifactssanmopia_settlement_data_room_actionsSettlementWorkspaceSettlementWorkspaceScopeSettlementArtifactRequestSettlementArtifactVersionSettlementArtifactGrantDownloadHandoffAuditSettlementRepairRequestOperatorReturnStateTokenBulkExportTemplatePolicySettlementDataRoomWorkspaceServiceSettlementDataRoomWorkspaceApiSettlementDataRoomWorkspaceAuthorizationServiceSupabaseSettlementDataRoomWorkspaceRepositorySupabaseSettlementDataRoomWorkspaceTemplatePolicyReaderGET /settlement-data-room-workspaces/{workspaceCode}?collection=...POST /settlement-data-room-workspaces/{workspaceCode}/artifact-requestsPOST /settlement-data-room-workspaces/{workspaceCode}/repair-requestsPOST /settlement-data-room-workspaces/{workspaceCode}/grant-handoffsPOST /settlement-data-room-workspaces/{workspaceCode}/return-statesanmopia_settlement_data_room_workspacessanmopia_settlement_data_room_template_policiesSettlementStatementSettlementRemittanceAccountSnapshotSettlementTransitionAuditSettlementStatementManualRowSettlementStatementCommandHandlerRequestSettlementDepositCommandAddManualSettlementRowCommandAcknowledgeBranchSettlementDepositCommandApproveHeadquartersSettlementCommandRequestSettlementArrearsDepositCommandGET /settlement-statements/{settlementStatementId}POST /settlement-deposit-requestsPOST /settlement-manual-rowsPOST /settlement-branch-deposit-acknowledgementsPOST /settlement-headquarters-settlement-approvalsPOST /settlement-arrears-deposit-requestssanmopia_settlement_statement_manual_rows
Target UX
Section titled “Target UX”sequenceDiagram
autonumber
actor BranchOperator as BranchOperator
actor HeadquartersOperator as HeadquartersOperator
participant Portal as Operator Portal
participant API as Backend API
participant Workflow as Restate Export Workflow
participant Storage as Supabase Storage
participant DB as Supabase Postgres
BranchOperator->>Portal: Open settlement workspace
Portal->>API: GET /settlement-data-room-workspaces/{code}?collection=...
API->>DB: Read workspace snapshot and active template policy
API-->>Portal: workspace, revision, template policy
HeadquartersOperator->>Portal: Request headquarters settlement export
Portal->>API: POST /settlement-data-room-export-requests
API->>DB: Store request revision 1 and action journal
API-->>Portal: requestId, status=requested
API->>Workflow: Start export build from frozen dataset
Workflow->>API: POST /settlement-data-room-requests/{id}/builds
API->>DB: status=building, revision=2
Workflow->>Storage: Write artifact to business-report-exports
Workflow->>API: POST /settlement-data-room-requests/{id}/ready-artifacts
API->>DB: Attach artifact, status=ready, revision=3
BranchOperator->>Portal: Open settlement data room
Portal->>API: POST /settlement-data-room-workspaces/{code}/artifact-requests
API->>DB: Append artifact request with deterministic idempotency code
API-->>Portal: workspace revision and artifact request
BranchOperator->>Portal: Download
Portal->>API: POST /settlement-data-room-workspaces/{code}/grant-handoffs
API->>DB: Issue grant and journal signed handoff
API-->>Portal: grant reference, audit id, expiry
BranchOperator->>Portal: Report mismatch
Portal->>API: POST /settlement-data-room-workspaces/{code}/repair-requests
API->>DB: Append repair request and preserve artifact history
BranchOperator->>Portal: Return from detail page
Portal->>API: POST /settlement-data-room-workspaces/{code}/return-state
API->>DB: Consume one actor-bound return-state token
HeadquartersOperator->>Portal: Request deposit
Portal->>API: POST /settlement-deposit-requests
API->>DB: Save SettlementStatement revision 1 and request audit
BranchOperator->>Portal: Acknowledge deposit by settlement line
Portal->>API: POST /settlement-branch-deposit-acknowledgements
API->>DB: Save line acknowledgements and revision 2
BranchOperator->>Portal: Retry same acknowledgement
Portal->>API: POST /settlement-branch-deposit-acknowledgements
API-->>Portal: Return committed revision 2 from idempotency key
HeadquartersOperator->>Portal: Approve headquarters settlement
Portal->>API: POST /settlement-headquarters-settlement-approvals
API->>DB: Save approval audit and settled or arrears status
UX requirements:
- BranchOperator and HeadquartersOperator portals show one settlement statement with actor-specific commands, not separate duplicated screens with hidden conditions.
- System workflow is the only actor allowed to start builds and mark artifacts ready; BranchOperator and HeadquartersOperator actors request exports, download handoffs, and repair actions through optimistic revisions.
- Download button shows build status, failure reason, retry/repair action, and last generated artifact; no hidden iframe and no branch/export token in the browser URL.
- Frontend settlement/export flows use authenticated reads for branch/HQ scope and request short-lived signed download handoffs only when the operator clicks download.
- Repair never deletes previous artifacts. New artifact supersedes old artifact with audit trail, and repair invalidation revokes active grants for the stale artifact version.
- BranchOperator never sees
HeadOfficePrivateMemo; status changes cannot change memo visibility. - Headquarters settlement approval is separate from branch deposit
acknowledgement. Branch acknowledgement records
SettlementStatementLineAcknowledgementper settlement line so missing fees, membership dues, delivery fees, and adjustments are not hidden in one boolean. - Headquarters manual etc rows are now
AddManualSettlementRowcommands withSettlementStatementManualRow, actor kind, idempotency key, expected revision, and before/afterSettlementTransitionAudit; they are only mutable before branch acknowledgement. Remaining slice: generated contract handoff and operator UI for pending manual settlement rows. Source context that must remain visible in UI/API: manual row name, count, unit price, source board id, statement line target, HQ message, private memo, actor, reason, expected revision, and command idempotency key. - Retried statement commands reuse
SettlementTransitionAudit.idempotencyKeyand never append duplicate audits; reusing the same key for a different command kind is rejected. - External-counterparty export requires explicit external recipient code. Inter-office export requires both branch sides in lookup scope.
- Source
DANBEE_STATUS_FLis not current-row truth in the modern model.ReservationExternalCounterpartySettlementStatusstores reservation-scoped completion state, statement reference, board status, lineage evidence keys, and dataset revision in a service-role-only Supabase projection. Branch/HQ reads useGET /reservation-external-counterparty-settlement-statuses/{reservationId}with branch-scope authorization. Internal workflow updates usePOST /internal/reservation-external-counterparty-settlement-status-updatesand reject stale dataset revisions before upserting the projection.
2026-07-10 Refund/Reissue/Approval Delta
Section titled “2026-07-10 Refund/Reissue/Approval Delta”No new SFC ids. These refine existing refund, branch/HQ settlement, data-room artifact, mailbox grant, and approval-conflict rows.
-
Refund-triggered board invalidation must refresh branch/HQ operator projections. Status:
Backend partial. Evidence:source-refs/sanmopia_web/application/models/Payment_model.php:416-430calls provider refund, then only flips the normal/voucher paid row to payment status2;source-refs/sanmopia-admin/application/models/Payment_model.php:3315still includes Danbee settlement rows whose payment status is1or2;source-refs/sanmopia-admin/application/models/Payment_model.php:3504-3516reads branch/HQ board detail rows by board id and admin-branch payment status;source-refs/sanmopia-admin/application/models/Payment_model.php:3579-3594reads coupon board rows with the source payment-status guard commented out; andsource-refs/sanmopia-admin/application/models/Payment_model.php:1086-1307derives branch/HQ operator labels, component flags, completed money, and unpaid money from current board/component flags. Modern gap:RefundAdjustedSettlementBoardInvalidation,BranchSettlementOperatorBoardRefresh,HeadquartersSettlementOperatorBoardRefresh, andSettlementArtifactGrantRevocationAfterRefundmust consume refund transition facts, mark affected statements stale, bump dataset revision, revoke active download grants, and enqueue reissue/repair tasks. Source payment status flips, commented filters, and board flag summaries are evidence only. Backendd478bdbnow routes provider-refund reporting queue work to branch/HQ settlement statement and operator-board read-model refresh validation. Latest settled-refund-impact stage proof booking9700b2e4-0b25-4978-9477-2c864c3f29c1reachedsettled, then provider refund eventstage-provider-refund-result-20260709201933-65135721produced paid-row mutation, settlement reversal, and reporting refresh fanout. Dataset revision bump, stage proof for grant revocation, and artifact reissue history remain pending. Supabase adapter persistence for workspace grant revocation is now regression-covered: saving/loadingSettlementWorkspacePayloadpreserves grantrevoked_by_repair_request_code,revoked_reason, repairrevoked_grant_ids, andreplacement_artifact_request_code. Backend repair planning/persistence is partial:PaymentRefundRepairPlanandSupabasePaymentRefundRepairPlanStorepersist repair cases, permissions, gateway-command payload, andsettlement_invalidation_key. Backend follow-up bindsPaymentRefundRepairHandlerintomain.pyand exposes internalPOST /internal/payment-refund-repairs/provider-refund-plans, so repair planning now has a runtime HTTP boundary. The internalPOST /internal/payment-refund-repairs/provider-refund-executionsroute now calls the configured billing gateway only for new idempotency keys and persists execution attempts with idempotency and source evidence. Matching stored attempts are replayed into the ledger-backed provider-result handler without a second provider call; mismatched replays are rejected. That handler feeds paid-row transition, settlement reversal, and reporting invalidation logic. Retry backoff/operator result-history projection, stage webhook proof, and downstream reporting plus artifact/grant invalidation fanout from executed repair results remain unproven. -
Data-room artifact reissue/revocation needs explicit invalidation lineage. Status:
Backend partial. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:568-578exports by rawexcelTypeandboardId;source-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3911reloads mutable board rows, recalculates fees, streams the workbook, and exits;source-refs/sanmopia-admin/application/controllers/DataRoom.php:85-94exports documents by rawexcelTypeplus reservation ids; andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3914-4198builds XLSX/PDF/ZIP artifacts from current rows and temporary files. Modern gap:SettlementArtifactRevocation,SettlementArtifactReissueRequest,SettlementArtifactSupersessionLink,SettlementArtifactReplacementRequestLink, andDocumentExportArtifactGrantRevokedmust persist invalidation reason, refund/provider-result id, affected statement revision, previous artifact id, revoked grant ids, replacement request id, and actor/system initiator. Streaming from current rows cannot prove stale artifact refusal or reissue history. Backend partial: data-room artifacts persist dataset revision andsuperseded_at, workspace artifact requests preserve version history, and artifact grants carryrevoked_at. Backend3e6d83fproves the workspace-domain and contract-level refund/repair command behavior that marks active grants revoked and records the replacement artifact request code. Missing slice is persistence/stage proof plus operator-visible lineage from superseded artifact id to replacement request. Backendc1e0904tightens the core repair transition:request_repairnow supersedes the active data-room artifact immediately, journals the superseded artifact id plus supersession reason, and persists that lineage through the Supabase data-room request RPC. Supabase/stage proof for grant revocation, durableSettlementArtifactReplacementRequestLink, and operator-visibleSettlementArtifactReissueLineageProjectionremain pending. 2026-07-10 workspace-domain follow-up: backend3e6d83fSettlementWorkspace.request_repairnow revokes active artifact grants for the invalidated artifact version, recordsrevoked_by_repair_request_codeandrevoked_reasonon each grant, and storesrevoked_grant_idsplusreplacement_artifact_request_codeon the repair request payload. 2026-07-10 Supabase adapter follow-up adds round-trip proof that the workspace JSON row persists that revocation and repair lineage. Remaining work is stage proof and operator-visible reissue lineage projection. -
Document mailbox downloads need grant-use audit and revocation state. Status:
Pending. Evidence:source-refs/sanmopia-admin/application/models/Data_room_model.php:85-99loads attachmentURLvalues;source-refs/sanmopia-admin/application/views/data_room/other_post_view.php:78-84renders direct<a href=... download>links;source-refs/sanmopia-admin/static/js/data_room/other_post_write.js:11-63posts attachment uploads and deleted file ids;source-refs/sanmopia-admin/static/js/data_room/other_post_write.js:97-108marks file ids for deletion in browser state; andsource-refs/sanmopia-admin/application/models/Data_room_model.php:163-179deletes attachment DB rows and physical files. Modern gap:DocumentMailboxAttachmentDownloadGrant,DocumentMailboxAttachmentGrantUseAudit, andDocumentMailboxAttachmentRevocationmust bind actor, post revision, participant branch scope, attachment version, expiry, use timestamp, revoke reason, and retained storage object key. Direct file URLs and physical delete side effects are evidence only. -
Branch/HQ approval conflicts need command-level conflict logs, not only workspace field-winner decisions. Status:
Pending. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:219-276changes HQ-side branch-settlement state based on current board status;source-refs/sanmopia-admin/application/controllers/Calculate.php:279-309lets branch acknowledgement mutate board/component flags;source-refs/sanmopia-admin/application/models/Payment_model.php:25-32logs before/after values but drops the passed board id;source-refs/sanmopia-admin/application/models/Payment_model.php:2977-3030computes board status without expected revision; andsource-refs/sanmopia-admin/application/models/Payment_model.php:4382-4419derives completion from current component counts. Modern gap:SettlementActorApprovalAttempt,SettlementApprovalConflictLog, andSettlementApprovalConflictDecisionmust record rejected stale attempts, expected revision, latest revision, actor grant, idempotency key, before/after projection hashes, conflicting field paths, selected resolution, and reason. Control-lane refinement:insertLog($branchId, $boardId, ...)receives a board id but does not persist it, so refund/repair impact cannot reliably link a stale branch/HQ approval attempt to the exact statement revision, artifact request, or later grant revocation. Modern commands must emitSettlementTransitionAudit,SettlementApprovalProvenanceSnapshot, andRefundRepairSettlementImpactJournalin the same transaction that mutates the settlement statement. Approval command conflicts are separate from settlement workspace edit conflicts; both must remain queryable for audit.
2026-07-03 Source Delta Queue
Section titled “2026-07-03 Source Delta Queue”-
Branch, headquarters, Danbee, and inter-office settlement ownership. 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/Calculate.php:70-150,source-refs/sanmopia-admin/application/models/Payment_model.php:2657-2814,source-refs/sanmopia-admin/application/models/Payment_model.php:2916-2972, andsource-refs/sanmopia-admin/application/models/Payment_model.php:4225-4238. Source behavior: branch menus, HQ menus, Danbee boards, and other-office boards are separate screens, but detail logic still depends onDANBEE_STATUS_FL,OTHER_OFFICE_STATUS_FL,BRANCH_TYPE, actor type, and current branch id. Other-office rows split service office and customer handoff office, while HQ and Danbee status are read from different payment tables. Modern gap:SettlementStatementKind,SettlementDataRoomCollection,ReservationExternalCounterpartySettlementStatus, andInterOfficeSettlementLookupKeymust keep these concepts separate through command, read model, export, and repair workflows. Branch acknowledgement, HQ approval, external-counterparty export readiness, and inter-office service/customer-relationship branch acknowledgement must not share one boolean, one board id, or one mutable source flag. -
Settlement statement typed command context split. Status:
Backend/contract foundation. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:70-150,source-refs/sanmopia-admin/application/controllers/Calculate.php:337-430, andsource-refs/sanmopia-admin/static/js/calculate_detail.js:276-285. Source behavior: one request payload mixes branch id, board id, actor type, line ids, coupon ids, membership/delivery booleans, manual etc rows, public branch message, private headquarters memo, and caller-provided total amounts. Modern replacement:SettlementStatementCommandContextinapplication/pricing_settlement/features/settlementas a typed context that carries statement id, statement kind, branch profile id, actor, expected revision, idempotency key, and selected settlement line references. It should build existing settlement commands such asAcknowledgeBranchSettlementDepositCommandwithout trusting caller totals.messageToBranchandheadOfficePrivateMemostay separate; branch acknowledgement cannot carry the private memo. Selected line refs must be non-empty for branch acknowledgement and must use settlement line kinds instead of source booleans such as coupon/cancel/member flags. EachSettlementStatementLineAcknowledgementmay now carrysourceEvidenceKey, and Supabase persists it onsanmopia_settlement_statement_line_acknowledgements. -
Collection-specific export reader parity. Status:
Pending. 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/Calculate.php:568-578, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:3741-3914. Source behavior: branch data room loadscalculate_central,calculate_danvi, andcalculate_danvi_other_officeboard summaries directly, while export uses rawexcelType/boardIdGET. The other-office data-room route readsfyear/fmonthbut comments out the period bounds and calls the reader withNULL, NULL, while the reader only applies date filters when explicit bounds are supplied (source-refs/sanmopia-admin/application/controllers/DataRoom.php:279-293;source-refs/sanmopia-admin/application/models/Payment_model.php:2684-2704). Modern gap: eachSettlementDataRoomCollectionneeds its own export reader, frozen dataset revision, canonical period scope, column contract, artifact request id, and signed download handoff. HQ-to-branch export must not accidentally read Danbee board tables or branch-wide unbounded other-office rows. -
Reservation document export worklist parity. Status:
Pending. 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/static/js/data_room/form_reservation_list.js:1-80,source-refs/sanmopia-admin/application/models/Statistics_model.php:873-895, andsource-refs/sanmopia-admin/application/models/Payment_model.php:228-231. Source behavior: the browser asks for a DataTables server-side list, but the controller loads reservation rows first, then searches, sorts, and slices in PHP memory. Document eligibility also lives in a controller switch by form id, service type, voucher end marker, and report type. Modern gap:ReservationDocumentExportWorklistmust push branch/HQ visibility, template eligibility, search, sort, pagination, status filters, and report kind into a database-backed read model with an expected revision and selection token. The portal should submit an immutable export selection, not a mutable list of checked reservation ids rebuilt from current rows. Status filters must keep12stop-requested and13stopped distinct, and stopped voucher rows must use the source-mined >=3 elapsed-service-span eligibility rule instead of UI-side status filters. Backend now owns the rule inReservationSettlementEligibilityRule: source status13is eligible only whenSettlementServicePeriod.elapsed_days()is at least3, matching MySQLDATEDIFF(end, start)semantics.is_voucher_settlement_worklist_eligiblekeeps the Statistics-model worklist selector separate from headquarters settlement, because source worklist status inclusion differs. Remaining acceptance: settlement/export readers must call the shared backend rule and include stopped voucher reservations only when status is13andDATEDIFF(SERVICE_END_DT, SERVICE_START_DT) >= 3, matchingsource-refs/sanmopia-admin/application/models/Statistics_model.php:875-893andsource-refs/sanmopia-admin/application/models/Payment_model.php:228-231. Do not reinterpret this as a count of attendance or daily-report rows unless a new domain policy version explicitly changes the source rule. -
Branch resource post storage and audit parity. Status:
Backend foundation contracted. Evidence:source-refs/sanmopia-admin/application/controllers/DataRoom.php:119-212andsource-refs/sanmopia-admin/application/models/Data_room_model.php:25-203. Source behavior: other-post routing depends on null branch ids and the headquarters branch id; create/update uploads files during the same request, deletes selected files immediately, and board removal hard-deletes rows plus filesystem paths. Modern replacement:BranchResourcePost,BranchResourceAttachmentVersion, andBranchResourceGrantuse explicit headquarters, branch, and all-branches sender/recipient scopes instead of null-routing or a fixed headquarters branch id. Commands now require actor, idempotency key, caller-supplied time, and expected post revision for mutations. Attachment versions supersede instead of replacing files in place; revoked attachments and retained/revoked posts deny signed download grants. Retention keeps business records addressable for audit, and application contracts are Pydantic-only at the boundary. Remaining proof: Supabase tables/storage policies, signed URL adapter, HTTP API, generated clients, and portal UI. -
Inter-office branch-side acknowledgement. Status:
Backend/API contract foundation. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:337-369,source-refs/sanmopia-admin/application/controllers/Calculate.php:376-430,source-refs/sanmopia-admin/application/controllers/Common.php:156-198, andsource-refs/sanmopia-admin/static/js/calculate_detail.js:276-285. Source behavior: oneotherOfficedetail page changes behavior by actor andfbranch-type; branch users update only board status, while HQ first updates reservation other-office settlement status and inserts detail. Modern gap:InterOfficeSettlementnow has branch-facing line projection forinter_office_branch_shareandinter_office_service_fee, and service-fee projection requires explicit charged-branch evidence. Branch acknowledgement now accepts typedInterOfficeSettlementAcknowledgementevidence through the application and HTTP boundary, validates service-delivery versus customer-relationship side, actor, expected revision, dataset revision, and projected line ids, then writes that evidence into transition-audit metadata. Remaining proof: bind live Danbee/operator boards and portal actions to this command path instead of sourcefbranch-type/OTHER_OFFICE_STATUS_FL. -
Settlement detail navigation state. Status:
Pending. Evidence:source-refs/sanmopia-admin/static/js/calculate_detail.js:297-310,source-refs/sanmopia-admin/static/js/calculate_detail.js:329-337, andsource-refs/sanmopia-admin/application/controllers/Calculate.php:460-498. Source behavior: successful settlement command redirects todocument.referrerwhen present, and history/export pages read GET filters. Modern gap: settlement command responses should include return-state token, list filters, current statement revision, and next visible action. Browser referrer cannot be source of record for branch/HQ settlement operations. -
Data-room document bundle export selection. Status:
Pending. Evidence:source-refs/sanmopia-admin/application/views/data_room/form_reservation_list.php:131,source-refs/sanmopia-admin/application/views/data_room/form_reservation_list.php:207,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:62,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:219,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:225,source-refs/sanmopia-admin/application/controllers/DataRoom.php:312-332,source-refs/sanmopia-admin/application/controllers/DataRoom.php:354,source-refs/sanmopia-admin/application/controllers/DataRoom.php:368,source-refs/sanmopia-admin/application/config/constants.php:217, andsource-refs/sanmopia-admin/application/models/Spreadsheet_model.php:4117. Source behavior: selected reservation ids are posted through a hidden iframe and streamed immediately.index == 16expands into a document bundle by source service labels such as바우처and일반, with controller-side document id switches. The source posts keyed hiddenreservation[service_type][id], enforces a single selected row in JavaScript, and deletes temp XLSX/PDF files after ZIP creation. Voucher bundles use source document ids1,3,4,5,6,20,7,8,9,10,11,15,17,21; normal bundles repeat the same six ids twice because raw ids and constants are both appended. Unknown service type returns존재하지 않는 서비스 유형입니다.. Modern gap:DocumentBundleExportRequestmust become an immutable backend request with explicit reservation selection token, service-kind decision, template/catalog version, artifact build id, and signed grant. The portal must not pick document ids, trust hidden service-type inputs, duplicate bundle membership, or use hidden POST-download frames. -
Settlement/data-room export UX workflow authority. Status:
Pending. Evidence:source-refs/sanmopia-admin/application/controllers/DataRoom.php:30-94,source-refs/sanmopia-admin/application/controllers/DataRoom.php:218-250,source-refs/sanmopia-admin/application/controllers/DataRoom.php:268-386,source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:17-240,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:1-260,source-refs/sanmopia-admin/application/views/table/data_room/table_calculate_central.php:1-69, andsource-refs/sanmopia-admin/application/views/table/data_room/table_calculate_danvi.php:1-57. Source behavior: reservation document worklists are filtered, searched, sorted, and paginated after the controller loads candidate rows; the branch filter lives in the URL hash; selected rows are posted through a hidden iframe; settlement data-room pages read current board summaries directly and expose raw export parameters. Modern gap:ReservationDocumentExportWorklist,SettlementDataRoomCollectionExportReader,SettlementArtifactVersion, andDownloadHandoffAuditneed to own query scope, selection token, dataset revision, bundle/template policy, artifact build state, signed grant, failed-build repair history, return-state token, and next visible action. UI cannot be source of record for filters, checked ids, board ids, or download success.2026-07-05 persistent-worker tightening:
Missing backend policy Source evidence Source behavior Modern target Worklist query authority source-refs/sanmopia-admin/application/controllers/DataRoom.php:30-94,source-refs/sanmopia-admin/application/controllers/ajax/DataRoom.php:14-240,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:26-162Controller receives DataTables params but loads candidate rows, then searches, sorts, and slices in PHP memory. Browser sends branch/date/form ids and maps raw row ids into checkboxes and hidden service-type inputs. ReservationDocumentExportWorklistQuerymust own branch/HQ scope, template eligibility, search, sort, pagination, status filters, result revision, and row selection ids in a DB-backed read model.Export selection and bundle membership 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:62-80,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:200-261,source-refs/sanmopia-admin/application/controllers/DataRoom.php:312-385UI posts mutable checked reservation ids through a hidden iframe; index == 16trusts hidden service type and expands source document ids in controller code.Backend foundation exists: ReservationDocumentExportWorklist,ReservationDocumentExportWorklistCriteria,ReservationDocumentExportSelectionToken, andReservationDocumentExportArtifactRequestfreeze reservation ids, document definition keys, actor scope, source collection, period/filter keys, and artifact request idempotency behind a SHA-256 criteria fingerprint. Remaining work: DB-backed worklist query authority, service-kind/template eligibility, bundle membership policy, worker handoff, and signed grant lifecycle.Download authority and artifact lifecycle source-refs/sanmopia-admin/application/controllers/DataRoom.php:85-94,source-refs/sanmopia-admin/application/controllers/DataRoom.php:388-418,source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:224-261Raw GET export params and POST iframe submissions stream files directly from current DB rows with no durable artifact, retry, expiry, use audit, or stale dataset rejection. SettlementArtifactVersion,DocumentExportArtifactVersion,SettlementArtifactGrant, andDownloadHandoffAuditmust issue signed expiring grants against immutable artifacts and record build, ready, failure, retry, supersession, and grant-use events.Return-state and filter authority source-refs/sanmopia-admin/static/js/data_room/form_reservation_list.js:163-195,source-refs/sanmopia-admin/application/controllers/DataRoom.php:47-69,source-refs/sanmopia-admin/application/controllers/DataRoom.php:268-308Browser rebuilds query strings for branch/date filters and settlement collection pages read current branch/month board rows directly. One JS path even rebuilds end_datequery text without a stable token.OperatorReturnStateTokenandSettlementDataRoomCollectionWorklistQuerymust preserve filters, collection, branch scope, month/date window, current dataset revision, and next visible action after export/repair/download. -
Settlement board role split and completion gate. Status:
Partial. Evidence:source-refs/sanmopia-admin/application/controllers/Calculate.php:126,source-refs/sanmopia-admin/application/models/Payment_model.php:554,source-refs/sanmopia-admin/application/models/Payment_model.php:2731,source-refs/sanmopia-admin/application/models/Payment_model.php:2917, andsource-refs/sanmopia-admin/application/models/Payment_model.php:4265. Source behavior: Danbee writesBOARD_PAYMENT_DANBEE_TBand flips reservation/couponDANBEE_STATUS_FL; branch-to-HQ settlement writes board/detail/coupon/etc tables; inter-office service-side and customer-relationship side use separateDANBEE_STATUS_FLandOTHER_OFFICE_STATUS_FLflags. Full completion may depend on all three payment rows carrying both flags. Modern gap:ExternalCounterpartySettlementBatch,HeadquartersBranchSettlementStatement, andInterOfficeSettlementCasemust keep separate statement revisions and completion gates. Do not collapse these source flags into one board status. Additional source dig:Payment_model::updateBoardIdstarts branch-to-HQ board status at1, may move to3for arrears, and only moves to2whengetCompleteFlagCountFromBoard()returns0. That counter filters detail rows wherePAYMENT_TYPE_LIST_ID_FK = 0, but current source writers insert selected UI payment-type ids and no writer for type0was found. Modern gate should prefer the canonicalgetFlagCountFromBoard(..., 'is_complete')all-flags-and-no-open-detail behavior while keeping type-0 as adapter-only legacy evidence. -
Caregiver service-balance approval route parity. Status:
Partial. Evidence:source-refs/sanmopia-admin/static/js/manager/manager_pay_inquiry.js:254,source-refs/sanmopia-admin/application/controllers/Manager.php:1057, andsource-refs/sanmopia-admin/application/models/Reservation_model.php:2453. Source behavior: manager service-balance approval has two axes:PAYMENT_STATUS_ID_FK/SUB_PAYMENT_STATUS_ID_FKandBALANCE_PRICE_PAYMENT_FL/SUB_BALANCE_PRICE_PAYMENT_FL. The UI showsrequire,check, andcomplete, while backend can move reservation status between5and6. Modern gap:CaregiverServiceBalanceApprovalmust preserve main/sub caregiver role, payout statement reference, expected revision, approval actor, and resulting reservation-status side effect. Additional source dig:/reservation/serviceBalanceConfirmis stale JavaScript path with no verified route alias; actual reachable path is/reservation/confirmServiceBalance, which setsSERVICE_BALANCE_PRICE,SERVICE_BALANCE_CONFIRM_FL = 1, andSERVICE_BALANCE_PRICE_USE_FL = 1. The stale model method only flipsSERVICE_BALANCE_CONFIRM_FL. Modern command must preserve the actual three-field closeout and mark the stale path as migration compatibility evidence, not product API.