The layers
| Layer | Location | Responsibility |
|---|---|---|
| Frontend | apps/frontend/src/ | React SPA — pages, components, Redux, Apollo Client |
| GraphQL resolvers | apps/backend/src/gql/ | Thin HTTP boundary — receive input, call utilities, return output |
| Utilities | apps/backend/src/utilities/ | Business logic — pure functions, no direct HTTP or SDK calls |
| Tools | apps/backend/src/tools/ | External service adapters — database, cache, queue, mailer, etc. |
| Configuration | apps/backend/src/configuration/ | One typed ConfigType per environment — no scattered process.env |
| Shared | apps/shared/src/ | Contracts, Zod schemas, and types shared between backend and tool packages |
| Tool packages | apps/tools/<tool>/<impl>/ | Pluggable vendor implementations (pino, BullMQ, StatsD, etc.) |
Key principles
Resolvers are thin. A GraphQL resolver receives input, calls a utility function, and returns a result. It never contains business logic, never calls the database directly, and never imports a vendor SDK. Tools are injected, not imported. Every resolver and utility receives atools object. No part of the codebase imports pino, Stripe, or redis directly — it only calls tools.logger, tools.paymentProcessor, tools.cache.
Configuration resolves once. process.env is read exactly once, in apps/backend/src/configuration/<env>.ts. Everything downstream receives a typed, validated ConfigType.
Implementations are swappable. Every external dependency — logger, queue, metrics, mailer, analytics — is pluggable. Change the client value in config and the loader dynamically imports the right package. Nothing else changes.
Architecture deep dives
| Topic | Where to go |
|---|---|
| Authentication and sessions | Authentication |
| Role-based access control and scopes | RBAC |
| Billing, Stripe, and webhooks | Billing |
| Pluggable tools and the loader pattern | Tooling system |
| ConfigType, env vars, and provider swapping | Configuration system |
What’s next?
Start with whichever system you’re about to touch:- Authentication — sessions, Passport, email verification, OAuth
- RBAC — roles, scopes, and how feature access is gated
- Billing — Stripe subscriptions, webhooks, checkout, downgrades
- Tooling system — how pluggable tools are loaded and swapped