-
-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
Chrison Simtian edited this page May 17, 2026
·
1 revision
The app follows an onion architecture with CQRS dispatched via Wolverine in-process. Dependencies point inward — Domain has no references; Application talks to ports; Infrastructure provides adapters.
┌─────────────────────────────────────────────────────────┐
│ ApiService / Web │ composition root
│ (Aspire-orchestrated, MudBlazor frontend) │
├─────────────────────────────────────────────────────────┤
│ ERP.Infrastructure │ adapters, DI
│ OR-Tools planner · EF Core · TickerQ · Save │
├─────────────────────────────────────────────────────────┤
│ ERP.Application │ ports, CQRS handlers
│ IRecipePlanner · IFactoryStateProvider · queries │
├─────────────────────────────────────────────────────────┤
│ ERP.Domain │ pure entities
│ ProductionTarget · ResourceAvailability · … │
└─────────────────────────────────────────────────────────┘
Two bounded contexts live under src/:
-
ERP/— the planner. Game-agnostic.-
Domain/— pure entities (ProductionPlan,ProductionTarget,ResourceAvailability,ProductionStep, …) -
Application/— ports + CQRS handlers, includingIRecipePlanner -
Infrastructure/— adapters (the OR-Tools planner lives here) -
Infrastructure/Persistence/— EF Core + dual-provider plumbing
-
-
Satisfactory/— game-specific adapters.-
Catalog/— parsesDocs.jsoninto game-agnostic recipes/items -
Save/— wraps the SatisfactorySaveNet fork and projects it into ERP.Domain entities
-
Both contexts publish ports into ERP.Application and provide adapters in
ERP.Infrastructure. Wolverine wires everything in AddErpInfrastructure.
src/AppHost/ # Aspire orchestrator — `dotnet run` entry point
src/ApiService/ # Minimal-API backend; PlanDto and friends live here
src/Web/ # Blazor Server UI (MudBlazor, FICSIT-themed)
src/ServiceDefaults/ # Aspire defaults
All architecturally significant decisions live in
docs/adr/.
Headline ones:
| ID | Title |
|---|---|
| 0001 | Use .NET 10 as the target framework |
| 0002 | Use Blazor for the UI |
| 0003 | Use .NET Aspire for orchestration |
| 0004 | Use Onion Architecture |
| 0005 | Use CQRS in the application layer |
| 0006 | Wolverine as the in-process mediator |
| 0008 | Playwright for UI tests |
| 0010 | Game-agnostic catalogue contract |
| 0014 | Pure-C# .sav ingestion via fork |
| 0017 | MudBlazor as the UI framework |
| 0018 | Dual-provider persistence stack |
| 0019 | TickerQ background scheduler |
ADRs are immutable once accepted — if the decision changes, write a new ADR that supersedes the old one (see ADR-0012 → ADR-0014 for the canonical example).
Start here
How it works
Reference
Off-wiki