Skip to content

fix(api): add missing 0018 migration for onboarding & pages.kind#755

Merged
otomatty merged 2 commits into
developfrom
fix/missing-onboarding-migration
Apr 26, 2026
Merged

fix(api): add missing 0018 migration for onboarding & pages.kind#755
otomatty merged 2 commits into
developfrom
fix/missing-onboarding-migration

Conversation

@otomatty
Copy link
Copy Markdown
Owner

@otomatty otomatty commented Apr 26, 2026

概要

#728 でマージされた welcome page 関連スキーマ変更(user_onboarding_status テーブルと pages.kind カラム)に対応する Drizzle マイグレーションが生成されていなかったため、本番および開発 DB が TS スキーマに追いつかず、/api/onboarding/status/api/pages が 500 を返していた。

Railway 本番ログ:

```
relation "user_onboarding_status" does not exist (42P01)
column "kind" of relation "pages" does not exist (42703)
```

CI (.github/workflows/deploy-{dev,prod}.yml) は bunx drizzle-kit migrate のみを実行するため、PR #728 で追加された db/migrations/005_add_onboarding_and_page_kind.sql(drizzle-kit が見ないパス)は永久に適用されない状態だった。

変更点

不足マイグレーションの追加(即時の 500 解消)

  • `server/api/drizzle/0018_add_onboarding_and_page_kind.sql` を追加。
    • `pages.kind` カラム + CHECK 制約(`user` / `welcome` / `update_notice`)
    • `idx_pages_owner_kind` インデックス
    • `idx_pages_unique_welcome_per_owner`(オーナーあたり welcome ページを 1 件に制限する部分ユニーク index。`welcomePageService.onConflictDoNothing` のターゲット)
    • `user_onboarding_status` テーブル + FK + CHECK
    • `idx_user_onboarding_status_needs_welcome` 部分インデックス
    • 既存ユーザーへのバックフィル(`setup_completed_at = NOW()` を入れて再ウィザード化を防ぐ)
  • `server/api/drizzle/meta/_journal.json` に対応エントリを追記。
  • `server/api/src/schema/pages.ts` に `idx_pages_unique_welcome_per_owner` を `uniqueIndex` として追記し、TS スキーマと SQL の記述を揃えた(実 DDL は SQL 側)。
  • `db/migrations/` ディレクトリは CI から参照されておらず再発の温床なので丸ごと削除(README からも参照を除去し、`server/api/drizzle/` を正本として明示)。

再発防止

  • `scripts/check-drizzle-migrations.mjs` を新規追加。`server/api/src/schema/**/.ts` の変更があるのに `server/api/drizzle/NNNN_.sql` の追加と `_journal.json` の更新がない PR を検出する。
  • `.github/workflows/ci.yml` に `drizzle-migration-check` ジョブを追加(PR 限定、ベース branch との diff を見る)。コメント / JSDoc 修正など SQL 不要な変更は `[skip drizzle-check]` で opt-out 可能。
  • `AGENTS.md` / `CLAUDE.md` に「TS スキーマと SQL マイグレーションは常に対で更新する」「正本は `server/api/drizzle/` のみ」「develop → dev DB / main → prod DB の自動適用パイプライン」のルールを追記。

変更の種類

  • 🐛 バグ修正 (Bug fix)
  • 🔧 ビルド/CI (Build/CI)
  • 📝 ドキュメント (Documentation)

環境別の自動適用について

ご質問の「develop にマージしたら development 環境、main にマージしたら production 環境にマイグレーションを適用したい」は、すでに `deploy-{dev,prod}.yml` の `migrate` ジョブが実装済みです。今回 #728 で適用されなかったのは、TS スキーマだけ変更して SQL を別ディレクトリに置いたために `drizzle-kit migrate` が「適用すべきものなし」と判断したためで、本 PR の `drizzle-migration-check` ジョブで再発を防ぎます。

テスト方法

マイグレーション検証

  1. develop にマージ → `Deploy Development` ワークフローの `migrate` ジョブで `bunx drizzle-kit migrate` が走り、dev DB に 0018 が適用される。
  2. dev API にアクセスし、`GET /api/onboarding/status` が 200 / `POST /api/pages` が 201 を返すこと、Railway logs に `relation "user_onboarding_status" does not exist` / `column "kind" of relation "pages" does not exist` が出ないことを確認。
  3. main へ release PR をマージ後、`Deploy Production` ワークフローで同様に prod DB へ適用される。

