Sample: Codebase Onboarding Document

Generated by scan_project in 4 minutes 32 seconds

Project: e-commerce-platform TypeScript 847 files 23 modules
CORTEX OUTPUT Analysis complete. Graph built, hub files ranked, AI narrative generated. 4m 32s 2026-02-28T09:14:07Z
01

Project Overview

ShopFlow is a full-stack e-commerce platform built with TypeScript, using Next.js 14 (App Router) for the frontend and Express.js for the API gateway. It follows a modular monolith architecture with clear domain boundaries — each bounded context owns its schema and exposes a typed public surface.

The codebase spans 847 files across 23 modules, with the six core domain modules (catalog, cart, checkout, users, orders, payments) handling all business logic. Shared infrastructure lives in src/shared/.

Frontend
Next.js 14 · React 18 · TailwindCSS · Zustand
Backend
Express.js · Prisma ORM · PostgreSQL
Infrastructure
Docker · Redis (caching) · BullMQ (job queues)
Testing
Vitest · Playwright · MSW
02

Architecture Overview

The system follows a modular monolith pattern with 6 bounded contexts communicating through an internal typed event bus. Each module owns its database schema (via Prisma) and exposes a public API through barrel exports — no module imports another module's internals directly.

Pattern: Each module follows the same internal structure — routes/, services/, repositories/, events/, and types/. This predictability means once you understand one module, you understand all of them.

03

Repository Structure

Top-level structure with file counts and responsibilities as scanned:

04

Module / Component Map

Hub files are ranked by dependent count. Higher dependents = higher blast radius if you break it.

Module Responsibility Key Hub File Dependents Risk
users Auth (JWT + OAuth), profile management users/services/auth-service.ts 41 CRITICAL
catalog Product CRUD, search indexing, category tree catalog/services/product-service.ts 34 HIGH
cart Cart state, promo engine, price calculation cart/services/price-calculator.ts 28 HIGH
checkout Multi-step checkout, address validation checkout/services/checkout-orchestrator.ts 22 HIGH
orders Order state machine, fulfillment webhooks orders/services/order-state-machine.ts 19 MEDIUM
payments Stripe API, refund logic, invoice generation payments/services/stripe-adapter.ts 15 MEDIUM
05

Key Concepts & Domain Model

These are the non-obvious concepts that a new developer must internalize before making changes:

  • Product Variant: Products have variants (size, color). The full type hierarchy is defined in catalog/types/variant.ts. A ProductVariant is always linked to a Product — never exists standalone.
  • Cart Rules Engine: Promotions are applied via a rules engine in cart/services/promo-engine.ts. Adding a new promo type means implementing the PromoRule interface, then registering it in the engine. Do not mutate cart state directly.
  • Order State Machine: Orders follow a strict lifecycle — createdpaidprocessingshippeddelivered, with cancelled and refunded as terminal branches. All transitions are in orders/services/order-state-machine.ts. Never set order status directly on the repository — always go through the state machine.
  • Internal Event Bus: Modules communicate via typed events, never via direct imports. shared/events/event-bus.ts is the hub. Events are defined per-module in events/types.ts and consumed in events/handlers.ts.
  • Barrel Exports: Each module exposes only what it intends to be public through its index.ts barrel. Importing from a module's internal subfolder directly is a convention violation.
06

Development Workflow

All commands use pnpm. Node 20+ required. Docker needed for full-stack local dev.

bash
# Initial setup
pnpm install

# Start development servers
pnpm dev            # Next.js frontend (port 3000)
pnpm dev:api         # Express API gateway (port 4000)
pnpm db:migrate      # Run pending Prisma migrations
pnpm db:seed         # Seed test data (dev only)

# Testing
pnpm test            # Vitest unit tests (watch mode)
pnpm test:e2e        # Playwright end-to-end suite
pnpm test:integration # API integration tests (requires running API)

# Production
pnpm build           # Full production build
pnpm docker:up       # Full stack via Docker Compose
07

Architectural Decisions

