Backend Architecture Core
Shared model for the backend-architecture cluster. The architecture, API, integration, and
deploy spokes all depend on these interlocking concepts — keep them consistent here so no spoke
contradicts another.
1. The decision this cluster turns on: dependencies point inward
Every spoke is an application of one rule — the domain depends on abstractions, never on
infrastructure. Business logic is pure; frameworks, drivers, and HTTP clients live at the edges
behind ports. This is the ports-and-adapters (hexagonal) boundary, and it is what makes a backend
testable, framework-swappable, and resistant to rot.
(driving / inbound) (driven / outbound)
HTTP · CLI · queue · cron ──> [Port] ──> Domain + Use cases ──> [Port] ──> DB · API · bus · cache
adapters (no framework imports) adapters
- Domain / use case — pure business rules and orchestration; imports nothing from the framework, ORM, or transport. →
hexagonal-architecture
- Port — an interface the core owns and depends on (e.g.
UserRepository, PaymentGateway).
- Adapter — a concrete implementation at the edge (Express handler, NestJS controller, Prisma repo, an outbound API connector). Adapters depend on the core; the core never depends on them.
Rule: if removing a library would force you to rewrite a use case, the dependency is pointing
the wrong way — put a port between them.
2. The layering contract
| Layer |
Owns |
Depends on |
Spoke |
| Transport |
HTTP/MCP/CLI shape, (de)serialization, status codes |
Application |
api-design, mcp-server-patterns, nestjs-patterns |
| Application |
use-case orchestration, transactions, validation |
Domain (via ports) |
hexagonal-architecture, backend-patterns |
| Domain |
entities, business invariants |
nothing external |
hexagonal-architecture |
| Adapter (driven) |
DB access, outbound calls, caching, jobs |
Domain ports |
backend-patterns, api-connector-builder |
Validate at the transport boundary; never trust an inbound request. Keep controllers thin —
they translate transport ⇄ use case, nothing more.
This cluster owns the app-layer view of data — the repository adapter, transactions via ports, the
API over it. A pure DB query, indexing, migration, or engine-tuning ask belongs to databases-data.
3. API & transport conventions
- REST: nouns + plurals for resources, correct status codes, cursor/offset pagination,
consistent error envelope, explicit versioning, rate limiting on public surfaces. →
api-design
- Outbound integrations: match the host repo's connector layout, config schema, auth model,
error handling, and registration wiring — one pattern, not two. →
api-connector-builder
- MCP: tools/resources/prompts with Zod-validated inputs; choose stdio vs Streamable HTTP by
deployment. →
mcp-server-patterns
- Treat a new public contract or persisted schema as a breaking-change candidate; record the call
with
architecture-decision-records.
4. Runtime / framework matrix
| Surface |
Default |
Spoke |
| Node service / API routes |
Node + TypeScript (Express / Next.js routes) |
backend-patterns |
| Structured TS backend |
NestJS (modules, providers, guards, interceptors) |
nestjs-patterns |
| Multi-language domain core |
TS / Java / Kotlin / Go behind ports |
hexagonal-architecture |
| AI tool server |
MCP TypeScript SDK |
mcp-server-patterns |
| Release |
Docker + CI/CD (blue-green / canary / rolling), health checks, rollback |
deployment-patterns |
SDK and framework APIs evolve — verify current method names against official docs/Context7 rather
than trusting memory.
5. Shared guardrails
- Dependencies point inward: domain imports no framework, driver, or HTTP client; edges go behind ports.
- Validate all inputs at the transport boundary; controllers stay thin.
- Match the existing repo pattern; don't introduce a second architecture for one more feature.
- State every contract change (public endpoint, persisted schema, outbound integration) explicitly.
- Capture non-obvious architectural trade-offs as ADRs so the "why" outlives the PR.
- Confirm health checks, rollback path, and env config before a production deploy.
1---2name: backend-architecture-core3description: Shared reference for the backend-architecture cluster: the dependency-inversion boundary (domain → ports → adapters), the layering contract, REST/transport conventions, and the runtime/framework matrix. USE WHEN drawing a module boundary, designing an API, wiring an integration, or planning a deploy — the interlocking rules every backend spoke shares.4---56# Backend Architecture Core78Shared model for the `backend-architecture` cluster. The architecture, API, integration, and9deploy spokes all depend on these interlocking concepts — keep them consistent here so no spoke10contradicts another.1112## 1. The decision this cluster turns on: dependencies point inward1314Every spoke is an application of one rule — **the domain depends on abstractions, never on15infrastructure**. Business logic is pure; frameworks, drivers, and HTTP clients live at the edges16behind ports. This is the ports-and-adapters (hexagonal) boundary, and it is what makes a backend17testable, framework-swappable, and resistant to rot.1819```20 (driving / inbound) (driven / outbound)21HTTP · CLI · queue · cron ──> [Port] ──> Domain + Use cases ──> [Port] ──> DB · API · bus · cache22 adapters (no framework imports) adapters23```2425- **Domain / use case** — pure business rules and orchestration; imports nothing from the framework, ORM, or transport. → `hexagonal-architecture`26- **Port** — an interface the core owns and depends on (e.g. `UserRepository`, `PaymentGateway`).27- **Adapter** — a concrete implementation at the edge (Express handler, NestJS controller, Prisma repo, an outbound API connector). Adapters depend on the core; the core never depends on them.2829**Rule:** if removing a library would force you to rewrite a use case, the dependency is pointing30the wrong way — put a port between them.3132## 2. The layering contract3334| Layer | Owns | Depends on | Spoke |35|---|---|---|---|36| Transport | HTTP/MCP/CLI shape, (de)serialization, status codes | Application | `api-design`, `mcp-server-patterns`, `nestjs-patterns` |37| Application | use-case orchestration, transactions, validation | Domain (via ports) | `hexagonal-architecture`, `backend-patterns` |38| Domain | entities, business invariants | nothing external | `hexagonal-architecture` |39| Adapter (driven) | DB access, outbound calls, caching, jobs | Domain ports | `backend-patterns`, `api-connector-builder` |4041Validate at the transport boundary; never trust an inbound request. Keep controllers thin —42they translate transport ⇄ use case, nothing more.4344This cluster owns the app-layer view of data — the repository adapter, transactions via ports, the45API over it. A pure DB query, indexing, migration, or engine-tuning ask belongs to `databases-data`.4647## 3. API & transport conventions4849- **REST**: nouns + plurals for resources, correct status codes, cursor/offset pagination,50 consistent error envelope, explicit versioning, rate limiting on public surfaces. → `api-design`51- **Outbound integrations**: match the host repo's connector layout, config schema, auth model,52 error handling, and registration wiring — one pattern, not two. → `api-connector-builder`53- **MCP**: tools/resources/prompts with Zod-validated inputs; choose stdio vs Streamable HTTP by54 deployment. → `mcp-server-patterns`55- Treat a new public contract or persisted schema as a breaking-change candidate; record the call56 with `architecture-decision-records`.5758## 4. Runtime / framework matrix5960| Surface | Default | Spoke |61|---|---|---|62| Node service / API routes | Node + TypeScript (Express / Next.js routes) | `backend-patterns` |63| Structured TS backend | NestJS (modules, providers, guards, interceptors) | `nestjs-patterns` |64| Multi-language domain core | TS / Java / Kotlin / Go behind ports | `hexagonal-architecture` |65| AI tool server | MCP TypeScript SDK | `mcp-server-patterns` |66| Release | Docker + CI/CD (blue-green / canary / rolling), health checks, rollback | `deployment-patterns` |6768SDK and framework APIs evolve — verify current method names against official docs/Context7 rather69than trusting memory.7071## 5. Shared guardrails7273- **Dependencies point inward**: domain imports no framework, driver, or HTTP client; edges go behind ports.74- Validate all inputs at the transport boundary; controllers stay thin.75- Match the existing repo pattern; don't introduce a second architecture for one more feature.76- State every contract change (public endpoint, persisted schema, outbound integration) explicitly.77- Capture non-obvious architectural trade-offs as ADRs so the "why" outlives the PR.78- Confirm health checks, rollback path, and env config **before** a production deploy.