This directory contains the engineering rules that apply across the LearnStack codebase. Architecture docs (docs/architecture/) explain what we are building; standards explain how we build it.
- Author-side: before opening a PR, skim the standards that touch your change.
- Reviewer-side: reference standards in review comments rather than re-litigating preferences.
- Newcomer-side: read 00-principles.md first; the rest is reference material.
- Disagreement: propose a change via PR against the standard itself. Standards are versioned documents, not folklore.
| # | Document | Scope |
|---|---|---|
| 00 | Principles | The handful of beliefs every other standard descends from. |
| 01 | Architecture Standards | Module boundaries, dependency direction, ports & adapters, aggregate ownership. |
| 02 | Backend Coding Standards | C# / .NET style, async, nullability, records, MediatR, EF Core. |
| 03 | Frontend Coding Standards | TypeScript / React / Next.js style, components, hooks, data fetching. |
| 04 | API Design Standards | REST, Problem Details, pagination, idempotency, versioning. |
| 05 | Database Standards | Schema conventions, migrations, indexing, tenant-aware patterns. |
| 06 | Testing Standards | Unit / integration / architecture / E2E / contract tests; pyramid; coverage targets. |
| 07 | Frontend Architecture Standards | App Router layout, server vs client components, tenant context, SDK shape. |
| 08 | Localization Standards | i18n rules for strings, content, URLs, SEO, formatting. |
| 09 | Error Handling Standards | Exception hierarchy, Problem Details, frontend error boundaries, user-facing copy. |
| 10 | Observability Standards | Logging, tracing, metrics, correlation, redaction. |
| 11 | Security Standards | Auth, tenant isolation enforcement, OWASP, secrets, file uploads, headers. |
| 12 | Infrastructure Standards | Docker, CI/CD, environments, configuration, deployment. |
| 13 | Documentation Standards | ADRs, code comments, diagrams, doc style. |
| 14 | Git Workflow Standards | Branching, commits, PRs, reviews. |
| 15 | Performance Standards | Budgets, caching, query shape, frontend perf. |
| 16 | Accessibility Standards | WCAG targets, semantic HTML, keyboard, screen readers. |
| 17 | Code Review Standards | What to look for, what not to block on, etiquette. Zero-tolerance blockers and author self-review gate. |
| 18 | Audit Coverage Standards | Which operations must be audited; payload contract; retention; per-module classification matrix. |
| 19 | Permissions Standards | {module}.{resource}.{action} naming, closed action set, registry pattern, matrix template, built-in roles. |
| 20 | Infrastructure Stack Standards | Demand-gated building blocks, the foundation ports (IEventBus, ICacheService, ISecretProvider), APISIX gateway, Hub contract surface + its two invariants, entitlement projection, outbox/inbox usage. |
| 21 | Architecture Tests + Analyzers Catalogue | Single source of truth for the identifier, assertion, status, and source ADR / standard of every non-skippable architecture test or Roslyn analyzer. Cross-link target so renames touch one place. |
Standards have one of three states:
- Active. Currently enforced; PRs must comply. There is code, tooling, or a live process that the standard governs today.
- Adopted. Agreed and binding on the code that will implement it — but that code does not exist yet, so nothing enforces it beyond review.
- Draft. Proposed; open for discussion.
A standard with no implementing code is
Adopted, notActive.
Each document declares its state at the top, and until 2026-08-08 all twenty-two
declared Active — including standards governing endpoints, migrations, permissions
and audit rows that do not exist. A three-state model whose every member sits in one
state is decorative: it tells a reader nothing, and it quietly overstates how much of the
corpus is load-bearing.
"Adopted" is not a weaker commitment. It is the honest one. It says: this is the rule the
implementing PR must satisfy, and there is nothing standing between a violation and
main except a reviewer who remembers. That is exactly the situation in which a reviewer
most needs to know.
Promotion Adopted → Active happens in the PR that lands the enforcement — the
migration, the endpoint, the analyzer, the architecture test — not in a separate
bookkeeping pass.
The table below is the current, accurate state as of 2026-08-28, at HEAD with Phase 02a Packets 0–3, 3b, 4, 5 and 6 shipped.
The individual documents still declare Active in their own headers. Reconciling the
twenty-two status lines with this table is a
Phase 02a Packet 10 deliverable, landed
together with the architecture-test reconciliation so the two views of "what is actually
enforced" change in one commit. Until that lands, this table wins.
| # | Standard | Status | What does or does not enforce it today |
|---|---|---|---|
| 00 | Principles | Active | Governs every PR and every ADR; principles 1, 16 and 17 are already deciding live scope questions. |
| 01 | Architecture Standards | Active | Module layout shipped; ModuleDomain_DoesNotDependOn_* and the planted-violation meta-test are green. |
| 02 | Backend Coding | Active | MediatR pipeline, Result<T>, IClock, the LS0001 analyzer and the pipeline-order test all ship. Packet 6 brought the first DbContext, the first aggregates and the ambient unit of work, so its EF Core and domain-modelling clauses are live too — for one module. |
| 03 | Frontend Coding | Adopted | ESLint and TypeScript strict mode are configured, and Packet 3b stood up the Vitest harness (jsdom + Testing Library) with one render test — so the required frontend check now asserts something. apps/web is otherwise still a scaffold with no components. First real code: Phase 02d. |
| 04 | API Design | Active | Packet 4 shipped the versioned route convention and its startup guards, one Problem Details shape on every error including the framework-minted ones, cursor pagination, the sort grammar, idempotency keys, ETag concurrency, correlation ids, the request-body limit and the tenancy edge — each with tests in the required backend check. No business endpoint exists yet; the conventions they will land into do. |
| 05 | Database | Active | Packet 6 applied it: two migration chains, ten tables, the four-role model, and the canonical RLS template this document owns — ENABLE and FORCE, one AND-ed policy per table, an explicit WITH CHECK — asserted against a real PostgreSQL as learnstack_app. Its § Concurrency, § Table classes, § Indexes and § GRANT matrix each have a test that fails without them. Partitioning and the retention job are still ahead. |
| 06 | Testing | Active | Unit, architecture, contract and integration suites all run in the required backend job — Packet 4 removed the filter that used to exclude the integration assembly, which by then held the only tests that could catch an unversioned route. The Docker-bound backend-integration job activated in Packet 6 with the four-role provisioning suite; the split is by [Trait("Requires","Docker")] and the two jobs' filters are exact complements. |
| 07 | Frontend Architecture | Adopted | Route groups exist as empty layouts; server/client split, tenant context and SDK shape are exercised first in Phase 02d. |
| 08 | Localization | Adopted | Packet 6 shipped tenant_locales and the slug schema; the i18n runtime lands in Phase 04. Nothing enforces "exactly one default locale per tenant" yet — recorded as an open question in the Tenancy module spec, Packet 7's call. |
| 09 | Error Handling | Active | L1 IExceptionHandler, the exception hierarchy, ProblemDetailsFactory and HttpStatusMap shipped in Packet 3. |
| 10 | Observability | Active | Serilog → OTLP, OpenTelemetry SDK, TenantContextSpanProcessor and the redaction enrichers shipped in Packet 3. |
| 11 | Security | Adopted | No auth yet; RLS is live. Packet 6 shipped the policies, the four roles and the isolation suite that runs as learnstack_app, and Packet 4 shipped the header-facing half — the tenancy edge, the trusted-hop predicate, host normalization and the anonymous rate limiter. Tenant isolation lands in Packet 7, authentication in Phase 02b. Its § Tenant Context is nonetheless the binding authority the implementing PR must follow. |
| 12 | Infrastructure | Active | Compose stack, Makefile, CI workflow, pre-commit hooks and secret scanning all live since Phase 01. |
| 13 | Documentation | Active | Governs this corpus; the CI link audit walks changed Markdown. |
| 14 | Git Workflow | Active | Conventional Commits, hooks and required checks are live. Two branch-protection settings — Require approvals and Do not allow bypassing — are deferred by maintainer decision (2026-08-10) while the repository has one active contributor; the trigger and what activating them involves are recorded in CONTRIBUTING § Branch protection. Everything else in Standards 14 is enforced today. |
| 15 | Performance | Adopted | No budget is measured and no load test exists. Enforcement lands in Phase 11. |
| 16 | Accessibility | Adopted | No user interface to audit. First surfaces render in Phase 02d; automated axe checks in Phase 06. |
| 17 | Code Review | Active | Applied to every pull request merged so far; the zero-tolerance blocker list is in live use. |
| 18 | Audit Coverage | Adopted | AuditLogBehavior is a shell and audit_log does not exist. Lands in Packet 9 under ADR-0033. |
| 19 | Permissions | Adopted | No permission key, policy or role exists. Lands in Phase 03. |
| 20 | Infrastructure Stack | Adopted | ISecretProvider shipped in Packet 3 and DeploymentMode branching is real, but the ports land in Packet 5 and the Dapr / Kafka / APISIX / Vault adapters are demand-gated to Phase 11 per ADR-0035. |
| 21 | Architecture Tests Catalogue | Active | Twenty-nine test methods run in the architecture assembly and seven further implemented rules run beside it, three of them against an applied schema; the catalogue's own per-row status column distinguishes those from the registered-but-unimplemented majority. |
Thirteen Active, nine Adopted. That split is the honest picture of a platform whose
foundation is real and whose domain has not been written yet — and it is far more useful
to a reviewer than twenty-two identical labels.
| Document type | Purpose |
|---|---|
ADR (docs/decisions/) |
A one-time decision with status, context, decision, consequences. Immutable history, corrected only by the two bounded mechanisms in 13-documentation.md § Correcting and Amending ADRs. |
Standard (docs/standards/) |
An ongoing rule that the team applies day to day. Editable as the team learns. |
When a standard is established, an ADR records the moment of adoption. The ADR then points at the standard for the living detail.
Where a standard can be enforced by automation, it must be:
- Roslyn analyzers /
.editorconfigfor backend. - ESLint / TypeScript strict mode for frontend.
- Custom architecture tests (NetArchTest / ArchUnitNET) for module-boundary rules.
- Test conventions enforced by CI.
- Commit / PR rules enforced by GitHub Actions and CODEOWNERS.
Manual-only rules are flagged in each document.