Files
Kordant/tasks/shieldai-unified-restructure/09-drizzle-schema-migration.md
2026-05-25 12:23:23 -04:00

4.8 KiB

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:
      • Stringvarchar, text, uuid
      • Intinteger
      • Floatreal
      • Booleanboolean
      • DateTimetimestamp
      • Jsonjsonb
      • 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.