# 09. Database — Migrate Full Prisma Schema to Drizzle ORM

meta:
  id: shieldai-unified-restructure-09
  feature: shieldai-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 `pgEnum`
- 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 PostgreSQL driver in `web/`:
   - `drizzle-orm`
   - `pg` (node-postgres) or `@neondatabase/serverless` if using Neon
   - `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` → `varchar`, `text`, `uuid`
     - `Int` → `integer`
     - `Float` → `real`
     - `Boolean` → `boolean`
     - `DateTime` → `timestamp`
     - `Json` → `jsonb`
     - `String[]` → `text().array()`
   - Preserve `@id`, `@default(uuid())`, `@unique`, `@index`, `@relation`
   - Map Prisma enums to Drizzle `pgEnum()`
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 local PostgreSQL instance 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 PostgreSQL-specific features (arrays, enums, jsonb). Ensure the Drizzle definitions use `pgTable`, `pgEnum`, etc.
