# 실제 데이터베이스 연결

> ERD를 실제 PostgreSQL·MySQL 데이터베이스와 대조하는 단계별 안내 — 로그인부터 CI에서 드리프트 검사까지.

**Pro**에서는 Sqemo가 실제 PostgreSQL 또는 MySQL 데이터베이스를 읽을 수 있습니다 —
스키마를 ERD로 가져오거나, 원본으로 삼는 ERD에서 데이터베이스가 *어긋났는지(drift)*
검사합니다. 전부 로컬(또는 CI 작업)에서
[sqemo-mcp](https://www.npmjs.com/package/sqemo-mcp)를 통해 실행되며, 데이터베이스
접속 정보는 Sqemo로 전송되지 않습니다.

이 안내는 전체 흐름을 처음부터 끝까지 다룹니다. 처음이라면 위에서 아래로 따라가세요.

## 필요한 것

- **Node.js 22+** (`node --version`으로 확인).
- **Pro** Sqemo 계정(또는 Team 워크스페이스 멤버). Free 플랜에서는 데이터베이스
  명령이 연결 전에 업그레이드 안내와 함께 멈춥니다.
- 검사할 데이터베이스 — 없어도 됩니다:
  [아래 Docker 옵션](#데이터베이스가-아직-없다면-docker)으로 몇 분 안에 하나 띄울 수
  있습니다.

## 1단계 — 터미널에서 로그인

데이터베이스 명령에는 로그인이 필요합니다. 한 번 로그인하세요:

```bash
npx sqemo-mcp login
#   1) Google           (브라우저를 엽니다)
#   2) GitHub           (브라우저를 엽니다)
#   3) Email + password (여기서 바로)
```

1 또는 2를 고르면 브라우저 탭이 열립니다. 거기서 로그인하면 터미널이 받습니다. 3을
고르면 터미널을 떠나지 않고 이메일과 비밀번호를 입력합니다. Google·GitHub·이메일 중
어떻게 가입했든 이 중 하나는 됩니다.

어느 쪽이든 리프레시 토큰이 `~/.erdmaker/credentials.json`에 저장됩니다(비밀번호는
저장되지 않습니다). `npx sqemo-mcp logout`이 지웁니다.

### 브라우저가 없는 기기에서

옵션 1·2는 콜백이 `127.0.0.1`로 돌아오므로 같은 기기에 브라우저가 필요합니다. SSH나
컨테이너 안에서는 비밀번호 경로를 바로 쓰세요:

```bash
npx sqemo-mcp login --password
```

자동화에서는 `login`을 아예 건너뛰고
[아래 CI 절](#ci에-넣기-github-actions-단계별)처럼 `SQEMO_EMAIL` / `SQEMO_PASSWORD`를
설정합니다.

스크립트는 제공자를 지정해 메뉴를 건너뛸 수도 있습니다:
`npx sqemo-mcp login --provider github`.

## 2단계 — 기준선이 될 ERD 준비

드리프트는 *ERD 대 데이터베이스*이므로 ERD 쪽이 필요합니다. 두 가지 방법:

- **서버 ERD**(계정에 저장됨): `--erd <id>`를 씁니다. id는 `list_erds` MCP 도구나,
  ERD를 열었을 때의 앱 URL에서 얻습니다.
- **로컬 프로젝트**(브라우저에만 있음): 먼저 파일로 내보냅니다. 앱에서 **툴바 →
  내보내기(Export) → 프로젝트 다운로드(Download project)**. `<이름>.erd.json` 파일이
  생깁니다(보통 다운로드 폴더). CI에서 검사할 거라면 이 파일을 저장소에 커밋하세요 —
  스키마의 원본이 됩니다.

## 3단계 — 드리프트 검사 실행

`lint`에 ERD와 데이터베이스를 지정합니다:

```bash
# 로컬 프로젝트 파일
npx sqemo-mcp lint "Online Shop Example.erd.json" --db "mysql://user:pass@host:3306/dbname"

# 파일 대신 서버 ERD
npx sqemo-mcp lint --erd <erd-id> --db "postgresql://user:pass@host:5432/dbname"
```

접속 URL 형식:

```
PostgreSQL: postgresql://user:pass@host:5432/dbname
MySQL:      mysql://user:pass@host:3306/dbname
```

### 어떤 데이터베이스를 지원하나요?

원칙: **라이브 `--db` 연결은 PostgreSQL과 MySQL(MariaDB 포함)만 됩니다.** 다른
방언은 여전히 SQL *가져오기·내보내기*를 지원하며,
[`--schema` 덤프 경로](#3단계--드리프트-검사-실행)로 드리프트 검사를 할 수 있습니다 —
라이브 연결만 안 됩니다.

| 데이터베이스 | ERD 내보내기/가져오기 | 라이브 `--db` | 덤프 `--schema --dialect` |
|----------|:---:|:---:|:---:|
| PostgreSQL | ✓ | ✓ | ✓ `postgres` |
| MySQL / MariaDB | ✓ | ✓ (`mysql://`) | ✓ `mysql` |
| Oracle | ✓ | — | ✓* `oracle` |
| SQL Server | ✓ | — | ✓* `sqlserver` |
| SQLite | ✓ | — | ✓* `sqlite` |
| H2 | ✓ | — | ✓* `h2` |
| CUBRID | ✓ | — | ✓* `cubrid` |

\* 파서는 있지만 공식 테스트 대상이 아니라, 덤프의 정확한 형식에 따라 결과가 다를 수
있습니다.

PostgreSQL과 MySQL만 라이브 연결이 되는 이유: 둘 다 **순수 JavaScript 드라이버**가
있어(`npx` 외에 설치할 것이 없음) 표준 `information_schema`를 공유하므로 인트로스펙션
경로 하나로 둘을 덮습니다. 나머지는 각각 다른 드라이버와 카탈로그가 필요합니다 —
Oracle은 Instant Client와 자체 데이터 딕셔너리, SQLite는 서버가 아니라 파일, H2는
Java/JDBC 전용 등 — 그래서 당분간 덤프 경로로 갑니다.

**MariaDB 참고:** MySQL 프로토콜을 쓰므로 `mysql://` 스킴으로 연결하세요
(`mariadb://`는 인식되지 않습니다). 덤프 모드는 `--dialect mysql`. MariaDB 고유 컬럼
타입은 오류가 아니라 *경고*(기본적으로 통과)로 나타날 수 있습니다.

유용한 옵션:

- `--db-schema <name>` — 읽을 스키마(PostgreSQL 기본 `public`; MySQL은 URL의
  데이터베이스를 읽음).
- `--ignore "flyway_*"` — DB에는 있지만 ERD에는 없는 테이블(마이그레이션 이력·감사
  테이블)을 건너뜀. 반복 지정 가능.
- `--strict` — 타입·표현 차이(보통 경고)도 실패로 처리.
- `--schema dump.sql --dialect postgres` — 연결 **대신** `pg_dump -s` 파일과 비교.
  데이터베이스 URL이 전혀 필요 없습니다.

## 4단계 — 결과 읽기

명령의 **종료 코드**가 답입니다(PowerShell은 `echo $LASTEXITCODE`, bash는
`echo $?`):

| 종료 코드 | 의미 |
|------|---------|
| **0** | ERD와 데이터베이스가 일치. |
| **1** | 드리프트 발견. 항목마다 나열됩니다. 예: `[missing_column] CUST.EMAIL`, `[missing_table] ORDER_ITEM`, 그리고 요약 한 줄. |
| **2** | 아직 비교 불가 — 접속 실패, 잘못됐거나 빈 스키마, 미로그인, Free 플랜, 사용법 오류. URL의 비밀번호는 메시지에서 `:****@`로 가려집니다. |

**빈 데이터베이스**(스키마에 테이블 0개)는 "전부 누락"이 아니라 종료 **2**를
보고합니다 — 거의 항상 스키마 이름이나 데이터베이스가 잘못 가리켜진 경우라, 거짓 양성을
쏟아내는 대신 확인을 요청합니다.

## 데이터베이스가 아직 없다면? Docker

호스팅된 데이터베이스가 없어도 시험할 수 있습니다. 하나 띄우고, ERD의 스키마를 적재하고,
검사하세요:

```bash
# 1) 일회용 MySQL 시작
docker run -d --name sqemo-my -e MYSQL_ROOT_PASSWORD=pw -e MYSQL_DATABASE=app -p 13306:3306 mysql:8
# 초기화까지 ~30초 대기

# 2) ERD를 SQL로 바꿔 적재
npx sqemo-mcp export "Online Shop Example.erd.json" --format sql --dialect mysql > shop.sql
docker exec -i sqemo-my mysql -uroot -ppw app < shop.sql

# 3) 검사 — 일치하므로 종료 0
npx sqemo-mcp lint "Online Shop Example.erd.json" --db "mysql://root:pw@localhost:13306/app"

# 4) DB를 바꾸고 다시 검사 — 이제 차이와 함께 종료 1
docker exec sqemo-my mysql -uroot -ppw app -e "ALTER TABLE CUST DROP COLUMN EMAIL;"
npx sqemo-mcp lint "Online Shop Example.erd.json" --db "mysql://root:pw@localhost:13306/app"

# 5) 정리
docker rm -f sqemo-my
```

PostgreSQL을 시험하려면 `mysql:8` / `mysql://` URL을 `postgres:16` /
`postgresql://postgres:pw@localhost:15432/app`(포트 `-p 15432:5432`)으로 바꾸세요.
팁: `--dialect`를 데이터베이스에 맞추세요 — 다른 엔진용으로 내보낸 스키마는 그 엔진에
없는 타입을 쓸 수 있습니다.

## 데이터베이스 접속 정보는 어디에 두나요?

Sqemo는 저장하지 않습니다 — 실행 시점에 URL을 넘깁니다. ERD 파일과 버전 관리 밖에
두세요:

- **로컬, 가끔 실행:** 환경 변수나 `.gitignore`에 든 `.env` 파일. 비밀번호를 명령줄에
  직접 치는 것은 피하세요(셸 히스토리에 남습니다).
- **MCP 클라이언트(에이전트):** 클라이언트의 서버 설정에 `env` 값으로(예: Claude
  Desktop의 `claude_desktop_config.json`). 기기 안에 머뭅니다.
- **CI:** 플랫폼의 시크릿 저장소 — GitHub Actions Secrets, GitLab CI 변수 등. 워크플로
  파일에는 절대 넣지 마세요.

**강력 권장:** 도구에 **읽기 전용 데이터베이스 계정**을 주세요. `information_schema` /
카탈로그만 조회하므로 읽기 전용 계정으로 잃는 것이 없고 — 시크릿이 유출되더라도 피해
범위가 데이터가 아니라 스키마 구조로 한정됩니다.

## CI에 넣기 (GitHub Actions, 단계별)

드리프트 검사의 목적은 손으로 돌리는 것을 기억하는 대신 자동으로 — 푸시마다, PR마다 —
잡는 것입니다. GitHub Actions 경험이 없다고 가정하고 처음부터 전체 설정을 적습니다.

### 1. ERD를 저장소에 커밋

프로젝트를 내보내(**툴바 → 내보내기 → 프로젝트 다운로드**) `.erd.json`을 저장소에,
예를 들어 `erd/app.erd.json`에 두고 커밋·푸시합니다. 이 파일이 이제 스키마의
원본입니다 — 변경은 다른 코드처럼 PR 리뷰를 거칩니다.

### 2. 시크릿 추가

시크릿은 GitHub이 작업에 주입하는 암호화된 값으로, 코드나 로그에 나타나지 않습니다.
GitHub의 저장소에서:

**Settings → Secrets and variables → Actions → New repository secret.** 세 개를
추가합니다:

| 이름 | 값 |
|------|-------|
| `DATABASE_URL` | 접속 문자열, 예: `mysql://user:pass@host:3306/db` (**읽기 전용** 계정 권장) |
| `SQEMO_EMAIL` | Sqemo Pro 계정 이메일 |
| `SQEMO_PASSWORD` | 그 계정의 비밀번호 ([아직 없다면?](#googlegithub으로-가입했다면-ci용-비밀번호를-한-번-설정)) |

#### Google/GitHub으로 가입했다면? CI용 비밀번호를 한 번 설정

대화형 로그인은 브라우저를 쓸 수 있지만 CI 작업에는 브라우저가 없어 이메일과 비밀번호가
필요합니다. *Google로 계속* / *GitHub*만 눌러 왔다면 계정에 아직 비밀번호가 없습니다.
한 번 추가하세요. 소셜 로그인이 **없어지지 않습니다** — 들어가는 길이 하나 더 생길
뿐입니다:

1. **[app.sqemo.com](https://app.sqemo.com)** 을 열고 로그인 대화상자를 엽니다.
2. **비밀번호를 잊으셨나요? / 재설정**을 클릭합니다.
3. Google/GitHub 계정이 쓰는 **같은 이메일**을 입력하고 링크를 보냅니다.
4. 받은 편지함의 링크를 열어 비밀번호를 설정합니다.
5. 그 이메일과 비밀번호를 위의 두 시크릿으로 씁니다. 다른 곳에서는 여전히
   Google/GitHub으로 로그인할 수 있습니다(`npx sqemo-mcp login` 포함).

### 3. 워크플로 파일 추가

저장소에 **`.github/workflows/schema-drift.yml`** 을 이 내용으로 만듭니다:

```yaml
name: Schema drift
on:
  push:
    paths: ["erd/**"]          # ERD가 바뀔 때 실행
  pull_request:                # 그리고 모든 PR에서 — 드리프트가 병합을 막도록
jobs:
  drift:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "22"
      - run: npx sqemo-mcp lint erd/app.erd.json --db "$DATABASE_URL" --ignore "flyway_*"
        env:
          DATABASE_URL:   ${{ secrets.DATABASE_URL }}
          SQEMO_EMAIL:    ${{ secrets.SQEMO_EMAIL }}
          SQEMO_PASSWORD: ${{ secrets.SQEMO_PASSWORD }}
```

- `${{ secrets.NAME }}`이 2단계에서 추가한 값을 끌어옵니다 — 실제 자격 증명을 이 파일에
  붙여 넣지 마세요.
- `on:`이 실행 시점을 정합니다. 위 그대로면: 푸시에서 ERD가 바뀔 때, 그리고 모든 PR.
  `paths`를 바꾸거나 `branches`를 추가해 조정하세요.
- `SQEMO_EMAIL` / `SQEMO_PASSWORD`는 그 작업 동안만 로그인합니다 — `login` 단계나
  저장된 토큰이 필요 없습니다.

### 4. 푸시하면 실행됩니다

워크플로 파일을 커밋하고 푸시하세요. 이제부터 GitHub이 지정한 이벤트에서 검사를
자동으로 실행합니다 — **직접 트리거하지 않습니다.** `erd/` 아래를 바꿔 푸시하거나 PR을
열면 작업이 스스로 시작됩니다.

### 선택: CI에 데이터베이스 자격 증명 두지 않기

CI에 라이브 데이터베이스 URL을 주고 싶지 않다면, **네트워크 안의** 작업이 `pg_dump -s`를
실행하게 하고 덤프 파일과 비교하세요. `DATABASE_URL`이 없어지고 `--db`가 `--schema`가
됩니다:

```yaml
      - run: npx sqemo-mcp lint erd/app.erd.json --schema schema.sql --dialect postgres
        env:
          SQEMO_EMAIL:    ${{ secrets.SQEMO_EMAIL }}
          SQEMO_PASSWORD: ${{ secrets.SQEMO_PASSWORD }}
```

### 선택: 파일 대신 서버 ERD와 비교

`--erd <id>`는 Sqemo 계정에 저장된 ERD를 기준선으로 쓰므로 파일 커밋을 건너뜁니다. CI
계정에 그 ERD의 읽기 권한이 있어야 합니다.

```yaml
      - run: npx sqemo-mcp lint --erd <erd-id> --db "$DATABASE_URL"
```

알아 둘 트레이드오프: 커밋된 `.erd.json`은 **고정되고 리뷰됩니다** — PR로만 바뀌고,
옛 커밋은 자기 기준선으로 다시 검사됩니다. 서버 ERD는 **현재의, 변하는** 표준이라
누군가 앱에서 편집하면 코드 변경 없이 CI 결과가 바뀔 수 있습니다. 재현 가능한 PR
게이트에는 커밋된 파일이 안전한 기본값이고, 팀이 서버 ERD를 의도적으로 단일 라이브
표준으로 삼을 때 `--erd`를 쓰세요.

## 결과는 어디에 보이나요?

Sqemo가 아니라 **GitHub**에 보입니다. Sqemo는 CI 실행을 수집하거나 표시하지 않습니다 —
드리프트 검사는 `0`(통과) 또는 `1`(드리프트)로 끝나는 명령이고, GitHub이 다른 검사처럼
보고합니다:

- **PR**에서는 **상태 검사**로 나타납니다 — PR 옆의 초록 체크 또는 빨간 ✗. 검사를
  필수로 만들면(Settings → Branches → branch protection) 드리프트가 병합을 막습니다.
- **Actions** 탭에서 각 실행의 전체 로그가 정확히 무엇이 어긋났는지
  (`[missing_column] CUST.EMAIL`, …) 나열합니다.
- 관련된 실행이 실패하면 GitHub이 (알림 설정에 따라) 이메일을 보냅니다.

즉 흐름은: 푸시 → GitHub이 실행 → PR에서 빨강/초록, 상세는 Actions 로그. Sqemo 안에서
다시 확인할 것은 없습니다.

## 보안 요약

- 읽기 전용: `information_schema` / 카탈로그만 조회하고 연결은 읽기 전용으로 엽니다.
  도구는 데이터베이스에 절대 쓰지 않습니다.
- 데이터베이스 URL은 로컬(또는 CI) 프로세스만 쓰며 **Sqemo 서버로 전송되지 않습니다**.
- 읽기 전용 DB 계정을 쓰고, CI에 자격 증명을 아예 주고 싶지 않으면 `--schema` 덤프
  경로를 쓰세요.

---
Source: https://sqemo.com/ko/docs/live-database/ · Updated 2026-08-29
