Architecture Overview
The CMF operates on two axes: domain modeling (what the data is) and content presentation (how the data is shown). Both axes are expressed as M2 DSLs on top of the M3 meta-metamodel, compiled by multi-staged Roslyn source generators.
Shared C# Kernel
The defining architectural choice is the shared kernel. The same C# types compile to both ASP.NET (server) and Blazor WebAssembly (browser). DTOs, validation rules, widget contracts, and content block definitions live in a shared project referenced by both the server and client. This eliminates the impedance mismatch between frontend and backend that plagues JavaScript-based CMSes.
Solution Structure
The CMF ships as NuGet packages. Each DSL is a project pair: attributes (the DSL surface) and generators (the compilation pipeline).
Cmf.sln
├── src/
│ ├── Cmf.Meta.Lib/ ← M3 attributes (MetaConcept, MetaProperty...)
│ ├── Cmf.Meta.Generators/ ← Stage 0: metamodel registry generator
│ │
│ ├── Cmf.Ddd.Lib/ ← M2: DDD DSL ([AggregateRoot], [Entity], [Composition]...)
│ ├── Cmf.Ddd.Abstractions/ ← Interfaces (IRepository<T>, ICommandHandler<T>...)
│ ├── Cmf.Ddd.Generators/ ← Stage 1+2: domain entity + CQRS generation
│ │
│ ├── Cmf.Content.Lib/ ← M2: CMS DSL ([ContentPart], [ContentBlock]...)
│ ├── Cmf.Content.Abstractions/ ← Interfaces (IContentPart, IBlock, IVersionable...)
│ ├── Cmf.Content.Generators/ ← Stage 2: content parts + blocks generation
│ │
│ ├── Cmf.Infrastructure.EfCore/ ← EF Core integration (DbContext base, conventions)
│ ├── Cmf.Infrastructure.EfCore.Generators/ ← Stage 2+3: persistence generation
│ │
│ ├── Cmf.Infrastructure.Search/ ← Search integration (Lucene.NET / Elasticsearch)
│ ├── Cmf.Infrastructure.Media/ ← Media processing (image resize, CDN, storage)
│ │
│ ├── Cmf.Admin.Lib/ ← M2: Admin DSL ([AdminModule], [AdminField])
│ ├── Cmf.Admin.Generators/ ← Stage 3: Blazor admin component generation
│ │
│ ├── Cmf.Pages.Lib/ ← M2: Page/Widget DSL + runtime entities
│ ├── Cmf.Pages.Abstractions/ ← Interfaces (IPage, IWidget, IZone, IPageRouter...)
│ ├── Cmf.Pages.Generators/ ← Stage 3: page widget + dynamic routing generation
│ │
│ ├── Cmf.Shared/ ← Shared kernel (DTOs, validation, contracts)
│ ├── Cmf.Cli/ ← CLI tool (dotnet tool)
│ └── Cmf.Templates/ ← dotnet new templates
│
├── test/
│ ├── Cmf.Ddd.Lib.Testing/ ← Test helpers (fake repos, event assertions)
│ ├── Cmf.Infrastructure.EfCore.Testing/ ← Test helpers (in-memory DbContext)
│ ├── Cmf.Pages.Lib.Testing/ ← Test helpers (fake page tree)
│ └── Cmf.Meta.Generators.Tests/ ← Generator unit testsCmf.sln
├── src/
│ ├── Cmf.Meta.Lib/ ← M3 attributes (MetaConcept, MetaProperty...)
│ ├── Cmf.Meta.Generators/ ← Stage 0: metamodel registry generator
│ │
│ ├── Cmf.Ddd.Lib/ ← M2: DDD DSL ([AggregateRoot], [Entity], [Composition]...)
│ ├── Cmf.Ddd.Abstractions/ ← Interfaces (IRepository<T>, ICommandHandler<T>...)
│ ├── Cmf.Ddd.Generators/ ← Stage 1+2: domain entity + CQRS generation
│ │
│ ├── Cmf.Content.Lib/ ← M2: CMS DSL ([ContentPart], [ContentBlock]...)
│ ├── Cmf.Content.Abstractions/ ← Interfaces (IContentPart, IBlock, IVersionable...)
│ ├── Cmf.Content.Generators/ ← Stage 2: content parts + blocks generation
│ │
│ ├── Cmf.Infrastructure.EfCore/ ← EF Core integration (DbContext base, conventions)
│ ├── Cmf.Infrastructure.EfCore.Generators/ ← Stage 2+3: persistence generation
│ │
│ ├── Cmf.Infrastructure.Search/ ← Search integration (Lucene.NET / Elasticsearch)
│ ├── Cmf.Infrastructure.Media/ ← Media processing (image resize, CDN, storage)
│ │
│ ├── Cmf.Admin.Lib/ ← M2: Admin DSL ([AdminModule], [AdminField])
│ ├── Cmf.Admin.Generators/ ← Stage 3: Blazor admin component generation
│ │
│ ├── Cmf.Pages.Lib/ ← M2: Page/Widget DSL + runtime entities
│ ├── Cmf.Pages.Abstractions/ ← Interfaces (IPage, IWidget, IZone, IPageRouter...)
│ ├── Cmf.Pages.Generators/ ← Stage 3: page widget + dynamic routing generation
│ │
│ ├── Cmf.Shared/ ← Shared kernel (DTOs, validation, contracts)
│ ├── Cmf.Cli/ ← CLI tool (dotnet tool)
│ └── Cmf.Templates/ ← dotnet new templates
│
├── test/
│ ├── Cmf.Ddd.Lib.Testing/ ← Test helpers (fake repos, event assertions)
│ ├── Cmf.Infrastructure.EfCore.Testing/ ← Test helpers (in-memory DbContext)
│ ├── Cmf.Pages.Lib.Testing/ ← Test helpers (fake page tree)
│ └── Cmf.Meta.Generators.Tests/ ← Generator unit testsA user project scaffolded by cmf new MyStore follows the same DDD separation:
MyStore.sln
├── src/
│ ├── MyStore.Lib/ ← Domain model (aggregates, entities, commands, events)
│ ├── MyStore.Abstractions/ ← Domain interfaces (shared across bounded contexts)
│ ├── MyStore.Infrastructure.Postgres/ ← EF Core implementation for Postgres
│ ├── MyStore.Infrastructure.Search/ ← Search implementation
│ ├── MyStore.Infrastructure.Media/ ← Media storage implementation
│ ├── MyStore.Server/ ← ASP.NET host (API + admin + page routing)
│ ├── MyStore.Client/ ← Blazor WASM (SPA frontend)
│ └── MyStore.Shared/ ← Shared kernel (DTOs, validation, widget contracts)
│
├── test/
│ ├── MyStore.Lib.Testing/ ← Domain unit tests
│ ├── MyStore.Infrastructure.Postgres.Testing/ ← Integration tests
│ └── MyStore.Server.Testing/ ← API integration testsMyStore.sln
├── src/
│ ├── MyStore.Lib/ ← Domain model (aggregates, entities, commands, events)
│ ├── MyStore.Abstractions/ ← Domain interfaces (shared across bounded contexts)
│ ├── MyStore.Infrastructure.Postgres/ ← EF Core implementation for Postgres
│ ├── MyStore.Infrastructure.Search/ ← Search implementation
│ ├── MyStore.Infrastructure.Media/ ← Media storage implementation
│ ├── MyStore.Server/ ← ASP.NET host (API + admin + page routing)
│ ├── MyStore.Client/ ← Blazor WASM (SPA frontend)
│ └── MyStore.Shared/ ← Shared kernel (DTOs, validation, widget contracts)
│
├── test/
│ ├── MyStore.Lib.Testing/ ← Domain unit tests
│ ├── MyStore.Infrastructure.Postgres.Testing/ ← Integration tests
│ └── MyStore.Server.Testing/ ← API integration testsCompilation Pipeline
The multi-staged source generator pipeline from Modeling, Metamodeling, and Meta-Metamodeling in C# compiles the five DSLs: