Skip to content
Merged

main #316

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
9de0494
fix(deps): update react monorepo to v19.2.5
renovate[bot] Apr 11, 2026
985a914
docs: Convexマイグレーションルールを追加
yn1323 Apr 11, 2026
6970634
design: 店舗設定編集の画面追加(ShopInfoBar + EditShopModal/Sheet)
yn1323 Apr 11, 2026
019a584
feat: Convex マイグレーション基盤を導入
yn1323 Apr 11, 2026
699fc5e
ci: develop/release の Convex デプロイ後にマイグレーションを自動実行
yn1323 Apr 11, 2026
dccfe94
docs: 店舗設定変更とマイグレーション基盤導入の実装計画を追加
yn1323 Apr 11, 2026
0483e13
chore: migration 実行用の npm scripts を追加
yn1323 Apr 11, 2026
5a36502
feat: 店舗設定変更(店舗名・シフト時間帯)を追加
yn1323 Apr 11, 2026
817c4ef
docs: TODO[narrow] コメント運用ルールを Convex 規約に追加
yn1323 Apr 11, 2026
dd554b3
design: ダッシュボード文言と LP 配色を微調整
yn1323 Apr 11, 2026
c1b61bb
Merge pull request #303 from yn1323/renovate/react-monorepo
yn1323 Apr 11, 2026
4b2a28d
Merge branch 'develop' of github.com:yn1323/yps-crispy-carnival into …
yn1323 Apr 11, 2026
7eb7391
chore(deps): update dependency @biomejs/biome to v2.4.11
renovate[bot] Apr 11, 2026
2224e10
Merge pull request #313 from yn1323/feat/0411-2
yn1323 Apr 11, 2026
fc8b3e1
Merge pull request #304 from yn1323/renovate/biomejs-biome-2.x
yn1323 Apr 11, 2026
e8631f6
fix(deps): update dependency convex to v1.35.1
renovate[bot] Apr 12, 2026
45ccd3e
Merge pull request #305 from yn1323/renovate/convex-1.x
yn1323 Apr 12, 2026
3745890
feat: ダッシュボード改善 / SEO・GTM整備 / UI改善 (#315)
yn1323 Apr 12, 2026
ffc380d
Merge branch 'main' into develop
yn1323 Apr 12, 2026
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
6 changes: 4 additions & 2 deletions .github/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,10 @@ CI/CDパイプラインの構成と運用ルール。

## デプロイ順序

Convex → ビルド → CloudFlare の順で実行する。
- Convexを先にデプロイすることで、スキーマ変更がビルド時に反映される
Convex deploy → Convex migrations → ビルド → CloudFlare の順で実行する。
- Convex を先にデプロイすることで、スキーマ変更がビルド時に反映される
- `convex deploy` 直後に `npx convex run migrations/index:run` を実行し、データのバックフィルを完了させてからビルドに進む(develop / release のみ、preview は実行しない)
- マイグレーションは `@convex-dev/migrations` で冪等に管理されるため、変更のない PR でも毎回走る(完了済みはスキップされる)
- ビルド時に `VITE_CONVEX_URL` を環境変数として埋め込む

## 注意事項
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ jobs:
run: npx convex deploy
env:
CONVEX_DEPLOY_KEY: ${{ secrets.CONVEX_DEPLOY_KEY }}
- name: Run Convex migrations
run: npx convex run migrations/index:run
env:
CONVEX_DEPLOY_KEY: ${{ secrets.CONVEX_DEPLOY_KEY }}
- name: Build
run: pnpm build
env:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ jobs:
id: playwright
run: pnpm e2e
env:
TZ: Asia/Tokyo
VITE_CONVEX_URL: ${{ steps.preview.outputs.PREVIEW_URL }}
CONVEX_PREVIEW_NAME: ${{ env.CONVEX_PREVIEW_NAME }}
E2E_CLERK_USER: ${{ vars.E2E_CLERK_USER }}
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ jobs:
env:
CONVEX_DEPLOY_KEY: ${{ secrets.CONVEX_DEPLOY_KEY }}

- name: Run Convex migrations
run: npx convex run migrations/index:run
env:
CONVEX_DEPLOY_KEY: ${{ secrets.CONVEX_DEPLOY_KEY }}

- name: Build
run: pnpm build
env:
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pnpm e2e e2e/path/to/file.spec.ts # 特定E2Eファイル

- 実装完了後、SubAgentで`pnpm lint`, `pnpm type-check`, `pnpm test` を実行すること(Context消費したくない)
- `lint`はwarningでも修正すること
- 次に`/review`を実行して、レビュー結果を要修正、不要で分けて提示してください。
- 上記完了後、SubAgentで`/simplify`を実行してリファクタを行うこと(Context消費したくない)

### フロントエンド(UIあり)
Expand Down
112 changes: 112 additions & 0 deletions convex/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,118 @@ query の返り値はドキュメントをそのまま返さず、必要なフ
- [ ] エラーメッセージから内部情報が漏れないことを確認
- [x] レートリミットを Magic Link 検証に適用

## スキーマ変更とマイグレーション

**前提**: 本番運用中のため、スキーマ変更は既存ドキュメントを壊さないことを最優先する。

### 基本ルール

- **フィールド追加は `v.optional()` から始める** — 既存ドキュメントをそのまま通す
- **破壊的変更は Widen → Migrate → Narrow の3ステップで進める**
1. Widen: 新旧両形式を受け入れるスキーマ(`v.union` / `v.optional`)にデプロイ
2. Migrate: internal mutation で既存ドキュメントを新形式に書き換え
3. Narrow: 新形式のみのスキーマにデプロイ
- **フィールド削除・リネーム・型変更は一発でやらない** — 必ず上記3ステップに分解
- **論理削除(`isDeleted`)の方針は維持** — 物理削除はしない

### バッチ書き換えが必要なとき

`@convex-dev/migrations` コンポーネントを使う(導入済み)。詳細は下記「マイグレーション基盤」を参照。

### マイグレーション基盤(`@convex-dev/migrations`)

**構成**: 1ファイル1マイグレーション方式

```
convex/
convex.config.ts # migrations コンポーネント登録
migrations/
index.ts # Migrations インスタンス + CI/CLI エントリ `run`
m001_{テーブル名}_{操作内容}.ts # 個別マイグレーション(後続PRで追加)
```

**命名規則**: `m{3桁連番}_{snake_case}.ts`
- 先頭 `m` は Convex のファイル名規則(先頭数字不可)を回避するため
- 連番は `001` から。欠番・再採番はしない
- 機能名は対象テーブルを先頭に置く(例: `m001_recruitments_add_shift_times.ts`)

**新しいマイグレーションの追加手順**:
1. `convex/migrations/m{次の連番}_{名前}.ts` を作成し、以下のように書く:
```ts
import { migrations } from "./index";

export const migration = migrations.define({
table: "targetTable",
migrateOne: async (ctx, doc) => {
if (doc.newField !== undefined) return; // 冪等チェック必須
await ctx.db.patch(doc._id, { newField: "default" });
},
});
```
2. `convex/migrations/index.ts` の `run` を以下の形に書き換える(または既に `runner([...])` になっていれば配列に追加):
```ts
import { internal } from "../_generated/api";
export const run = migrations.runner([
internal.migrations.m001_xxx.migration,
internal.migrations.m002_yyy.migration, // 新しいものを末尾に追加
]);
```
3. `pnpm convex:dev` で `_generated` が更新されることを確認
4. PR にマージ → CI が `deploy-develop` で `convex deploy` → `migrations/index:run` を自動実行
5. `release:*` ラベル付き PR を main マージ → 本番にも自動適用

**手動実行**(ローカル dev 等):
- 全実行: `pnpm convex:migrate`(= `npx convex run migrations/index:run`)
- 進捗確認: `pnpm convex:migrate:status`(= `npx convex run --component migrations lib:getStatus --watch`)
- 特定マイグレーション単発: `npx convex run migrations/index:run '{"fn": "migrations/m001_xxx:migration"}'`
- キャンセル: `npx convex run --component migrations lib:cancel '{name: "migrations/m001_xxx:migration"}'`

**Widen → Migrate → Narrow の進め方**:
1. スキーマに `v.optional()` で新フィールドを追加(Widen)
2. コード側はフォールバック付きで読み取り(新旧両方を許容)
3. `convex/migrations/mXXX_xxx.ts` でマイグレーションを定義し `index.ts` の runner 配列に追加
4. **Narrow 忘れ防止のために `TODO[narrow]: ...` コメントを入れる**(下記ルール参照)
5. PR マージ → CI が develop 環境に自動適用 → 全件完了を `lib:getStatus` で確認
6. 別 PR でスキーマ Narrow(`v.optional` を外す、TODO コメントも削除)
7. `release:*` 付きで main マージ → 本番に順次適用

**`TODO[narrow]` コメント運用ルール**:

Widen PR で「マイグレ完走後に戻す必要がある箇所」を Narrow PR まで確実に追跡するため、以下 2 箇所に `TODO[narrow]:` で始まるコメントを必ず残す:

- `convex/schema.ts` の該当 `v.optional()` フィールド直上
- フォールバック読み取りをしている query / mutation の該当行直上(例: `?? shop.xxx`)

コメントには以下を含める:
- **前提**: どのマイグレーション(`m0XX_xxx`)が完走していれば Narrow できるか
- **確認コマンド**: `pnpm convex:migrate:status`(state: done を確認)
- **対応内容**: 「この行の `v.optional()` を外す」「`?? shop.xxx` を削除する」など具体的な差分

例:

```ts
// convex/schema.ts
// TODO[narrow]: Widen → Migrate → Narrow の 2 段階目。
// 前提: develop/prod で m001_xxx が完走していること(確認: pnpm convex:migrate:status)
// 対応: v.optional() を外して v.string() にする
shiftStartTime: v.optional(v.string()),
```

```ts
// convex/shiftBoard/queries.ts
// TODO[narrow]: m001_xxx 完走後に `?? shop.xxx` を削除(schema の narrow と同じ PR で対応)
const startTimeStr = recruitment.shiftStartTime ?? shop.shiftStartTime;
```

Narrow PR 作成時は `grep -r "TODO\[narrow\]" convex/ src/` で残タスクを網羅的に拾う。Narrow PR マージ時に対応コメントも同時削除する。

### デプロイ前チェック

- [ ] dev 環境(`dev-yps-crispy-carnival`)でスキーマデプロイが通ることを確認
- [ ] 既存ドキュメントが新スキーマに合致するか(Convex はデプロイ時に全件バリデートする)
- [ ] バックフィルが必要な場合、マイグレーションを `convex/migrations/` に追加し `index.ts` の runner 配列に登録したか
- [ ] 本番デプロイは `release:*` ラベル付き PR 経由で行う(`.github/CLAUDE.md` 参照)

## テスト

### 方針
Expand Down
96 changes: 95 additions & 1 deletion convex/_generated/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import type * as email_actions from "../email/actions.js";
import type * as email_mutations from "../email/mutations.js";
import type * as email_queries from "../email/queries.js";
import type * as email_templates from "../email/templates.js";
import type * as migrations_index from "../migrations/index.js";
import type * as migrations_m001_recruitments_add_shift_times from "../migrations/m001_recruitments_add_shift_times.js";
import type * as recruitment_mutations from "../recruitment/mutations.js";
import type * as recruitment_schemas from "../recruitment/schemas.js";
import type * as setup_mutations from "../setup/mutations.js";
Expand All @@ -29,6 +31,7 @@ import type * as shiftBoard_queries from "../shiftBoard/queries.js";
import type * as shiftSubmission_mutations from "../shiftSubmission/mutations.js";
import type * as shiftSubmission_queries from "../shiftSubmission/queries.js";
import type * as shiftSubmission_schemas from "../shiftSubmission/schemas.js";
import type * as shop_mutations from "../shop/mutations.js";
import type * as staff_mutations from "../staff/mutations.js";
import type * as staff_schemas from "../staff/schemas.js";
import type * as staffAuth_mutations from "../staffAuth/mutations.js";
Expand All @@ -55,6 +58,8 @@ declare const fullApi: ApiFromModules<{
"email/mutations": typeof email_mutations;
"email/queries": typeof email_queries;
"email/templates": typeof email_templates;
"migrations/index": typeof migrations_index;
"migrations/m001_recruitments_add_shift_times": typeof migrations_m001_recruitments_add_shift_times;
"recruitment/mutations": typeof recruitment_mutations;
"recruitment/schemas": typeof recruitment_schemas;
"setup/mutations": typeof setup_mutations;
Expand All @@ -64,6 +69,7 @@ declare const fullApi: ApiFromModules<{
"shiftSubmission/mutations": typeof shiftSubmission_mutations;
"shiftSubmission/queries": typeof shiftSubmission_queries;
"shiftSubmission/schemas": typeof shiftSubmission_schemas;
"shop/mutations": typeof shop_mutations;
"staff/mutations": typeof staff_mutations;
"staff/schemas": typeof staff_schemas;
"staffAuth/mutations": typeof staffAuth_mutations;
Expand Down Expand Up @@ -98,4 +104,92 @@ export declare const internal: FilterApi<
FunctionReference<any, "internal">
>;

export declare const components: {};
export declare const components: {
migrations: {
lib: {
cancel: FunctionReference<
"mutation",
"internal",
{ name: string },
{
batchSize?: number;
cursor?: string | null;
error?: string;
isDone: boolean;
latestEnd?: number;
latestStart: number;
name: string;
next?: Array<string>;
processed: number;
state: "inProgress" | "success" | "failed" | "canceled" | "unknown";
}
>;
cancelAll: FunctionReference<
"mutation",
"internal",
{ sinceTs?: number },
Array<{
batchSize?: number;
cursor?: string | null;
error?: string;
isDone: boolean;
latestEnd?: number;
latestStart: number;
name: string;
next?: Array<string>;
processed: number;
state: "inProgress" | "success" | "failed" | "canceled" | "unknown";
}>
>;
clearAll: FunctionReference<
"mutation",
"internal",
{ before?: number },
null
>;
getStatus: FunctionReference<
"query",
"internal",
{ limit?: number; names?: Array<string> },
Array<{
batchSize?: number;
cursor?: string | null;
error?: string;
isDone: boolean;
latestEnd?: number;
latestStart: number;
name: string;
next?: Array<string>;
processed: number;
state: "inProgress" | "success" | "failed" | "canceled" | "unknown";
}>
>;
migrate: FunctionReference<
"mutation",
"internal",
{
batchSize?: number;
cursor?: string | null;
dryRun: boolean;
fnHandle: string;
name: string;
next?: Array<{ fnHandle: string; name: string }>;
oneBatchOnly?: boolean;
reset?: boolean;
},
{
batchSize?: number;
cursor?: string | null;
error?: string;
isDone: boolean;
latestEnd?: number;
latestStart: number;
name: string;
next?: Array<string>;
processed: number;
state: "inProgress" | "success" | "failed" | "canceled" | "unknown";
}
>;
};
};
};
6 changes: 6 additions & 0 deletions convex/convex.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import migrations from "@convex-dev/migrations/convex.config";
import { defineApp } from "convex/server";

const app = defineApp();
app.use(migrations);
export default app;
Loading
Loading