SchoolAccount-Web is an MVC presentation application for the DfE School Account service built on .NET 10. It uses a minimal clean architecture solution, with CQRS abstractions, structured logging, error handling, and architecture tests.
- Clean Architecture - layers, dependency rules, and code organisation
- Coding Standards - formatting, code analysis, naming, and style conventions
- Contributing - guidance on repository branching strategies
- Testing Standards - conventions and practices for writing tests
- Integration Testing - guidance on integration testing of the controller endpoints
Architecture decisions are recorded as ADRs in the decisions folder:
- Use Markdown Architectural Decision Records - why and how we record decisions
- Structure the solution using clean architecture - layers, dependency rules, and code organisation
- Strip the imported template to a minimal core - what was removed from the original template and why
- Run tests on the Microsoft Testing Platform - testing platform and how results and coverage are reported in CI
- Format code with CSharpier - why formatting is automated and enforced in the build
- Enforce code quality with Roslyn analysers - why SonarAnalyzer.CSharp and strict analysis are enforced in the build
- Supporting SASS within GDS Styles - why SASS support has been enabled
- Use feature structure - why the feature structure has been adopted
- Authentication using DSI - why we authenticate with DfE Sign-In
-
- Use containerisation to publish code - why we have chosen to use containerisation and push to the github container registry
New decisions should follow the ADR template.
Follow these steps to start the MVC locally.
Note: Windows users can use the git bash command prompt to run the project's .sh bash scripts.
-
Install prerequisites:
- .NET 10 SDK
- Docker Desktop
- Rider, Visual Studio, or Visual Studio Code
-
Run the setup script from the repository root to restore the dotnet tools and enable the git hooks:
./init.sh
-
Run the MVC using one of the following:
Method Command Outcome Docker Compose docker compose up --buildStarts the MVC and its dependencies (Seq) in containers .NET CLI dotnet run --project src/SchoolAccount.Web.MvcRuns the MVC directly using the httplaunch profile, no containersIn Rider or Visual Studio you can use the equivalent
docker-composeorhttprun configurations from the toolbar. -
Once running, the presentation is available at
http://localhost:5016:- Logs (if started with compose) at
http://localhost:8081
- Logs (if started with compose) at
-
Debugging guidance:
- Set breakpoints in your C# files under
src/and start either run configuration with debugging enabled.
- Set breakpoints in your C# files under
The project requires the following app configuration values to be overridden, ideally using User Secrets:
{
"OpenIDConnectSettings": {
"Authority": "<URL-OF-DSI-OIDC-SERVER>",
"ClientId": "<DSI-CLIENT-ID>"
}
}Use the .NET CLI to build or test the solution.
-
To build locally:
dotnet build
-
To run all tests:
dotnet test
Architecture tests under tests/SchoolAccount.ArchitectureTests enforce the clean architecture dependency rules between layers.
Code is formatted with CSharpier, installed as a local dotnet tool and enforced by the "Check formatting" step in the build workflow. To format the solution locally:
dotnet csharpier format .A pre-commit hook, managed by Husky.NET and configured in .husky/task-runner.json, formats staged C# files automatically before each commit; init.sh installs it and restores the tools on a fresh clone. To format on save, install the Rider plugin or the VS Code extension; the editors documentation covers setup for these and other IDEs. See Format code with CSharpier for the reasoning.
The build runs with the full set of .NET/Roslyn analyzers (AnalysisLevel=latest, AnalysisMode=All) plus
SonarAnalyzer.CSharp, configured in
Directory.Build.props. TreatWarningsAsErrors means any violation fails dotnet build,
locally and in the build workflow, rather than being left as a warning. Rules that
don't fit this codebase are suppressed by ID in .editorconfig. See
Coding Standards and
Enforce code quality with Roslyn analysers for the
conventions and the reasoning.
The build workflow collects code coverage on every run, posts a summary to the pull
request, and fails the build if line coverage drops below the minimum threshold. The threshold is defined by the
MIN_LINE_COVERAGE variable at the top of build.yml. Which files are included is
controlled by coverage.config.
To generate the same report locally, run coverage.sh from the repository root:
./coverage.shThe script runs all tests with coverage enabled, merges the per-project results with ReportGenerator, and writes an
HTML report to TestResults/CoverageReport/index.html. Pass --open to open the report in your browser when it
finishes:
./coverage.sh --openThe solution follows a clean architecture pattern with vertical slice features:
| Project | Purpose |
|---|---|
SchoolAccount.Web.Mvc |
ASP.NET Core Web MVC - controllers, middleware, error handling |
SchoolAccount.Application |
CQRS handlers and feature logic, organised by feature folder |
SchoolAccount.Domain |
Domain entities and business rules |
SchoolAccount.Infrastructure |
External concerns - time, data access, integrations |
SchoolAccount.SharedKernel |
Shared primitives - Result<T>, Error, ValidationError |
Structured logs are written via Serilog to Seq. When running via Docker Compose, the Seq UI is available at http://localhost:8081.
The Web project is published to the GitHub Container Registry
as a Docker image that can be pulled down and run.
The image is created on every push to the main branch and tagged with the current commit SHA and the latest tag.
To verify the image locally, you can run:
docker run --platform linux/amd64 --name web -e OpenIDConnectSettings__ClientId=SA_TEST_CLIENT -e OpenIDConnectSettings__Authority=https://localhost:7041 -e ASPNETCORE_ENVIRONMENT=development -p 5100:8080 -d --pull=always ghcr.io/dfe-digital/schoolaccount-web:latest
You can then test the Web project by visiting http://localhost:5100.
To stop and delete the container, you can run:
docker stop web
docker rm web
- Branch from
mainusing the conventiontask/<short-description>orfeature/<short-description>. - Open a pull request against
main. - The build workflow must pass before merging.