-
Notifications
You must be signed in to change notification settings - Fork 0
Tech Stack
Draft v0 is a full-stack TypeScript application. Every technology choice has a rationale — recorded in Architecture Decisions.
| Layer | Technology | Why |
|---|---|---|
| Frontend | React 19, TypeScript | Stable, widely adopted, React 19 removes legacy APIs (forwardRef, React.FC) |
| Routing | TanStack Router | Type-safe file-based routing without Next.js overhead |
| Data fetching | TanStack Query | Server state management with caching, invalidation, and background refetching |
| Design System | DSAi + Bootstrap 5.3 | Token-driven design system with Figma sync, multi-format output, Bootstrap utility classes |
| Backend | Node.js + Express | Minimal and flexible, pairs cleanly with TypeScript |
| Database | Prisma ORM (SQLite) | Type-safe queries, easy migrations, SQLite for zero-config dev |
| Build | Vite 6 | Fast HMR, ESM-first, handles both client and server builds |
| Testing | Vitest + Playwright | Unit tests via Vitest (same API as Jest), e2e via Playwright |
| Quality | Biome + ESLint | Biome for fast lint/format, ESLint for additional rules |
| Forms | React Hook Form + Zod | Performant forms, Zod schemas shared between client and server |
| Client state | Zustand | Minimal, focused stores for UI-only state (modals, sidebar, theme) |
| Design | Figma MCP + Code Connect | Direct Figma API access for design-to-code, Dev Mode integration |
| Security | Helmet + express-rate-limit | HTTP security headers, API rate limiting out of the box |
React 19 removes several legacy APIs that caused confusion and added boilerplate:
-
No
forwardRef—refis now a regular prop -
No
React.FC— just writefunction MyComponent(props: Props) -
No
propTypes— TypeScript handles runtime-safety concerns at build time
All components in this project follow React 19 conventions. See Skills Reference → react skill.
TanStack Router provides full type safety across routes, params, and search params. Key advantages over alternatives:
- Type-safe
useParams(),useSearch(), andLinkcomponent - File-based routing (
src/client/routes/) — no manual route config - Works as a pure SPA without a server-side rendering framework
All server data flows through TanStack Query. Never use useState + useEffect to fetch API data.
// Correct: server data via useQuery
const { data: users } = useQuery({
queryKey: ["users"],
queryFn: () => fetch("/api/users").then((r) => r.json()),
});
// Correct: mutations via useMutation
const mutation = useMutation({
mutationFn: createUser,
onSuccess: () => queryClient.invalidateQueries({ queryKey: ["users"] }),
});The project uses the DSAi design system for design token management and Bootstrap 5.3 as the utility/component framework. This replaces the previous Tailwind CSS v4 + shadcn/ui setup (see ADR 0014).
Key aspects:
-
Design tokens are structured JSON files in
src/collections/(color, typography, spacing, shadow, border, layout) -
Token pipeline (
pnpm tokens:build) transforms tokens into CSS variables (--dsai-*), SCSS variables, JS/TS constants, and JSON -
Bootstrap integration —
src/scss/dsai-theme-bs.scssmaps DSAi tokens to Bootstrap 5.3 variables -
Dark mode via
[data-dsai-theme="dark"]attribute andprefers-color-schememedia query -
Figma sync —
pnpm figma:syncpulls design tokens directly from Figma
Components use Bootstrap utility classes (btn, container, d-flex, p-4, etc.) and --dsai-* CSS custom properties for design token values.
See DSAi Design System for the full guide and Figma Tokens for the token mapping.
The backend follows a strict 4-layer architecture. Each layer has one responsibility:
Route → Controller → Service → Repository → Prisma (SQLite)
| Layer | Location | Responsibility |
|---|---|---|
| Routes | src/server/routes/ |
Map HTTP method + path to controller |
| Controllers | src/server/controllers/ |
Parse request, call service, send response |
| Services | src/server/services/ |
Business logic, throw custom errors |
| Repositories | src/server/repositories/ |
Prisma queries only, no business logic |
See Project Structure for the full breakdown.
Prisma provides type-safe database access. The schema lives in prisma/schema.prisma. Changes are applied with pnpm db:push (development).
Key rules:
- Never use raw SQL — use the Prisma Client API
- Handle
P2002(unique constraint) andP2025(record not found) explicitly - Use
import type { User } from "@prisma/client"for model types
| Tool | Role |
|---|---|
| Biome | Fast lint and format — replaces ESLint + Prettier for most rules |
| ESLint | Additional rules Biome does not cover |
| TypeScript strict |
noImplicitAny, strictNullChecks, noUncheckedIndexedAccess
|
| Helmet | Sets Content-Security-Policy, X-Frame-Options, and other security headers |
| express-rate-limit | Protects API routes from abuse and brute-force attacks |
| Codacy CLI | Automated code quality analysis after every file edit |
→ Architecture Decisions for the full decision log · Contributing for quality gates