ADR-0067: monorepo 構成と pnpm workspaces + Turborepo 採用 (Phase 1: root 除外型から段階移行)
- Status: Accepted
- Mode: Standard
- Kruchten Type: Executive/Property
- Scope: platform
- Implementation Status: Phase 1-2 Done (PR #957 Phase 1, PR #968 Phase 2a, PR #972 Phase 2b, PR #974 Phase 2c — Lock 統合 + Turborepo 2.x + turbo.json + CI pnpm 移行 + syncpack + Catalogs 完了; Phase 3 (packages/types + packages/engines + sync-engines 廃止) は将来別 ADR)
- 起案者: [email protected]
- 起案日時 (JST): 2026-05-25 13:23
- 承認日時 (JST): 2026-05-26
- Deciders: [email protected] (単独)
- Pipeline Validation: 2026-05-25, 47/50 (Standard 閾値 40 超過, Critical 閾値 45 超過)
1. コンテキスト
1.1 背景 (Background)
bizlp-gas-accounting リポジトリは、GAS 本体 (root) と 4 サブプロジェクト (webapp_client, drp, docs-search-worker, docs/) が混在する準 monorepo 状態にあり、依存管理・build orchestration・型同期の各所で構造的負債が顕在化している。Jr 入社 (2026-10 予定) を控え、AI agent (Claude Code) 主体の個人開発体制で持続可能な構造への移行が必要となった。
1.2 現状 (Current State / As-Is)
- npm (root) と pnpm (サブプロジェクト) が並存し、各サブプロジェクトが独立 lock ファイルを保持
- root に
pnpm-workspace.yamlが存在するが、内容はallowBuilds: fsevents: set this to true or falseというプレースホルダのみ - root の
npm run build:spaで webapp_client をビルドする手動 orchestration sync-engines.mjsによるファイルコピーベースの型同期 (sidebar_api.d.ts 等) が CI 非統合
1.3 課題 (Problem)
- 依存管理の破綻予兆: npm / pnpm 並存と独立 lock ファイルにより phantom dependency のリスクが各所に潜在
- 手動 build orchestrator の拡張性限界: サブプロジェクト増加に伴い手動 orchestration が破綻寸前
- 脆弱な SSoT 同期:
sync-engines.mjsのファイルコピーベース型同期は CI 非統合でドリフト検知が属人的 - 壊れた pnpm-workspace.yaml: プレースホルダのまま放置され workspace 設定が未構成
- AI agent 探索効率の最適化要請: Claude Code が主要開発ツールである本プロジェクトでは、monorepo 構造の明確化が AI agent のファイル探索・コンテキスト理解効率に直結する (探索パス判断ミスがトークン浪費・誤修正に繋がる)
1.4 制約・要件 (Constraints & Requirements)
- GAS 本体 (root) は clasp 3.x の rootDir 制約があり、安易なディレクトリ移動は
.clasp.json/ 全スクリプトパス破壊に直結 - 個人開発 + AI agent 主体 (Jr 入社 2026-10 予定) のため、学習コスト・運用負荷を最小化する必要
- 既存 CI (GitHub Actions) との互換性維持が必須
1.5 目標 (Goals / To-Be)
- pnpm workspaces + Turborepo + Catalogs による依存管理・build orchestration・型共有の構造的統合
- Phase 1 では root (GAS) を workspace から除外しつつ、3 サブプロジェクトを統一管理する段階的移行の起点を確立
- Non-Goals: Phase 1 時点での root (GAS) workspace 包含、sync-engines.mjs の即時廃止、Phase 3 完了形の確定
2. 決定
RQ-053 Synthesis (3 LLM 並列調査 + MCDA 加重和評価) の結果に基づき、案 C (GPT 段階的移行) を採択 (MCDA 加重和 0.927/1.0、最高スコア)。pnpm 10.x + pnpm workspaces (Catalogs catalogMode: strict) + Turborepo 2.x + TypeScript Project References + Vercel Remote Cache + syncpack + GitHub Actions (pnpm/action-setup@v4 + turbo run --affected) を tooling stack とする。Phase 1 では root を workspace に含めず 3 サブプロジェクト (webapp_client, drp, docs-search-worker) のみを対象とし、Phase 2 で lock 統合 + Turborepo 導入、Phase 3 で packages/types/ + packages/engines/ の共有 packaging を実施する。Root 包含可否は Phase 3 でデータドリブンに再判断する。
3. 判断基準 (Decision Drivers)
3.1 評価軸 (Q42 9 タグから選定)
| # | 軸 | 重要度 (係数) | 案件特有の解釈 |
|---|---|---|---|
| 1 | #maintainable | [Must] (×2.0) | AI agent / Jr が 6 ヶ月後に構造を再現できるか |
| 2 | #suitable | [Must] (×2.0) | 既存接続 (sync-engines.mjs, sidebar_api.d.ts) + CLAUDE.md / ADR-0019 との整合性 |
| 3 | #operable | High (×1.0) | 実装コスト (Claude Code セッション数) |
| 4 | #usable | Medium (×0.5) | Jr オンボーディング学習コスト |
K.O. criterion: Must 軸の score < 3 は不採用 (機能要件未充足)。
係数設定根拠: Must (×2.0) は「欠如すると運用不能」な軸、High (×1.0) はベースライン、Medium (×0.5) は「あると良い」軸。ADR-0050 §4.2 の標準係数体系に準拠。#secure / #reliable / #efficient / #flexible / #safe は本件の build infrastructure 選定には直接影響しないため省略 (Q42 公式テンプレートで 5 軸選定が標準)。
3.2 評価軸 x 案スコア表
| 軸 | 係数 | 案 C (採択) | 案 A | 案 B |
|---|---|---|---|---|
#maintainable [Must] | ×2.0 | 5 | 4 | 5 |
#suitable [Must] | ×2.0 | 5 | 5 | 3 |
#operable High | ×1.0 | 4 | 5 | 2 |
#usable Medium | ×0.5 | 4 | 4 | 5 |
| 加重和 (正規化, max 27.5) | 0.927 | 0.836 | 0.673 | |
| K.O. 通過 (Must >=3) | pass | pass | pass |
加重和は絶対判定ではなく K.O. 通過候補のタイブレーク用 (Suhr 1999 CBA criterion 準拠)。
4. 検討した代替案 (Alternatives Considered)
- 案 A (Claude 同梱型): GAS root + サブを同一 workspace に即時包含 -- 不採用理由: GAS が root にある状態で workspace に含めると、AI agent が GAS コードと orchestrator コードを混同する探索効率劣化 (#maintainable=4 vs 案 C の 5: 案 C は Phase 3 まで GAS を workspace 外に置くことで AI agent の探索スコープを明確に分離)。clasp rootDir とワークスペース境界の衝突リスク。MCDA 加重和 0.836/1.0
- 案 B (Gemini 分離型): GAS を
apps/gas-core/に移動 -- 不採用理由: GAS ディレクトリ移動が破壊的 (.clasp.json/ 全スクリプトパス書換え = mega 工数)。#operable=2 で K.O. ぎりぎり。個人開発では ROI が成立しない。MCDA 加重和 0.673/1.0 - 案 D (現状維持): 不採用理由: 壊れた pnpm-workspace.yaml の放置、sync-engines.mjs のドリフトリスク増大、サブプロジェクト追加時の手動 orchestration 限界が近い
4.1 Tooling Stack (3 モデル合意ベース)
| Layer | 採用 | 根拠 |
|---|---|---|
| Package manager | pnpm 10.x | 3 モデル合意 (phantom dep 防止、Catalogs、content-addressable store) |
| Workspace | pnpm workspaces + Catalogs (catalogMode: strict) | Claude / Gemini 合意 + GPT 明示支持。Catalogs でバージョンドリフトを構造的に防止 |
| Build orchestrator | Turborepo 2.x | 3 モデル合意 (Nx は個人開発に overkill、Vercel Remote Cache 2024-12-22 無料化済) |
| 共有型管理 | TypeScript Project References + workspace:* | 3 モデル合意 (path aliases 非推奨、TypeScript 公式推奨) |
| Remote cache | Vercel Remote Cache (無料) | Claude / GPT 合意、CI <-> local cache 共有を個人開発でも実現。データガバナンス注記: Vercel の DPA (Data Processing Agreement) を確認済、ソースコードはキャッシュされない (ビルド成果物のみ)。rate limit は個人開発規模では問題にならないが、CI 並列度増加時は self-hosted cache (turborepo-remote-cache OSS) にフォールバック可能 |
| Dep drift 監視 | syncpack + pnpm catalog: enforcement | Claude 推奨、Gemini も Catalogs 推奨 (実質合意) |
| CI | GitHub Actions + pnpm/action-setup@v4 + turbo run --affected | 3 モデル合意 |
4.2 Root 包含戦略: 段階的 (案 C)
- Phase 1 (本 ADR スコープ): Root を pnpm-workspace.yaml に含めない。
packages: ['webapp_client', 'drp', 'docs-search-worker']-- workspace は 3 サブプロジェクトのみ - Phase 2: Lock 統合 (各サブの
package-lock.json/pnpm-lock.yaml削除 ->pnpm import-> 統一pnpm-lock.yaml)。Turborepo 導入、rootnpm run build:spaをturbo run build --filter=webapp_clientに置換 - Phase 3: 共有 packaging。
packages/types/(sidebar_api.d.ts 移設) +packages/engines/(400_domain 抽出、sync-engines.mjs 廃止)。Root 包含可否は Phase 3 でデータドリブンに再判断 (現時点では確定しない)。GAS bundling 戦略: GAS は標準で Node.js モジュール解決をサポートしないため、共有パッケージを GAS 側で利用するには esbuild / rollup 等のバンドラ導入が前提。Phase 3 計画時に bundler 選定 ADR を別途起案する
4.3 壊れた pnpm-workspace.yaml の処置
Phase 1 開始時に現在の無効なプレースホルダを削除し、正しい workspace 設定で再作成。allowBuilds (pnpm v10+ 機能) は初期省略、必要時 pnpm approve-builds で選択的承認。
5. 影響 (Consequences)
5.1 正の影響 (Good)
- 依存管理統一: pnpm Catalogs + syncpack でバージョンドリフトが構造的に不可能に
- AI agent 探索効率: monorepo 構造の明確化で Claude Code の探索パス判断精度が向上、トークン消費削減
- CI 高速化: Turborepo + Vercel Remote Cache で変更影響範囲のみビルド (
--affected) - build orchestration 自動化:
turbo run buildで依存グラフベースの自動実行 (手動npm run build:spa廃止) - 型安全の向上: TypeScript Project References +
workspace:*でコンパイル時型チェック (sync-engines.mjs のファイルコピー廃止)
5.2 負の影響 (Bad)
- 移行工数: 3 Phase 合計で ~15-20h Claude Code セッション (Phase 1 ~1h / Phase 2 ~4-6h / Phase 3 ~10-13h; 1.5x バッファ込み)
- pnpm 学習コスト: npm から pnpm への移行で、Jr (2026-10 入社) に追加学習負荷。ただし業界標準ツールのため長期的にはプラス
- Turborepo 運用知識:
turbo.jsonのタスクグラフ定義、cache 設定の理解が必要
5.3 中立・トレードオフ (Neutral / Trade-offs)
- Phase 3 で root (GAS) 包含可否を実データに基づき再判断 -- 現時点で確定しないことが「適切な不確定性」
5.4 影響範囲
| 軸 | Phase 1 | Phase 2 | Phase 3 |
|---|---|---|---|
| ファイル | root pnpm-workspace.yaml | 全サブ lock ファイル + turbo.json + CI workflows | packages/ 新規 + import パス書換え |
| モジュール | なし (GAS コード影響ゼロ) | root package.json scripts | webapp_client / decision-pipeline imports |
| データ | なし | なし | なし |
| ステークホルダー | AI agent (探索パス変更なし) | AI agent + CI | AI agent + CI + Jr (2026-10 入社後) |
5.5 コスト試算
| 項目 | Phase 1 | Phase 2 | Phase 3 | 合計 |
|---|---|---|---|---|
| Claude Code セッション | ~1h | ~4-6h | ~10-13h | ~15-20h |
| 人間レビュー | ~15 min | ~30 min | ~1h | ~2h |
| CI 設定変更 | なし | ~1h | ~1h | ~2h |
| 月次運用コスト (移行後) | -- | -- | -- | ~2h/年 (syncpack check + turbo cache 監視) |
Phase 1 -> Phase 2 間隔は最低 1 週間 (Phase 1 安定性確認: CI green 連続 5 日以上)。Phase 2 -> Phase 3 間隔は最低 1 ヶ月 (Phase 2 安定性 + KPI baseline 取得: CI green 連続 2 週間 + incident 0 件)。
6. 運用上の罠・後任がハマりそうな落とし穴
- clasp rootDir との衝突: pnpm workspace に root を含めると、
node_modules/.pnpm構造と clasp のrootDir: '.'が干渉する可能性。Phase 1 で root を除外するのはこのリスク回避が主目的の一つ - pnpm Catalogs の strict mode 罠:
catalogMode: strictでは workspace 内の全package.jsonで catalog に定義されていない依存を追加するとエラー。新規依存追加時は必ずpnpm-workspace.yamlのcatalog:セクションに先に追加する運用が必要。Phase 1 完了時に CLAUDE.md に依存追加手順を明記する - Turborepo cache invalidation:
turbo.jsonのinputs/outputs定義が不正確だと stale cache が残り、ビルド結果が古い。Phase 1-2 期間中は GAS (workspace 外) から webapp_client (workspace 内) への型同期が Turborepo の依存グラフ外となるため、cache invalidation 不能で誤ビルドリスクが残る。対策: sync-engines.mjs 実行後にturbo run build --forceを明示的に実行する CI step を追加 - lock ファイル統合時の依存解決: Phase 2 で
pnpm importを実行する際、npm lock と pnpm lock の依存解決差異で一部パッケージの version が変わる可能性。統合前にnpm ls --all/pnpm ls --depth Infinityの diff を取って検証する - Vercel Remote Cache の rate limit: 無料プランの rate limit を事前確認。個人開発規模では問題にならないが、CI 並列度が上がると hit する可能性。フォールバック: turborepo-remote-cache (OSS self-hosted)
- Phase 3 の sync-engines.mjs 廃止タイミング: 新しい
packages/engines/が完全に動作確認できるまで sync-engines.mjs を残す (並行運用期間を設ける)。一括廃止は rollback 困難 - Phase 3 の GAS bundling: GAS は CommonJS 風で TypeScript Project References の output をそのまま import できない。
packages/engines/を GAS 側で利用するにはバンドラ (esbuild 等) の導入・設定が必須。Phase 3 着手前に bundler 選定 ADR を別途起案する
7. 撤退条件 (Rollback Plan)
各 Phase に独立した rollback 経路を設計し、Phase 間の依存を最小化:
| Phase | 撤退手順 | 想定所要時間 | 影響範囲 |
|---|---|---|---|
| Phase 1 | pnpm-workspace.yaml 削除のみで即時完全復旧 | ~5 分 | workspace 設定のみ (GAS / サブプロジェクト挙動影響なし) |
| Phase 2 | git revert + 各サブプロジェクト pnpm install 再実行 | ~30 分 | lock ファイル + CI 設定 |
| Phase 3 | Phase 2 完了時に必ず git tag monorepo-phase-2-stable を打つ。Phase 3 着手後の問題発生時はこの tag に復元 | ~1h | packages/ + import パス |
- 6 ヶ月後 KPI (下記 Confirmation) 達成不可: Phase 計画を見直し (Phase 間隔延長、scope 縮小、或いは tooling stack の部分変更) を検討。Phase 2 状態が安定している場合は Phase 2 で留まる選択肢を優先
8. Confirmation (準拠確認 / Fitness Function)
8.1 検証可能な完了条件 (6 ヶ月後 KPI)
3 LLM KPI 提案を統合。6 ヶ月後 (2026-11 頃) に評価:
| KPI | 測定方法 | 成功閾値 |
|---|---|---|
pnpm install 全 workspace 時間 | CI ログ | <=90 sec (cold) |
| Turbo cache hit rate | turbo run build --summarize JSON | >=60% |
| 共有依存バージョンドリフト数 | syncpack list-mismatches 週次 CI | 0 件 |
| Cross-package PR 比率 | GitHub label / git diff | >=30%/月 |
| Claude Code 探索パス修正回数 | grep -c "wrong directory" ~/.claude/projects/*/memory/*.md + Claude Code session ログの re-navigation 回数 | 50% 削減 (移行前 baseline を Phase 1 着手前に 2 週間計測) |
| GAS runtime 'unexpected module' エラー | Stackdriver ログ | 0 件 |
| 依存コンフリクト incident 数 | PR カウント | 0 件維持 |
8.2 Phase 別 中間 checkpoint
| Phase | 安定性判定基準 | 最低期間 |
|---|---|---|
| Phase 1 -> Phase 2 | CI green 連続 5 日以上 + pnpm install 全 workspace 成功 + GAS runtime エラー 0 件 | 1 週間 |
| Phase 2 -> Phase 3 | CI green 連続 2 週間 + incident 0 件 + turbo run build 全プロジェクト成功 + Remote Cache 接続確認 | 1 ヶ月 |
- Phase 1 完了条件: pnpm-workspace.yaml が valid、
pnpm installが全 workspace で成功、既存 CI が green - Phase 2 完了条件: 統一 lock ファイル、
turbo run buildが全プロジェクトで成功、Remote Cache 接続確認 - Phase 3 完了条件: sync-engines.mjs 廃止、TypeScript Project References で型チェック通過、全 import パス書換え完了
8.3 Fitness Function 3 要素
- 検証手段:
- 週次 CI に
syncpack list-mismatchesを組み込み、ドリフト 0 件を gate 化 turbo run build --summarizeの JSON output を CI artifact として保存、cache hit rate を月次集計pnpm install時間を CI ログから抽出し閾値超過時に warning- GAS Stackdriver で
unexpected moduleエラーをアラート設定
- 週次 CI に
- 実行頻度: 週次 (CI 自動), 月次 (KPI 集計), 6 ヶ月後 (総合 KPI レビュー), 1 年後 (Review After)
- 違反時の対応:
- KPI 単項目未達 -> 原因調査 + ADR 追記 (Phase 計画見直し)
- 6 ヶ月後 KPI 総合未達 -> Phase 計画見直し (Phase 間隔延長、scope 縮小、tooling 部分変更)
- GAS runtime エラー発生 -> 即時 Phase 1 rollback (~5 分)
9. 長期的影響
Review After: 2027-05-26 (1 年後)
- Phase 3 完了後に root (GAS) を workspace に含めるかの最終判断
- Turborepo -> 別ツール (Nx 等) への移行必要性を KPI で評価
- Jr 開発者の monorepo 運用習熟度を 1-on-1 で確認
負債化リスク
- Phase 2 で停滞するリスク: Phase 2 完了後に Phase 3 着手の動機が薄れ、sync-engines.mjs が「動いているから触らない」状態で残存。対策: Phase 2 完了時に Phase 3 着手予定日 (最遅 2027-02) を ADR に追記 + GitHub Issue を自動作成 (scheduled reminder)
- Turborepo EOL リスク: Vercel の Turborepo 開発優先度変更。ただし MIT ライセンスで fork 可能、pnpm workspace 自体は Turborepo 非依存
- pnpm メジャーバージョンアップ: Catalogs API の breaking change。ただし pnpm チームは後方互換性を重視する傾向
10. 参照 (References)
10.1 過去 ADR との関係
- Refines ADR-0019: drp のサブプロジェクト化 (ADR-0019 §2 で pnpm + 独立 lock を採用) が本 ADR の段階的 monorepo 化の先例。本 ADR は ADR-0019 の「サブプロジェクト独立管理」方針を「workspace 統合管理」に発展させる。Supersede ではない (ADR-0019 の Pipeline 移行決定自体は有効)
- Reuses ADR-0050: Q42 5 軸 + WSM + CBA K.O. フレームワーク。本 ADR で MCDA 加重和を適用
- Pattern-aligned with ADR-0054 / ADR-0058: Lint Rule Reference SSoT パターン -- monorepo 構造で SSoT の一元管理がさらに容易に
- Pattern-aligned with ADR-0065: 設計根拠 citation framework -- 本 ADR §10.2 で 5 タイプ citation 準拠
- No Supersede / No Conflict: 本 ADR は既存 ADR を上書き・矛盾させない
10.2 設計根拠 (Theoretical Foundation)
ADR-0065 §7.2 準拠、5 タイプ citation 形式:
- pnpm Workspaces -- pnpm 公式 workspace ドキュメント: https://pnpm.io/workspaces (canonical)
- pnpm Catalogs -- pnpm 公式 Catalogs ドキュメント: https://pnpm.io/catalogs (canonical)
- Turborepo -- Vercel 公式 Turborepo ドキュメント: https://turborepo.com/docs (canonical)
- Potvin & Levenberg (2016) -- Google の monorepo 運用実態: "Why Google Stores Billions of Lines of Code in a Single Repository", Communications of the ACM, Vol. 59, No. 7. DOI: 10.1145/2854146 (DOI)
- monorepo.tools -- monorepo ツール比較・ベストプラクティス集: https://monorepo.tools (canonical)
10.3 関連リソース
- RQ-053 Synthesis:
docs/_internal/01_discovery/research_prompts/RQ-053_monorepo_topology_synthesis.md - 3 LLM 調査結果:
docs/_internal/01_discovery/research_prompts/RQ-053_monorepo_topology_result_{claude,gemini,gpt}.md - PR #948 (Synthesis merged): commit
cfd4bbd - PR #933 (RQ-053 起案 + 3 LLM 結果): commit
cf64dde
11. Pipeline 審査履歴
11.1 初回審査 (2026-05-25, 順方向起案)
- 投入方法:
POST /drafts(id:adr-monorepo-pnpm-turborepo, retroactive: false) +POST /chat/start - Triage: Standard (monorepo 化による依存管理・ビルド効率・AI 探索効率の改善。段階的移行でリスクを抑制)
- Socratic: Pass (情報充足、追加質問なし)
- Consistency: PASS (既存 ADR との矛盾なし、Supersede 不要)
- Score: 47/50 (Standard 閾値 40 超過、Critical 閾値 45 超過)
| 採点項目 | 点数 | 改善対応 |
|---|---|---|
| 問題定義 | 4 | v2 で Phase 1 着手前に baseline 計測タスクを追記検討 |
| 代替案 | 5 | -- |
| 判断基準 | 5 | -- |
| 過去 ADR 整合性 | 4 | v2 で Refines ADR-0019 の具体記述を補強済 (§10.1) |
| 影響範囲 | 4 | v2 で §5.4 を軸別表に再構成済 |
| 運用上の罠 | 5 | -- |
| ロールバック性 | 5 | -- |
| コスト試算 | 5 | -- |
| 完了条件 | 5 | -- |
| 長期的影響 | 5 | -- |
- Parallel Review (3 モデル): Gemini / Claude / o3 の主要指摘と対応
- Claude Code 探索ミス率 KPI の主観性 (3 モデル共通) -> §8.1 で定量指標 (re-navigation 回数 + baseline 計測) に変更
- Phase 3 GAS bundling 戦略の欠如 (Gemini, Claude) -> §4.2 Phase 3 + §6 罠 #7 に esbuild/rollup 前提を明記
- Vercel Remote Cache データガバナンス (o3) -> §4.1 Remote cache 行に DPA 確認 + self-hosted フォールバック追記
- 工数見積もり過少リスク (o3) -> §5.5 で 1.5x バッファ込みに上方修正
- MCDA 係数設定根拠の不透明性 (Claude) -> §3.1 に係数設定根拠を追記
- Phase 進行判定の主観依存 (Claude) -> §8.2 に定量的安定性判定基準を追記
- 撤退時の案 A 転換矛盾 (Claude) -> §7 で Phase 計画見直しに修正 (案 A 自動転換を削除)