> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# migrate

> 데이터베이스 마이그레이션 관리하기

`pnpm migrate` 명령어는 데이터베이스 스키마 변경을 안전하게 관리합니다. Entity 정의를 기반으로 자동으로 마이그레이션을 생성하고, 여러 데이터베이스에 일관되게 적용할 수 있습니다.

## 기본 개념

마이그레이션은 데이터베이스 스키마 변경을 **버전 관리**하는 시스템입니다:

* **Entity 기반**: Entity 정의에서 자동으로 마이그레이션 생성
* **순차 실행**: 생성 순서대로 마이그레이션 적용
* **다중 DB 지원**: 여러 데이터베이스를 동시에 관리
* **자동 감지**: Entity 변경사항 자동 감지 및 코드 생성

## 명령어

### status - 상태 확인

현재 마이그레이션 상태를 확인합니다.

```bash theme={null}
pnpm migrate status
```

**출력 예시**:

```
Development Master: ✓ Up to date (v20240115_143022)
Testing: ⚠ 2 pending migrations
Production: ✓ Up to date (v20240115_143022)

Prepared migrations:
  • 20240116_101530_add_user_profile
  • 20240116_102045_create_posts_table
```

**상태 종류**:

* `✓ Up to date`: 모든 마이그레이션 적용 완료
* `⚠ N pending`: N개의 미적용 마이그레이션
* `❌ Error`: 데이터베이스 연결 실패

### run - 마이그레이션 실행

대기 중인 마이그레이션을 모두 적용합니다.

```bash theme={null}
pnpm migrate run
```

**실행 과정**:

```
Running migrations...

Development Master:
  ✓ 20240116_101530_add_user_profile (0.2s)
  ✓ 20240116_102045_create_posts_table (0.3s)

Testing:
  ✓ 20240116_101530_add_user_profile (0.2s)
  ✓ 20240116_102045_create_posts_table (0.3s)

All migrations completed successfully!
```

**자동 생성 및 적용**:

* Entity 변경사항을 감지
* 마이그레이션 코드 자동 생성
* 모든 대상 DB에 순차 적용

<Info>
  Sonamu는 Entity 정의를 분석하여 필요한 마이그레이션을 **자동으로 생성**합니다. 수동으로
  마이그레이션 파일을 작성할 필요가 없습니다.
</Info>

## 마이그레이션 생성

### 자동 생성

Entity를 수정하면 Sonamu가 자동으로 마이그레이션을 생성합니다.

```typescript title="user.entity.ts" theme={null}
// Entity 정의 변경
const UserEntity = {
  properties: [
    {
      name: "email",
      type: "string",
      length: 255,
    },
    // 새 필드 추가
    {
      name: "phone",
      type: "string",
      length: 20,
      nullable: true,
    },
  ],
};
```

```bash theme={null}
# 상태 확인
pnpm migrate status

# 출력:
# Prepared migrations:
#   • 20240116_103045_add_phone_to_users

# 적용
pnpm migrate run
```

### 마이그레이션 파일

생성된 마이그레이션 파일은 `src/migrations/` 디렉토리에 저장됩니다.

```typescript title="src/migrations/20240116_103045_add_phone_to_users.ts" theme={null}
import type { Knex } from "knex";

export async function up(knex: Knex): Promise<void> {
  await knex.schema.alterTable("users", (table) => {
    table.string("phone", 20).nullable();
  });
}

export async function down(knex: Knex): Promise<void> {
  await knex.schema.alterTable("users", (table) => {
    table.dropColumn("phone");
  });
}
```

**구조**:

* `up()`: 마이그레이션 적용 (테이블 생성, 컬럼 추가 등)
* `down()`: 마이그레이션 롤백 (변경사항 되돌리기)

## 지원하는 변경사항

Sonamu가 자동으로 감지하고 마이그레이션을 생성하는 변경사항:

