Architecture Overview
Tech Stack
Section titled “Tech Stack”Layer | Technology | Purpose |
---|---|---|
Frontend | Next.js 15 App Router | React 19, SSR, RSC |
Auth | Custom JWT | User management |
Database | Neon + Drizzle ORM | Serverless Postgres + type-safe queries |
Payments | Stripe | Subscriptions + checkout |
Resend | Transactional emails | |
Validation | Zod | Runtime validation |
Data Fetching | TanStack Query | Server state + caching |
Forms | React Hook Form | Form management |
UI | shadcn/ui + Tailwind | Components + styling |
Analytics | PostHog + Axiom | Events + logging |
Jobs | Trigger.dev | Background tasks |
Monorepo | Turborepo + pnpm | Build + packages |
Data Flow
Section titled “Data Flow”Creating a task:
User fills form
↓
Zod validates (client)
↓
Submit to API
↓
Zod validates (server)
↓
Drizzle inserts
↓
TanStack Query updates cache
↓
UI updates
Fetching tasks:
Component calls useTasks()
↓
TanStack Query checks cache
↓
If stale, fetch from API
↓
JWT auth verification
↓
Drizzle queries Neon
↓
Cache result
↓
Render
Type Flow
Section titled “Type Flow”Drizzle Schema (source of truth)
↓
TypeScript Types + Zod Schemas (auto-generated with Drizzle-Zod)
↓
@workspace/database exports entities + schemas
↓
@workspace/types re-exports + composes API responses
↓
API + Frontend import ONLY from @workspace/types
Example:
// 1. Define in Drizzle
export const tasks = pgTable("tasks", { id: integer(), title: varchar() });
// 2. Auto-generated with Drizzle Zod
export type Task = typeof tasks.$inferSelect;
export const insertTaskSchema = createInsertSchema(tasks);
// 3. Use everywhere
const validated = insertTaskSchema.parse(body); // API
const form = useForm({ resolver: zodResolver(insertTaskSchema) }); // Frontend
See Type System and Type Flow for details.
Key Principles
Section titled “Key Principles”- Database schema = source of truth - Everything derives from it
- Validate twice - Client (UX) + server (security)
- Type-safe everywhere - @workspace/types ensures API/frontend alignment
- Cache by default - TanStack Query handles it
- Monorepo - Share code, isolate apps