Leadline Architecture Design

Principles

Cross-cutting principles we apply when designing and implementing backend services.

These principles summarize how we structure services, choose boundaries, and keep systems evolvable. They align with NestJS conventions where practical, and with explicit architectural discipline where complexity demands it.

Separation of concerns

HTTP adapters map requests and responses; application code orchestrates use cases; domain types express business rules; infrastructure implements technical details (databases, brokers, third-party APIs). Thin controllers and explicit persistence boundaries reduce accidental coupling between transport and storage.

Dependency direction

Core logic should not depend on frameworks or vendors at compile time more than necessary. Prefer ports (interfaces or abstract contracts owned by the application or domain) and adapters (Nest providers that implement those contracts) so tests and refactors can swap implementations without rewriting business rules.

Scope and lifetime clarity

Understand provider scope (DEFAULT, REQUEST, TRANSIENT) and how it propagates up the injection graph. Use request-scoped providers only when request identity or isolation truly requires it; pair with durable context strategies when load and reuse matter (see Dependency injection).

Consistency and failure modes

When reads and writes follow different paths (CQRS, projections, sagas), treat the read side as eventually consistent by default. Design APIs, UX, and monitoring for lag, retries, and duplicate delivery instead of assuming instantaneous mirror state.

Multi-tenant safety

If tenants share storage, enforce tenant discrimination consistently—in middleware, repositories, or database policies—and carry tenant identifiers through logs, metrics, and traces. Prefer centralized tenant resolution over ad hoc header parsing scattered across handlers.

Operational honesty

Instrument cross-boundary calls (timeouts, retries, circuit breaking) and prefer fail-fast behavior when downstream systems are unhealthy. CPU-heavy work should not block the Node.js event loop; offload or pool when appropriate (see Reliability and concurrency).

Learn more

This page and links

Loading map…

On this page