Skip to content

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.

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, and interfaces already 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;
  • interfaces is mostly flat, while top-level orchestration/platform placement is incomplete and runtime composition remains in root main.py;
  • some application/adapter contexts still omit features/<feature>;
  • settlement uses the obsolete application/pricing_settlement/features/settlement/cqrs wrapper;
  • 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.

  • 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; no test_*.py or *.test.py in 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/cqrs uses a dedicated CQRS folder. Command, projection, and read-model names also appear inside several regular feature files.
Domain folderFindingFeature-slice / CQRS noteTODO
branch_operationsGood 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_reportingGood 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_deliveryGood 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_assignmentStrong 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_managementThin 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_recognitionClear 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_managementVery 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_engagementGood 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_reportingGood 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_managementGood 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_governanceClear 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_accessClear 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_settlementLargest 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_operationsStrong 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_calendarClear 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_kernelUsed 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.
  • 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.

    FolderDriftTarget
    domain/shared_kernelsource_reservation_status and customer_detail_surface make 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_operations service-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_identity owns 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, and evidence_payload_fingerprint; provider route names stay in source evidence/provider adapters.
    domain/customer_engagement and domain/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_assignment and caregiver_performance_recognition shadow 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_calendar owns 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 CreditedServiceDayBenefitEntitlement in pricing/promotion; keep service calendar responsible only for credited occurrence facts.
    domain/pricing_settlement/features/settlementSettlement participant vocabulary uses InterOfficeSettlementAcknowledgementSide and aliases it as InterOfficeSettlementParticipantRole in closeout logic.Promote explicit SettlementParticipantRole for 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 to CustomerReservationLifecycleSnapshot, lifecycle Entry, 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_bundle no longer exposes CardState or card_state from domain/application read models. The domain name is now ReservationDocumentBundleCustomerVisibleState, exposed through customer_visible_state; UI card rendering remains a frontend/application concern.

  • 2026-07-05 follow-up cleanup: printable_document_access no longer exposes UI wording for read access as a first-class domain enum. The canonical domain scope is READ_DOCUMENT; legacy/raw view input 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_period was integrated as a domain feature root, not a domain commands folder. The slice keeps ServicePeriodPlanningRequest, 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_plan maps 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 inside reservation_operations; pricing/customer-engagement targets are represented as target-context facts, not imports across bounded contexts. Runtime execution can later live in reservation_orchestration or workflow adapters without moving source-era status logic into frontend/UI code.

PathDriftTarget
domain/pricing_settlement/features/settlement/cqrsCommand/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_viewFolder/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_availabilityPresentation/navigation/projection vocabulary sits beside policy.Split CustomerReservationActionPolicy from CustomerActionAvailabilityProjection.
domain/pricing_settlement/features/settlement_data_room_workspaceWorkspace/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.pyProvider 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_roomStorage/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, and reservation_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.py knows more bounded contexts than tach.toml, the application context check is subset-only, generic feature names such as payment, pricing, settlement, matching, content, and notification still 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, add ServiceWeekPolicy or ServiceCalendarProfile, and introduce a shared AdministrativeAddressKey value 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_mapping helpers 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_delivery Supabase 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_document printable 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/organization branch 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_matching frozen caregiver candidate snapshot rows now validate through a Pydantic Supabase row model before sorting and domain reconstruction. Manual candidate_snapshot object 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_audit holiday 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_account family 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_audit holiday 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_audit service-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/payment payment 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/settlement settlement 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/settlement inter-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_context mother 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_context remaining 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, and pricing_settlement/features/settlement/external_settlement_counterparty_status.py.

  • 2026-07-05 follow-up cleanup: pricing_settlement/features/settlement/policy.py no longer defines a one-off numeric ReservationLifecycleStatus enum. Settlement domain now uses provider/source-neutral SettlementReservationLifecycleStatus; source status integer mapping moved to application/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/6 or collection status ids 0/1 as domain IntEnum values. Domain now uses ReservationPaymentPurpose plus PreReservationPaymentCollectionState, while application/pricing_settlement/features/payment/source_reservation_payment_acl.py maps legacy payment type/status codes before PreReservationPaymentCapture is created.

  • 2026-07-05 follow-up cleanup: branch settlement board domain no longer owns persisted status codes 0/1/2/3/4 through enum methods or duplicate status helpers. BranchSettlementBoardStatus stays pure lifecycle vocabulary; source status code conversion moved to application/pricing_settlement/features/settlement/branch_settlement_status_acl.py, and settlement persistence adapters call that ACL before writing STATUS_FL.

  • 2026-07-05 follow-up cleanup: external settlement counterparty domain no longer owns persisted status code 0/1 conversion. Domain keeps ExternalSettlementCounterpartyCompletionState; source completion-state code conversion moved to application/pricing_settlement/features/settlement/external_settlement_counterparty_status_acl.py.

  • 2026-07-05 follow-up audit: reserve domain lifecycle wording consistently: Status means persisted business lifecycle, Stage means customer-facing projection, State means transient readiness/projection state, and Bucket means 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.py uses CANCELED, while reservation/customer-facing slices use CANCELLED. 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 / ServiceCalendarTerm language and keep ServiceTermUnit.WEEK as 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_status with ReservationExternalSettlementCounterpartyStatus and ExternalSettlementCounterpartyCompletionState. 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/cqrs to application/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_availability no longer uses CustomerActionPresentation or CustomerReservationStateProjection in domain language. The domain names are now CustomerActionDescriptor and CustomerReservationStateSnapshot; application contracts keep existing presentation payload fields as compatibility mapping only.

  • 2026-07-05 follow-up cleanup: settlement_data_room_workspace now exposes provider-neutral ExternalSettlementCounterpartyDetailLookupKey and ExternalSettlementCounterpartyCollectionSummary domain names. Existing ExternalCounterpartySettlement* 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_view no longer uses LifecycleView, ProjectionMeta, Card, CardKind, DisplayFact, or PresentationFact as domain symbol names. Domain naming now centers on lifecycle Snapshot, snapshot metadata, lifecycle Entry, entry kind, entry facts, report obligations, care-team facts, and bucket entries. The application contract still translates legacy JSON keys such as card_display, report_presentation, and caregiver_display until client codegen can switch without breaking existing frontends.

  • Feature public APIs are inconsistent. Most feature __init__.py files do not export a stable surface; pricing_settlement/features/payment_conversion is 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.py and cqrs/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.

  • caregiver_assignment: top-level context, care_delivery feature, reservation_operations/features/reservation/caregiver_assignment.py, and matching optimizer language. Prefer caregiver_assignment as owner context.
  • caregiver_performance_recognition: top-level context and care_delivery feature. Prefer top-level owner for scoring/recognition; care delivery should own service facts.
  • service_calendar: top-level context and reservation_operations feature. Prefer top-level owner for calendar policy and holiday audit; reservation should own reservation calendar decisions.
  • daily_report: care_delivery/daily_care_report and document_reporting/daily_report. Prefer care-delivery report facts versus printable/reporting document names.
  • content: customer_engagement/features/content and content_management/features/content_attachment_lifecycle. Prefer public content publication versus content asset lifecycle names.
  • settlement_data_room and settlement_data_room_workspace: both under pricing_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.

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_availability and customer_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_reporting document 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.

  • Document context ownership decisions for caregiver_assignment, caregiver_performance_recognition, service_calendar, content, and daily_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}.py only 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_kernel small. 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.