| 변경 타입  | 설명          | 예시                              |
| ------ | ----------- | ------------------------------- |
| 테이블 생성 | 새 Entity 추가 | `PostEntity` 생성                 |
| 컬럼 추가  | 새 프로퍼티 추가   | `phone` 필드 추가                   |
| 컬럼 수정  | 타입/길이 변경    | `varchar(100)` → `varchar(255)` |
| 컬럼 삭제  | 프로퍼티 제거     | `deprecated_field` 삭제           |
| 인덱스 추가 | 인덱스 정의      | `indexes` 배열                    |
| 외래키 추가 | 관계 정의       | `belongsTo` 관계                  |

## 다중 데이터베이스 관리

Sonamu는 여러 데이터베이스를 동시에 관리할 수 있습니다.

### 데이터베이스 구성

```typescript title="sonamu.config.ts" theme={null}
export default {
  database: {
    // 개발 환경 - 마스터
    development_master: {
      client: "mysql2",
      connection: {
        host: "localhost",
        database: "myapp_dev",
        user: "root",
        password: "password",
      },
    },
    // 개발 환경 - 슬레이브 (읽기 전용)
    development_slave: {
      // 슬레이브는 자동으로 무시됨
    },
    // 테스트 환경
    test: {
      client: "mysql2",
      connection: {
        host: "localhost",
        database: "myapp_test",
        user: "root",
        password: "password",
      },
    },
    // 프로덕션 환경
    production: {
      client: "mysql2",
      connection: {
        host: "prod-db.example.com",
        database: "myapp_prod",
        user: "root",
        password: process.env.DB_PASSWORD,
      },
    },
  },
};
```

**마이그레이션 대상**:

* `_master`로 끝나는 데이터베이스
* `_slave`가 아닌 모든 데이터베이스

### 일괄 적용

```bash theme={null}
# 모든 데이터베이스에 적용
pnpm migrate run

# 출력:
# Development Master: ✓ 2 migrations applied
# Testing: ✓ 2 migrations applied
# Production: ✓ 2 migrations applied
```

## 실전 워크플로우

### 1. Entity 변경

```typescript title="user.entity.ts" theme={null}
const UserEntity = {
  properties: [
    // 기존 필드...
    {
      name: "profile_image",
      type: "string",
      nullable: true,
    },
  ],
};
```

### 2. 상태 확인

```bash theme={null}
pnpm migrate status
```

```
Prepared migrations:
  • 20240116_110230_add_profile_image_to_users
```

### 3. 마이그레이션 적용

```bash theme={null}
pnpm migrate run
```

```
✓ All migrations applied successfully!
```

### 4. 코드 업데이트

```typescript title="user.model.ts" theme={null}
class UserModelClass extends BaseModelClass {
  async updateProfileImage(userId: number, imageUrl: string) {
    await this.getPuri("w").table("users").update({ profile_image: imageUrl }).where("id", userId);
  }
}
```

## 고급 사용법 (프로그래매틱)

CLI 명령어로 제공되지 않는 고급 기능은 `Migrator` 클래스를 직접 사용하여 구현할 수 있습니다.

### Migrator 클래스 사용

```typescript title="src/scripts/migration-tools.ts" theme={null}
import { Migrator } from "sonamu";

const migrator = new Migrator();

// 롤백 (마지막 배치)
await migrator.runAction("rollback", ["development_master"]);

// 특정 데이터베이스만 선택
await migrator.runAction("apply", ["test"]);

// 상태 확인 (프로그래매틱)
const status = await migrator.getStatus();
console.log(status);
```

### 롤백 스크립트

```typescript title="src/scripts/rollback-migration.ts" theme={null}
import { Migrator, Sonamu } from "sonamu";

Sonamu.runScript(async () => {
  const migrator = new Migrator();

  console.log("Rolling back last migration batch...");
  await migrator.runAction("rollback", ["development_master", "test"]);
  console.log("Rollback completed!");
});
```

**실행**:

```bash theme={null}
pnpm tsx src/scripts/rollback-migration.ts
```

