Thank you for your interest. v2 is early. The most useful contributions right now are review of the requirements and the architecture decision records, and work on issues in the M1 milestone.
| Branch | Role |
|---|---|
v2 |
v2 development and the default branch. All v2 pull requests target it. |
dev |
v1, security fixes only. v1 pull requests must target dev explicitly. |
archive/* |
Old experiments, kept for reference, not maintained. |
docs/requirements/: what v2 must do.docs/adr/: why it is built the way it is.
- Every change starts from an issue. Pick one from the M1 milestone or open one with the matching template. For anything beyond a small fix, wait for a maintainer to confirm the approach before writing code.
- Branch from
v2, named<issue-number>-<short-slug>, for example2412-bootstrap-v2. - Open a pull request against
v2. PutCloses #<issue-number>in the description. Keep the pull request to its issue; unrelated changes go in their own issue. - CI must pass. Pull requests are squash-merged, so the pull request title becomes the commit title. Keep it short and imperative: "Add change set revert", not "Added revert feature".
Commits and pull requests are authored by the person who submits them. Do not add tool-generated co-author trailers or "generated by" footers. You are responsible for what you submit, whatever tools you used to write it.
v1orv2: which line the issue belongs to.type:*:epic,feature,bug,chore,docs,adr,question.area:*: the requirement group the work touches:schema,content,entities,change-sets,rules,checks,routing,desk,mcp,audit,api,forms,media,users,ext,infra.- Milestones
M1 Governance core,M2 Built-in agent and full adminandM3 Scale outfollowdocs/requirements/03-feature-list.md.
Open an issue with the ADR template (label type:adr). Describe the context, the proposed decision, the alternatives and the consequences. If the maintainers accept it, add the record to docs/adr/ following the format in ADR-0001, either in the pull request that implements the change or in its own pull request when the decision comes first.
Product decisions live in docs/requirements/00-decision-record.md. Propose a change through an issue. The maintainers update the record; requirement documents are not edited in feature pull requests.
You need the .NET 10 SDK and nothing else; global.json pins the version and Node is not required.
dotnet build
dotnet testTests run against SQLite in-process. To run the PostgreSQL tests as well, set FLUENTCMS_TEST_POSTGRES to a connection string for an empty database, for example Host=localhost;Port=5432;Database=fluentcms_test;Username=postgres;Password=postgres. CI does this with a service container. Without the variable those tests are skipped.
To run the host, dotnet run --project src/FluentCMS.Host starts the web host on http://localhost:5000 with a SQLite database in fluentcms.db, and dotnet run --project src/FluentCMS.Host -- mcp starts the stdio mode. Configuration comes from environment variables such as Database__ConnectionString, Database__Provider (sqlite or postgresql, inferred from the connection string when omitted) and JobQueue__WorkerCount, and from an optional appsettings.json next to the binary.
Each provider has its own DbContext subclass and migrations folder (ADR-0005). After changing the model, add a migration for both; no database needs to be running, the design-time factories build the model on their own.
dotnet tool restore
dotnet ef migrations add <Name> --project src/FluentCMS.Infrastructure --context SqliteFluentCmsDbContext --output-dir Persistence/Migrations/Sqlite
dotnet ef migrations add <Name> --project src/FluentCMS.Infrastructure --context PostgreSqlFluentCmsDbContext --output-dir Persistence/Migrations/PostgreSqlMigrations apply automatically when the host starts. Every migration needs a working Down, since upgrades must be reversible one version back (OPS-04).
Every pluggable part of the product is an interface in FluentCMS.Core marked [ExtensionPoint]. Implementations register through dependency injection, either explicitly with AddFluentCmsExtension<TContract, TImplementation>() or by discovery with AddFluentCmsExtensions(assembly), which picks up every concrete class implementing an extension-point interface in that assembly. Both paths produce the same IExtensionCatalog entry and the same IEnumerable<TContract> resolution, so built-ins under FluentCMS.Core.Builtin and future plugins look identical to the rest of the product. Each interface is documented where it is defined, together with the conformance tests an implementation must pass.
.editorconfig is the source of truth: UTF-8, LF line endings, four spaces in C#, two in JSON and YAML, file-scoped namespaces. Nullable reference types and implicit usings are enabled project-wide. Prefer clear code over clever code. Comments explain why, not what. Do not add XML documentation comments unless an issue asks for them.
This project follows the Code of Conduct. Report vulnerabilities as described in the security policy, never in a public issue.