---
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
