Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions .github/workflows/schema-drift.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Schema drift PR gate (#373 v2)
# TS 상수 ↔ DB CHECK constraint 정합성을 PR 단계에서 검증
# 자세한 운영 가이드: docs/database/schema-drift-sot.md
name: Schema drift gate

on:
pull_request:
paths:
- "supabase/migrations/**"
- "packages/api-server/migration/**"
- "packages/web/lib/api/admin/**.ts"
- "scripts/check-schema-drift.ts"
- ".github/workflows/schema-drift.yml"
- "docs/database/schema-drift-sot.md"

permissions:
contents: read
pull-requests: write

jobs:
drift:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:17
env:
POSTGRES_PASSWORD: testpass
POSTGRES_DB: drift
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
LOCAL_DATABASE_URL: postgresql://postgres:testpass@localhost:5432/drift
steps:
- uses: actions/checkout@v6

- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.10"

- name: Install postgresql-client 17
run: |
set -euo pipefail
sudo apt-get update -qq
sudo apt-get install -y curl ca-certificates lsb-release gnupg
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc \
| sudo gpg --dearmor -o /usr/share/keyrings/postgresql.gpg
echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" \
| sudo tee /etc/apt/sources.list.d/pgdg.list
sudo apt-get update -qq
sudo apt-get install -y postgresql-client-17
psql --version

- name: Install dependencies
run: bun install --frozen-lockfile

- name: Run schema drift check
id: drift
# drift-bypass label → step failure를 무시하여 job green 유지
# 단, drift report 는 항상 PR comment 로 게시
continue-on-error: ${{ contains(github.event.pull_request.labels.*.name, 'drift-bypass') }}
run: bun run scripts/check-schema-drift.ts | tee /tmp/drift.md

- name: Comment PR with drift report
if: always() && hashFiles('/tmp/drift.md') != ''
uses: marocchino/sticky-pull-request-comment@v2
with:
header: schema-drift
path: /tmp/drift.md
15 changes: 11 additions & 4 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 9 additions & 3 deletions docs/database/drift-check.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@
title: DB drift check (nightly)
owner: human
status: approved
updated: 2026-04-30
updated: 2026-05-28
tags: [db, ops]
related:
- docs/database/operating-model.md
- docs/database/schema-drift-sot.md
- .github/workflows/db-drift-check.yml
- .github/workflows/schema-drift.yml
- scripts/check-db-drift.sh
- scripts/check-schema-drift.ts
---

# DB drift check (nightly)
# DB drift check

PRD ↔ `supabase/migrations` 정합성을 매일 자동 검증한다 (#373).

## 동작
본 문서는 **v1 nightly** 채널을 설명한다. PR 단계 TS ↔ DB CHECK constraint
검증(**v2 PR gate**, 2026-05 landed)은 `docs/database/schema-drift-sot.md` 참조.

## v1 nightly 동작

1. `.github/workflows/db-drift-check.yml` cron — 매일 04:00 KST (UTC 19:00). 수동 실행은 GitHub Actions UI 의 "DB drift check" → Run workflow.
2. `pg_dump --schema-only` PRD → `/tmp/drift-prd.sql`
Expand Down
69 changes: 69 additions & 0 deletions docs/database/schema-drift-sot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: Schema drift SOT mapping
owner: human
status: approved
updated: 2026-05-28
tags: [db, ops, ci]
related:
- .github/workflows/schema-drift.yml
- scripts/check-schema-drift.ts
- docs/database/drift-check.md
---

# Schema drift SOT mapping (#373 v2)

본 문서는 **TypeScript 상수 ↔ Postgres CHECK constraint** 매핑을 정의하는
SSOT(Single Source Of Truth)이다. `.github/workflows/schema-drift.yml` (PR gate)
가 `scripts/check-schema-drift.ts` 를 실행할 때 본 표의 entry 를 기준으로
양쪽이 set-equal 한지 검증한다.

## 등록된 SOT

| # | TS 파일 / 상수 | DB 테이블 / 컬럼 / 제약 |
|---|---|---|
| 1 | `packages/web/lib/api/admin/magazines.ts` / `MAGAZINE_STATUSES` | `public.post_magazines.status` / `post_magazines_status_check` |

> 매핑 본체는 `scripts/check-schema-drift.ts` 의 `SOT_MAPPINGS` 배열이다.
> 본 표는 사람이 한눈에 보기 위한 사본 — **두 곳을 함께 갱신**한다.

## 등록 규칙

- TS 상수는 `export const X = [...] as const` 패턴이어야 한다 (script 의 AST
추출은 이 패턴만 지원).
- DB CHECK constraint 는 `pg_get_constraintdef` 결과가 다음 중 하나여야 한다:
- `CHECK ((col)::text = ANY ((ARRAY['a'::text, 'b'::text])::text[]))`
- `CHECK (col = ANY (ARRAY['a'::text, ...]))`
- `CHECK (col IN ('a','b','c'))`
- 신규 SOT 추가 시:
1. 본 표에 row 추가
2. `scripts/check-schema-drift.ts` 의 `SOT_MAPPINGS` 에 entry 추가
3. PR 자체 workflow run 으로 자기 자신을 검증

## 알려진 미커버 항목 (v3 후속)

| 항목 | 사유 | 후속 |
|---|---|---|
| `public.posts.status` (TS `POST_STATUSES`) | DB 측에 CHECK constraint 가 없음 (`character varying(20)` + default 'active' 만). | 별도 issue — CHECK 추가 마이그레이션 후 본 표 등록 |
| generated types ↔ DB | `packages/web/lib/api/generated/` 는 OpenAPI 산출물이라 별도 drift 채널 필요. | v3 후속 issue 권장 |
| `warehouse.*` / `auth.*` schema | v2 는 `public` 만 검증. | 필요 시 별도 mapping 추가 |

## drift 발견 시

PR comment 에 sticky 한 `schema-drift` block 으로 결과가 갱신된다:

- **OK**: drift 없음 — PR check green
- **DRIFT**: TS / DB set 차이를 표로 표기 — PR check red
- **PARSE\_FAIL**: constraint 정의를 정규식으로 못 읽음 — raw `pg_get_constraintdef`
출력을 그대로 보여줌 (script bug 가능, 즉시 maintainer 확인)

## 의도적 우회

`drift-bypass` label 을 PR 에 붙이면 step 이 `continue-on-error` 로 전환되어
job 은 green 이 되지만 drift report 는 그대로 PR comment 에 남는다. branch
protection rule 은 별도 설정 — 본 workflow 만으로 머지 차단은 보장되지 않는다.

## 관련

- nightly v1: `.github/workflows/db-drift-check.yml` (PRD ↔ supabase/migrations, 유지)
- #372 trigger 사례: MAGAZINE\_STATUSES vs `post_magazines_status_check` drift
- 운영 모델: `docs/database/operating-model.md`
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@types/react-dom": "^19.2.0",
"ajv": "^8.18.0",
"gray-matter": "^4.0.3",
"ts-morph": "^24.0.0",
"turbo": "^2.9.3"
},
"overrides": {
Expand Down
Loading
Loading