# ADR-0003: Snapshot baseline 戦略 (pre-launch 期は migration を持たない)

- **Status:** Accepted
- **Date:** 2026-04-29 (確定) / 2026-04-30 (ADR 化)
- **Decision Drivers:** 1 人開発・スキーマ変更頻度高・dev-only 運用 (prod 未稼働)、migration ファイルの陳腐化、Flutter リリース 2026-06-30 までは後方互換不要、CI で drift を機械検知できる体制
- **Stakeholders:** dev@parky.co.jp (sole maintainer)

## Context

### 出発点

Parky は 2026-03 末に開発開始し、Flutter リリース予定が 2026-06-30。pre-launch 期 (〜2026-06-30) は **後方互換を考慮する必要がない** (memory: project_parky_release_phase) ため、データ移行を伴う migration を書く意味がない。

それでも従来は migration ファイル (`infra/supabase/migrations/NNN_*.sql`) を書いていたが、以下の問題が発生していた:

1. **migration の陳腐化**: schema を 5 回修正すると 5 つの migration ファイルができ、最終形を見るには全部追わないといけない
2. **「現状の schema」の SSoT が曖昧**: dev DB / migrations / 手元の TS 型 のどれが真実か分からない
3. **destructive な変更の連鎖**: 1 日のうちに「ADD COLUMN → RENAME COLUMN → DROP COLUMN」のような連鎖が発生し、migration ファイルが醜くなる
4. **migration 適用順序の問題**: ファイル名先頭の番号 / 日付の管理が手動で、衝突が起きる

リリース後は通常の migration 運用に戻すが、それまでは **「dev DB の現状 = SSoT」** という割り切った運用にしたい。

### 制約

- 後方互換不要 (リリース前なので顧客が居ない)
- ただし dev DB が消えても再現できる必要がある (チーム外の検証環境 / ephemeral PG / CI test 環境)
- スキーマの変更履歴は git history で追えれば十分 (migration ファイルとして個別に残す必要なし)
- CI で「dev DB の現状」と「committed baseline」が drift していないことを検知できる必要がある

### Supabase Branching の検討と不採用

2026-04-30 に Supabase Branching を検討したが採用見送り (memory: project_parky_supabase_environments)。理由:

- 別プロジェクト構成 (`parky` / `parkydev`) のほうが Auth / Storage / Edge Functions まで完全分離できる
- Branching は DB のみで Auth users / Storage / Edge は branch コピー不可
- 運用複雑度 (ephemeral 管理 / GitHub App 連携 / branch URL 抽出 CI) が高い
- PR ephemeral DB の利点「PR 単位の migration drift 検出」は、本 ADR の baseline-drift 戦略で等価カバー済み

## Decision

### 戦略

pre-launch 期は migration ファイルを書かず、以下の運用にする:

1. **dev DB に直接変更を apply**
   - DDL 系: `mcp__supabase__apply_migration` で SQL を直接流す
   - データ整形・REFRESH MV・one-shot SQL: `mcp__supabase__execute_sql` で流す
   - 詳細: memory `tooling/feedback_apply_migrations_directly.md`

2. **`infra/supabase/baseline/` を SSoT として維持**
   - schema 単位 split (`public/`, `admin/`, `marketing/`, `analytics/`, `bff_only/`, `auth_helpers/`, `infra/`, `90_constraints/`)
   - 各 schema 配下に table 単位 SQL ファイル
   - dev DB 変更後、必ず `bash scripts/db/refresh-baseline.sh` で baseline を再生成
   - 内部処理: `gh workflow run oneshot-dump-baseline.yml --ref dev` → 完了待機 → artifact download → `infra/supabase/baseline/` 置換

3. **アプリ側コード変更と同じ PR で baseline を commit**
   - schema 変更 → 単独 PR ではなく、利用側 (data 層 / OAS / FE) と一緒に
   - data 層・型・API・OAS・Docs・FE の 6 点セットを同 PR で揃える (memory: feedback_parky_datamodel_change_flow)

4. **CI で drift を機械検知**
   - `.github/workflows/baseline-drift.yml` が daily + workflow_dispatch + PR で起動
   - dev DB を pg_dump → `scripts/db/split-baseline.mjs` で同じ split 構造を生成
   - committed baseline との `git diff` で差分があれば fail
   - 加えて `api-rls-tests` / `api-integration-tests` が baseline を fresh PG に apply し、RLS smoke / data 層 shape を検証

### 禁止事項

- `infra/supabase/baseline/` 配下のファイルを手編集する (生成物のため)。例外は `00_preamble.sql` の role / extension preamble のみ
- アプリコードを先に commit、baseline を後追い commit する (CI test が壊れる)
- baseline 変更だけ commit して dev DB を更新しない (drift 発生)
- prod 環境 (まだ稼働していないが) に migration を apply するときは memory `workflow/feedback_no_prod_migration_yet` に従い明示許可必須

### スクリプト構成

- `scripts/db/apply-baseline.sh`: 12 step の apply 順序で baseline を fresh DB に展開 (CI test / 別マシン再現用)
- `scripts/db/refresh-baseline.sh`: dev DB → baseline 再生成 (開発時の定期作業)
- `scripts/db/split-baseline.mjs`: pg_dump 出力を schema/table 単位に振り分け
- `.github/workflows/oneshot-dump-baseline.yml`: dev DB を pg_dump して artifact 化
- `.github/workflows/baseline-drift.yml`: drift 検知 CI

