Skip to content

Coding Service - Domain Design

1. Coding Orchestrator sub-domain

Aggregate Root: CodingOrchestrator

a. Description

The Coding Orchestrator domain represents the orchestrator of the optimization workflow and will further be the orchestrator of the primo-coding workflow. It is the central aggregate that orchestrates the workflows to handle an optimization or a primo-coding consistent (state-machine).

b. States & commands

The Coding Orchestrator progresses through the following states:

CREATED → CODING_REQUESTED → [CODING_SUGGESTED | CODING_FAILED] → REVIEWED → CERTIFIED → VALIDATED

                                                                        IGNORED

State Definitions:

StateDescription
CREATEDMedical stay imported from RSS file, ready for processing
CODING_REQUESTEDCoding has been requested
CODING_FAILEDCoding process encountered errors
CODING_SUGGESTEDSuccessfully suggested codes
REVIEWEDTIM coder validated the suggestions
CERTIFIEDInternal Medical DIM reviewer validated the coding
VALIDATEDFinal validation by the customer DIM completed
IGNOREDStay has zero optimization gain, temporarily set aside

Internal Commands and State Transitions:

Commands are methods on the CodingOrchestrator aggregate that enforce business rules and transition states:

CommandTriggered ByFrom StatesTo State
requestCoding()Human (Admin)CREATED, CODING_FAILED, CODING_SUGGESTED, CODING_VALIDATED, REVIEWEDCODING_REQUESTED
failCoding()System (Events from Optim or PromoCoding aggregatesCODING_REQUESTED, CODING_FAILED, CODING_SUGGESTEDCODING_FAILED
suggestCoding()System (Events from Optim or PromoCoding aggregatesCODING_REQUESTED, CODING_FAILED, CODING_SUGGESTEDCODING_SUGGESTED
validateCoding()Human (Tim)CODING_SUGGESTED, CODING_FAILEDCODING_VALIDATED or IGNORED
reviewCoding()Human (Internal Dim)CODING_VALIDATEDREVIEWED or IGNORED
validateMedicalStay()Human (Customer Dim)REVIEWED, IGNOREDVALIDATED
cancelAction()Human (various roles)VALIDATED, REVIEWED, IGNORED, CODING_VALIDATEDPrevious state (from RollBackStatus)
evaluateOptimization()System (mostly after code changes)IGNOREDPrevious state if gain > 0

c. Domain Entry Points

Static MethodPurposeTriggered By
createFromImport()Create new MedicalStay from RSS importSystem during RSS file processing

d. Domain Boundaries and Vision

The Coding Orchestrator governs the lifecycle of a medical stay across optimization and primo-coding journeys while staying agnostic of any AI-specific mechanics. Its responsibility is to react to domain-level signals—principally from the Optimization and Coding aggregates—and maintain consistent orchestration state (currentOptimId, currentPrimoCodingId).

Inbound domain events & commands

  • createFromImport() initializes a CodingOrchestrator as soon as an RSS file imports a medical stay. Creation immediately pairs the orchestrator with an Optimization aggregate because RSS imports always yield an optimization need.
  • When business users or automated policies want a fresh optimization cycle, they now issue requestCoding(). This command will instantiate a new Optimization aggregate instance. The Optimization domain then emits its own OptimizationStarted event, which downstream adapters (e.g. the AI Coding application service) listen to in order to launch AI Coding. The orchestrator still transitions into a "waiting for optimization" posture but never calls AI itself.
  • Completion flows arrive strictly via events: once AICoding finishes, it raises AICodingFinalized. Optimization handles the AI response through succeed(), mutates its own state, and emits OptimizationSuggested. The Coding Orchestrator subscribes to that success event to run its own succeed() or a future failure complement, recording the new currentOptimId and moving its finite-state machine forward.

Change states for the CodingOrchestrator Aggregate:

  • AI_CODING_TRIGGERED → CODING_REQUESTED
  • AI_CODING_SUCCEEDED → CODING_SUGGESTED
  • AI_CODING_FAILED → CODING_FAILED

Vision

  • Preserve a single source-of-truth for orchestration: Optimization and Coding aggregates retain ownership of AI integration. The orchestrator acts as a stateful coordinator that waits for their verdicts to decide subsequent human workflows (validation, review, final customer dim validation).
  • Decouple future expansions: Primo-coding will mirror the optimization path. When introduced, a triggerNewPrimoCoding() command will create a dedicated Primo Coding aggregate whose events mirror today's optimization flow. The orchestrator will track currentPrimoCodingId the same way, without gaining any AI-specific knowledge.

2. Optimization sub-domain

Aggregate Root: Optimization

a. Description

The Optimization domain represents the core value proposition: comparing a reference coding against a working coding to calculate optimization gain. Each optimization contains two complete Coding entities: the reference (baseline) and the working (improved) coding.

b. Current states & commands

The Optimization aggregate doesn't have explicit state enums, but has implicit lifecycle states based on its data:

Implicit StateIndicatorsDescription
CreatedoptimizationGain === nullJust created, not yet evaluated
EvaluatedoptimizationGain !== nullHas been grouped and priced
CodeUpdatedupdatedAt !== nullCodes have been modified since creation

Key Properties:

  • referenceCoding: The baseline coding from RSS import or previous state
  • workingCoding: The coding being optimized with AI suggestions
  • optimizationGain: Calculated price difference (working - reference)
  • updatedAt: Last modification timestamp

Commands and Operations:

CommandTriggered ByPurposeBusiness Logic
suggestCode()System (Consumption of event AiCoding.Finalized)AI suggests a new medical codeUpdates workingCoding and emits event OptimizationSuggested
acceptCode()Human (Coder)Coder accepts suggestionUpdates code status to ACCEPTED
rejectCode()Human (Coder)Coder rejects suggestionUpdates code status to REJECTED
changeCodeCategory()Human (Coder)Coder changes code category (DP/DR/DAS)Updates code category
groupAndPriceReference()System (Evaluation use case)Re-group and re-price reference codingValidates GHM consistency, handles mismatches
evaluate()System (Evaluation use case)Group, price working coding, calculate gainEmits OptimizationEvaluatedEvent

c. Domain Entry Points

The Optimization aggregate provides static factory methods that serve as entry points for creating new instances:

Static CommandTriggered ByPurpose
startFromRSS()Human (RSS import)Creates both reference and working coding from single source (RSS import)
startFromReference(isExperiment: boolean)1. System (CodingOrchestrator.CodingRequestedEvent consumption)
2. Human (to trigger experiments)Creates optimization with working coding using only selected documents and reference

👉 All those commands will emit the OptimizationStarted event

Key Aggregate Invariants:

  1. Reference Immutability: Reference coding should not be modified after creation (except for re-grouping)
  2. Working Coding Mutability: Working coding can be modified through code operations
  3. Gain Calculation: optimizationGain = round((workingPrice - referencePrice) * 100) / 100

d. Domain Boundaries and Vision

Optimization owns coding comparison and pricing logic while remaining unaware of higher-level orchestration or AI internals. Its job is to expose commands and events that other domains consume to drive workflows.

Integration boundaries

  • ↔ Coding Orchestrator: The orchestrator emits en event CodingRequestedEvent to create a new Optimization aggregate (using startFromReference()). Optimization emits OptimizationStarted, OptimizationSuggested, OptimizationFailed, etc. The orchestrator subscribes to those events to update its state (currentOptimId) but never mutates Optimization directly.
  • → AICoding domain: AICoding listens to OptimizationStarted, runs its AI workflows, and manipulates the aggregate exclusively through public commands (suggestCode(), acceptCode(), rejectCode(), evaluate()). When AI work finishes, AICoding raises AICodingFinalized; Optimization consumes that to invoke succeedAiCoding()/failAiCoding() internally, updating gain and queueing its own domain events.
  • ← Document Domain: listens to AllDocumentsReadyEvent to know when to automatically startFromReference() and emit a OptimizationStarted to start the AICoding pipeline

Vision

  • Optimization supports experiment runs: experiment triggers instantiate the aggregate, produce AI work, and emit the usual success/failure events. When raising OptimizationSuggested, the domain includes a boolean isExperiment so downstream listeners (Coding Orchestrator) can decide whether to treat the result as canonical.

3. AI Coding sub-domain

Aggregate Root: AiCoding

a. Description

The AI Coding domain orchestrates the AI-driven medical coding suggestion workflow starting from ready documents. It is responsible for transforming processed medical documents into validated code suggestions that feed the Optimization aggregate.

Core Responsibility: Coordinate medical context standardization, invoke AI models to generate code suggestions for each medical unit stay, track suggestion completeness, and emit finalization events—while maintaining a clear audit trail of AI pipeline state and artifacts.

Key Principle: AI Coding acts as a producer of AI-specific artifacts (code candidates, citations, model versions) that other domains consume. It consumes ready documents from the Document domain and produces code suggestions for the Optimization domain.

b. Current states & commands

The AI Coding aggregate progresses through AI-specific processing stages:

CREATED → PENDING_CODING_SUGGESTIONS → COMPLETED
                ↓                         ↓
              FAILED                     FAILED

State Definitions:

StateDescriptionIndicates
CREATEDAI Coding process initializedWaiting for documents to be ready
PENDING_CODING_SUGGESTIONSCode suggestions being generatedAI models suggesting codes for each unit stay
COMPLETEDAll unit stays coded successfullyReady to finalize optimization
FAILEDProcess failed at any stageContains errorType and errorDetails

Error Types:

  • DOCUMENTS_NOT_READY_ERROR: Required documents not in READY state
  • CODING_SUGGESTION_ERROR: AI model invocation failure

Internal Commands and State Transitions:

CommandTriggered ByFrom StatesTo StateBusiness Rules
completeUnit()System (SuggestMedicalUnitStayCodingUseCase)CREATEDPENDING_CODING_SUGGESTIONSPENDING_CODING_SUGGESTIONS
succeed()System (FinalizeMedicalStayUseCase)PENDING_CODING_SUGGESTIONSCOMPLETEDAll medical unit stays must be completed
fail()System (various error handlers)Any except COMPLETEDFAILEDMust provide errorType and errorDetails

Key Aggregate Properties:

  • id: Unique identifier for this AI coding run
  • optimizationId: Reference to the optimization being built
  • modelVersion: AI model version used for suggestions
  • medicalUnitStayStatuses: Map tracking completion status of each unit stay
  • selectedDocumentIds: Which documents to use for this coding run

c. Domain Entry Points

The AI Coding domain provides a single static factory method as its entry point:

Static MethodPurposeTriggered By
create()Initialize AI Coding processOptimizationStarted event consumption

d. Domain Boundaries and Vision

The AI Coding domain serves as a specialized orchestrator for AI-driven workflows, consuming artifacts from the Document domain and producing artifacts for the Optimization domain.

Integration Boundaries

← Document Domain:

  • Consumes: Ready documents (OCR'd and pseudonymized) via query interface
  • Boundary: Never manipulates document state; only reads ready artifacts

→ Optimization Domain:

  • Consumes: referenceCoding from previous optimization (immutable baseline)
  • Produces: Code suggestions via optimization.suggestCode() command
  • TriggersBy: OptimizationStarted event at creation
  • Finalizes: Signals completion via AICodingFinalized event (or more AiCodingSucceeded event ?)
jsx
// 1. AI Coding completes
AICoding.succeed() 
  → emits AICodingFinalized { aiCodingId, optimizationId }

// 2. Optimization aggregate subscribes and validates
Optimization (subscriber to AICodingFinalized)
  → receives AICodingFinalized
  → calls this.suggest()
  → emits OptimizationSuggested { 
      optimizationId, 
      medicalStayId,
      isExperiment 
    }

// 3. Coding Orchestrator subscribes and updates state
CodingOrchestrator (subscriber to OptimizationSuggested)
  → receives OptimizationSuggested
if (!isExperiment) { 
      this.setCurrentOptimId(optimizationId) 
    }
  → calls this.succeed()
  → transitions to CODING_SUCCEEDED state

4. Primo-Coding Domain

Entity: currently Coding (not an aggregate root in current implementation)

a. Description

The Primo-Coding domain represents a complete medical coding snapshot: a collection of medical unit stays, each containing medical codes and medical acts. It also stores the grouping results (GHM, GHS, price, errors).

Current Architecture Note: Coding is an entity owned by the Optimization aggregate. It doesn't have its own lifecycle or persistence—it's always part of a reference or working coding within an Optimization.

b. Structure and business rules

Coding
├── Basic Properties
│   ├── id: string
│   ├── durationInDays: number
│   ├── dischargeDate: Date | null
│   ├── rawMedicalInformationsIds: string[] (documents used)
│   └── createdAt: Date

├── Grouping Results (set by evaluate)
│   ├── ghm: string | null (Groupe Homogène de Malades)
│   ├── ghs: string | null (Groupe Homogène de Séjours)
│   ├── ghmsSeverity: number | null
│   ├── ghmsMajorDiagnosisCategory: string | null
│   ├── ghmsMedicalStayType: string | null
│   ├── ghmsMedicalStaySubtype: string | null
│   ├── price: number | null
│   └── groupingError: GroupingError | null

└── Medical Unit Stays (entities)
    └── MedicalUnitStay[]
        ├── generalInformation
        ├── medicalActs[]
        └── medicalCodes[]

Business Rules for Medical Unit Stay Validation:

  1. Exactly one Principal Diagnosis (DP) per unit stay
  2. At most one Related Diagnosis (DR) per unit stay
  3. Any number of Associated Diagnoses (DAS)

d. Domain Boundaries and Vision

The Coding entity is currently owned by the Optimization aggregate, representing an internal entity without independent lifecycle:

🔗 Coding ⊂ Optimization Interface

  • Responsibility: Coding encapsulates a complete medical coding snapshot with grouping results
  • Direction: Coding is owned and managed by Optimization (composition relationship)
  • Boundary Rule: Coding has NO independent persistence or lifecycle outside of Optimization. This will change for sure if we start PrimoCoding

Key Encapsulation Rules:

  1. External actors CANNOT directly manipulate Coding entities
  2. All Coding operations MUST go through Optimization aggregate commands
  3. Coding entities contain rich business logic but lack independent identity outside their Optimization