DDD Domain Folder Audit
DDD Domain Folder Audit
Section titled “DDD Domain Folder Audit”Scope: backend-repo/src/sanmopia_modernization/domain only, with domain tests
used as evidence. Frontend was not read or edited. No full pytest run.
Current authority is
ADR 029: backend
structure is layer first, then bounded context, then feature slice. CQRS is
optional feature-local application structure, using populated commands/
and/or queries/ directly. Tach and architecture tests must enforce import
boundaries across the complete production graph.
2026-07-13 Full-layer Follow-up
Section titled “2026-07-13 Full-layer Follow-up”The older domain-only findings below remain historical mining evidence, not the current whole-backend compliance verdict. The full-layer follow-up found:
- the layer-first roots
domain,application,adapters, andinterfacesalready exist and no top-level feature root exists; - domain has no outer-layer or framework imports;
- the old Tach gate passes, but its graph is incomplete;
- reservation-booking adapters import and construct interface APIs, violating the fixed direction;
interfacesis mostly flat, while top-level orchestration/platform placement is incomplete and runtime composition remains in rootmain.py;- some application/adapter contexts still omit
features/<feature>; - settlement uses the obsolete
application/pricing_settlement/features/settlement/cqrswrapper; - representative sibling-feature deep imports exist without explicit public contracts or consumer-owned ports.
Therefore architecture status is partial. A passing legacy Tach result is not evidence of complete ADR-029 compliance.
Backend ee7b9b8 resolved the first audited violations: reservation-booking API
composition moved from adapters to
orchestration/reservation_operations/features/reservation_booking, the
settlement cqrs/ wrapper became direct populated commands/ and queries/,
and the flat document_code.py helper became the public document_identity
feature contract. Structural tests and Tach now reject adapter/interface
reverse imports and orchestration back-imports. Flat interfaces, incomplete
context/feature placement, root main.py, incomplete Tach declarations, and
unreviewed sibling-feature imports remain migration debt.
Backend 8aeaf0a followed with a bounded public-contract cleanup for the
audited payment-conversion, receipt-progress, service-offering availability,
and service-balance projection imports. This removes those concrete deep
imports only; it does not promote the remaining cross-feature graph to
compliant status.
Current Shape
Section titled “Current Shape”- 16 bounded-context folders, excluding generated
__pycache__folders. - 76 feature folders under
domain/<bounded_context>/features/<feature>. - 143 production domain Python files and 125 domain test files.
- All domain tests found use
*_test.py; notest_*.pyor*.test.pyin domain scope. - No production domain import from
application,adapters,interfaces, or platform layers was found. - Production cross-context imports found only through
shared_kernel. - Only
pricing_settlement/features/settlement/cqrsuses a dedicated CQRS folder. Command, projection, and read-model names also appear inside several regular feature files.
Folder Findings
Section titled “Folder Findings”| Domain folder | Finding | Feature-slice / CQRS note | TODO |
|---|---|---|---|
branch_operations | Good bounded context for branch organization, office profile, and office content. organization contains branch entity and service-area policies, so ownership is coherent but broad. | Feature slice works. CQRS not needed in domain unless branch operator boards become independent read models. | Keep branch service-area policy here. Add public feature exports before other contexts depend on branch scope. |
business_reporting | Good reporting context, but statistics is legacy/generic language beside report_catalog and report_refresh_schedule. | Reporting is read-model heavy. CQRS fits at application/query boundary, not as domain handler code. | Rename or alias statistics toward business_report_metrics or report_metric_definition. |
care_delivery | Good context for service records, attendance, daily care report, record confirmation, and notification obligations. Risk: contains caregiver_assignment and caregiver_performance_recognition, both also appear as top-level contexts or context candidates. | Feature slices mostly good. CQRS fits notification_obligation_dispatch and customer-facing report projections. Avoid CQRS for simple attendance/value-policy slices. | Decide if assignment and recognition slices are delivery-specific facts or misplaced ownership. Rename if kept: care_delivery_assignment_history, care_delivery_performance_facts. |
caregiver_assignment | Strong bounded context for matching profile, matching policy, optimizer inputs, and care team contract. This should probably own matching and assignment decisions. | Feature slice works. CQRS should stay in application for optimizer queries/commands; domain should expose policies, facts, and decisions. | Make this owner for assignment language. Move or rename reservation/care-delivery assignment concepts that are not owner concepts. |
caregiver_management | Thin but clear context with credential_dossier. Caregiver profile currently lives in care_delivery/features/caregiver, which creates profile ownership ambiguity. | Feature slice is fine. CQRS not needed yet. | Decide if caregiver profile belongs here. If yes, move or rename care-delivery profile to delivery participation/profile snapshot. |
caregiver_performance_recognition | Clear context for performance season and scorecard. Duplicated by care_delivery/features/caregiver_performance_recognition. | Feature slice works. CQRS may fit scorecard read models later, but not core score rules. | Make this owner for recognition scoring and seasons. Let care delivery emit facts only. |
content_management | Very thin context with only content_attachment_lifecycle. It overlaps with customer_engagement/features/content. | Feature slice is underdeveloped. CQRS not needed until content moderation/publication boards exist. | Either grow this into content/asset lifecycle owner or fold attachment lifecycle into a renamed engagement content feature. |
customer_engagement | Good context for inquiry, campaign publication, mother lead intake, communication delivery, notification, child health guidance, and public content. Generic content and notification names are drift risks. | Feature slice works. CQRS should be reserved for publication/read surfaces and message delivery state, not every content value object. | Rename content toward public_content_publication; rename notification toward engagement_notification_policy or customer_notification_preference. |
document_reporting | Good context for document catalog, room, delivery, printable document, reservation document, and document access. daily_report collides with care_delivery/daily_care_report. | Feature slice works. CQRS fits document room/catalog/access read surfaces at application boundary. Domain should keep document policy and grant rules. | Rename daily_report toward daily_report_document or daily_care_report_print_bundle. Add public exports for catalog/document policy before internal imports grow. |
member_management | Good member/family/privacy lifecycle context. member is generic but currently local to account/profile policy. | Feature slice works. CQRS not needed in domain. | Rename member toward member_profile if more member subfeatures appear. Keep privacy lifecycle here. |
migration_governance | Clear migration-only context with source evidence reconciliation. It is isolated from business contexts. | Feature slice works. CQRS not needed. | Keep out of runtime business flows. Use only for source evidence parity and audit facts. |
operator_access | Clear operator identity/session context. Must stay distinct from Supabase Auth implementation and from business authorization policies. | Feature slice works. CQRS not needed in domain. | Keep credential/session audit language here. Leave transport/session storage to adapters/application. |
pricing_settlement | Largest context by far: pricing, payment, settlement, compensation, promotion, import, quote, financial lifecycle, and data room. Standard uses this name as example, but current size risks becoming a macro-context. | Feature slices exist but several are orchestration-like. CQRS is justified for settlement board/read model and payment conversion projection. Do not apply CQRS to pure value objects such as money, price_version, or regional_benefit. | Split language internally: pricing catalog/quote, payment/refund, settlement board, caregiver compensation. Add public feature APIs and context-map dependency rules before more features import each other directly. |
reservation_operations | Strong central reservation context. Risk areas: service_calendar duplicates top-level service_calendar; reservation/caregiver_assignment.py and matching overlap with caregiver_assignment. | Feature slice works. CQRS fits lifecycle views, action availability, collaboration, and admin command boards. Do not force CQRS into birth information, care catalog, or simple status/value policies. | Rename service_calendar to reservation_service_calendar if kept here. Move matching/assignment owner concepts to caregiver_assignment or clarify them as reservation assignment terms/snapshots. |
service_calendar | Clear holiday audit context, but duplicates reservation_operations/features/service_calendar. Backend fee19fe now places ServiceWeekProfile and ServiceDurationProfile in this top-level context. | Feature slice works. CQRS can exist for holiday publication/audit commands in application, not core holiday facts. | Keep this owner for holiday/audit/calendar policy language, service-week/duration profiles, and frozen occurrence ledger language. Reservation should consume policy decisions, not own calendar policy. |
shared_kernel | Used by reservation and pricing for source reservation status, customer detail surface, pre-reservation payment, and now stable identity predicates. Cross-context imports are currently limited to this folder, which is good. Risk: features inside shared kernel can become a dumping ground. | Do not use CQRS here. Shared kernel should contain stable value objects, source-state vocabulary, pure predicates, and small facts only. | Add a strict rule: no workflow commands, handlers, repositories, or adapter-facing concerns in shared kernel. Promote growing behavior into a real bounded context. |
Missing Abstractions
Section titled “Missing Abstractions”-
2026-07-05 CaveCrew follow-up found renewed drift in domain naming. Treat the entries below as refactor queue items, not source structures to copy.
Folder Drift Target domain/shared_kernelsource_reservation_statusandcustomer_detail_surfacemake shared kernel look like a feature dumping ground.Keep only stable cross-context facts. Move source mappings to ACL/application and lifecycle behavior to reservation_operations.domain/reservation_operationsservice-calendar/service-period/service-commitment/customer-action slicesRepeated stable code/reference validation duplicated lower-code syntax in each feature. Resolved 2026-07-05: shared_kernel/features/stable_identityowns pure text/code/reference predicates, while each bounded-context helper keeps its own domain error and ubiquitous message. Continue promoting only covered predicates; do not move domain commands or policies into shared kernel.domain/branch_operations/features/organizationDaum/Kakao address-provider evidence appeared in domain service-area policy. Resolved 2026-07-05: domain/API now use AddressEvidenceSourceKind.EXTERNAL_LOOKUP/OPERATOR_INPUT/LEGACY_IMPORT,ServiceAreaAddressEvidence,source_kind, andevidence_payload_fingerprint; provider route names stay in source evidence/provider adapters.domain/customer_engagementanddomain/document_reportingKakao/Novu/Strapi/channel terms repeat in domain-level communication/document policy names. Use provider-neutral channel and authoring concepts; map provider routes in application/adapters. domain/care_deliverycaregiver_assignmentandcaregiver_performance_recognitionshadow top-level bounded contexts.Assignment and recognition contexts own decisions/seasons; care delivery publishes service-day/service-record facts. domain/reservation_operations/features/service_calendarCalendar policy overlaps the separate domain/service_calendar.service_calendarowns holiday/calendar policy, service-week profiles, and frozen occurrence ledger semantics; reservation operations consumes reservation-scoped decisions.domain/reservation_operations/features/service_calendar,domain/pricing_settlement/features/promotion_entitlement,domain/reservation_operations/features/service_commitmentCoupon/benefit issuance appears as service-day coupon entitlement, promotion entitlement, and coverage-triggered coupon obligation. Promote CreditedServiceDayBenefitEntitlementin pricing/promotion; keep service calendar responsible only for credited occurrence facts.domain/pricing_settlement/features/settlementSettlement participant vocabulary uses InterOfficeSettlementAcknowledgementSideand aliases it asInterOfficeSettlementParticipantRolein closeout logic.Promote explicit SettlementParticipantRolefor statement/closeout commands; keep side aliases temporary and adapter-local.domain/reservation_operations/features/customer_action_availabilityUI action target, projection, and command vocabulary mix inside domain. Domain becomes CustomerReservationEligibilityPolicy; query/action payloads move to application query slices.domain/reservation_operations/features/customer_reservation_lifecycle_viewFolder/module and wire payloads still carry view,card, and display compatibility language. Domain symbols were tightened on 2026-07-05 toCustomerReservationLifecycleSnapshot, lifecycleEntry, entry facts, report obligations, and care-team facts.Next cleanup: move/alias the feature path and application payload names toward customer_reservation_lifecycle_snapshot; keep legacy JSON keys only as explicit contract aliases.domain/pricing_settlement/features/settlementDanbee/external-counterparty names, data-room views, read models, and partial CQRS are mixed. Use ExternalSettlementCounterparty; move boards/exports/data-room reads to application query slices.domain/document_reporting/features/branch_resource_postCommand dataclasses sit inside aggregate lifecycle file. Split commands.py, aggregate policy, and access-grant/read query concerns.domain/business_reportingReport query/export/display metadata is close to domain policy. Domain owns ReportDefinitionPolicy; executable queries/export schemas move to application queries. -
2026-07-05 follow-up cleanup:
reservation_document_bundleno longer exposesCardStateorcard_statefrom domain/application read models. The domain name is nowReservationDocumentBundleCustomerVisibleState, exposed throughcustomer_visible_state; UI card rendering remains a frontend/application concern. -
2026-07-05 follow-up cleanup:
printable_document_accessno longer exposes UI wording for read access as a first-class domain enum. The canonical domain scope isREAD_DOCUMENT; legacy/rawviewinput is normalized at the domain boundary so stored grants and old contracts can migrate without leaking UI language into new code. -
2026-07-05 follow-up cleanup:
reservation_operations/features/service_periodwas integrated as a domain feature root, not a domaincommandsfolder. The slice keepsServicePeriodPlanningRequest, templates, duration, policy, and immutable planning results in domain language, while application contracts own incoming command payloads and Pydantic validation. -
2026-07-05 follow-up cleanup:
reservation_operations/features/reservation_lifecycle_side_effect_planmaps accepted state-transition follow-up actions into typed durable work items: reservation audit entry, customer lifecycle notification, payment refund closeout, reserved benefit release, branch settlement opening, and financial lifecycle closeout. The slice persists intent, not provider calls. It stays insidereservation_operations; pricing/customer-engagement targets are represented as target-context facts, not imports across bounded contexts. Runtime execution can later live inreservation_orchestrationor workflow adapters without moving source-era status logic into frontend/UI code.
CaveCrew Refactor Queue
Section titled “CaveCrew Refactor Queue”| Path | Drift | Target |
|---|---|---|
domain/pricing_settlement/features/settlement/cqrs | Command/query DTOs live in domain and encourage CQRS folder drift. | Move branch settlement commands and board queries to application command/query slices; keep domain settlement policy and facts only. |
domain/reservation_operations/features/customer_reservation_lifecycle_view | Folder/module and application wire keys still expose view, card_display, report_presentation, and caregiver_display. Domain symbols now use CustomerReservationLifecycleSnapshot, CustomerReservationLifecycleEntry, entry_fact, report_obligation, care_team, and bucket entries. | Move or alias the feature path to lifecycle snapshot language; keep wire compatibility in application contracts until frontend generated clients migrate. |
domain/reservation_operations/features/customer_action_availability | Presentation/navigation/projection vocabulary sits beside policy. | Split CustomerReservationActionPolicy from CustomerActionAvailabilityProjection. |
domain/pricing_settlement/features/settlement_data_room_workspace | Workspace/operator return token and Danbee names mix UI, provider, and domain. | Use settlement artifact/reconciliation language in domain; move workspace/session/provider mapping to application/adapters. |
domain/pricing_settlement/features/payment/payment.py | Provider payment method code mapping is inside domain. | Keep neutral PaymentMethod in domain; move provider code mapping to application ACL or adapter. |
domain/document_reporting/features/document_room | Storage/HTML artifact language leaks into domain. | Rename toward ManagedDocumentArtifact and map concrete storage/provider fields in infrastructure. |
-
2026-07-05 follow-up audit: Tach now catches direct provider/application boundary violations, but several existing feature folders still need explicit feature-level modules before the graph is strict enough. First targets:
pricing_settlement/features/payment_conversion,pricing_settlement/features/reservation_price_version_adjustment,pricing_settlement/features/settlement_data_room_workspace,reservation_operations/features/customer_action_availability,reservation_operations/features/customer_reservation_lifecycle_view,reservation_operations/features/offline_reservation_intake,reservation_operations/features/postpartum_care_center_stay,reservation_operations/features/reservation_collaboration, andreservation_operations/features/reservation_continuation. -
2026-07-05 CaveCrew architecture audit found no Pydantic imports under
domain/, which is the intended boundary. Remaining enforcement drift:architecture_test.pyknows more bounded contexts thantach.toml, the application context check is subset-only, generic feature names such aspayment,pricing,settlement,matching,content, andnotificationstill survive below contexts, service-week/weekend semantics are duplicated, and address keys are named differently across branch, pricing, and caregiver profiles. Next architecture slice should promote one bounded-context manifest for Tach/tests, addServiceWeekPolicyorServiceCalendarProfile, and introduce a sharedAdministrativeAddressKeyvalue object with context-local wrappers. -
2026-07-06 Pydantic boundary audit: keep domain dataclasses Pydantic-free. Efficient conversions belong at application/interface/adapter boundaries where JSON, workflow, or Supabase row payloads cross process boundaries. First backend cleanup converted Restate workflow response payloads for reservation booking, payment, financial lifecycle, operation follow-up, branch settlement reconciliation export, member privacy lifecycle, and member privacy purge to strict Pydantic models. Remaining high-value candidates are adapter row parsers with repeated
_required_*_from_mappinghelpers and large interface API dataclass response groups; convert those only slice-by-slice with focused tests so domain purity and Tach boundaries stay intact. -
2026-07-06 follow-up:
document_reporting/features/document_deliverySupabase delivery-attempt rows now enter through a strict Pydantic adapter row model. Manual string/int/datetime/mapping helpers were removed, timezone awareness and provider payload shape are validated at the adapter boundary, and colocated tests pin malformed-row rejection. -
2026-07-06 follow-up:
document_reporting/features/printable_documentprintable template repeat-section JSONB rows now use Pydantic adapter row models with template-key aliases. Manual object/string/boolean helpers were removed from repeat section reconstruction, and colocated tests pin malformed repeat arrays, boolean leakage, and item-field shape rejection. -
2026-07-06 follow-up:
branch_operations/features/organizationbranch service-area policy rule/revision rows now use strict Pydantic adapter row models. Manual text/int/date/datetime/sequence helpers were removed, branch coverage profile keys are normalized at the adapter boundary, and revision timestamps are timezone-aware before domain reconstruction. -
2026-07-06 follow-up:
caregiver_assignment/features/caregiver_matchingfrozen caregiver candidate snapshot rows now validate through a Pydantic Supabase row model before sorting and domain reconstruction. Manualcandidate_snapshotobject checks and repeated Supabase row reads were removed, with colocated tests pinning malformed snapshot payload and revision leakage rejection. -
2026-07-06 follow-up:
service_calendar/features/holiday_auditholiday audit JSONB snapshot rows now validate through a Pydantic adapter row before aggregate reconstruction, replacing the last local mapping helper in that store and pinning malformed snapshot rejection with a colocated test. -
2026-07-06 follow-up:
member_management/features/family_accountfamily account, family member, reservation sponsor, payment delegation, and care-history grant Supabase rows now enter through Pydantic adapter row models with stripped nonblank identifiers, enum scope parsing, and timezone-aware authority windows before domain aggregate reconstruction. -
2026-07-06 follow-up:
service_calendar/features/holiday_auditholiday impact RPC candidate rows now validate directly through the existing Pydantic application contract instead of a hand-written Supabase row mapper, so malformed policy fingerprints fail before impact preview use. -
2026-07-06 follow-up:
service_calendar/features/holiday_auditservice-calendar holiday policy rows now use a dedicated Pydantic adapter row model instead of the generic Supabase row reader. Observed dates stay date-only and active flags stay strict booleans, with malformed-row rejection covered by colocated tests. -
2026-07-06 follow-up:
pricing_settlement/features/paymentpayment refund ledger nested JSONB payloads now use Pydantic adapter row models for cancellation explanation snapshots, refund deductions, discount adjustments, and additional charge adjustments. This moves refund math support data away from repeated manual Supabase row reads and pins string-number, string-boolean, and date-time leakage rejection with colocated tests. -
2026-07-06 follow-up:
pricing_settlement/features/settlementsettlement data-room request, artifact, action, and save-result Supabase rows now use Pydantic adapter row models. Manual row helper calls were replaced by explicit request/artifact/action reconstruction, with timezone, integer, text tuple, and metadata-shape checks pinned by colocated repository tests. -
2026-07-06 follow-up:
pricing_settlement/features/settlementinter-office settlement and line Supabase rows now use Pydantic adapter row models. Manual helper calls were removed from history filtering, save-result validation, aggregate reconstruction, and line-item mapping, with date, integer, and payload-shape checks pinned by colocated tests. -
2026-07-06 follow-up:
reservation_orchestration/features/mother_booking_contextmother profile, branch context, and branch actor Supabase JSON fragments now validate through Pydantic adapter row models before operational booking context reconstruction. This keeps domain/application booking facts Pydantic-free while rejecting string identifiers, scalar caregiver id lists, and blank branch actor identity at the adapter boundary. -
2026-07-06 follow-up:
reservation_orchestration/features/mother_booking_contextremaining operational booking context collections now reconstruct through a single top-level Pydantic adapter row. Caregiver candidates, caregiver profiles, care environment pets, service options, and payment method options no longer use hand-written JSON helper functions; strict boolean, numeric, array, and supported payment-method checks are pinned by colocated tests. -
2026-07-05 follow-up audit: legacy numeric lifecycle/status mapping remains inside some domain features. Move source or persisted integer conversion out to application anti-corruption layers or adapters. Concrete targets:
pricing_settlement/features/settlement/policy.py,pricing_settlement/features/payment/pre_reservation_refund_policy.py,pricing_settlement/features/settlement/branch_settlement_board.py, andpricing_settlement/features/settlement/external_settlement_counterparty_status.py. -
2026-07-05 follow-up cleanup:
pricing_settlement/features/settlement/policy.pyno longer defines a one-off numericReservationLifecycleStatusenum. Settlement domain now uses provider/source-neutralSettlementReservationLifecycleStatus; source status integer mapping moved toapplication/pricing_settlement/features/settlement/reservation_settlement_status_acl.py. The previously listed numeric-status cleanup targets in this settlement slice are now application ACL mappings, not domain enum helpers. -
2026-07-05 follow-up cleanup: pre-reservation refund policy no longer owns source payment type ids
1/6or collection status ids0/1as domainIntEnumvalues. Domain now usesReservationPaymentPurposeplusPreReservationPaymentCollectionState, whileapplication/pricing_settlement/features/payment/source_reservation_payment_acl.pymaps legacy payment type/status codes beforePreReservationPaymentCaptureis created. -
2026-07-05 follow-up cleanup: branch settlement board domain no longer owns persisted status codes
0/1/2/3/4through enum methods or duplicate status helpers.BranchSettlementBoardStatusstays pure lifecycle vocabulary; source status code conversion moved toapplication/pricing_settlement/features/settlement/branch_settlement_status_acl.py, and settlement persistence adapters call that ACL before writingSTATUS_FL. -
2026-07-05 follow-up cleanup: external settlement counterparty domain no longer owns persisted status code
0/1conversion. Domain keepsExternalSettlementCounterpartyCompletionState; source completion-state code conversion moved toapplication/pricing_settlement/features/settlement/external_settlement_counterparty_status_acl.py. -
2026-07-05 follow-up audit: reserve domain lifecycle wording consistently:
Statusmeans persisted business lifecycle,Stagemeans customer-facing projection,Statemeans transient readiness/projection state, andBucketmeans list grouping only. Do not introduce new source-status or UI-status names without this mapping. -
2026-07-05 follow-up audit: normalize cancellation spelling at the bounded context boundary.
pricing_settlement/features/payment/payment.pyusesCANCELED, while reservation/customer-facing slices useCANCELLED. Pick one canonical domain spelling and map provider strings in ACL/adapter code. -
2026-07-05 follow-up cleanup: backend payment and payment-summary domain spelling now uses
CANCELLED/cancelled; Supabase payment status constraints, booking adapters, payment workflow results, Kill Bill event synchronization, and focused tests were updated to the same modern spelling. -
2026-07-05 follow-up audit: service duration naming must not regress to one-week/two-week strings. Promote
ServicePeriodDuration/ServiceCalendarTermlanguage and keepServiceTermUnit.WEEKas a duration unit, not as a product or workflow name. -
2026-07-05 follow-up audit: stable-code/reference/text validators are duplicated across service calendar, service period, customer action availability, and new service commitment slices. Promote the common checks to shared-kernel value validation only after focused tests cover each slice.
-
2026-07-05 follow-up cleanup: reservation-scoped Danbee status domain vocabulary moved to
external_settlement_counterparty_statuswithReservationExternalSettlementCounterpartyStatusandExternalSettlementCounterpartyCompletionState. Danbee-specific API routes, Supabase table names, and source projection adapters remain compatibility surfaces until a forward DB/API contract migration lands. -
2026-07-05 follow-up cleanup: branch-settlement CQRS command/query DTOs moved from
domain/pricing_settlement/features/settlement/cqrstoapplication/pricing_settlement/features/settlement/cqrs. Domain settlement slices now keep settlement policies/facts while application owns command/query payloads. -
2026-07-05 follow-up cleanup:
customer_action_availabilityno longer usesCustomerActionPresentationorCustomerReservationStateProjectionin domain language. The domain names are nowCustomerActionDescriptorandCustomerReservationStateSnapshot; application contracts keep existing presentation payload fields as compatibility mapping only. -
2026-07-05 follow-up cleanup:
settlement_data_room_workspacenow exposes provider-neutralExternalSettlementCounterpartyDetailLookupKeyandExternalSettlementCounterpartyCollectionSummarydomain names. ExistingExternalCounterpartySettlement*names remain aliases for application/API adapter compatibility until data-room payload and storage-key migration lands. -
2026-07-05 follow-up cleanup:
customer_reservation_lifecycle_viewno longer usesLifecycleView,ProjectionMeta,Card,CardKind,DisplayFact, orPresentationFactas domain symbol names. Domain naming now centers on lifecycleSnapshot, snapshot metadata, lifecycleEntry, entry kind, entry facts, report obligations, care-team facts, and bucket entries. The application contract still translates legacy JSON keys such ascard_display,report_presentation, andcaregiver_displayuntil client codegen can switch without breaking existing frontends. -
Feature public APIs are inconsistent. Most feature
__init__.pyfiles do not export a stable surface;pricing_settlement/features/payment_conversionis the only observed feature package with__all__. -
Context ownership map is missing in domain docs/code. Current tree needs a written dependency rule for owner contexts, supporting contexts, and
shared_kernel. -
CQRS folder convention is missing. One feature uses
cqrs/commands.pyandcqrs/queries.py, while other commands, projections, and read models live directly in feature files. -
Cross-feature imports inside large contexts are growing. This is acceptable while contexts are cohesive, but direct imports should move through public feature contracts before Tach boundaries become stricter.
-
Generated
__pycache__folders are present under domain. They should not be part of architecture review and should be ignored or removed from tracked artifacts if tracked.
Naming Collision Candidates
Section titled “Naming Collision Candidates”caregiver_assignment: top-level context,care_deliveryfeature,reservation_operations/features/reservation/caregiver_assignment.py, and matching optimizer language. Prefercaregiver_assignmentas owner context.caregiver_performance_recognition: top-level context andcare_deliveryfeature. Prefer top-level owner for scoring/recognition; care delivery should own service facts.service_calendar: top-level context andreservation_operationsfeature. Prefer top-level owner for calendar policy and holiday audit; reservation should own reservation calendar decisions.daily_report:care_delivery/daily_care_reportanddocument_reporting/daily_report. Prefer care-delivery report facts versus printable/reporting document names.content:customer_engagement/features/contentandcontent_management/features/content_attachment_lifecycle. Prefer public content publication versus content asset lifecycle names.settlement_data_roomandsettlement_data_room_workspace: both underpricing_settlement. Clarify whether workspace is a domain concept or an application workflow/read model.shared_kernel/features: feature-slice wording inside shared kernel is ambiguous. Shared kernel should not look like another use-case area.
CQRS Guidance
Section titled “CQRS Guidance”Use CQRS where read and write models are naturally different:
pricing_settlement/features/settlement: settlement board command contracts, branch settlement read models, reconciliation exports, and settlement data room views.pricing_settlement/features/payment_conversion: projection and follow-up commands.reservation_operations/features/customer_action_availabilityandcustomer_reservation_lifecycle_view: customer-safe read models.reservation_operations/features/reservation_collaboration: write command, revision conflict, and realtime projection event.care_delivery/features/notification_obligation_dispatch: dispatch commands, retry/suppression actions, and work-queue projections.document_reportingdocument room/catalog/access surfaces when application query models diverge from document policy.
Do not use CQRS by default for stable value objects, policy calculators, status
catalogs, source vocabulary, or thin one-file features. Examples: money,
price_version_year, member_privacy_lifecycle, credential_dossier,
branch_service_area_policy, and shared-kernel source status.
Concrete TODO Checklist
Section titled “Concrete TODO Checklist”- Document context ownership decisions for
caregiver_assignment,caregiver_performance_recognition,service_calendar,content, anddaily_report. - Rename or alias collision-prone folders before more application/adapters import them.
- Add public feature exports or contract modules for high-dependency features: reservation status/capability, service calendar policy, settlement board, pricing summary, payment summary, document catalog, and shared-kernel reservation lifecycle.
- Define CQRS convention:
features/<feature>/cqrs/{commands,queries}.pyonly for features with independent command/query contracts; otherwise keep command/read-model dataclasses inside the feature module. - Add Tach rules for context-level imports: domain can depend on common and shared kernel; business contexts should not import peer business contexts except through explicit public contracts.
- Keep
shared_kernelsmall. Reject workflow commands, handler logic, repositories, and adapter-facing concerns there. - Remove generated
__pycache__directories from tracked artifacts if any are tracked. - Add focused architecture tests or static checks for domain folder shape:
domain/<context>/features/<feature>,*_test.py, no application/adapters imports from domain, and no peer-context imports outside approved contracts.