03. Domain Model
Why This Page Matters
A training repo becomes much easier to understand when the learner can separate stable domain nouns from runtime coordination logic.
The domain model in this project is intentionally compact. That is a strength. It gives the rest of the system a shared vocabulary without hiding workflow behavior inside giant “smart” entity classes.
The Core Domain Contracts
The InspectionPrototype.Domain project holds the primary nouns the rest of the repo shares:
RecipeScanPointFrameInspectionResultAlarmRunSummaryRunTerminalStatus
These types are simple records, not large inheritance hierarchies.
Relevant files:
src/InspectionPrototype.Domain/Contracts/Recipe.cssrc/InspectionPrototype.Domain/Contracts/ScanPoint.cssrc/InspectionPrototype.Domain/Contracts/Alarm.cssrc/InspectionPrototype.Domain/Contracts/RunSummary.cs
How The Domain Is Used
Recipe And ScanPoint
Recipe defines the ordered scan plan:
- a
RecipeId - a name
- an ordered list of
ScanPointentries
That ordered nature matters because the workflow processes points sequentially during a run. The recipe is not just configuration data; it shapes the runtime path.
Alarm
Alarm is a good example of a domain object staying focused while still carrying operational meaning.
It includes:
- alarm code
- severity
- message
- whether acknowledgment is required
- whether the alarm is active
- whether the operator has acknowledged it
This is enough to teach the difference between:
- active unsafe condition
- operator awareness
- later clearance and recovery handled by application logic
RunSummary
RunSummary is the durable story of a finished run.
It includes:
- identity
- recipe name
- start and end times
- terminal status
- defect count
- major alarms
- richer slice-4 metrics such as point counts, profile name, and defect breakdowns
That makes it suitable for both the “last run” view and the persisted history list.
Why The Domain Is Small
This repo does not try to make the domain layer own everything.
That is a deliberate design choice.
The application layer owns:
- workflow state transitions
- command guards
- orchestration
- fault recovery semantics
The domain layer owns the stable nouns and outcomes.
This is a good fit because the repo is simulating an industrial workstation, not implementing a full DDD-heavy enterprise model with rich aggregates everywhere.
The Real Runtime Model Lives Partly In Application State
One subtle but important architectural detail is that some important runtime concepts are not pure domain contracts. They live in InspectionPrototype.Application.State.
Examples:
AppStateActiveRunStateWorkflowStateSafetySignalsDiagnosticsEntrySimulatorProfile
That split is healthy:
- domain contracts describe business objects and durable outcomes
- application state describes the live runtime snapshot needed to coordinate the workstation
Trade-Offs
Benefits
- the domain stays easy to read
- stable contracts are shared cleanly across layers
- runtime behavior remains explicit in orchestration code rather than hidden in rich entity methods
Costs
- the learner must understand both domain contracts and application state
- some concepts such as active-run metrics are represented outside the domain project
That trade is sensible for a training-oriented workstation app. It makes runtime control logic easier to inspect.
Where To Look In Code Next
After reading this page:
- read
Recipe.cs,Alarm.cs, andRunSummary.cs - compare them with
ActiveRunState.csandAppState.cs - notice how terminal run information becomes more durable and compact than active-run information
That transition from live state to durable summary is one of the most teachable design moves in the repo.
Related Lessons
- 15. OOP in Real-World .NET
- 16. SOLID Principles in .NET
- 26. Domain Modeling in .NET
- 06. Recipe in Industrial Machines
Diagram Brief
Title: Domain model and runtime-adjacent statePurpose: Show the most important domain contracts and how they relate to application-side runtime stateAudience: newcomer developer learning the system vocabularyNodes: Recipe, ScanPoint, InspectionResult, Alarm, RunSummary, RunTerminalStatus, ActiveRunState, AppStateEdges: Recipe contains ScanPoints; AppState references LoadedRecipe, ActiveRunState, ActiveAlarms, LastRunSummary, RunHistory; ActiveRunState evolves into RunSummary at terminal completion; RunSummary uses RunTerminalStatusGrouping: Domain contracts, application runtime state, terminal outcomesCaption: The repo keeps domain nouns small and stable, while live orchestration state stays in the application layerDestination file path:docs/diagrams/source/architecture-03-domain-model.drawio