Skip to content

Profile dotnet modular react postgresql

Thiago Botelho edited this page Aug 15, 2026 · 1 revision

Profile: .NET modular + React + PostgreSQL

  • Identifier: dotnet-modular-react-postgresql
  • Version: 1.0.0
  • Digest: sha256:89963b03fac95b7af4972176a46b92143948ddf280b3bc627d53539af797b56f
  • Contents: 6 policies, 4 recipes, 1 gate set, 21 rules

The only profile shipping in 0.1. It describes a modular monolith on ASP.NET Core .NET 10, a React web client, and PostgreSQL through EF Core.

Reference architecture

flowchart TD
    WEB["React Web"] --> API["ASP.NET Core /api/v1"]
    API --> APP["Application, use cases"]
    APP --> DOM["Domain, rules and invariants"]
    INF["Infrastructure, adapters"] --> APP
    INF --> DB["PostgreSQL"]
Loading

Each module owns one business capability along with its model, use cases, and persistence. The HTTP API and the composition host sit at the edge.

The shape keeps a path open toward extracting services later without paying the operational cost of microservices up front. That is a bet, and the profile says so in its architecture policy: extract when metrics justify it, not when an architecture diagram looks crowded.

Principles

The manifest states five:

  • contracts before implementation;
  • modules driven by business capability;
  • security by default and least privilege;
  • observability from the first deployment;
  • automation that can be verified and reversed.

Core conventions

Area Standard
Backend ASP.NET Core .NET 10
Architecture Modular monolith by business capability
API REST /api/v1, OpenAPI, and Problem Details
Security JWT Bearer/OIDC, policies, and default deny
Database PostgreSQL, EF Core with Npgsql, and migrations
Frontend React and TypeScript, without Next.js
Observability Health checks, correlation ID, and structured logs
Quality Unit, integration, and architecture tests, plus critical journeys

Recommended structure

The detector looks for equivalent signals rather than for this exact tree, but this is the layout the rules were written against:

src/
  Api/
    Controllers/        or Endpoints/
  BuildingBlocks/
  Modules/
    <Module>/
      Domain/
      Application/
      Infrastructure/
        Migrations/
web/
  src/
    app/
    features/
    shared/
tests/
  UnitTests/
  IntegrationTests/
  ArchitectureTests/

Two details are load-bearing. Migrations/ is matched case-sensitively, and the three test directories are matched by name, so a repository that calls them something else fails those rules while being perfectly well tested. See the signal reference.

Policies

Six policy documents carry the reasoning. They are not evaluated by the tool, which is the point: a decision such as "start as a modular monolith" cannot be checked by grepping a repository, and pretending otherwise would produce confident nonsense.

architecture

Start as a modular monolith and extract services only when metrics justify it. Organize modules by business capability rather than by global technical type. Domain depends on nothing above it. Application depends on Domain and declares ports for external effects. Infrastructure implements those ports without leaking details back. Endpoints validate the protocol and delegate.

Explicitly forbidden: references from Domain to Infrastructure, business rules inside controllers or React components, and a database shared directly between modules without an application contract.

api

REST under /api/v1 for public commands and queries. OpenAPI published as a verifiable contract. Problem Details for errors. Pagination, filtering, and sorting with explicit limits. A correlation ID propagated across requests, logs, and integrations. SignalR only for real-time notifications, never as a replacement for the command API.

Response conventions: an explicit DTO with a semantic status on success, application/problem+json on error, Problem Details with per-field errors on validation, and idempotency required for external commands that can be retried.

security

Validate JWT Bearer tokens from a trusted OIDC provider. Express authorization through policies tied to business capabilities. Apply default deny and declare anonymous access explicitly. Keep secrets out of the repository and rotatable. Record security events without tokens, credentials, or sensitive data. Run dependency scanning and static analysis in the pipeline.

Four changes always require review: authentication or authorization, new public exposure, handling of personal data, and adoption of multi-tenancy or Row Level Security.

database

EF Core with Npgsql as the persistence standard. Versioned migrations run as a controlled deployment step. Every module owns its own tables. Short transactions with boundaries that match the use case. Indexes added from real queries and real metrics. PostGIS only for geospatial requirements. Row Level Security only after an explicit multi-tenancy decision.

Migration safety: destructive changes need expand-contract, a logical rollback must be documented before deployment, and backfills must be observable, restartable, and bounded.

frontend

React without Next.js. Code organized by feature with a shared design system. Generated or typed clients derived from OpenAPI. Server state, local state, and form state kept separate. Loading, empty, error, and success handled in every asynchronous journey. Accessibility and responsiveness starting from the base components.

Quality bar: strict TypeScript, lint and formatting in the pipeline, tests for critical components, and end-to-end tests for the main journeys.

testing

Four layers with distinct jobs. Unit tests cover Domain and Application, fast and deterministic. Integration tests cover HTTP, PostgreSQL, and adapters, which is where the real contracts live. Architecture tests cover dependencies between projects and namespaces, to prevent erosion. End-to-end tests cover the essential journeys on the deployed system.

The pipeline should carry a reproducible build, automated tests, OpenAPI validation, static and dependency analysis, and migration verification.

Recipes

Four ordered procedures, each with inputs, steps, the approvals a human owes, and the conditions that mean it is done. In 0.1 they are documentation. From 0.3 they become what templates are generated from.

create-system establishes the minimum structure without irreversible decisions. Its human approvals are module boundaries, the identity provider, multi-tenancy and Row Level Security, and the deployment strategy.

add-api-module walks a new business capability from boundary definition through Domain, Application, Infrastructure, endpoints, policies, tests, and telemetry.

add-react-feature walks a journey from accessibility criteria through the typed client, the four interface states, and the critical-journey test.

add-database-migration classifies a change as additive, transformative, or destructive, applies expand-contract where versions would be incompatible, and requires human approval for destructive operations, long-held locks, production backfills, and enabling Row Level Security.

Gates

One gate set, split by moment.

Pull request: formatting and lint, .NET and React build, unit tests, integration tests, architecture tests, OpenAPI contract validation, static and dependency analysis, migration validation.

Deployment: an immutable artifact identified by commit, configuration and secrets supplied externally, the migration run as a controlled step, readiness approved before traffic, telemetry and alerts active.

Release evidence: commit and version, test results, OpenAPI digest, migrations applied, required approvals, rollback plan.

Mestre Yoda does not run your pipeline. Gates describe what it should enforce.

Optional capabilities

Five things the profile deliberately does not require:

SignalR enters when something genuinely updates in real time, and never as a substitute for the command API.

PostGIS enters when the domain has geospatial queries.

Row Level Security enters only after somebody has decided on a tenant model and an operational strategy. Turning RLS on because it sounds safe is how teams end up with a policy layer nobody can reason about.

Flutter can be added as another client of the same OpenAPI contract.

OIDC provider adapters are configurable, not a Domain dependency.

Rules

All 21, with severity, signal, and what to do on failure, are in the rule reference.

Six blocking: stack.no-nestjs, stack.no-nextjs, architecture.modular-dotnet, api.version-v1, security.default-deny, frontend.react.

Fourteen required and one recommended, quality.architecture-tests, make up the rest.

When this profile is the wrong answer

An API-only service fails frontend.react, which is blocking, so it can never be compliant here. A service behind a gateway that terminates authentication elsewhere fails security.jwt. A team with a different test-directory convention loses three rules for a naming disagreement.

None of those are bugs in the repository being checked. They mean the profile does not describe that system, and the honest fix is a profile that does. See Authoring a profile.

Clone this wiki locally