91 lines
5.0 KiB
Markdown
91 lines
5.0 KiB
Markdown
# 09. Database — Migrate Full Prisma Schema to Drizzle ORM
|
|
|
|
meta:
|
|
id: kordant-unified-restructure-09
|
|
feature: kordant-unified-restructure
|
|
priority: P0
|
|
depends_on: []
|
|
tags: [backend, database, drizzle, schema]
|
|
|
|
objective:
|
|
- Convert the entire 900-line Prisma schema from `packages/db/prisma/schema.prisma` into Drizzle ORM TypeScript schema files in `web/src/server/db/schema.ts` and related files. This is the foundational data layer for the unified monolith.
|
|
|
|
deliverables:
|
|
- `web/src/server/db/schema.ts` — Main schema file with all tables:
|
|
- User & Authentication (User, Account, Session, DeviceToken)
|
|
- Family & Subscription (FamilyGroup, FamilyGroupMember, Subscription)
|
|
- DarkWatch (WatchlistItem, Exposure)
|
|
- Notifications & Alerts (Alert)
|
|
- VoicePrint (VoiceEnrollment, VoiceAnalysis, AnalysisJob, AnalysisResult)
|
|
- SpamShield (SpamFeedback, SpamRule)
|
|
- Audit & Analytics (AuditLog, KPISnapshot)
|
|
- Correlation (NormalizedAlert, CorrelationGroup)
|
|
- Reports (SecurityReport)
|
|
- Marketing (WaitlistEntry, BlogPost)
|
|
- HomeTitle (PropertyWatchlistItem, PropertySnapshot, PropertyChange)
|
|
- RemoveBrokers (InfoBroker, RemovalRequest, BrokerListing)
|
|
- `web/src/server/db/schema/` — Optional split directory if single file becomes unwieldy:
|
|
- `auth.ts`, `subscription.ts`, `darkwatch.ts`, `voiceprint.ts`, `spamshield.ts`, `alerts.ts`, `correlation.ts`, `reports.ts`, `marketing.ts`, `hometitle.ts`, `removebrokers.ts`
|
|
- All enums defined as TypeScript const arrays or Drizzle `enum()`
|
|
- All indexes, unique constraints, and foreign keys preserved
|
|
- Relations defined using Drizzle's `relations()` helper
|
|
|
|
steps:
|
|
1. Read and analyze `packages/db/prisma/schema.prisma` completely. Document every model, enum, relation, index, and constraint.
|
|
2. Install Drizzle ORM and Turso client in `web/`:
|
|
- `drizzle-orm`
|
|
- `@libsql/client` (Turso/libsql client)
|
|
- `drizzle-kit` for migrations
|
|
3. Create `web/src/server/db/schema.ts` (or split directory).
|
|
4. For each Prisma model, create a Drizzle table definition:
|
|
- Map Prisma field types to Drizzle column types:
|
|
- `String` → `text`, `varchar`
|
|
- `Int` → `integer`
|
|
- `Float` → `real`
|
|
- `Boolean` → `integer` (SQLite has no native boolean, use 0/1)
|
|
- `DateTime` → `text` (ISO strings) or `integer` (Unix timestamp)
|
|
- `Json` → `text` (SQLite stores JSON as text)
|
|
- `String[]` → `text` (serialize to JSON string)
|
|
- Preserve `@id`, `@default(uuid())`, `@unique`, `@index`, `@relation`
|
|
- Map Prisma enums to Drizzle `enum()` or `text()` with check constraints
|
|
5. Define all indexes using Drizzle's `.index()` and `.unique()` on table definitions.
|
|
6. Define relations using `relations()` helper for:
|
|
- User → accounts, sessions, familyGroups, subscriptions, alerts, voice enrollments, etc.
|
|
- Subscription → watchlistItems, exposures, alerts, propertyWatchlistItems, removalRequests
|
|
- WatchlistItem → exposures
|
|
- PropertyWatchlistItem → snapshots, changes
|
|
- And all other one-to-many / many-to-one relations
|
|
7. Export a unified schema object for use with Drizzle Kit.
|
|
8. Verify the schema compiles without TypeScript errors.
|
|
9. Generate an ER diagram or schema summary for documentation.
|
|
|
|
steps:
|
|
- Unit: Schema file compiles without TS errors
|
|
- Integration: `drizzle-kit generate` produces migration SQL that matches Prisma schema structure
|
|
- Compare: Automated or manual comparison of Prisma schema vs Drizzle schema to ensure no models/fields are missing
|
|
|
|
acceptance_criteria:
|
|
- [ ] Every model from Prisma schema has a corresponding Drizzle table definition
|
|
- [ ] All enums are defined and used correctly
|
|
- [ ] All primary keys, unique constraints, and indexes are preserved
|
|
- [ ] All foreign key relations are defined using Drizzle relations
|
|
- [ ] `drizzle-kit generate` runs successfully and outputs SQL
|
|
- [ ] Generated SQL creates tables with correct column types and constraints
|
|
- [ ] No data loss: the new schema is structurally equivalent to the old one
|
|
|
|
validation:
|
|
- Run `cd web && npx drizzle-kit generate` and inspect generated SQL
|
|
- Compare table count: Prisma schema has X models, Drizzle schema has X tables
|
|
- Verify enum values match exactly between Prisma and Drizzle
|
|
- Run `npx drizzle-kit push` against a Turso database (or local SQLite) and confirm all tables are created
|
|
|
|
notes:
|
|
- This is the most critical backend task. A missing field or incorrect relation will cascade into broken tRPC routers.
|
|
- Prisma's implicit many-to-many relations must be explicitly defined as junction tables in Drizzle.
|
|
- Prisma's `@updatedAt` auto-timestamp can be replicated with Drizzle's `$onUpdateFn(() => new Date())`.
|
|
- Keep the old Prisma schema file as reference until task 41.
|
|
- Consider using `drizzle-zod` later (task 11+) to auto-generate validation schemas from Drizzle tables.
|
|
- The schema uses SQLite-compatible types. Ensure the Drizzle definitions use `sqliteTable`, `enum()`, etc.
|
|
- SQLite stores JSON as text — serialize/deserialize in application code or use Drizzle's `json()` helper.
|
|
- SQLite doesn't have native array types — store arrays as JSON-encoded text strings.
|