CI ガード検証

  • `scripts/check-drizzle-migrations.mjs` をローカルでも実行可能(`DRIZZLE_DIFF_BASE` で比較ベースを変更可)。本 PR ではスキーマ変更 + 0018 マイグレーション + journal 更新が揃っているため OK 判定。

チェックリスト

  • テストがすべてパスする(既存の 3 件の失敗は本 PR と無関係 / develop でも同じ失敗を確認済み)
  • Lint エラーがない
  • 必要に応じてドキュメントを更新した(README / AGENTS.md / CLAUDE.md)
  • コミットメッセージが Conventional Commits に従っている

関連

Made with Cursor


Open in Devin Review

Summary by CodeRabbit

  • New Features

    • Added DB support for user onboarding status (timestamps, locale) and page kinds (user, welcome, update notice), including constraint to ensure a single active welcome page per owner
  • Chores

    • CI now enforces DB schema-to-migration consistency for non-draft PRs
    • Removed obsolete legacy migration artifacts
  • Documentation

    • Updated migration guidance and clarified the canonical migrations directory and workflow enforcement

PR #728 added the userOnboardingStatus table and the pages.kind column to
the Drizzle TS schema but never produced a matching migration under
server/api/drizzle/. CI runs only `bunx drizzle-kit migrate`, so the legacy
SQL placed in db/migrations/005_*.sql was never applied to either dev or
prod, leaving production with `relation "user_onboarding_status" does not
exist` and `column "kind" of relation "pages" does not exist` (500 on
GET /api/onboarding/status and POST /api/pages).

This commit:

- Adds server/api/drizzle/0018_add_onboarding_and_page_kind.sql with the
  pages.kind column + CHECK, the partial unique index used by
  welcomePageService.onConflictDoNothing, the user_onboarding_status table,
  the retry-scan partial index, and a backfill that marks existing users as
  setup-complete so they are not pushed back through the wizard.
- Mirrors the partial unique index idx_pages_unique_welcome_per_owner in
  the TS schema for documentation parity.
- Removes the legacy db/migrations/ directory entirely; CI never touched
  it and leaving it around invites the same regression. README is updated
  to point at server/api/drizzle/ as the single source of truth.

Re-fix-prevention:

- New CI job drizzle-migration-check (PR-only) runs
  scripts/check-drizzle-migrations.mjs, which fails when a PR modifies any
  server/api/src/schema/**/*.ts file without adding a matching
  server/api/drizzle/NNNN_*.sql and updating _journal.json. PRs that truly
  do not need a DB migration can opt out with [skip drizzle-check].
- AGENTS.md / CLAUDE.md document the schema/migration pairing rule and the
  develop->dev / main->prod auto-apply pipeline.

Made-with: Cursor
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 26, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bfc7e035-5355-41cb-adea-d747ec807cb6

📥 Commits

Reviewing files that changed from the base of the PR and between 240d18d and 8d79efe.

📒 Files selected for processing (1)
  • scripts/check-drizzle-migrations.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/check-drizzle-migrations.mjs

📝 Walkthrough

Walkthrough

