Repository navigation
Rule reference
Every rule in dotnet-modular-react-postgresql@1.0.0, what it checks, why it
has the severity it has, and what to do when it fails.
All 21 rules expect their signal to be true. Six are blocking, fourteen are
required, one is recommended. The maximum weighted score is 73 points: 6 × 5 +
14 × 3 + 1 × 1.
{
"id": "api.version-v1",
"severity": "blocking",
"description": "The public API uses the /api/v1 prefix.",
"signal": "apiVersioning",
"expected": true,
"remediation": "Version public routes under /api/v1 and document the evolution policy."
}The rule passes when the observed signal equals expected. The remediation
string is what appears in the report and becomes the task text in the plan, so
it is written as an instruction rather than as a complaint.
blocking is reserved for two situations: a stack decision that would make the
whole profile the wrong standard, or a security default whose absence is
dangerous rather than merely untidy. Everything a team would reasonably fix
next sprint is required. Everything that is good practice but context
dependent is recommended.
One blocking failure makes the repository not compliant regardless of score. The full arithmetic is in Scoring and compliance.
blocking · signal forbiddenNestAbsent
The backend does not use NestJS.
Remove NestJS dependencies and keep the backend on ASP.NET Core.
Blocking because it is not a defect, it is a different architecture. A NestJS backend is not a partially compliant .NET system, so continuing to grade it against this profile produces a meaningless number. Either the repository belongs to a different Golden Path, or this dependency arrived by accident.
blocking · signal forbiddenNextAbsent
The frontend does not use Next.js.
Remove Next.js and keep the frontend as a React application.
Detected by a next dependency or by a next.config.* file. The profile treats
server-side rendering as a decision that belongs to a different path, mostly
because it changes where authorization and data fetching live, and this
profile's security rules assume the API is the only trust boundary.
blocking · signal modularDotnet
The .NET solution separates Domain, Application, and Infrastructure.
Organize the .NET solution into business modules with Domain, Application, and Infrastructure layers.
Blocking because it is the profile's central claim. This is the only rule whose
signal is composite: it needs a .sln or .csproj and all three layer
directories. A repository failing it will usually also fail the three rules
below, which is redundancy on purpose. The three tell you which layer is
missing, this one tells you the shape is wrong.
required · signal domainLayer
There is an independent Domain layer.
Create the Domain layer and keep business rules and models there, free of infrastructure dependencies.
The signal only proves a Domain/ directory exists. It cannot prove
independence. quality.architecture-tests is what actually enforces the
dependency direction, and this rule is the cheap precondition for it.
required · signal applicationLayer
There is an Application layer for use cases.
Create the Application layer and make use cases, commands, queries, and ports explicit.
required · signal infrastructureLayer
There is an Infrastructure layer for external adapters.
Create the Infrastructure layer and keep persistence and external integrations there.
required · signal endpointLayer
Controllers or endpoints form a thin HTTP layer.
Create thin Controllers or Endpoints that delegate execution to use cases.
Satisfied by a Controllers/ or Endpoints/ directory. Minimal APIs declared
entirely inside Program.cs will fail this rule even though they are a
perfectly good design. Group them into an Endpoints/ directory to pass, which
is the layout the profile recommends anyway.
blocking · signal apiVersioning
The public API uses the /api/v1 prefix.
Version public routes under /api/v1 and document the evolution policy.
Blocking because an unversioned public API is a decision you cannot undo
cheaply. Once external clients depend on /orders, introducing versioning means
breaking them or maintaining two shapes forever.
The detector wants a quoted literal containing /api/v1. Attribute routes
written as [Route("api/v1/orders")] miss, because the pattern expects the
leading slash inside the quotes. Route prefixes assembled by concatenation also
miss. See the signal reference.
required · signal openApi
The API publishes an OpenAPI contract.
Enable OpenAPI and validate the generated document in the pipeline.
Matches AddOpenApi, MapOpenApi, AddSwaggerGen, or UseSwagger, so both
the .NET 9+ built-in and Swashbuckle satisfy it.
required · signal problemDetails
HTTP errors follow Problem Details.
Standardize errors with RFC 9457 Problem Details and stable domain codes.
The weakest signal in the profile: any mention of the ProblemDetails type
passes it. Do not read a pass here as evidence that your error contract is
consistent.
required · signal jwtBearer
The API authenticates JWT Bearer tokens issued by the OIDC provider.
Configure JWT Bearer with validated issuer, audience, signature, and clock skew.
Required rather than blocking, because an internal service behind a gateway that terminates authentication elsewhere is a legitimate design. If that is your case, the honest resolution is a profile of your own rather than ignoring the finding.
required · signal authorizationPolicies
Authorization is expressed through policies.
Define policies per business capability and apply them to the endpoints.
Matches AddPolicy or IAuthorizationHandler. Role checks scattered through
[Authorize(Roles = "...")] attributes will not satisfy it, which is the point:
the policy asks for authorization expressed as named capabilities rather than as
role strings repeated across controllers.
blocking · signal defaultDeny
Authorization uses default deny.
Set an authenticated FallbackPolicy and grant anonymous access only where it is declared.
Blocking because the failure mode is silent. An endpoint added without an
[Authorize] attribute is public, nobody notices in review, and the first
person to notice is whoever finds it. A FallbackPolicy inverts that: forgetting
the attribute produces a 401 rather than a leak.
The signal only checks that the word FallbackPolicy appears somewhere in a
.cs file. It does not verify the value assigned to it.
required · signal postgresEfCore
Persistence uses PostgreSQL through the EF Core Npgsql provider.
Configure EF Core with Npgsql and keep data access inside Infrastructure.
Matches the package name or a UseNpgsql call, in any text file, so a
PackageReference in a .csproj is enough.
required · signal migrations
Database changes are versioned as migrations.
Add versioned migrations and validate them before deployment.
The path pattern is case-sensitive and expects Migrations/. A lowercase
migrations/ directory fails. This is the most common false negative in the
profile.
blocking · signal reactWeb
The web interface uses React without Next.js.
Create a React application and organize features by domain.
Requires a react dependency and the absence of next. A repository with no
frontend at all fails this rule, which is the correct answer for a profile whose
name promises React, and the wrong answer for an API-only service. An API-only
service should use a profile that does not claim a frontend.
required · signal unitTests
Domain rules and use cases have unit tests.
Add unit tests for domain rules and for critical use cases.
Detected by a UnitTests/ directory. It measures the convention, not coverage.
required · signal integrationTests
HTTP and PostgreSQL integrations have automated tests.
Add integration tests for the API and for PostgreSQL persistence.
Detected by an IntegrationTests/ directory.
recommended · signal architectureTests
Dependencies between layers are protected by architecture tests.
Add architecture tests that prevent unwanted dependencies between layers.
The only recommended rule, and the only one worth arguing about. It is what
actually keeps architecture.domain honest over time, since a directory named
Domain/ stops meaning anything the day someone adds a DbContext reference to
it. It stays recommended because a small team can reasonably hold that line by
review, and a rule nobody can satisfy on day one gets ignored.
Detected by an ArchitectureTests/ or ArchTests/ directory.
required · signal healthChecks
The application exposes operational health checks.
Configure liveness and readiness, including the PostgreSQL dependency.
Matches AddHealthChecks or MapHealthChecks. It cannot tell liveness from
readiness, and it cannot tell whether the PostgreSQL dependency is included. The
remediation asks for more than the signal can verify, on purpose: it is written
for the person doing the work, not for the detector.
required · signal structuredLogging
Logs are structured and preserve correlation.
Configure ILogger or Serilog with structured properties and a correlation ID.
Matches Serilog or ILogger< in any text file. Nearly every ASP.NET Core
application passes this by default, so treat it as a floor rather than as
evidence that correlation actually works.
| Rule | Severity | Signal |
|---|---|---|
stack.no-nestjs |
blocking | forbiddenNestAbsent |
stack.no-nextjs |
blocking | forbiddenNextAbsent |
architecture.modular-dotnet |
blocking | modularDotnet |
architecture.domain |
required | domainLayer |
architecture.application |
required | applicationLayer |
architecture.infrastructure |
required | infrastructureLayer |
api.endpoints |
required | endpointLayer |
api.version-v1 |
blocking | apiVersioning |
api.openapi |
required | openApi |
api.problem-details |
required | problemDetails |
security.jwt |
required | jwtBearer |
security.policies |
required | authorizationPolicies |
security.default-deny |
blocking | defaultDeny |
database.postgresql-efcore |
required | postgresEfCore |
database.migrations |
required | migrations |
frontend.react |
blocking | reactWeb |
quality.unit-tests |
required | unitTests |
quality.integration-tests |
required | integrationTests |
quality.architecture-tests |
recommended | architectureTests |
operations.health-checks |
required | healthChecks |
operations.structured-logging |
required | structuredLogging |
Repository · Releases · Issues · MIT license
Normative contracts live in
docs/. Where
this wiki disagrees with the repository, the repository is correct.
Getting started
Reference
The catalog
Using it
Project