- Monorepo
- Turbo (recommended) or nx
- Full-stack TS
- Docker
- Cloud Platform
- Compute
- 3 environments: dev, stage, prod
- Packages
- Error tracking
- Sentry or Rollbar
- Global error handler
- Error notifications
- Errors should ping us in Slack. False positives should be muted. Error notifs should be maintained
- Logging
- Telemetry
- Open Telemetry Auto instrumentation
- Linter & auto-formatter
- Prettier, eslint - husky commit hooks to auto format w/ prettier
- Package manager
- Branching strategy
- dev for dev
- stg for stage
- prd for prod
- CI/CD
- GitHub Actions (recommended)
- Should autodeploy by branch
- Preview deploys on topic branches
- MUST run unit tests & e2e tests
- Canary deploys
- Testing
- Unit tests: fast, use vitest or jest (mock external calls)
- e2e tests: slower, can call REAL dev or testing DB - scope the data accordingly, build cleanup accordingly
- Note: NeonDB supports branching to prevent test data leaking through into dev
- Secret Management: ALL secrets must be managed, never checked into source control
- GCP Secrets Manager (recommended)
- Shared types
- Depending on backend: shared package (nestjs) OR tRPC
- Vulnerability Scanning
- Disaster recovery
- Feature flags (Optional - depending on need)
- Remote config, home-grown, etc…
- CLI (OPTIONAL): Custom cli for ops tasks (oclif)
- IaC (OPTIONAL): Reproducable infra
- SLAs & SLOs (OPTIONAL)
- CPU & Memory usage notifications
- Framework
- NestJS (recommended)
- Consider: Hono (more lightweight)
- MUST have swagger auto-doc for endpoints
- Database
- Postgres (recommended)
- NeonDB (recommended), Supabase, or GCP Cloud SQL
- Firestore (vendor lockin)
- MongoDB
- ORM
- Prisma (recommended) - various alternatives
- OR Drizzle ORM
- Auth
- Always go for managed auth - NEVER roll your own auth
- Firebase auth, Auth0, Clerk, Better Auth
- RBAC
- Multi-tenant? (depending on need)
- Security
- Async processing (OPTIONAL - depends on requirements)
- Any long-running tasks shouldn’t make the user wait
- GCP PubSub (recommended)
- At least once processing
- Idempotent
- Replay or retry
- Scheduled tasks
- DLQs
- File storage
- Rate limiting (for public APIs)
- Nestjs throttler (recommended)
- Input validation
- Emails
- React or React Native (recommended)
- Web: NextJS (recommended, depending on project!)
- Caching solution
- Forms
- Tanstack forms
- Validation: zod
- Store (optional)
- Component lib
- Shadcn (recommended) - fully customisable, themeable, darkmode
- RN: Need component lib recommendation (ideally supports Nativewind)
- Storybook for component management (optional)
- Styling & theming
- Design system
- Tailwind’s system is good
- Analytics
- GA or PostHog auto-instrumentation
- Accessibility
- i18n
- SEO
- Error boundaries
- Consider: Performance e.g. Lighthouse CI
- Design Tokens
- Tailwind config IS your token layer — spacing, color, typography, shadows, radii, motion
- Shadcn’s HSL CSS variables (recommended) — swap themes without touching components
- Sync tokens to Figma variables for design-code parity
- Spacing System
- 4px base grid (Tailwind default) — #1 differentiator between amateur and professional UI
- Stick to Tailwind’s scale — arbitrary values (
mt-[13px]) are a smell
- Typography
- Modular type scale (1.25 ratio) — max 4–5 sizes in the whole app
- Inter or system font stack (recommended) — one family, two weights covers 90% of apps
- Color System
- Semantic tokens only:
background, foreground, muted, accent, destructive — never raw hex
- Neutral palette matters more than brand color
- WCAG AA contrast minimums — non-negotiable
- Dark mode from day one, not bolted on
- Visual Hierarchy
- Size > Weight > Color — use in that order to create emphasis
- Every screen: ONE primary action. If everything is bold, nothing is bold
- When in doubt, more whitespace
- Layout
- Mobile-first, max content width ~1280px centered
- Grid for page layout, Flexbox for component layout
- Build reusable page shells early
- Iconography
- One set everywhere — Lucide (recommended, ships with Shadcn)
- Pair with text labels; consistent sizing (16/20/24px)
- Motion
- Purposeful, not decorative — communicates state change
- Framer Motion (recommended)
- Interactions < 200ms, layout shifts 300–500ms
- Respect
prefers-reduced-motion
- Responsive
- Design 3 layouts (mobile, tablet, desktop) — not per-device pixel-perfects
- Touch targets: 44x44px minimum (Apple HIG)
- UX Patterns
- Loading: skeletons > spinners (no layout jump)
- Empty states: never blank — guide user to first action
- Error states: inline, contextual, actionable
- Optimistic updates where safe
- Destructive actions require confirmation
- Microcopy
- Design with real content, never lorem ipsum
- Button labels, empty states, error messages are UX — not afterthoughts
- Tooling
- Figma (recommended) — single source of truth
- Mirror Shadcn library in Figma 1:1
- Figma MCP for AI-assisted design-to-code
- AGENTS.md
- Maintain this well
- Symlink a CLAUDE.md file to it if using claude
- Bonus: Scope per project (web, api, etc…)
- Context Engineering
- Dictation
- Plans & reports
- Before work: Have AI generate plan files in the
plans folder
- After work: Have AI generate a report file in the
docs folder
- Prefix AI generated files w/ the ISO datetime
2026-04-01_filename.md
- Plans are how you decide how to work
- Reports are how you remember what you did, and what you want AI to reference first if you go back to tweak a feature
- Both should include paths to all relevant files
- Plans should include blocking questions
- Testing loop
- THE VALUE OF THIS CANNOT BE OVERSTATED
- AI should be given as much capability to check its own work as possible
- AI should follow TDD
- AI should be taught to boot up the app and check it itself when building a new feature - browser verification
- Remove as many blockers to this loop as possible
- Unit / e2e split is valuable
- Error messages, clean failure context
- Review test cases as part of the plan
- Commands & Skills
- Commands for context you want to load manually
- Skills for things you want agents to auto-load when doing certain tasks
- Model: Claude Opus 4.6
- Harness: Claude Code or Cursor
- MCP: Context7, Database access, Figma
- Agent orchestration?
- Server-side caching (if needed)
- Feature flags
- Remote config, many alternatives
---
title: System Architecture Overview
---
graph TB
%% ─── Client Layer ───────────────────────────────────────────────
subgraph CLIENT["👤 Client Layer"]
Browser["Browser / Mobile App"]
end
%% ─── Frontend ───────────────────────────────────────────────────
subgraph FRONTEND["⚛️ Frontend (Next.js)"]
direction TB
Pages["Pages & Routes"]
UI["UI Components (Shadcn + Tailwind)"]
Cache["Client Cache (TanStack Query)"]
Forms["Forms (TanStack Forms + Zod)"]
Store["Global State (Zustand)"]
Analytics["Analytics (GA / PostHog)"]
end
%% ─── Shared Layer ───────────────────────────────────────────────
subgraph SHARED["📦 Shared Packages (Monorepo)"]
Types["Shared Types (tRPC or shared pkg)"]
Utils["Shared Utilities"]
Config["Shared Config"]
end
%% ─── Backend ────────────────────────────────────────────────────
subgraph BACKEND["🖥️ Backend (NestJS)"]
direction TB
API["REST API (Swagger auto-docs)"]
Guards["Auth Guards (token validation)"]
Services["Business Logic Services"]
ORM["ORM Layer (Prisma)"]
end
%% ─── Auth Provider ──────────────────────────────────────────────
subgraph AUTH["🔐 Managed Auth"]
AuthProvider["Firebase Auth / Auth0 / Clerk"]
end
%% ─── Async Processing ───────────────────────────────────────────
subgraph ASYNC["⚡ Async Processing (Optional)"]
PubSub["GCP PubSub"]
Workers["Background Workers"]
end
%% ─── Data Layer ─────────────────────────────────────────────────
subgraph DATA["🗄️ Data Layer"]
Postgres["PostgreSQL (NeonDB)"]
RedisCache["Redis / Memorystore (Optional)"]
end
%% ─── Observability ──────────────────────────────────────────────
subgraph OBS["📊 Observability"]
Sentry["Error Tracking (Sentry)"]
Logs["GCP Logs Explorer"]
OTel["OpenTelemetry"]
Slack["Slack Notifications"]
end
%% ─── Cloud Platform ─────────────────────────────────────────────
subgraph CLOUD["☁️ GCP"]
Secrets["Secrets Manager"]
Hosting["Cloud Run / GKE"]
end
%% ─── Connections ────────────────────────────────────────────────
Browser -->|"HTTPS"| FRONTEND
FRONTEND -->|"API calls"| API
FRONTEND ---|"imports"| SHARED
BACKEND ---|"imports"| SHARED
API --> Guards
Guards -->|"validate token"| AuthProvider
Guards --> Services
Services --> ORM
ORM -->|"queries"| Postgres
Services -->|"cache read/write"| RedisCache
Services -->|"publish message"| PubSub
PubSub -->|"triggers"| Workers
Workers --> ORM
Browser -->|"login/signup"| AuthProvider
AuthProvider -->|"JWT token"| Browser
BACKEND --> Sentry
FRONTEND --> Sentry
Sentry -->|"alerts"| Slack
BACKEND --> OTel
OTel --> Logs
BACKEND -->|"reads secrets at boot"| Secrets
sequenceDiagram
actor User
participant FE as ⚛️ Frontend
participant Cache as 📋 TanStack Query
participant Auth as 🔐 Auth Provider
participant API as 🖥️ NestJS API
participant Guard as 🛡️ Auth Guard
participant Svc as ⚙️ Services
participant DB as 🗄️ PostgreSQL
participant Sentry as 📊 Sentry
participant PubSub as ⚡ PubSub
Note over User,DB: 🟢 Happy Path
User->>FE: Click / submit
FE->>FE: Validate input (Zod)
FE->>Cache: Check cache
alt Cache hit
Cache-->>FE: Cached data
FE-->>User: Render instantly
else Cache miss
FE->>API: HTTP request + JWT
API->>Guard: Intercept
Guard->>Auth: Verify JWT
Auth-->>Guard: Valid (uid, roles)
Guard->>Svc: User context attached
Svc->>DB: Query via Prisma
DB-->>Svc: Result
Svc-->>API: Response
API-->>FE: JSON (200)
FE->>Cache: Store result
FE-->>User: Render
end
Note over User,DB: 🟡 Async Path (long-running tasks)
User->>FE: Trigger async action
FE->>API: Request + JWT
API->>Svc: Handle
Svc->>PubSub: Publish message
Svc-->>API: Accepted (202)
API-->>FE: Processing...
FE-->>User: Show loading state
PubSub->>Svc: Worker picks up
Svc->>DB: Write result
Note over User,DB: 🔴 Error Path
User->>FE: Action triggers error
FE->>API: Request
API->>Svc: Handle
Svc->>DB: Query fails
DB-->>Svc: Error
Svc-->>API: Exception
API->>Sentry: Capture error
Note right of Sentry: Alerts Slack<br/>(false positives muted)
API-->>FE: Error (4xx/5xx)
FE-->>User: Show error message