Overview
A 16-chapter engineering guide paired with a complete full-stack application. The project teaches production-grade Clean Architecture, TypeScript microservices, Next.js BFF pattern, and Kubernetes deployment by building a Neighborhood Grocery List from an empty directory.
Every pattern in this guide comes from a real system. I engineer a financial blockchain protocol where a single bug in a transfer function means real money disappearing. The discipline, the layering, the error handling... it all carries. I wrote it down so someone else doesn't have to learn it at 2 AM.
Objectives
The Application
The Neighborhood Grocery List is deliberately simple. Families add items they need. A household manager approves or rejects them. When someone buys an approved item, the cost is deducted from a monthly budget. Everyone sees what's been spent and what's remaining.
Underneath that surface:
$3.50 is stored as 350. All arithmetic stays in integers. A Money value object makes the wrong thing impossible.Solution Architecture
The backend follows Clean Architecture with four concentric layers. Dependencies always point inward. The domain knows nothing about Express, Prisma, or HTTP.
| Layer | Responsibility | Example |
|---|---|---|
| Domain | Business rules, value objects, errors | Money type, state machine, DomainError hierarchy |
| Application | Use cases, DTOs, port interfaces | CreateItem, ApproveItem, MarkBought |
| Infrastructure | Database implementations | Prisma repositories, read models |
| Interface | HTTP layer, middleware, controllers | Express routes, Zod validation, JWT auth |
The frontend uses a Backend-for-Frontend (BFF) pattern. Next.js API routes sit between the React client and the Express microservice, handling session management, JWT forwarding, and topology hiding.
Manual dependency injection wires everything together. One TypeScript file. No framework magic. Read it and you understand the entire application's wiring.
Tech Stack
| Layer | Tools |
|---|---|
| Frontend | Next.js (App Router), React, TypeScript, TanStack Query, React Hook Form, Tailwind CSS |
| Backend | Express.js, TypeScript, Zod, Prisma ORM, pino |
| Database | PostgreSQL (multi-file Prisma schema) |
| Auth | JWT, bcryptjs, HTTP-only cookies, role middleware |
| DevOps | Docker (multi-stage builds), Kubernetes, npm workspaces monorepo |
Key Features
Challenges & Learnings
1. Floating-Point Money
Challenge: JavaScript 0.1 + 0.2 equals 0.30000000000000004. In a budget tracker, rounding errors compound silently. Solution: Store all money as integers (cents). A Money value object handles arithmetic, formatting, and comparison. The type system prevents mixing cents and dollars.
2. Connection Pool Exhaustion
Challenge: Prisma creates a connection pool per client instance. Hot-reload in development creates new instances on every file save, exhausting PostgreSQL connections. Solution: Singleton pattern storing the Prisma client on globalThis in development. One client, one pool, regardless of reloads.
3. Generic Error Messages
Challenge: 500 Internal Server Error tells the frontend nothing. No error code, no context, no path to resolution. Solution: A DomainError base class carrying code, message, HTTP status, and structured details. ItemNotFoundError maps to 404. InvalidItemStateError maps to 400 with current/target state in the details payload.
4. Tight Frontend-Backend Coupling
Challenge: If the React frontend knows the backend's port and address, any topology change breaks the client. Solution: BFF pattern with Next.js API routes. The frontend talks to itself. The BFF forwards to the microservice with authentication headers. The visitor never needs to know which department to call.
Outcome
Read the Guide
The full 16-chapter guide is available as a PDF. Download it, open your terminal, and build alongside it.
Role & Responsibilities
---
I didn't want to write a textbook. I wanted to sit next to someone, open a terminal, and build something together. This is as close as text gets.