<Warning>
  **데이터 손실 위험**: 롤백은 테이블이나 컬럼을 삭제할 수 있으므로 **프로덕션에서는 매우 신중하게**
  사용하세요.
</Warning>

### 사용 가능한 액션

`Migrator.runAction()` 메서드가 지원하는 액션:

| 액션         | 설명        | 사용 예시           |
| ---------- | --------- | --------------- |
| `apply`    | 마이그레이션 적용 | 새 스키마 변경 적용     |
| `rollback` | 마지막 배치 롤백 | 실수한 마이그레이션 되돌리기 |

## 문제 해결

### 마이그레이션 충돌

**문제**: 여러 개발자가 동시에 마이그레이션 생성

```
Error: Migration conflict detected
```

**해결**:

```bash theme={null}
# 1. 최신 코드 가져오기
git pull

# 2. 마이그레이션 상태 확인
pnpm migrate status

# 3. 필요 시 마이그레이션 재생성
pnpm migrate run
```

### 데이터베이스 연결 실패

**문제**: DB 연결 실패

```
Error: connect ECONNREFUSED 127.0.0.1:3306
```

**해결**:

```bash theme={null}
# 1. MySQL 실행 확인
mysql -u root -p -e "SHOW DATABASES;"

# 2. 연결 정보 확인
cat sonamu.config.ts

# 3. 데이터베이스 생성
mysql -u root -p -e "CREATE DATABASE myapp_dev;"
```

### 마이그레이션 순서 오류

**문제**: 잘못된 순서로 적용됨

```
Error: Foreign key constraint violation
```

**해결**:

외래키 참조 관계가 있는 경우, 참조되는 테이블이 먼저 생성되어야 합니다.

**수정 방법 1: 프로그래매틱 롤백 후 재적용**

```typescript theme={null}
// 롤백
const migrator = new Migrator();
await migrator.runAction("rollback", ["development_master"]);

// 마이그레이션 파일명 수정 (타임스탬프 조정)
// 20240116_110230_*.ts → 20240116_110231_*.ts

// 재적용
await migrator.runAction("apply", ["development_master"]);
```

**수정 방법 2: Entity 정의 순서 조정**

```typescript theme={null}
// users 테이블을 먼저 생성하도록 Entity 파일 순서 조정
// 그 후 pnpm migrate run
```

## 베스트 프랙티스

### 1. 자주 적용하기

```bash theme={null}
# 작은 단위로 자주 마이그레이션
pnpm migrate run  # 매일
```

### 2. 프로덕션 전 테스트

```bash theme={null}
# 테스트 DB에서 먼저 확인
pnpm migrate status
pnpm migrate run

# 문제없으면 프로덕션 적용
```

### 3. 백업 필수

```bash theme={null}
# 프로덕션 마이그레이션 전 백업
mysqldump -u root -p myapp_prod > backup_$(date +%Y%m%d).sql

# 마이그레이션 적용
pnpm migrate run
```

### 4. 롤백 가능성 고려

```typescript theme={null}
// ✅ 롤백 가능 - down() 함수가 제대로 정의됨
export async function up(knex: Knex) {
  await knex.schema.alterTable("users", (table) => {
    table.string("phone").nullable();
  });
}

export async function down(knex: Knex) {
  await knex.schema.alterTable("users", (table) => {
    table.dropColumn("phone");
  });
}
```

### 5. Git으로 버전 관리

```bash theme={null}
# 마이그레이션 파일을 Git에 커밋
git add src/migrations/
git commit -m "Add phone field to users table"

# 팀원들과 공유
git push
```

## 다음 단계

<CardGroup cols={2}>
  <Card title="fixture" icon="database" href="/ko/tools-and-cli/sonamu-cli/fixture">
    테스트 데이터 관리하기
  </Card>

  <Card title="Entity" icon="cube" href="/ko/core-concepts/entity">
    Entity 정의 자세히 알아보기
  </Card>
</CardGroup>
