5.1 KiB
Phase 2: Database (Drizzle ORM)
Status: ✅ Done Progress: 12/12 tasks (100%) Started: 2025-10-30 Completed: 2025-10-30 Assigned to: -
Overview
Setup Drizzle ORM, define complete database schema for all tables (users, products, carts, cart_items, orders, order_items), generate and apply migrations, and create database utilities.
Goal: Fully functional database with all MVP tables ready for use.
Dependencies
- ✅ Phase 1: Foundation must be completed
- ✅ PostgreSQL running in Docker (docker-compose.dev.yml)
Tasks
Drizzle Setup
-
Install Drizzle ORM & PostgreSQL driver
pnpm add drizzle-orm postgres pnpm add -D drizzle-kit -
Configure drizzle.config.ts
import { defineConfig } from 'drizzle-kit' export default defineConfig({ schema: './server/database/schema.ts', out: './server/database/migrations', dialect: 'postgresql', dbCredentials: { url: process.env.DATABASE_URL!, }, }) -
Add database scripts to package.json
{ "scripts": { "db:generate": "drizzle-kit generate", "db:migrate": "drizzle-kit migrate", "db:studio": "drizzle-kit studio", "db:push": "drizzle-kit push" } }
Schema Definition
-
Create users table schema
- File:
server/database/schema.ts - Fields: id (UUID), experimenta_id (unique), email, first_name, last_name, salutation, date_of_birth, street, post_code, city, country_code, phone, created_at, updated_at
- See: ARCHITECTURE.md Section 4.1
- File:
-
Create products table schema
- Fields: id (UUID), nav_product_id (unique), name, description, price (decimal), stock_quantity, category, active, created_at, updated_at
- Indexes: nav_product_id, active, category
-
Create carts table schema
- Fields: id (UUID), user_id (FK to users, nullable), session_id, created_at, updated_at
- Relations: hasMany cart_items
-
Create cart_items table schema
- Fields: id (UUID), cart_id (FK to carts), product_id (FK to products), quantity, added_at
- Relations: belongsTo cart, belongsTo product
-
Create orders table schema
- Fields: id (UUID), order_number (unique), user_id (FK to users), total_amount, status, billing_address (JSON), payment_id, payment_completed_at, created_at, updated_at
- Relations: hasMany order_items
- Indexes: order_number, user_id, status
-
Create order_items table schema
- Fields: id (UUID), order_id (FK to orders), product_id (FK to products), product_snapshot (JSON), quantity, price_snapshot, created_at
- Relations: belongsTo order, belongsTo product
Migrations
-
Generate initial migration
pnpm db:generate- Verify migration files in
server/database/migrations/
- Verify migration files in
-
Apply migrations to dev database
pnpm db:migrate- Verify tables exist in PostgreSQL
docker exec -it experimenta-db-dev psql -U dev -d experimenta_dev -c "\dt"
Database Utilities
-
Create database connection utility
- File:
server/utils/db.ts
import { drizzle } from 'drizzle-orm/postgres-js' import postgres from 'postgres' import * as schema from '../database/schema' const config = useRuntimeConfig() const client = postgres(config.databaseUrl) export const db = drizzle(client, { schema }) - File:
-
Test CRUD operations
- Create test endpoint:
server/api/test/db.get.ts - Test insert, select, update, delete on users table
- Verify relations work (e.g., fetch cart with items)
- Remove test endpoint after verification
- Create test endpoint:
Tools
-
Setup Drizzle Studio
pnpm db:studio- Open http://localhost:4983
- Verify all tables are visible
- Test data manipulation via Studio
-
Document schema decisions
- Add comments to schema.ts explaining design choices
- Document why JSONB for billing_address
- Document why UUID vs serial IDs
Acceptance Criteria
- Drizzle ORM is installed and configured
- All 6 tables are defined in schema.ts (users, products, carts, cart_items, orders, order_items)
- Relations between tables are defined correctly
- Initial migration is generated and applied
- All tables exist in PostgreSQL database
- Database connection utility (db.ts) is working
- CRUD operations work as expected
- Drizzle Studio can connect and display tables
- Schema is documented with comments
Notes
- UUID vs Serial: Using UUIDs for better distributed systems support and security
- JSONB for billing_address: Flexible address storage, avoids complex normalized address tables
- Decimal for prices: Using decimal(10,2) for accurate money calculations
- created_at/updated_at: Timestamps for audit trail
Blockers
- None currently