elearning/.agent/workflows/database-migration.md

312 lines
5.9 KiB
Markdown
Raw Normal View History

---
description: How to create and run database migrations
---
# Database Migration Workflow
Follow these steps to create and apply database migrations using Prisma.
---
## Step 1: Update Prisma Schema
Edit `prisma/schema.prisma`:
```prisma
model Course {
id Int @id @default(autoincrement())
title Json // { th: "", en: "" }
description Json
price Decimal @db.Decimal(10, 2)
is_free Boolean @default(false)
have_certificate Boolean @default(false)
status CourseStatus @default(DRAFT)
thumbnail String?
category_id Int
category Category @relation(fields: [category_id], references: [id])
created_by Int
creator User @relation(fields: [created_by], references: [id])
chapters Chapter[]
instructors CourseInstructor[]
enrollments Enrollment[]
created_at DateTime @default(now())
updated_at DateTime @updatedAt
deleted_at DateTime?
is_deleted Boolean @default(false)
@@index([category_id])
@@index([status])
@@index([is_deleted])
}
```
---
## Step 2: Create Migration
// turbo
Run migration command:
```bash
npx prisma migrate dev --name add_course_model
```
This will:
1. Generate SQL migration file
2. Apply migration to database
3. Regenerate Prisma Client
---
## Step 3: Review Migration File
Check generated SQL in `prisma/migrations/`:
```sql
-- CreateTable
CREATE TABLE "Course" (
"id" SERIAL NOT NULL,
"title" JSONB NOT NULL,
"description" JSONB NOT NULL,
"price" DECIMAL(10,2) NOT NULL,
"is_free" BOOLEAN NOT NULL DEFAULT false,
...
CONSTRAINT "Course_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "Course_category_id_idx" ON "Course"("category_id");
```
---
## Step 4: Update Prisma Client
// turbo
Regenerate client if needed:
```bash
npx prisma generate
```
---
## Step 5: Create Seed Data (Optional)
Update `prisma/seed.js`:
```javascript
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
async function main() {
// Create categories
const category = await prisma.category.create({
data: {
name: { th: 'การเขียนโปรแกรม', en: 'Programming' },
description: { th: 'หลักสูตรด้านการเขียนโปรแกรม', en: 'Programming courses' }
}
});
// Create test user
const user = await prisma.user.create({
data: {
username: 'instructor1',
email: 'instructor@example.com',
password: '$2b$10$...', // hashed password
role_id: 2 // INSTRUCTOR
}
});
// Create test course
const course = await prisma.course.create({
data: {
title: { th: 'Python สำหรับผู้เริ่มต้น', en: 'Python for Beginners' },
description: { th: 'เรียนรู้ Python', en: 'Learn Python' },
price: 990,
is_free: false,
category_id: category.id,
created_by: user.id
}
});
console.log('Seed data created:', { category, user, course });
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});
```
---
## Step 6: Run Seed
// turbo
Seed the database:
```bash
npx prisma db seed
```
---
## Common Migration Tasks
### Add New Field
```prisma
model Course {
// ... existing fields
slug String @unique // New field
}
```
// turbo
```bash
npx prisma migrate dev --name add_course_slug
```
### Add Index
```prisma
model Course {
// ... existing fields
@@index([created_at]) // New index
}
```
### Add Relation
```prisma
model Lesson {
// ... existing fields
quiz_id Int?
quiz Quiz? @relation(fields: [quiz_id], references: [id])
}
```
### Rename Field
```prisma
model Course {
// Old: instructor_id
created_by Int // New name
}
```
**Note**: Prisma will detect rename and ask for confirmation
---
## Production Migration
### Step 1: Generate Migration (Dev)
```bash
npx prisma migrate dev --name migration_name
```
### Step 2: Commit Migration Files
```bash
git add prisma/migrations/
git commit -m "Add migration: migration_name"
```
### Step 3: Deploy to Production
```bash
npx prisma migrate deploy
```
**Important**: Never use `migrate dev` in production!
---
## Rollback Migration
### Option 1: Manual Rollback
```bash
# Find migration to rollback
ls prisma/migrations/
# Manually run the down migration (if exists)
psql $DATABASE_URL < prisma/migrations/XXXXXX_migration_name/down.sql
```
### Option 2: Reset Database (Dev Only)
```bash
npx prisma migrate reset
```
**Warning**: This will delete all data!
---
## Troubleshooting
### Migration Failed
```bash
# Check database status
npx prisma migrate status
# Resolve migration
npx prisma migrate resolve --applied MIGRATION_NAME
# or
npx prisma migrate resolve --rolled-back MIGRATION_NAME
```
### Schema Drift
```bash
# Check for drift
npx prisma migrate diff
# Reset and reapply
npx prisma migrate reset
```
### Generate Client Error
```bash
# Clear node_modules and reinstall
rm -rf node_modules
npm install
# Regenerate client
npx prisma generate
```
---
## Checklist
- [ ] Schema updated in `prisma/schema.prisma`
- [ ] Migration created with descriptive name
- [ ] Migration SQL reviewed
- [ ] Migration applied successfully
- [ ] Prisma Client regenerated
- [ ] Seed data updated (if needed)
- [ ] Tests updated for new schema
- [ ] Migration files committed to git
---
## Best Practices
1. **Descriptive Names**: Use clear migration names
-`add_course_certificate_field`
-`update_schema`
2. **Small Migrations**: One logical change per migration
3. **Review SQL**: Always check generated SQL before applying
4. **Test First**: Test migrations on dev database first
5. **Backup**: Backup production database before migrating
6. **Indexes**: Add indexes for frequently queried fields
7. **Constraints**: Use database constraints for data integrity