Migrations
UniPulse uses Prisma Migrate to manage database schema changes. All migrations are stored as SQL files in apps/api/prisma/migrations/ and applied in order.
Migration Workflow
Creating a Migration
After modifying apps/api/prisma/schema.prisma:
cd apps/api
npx prisma migrate dev --name describe_your_change
This will:
| Step | Action |
|---|---|
| 1 | Diff the schema against the current database state |
| 2 | Generate a timestamped SQL migration in prisma/migrations/ |
| 3 | Apply the migration to your local PostgreSQL database |
| 4 | Regenerate the Prisma client with updated types |
Migration File Structure
apps/api/prisma/migrations/
├── 20260101000000_initial_schema/
│ └── migration.sql
├── 20260115000000_add_audience_segments/
│ └── migration.sql
├── 20260201000000_add_revenue_attribution/
│ └── migration.sql
└── migration_lock.toml
Applying Migrations in Production
# In the production environment (or Docker container)
npx prisma migrate deploy
This applies all pending migrations without generating new ones. It is safe to run multiple times -- already-applied migrations are skipped.
# Via Docker Compose
docker compose exec api npx prisma migrate deploy
Checking Migration Status
npx prisma migrate status
Shows which migrations have been applied and which are pending.
Resetting the Database
npx prisma migrate reset
This drops all tables and data, then re-applies all migrations from scratch. Only use in development environments. Never run this in production.
Common Migration Operations
Adding a New Model
// schema.prisma
model CouponGenerated {
id String @id @default(cuid())
workspaceId String
workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade)
code String
discount Float
usageCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([workspaceId])
}
npx prisma migrate dev --name add_coupon_generated
Adding a Field to an Existing Model
model Post {
// ... existing fields
sentimentScore Float? // New nullable field
}
npx prisma migrate dev --name add_sentiment_score_to_post
Adding an Index
model PostMetric {
// ... existing fields
@@index([publicationId, date]) // New composite index
}
npx prisma migrate dev --name add_index_post_metric_date
Renaming a Field (Requires Custom SQL)
Prisma cannot auto-detect renames. You need to create a custom migration:
npx prisma migrate dev --name rename_field --create-only
Then edit the generated SQL:
-- Instead of DROP + ADD, use ALTER COLUMN RENAME
ALTER TABLE "Post" RENAME COLUMN "old_name" TO "new_name";
Then apply:
npx prisma migrate dev
Migration Best Practices
| Practice | Why |
|---|---|
| Name migrations descriptively | add_audience_segments, add_index_on_post_created_at |
| Review generated SQL before committing | Catch unintended schema changes |
| Never edit applied migration files | Breaks migration history |
| Test on staging before production | Catch issues before they affect live data |
| Back up database before production migrations | Safety net for rollbacks |
Add workspaceId + index to new models | Maintains multi-tenant isolation |
Use onDelete: Cascade thoughtfully | Prevent orphaned records but avoid cascade surprises |
| Make new fields nullable or provide defaults | Avoids migration failures on existing data |
Seeding
For development data seeding:
npx prisma db seed
The seed script is defined in apps/api/prisma/seed.ts and creates sample workspaces, users, posts, and other test data.
- Schema Overview -- all 69+ models
- Key Relations -- foreign keys and indexes
- Backend Local Setup -- initial migration during setup
- Deployment -- production migration steps
- New Feature Checklist -- migration as part of feature development