💻 システム開発
SCALE_CRM_リスト性能_残課題洗い出し_第2弾
最終更新 2026年07月06日 / 31_システム開発部/_SCALE_CRM_リスト性能_残課題洗い出し_第2弾.md
SCALE CRM 架電リスト性能 残課題洗い出し 第2弾
大串FB(2026-07-06)「重い原因で対処しきれてないことないか洗い出して。超高品質なCRMにしたい。架電はひたすら数こなすからちょっとのラグが凄いストレス」への回答。
前提: 第1弾(_SCALE_CRM_リスト性能_根本原因とHubSpot対比)の①仮想スクロール+HubSpot体制Phase1-3は本番LIVE済み。本ノートはその後も残っている未対処分をコード実証(3並列調査・ファイル:行番号つき)で洗い出したもの。
対処済みの確認(再発なし)
- 仮想スクロール本体(calllist_core.js:1380-1420): RAF throttle・編集中の再描画抑止・行高キャッシュあり=堅牢
- 検索入力の220ms debounce(calllist_core.js:577)
- per-row 1行PUT(json_patch・UI非ブロック)・イベントリスナ(inline onclick=自動GC)
- E1(per-row同期の毎分フリーズ・v11.5.78)/ E2(401無限スピナー・v11.5.79)
未対処の残課題(体感影響順)
A. 操作のたびのマイクロラグ(架電メンバーのストレス直撃・最優先)
| # | 課題 | 場所 | 何が起きるか |
|---|---|---|---|
| A1 | 🔴 getLatestCallSt メモ化なし | lib/calllist_const.js:53-62 | 毎回5スロット走査。フィルタ・ソート・統計・モーダル等 計8箇所以上から重複呼び出し |
| A2 | 🔴 filterCL がプリセット/ソート/タブ切替のたび全件走査 | lib/calllist_core.js:1486-1543 | フィルタO(n×5)+ソートコンパレータ内で getLatestCallSt 再計算(6千行×log n≈8万回)。1操作で合計約14万スロット走査=200-500msの引っかかり |
| A3 | 🔴 _collectTodayStats がステータス変更のたび全行走査 | lib/pagecore_report.js:8-46(呼出: pagecore_timer.js:743 / calllist_misc.js:639 / calllist_status.js:338) | 架電1件入力するごとに6,134行×5スロット再スキャン。「数をこなす」動線に毎回乗る |
| A4 | 🟡 _migrateCallListV3 が renderCallList のたび全行forEach | lib/calllist_core.js:11-37, 706 | 「一度だけ」のはずが毎render全行チェック(1回5-10ms・積算) |
→ A1〜A3の連鎖が「ちょっとのラグ」の正体。仮想スクロールで描画はO(1)になったが、描画の前段の計算が全部O(n)のまま。
B. 初期ロード・ページ再訪の重さ
| # | 課題 | 場所 | 何が起きるか |
|---|---|---|---|
| B1 | 🔴 全機能JS 約2.6MBを全員が初期ロード | index.html:19-143 | service.min.js 724KB(AI共創)・kickoff 91KB・ai 48KB・list_pool 50KB を架電メンバーにも強制DL+評価。lazy load なし |
| B2 | 🟡 JS/CSSが no-cache | _headers | ?v= 版付きなのに毎回再検証(304往復200-500ms)。immutable + max-age=31536000 にできる。SWが部分救済中 |
| B3 | 🟡 _routes.json 不在 | (ファイルなし) | 静的アセットも認証middlewareを通過(regex×20/リクエスト・初回30-50リクエスト分) |
| B4 | 🟡 起動シーケンスが直列3往復 | core.js:5620-5750 | _initSupabase → _v2SyncBoot → clLoadRows が直列。並列化・集約の余地 |
| B5 | 🟡 sessionMemberExists の isolate 60秒キャッシュ | functions/_middleware.ts | isolate 寿命が短く、ページ移動/プロジェクト切替で D1 member_rows 再読込(40-100ms/回)。KV昇格の余地 |
C. ネットワーク・データ量(弱回線メンバーに効く)
| # | 課題 | 場所 | 何が起きるか |
|---|---|---|---|
| C1 | 🟡 120秒 full reconcile の全件再DL が残存 | core.js:3727 | DOM/parse側は v11.5.78 で軽量化済みだが、5MB級のDL自体は2分ごとに発生(弱回線の帯域圧迫・第1弾#4の残り) |
| C2 | 🟡 リロード時の全件再DL | core.js:3542(loadRows)+ calllist_core.js:715-765 | v86スナップ即表示はUIのみ。裏で毎回 5.9MB DL+6千回JSON.parse。ページングなし(第1弾#2の残り) |
| C3 | 🟢 APIレスポンスの不要フィールド | functions/api/calls/index.ts:68-80 | 全件GET時も updated_at/updated_by を全行送信(約100KB余分) |
D. 掃除・将来リスク
| # | 課題 | 場所 | 何が起きるか |
|---|---|---|---|
| D1 | 🟡 旧chunked blob 7.92MB がD1に残骸 | core.js:979-986(fire-and-forget削除のみ) | 物理削除スクリプト未実装。第1弾#6が未実施のまま |
| D2 | ⚠️ query.ts が「全行SELECT→JSで絞り込み」 | functions/api/calls/query.ts:137-139 | 現在は _clServerMode OFF なので体感影響ゼロ。ただしPhase4をONにすると1リクエスト1-2秒=逆に遅くなる。ON前に c_* 物理列でのSQL絞り込み化が必須 |
対処パッケージ(効果順・実装するならこの単位)
- パック①: クライアント計算のO(n)撲滅(A1メモ化 → A2重複排除 → A3差分/キャッシュ化 → A4スキップ)=「操作のたびの引っかかり」根治。架電メンバーの体感に最も効く
- パック②: 配信最適化(B2 immutableキャッシュ → B3 _routes.json → B1 lazy load)=開く・戻るが速くなる
- パック③: ネットワーク削減(C1 full reconcileの軽量化 → B4 起動並列化 → C2 ページング)
- パック④: 掃除(D1 chunked blob削除スクリプト)
- (Phase4をONにする時)D2 query.tsのSQL化を先に
実装結果(2026-07-06 v11.6.3・本番LIVE・同日中に全部実装)
大串指示「全部実装して。完璧に超スピード感もった完璧なツールに」→ 同日実装・デプロイ・本番実バイト検証済み。
| 課題 | 結果 |
|---|---|
| A1 getLatestCallStメモ化 | ✅ WeakMap+キー検証(ステータス変化で自動再計算=無効化漏れゼロ) |
| A2 filterCLソート再計算 | ✅ 事前計算(Schwartzian)化・安定ソートで順序完全同一 |
| A3 統計の全行走査 | ✅ 集計本体500msメモ化+_updateCallListStatsOnly冒頭で必ず無効化(編集経路の鮮度は従来同一) |
| A4 _migrateCallListV3 | ✅ 案件ごとセッション内1回に(不要PSも排除) |
| B1 JS遅延ロード | ⚠️ 縮小実施: preloadをcore+lib_bundleに付替のみ。フル遅延はrenderPageのRマップ(core.js:6196)がrenderService等を裸参照=ReferenceErrorリスクで見送り |
| B2 immutableキャッシュ | ✅ 版付き9ファイルを1年immutable化。Pagesの_headersは同名ヘッダを結合する仕様(本番実測)→「! Cache-Control」で前段no-cacheを取り消してから設定。SW/HTMLはno-cache維持 |
| B3 _routes.json | ❌ 見送り: min.jsのAUTH_GUARD保護(未ログイン403)が外れる=認証姿勢の変更。効果もB2でほぼ吸収 |
| B4 起動並列化 | ❌ 見送り: ブート順序依存が深くPhase4とセットで設計すべき |
| C1 full reconcile全件DL | ✅ /api/calls?digest=1新設(件数+MAX(updated_at)・数百バイト)→一致でDLスキップ。安全弁=失敗/不一致は従来full・連続スキップ15回上限(30分毎に本物full=保険維持)・digest基準はfull成功後確定。帯域最大1/15 |
| C2 リロード全件DL | ❌ 見送り: slimスナップを正データ化するとデータ消失リスク。真の解決はPhase4ページング |
| D1 chunked blob残骸 | ✅ 36キー15.73MB削除(dump保存→DELETE→残存0検証・DB 653.7→633.6MB) |
| D2 query.ts SQL化 | ✅ 実施: c_latest_status整合を本番実測(「ステータス有り×NULL」矛盾0行)で確認の上、st/cp/sg/presetを1次WHEREに押込(上位集合保証・early-return系preset除外・recentIds OR包み)。JS述語は最終判定に不変維持 |
重要な実測: 最大案件mnpg72の現役行は14,900行(6/24の6,134行から2.4倍に成長)。行数比例の設計が残っていたら近々再クラッシュだった。
観測: [CL-FULL-SKIP](digestスキップ)・[CL-FULL](full実測ms)・window._perfStats(longtask)。
関連
- _SCALE_CRM_リスト性能_根本原因とHubSpot対比(第1弾・2026-06-24)
- _SCALE_CRM_HubSpot体制移行_実装計画(Phase1-4)
- _SCALE_共通_トラブルシューティング集 E1/E2