Skip to main content
Archived design reference — not the current architecture

These docs describe a proposed Simplified Hexagonal Architecture from an internal design exploration that was not adopted. The design principles (entity invariants, contracts, dependency inversion, load → authorize → validate → execute, in-memory-fake testing) remain useful, but the specifics below do not exist in this codebase: the package paths packages/core / packages/infra / packages/shared, the @packages/* import aliases, the main.ts wiring entry point, and the EnableArchitectureTransition feature flag. Do not follow the paths, aliases, or imports here as-is.

Application Architecture

A pragmatic, simplified approach to application architecture that keeps business logic isolated from external systems.


AI Agent Quick Start

What Are You Trying to Do?

TaskStart HereThen Read
Implement a new feature18-tutorial-building-products.md00-quick-reference.md
Add a new action to existing feature05-actions.md00-quick-reference.md
Add a new entity03-domain-objects.md04-contracts.md
Add an API endpoint06-entry-points.md10-validation.md
Wire dependencies in main.ts06-entry-points.md13-cross-feature-communication.md
Fix a bug03-domain-objects.md10-validation.md
Understand the architecture01-core-concepts.md08-rules-and-guidelines.md
Review code for violations08-rules-and-guidelines.mdAnti-Pattern Detection section
Write tests15-testing.md-
Add cross-feature logic13-cross-feature-communication.md02-feature-design.md

Quick Reference

For immediate access to file paths, import rules, signatures, and templates: 00-quick-reference.md - Read this first for any implementation task.

Key Rules (Memorize These)

1. Core knows nothing about infra or HTTP
2. Dependencies are interfaces (contracts)
3. Wire implementations at startup in main.ts
4. User actions: (deps, ctx, input) → Promise<Result>
5. System actions: (deps, input) → Promise<Result>
6. Entities throw InvariantError, Actions throw NotFoundError/BusinessError

The Essence

Your business logic shouldn't know about databases, HTTP, or any external system.

Everything else is ceremony.


Documentation Sections

Essential (Start Here)

The core concepts every developer needs to understand:

SectionDescription
Quick ReferenceFile paths, import rules, signatures, templates - all in one place
Core ConceptsThe simplified model and monorepo structure
Feature DesignDeciding what type of feature to build (resource, orchestration, computation)
Domain ObjectsEntities with business rules and invariants
ContractsInterfaces that define external dependencies
ActionsBusiness operations that orchestrate the domain
Entry PointsHTTP API, CLI, and Workers - how the outside world calls your app
InfrastructureImplementations of contracts (DB, Email, etc.)
Rules & GuidelinesImport rules, naming conventions, anti-patterns, and common mistakes

Decision Guides

References for common architectural decisions:

SectionDescription
Where to Put LogicEntity vs Action - the most common question
AuthorizationPolicies, permissions, and AuthContext
ValidationInput, business, and invariant validation layers

Advanced Patterns

Use when your application needs them:

SectionDescription
CQRS and Read ModelsSeparate read/write models for complex query needs
TransactionsDatabase transactions and atomicity
Shared ContractsSharing contracts across features
Cross-Feature CommunicationAction-based dependencies between features
The Shared PackageSharing types with frontend apps
Dependency ManagementOrganizing dependencies as your app grows

Reliability

Patterns for robust, observable systems:

SectionDescription
Error HandlingError types, Result pattern, partial failures
LoggingStructured logging, boundaries, and observability

Quality

SectionDescription
TestingTesting strategies with fakes

Tutorials

SectionDescription
Building a Products FeatureComplete end-to-end walkthrough building a feature from scratch

Quick Start

The Simplified Model

┌─────────────────────────────────────┐
│ OUTSIDE │
│ (HTTP, DB, Files, APIs, etc.) │
│ │
│ ┌───────────────┐ │
│ │ CONTRACTS │ │
│ │ (Interfaces) │ │
│ └───────┬───────┘ │
│ │ │
│ ┌───────▼───────┐ │
│ │ CORE │ │
│ │ (Your App) │ │
│ └───────────────┘ │
└─────────────────────────────────────┘

Just 3 concepts:

ConceptDescription
CoreYour business logic (domain objects, actions, contracts)
ContractsInterfaces that define what external things you need
OutsideImplementations of contracts + entry points (API, CLI)

Folder Structure

├── apps/
│ ├── client/ # Next.js App (Frontend + API)
│ │ ├── pages/
│ │ │ └── api/ # Entry points (Next.js API Routes)
│ │ │ ├── validators/ # Input validation schemas
│ │ │ └── handlers/ # Request handlers
│ │ └── server/ # Server-side code
│ │ └── middlewares/
│ │ └── baseApi.ts # Base API middleware factory
│ │
│ └── worker/ # Background workers (optional)
│ └── src/
│ └── ...

└── packages/
├── core/ # Business logic (backend only)
│ └── src/
│ ├── shared/ # Shared contracts across features
│ │ ├── authorization/
│ │ │ └── AuthContext.ts
│ │ ├── Mailer.ts
│ │ ├── Logger.ts
│ │ ├── TransactionManager.ts
│ │ ├── Result.ts
│ │ └── errors.ts
│ │
│ └── orders/ # Feature: Orders
│ ├── Order.ts # Entity (write model)
│ ├── OrderRepository.ts # Combined read/write contract
│ ├── OrderReadModels.ts # DTOs for queries
│ ├── OrderPolicies.ts
│ ├── actions/ # Commands (writes)
│ │ ├── createOrder.ts
│ │ └── cancelOrder.ts
│ ├── queries/ # Queries (reads)
│ │ ├── getOrderDetails.ts
│ │ └── listCustomerOrders.ts
│ └── index.ts

├── infra/ # Infrastructure implementations
│ └── src/
│ ├── shared/ # Shared infra (core/shared contracts)
│ │ ├── mongodb/
│ │ │ ├── connection.ts
│ │ │ ├── BaseMongoRepository.ts
│ │ │ └── MongoTransactionManager.ts
│ │ ├── email/
│ │ │ └── SendGridMailer.ts
│ │ └── logging/
│ │ └── PinoLogger.ts
│ │
│ └── orders/ # Feature infra (core/orders contracts)
│ ├── OrderRepositoryMongo.ts
│ └── memory/
│ └── InMemoryOrderRepository.ts

└── shared/ # Shared with frontend
└── src/
├── api-types/ # Request/Response DTOs
│ ├── orders.ts
│ └── users.ts
├── validation/ # Zod schemas
│ └── orders.ts
└── constants/
└── orderStatuses.ts

For import rules and guidelines, see Rules & Guidelines.


The Mental Model

"My business logic is in core/.
It talks to the outside world through interfaces.
I plug in real implementations at startup."

That's the whole pattern.