Adds a CI job and Node CLI to enforce that TypeScript Drizzle schema edits are paired with new SQL migrations and journal updates; moves documented migration path to server/api/drizzle/; removes legacy db/migrations/* files; and adds a new Drizzle migration + schema change for onboarding and page kind.

Changes

Cohort / File(s) Summary
CI & Enforcement
\.github/workflows/ci.yml, scripts/check-drizzle-migrations.mjs
Introduces drizzle-migration-check GitHub Actions job that checks PR context and runs scripts/check-drizzle-migrations.mjs to validate schema (.ts) edits under server/api/src/schema/ have added migration .sql files in server/api/drizzle/ and updates to server/api/drizzle/meta/_journal.json; supports skip marker.
Documentation
AGENTS.md, CLAUDE.md, README.md
Adds a "DB schema changes" / "DB スキーマ変更" section documenting migration conventions, CI enforcement, skip-marker usage, and updates migration directory reference from db/migrations to server/api/drizzle/.
Removed legacy migrations
db/migrations/001_add_notes_tables.sql, db/migrations/002_add_page_snapshots.sql, db/migrations/003_add_invitation_tokens.sql, db/migrations/004_add_invitation_locale_tracking.sql, db/migrations/005_add_onboarding_and_page_kind.sql
Deletes multiple legacy SQL migration files (notes tables, page snapshots, invitations, onboarding/page-kind) from db/migrations/.
New migration & journal
server/api/drizzle/0018_add_onboarding_and_page_kind.sql, server/api/drizzle/meta/_journal.json
Adds migration 0018_add_onboarding_and_page_kind.sql that creates pages.kind, indexes, user_onboarding_status table, partial indexes, and a backfill; records entry in Drizzle _journal.json.
Schema update
server/api/src/schema/pages.ts
Updates schema to import and use uniqueIndex and defines a partial unique index enforcing one non-deleted welcome page per owner (aligns schema with new migration).

Sequence Diagram(s)

sequenceDiagram
  participant GH as GitHub Actions (ci.yml)
  participant Repo as Git Repo
  participant Script as check-drizzle-migrations.mjs
  participant PR as Pull Request (title/body/commits)

  GH->>Repo: checkout (fetch-depth:0)
  GH->>PR: read PR_TITLE, PR_BODY, PR base/branch
  GH->>Script: run node scripts/check-drizzle-migrations.mjs with env
  Script->>Repo: git diff (base..HEAD) -> changed/added paths
  Script->>Script: detect schema .ts changes under server/api/src/schema/
  alt schema changes found
    Script->>Repo: check for added server/api/drizzle/*.sql (excluding /meta/)
    Script->>Repo: check meta/_journal.json modified
    alt migrations & journal present
      Script->>GH: exit 0 (OK)
    else skip marker present in commits/title/body
      Script->>GH: exit 0 (skipping)
    else
      Script->>GH: exit 1 (FAIL with remediation message)
    end
  else no schema changes
    Script->>GH: exit 0 (no-op)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰✨ I dug a tunnel through the CI,
Found schema hops and migration sky—
I nibbled checks, updated the log,
Now Drizzle hops in tidy cog. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(api): add missing 0018 migration for onboarding & pages.kind' directly and accurately summarizes the main change: adding the missing Drizzle SQL migration file (0018) that pairs with the TypeScript schema updates for onboarding and the pages.kind feature.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/missing-onboarding-migration

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request formalizes the database migration workflow by consolidating migrations into server/api/drizzle/ and introducing a validation script, scripts/check-drizzle-migrations.mjs, to ensure TypeScript schema changes are always accompanied by SQL migrations. Documentation in AGENTS.md, CLAUDE.md, and README.md has been updated to reflect these requirements. Feedback was provided regarding the validation script's potential to silently skip checks in CI environments due to shallow clones, which could lead to undetected schema inconsistencies.

Comment on lines +150 to +155
if (!ensureBaseExists(base)) {
console.log(
`[check-drizzle-migrations] base ref "${base}" not found; skipping check (most likely running outside PR context).`,
);
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

GitHub Actions のデフォルト設定(shallow clone)では origin/develop などのリモートブランチが取得されないため、ensureBaseExistsfalse を返し、マイグレーションのチェックが静かにスキップされる可能性があります。これにより、スキーマ不整合がある PR を誤ってパスさせてしまうリスクがあります。ワークフロー側で fetch-depth: 0 を設定するか、ベースブランチが見つからない場合にエラーを出す、あるいは警告をより目立たせるなどの対応を検討してください。

@otomatty otomatty self-assigned this Apr 26, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 240d18d82c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/check-drizzle-migrations.mjs Outdated
* @returns {string[]}
*/
function changedPaths(base) {
const out = git(["diff", "--name-only", "--diff-filter=AMR", `${base}...HEAD`]);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Detect deleted schema files in migration check

Use a diff filter that includes deletions when collecting schema changes. The current git diff --name-only --diff-filter=AMR ignores D, so removing a file under server/api/src/schema/** (for example, dropping a table schema module) will not trigger this guard and CI can pass without adding a migration/journal update, reintroducing the exact schema-drift failure this check is meant to prevent.

Useful? React with 👍 / 👎.

devin-ai-integration[bot]

This comment was marked as resolved.

coderabbitai[bot]

This comment was marked as resolved.

Tighten the Drizzle migration consistency checker by detecting deleted schema files, honoring the documented types/ exclusion, failing fast in CI when the diff base is unavailable, and aligning JSDoc with the required SQL-plus-journal policy.

Made-with: Cursor
@otomatty otomatty merged commit 8124251 into develop Apr 26, 2026
17 checks passed
@otomatty otomatty deleted the fix/missing-onboarding-migration branch April 26, 2026 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant