.NET 9 Clean Architecture solution for the LexFlow Enterprise Lawyer CRM API.
Companion to lexflow-database (schema owner) and lexflow-web (Angular clients).
See LexFlow_PRD.md and LexFlow_Build_Playbook.md (§1.2) for the full spec.
lexflow-api/
├── src/
│ ├── LexFlow.Domain/ entities, value objects, domain events, enums — no external dependencies
│ ├── LexFlow.Application/ MediatR CQRS, FluentValidation, Mapster, repository/service interfaces
│ ├── LexFlow.Infrastructure/ EF Core (Database-First) + Npgsql, Redis, Elasticsearch, Blob, Key Vault
│ ├── LexFlow.Api/ ASP.NET Core Web API: controllers, middleware, SignalR hubs, Program.cs
│ └── LexFlow.Workers/ Hangfire background job host (own Dockerfile)
├── tests/
│ ├── LexFlow.UnitTests/ xUnit + FluentAssertions
│ ├── LexFlow.IntegrationTests/ xUnit + FluentAssertions + Testcontainers.PostgreSql
│ └── LexFlow.E2ETests/ xUnit + FluentAssertions + WebApplicationFactory<Program>
├── client/ TypeScript client generation for lexflow-web (see client/README.md)
├── deploy/helm/lexflow-api/ Helm chart for AKS blue-green deploys (§38)
├── docs/local-dev.md full three-repo local bring-up (see below)
├── docs/staging-release.md staging deploy + D-18/C-15 release gate (§38, see below)
├── Dockerfile LexFlow.Api image
├── docker-compose.yml api + workers + postgres + redis + elasticsearch + azurite (local dev)
├── docker-compose.full.yml + lexflow-database's DB Runner + lexflow-web's dev servers
├── COMPATIBILITY.md cross-repo version pairing rules
└── LexFlow.sln
Important: schema is owned exclusively by lexflow-database (raw SQL, applied via
its DbUp runner). LexFlow.Infrastructure's LexFlowDbContext is Database-First —
Fluent API entity configurations only. Never run dotnet ef migrations add against
this solution.
docker compose up -d postgres redis elasticsearch azurite
dotnet build LexFlow.sln
dotnet run --project src/LexFlow.ApiOr run the full stack (api + workers + every backing service) in containers:
docker compose up -d --builddocker compose -f docker-compose.full.yml up --buildRequires lexflow-database and lexflow-web checked out as siblings of this
repo. See docs/local-dev.md for the health-check-gated bring-up order and
COMPATIBILITY.md for which versions of the three repos are meant to run
together.
Swagger UI: http://localhost:5000/swagger (or :8080 under docker compose) — every
environment except Production; the raw /swagger/v1/swagger.json OpenAPI 3.1 document
is always served, Production included (see client/README.md for why).
Health check: http://localhost:5000/health.
Connection strings and other local secrets go in each project's
appsettings.Development.json (gitignored) — see the checked-in
appsettings.Development.json.example in src/LexFlow.Api/ for the shape.
Blob storage runs against Azurite locally (BlobStorage:ConnectionString defaults to
UseDevelopmentStorage=true, matching Azure Storage SDK's built-in Azurite shorthand);
docker-compose's azurite service uses the well-known public Azurite dev account key
instead (there's no real credential to leak — that key is Microsoft's own documented
default for the emulator).
client/ generates a typed Angular TypeScript client from the API's own OpenAPI
document — see client/README.md for the full workflow and the "why a copied file, not
a published npm package" decision.
SignalR hub stubs are mapped and ready for module wiring:
/hubs/notifications, /hubs/chat, /hubs/presence, /hubs/jobs.
.github/workflows/api-ci.yml implements §37's full gate sequence:
- build → unit → integration (
build-test, Postgres + Redis service containers) - SonarQube quality gate (
sonarqube) — self-activates onceSONAR_TOKEN/SONAR_HOST_URLrepo secrets exist; a no-op until then (no workflow edit needed) - contract (
contract) — OpenAPI 3.1 schema validation via Redocly lint against a live instance. Pact (portal/mobile) isn't wired up — no Pact Broker provisioned yet. - security —
gitleaks(secrets scan),zap-baseline(OWASP ZAP baseline against the full docker-compose stack),trivy(container CVE scan). G-AC3's cross-tenant fuzz suite and G-AC4's permission-matrix generator run as ordinaryLexFlow.IntegrationTests/LexFlow.UnitTestsinsidebuild-test, not as separate jobs. generate-ts-client— builds the TypeScript client (see above) and uploads it as a workflow artifact.build-push-images— on push tomainonly, once every gate above passes: builds + pusheslexflow-api/lexflow-workersimages to GHCR, tagged by short SHA.
That's where api-ci.yml ends. .github/workflows/release.yml picks up from there
(triggered once api-ci.yml finishes on main) and owns the rest of §38 — see
docs/staging-release.md for the full chain, but in short:
- Staging: DB Runner (pre-deploy job, per §38) +
tools/E2eSeedagainst the managed Postgres Flexible Server → Helm-deploy API+Workers to an AKS staging namespace → deploy both Angular apps to Azure Static Web Apps' staging environment. - Release gate: the D-18 Playwright critical-journey suite and C-15's staging smoke tests (auth reachability + a real G-AC1/G-AC2/AC-CC3 check) both run against that staging deployment — promotion to production does not proceed unless both pass.
promote-production— §38 blue-green on AKS behind Azure Front Door, gated by theproductionGitHub Environment's required-reviewers rule (manual approval). Pre-deploy DB migrations (expand-contract, backward-compatible with the still-live "blue" stack) → Helm-upgrade the idle slot (deploy/helm/lexflow-api) → in-cluster smoke test → flip the live Service's selector to cut traffic over → 30-minute canary watch (health-check based; a real Application-Insights error-rate/P95 query is a documented follow-up, not wired up here) with auto-rollback on failure. The old "blue" slot is deliberately left running rather than torn down —.github/workflows/rollback.yml(manual, instant) and.github/workflows/cleanup-blue.yml(scheduled daily, only scales down a slot once it's been idle >24h) are the two companion workflows that act on that window.
None of AZURE_CREDENTIALS, AKS_RESOURCE_GROUP, AKS_CLUSTER_NAME, AKS_NAMESPACE,
LEXFLOW_DATABASE_CONNECTION_STRING, or the production Environment itself exist yet
in repo settings — deploy/rollback/cleanup-blue are real, runnable pipelines the
moment that infrastructure is provisioned and those secrets are added, not aspirational
placeholders requiring further workflow-file changes. Same for release.yml's own
staging-specific secrets — see docs/staging-release.md for the full list.