DDD Application Contract Folder Audit
DDD Application Contract Folder Audit
Section titled “DDD Application Contract Folder Audit”Audit date: 2026-07-05 KST.
Source of truth: standard.md. Fixed architecture priority is DDD, bounded
context, feature slice, CQRS, contract-first, Tach boundaries, and
Supabase-first platform choices.
Inspected scope:
backend-repo/src/sanmopia_modernization/applicationbackend-repo/src/sanmopia_modernization/adaptersas current infrastructure surface. Requestedbackend-repo/src/sanmopia_modernization/infrastructuredoes not exist.contract-repo/schemascontract-repo/openapibackend-repo/tach.toml
Not run: full pytest. Not edited: backend, contract, frontend. Existing backend and contract dirty work was left untouched.
Snapshot
Section titled “Snapshot”| Surface | Observed |
|---|---|
| Application Python files | 416 |
| Application feature folders | 70 |
| Adapter Python files | 273 |
| Adapter feature folders | 33 |
| Contract JSON schemas | 105 |
| Public OpenAPI paths / operations | 69 paths / 68 operations |
| Internal OpenAPI paths / operations | 3 paths / 3 operations |
| Tach dependency/interface gate | tach check --dependencies --interfaces --exact passed |
| Tach external gate | Parent verification uv run tach check-external passed |
Highest-Risk Findings
Section titled “Highest-Risk Findings”- Infrastructure naming drift exists. The task asked for
infrastructure/, the repo usesadapters/, andstandard.mdcontains both adapter-shaped backend trees and final wording that says infrastructure. Decide one canonical term before tightening Tach layers. - Tach does not cover all adapter contexts.
tach.tomlhas modules for broadadapters,branch_operations,platform,document_reporting,care_delivery, andpricing_settlement, but no modules for currentadapters.customer_engagement,member_management,reservation_booking,reservation_operations,caregiver_assignment,service_calendar,notification, or flatreservation. - External dependency metadata needs continued watch. Worker-local audit
initially flagged ReState/OTEL metadata drift, but parent verification on the
current worktree passed
uv run tach check-external. Keep ReState/OTEL imports behind platform adapters and rerun the parent gate after Tach module expansion. - Application has no direct
application -> adapters/interfacesimports, which is good. The first payment provider naming leak was reduced on 2026-07-05: the application port is nowapplication/pricing_settlement/features/payment/payment_gateway_client.py, withPaymentGatewayClientandPaymentGatewayResultnames. Remaining provider names should stay in provider adapters, internal APIs, webhooks, and source-evidence docs only. - Contract folder aliases are now explicit in
scripts/check_contract_layout.mjs.reservation-settlementis a stable public API alias for backendpricing_settlement;reservation-bookingspansreservation_orchestrationandreservation_operations; andcaregiver-portalmaps tocare_deliverycaregiver work-schedule projections. New schema groups must declare their backend-context alias. - Contract
$iddrift was resolved on 2026-07-05. Schema ids now use canonicalhttps://contracts.sanmopia.local/schemas/<schema-relative-path>, andscripts/check_contract_layout.mjsrejects mismatched$idvalues. - OpenAPI auth scheme drift was resolved on 2026-07-05. Components define
supabaseBearerAuth,/killbill-payment-admin-operationsnow uses that same scheme, andscripts/check_contract_layout.mjsrejects undefined OpenAPI security scheme references in public and internal API specs. - Campaign publication domain storage validation was reduced on 2026-07-05:
campaign_publication.pynow validates provider-neutral managed storage artifact references instead of Supabase-specific media URLs. Supabase object mapping remains an adapter/CMS concern.
Folder-By-Folder Findings
Section titled “Folder-By-Folder Findings”Application
Section titled “Application”| Folder | Finding | Boundary / CQRS action |
|---|---|---|
application/branch_operations | Good context/features shape. Contract group branch-operations exists. | Keep command-style branch mutations separate from profile/snapshot reads. |
application/business_reporting | Reporting context exists, but no matching contract schema group. | Add contract group only for public reporting API. Otherwise keep internal read models out of contract repo. |
application/care_delivery | Broad context with daily report, attendance, confirmation, notification obligation, and caregiver work schedule. | Split read projections such as caregiver_work_schedule from write commands such as attendance/report submission. |
application/caregiver_assignment | Matching feature contains repository/query ports and contracts. | Separate optimizer input query models from command-side snapshot persistence ports. |
application/caregiver_management | Small credential dossier slice. No matching contract group. | If exposed externally, create caregiver-management schemas; otherwise keep internal. |
application/caregiver_performance_recognition | Separate context exists while care_delivery/features/caregiver_performance_recognition also exists. | Resolve duplicate bounded-context ownership before adding more scorecard/grade APIs. |
application/content_management | Attachment lifecycle context exists, but no matching contract group. | Decide if this belongs under customer_engagement/content_authoring or remains independent content context. |
application/customer_engagement | Campaign, guidance, communication, authoring, and lead intake live together. Communication code has Novu vocabulary in application contracts/tests. | Keep provider-specific Novu concerns in adapters; expose generic communication dispatch ports from application. |
application/document_reporting | Mature feature-slice shape around catalog, delivery, document room, printable document, and access. | Split document read catalogs/rooms from signed-access and render commands. |
application/member_management | Family account and privacy lifecycle exist. Contract group member-management exists. Privacy lifecycle mixes plan, purge workflow, repair history, and receipt projection. | Split member withdrawal command, receipt query, purge workflow, and repair command files. |
application/migration_governance | Source evidence reconciliation exists. Internal OpenAPI has source evidence endpoint. | Keep internal-only; avoid public contract expansion unless migration evidence becomes product API. |
application/operator_access | Operator identity session exists without contract group. | Decide whether this is auth/session bounded context or platform concern. |
application/platform | Supabase platform ports exist, but OPA, SpiceDB, and Restate vocabulary also live in application platform. | Supabase-first exception required for OPA/SpiceDB/ReState. Keep concrete HTTP and SDK details in adapters. |
application/pricing_settlement | Largest app area. Payment and settlement carry many commands, workflows, read models, contracts, and provider events. Contract group reservation-settlement is an explicit stable public alias for this backend context. | High priority CQRS split: payment commands/events, payment queries/projections, settlement commands, settlement read boards, export workflows. |
application/reservation_operations | Wide operational context with booking facts, collaboration, service calendar, suspension, admin lifecycle, continuation. | Split collaboration command/query, service calendar read model vs decisions, suspension command vs persistence port. |
application/reservation_orchestration | Cross-context orchestration imports many domains and the provider-neutral PaymentGatewayClient application port. Tach explicitly allows pricing_settlement.features.payment. | Treat as process manager. Keep only orchestration commands/workflows here; avoid owning payment provider or adapter details. |
application/service_calendar | Separate service calendar context exists while reservation operations also owns service-calendar features. | Resolve ownership: shared calendar policy context or reservation-scoped calendar feature, not both without clear rule. |
application/shared_kernel | Small shared reference model. | Keep small. Do not let shared kernel become cross-context dumping ground. |
Application checks:
- No direct imports from
sanmopia_modernization.adaptersorsanmopia_modernization.interfaceswere found underapplication/. *_persistence.pyand repository files checked in sampled slices are Protocol ports, not concrete SQL/Supabase implementations. Keep that rule.test_*.pyfiles were not found in scoped application/adapters paths;*_test.pynaming is used.
2026-07-05 CaveCrew follow-up queue:
| Folder | Drift | Target |
|---|---|---|
application/platform | Supabase/SpiceDB/ReState names define application ports and types. | Rename toward WorkflowPort, AuthorizationPort, QueuePort, and keep provider implementations in adapters. |
application/customer_engagement/features/communication_delivery | Workflow catalog validates Supabase row, Strapi authoring, and Novu workflow terms together. | Split provider-neutral CommunicationWorkflowCatalog from CommunicationProviderSeedAdapter. |
application/pricing_settlement/features/payment | Kill Bill ExtBusEvent normalization, internal callback admission, atomic Supabase inbox/PGMQ registration, conflict quarantine, and gateway orchestration share one application slice. Kill Bill provides no callback signature. | Keep provider payload parsing in adapter ACL, application acceptance/ingestion in the payment feature, and business payment/refund decisions in domain/application policies. Extract a provider-neutral inbox only when a second provider proves shared semantics. |
application/pricing_settlement/features/financial_lifecycle | Mother-visible charges, payment totals, discounts, balances, and mismatch calculations live in application read model code. | Promote arithmetic to domain CustomerChargePaymentProjectionService; application maps query output only. |
application/pricing_settlement/features/settlement | Settlement arithmetic repeats across contract validators, operator-board reads, and calculation snapshots. | Promote SettlementArithmeticService and BranchSettlementCalculator; contracts display validated facts. |
application/member_management/features/member_privacy_lifecycle and settlement workflows | start/transition/fail/complete workflow patterns repeat. | Extract provider-neutral DurableWorkflowLifecycle port/service and let slices provide payload/action policy. |
application/branch_operations/features/office_profile | Profile update, lifecycle, settlement account, fee policy, credential, and query share one contract surface. | Split into office_profile_update, settlement_account, membership_fee_policy, operator_credential, and office_profile_query. |
application/pricing_settlement/features/settlement_data_room_workspace | Many commands, query handler, grant, repair, and build concerns share one file; DataRoom/Workspace is weak domain language. | Split artifact request/build/grant/handoff/query/repair slices; domain target is SettlementArtifactCollection. |
application/reservation_operations/features/reservation_collaboration | Open workspace query, journal query, and browser-event command are mixed. | Split open_workspace_query, collaboration_journal_query, and record_workspace_event_command. |
application/caregiver_assignment/features/care_team_contract | care_team_contract/care_team_contract_contract.py repeats contract terminology. | Rename payload file or feature toward care_team_contracting; keep domain contract and application payload distinct. |
Adapters As Infrastructure
Section titled “Adapters As Infrastructure”| Folder | Finding | Boundary / Supabase-first action |
|---|---|---|
adapters/branch_operations | Mostly context/features aligned, Supabase-backed. Tach covers this broad context. | Keep aligned with application/branch_operations/features/*. |
adapters/care_delivery | Context/features aligned, Supabase-backed. Tach blocks care delivery adapters from pricing app/adapters. | Good guardrail. Extend same pattern to other adapter contexts. |
adapters/caregiver_assignment | Matching adapters exist, but Tach has no explicit module for this adapter context. | Add Tach module and block unrelated adapter contexts. |
adapters/customer_engagement | Communication delivery mixes Supabase persistence and Novu HTTP adapter. It imports pricing payment application types and payment adapter row helpers. | Add Tach module. Keep cross-context payment facts behind application ports or shared contract DTOs. |
adapters/document_reporting | Context/features aligned. Contains Supabase document adapters and HTML print renderer. Tach covers broad document reporting adapter. | Keep renderer as infrastructure. Ensure storage/output remains Supabase Storage first. |
adapters/member_management | Family account and privacy lifecycle Supabase adapters exist, but Tach has no explicit module. | Add Tach module and make privacy lifecycle workflow boundaries explicit. |
adapters/notification | Flat in_memory_notification_gateway.py; no bounded context/features shape. | Move to test/support or create owned notification adapter context with Tach boundary. |
adapters/platform | Supabase HTTP plus OPA, SpiceDB, Restate, OTEL adapters. | Supabase-first exceptions need ADRs. Tach should separate platform ports from concrete external provider adapters. |
adapters/pricing_settlement | Rich feature adapters for payment, settlement, financial lifecycle, pricing, imports. Tach covers several pricing subfeatures. | Continue subfeature Tach coverage; check KillBill adapter isolation and avoid leaking provider types into application APIs. |
adapters/reservation | Flat repository/schema files outside context/features. | Move under adapters/reservation_operations/features/reservation or mark legacy with migration checklist. |
adapters/reservation_booking | Flat composition root and stores. Imports interfaces.reservation_booking_api, pricing payment app ports, and reservation orchestration app service. Tach has no module. | High risk. Move toward adapters/reservation_orchestration/features/reservation_booking or define reservation_booking bounded context consistently across app/domain/contracts/Tach. |
adapters/reservation_operations | Feature adapters exist, including OR-Tools matching and Supabase service calendar/read models. Tach has no explicit module. | Add Tach module. Treat OR-Tools as compute adapter, not data-platform replacement. |
adapters/service_calendar | Holiday audit Supabase adapters exist. Tach has no explicit module. | Add Tach module after service-calendar ownership decision. |
Contracts
Section titled “Contracts”| Folder | Finding | Action |
|---|---|---|
schemas/branch-operations | Matches backend branch_operations. | Good; keep schema IDs normalized. |
schemas/care-delivery | Matches backend care_delivery but only small coverage. | Add only externally exposed care-delivery schemas; avoid dumping every internal model. |
schemas/caregiver-portal | Stable public portal alias mapped to backend care_delivery caregiver work-schedule projection. | Keep alias mapped in layout:check; split later only if caregiver portal grows beyond care-delivery read models. |
schemas/common | Shared money schema. | Keep small and versioned. |
schemas/member-management | Matches backend context; $id host/path is normalized and guarded. | Keep schema ids path-derived. |
schemas/reservation-booking | Stable public booking alias mapped to backend reservation_orchestration and reservation_operations. | Keep alias mapped in layout:check; split later if command/process-manager contracts diverge from reservation-operation read models. |
schemas/reservation-settlement | Stable public settlement alias mapped to backend pricing_settlement. Most OpenAPI refs point here. | Keep alias mapped in layout:check; do not introduce pricing-settlement without a migration plan for public refs and generated clients. |
schemas/workflow-status | Platform workflow projection schema. | Keep platform-facing; avoid leaking ReState if workflow engine can change. |
openapi/public-api.yaml | Customer, branch, operator, and workflow-facing operations only. layout:check rejects provider/internal KillBill paths here. | Keep provider webhook/admin paths out of the public API. |
openapi/internal-api.yaml | Internal settlement build/ready-artifact operations, source evidence, and provider-owned KillBill webhook/admin operations. | Keep provider-specific operations here unless a separate provider API spec is introduced. |
Missing OpenAPI refs: none found.
CQRS Split Candidates
Section titled “CQRS Split Candidates”Prioritize these because they mix commands, queries, workflows, provider events, contracts, and persistence ports inside one feature folder:
| Candidate | Why split | Suggested split |
|---|---|---|
application/pricing_settlement/features/settlement | 38 files; commands, read boards, export workflow, data room, statements, contracts. | commands/*, queries/*, workflows/reconciliation_export, contracts/*, then map adapters one-to-one. |
application/pricing_settlement/features/payment | Payment pre-registration, receipts, change adjustment, workflow, provider event/admin operations. The payment gateway port is now provider-neutral; KillBill remains adapter/internal-provider vocabulary. | Payment command handlers, payment read models, provider webhook ingestion, workflow start/status. |
application/member_management/features/member_privacy_lifecycle | Withdrawal planning, receipt status, purge workflow, repair history. | Withdrawal command, receipt query, purge workflow, repair command. |
application/reservation_operations/features/reservation_collaboration | Open workspace, events, journal, commit, conflict resolution. | Workspace query/read model, event command, commit command, conflict command. |
application/reservation_operations/features/service_calendar | Compatibility decisions, snapshots, policy profile, impact query, holiday provider. | Calendar impact query, compatibility decision command, policy profile read model. |
application/service_calendar/features/holiday_audit | Command, contract, persistence port, decision, impact preview. | Audit command, impact preview query, publication decision, persistence port. |
application/reservation_orchestration/features/reservation_operation_command | Command board and follow-up workflow share one feature. | Command-board query, operation advance command, follow-up workflow. |
application/caregiver_assignment/features/caregiver_matching | Candidate snapshot repository, matching policy query, contracts. | Matching query/read model, snapshot persistence port, matching command if mutation exists. |
application/customer_engagement/features/communication_delivery | Workflow catalog, dispatch planning, payment dispatch side effects, Novu provider vocabulary. | Workflow catalog query, dispatch command, provider-neutral delivery result read model. |
CaveCrew Follow-Up Queue
Section titled “CaveCrew Follow-Up Queue”These are read-only audit findings from the 2026-07-05 folder pass. Each item is an implementation queue entry, not a decision to copy source structure.
2026-07-06 Naming And Boundary Delta
Section titled “2026-07-06 Naming And Boundary Delta”| Priority | Finding | Promotion target |
|---|---|---|
| P0 | Actor vocabulary split across hq_admin, headquarters_admin, headquarters_administrator, branch_operator, branch_manager, and branch_owner. | shared_kernel / ActorKindAliasCatalog plus context-specific capability policies. |
| P0 | Settlement data-room API still accepts request-side actor identity and raw export format strings. | SettlementActorContextResolver and SettlementDataRoomExportFormat. |
| P0 | Payment delegation exists, but payment-change/refund authority remains mother/requester-centric. | PaymentParticipantAuthority and RefundRecipientAuthority. |
| P0 | Reservation lifecycle predicates are reimplemented as raw string sets in care-delivery projections. | ReservationLifecyclePredicate read policy. |
| P1 | Branch coverage has parallel service-area, managed-area, office-profile, and matching-area models. | BranchCoverageDecision and AddressScopeKey owned by branch_operations. |
| P1 | Caregiver matching vocabulary still uses CandidateRankingPolicy, while checklist uses CaregiverCandidateOrderingPolicy; the public backend and contract travel-time weight is now standardized as travel_duration_minutes_weight / travelDurationMinutesWeight, with legacy Supabase storage column mapping isolated in the adapter. | Decide whether the ubiquitous name should be CaregiverCandidateOrderingPolicy and rename the remaining ranking-policy symbol family in one backend/contract pass. |
| P1 | Care-team assignment, payout acknowledgement, payout adjustment, destination change, and admin payout projection were importing a reservation-booking SpiceDB permission helper from settlement-named settlement_actor_authorization. | Resolved 2026-07-07 by backend commit 38dd9ec: generic interfaces.reservation_booking_authorization.has_reservation_booking_permission owns reservation-booking object checks, while settlement_actor_authorization keeps only settlement actor-kind helpers. |
| P1 | Document render queue consumption needed application printable contracts from a Supabase service-use-contract adapter, but the printable application slice was not declared as an explicit Tach module. | Resolved 2026-07-07 by backend commit 3cdc86a: application.document_reporting.features.printable_document is a declared feature slice, the Supabase adapter depends on that slice explicitly, and the service-use-contract application command stays platform-neutral while queue payload parsing remains in the adapter. |
| P1 | Care team role value object is bypassed by raw caregiver_role strings in care delivery. | Exported CareTeamMemberRole consumed by care-delivery projections. |
| P1 | Document delivery/grant flows use multiple actor vocabularies and raw boundary strings. | DocumentAuthorityActor shared with family/proxy/payment authority. |
| Area | Finding | Target |
|---|---|---|
| Domain/application provider leak | domain/operator_access/features/operator_identity_session/operator_identity_session.py had SupabaseIdentityMetadataFact, SpiceDbRelationshipFact, OpaStatusGateFact, and app_metadata vocabulary. | Renamed to IdentityAuthorizationMetadataFact, AuthorizationRelationshipFact, PolicyStatusGateFact, and authorization_metadata; provider mapping stays in platform/interface/adapters. |
| Domain provider leak | domain/pricing_settlement/features/payment/payment_refund.py previously exposed KillBillRefundCommand with adapter HTTP method/path/body shape. | Renamed to provider-neutral PaymentRefundGatewayCommand; adapter now owns KillBill payload construction. 2026-07-05 follow-up renamed the persisted refund command column to billing_gateway_refund_command and keeps Kill Bill payload shape inside the Supabase adapter/provider boundary. |
| Domain/application provider leak | domain/pricing_settlement/features/payment/killbill_admin_operation.py and the matching application use case used provider brand as core vocabulary. | Renamed domain/application files and symbols to PaymentProviderAdminOperation*; KillBill-specific gateway/store names remain in adapters and internal provider API. Remaining work: interface facade and persisted DB naming migration. |
| Source-era settlement vocabulary leak | Settlement board transition provenance and matching application contract exposed source-era labels as core naming. | Renamed to SettlementBoardTransitionProvenance, ImportedSettlementBoardTransitionRow, source_branch_marker, and settlement_board_statuses; source evidence stays explicit in import rows, while domain/application contract language stays modern. |
| Domain provider leak | domain/customer_engagement/features/campaign_publication/campaign_publication.py validated supabase:// media references directly. | Renamed the rule to managed storage artifact references and allowed provider-neutral artifact:// / storage:// refs. CMS/Supabase object mapping stays in adapters. |
| Domain CQRS drift | domain/pricing_settlement/features/settlement/cqrs/{commands.py,queries.py} stores command/query DTOs in domain. | Move application DTOs to application/pricing_settlement/features/settlement; keep domain policy value objects only. |
| Domain command drift | domain/document_reporting/features/branch_resource_post/branch_resource_post.py duplicates application command payloads. | Application commands plus mapper; domain BranchResourcePostDraft and BranchResourceAttachmentChange. |
| Legacy status leak | domain/shared_kernel/features/reservation_lifecycle/source_reservation_status.py and reservation state transition expose source status. | Core ReservationLifecycleStatus; source-code mapper in migration anti-corruption layer. |
| Duplicated bounded context | domain/care_delivery/features/caregiver_assignment duplicates domain/caregiver_assignment. | caregiver_assignment owns assignment; care delivery emits assignment facts. |
| Duplicated bounded context | domain/care_delivery/features/caregiver_performance_recognition duplicates domain/caregiver_performance_recognition. | caregiver_performance_recognition owns grades/scorecards; care delivery emits performance facts. |
| Calendar ownership | domain/reservation_operations/features/service_calendar overlaps domain/service_calendar/features/holiday_audit. | service_calendar owns holiday/policy; reservation operations consumes reservation-scoped calendar policy. |
| Application context gap | application/reservation_orchestration has no matching domain bounded context. | Fold process manager into reservation_operations or add a real domain/reservation_orchestration. |
| Oversized use case | application/reservation_orchestration/features/reservation_booking/booking.py has a large ReservationBooking orchestration service. | Split into BookReservationUseCase plus process-manager steps: pricing, payment, notification, content/statistics projections. |
| CQRS naming drift | GetReservationOperationBoardCommand, ReadRecipientDocumentAccessHistoryCommand, and settlement data-room *LookupKeyCommand are reads. | Rename to *Query or *Selection and separate read handlers. |
| Platform provider leak | application/platform/supabase_*.py, spicedb_*.py, restate_workflow.py expose provider names in application ports. | Provider-neutral AuthPort, RelationshipAuthorizationPort, WorkflowEnginePort; SDK details in adapters/platform. |
| Interface provider leak | KillBill admin/event API names, public Restate status fields, Supabase/SpiceDB API payload names, and source address-provider fields. | Daum/Kakao branch service-area address fields were neutralized on 2026-07-05 with addressEvidenceSourceKind and evidencePayloadFingerprint; remaining public/operator APIs should keep provider evidence internal-only. |
| DB contract leak | Supabase migrations still persist sanmopia_killbill_admin_operation_audits; refund ledger command storage now uses billing_gateway_refund_command. | New tables/columns should use provider-neutral names such as payment_provider_admin_operation_audits and billing_gateway_refund_command; old provider-branded table names need a migration plan. |
| Duplicate adapter mapping | 67 local row coercion clones remain despite adapters/platform/supabase_row_value.py. | Promote to shared row codec helpers and feature-specific mappers only. |
| Duplicate settlement audit insert | jsonb_to_recordset(p_transition_audits) insert blocks repeat across settlement migrations. | append_settlement_transition_event() / SettlementTransitionEventLedger. |
| Duplicate payout event mapping | Caregiver payout acknowledgement, adjustment, and destination-change adapters repeat audit/event mapping. | CaregiverPayoutChangeEvent and PayoutInstructionTargetMapper. |
Boundary Violations To Check Next
Section titled “Boundary Violations To Check Next”- Decide
adaptersvsinfrastructurenaming, then updatestandard.md,tach.toml, docs, and folders consistently. - Add explicit Tach modules for every live adapter context, especially
adapters.reservation_bookingandadapters.customer_engagement. - Add feature-level Tach modules for read/write-heavy slices before more code
is migrated:
pricing_settlement/payment_conversion,pricing_settlement/reservation_price_version_adjustment,pricing_settlement/settlement_data_room_workspace,reservation_operations/customer_action_availability,reservation_operations/customer_reservation_lifecycle_view,reservation_operations/reservation_collaboration, andreservation_operations/reservation_continuation. - Add Tach checks that forbid flat adapter folders except documented platform support modules.
- Decide if
reservation_bookingis a bounded context, an orchestration feature, or an API adapter. Current repo uses all three meanings. - Keep payment provider ports provider-neutral. The application payment port was
renamed to
PaymentGatewayClient; next cleanup is moving the concreteDebugPaymentGatewayClientfake out of the application layer or documenting it as test-support composition. - Replace provider/runtime vocabulary in public/internal interface names:
/killbill-payment-admin-operations,attach_killbill_payment_event_http_routes, publicrestateDTO fields, and provider-shaped branch service area payloads. - Deduplicate adapter mapping code. Highest-impact targets are Supabase row coercion clones, settlement transition audit insert blocks, and caregiver payout audit/event mappers.
- Keep workflow kinds in one source.
workflow_status_http.pyandsupabase_workflow_status_projection.pycurrently disagree onreservation_operation_follow_up. - Keep OPA, SpiceDB, ReState, KillBill, Novu, and OR-Tools as explicit exceptions. None should silently become default platform choices under Supabase-first rules.
- Reconcile Pydantic application contract models with JSON Schema contract repo. Contract repo should remain API SSOT; backend models should be generated or compatibility-checked against schemas.
- Keep contract schema group aliases mapped in
layout:check; add no new schema group without an explicit backend bounded-context owner. - Keep schema
$idvalues path-derived and guarded bylayout:check. - Keep OpenAPI auth scheme references guarded by
layout:check; do not add provider-specific schemes without defining them in the same API spec. - Keep provider/internal KillBill webhook/admin endpoints out of
public-api.yaml;layout:checkenforces this split. - Keep CQRS shape consistent. Either standardize large application slices on
features/<feature>/cqrs/{commands,queries}.pyor keep suffix-only command/query modules and remove one-off CQRS folders. Do not mix both patterns without a documented feature-level reason. - Keep UI-side calculations out of frontend migrations. Booking, payment, settlement, and document workspaces should request backend projections or command payload builders; frontend state stores may assemble existing backend contract fields but must not recompute money, status, or eligibility.
Checklist
Section titled “Checklist”- Pick canonical infrastructure folder term:
adaptersorinfrastructure. - Remove or document the non-existing
backend-repo/src/.../infrastructureassumption. - Add
exact = true,layers_explicit_depends_on = true, and layer names totach.tomlif config should matchstandard.mddirectly. - Add Tach modules for all live adapter contexts.
- Add Tach modules for high-risk feature slices found in the 2026-07-05 DDD follow-up audit.
- Keep
tach check-externalgreen after ReState/OTEL/platform Tach module expansion. - Rename payment application provider port to provider-neutral
PaymentGatewayClient/PaymentGatewayResult. - Neutralize campaign publication storage validation so domain rules do not require Supabase-specific object schemes.
- Add Tach guard for application provider names: no concrete provider class names unless file is a provider-neutral port with no implementation.
- Split high-risk CQRS folders listed above.
- Move concrete debug/test adapters out of application layer.
- Rename or isolate provider/runtime API vocabulary in public
interfacesand DB contracts: KillBill webhook/admin, ReState status payloads, Supabase/SpiceDB identity port names, Daum/Kakao address source fields, and raw provider payment method literals. - Promote duplicate adapter helpers:
SupabaseRowValue, settlement transition append, and caregiver payout event mapping. - Align contract schema group names with bounded-context names or document
stable public aliases, with
layout:checkenforcement. - Normalize all schema
$idhosts to one contract host and one/schemas/path style, withlayout:checkenforcement. - Fix OpenAPI undefined
bearerAuthand addlayout:checkguard for undefined security scheme references. - Move provider webhook/admin operations to
internal-api.yaml; future separate provider API must replace, not duplicate, that ownership. - Add contract compatibility tests that compare backend application
contract models to
contract-repo/schemas. - Add migration checklist item for every external-platform exception: reason, owner, Supabase alternative considered, and rollback path.
- Keep frontend untouched for this audit.
Verification Commands Used
Section titled “Verification Commands Used”sed -n '1,1700p' standard.mdfind backend-repo/src/sanmopia_modernization/application -path '*/__pycache__' -prune -o -type f -name '*.py' -printfind backend-repo/src/sanmopia_modernization/adapters -path '*/__pycache__' -prune -o -type f -name '*.py' -printfind contract-repo/schemas contract-repo/openapi -type f -printtach check --dependencies --interfaces --exacttach check-externalrg -n "sanmopia_modernization\\.(adapters|interfaces)" backend-repo/src/sanmopia_modernization/applicationrg -n "bearerAuth|supabaseBearerAuth" contract-repo/openapi/public-api.yaml contract-repo/openapi/internal-api.yamlrg -n "/killbill-payment" contract-repo/openapi/public-api.yaml contract-repo/openapi/internal-api.yamlrg -n "contracts\\.sanmopia\\.yamon\\.io|contract\\.sanmopia\\.local|contracts\\.sanmopia\\.local/(reservation-|member-|branch-|workflow-|care-)" contract-repo/schemaspnpm layout:checkpnpm check