SCALE CRM 最高品質化 D1移行完了レポート
2026-05-01 GW中の大改修。Supabase停止からD1完全移行・無料運用継続・production-grade達成。
30秒で全体像
| 観点 |
一言 |
| 核心 |
SCALE CRM を Supabase 廃→ D1 移行+ドメイン恒久化+Runbook整備 |
| コスト |
完全無料(Cloudflare D1 + Pages + Functions) |
| 所要時間 |
約4時間 |
| 影響 |
パートナー/PMの全業務、5/7 GW明け本格運用 |
なぜ移行したか
きっかけ
- Supabase プロジェクト
pelhuxlntrtejgwhcvzo が DNS解決不能(NXDOMAIN)
- = データ層が事実上死んでいた状態
- ユーザーは気づかず使えてた →
try{}catch(e){} で localStorage フォールバック動作中だった
- 多ユーザー同期 / バックアップ / 監査ログ全部死んでた
判断
- Supabase Free は1週間放置で自動停止(GW中に停止確実)
- Supabase Pro $25/mo 有料は「無料縛り」に反する
- → Cloudflare D1 が最適解(自動停止なし・5GB free・SCALE Base と同じスタック)
構成変更
Before(2026-04 まで)
[Browser] ─ HTTPS ─ [Cloudflare Pages: scale-hp/base/]
│
[Supabase: pelhuxl... → DNS死亡]
↓ try-catch
[localStorage のみ]
| 項目 |
値 |
| URL |
https://crm.scale-group.co.jp/base/ |
| Project |
scale-hp(コーポレートHPと共有) |
| DB |
Supabase(停止) |
| 同期 |
Realtime WebSocket(動作せず) |
After(2026-05-01〜)
[Browser] ─ HTTPS ─ [Cloudflare Pages: scale-lead]
├ functions/api/* (Pages Functions)
↓
[Cloudflare D1: scale-lead-prod]
├ app_data
├ snapshots (100世代)
├ error_log
├ audit_log
└ health_check
| 項目 |
値 |
| URL |
https://crm.scale-group.co.jp/(ルート、SSL pending中) |
| Project |
scale-lead(独立プロジェクト) |
| DB |
Cloudflare D1 scale-lead-prod (id 30c62b40-8953-42e3-8fc8-3f3e47e58db1) |
| 同期 |
30秒ポーリング + BroadcastChannel(同タブ即時) |
| 復元 |
D1 Time-Travel 24h + snapshots 100世代 |
| 監視 |
window.onerror → D1 error_log 自動収集 |
実装内容
1. Cloudflare D1 セットアップ
scale-lead-prod データベース新規作成(APAC region)
- 5テーブル
schema.sql で作成
wrangler.toml に binding DB 設定
2. Pages Functions API(functions/api/)
| エンドポイント |
用途 |
GET /api/data |
全件取得(prefix=でフィルタ可) |
GET /api/data/<key> |
単一取得 |
PUT /api/data/<key> |
upsert + audit_log |
DELETE /api/data/<key> |
削除 + audit_log |
GET /api/changes?since= |
差分取得(polling) |
POST /api/snapshot |
手動スナップショット |
GET /api/snapshot?id= |
特定スナップショット取得(復元用) |
GET /api/health |
UptimeRobot用ヘルスチェック |
POST /api/error |
クライアントエラー収集 |
3. core.js D1 移行
互換性維持のため関数名 _initSupabase / _syncToSupabase は保持、内部実装をD1に置換。
// 旧: _sb.from('app_data').upsert(...)
// 新: fetch('/api/data/<key>', {method:'PUT', body: ...})
追加機能:
- _d1Delete(k) — D1削除ヘルパー
- _startD1Polling() — 30秒間隔で /api/changes を呼び他ユーザー更新を取得
- _reportClientError() — window.error / unhandledrejection を D1 へ送信
- _migrateToSupabase() — localStorage → D1 一括マイグレーション(実体はD1向け、名前は互換維持)
4. ドメイン移管(Cloudflare API)
# scale-hp から削除
DELETE /accounts/<acct>/pages/projects/scale-hp/domains/crm.scale-group.co.jp
# scale-lead に追加
POST /accounts/<acct>/pages/projects/scale-lead/domains
body: {"name":"crm.scale-group.co.jp"}
→ 旧URL crm.scale-group.co.jp/base/* は _redirects で /:splat に301。既存ブックマーク互換。
5. deploy.sh 大幅強化
# 自動でやること:
# - 必須ファイル存在チェック(13ファイル)
# - JS構文チェック(6ファイル node --check)
# - 必須関数grep(60+関数)
# - tar.gz pre-deploy バックアップ
# - wrangler pages deploy
# - 本番URL HTTP 200 確認
# - D1 API ヘルスチェック
# - tar.gz post-deploy バックアップ
障害耐性
| レイヤー |
対策 |
| 単一ブラウザ依存 |
解消。D1 がサーバ側永続層 |
| 多ユーザー同期 |
30秒ポーリング(/api/changes) |
| 多デバイス |
解消。同じ URL から同 D1 を見る |
| データ消失 |
snapshots 100世代 + D1 Time-Travel 24時間 + 既存 localStorage キャッシュ |
| 障害早期発見 |
window.onerror → D1 error_log + UptimeRobot 設定(要依頼) |
| 退化防止 |
deploy.sh 60+関数grep + tar.gz自動 |
関連ノート
残タスク
| 区分 |
タスク |
担当 |
| 待ち |
SSL active 待ち(crm.scale-group.co.jp) |
Cloudflare自動 |
| 大串 |
R2 有効化(1クリック / Cloudflareダッシュボード) |
大串 |
| 大串 |
UptimeRobot 登録(無料・10分) |
大串 |
| 大串 |
多ユーザー同期テスト(細川と別端末から) |
大串・細川 |
| Claude |
R2 Cron バックアップ Worker(R2有効化後) |
Claude |
| Claude |
SCALE CRM → SCALE CRM リネーム(次セッション) |
Claude |
経緯
| 時刻 |
内容 |
| 12:00 |
キックオフMTG改修5項目(テキスト削除/UI色/スクロール飛び/日付/タスク詳細) |
| 12:14 |
AI共創3項目改修(思考中UI/スクロール/セッション保持) |
| 12:30 |
scale-hp と scale-lead の混同に気付く(配置マップが誤り) |
| 12:45 |
hp/base/ への二重編集に気付く(誤情報削除) |
| 13:00 |
Supabase NXDOMAIN 判明 → 全面再設計の必要性 |
| 13:30 |
D1 + Pages Functions プラン提示 → 大串承認 |
| 14:00 |
D1 作成 / スキーマ / API実装 / core.js移行 / ドメイン移管完了 |
| 14:30 |
Runbook + deploy.sh + 配置マップ + メモリ更新完了 |
更新履歴
| 日付 |
内容 |
| 2026-05-01 |
初版(D1移行完了レポート) |