These decisions were surfaced from commit history, ADR files, and code structure analysis:

  • Modular monolith over microservices: Chosen for team size (8 developers). The module boundaries are clean enough that each module can be extracted to an independent service later without major surgery.
  • Prisma over raw SQL: Type-safe queries and auto-generated client reduce runtime type errors. Migration files live in shared/database/migrations/ — always review generated SQL before applying to production.
  • Zustand over Redux: Simpler API, smaller bundle. Each page has its own store slice under stores/. Do not use a single global store — colocate state with the feature that owns it.
  • BullMQ for async jobs: Email sending, inventory sync, and webhook retries run as background jobs. Queue definitions live in shared/jobs/. Redis must be running for any job-dependent feature to work locally.
08

Cross-Cutting Concerns

  • Authentication: JWT tokens with refresh rotation. Middleware at shared/middleware/auth.ts. Every API route except /auth/* requires a valid Authorization: Bearer token. The middleware attaches req.user for downstream use.
  • Error Handling: Centralized handler in shared/middleware/error-handler.ts. All domain errors must extend AppError. Never throw raw Error objects from service layer — use the typed subclasses (NotFoundError, ValidationError, etc.).
  • Logging: Structured JSON via Pino. Request IDs propagated through the x-request-id header. Always include requestId in log context for traceability.
  • Caching: Redis cache with per-module namespacing (catalog:, cart:, etc.). Cache invalidation events flow through the event bus — do not call redis.del() directly from business logic.
09

Danger Zones & Common Tasks

High-Risk Files — Modify With Extreme Caution

File Dependents Why It's Dangerous
users/services/auth-service.ts 41 Auth logic — breaking this locks out every user in production
shared/events/event-bus.ts 38 Inter-module communication hub — type changes cascade everywhere
catalog/services/product-service.ts 34 Product data — affects search, cart, checkout, and orders simultaneously
shared/database/prisma-client.ts 31 Database access singleton — every module depends on this
cart/services/price-calculator.ts 28 Price logic — a silent calculation bug means revenue loss at scale

Circular Dependencies — 2 Clusters Detected

Cluster 1: checkout ↔ payments

checkout calls payments to initiate a charge; payments emits a payment.confirmed event that checkout listens to for order completion. This creates a logical cycle. Status: Acceptable — event-based decoupling already planned for Q3. Do not resolve by adding a direct import.

Cluster 2: catalog ↔ cart

cart reads catalog prices for calculation; catalog reads cart state for "in-cart" badge display. Status: Action needed. Extract shared price types to shared/types/pricing.ts to break this cycle before adding new cross-module features.

Common Tasks — Step-by-Step

Add a new API endpoint: Create a route handler in modules/[name]/routes/, apply the auth middleware, then register the router in api/router.ts. Follow the existing pattern in any other module's routes folder.
Add a new domain event: Define the type in modules/[name]/events/types.ts, emit it via eventBus.emit() in the service layer, and subscribe in the consumer module's events/handlers.ts. Never use setTimeout as a substitute for async event handling.
Add a new promotion type: Implement the PromoRule interface in a new file under cart/services/rules/, write unit tests for edge cases, then register the rule in cart/services/promo-engine.ts. Rule order matters — check existing ordering comments.
10

Quick Reference

Entry Points

API Server
src/api/gateway.ts
Express app instantiation, global middleware
Frontend Root
src/app/layout.tsx
Next.js root layout, global providers
Database
src/shared/database/prisma-client.ts
Singleton Prisma client, connection config
Module Wiring
src/api/router.ts
Start here to see how modules are registered

Recommended Reading Order (for new engineers)

src/api/router.ts — See how all modules are wired together at the route level
src/shared/events/event-bus.ts — Understand inter-module communication before modifying any service
src/modules/catalog/services/product-service.ts — Canonical example of the service layer pattern used across all modules
src/shared/middleware/auth.ts — Understand the auth flow before touching any protected route

Critical Environment Variables

Full list in .env.example. These must be set before the application starts:

DATABASE_URL = PostgreSQL connection string (includes credentials, DB name, SSL params)
STRIPE_SECRET_KEY = Stripe API key — use sk_test_... for local dev, never sk_live_... in dev
REDIS_URL = Cache and BullMQ job queue connection. Required for cart and async jobs.
JWT_SECRET = Token signing secret — must be 32+ chars. Changing this invalidates all sessions.
NEXT_PUBLIC_API_URL = Frontend API base URL (e.g. http://localhost:4000). Baked into Next.js build.