# Elsa Workflows Constitution ## Core Principles ### I. Modular Architecture Every feature area MUST be implemented as an independent module (separate .csproj) with clear boundaries. - Modules reside under `src/modules/` and MUST be self-contained with their own DI registration, contracts, and implementations. - Each module MUST follow the standard directory structure: `ShellFeatures/`, `Contracts/`, `Services/`, `Extensions/`, `Models/`, and optionally `Activities/`, `Middleware/`, `Handlers/`. - No module may directly reference another module's internal types. Cross-module communication MUST go through published contracts (interfaces) or the mediator. - Shared infrastructure belongs in `src/common/`; application hosts belong in `src/apps/`. **Rationale**: Modularity enables independent development, testing, and deployment of features. It keeps the 100+ project solution manageable and allows consumers to depend only on the modules they need via NuGet. ### II. Composition & Extensibility The system MUST favour composition over inheritance and provide explicit extensibility points for every major subsystem. - Features register via Shell Features (`IShellFeature`, `IMiddlewareShellFeature`) with dependency declarations through the `[ShellFeature(DependsOn = [...])]` attribute. The shell resolves and initialises features in correct order. - Activities are the composable building blocks of workflows. New activities MUST extend `Activity`, `Activity`, `CodeActivity`, or `CodeActivity` and declare metadata via `[Activity]`, `[Input]`, and `[Output]` attributes. - Persistence MUST be provider-agnostic. Store interfaces (e.g., `IWorkflowDefinitionStore`) define the contract; EF Core implementations are one provider among potentially many. - Expression evaluation MUST be pluggable via `IExpressionEvaluator` implementations (JavaScript, C#, Python, Liquid). - Service registration MUST use `Microsoft.Extensions.DependencyInjection` with fluent `IServiceCollection` extension methods per module. **Rationale**: Elsa is a library embedded in arbitrary .NET hosts. Users MUST be able to swap persistence, expression engines, and feature sets without modifying core code. ### III. Convention-Driven Design The codebase MUST use consistent, discoverable conventions to reduce cognitive load and enable tooling automation. - Activity metadata MUST be declared via attributes (`[Activity]`, `[Input]`, `[Output]`) — not via external configuration. - Inputs and outputs MUST use the typed wrappers `Input` and `Output` for expression-capable, type-safe data flow. - API endpoints MUST follow the single-endpoint-per-class pattern (`ElsaEndpoint`) with collocated request/response models. - Naming conventions: - Feature classes: `{Area}Feature` (e.g., `HttpFeature`, `WorkflowsFeature`) - Store interfaces: `I{Entity}Store` - Extension methods: `{Module}ServiceCollectionExtensions` - Test classes: `{Subject}Tests` - C# latest language version, nullable reference types enabled, implicit usings enabled — enforced via `Directory.Build.props`. **Rationale**: Predictable patterns make the large codebase navigable and reduce onboarding friction. Attribute-driven metadata enables automatic UI generation in the visual designer. ### IV. Async & Pipeline Execution All I/O-bound and workflow execution paths MUST use async/await. Cross-cutting concerns MUST be handled via middleware pipelines. - Activity execution flows through `IActivityExecutionPipeline` — a composable middleware chain built with `IActivityExecutionPipelineBuilder`. - Workflow execution uses `IWorkflowRunner` with scoped `ActivityExecutionContext` for state isolation. - Internal messaging uses the custom `IMediator` (request/response and notification patterns) — not external libraries. - `ValueTask` SHOULD be preferred over `Task` for hot execution paths where synchronous completion is common. **Rationale**: Workflows are inherently asynchronous and long-running. Pipeline architecture enables observability, resilience, and logging middleware without polluting activity code. ### V. Testing Discipline New code MUST include tests. Tests MUST be organised by scope and follow established patterns. - **Framework**: xUnit with `[Fact]` and `[Theory]` attributes. - **Test organisation**: `test/unit/` for isolated tests, `test/integration/` for end-to-end scenarios, `test/component/` for feature testing. - **Shared fixtures**: Use `ActivityTestFixture` for unit-testing activities and `WorkflowTestFixture` for integration tests. - Test methods MUST use descriptive names; `DisplayName` SHOULD be set for readability. - Tests MUST NOT depend on external services or network access unless explicitly categorised as integration tests. **Rationale**: The workflow engine is the critical path for all consuming applications. Regressions in core execution logic have outsized impact. ### VI. Trunk-Based Development All changes MUST flow through Pull Requests targeting the `main` branch. - One PR = one concern (bug fix, refactor, feature, docs, or dependency update). PRs that mix unrelated concerns MUST be split. - PRs MUST include: clear problem statement, expected behaviour, steps to verify, and tests for new code. - Small, focused PRs are preferred for faster review and safer merges. - API documentation MUST be updated when APIs change. - Code review is required before merge. **Rationale**: Trunk-based development with focused PRs maintains velocity while keeping the codebase stable for the large contributor community. ### VII. Simplicity & Focus Complexity MUST be justified. Start simple; avoid speculative generalisation. - YAGNI: do not add features, abstractions, or configuration for hypothetical future requirements. - Prefer direct implementations over indirection layers unless the indirection serves a documented extensibility need. - Each module MUST have a clear, singular purpose — no "grab bag" utility modules without justification. - Error handling SHOULD be proportional: validate at system boundaries (user input, external APIs); trust internal code and framework guarantees. **Rationale**: A 100+ project solution is only sustainable when each part earns its existence. Unnecessary abstraction increases maintenance burden and onboarding cost. ## Technology Stack & Constraints - **Runtime**: .NET 10.0 (primary), with multi-target support for .NET 8.0 and .NET 9.0 via `` in `src/Directory.Build.props`. - **Language**: C# latest (`latest`). - **Nullable reference types**: Enabled globally. - **Implicit usings**: Enabled globally. - **Build system**: NUKE build automation (`build/Build.cs`); CI runs `./build.cmd Compile Test Pack`. - **Package management**: Central package management via `Directory.Packages.props`; NuGet source mapping in `NuGet.Config`. - **Serialization**: System.Text.Json with custom converters and type registries; polymorphic serialisation via `IWellKnownTypeRegistry`. - **Persistence**: EF Core with per-module `DbContext`; generic `Store` base class; supports SQL Server, PostgreSQL, MySQL, SQLite, Oracle. - **Multi-tenancy**: `ITenantAccessor` with `AsyncLocal` context; query filters for tenant isolation. - **License**: MIT. - **Docker**: Server, Studio, and combined images available under `docker/`. ## Development Workflow & Quality Gates ### Build ```bash # Restore (always use --ignore-failed-sources for external feed resilience) ./build.sh Restore --ignore-failed-sources # Compile (excludes studio apps) ./build.sh Compile # Test ./build.sh Test # Full CI pipeline ./build.sh Compile Test Pack ``` - NU1900/NU1801 warnings for external feeds are expected and safe to ignore. - Individual modules can be built with `dotnet build src/modules/{Module}/`. ### Quality Gates for PRs 1. Code compiles without errors on all target frameworks. 2. All existing tests pass. 3. New code includes appropriate tests (unit and/or integration). 4. API changes include documentation updates. 5. PR is scoped to a single concern. 6. Code review approved by at least one maintainer. ### Commit Message Convention Follow conventional commits: `feat:`, `fix:`, `refactor:`, `chore:`, `docs:`, `test:`, `perf:`. ## Governance This constitution is the authoritative reference for architectural decisions and development practices in the Elsa Workflows repository. - **Precedence**: This constitution supersedes ad-hoc conventions. When in conflict, this document governs. - **Amendments**: Changes to this constitution MUST be documented with a version bump, rationale, and migration guidance where applicable. - **Versioning**: Constitution versions follow semantic versioning: - MAJOR: Backward-incompatible principle removals or redefinitions. - MINOR: New principle or section added, materially expanded guidance. - PATCH: Clarifications, wording, typo fixes, non-semantic refinements. - **Compliance review**: PRs and implementation plans SHOULD reference the Constitution Check section in `plan-template.md` to verify alignment. - **Complexity justification**: Any deviation from these principles MUST be documented in the Complexity Tracking table of the implementation plan. - **Runtime guidance**: See `.github/copilot-instructions.md` for build commands, troubleshooting, and CI details. **Version**: 1.0.0 | **Ratified**: 2026-03-08 | **Last Amended**: 2026-03-08