CCC is an example application for illustrating Command Context Consistency (CCC).
It implements a very basic version of the ideas behind the Calinga system: tenants, projects, translation keys, and related write-side business rules.
The repository is not intended to be a generic content management system. Its main purpose is to explore and demonstrate an event-sourced write model based on minimal command-specific context slices and conditional appends.
backend/- ASP.NET Core backend with the event-sourced write model and API, split intoApi, one project per module underModules/,Domain,EventStore, and the shared projectsAbstractions,Dcb,ModuleHosting,Projections,AutomationsandTestKitunderBase/(see ADR-006, ADR-009, ADR-011, ADR-012, ADR-013, ADR-014 and ADR-015)frontend/- React frontend for exploring and exercising the sample applicationpresentation/- standalone React/RevealJS slide deck used to explain CCC in this repositorydocs/architecture/- architecture decision records for the main technical choices
dotnet build backend/CCC.sln
dotnet test backend/CCC.sln
dotnet run --project backend/Api/Api.csprojThe backend and the projection slice tests need PostgreSQL on localhost:5432. The tests use the server in the CCC_TEST_POSTGRES connection string instead, if it is set.
In development, the OpenAPI document is served at http://localhost:5039/openapi/v1.json and Swagger UI at http://localhost:5039/swagger.
cd frontend
npm install
npm run devUI is available at http://localhost:5173. Requires the backend to be running.
cd presentation
npm install
npm run devThe browser-hosted presentation runs on Vite's default dev port unless that port is already in use.
| Document | Description |
|---|---|
| ADR-001: Use Architecture Decision Records | Establishes the ADR format and file naming convention used in this project |
| ADR-002: Event Sourcing with Command-Context-Consistency | Defines the core architectural model used in this example |
| ADR-003: PostgreSQL as Event Log Database | Explains why PostgreSQL is used as the append-only event log |
| ADR-004: Dapper as Event Log Data Access Library | Explains why the event store uses Dapper and explicit SQL |
| ADR-005: No CRUD Terminology in Requests, Commands, and Events | Defines the naming convention for commands, requests, and events |
| ADR-006: Split the Backend into API, Commands, Domain and EventStore Projects | Defines the backend projects, the direction of their dependencies, and where validation happens |
| ADR-007: Projections Answer Queries, One Project per Slice | Defines how projections are built, woken up and queried, and why appends are serialized |
| ADR-008: An Abstractions Project for the Handler Contracts | Puts the command and query handler contracts into a project that references nothing |
| ADR-009: Modules by Area of Work | Groups commands, projections and queries into one project per area of work |
| ADR-010: Projections Stall After Repeated Failures | Defines when a projection gives up, how the stall is recorded, and how to unstall it |
| ADR-011: Projection Infrastructure in a ProjectionBase Project | Moves the projection runner and its helpers out of the event store |
| ADR-012: State Model Primitives in a Dependency-Free Dcb Project | Moves state models, tags and event records into a project that references nothing, so the domain no longer depends on the event store |
| ADR-013: A Base Folder for the Shared Projects | Groups Abstractions, Dcb, Projections and TestKit under Base/, with CCC.Base.* namespaces |
| ADR-014: Automations React to Events by Issuing Commands | Adds automations, such as the default team of a new tenant, which issue commands instead of appending events, and defines their bookmark, repeated reactions and stalls |
| ADR-015: Every Module Owns Its Database, Hosted Through ModuleHosting | Gives every module its own database for projections and automation bookmarks, with one default connection string and optional overrides, and moves what projections and automations share into ModuleHosting |