Thanks for your interest in contributing. This repository is both a working reference application and a packaged dotnet new template, so changes are verified in both forms.
- .NET SDK matching global.json (10.0.2xx;
rollForward: latestFeatureapplies). - Docker — required to run the API integration tests (Testcontainers) and local PostgreSQL.
- No IDE requirement; the solution file is CleanApiStarter.slnx.
git clone https://github.com/cbjpdev/clean-api-starter.git
cd clean-api-starter
dotnet build CleanApiStarter.slnx
dotnet test CleanApiStarter.slnxTo run the API locally, use the Aspire AppHost (starts PostgreSQL with the schema scripts applied, plus pgAdmin):
dotnet run --project src/CleanApiStarter.AppHostAlternatively, start PostgreSQL with docker compose up -d and run src/CleanApiStarter.Api directly.
See the README for the solution layout and layer dependency rules. The short version: dependencies point inward — Domain references nothing, Application references only Domain, and web/persistence concerns stay in Api, AspNetCore, and Infrastructure.
- Branch from
main(the convention here isfeature/<issue-number>-short-description). - Keep changes focused; unrelated refactoring belongs in its own PR.
- Open a pull request against
main. CI must pass before review.
The same checks run on every PR (build.yml, template.yml, codeql.yml):
- Formatting —
dotnet format CleanApiStarter.slnx --verify-no-changes. Rundotnet format CleanApiStarter.slnxbefore pushing; style rules live in .editorconfig. - Build and tests — the full suite, including the Testcontainers-based integration tests.
- Template verification — the template is packed, installed, and instantiated to confirm generated projects still build.
- CodeQL security scanning.
- Unit tests:
tests/CleanApiStarter.Application.UnitTests(xUnit v3, AutoFixture, NSubstitute, Shouldly). - Integration tests:
tests/CleanApiStarter.Api.IntegrationTests(xUnit v3 against a real PostgreSQL container; Docker must be running). - Shared test infrastructure (the
ApiApplicationFactoryclass fixture, AutoFixture attributes) lives intests/CleanApiStarter.Tests.
New behavior needs tests. Integration tests share one database per test class, so isolate through unique user ids or resource names rather than assuming a fresh schema.
For a local coverage report:
./scripts/test-coverage.shThe SQL scripts in database/migrations are the schema's source of truth; the EF Core entity configurations in src/CleanApiStarter.Infrastructure/Persistence/Configuration must be kept in sync with them manually. When changing either, update both.
Conventions:
- Timestamp columns are
TIMESTAMP WITH TIME ZONE; all values are stored in UTC (DateTime.UtcNowin code). - Migration files are named
V<NNN>__description.sqland are applied in file-name order by both the AppHost and the integration test factory. - Migrations must be idempotent (
CREATE TABLE IF NOT EXISTS, etc.).
If your change affects the project structure, file names, or anything under .template.config/template.json, verify the template output locally:
dotnet pack CleanApiStarter.Template.csproj --configuration Release --output artifacts
dotnet new install artifacts/CleanApiStarter.Template.0.0.0.nupkg --force
dotnet new clean-api-starter -n DemoProduct -o /tmp/DemoProduct
dotnet build /tmp/DemoProductRepository-only files (CI release workflows, this guide, install scripts) must be listed in the exclude section of template.json so they don't ship inside generated projects.
Open a GitHub issue with reproduction steps, expected vs. actual behavior, and your environment (OS, .NET SDK version). For security vulnerabilities, please do not open a public issue — contact the maintainer directly instead.