## Consequences

### Positive

- schema の最終形が常に baseline ファイル群として可読 (migration を遡る必要なし)
- dev DB の変更速度が migration 書く時間にブロックされない
- baseline は schema/table 単位で split されているため、変更レビューが「どの table に何が起きたか」一目で分かる
- CI が drift を機械検知するので、baseline の更新忘れが PR で必ず止まる
- fresh PG (CI / 別マシン) に baseline を apply するだけで現状再現できる
- dev / prod 別プロジェクト構成と組み合わせて、Auth / Storage まで含めた環境完全分離が成立

### Negative / Trade-offs

- リリース後は migration 運用に切り替える必要があり、二段階の運用知識が必要
- 「ある時点の schema」を後から再構築する場合、git の commit 履歴を遡る必要がある (migration ファイルなら apply 順を追える)
- pre-launch 期に 1 度だけ destructive な変更を入れて後悔する場合、git revert + dev DB を手動戻し が必要
- `scripts/db/refresh-baseline.sh` の実行を忘れると CI が落ちる (機械強制があるので致命的ではないが、PR で気付く)

### Mitigations

- `api/CLAUDE.md` / `parky/CLAUDE.md` (project root) に手順を明文化
- baseline-drift.yml が daily で動くため、手動 refresh 忘れは 24 時間以内に検知される
- `infra/supabase/baseline/00_preamble.sql` のみ手編集可とする例外を明示
- リリース後の migration 運用切替は、本 ADR を Deprecate して後継 ADR を立てる
- 段階的に切り替える場合、`infra/supabase/migrations/` ディレクトリは既に存在するので両立期は併用可能

## Alternatives Considered

- **Alternative A: 通常の migration ファイル方式**
  - 不採用理由: pre-launch 期は schema 変更頻度が高く、最終形を追うのにコストがかかる。後方互換不要なので migration の唯一のメリット (順序付き適用) が無価値

- **Alternative B: Supabase Branching (PR ごとに ephemeral DB)**
  - 不採用理由: 2026-04-30 に検討。Auth / Storage / Edge Functions まで完全分離できないため、別プロジェクト構成のほうが優位。drift 検出の利点は本戦略で等価カバー (memory: project_parky_supabase_environments)

- **Alternative C: prisma migrate / drizzle-kit / atlas**
  - 不採用理由: ORM 不採用 ([ADR-0002](./0002-postgres-js-raw-sql-hybrid.md)) と整合しない。複雑クエリ / RPC / RLS / pg_cron / pg_net 等 Postgres 固有機能の DSL 化が困難

- **Alternative D: 単一 init.sql (split しない)**
  - 不採用理由: 単一ファイルは 5,000 行を超えるとレビュー困難。schema/table 単位 split のほうが diff レビューがしやすい

- **Alternative E: dump バイナリ (pg_dump -Fc) を git に commit**
  - 不採用理由: バイナリは diff レビュー不可、git LFS 必須でコスト増。テキスト SQL のほうが履歴も追える

## References

- 関連 memory:
  - `C:/Users/Taiga/.claude/projects/e--Claude/memory/parky/project_parky_supabase_environments.md` (Branching 不採用 / 別プロジェクト構成)
  - `C:/Users/Taiga/.claude/projects/e--Claude/memory/tooling/feedback_apply_migrations_directly.md` (MCP で直接 apply するルール)
  - `C:/Users/Taiga/.claude/projects/e--Claude/memory/parky/project_parky_release_phase.md` (pre-launch 期は後方互換不要)
  - `C:/Users/Taiga/.claude/projects/e--Claude/memory/parky/feedback_parky_datamodel_change_flow.md` (6 点セット同期)
  - `C:/Users/Taiga/.claude/projects/e--Claude/memory/workflow/feedback_no_prod_migration_yet.md` (prod は明示許可まで保留)
- 関連 code:
  - `e:/Claude/high-field/parky/infra/supabase/baseline/` (SSoT)
    - `00_preamble.sql` / `01_schemas.sql` / `99_grants.sql`
    - `public/` / `admin/` / `marketing/` / `analytics/` / `bff_only/` / `auth_helpers/` / `infra/` / `90_constraints/`
  - `e:/Claude/high-field/parky/scripts/db/apply-baseline.sh`
  - `e:/Claude/high-field/parky/scripts/db/refresh-baseline.sh`
  - `e:/Claude/high-field/parky/scripts/db/split-baseline.mjs`
  - `e:/Claude/high-field/parky/.github/workflows/baseline-drift.yml`
  - `e:/Claude/high-field/parky/.github/workflows/oneshot-dump-baseline.yml`
- 関連 docs:
  - `../../CLAUDE.md` § DB スキーマ変更フロー (snapshot 戦略)
  - `../db/` (DB 概要)

## Revisit Triggers

- Flutter リリース (2026-06-30) 後、本番ユーザーが乗った時点
  - 後方互換が必要になる → 通常の migration 運用 (sequential file + 一方向適用) に戻す
  - 本 ADR を `Deprecated` 化し、後継 ADR を起票
- 複数開発者が同時に schema を触るようになった時 (PR ごとの conflict が増えるなら branching 再考)
- baseline-drift.yml の実行時間が長くなって CI コストを圧迫した時
- Supabase Branching の Auth / Storage 対応が公式に揃った時 (再評価のトリガ)
