Skip to content

Bounded context

Backend domain code uses this shape:

domain/<bounded_context>/
features/
<feature>/
__init__.py
...
cqrs/
__init__.py
commands.py
queries.py
read_models.py

domain/<bounded_context> may contain only __init__.py and features/. Shared infrastructure does not live under domain.

Application code mirrors the bounded-context name when it owns orchestration for that context:

application/<bounded_context>/
features/
<feature>/
__init__.py
...

Do not keep context-specific application services in retired flat folders such as application/settlement, application/payment, or application/pricing.

Cross-context saga orchestration has its own application bounded context. The reservation booking saga lives under application/reservation_orchestration/features/reservation_booking because it coordinates member, branch, matching, pricing, payment, settlement, notification, care delivery, and reporting domains. It must not live under application/reservation_operations, which owns only reservation-operation feature services.

Adapter code also mirrors bounded-context and feature names when the adapter belongs to a context:

adapters/<bounded_context>/
features/
<feature>/
__init__.py
...

Do not keep context-specific adapters in flat folders such as adapters/payment, adapters/pricing, or adapters/settlement.

  • branch_operations
  • business_reporting
  • care_delivery
  • caregiver_assignment
  • caregiver_management
  • caregiver_performance_recognition
  • content_management
  • customer_engagement
  • document_reporting
  • member_management
  • migration_governance
  • operator_access
  • pricing_settlement
  • reservation_orchestration (application-only saga context)
  • reservation_operations
  • service_calendar
  • shared_kernel (explicit shared vocabulary only, never a feature bucket)

The authoritative context inventory comes from backend-repo/src/sanmopia_modernization/domain. Application-only and adapter-only folders must be marked as orchestration or legacy shim exceptions. Retired flat adapters such as adapters/reservation or adapters/reservation_booking are cleanup targets unless a migration note says they are still active anti-corruption shims.

This is the DDD view behind the C4 Level 3 Component diagram. It shows business ownership, not source controller names or table names.

flowchart LR
  actor["Actor capability projections"] --> operator_access
  actor --> member_management
  actor --> branch_operations

  reservation_orchestration["reservation_orchestration<br/>application saga"] --> reservation_operations
  reservation_orchestration --> service_calendar
  reservation_orchestration --> caregiver_assignment
  reservation_orchestration --> pricing_settlement
  reservation_orchestration --> care_delivery
  reservation_orchestration --> document_reporting
  reservation_orchestration --> customer_engagement

  reservation_operations --> service_calendar
  reservation_operations --> caregiver_assignment
  reservation_operations --> pricing_settlement
  reservation_operations --> branch_operations
  reservation_operations --> member_management

  caregiver_assignment --> caregiver_management
  caregiver_assignment --> caregiver_performance_recognition
  caregiver_assignment --> care_delivery
  caregiver_assignment --> pricing_settlement

  pricing_settlement --> document_reporting
  pricing_settlement --> business_reporting
  pricing_settlement --> customer_engagement

  branch_operations --> business_reporting
  branch_operations --> content_management
  customer_engagement --> content_management
  document_reporting --> business_reporting

  migration_governance -.-> reservation_operations
  migration_governance -.-> pricing_settlement
  migration_governance -.-> document_reporting
  shared_kernel -.-> reservation_operations
  shared_kernel -.-> pricing_settlement

Read arrows as allowed domain language dependencies or application orchestration flows that must be proven by contracts/tests. They are not permission to bypass ports, import adapters from domain, or place workflow commands in shared_kernel.

  • Domain must not import application, adapters, interfaces, FastAPI, Pydantic, or SQLAlchemy. Tach enforces this.
  • *ReadModel, *Projection, and cqrs/queries.py in domain are migration debt unless they are pure domain snapshots. Prefer application query handlers.
  • Legacy/source vocabulary belongs in anti-corruption adapters and source evidence docs. Domain names use modern ubiquitous language.
  • Adapter tests may share reusable port recorders under adapters/platform. Do not keep feature-local Supabase fake database classes unless the fake models feature-specific failure semantics. Use RecordingSupabaseDatabase for normal fetch/insert/upsert/update/RPC call recording. Turn on its filter/projection options when adapter tests need Supabase-like row filtering or selected-column behavior.
  • Canonical owners found by audit:
    • caregiver_performance_recognition owns performance seasons and scorecards.
    • daily_care_report owns DailyCareReportReviewOutcome facts for reviewed caregiver report submissions.
    • customer_daily_report_review owns customer-authored service-day review, readiness, rating, and reward-grant facts.
    • branch_operations owns branch service-area policy and coverage evidence.
    • customer_engagement/features/content owns reusable publication placement.