2026-04-17 | Claude Code | v2(19)を Codex 8回目指摘6件で全面改訂 + vendor 実価格で Decision 再検証
Decision が γ(Neon+Clerk+Trigger.dev)から β(Supabase)に変更。
Codex 8回目レビュー(20)を受けて vendor の data residency と実価格を WebFetch 実調査した結果、 γ の各ベンダ(Neon / Clerk / Trigger.dev)はいずれも Tokyo region 非対応で INV-18 Data residency を構造的に満たせないことが判明。 一方 Supabase は Tokyo (ap-northeast-1) を公式サポート。 TCO も vendor 実価格で再計算したところ γ は β より約 20% 高コスト(v2 で主張した 1.6% 差は誤り)。
8ラウンドの Codex レビューを経て到達した最終決定文書。 子安氏に送るのは本書(21)+ Codex 9回目レビュー(実施予定)の組み合わせ。
v2(19) と同一。1.1 ビジネス要件 / 1.2 機能要件 / 1.3 運用要件は 19 §1 を参照。
INV-1〜20 の内容は 19 §2 と同一。
| レイヤー | 製品 / 技術 | 備考 |
|---|---|---|
| Frontend | Cloudflare Pages + React 19 + Vite | 既存 v2/v3 の Pages 資産を流用 |
| API Gateway | Cloudflare Workers + Hono | 既存コード構造を流用 |
| 業務ロジック実行 | Supabase Edge Functions(Deno)or CF Workers | DB 近接処理は Edge Functions、残りは Workers |
| Auth | Supabase Auth | Email/Password + MFA + SSO、JWT 発行・検証は Supabase 側 |
| 一貫性境界 | Postgres 14+ advisory lock + トランザクション | outbox / audit chain / rate limit counter 全部 Postgres |
| 非同期ジョブ | pg-boss(Postgres 上の job queue) | Trigger.dev と違い DB 同居で region 制約なし |
| Cron | pg_cron(Postgres 拡張) | 同上 |
| Media | Cloudflare R2 + client presigned URL | 既存資産継続 |
| DB | Supabase Postgres (Medium compute) | Tokyo region (ap-northeast-1)、PITR $100/mo add-on 購入 |
| Abuse | Cloudflare WAF + Turnstile | 既存継続 |
| 観測 | Supabase Logs + Sentry + Better Stack | Better Stack 2 responder(24/7 SMS 込み) |
| Secrets | Supabase Vault (pgsodium) + Cloudflare Workers Secrets | IG token は Supabase Vault、infra secret は CF Workers Secrets |
| Backup | PITR 7日(Pro add-on $100/mo)+ 日次バックアップ標準 | INV-12 を native で満たす |
Codex 7/8回目 と同じく Hard Gate 失敗で Reject:
5=Native / 4=Sound / 3=Achievable / 2=Difficult / 1=Blocked(Hard Gate) / ?=Unknown
Codex 8回目指摘 #3 対応で INV-18 を pre-Q1 blocker に。評価は以下:
| INV-18 Data residency | α | β | γ |
|---|---|---|---|
| CF Workers Tokyo | 5 | 5 | 5 |
| DB Tokyo region | 5 (D1 edge) | 5 (Supabase Tokyo 公式) | 1 (Neon Tokyo なし) |
| Auth Tokyo residency | 5 (自前実装) | 5 (Supabase Tokyo) | 1 (Clerk 未提供) |
| Queue Tokyo residency | 5 (CF Queues) | 5 (pg-boss DB同居) | 1 (Trigger.dev payload 越境) |
| 総合 | 5 | 5 | 1 (Hard Gate Fail) |
INV-1〜17, 19, 20(INV-18 は Hard Gate)でスコア合計:
| Vendor | 実価格(調査結果) |
|---|---|
| Supabase Pro | $25/mo 基本 + Micro compute 込み($10 credit) |
| Supabase Compute add-on | Small $15 / Medium $60 / Large $110(Pro plan は Micro 無料) |
| Supabase PITR | $100/mo add-on(INV-12 のため必須) |
| Supabase Disk | 8GB 込み、超過 $0.125/GB |
| Cloudflare Workers Paid | $5/mo(10M req 込み) |
| Cloudflare R2 | $0.015/GB/mo + $4.50/M Class A |
| Cloudflare WAF Rate Limiting | $20/mo(実質必須) |
| Cloudflare Turnstile | Free(本番ほぼ無料) |
| Sentry Team | $26/mo |
| Better Stack 2 responders | $68/mo(SMS 無制限含む) |
| Claude API (Haiku 4.5) | usage-based、$0.25/$1.25 per MTok |
実調査ソース: supabase.com/pricing, developers.cloudflare.com/workers/platform/pricing, betterstack.com/pricing, sentry.io/pricing
| 項目 | 30店舗 | 100店舗 | 300店舗 | 備考 |
|---|---|---|---|---|
| Supabase Pro 基本 | $25 | $25 | $25 | Pro plan subscription |
| Supabase Compute | Micro込み ($0) | Small $15 | Medium $60 | - $10 credit |
| Supabase PITR add-on | $100 | $100 | $100 | INV-12 Hard Gate |
| Supabase Disk (超過分) | $0 | $2 | $12 | 8GB 込み、超過 $0.125/GB |
| Supabase Egress | $0 | $0 | $9 | 250GB 込み、超過 $0.09/GB |
| CF Workers Paid | $5 | $5 | $10 | 10M req 超過分 |
| CF R2 | $2 | $5 | $15 | 画像ストレージ |
| CF WAF | $20 | $20 | $20 | |
| Sentry Team | $26 | $26 | $26 | |
| Better Stack 2 responders | $68 | $68 | $68 | 24/7 on-call + SMS |
| Claude API | $15 | $40 | $120 | usage |
| Staging/Dev | $25 (Free + Small) | $30 (Free + Small) | $50 (Pro + Small) | |
| 月額合計 | $286 | $336 | $515 | |
| 店舗あたり単価 | $9.5 | $3.4 | $1.7 | |
| 売上比 | ¥42,900 / ¥600,000 = 7.2% | ¥50,400 / ¥3.5M = 1.4% | ¥77,250 / ¥6M = 1.3% | Infra 比率 |
| 項目 | 案β 合計 | 備考 |
|---|---|---|
| Infra 3年 ($336 × 36) | $12,096 ≈ ¥1.81M | usage-based 再計算済み |
| 実装工数(180h × ¥8,000) | ¥1.44M | 子安氏稼働単価 |
| 運用工数(3年 10h/月 × ¥8,000) | ¥2.88M | 24/7 escalation 込み |
| Incident 対応(年1回想定) | ¥0.6M | PITR + runbook 整備済み前提 |
| 3年 TCO 合計 | 約 ¥6.7M | |
| 売上 3年(¥3.5M × 36) | ¥126M | 100店舗想定 |
| 粗利率 | 94.7% |
| シナリオ | 年次コスト | 売上比 |
|---|---|---|
| 30店舗で停滞(¥600k/mo) | ¥3.43M | 47.6%(赤字リスク) |
| 100店舗達成(¥3.5M/mo) | ¥4.03M | 9.6%(健全) |
| 300店舗拡大(¥6M/mo) | ¥6.18M | 8.6%(健全) |
重要: 30店舗停滞時は運用工数 + Better Stack/Sentry 固定費が重い。 30店舗到達まで Better Stack を 1 responder にして $34/月に抑える、 Sentry は Developer plan $26 を Hobby (Free) から始める選択肢を追加。
Supabase (Tokyo region) + Postgres 14 + pgsodium Vault + pg-boss + pg_cron
+ Cloudflare Pages + Workers + R2 + WAF + Turnstile
+ Sentry + Better Stack (24/7 responders)
Hard Gate 通過(INV-3/8/12/13/18)/Weighted 66/75 / 3年 TCO ¥6.7M / 粗利率 94.7%
| 弱点 | Mitigation |
|---|---|
| Supabase 単一障害点 | Better Stack monitoring + Supabase status 購読 + 非常時 read-only mode(Runbook R4) |
| Edge Functions の cold start | 業務ロジックは CF Workers 側、DB 近接処理のみ Edge Functions、pgbouncer で connection pool |
| Supabase Auth の機能が Clerk より弱い(MFA は Pro 含、SSO は Team $599 から) | SSO は Phase 2 まで不要、MFA は Pro 込み |
Supabase は Vault(pgsodium 拡張ベース)を native に提供。secret の暗号化保管と復号ヘルパが SQL から使える。
-- IG token を暗号化保管 SELECT vault.create_secret( 'ig_access_token_plaintext_here', 'ig_token_store_001', 'Instagram access token for store_001' ); -- 復号 SELECT decrypted_secret FROM vault.decrypted_secrets WHERE name = 'ig_token_store_001';
pgsodium は master key rotation を自動管理。Supabase 側で encryption key の世代管理を 内部で行うため、アプリ側は rotation job を持たなくて良い。 Codex 8回目指摘 critical(MEK rotation と PITR の矛盾)は β 採用で自動解決。
SELECT vault.update_secret(id, null) または row DELETE で secret 消去Supabase PITR は Vault data を含めて過去時点に restore 可能。 master key は Supabase が管理するので、restore 時にも自動的に対応する master key で復号できる。 v2/v3 の γ 設計で問題になった「MEK 削除で PITR restore 後に復号不能」という矛盾は発生しない。
以下を audit_logs に記録:
v2 (19 §10.1) と同じ。Supabase Auth + RLS policies の test。
| Crash timing | Injection 方法 | Expected recovery |
|---|---|---|
| Before IG media_create | CF Workers throw feature flag で強制例外 | pg-boss が retry、outbox からキューに再登録 |
| After media_create, before creation_id saved | IG mock で 200 返却後、throw で DB commit 前停止 | reconciliation cron が orphan check、creation_id 取得して再開 |
| After creation_id saved, before media_publish | pg-boss job が creation_id を保存後に kill(signal 経由) | 次の cron で保存済み creation_id を読んで publish 実行 |
| After media_publish, before DB commit | Supabase tx 中に pg_cancel_backend で強制切断 | reconciliation: IG から media_id 取得、posts 更新 |
| After DB commit, before pg-boss ack | pg-boss 完了前に job worker を kill | pg-boss retry、status='published' を見て skip(idempotent) |
| During reconciliation | reconciliation cron を中断 | 次の cron で再開、orphan-free 保証 |
Test mechanics: k6 or autocannon で 100 並行リクエスト、各 endpoint が audit_logs.append を呼ぶ。
Postgres advisory lock (pg_advisory_xact_lock) + seq INSERT 原子的。
Pass: 全 100行が prev_hash で連結、seq 連番、fork ゼロ。
| Scenario | Injection | Expected |
|---|---|---|
| IG API 500 (30 posts backlog) | wiremock で IG 相当の endpoint を返す、500 応答 | outage 解除後 5分で全完了 |
| IG API 429 rate limit (100 posts) | wiremock で Retry-After header 付き 429 | exponential backoff で 20分以内完了 |
| Supabase DB 障害(mock) | Supabase Edge Functions 側で意図的に DB connection 切断 | pg-boss job 失敗 → CF Workers 側で degraded mode、復旧後 queue から再実行 |
| Dataset | Mechanics | Pass |
|---|---|---|
| v2 現本番 10店舗 | D1 export → Postgres import script、dual-read で 検証 | 1店舗 5分以内、posts 件数・内容 diff ゼロ |
| 合成 100店舗 | faker で合成、大規模一括 import | 全件 30分以内、サンプル 100件の内容一致 |
| 移行中 v2→v4 dual-write | CF Workers 経由で v2/v4 両方に投稿 insert、cron で diff 検出 | 最大 10秒遅延で同期 |
| Rollback: v4→v2 | Supabase Branch で v4 state を保存 → v2 D1 へ restore script | 1店舗 10分以内、データ喪失ゼロ |
E9 Data residency: β 採用により Supabase Tokyo + CF Tokyo + R2 で全ベンダ JP region 対応。PII が region を出ない設計を確認。
v2 (19 §12) と同じ。子安氏への質問 Q6 として on-call 受諾 + compensation 確認を追加(§11 参照)。
Phase 1 MVP 12週間は v2 と同じ。ただし Week 3-4 の Auth 実装は Clerk → Supabase Auth に変更のため工数は同等。
| # | 質問 | 回答形式 |
|---|---|---|
| Q1 | Decision(6章)の案β(Supabase + Cloudflare hybrid)で進めて良いか | Yes / No |
| Q2 | Invariants 20項目(v2 19§2)に追加・削除・優先度変更はあるか | 追加リスト or 「なし」 |
| Q3 | Evidence(§8)E1〜E9 の test mechanics に修正はあるか | 修正リスト or 「なし」 |
| Q4 | Delivery Plan 12週間で実装可能か(Supabase 経験前提で) | Yes / No(No なら現実工期) |
| Q5 | Blocking concerns 自由記述 | 自由記述 |
| Q6 | 24/7 on-call 受諾可否 + compensation / escalation 合意 |
|