SOLUTION ARCHITECTURE · DESIGN PROPOSAL v4

SF改修 → BQ / ダッシュボード
影響事前検知システム 設計提案

Salesforceの宣言的なスキーマ変更が、後続のBigQuery・経営コクピットのダッシュボードを「壊れてから気づく」状態を解消する。依存関係の地図(辞書)自動スキーマ差分検知を土台に、データチーム側だけで完結して動かす。

ステータス: 2026-05-20 西川 承認 → v4改訂 対象: 西川・稲川・SFチーム・琴哉・経営/デジセン
How to read

読み方・凡例

凡例
  • 結論ファースト: 各章は「要は何か(So What)」を先に置き、根拠は小さく添える
  • 確信度: ★★★A 一次情報(コード/データ実体) / ★★B 二次情報(本人回答・部分確認)
  • 2つの依存経路: Path A=SF→SQL→…→ダッシュボード(SQL経由) / Path B=ダッシュボードのGASがSFを直読み(SQLを通らない近道)
Section 1 · Problem

課題:要は何が問題なのか(結論ファースト)

SFのUI変更が「見えない依存」を通って後続を沈黙的に壊す。
根因は依存関係が地図化されておらず、変更を捕まえる自動の仕組みが無いこと。
① 検知不在事前も事後も変更を捕まえる仕組みが無い。依存の地図そのものが存在しない
② 沈黙故障項目リネームはエラーにならずNULL化。気づくのは「ダッシュボードが変」と人が言った後
So What(だから何が必要か) 対症療法(壊れたら直す)では追いつかない。(1) SF項目→BQ→ダッシュボードの依存を地図化し、(2) 変更を自動で捕まえて、(3) 影響と直し方を提示してBQチームに通知する ——この3点が揃って初めて「事前に防ぐ」が成立する。

根拠(確認済みファクト・補足)

事故は既発生2026-04-16 SurveyLpCurrentGoal__cSurveyLpConcerns__c のリネームを integrated_customer_analytics.sql 等でCOALESCEで事後対応した痕跡 ★★★A
2系統の依存Path A: SF→staging_*(毎時)→…→ダッシュボード。Path B: org-coaching.gsOrganizationalCoaching__c を直読み ★★★A
選択肢値依存org-coaching.gsStageName__c の選択肢値9個を IN(...) でハードコード→値リネームで破壊 ★★★A
土台は揃うsf_utils.py でSFスキーマ全取得可、Slack/Backlog即通知可、コクピットGASはパース可能 ★★★A
変更手段SF変更は基本「管理画面の宣言的UI変更」=デプロイ・履歴・レビューが存在しない ★★B
Section 2 · Architecture

推奨アーキテクチャ(理想形)

設計の核は 依存関係の地図(辞書)を土台に置き、2方向の入口(事後の自動検知/事前の人間起点)から同じ1つの出口(影響の提示+通知)へ繋ぐこと。

flowchart TB
    classDef core fill:#e8eef7,stroke:#1A365D,color:#1A365D
    classDef auto fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef human fill:#ede9fe,stroke:#7c3aed,color:#4c1d95

    subgraph BASE["土台:依存関係の地図(辞書)"]
        psql["SQLを読み解いて依存を抜き出す"]:::core
        pgas["コクピットGASを読み解いて依存を抜き出す"]:::core
        dg["依存の地図(辞書)
『この項目を変えたら、どのBQ表・SQL・
ダッシュボードのKPIが倒れるか』を引ける"]:::core psql --> dg pgas --> dg end subgraph AUTO["事後(自動・必須):SF変更を毎時みはる"] snap["describe で SFの設計図
(項目・型・選択肢値)を読み取る"]:::auto diff["前回と差分をとる
(消えた / 増えた / 型変更 / 選択肢値変更)"]:::auto snap --> diff end subgraph PRE["事前(人間):既存の依頼フローを拡張"] form["既存:依頼フォーム→Backlog→Slack→Claude要件Q&A"]:::human lookup["変更前に影響を引く /sf-impact (Slack)"]:::human end engine["影響を照合する
変更 × 依存の地図"]:::auto act["影響と直し方をまとめて知らせる
Claude修正案 + Slack通知 + Backlog起票"]:::auto dg --> engine diff --> engine form --> engine lookup --> engine engine --> act
図1:依存の地図(土台)の上に、事後(自動)と事前(人間)の2入口が共通エンジン→出口へ繋がる
So What 土台(依存の地図)+自動検知を先に作れば、人が何を忘れても事故は激減する。 事前の入口(既存フォーム拡張・Slackルックアップ)は「より早く・上流で」捕まえる付加価値。土台はあくまで地図と自動検知。
運用の独立性(重要) 毎時自動で検知するので、SFチームに「デプロイ前に確認して」と依頼する必要がない。検知・差分・通知・起票はraftel(データチーム)側で完結して動く。必要なのは最初のSF接続認証(Connected App/JWT)の設定だけ。=相手チームの運用を変えずに今すぐ始められる。
Section 3 · Operational Flow

業務フローとシーケンス

運用は2つの流れ。事後(安全網)=SF変更が起きたら自動で検知して通知。事前(上流)=開発依頼フォームでSF項目変更の意図を検知したら、影響を要件Q&Aにインライン提示してBQチームへ事前連携。

フロー① 事後(自動の安全網)

sequenceDiagram
    autonumber
    actor admin as SF変更者
    participant sf as Salesforce
    participant sys as 検知システム(raftel)
    participant dg as 依存の地図
    participant slack as Slack(西川/稲川)
    participant bl as Backlog
    admin->>sf: 項目/選択肢値をUI変更
    loop 毎時
        sys->>sf: describe で設計図を読み取る
        sys->>sys: 前回スナップと差分をとる
    end
    sys->>dg: 変更項目/値を照合
    alt 後続に影響あり
        dg-->>sys: 影響先(SQL・ダッシュボード・KPI)
        sys->>slack: 影響 + Claude修正案を通知
        sys->>bl: SYSDEVREQ に自動起票
    else 影響なし
        sys->>sys: 記録のみ(通知しない=ノイズ抑制)
    end
        
図2:SF変更を毎時の差分で検知し、地図に当たった時だけ通知・起票する

フロー② 事前(依頼インテイク拡張)

sequenceDiagram
    autonumber
    actor req as 依頼者
    participant form as 開発依頼フォーム
    participant claude as ClaudeCode(要件Q&A)
    participant dg as 依存の地図
    participant slack as Slack(西川/稲川)
    req->>form: 開発依頼を送信
    form->>claude: Backlog起票 + 要件整理を開始
    claude->>claude: SF項目変更の意図を検知
    alt SF項目変更を含む
        claude->>dg: 変更前に影響を引く
        dg-->>claude: 影響先一覧
        claude->>req: 要件Q&Aに影響をインライン提示
        claude->>slack: 西川/稲川へ事前連携
    else 通常依頼
        claude->>req: 通常の要件Q&A
    end
        
図3:既存の依頼フロー(稼働中)にSF影響ブランチを差し込む。新ツールは増やさない
Section 4 · How it works

仕組みの具体例(describe / 依存の地図)

① describe=「SFの設計図を読み取る」

あるオブジェクト(テーブル相当)の全項目の仕様(設計図)を一発で取るSFの機能。sf_utils.py が裏で SF CLI を叩いて返す。これを毎時取って前回と比べる=検知の心臓。

# describe("OrganizationalCoaching__c") が返す1項目の例
{
  "name": "StageName__c",        // API名(リネーム検知の主キー)
  "label": "商談フェーズ",         // 画面表示名
  "type": "picklist",            // 型(変更を検知)
  "custom": true,
  "nillable": true,
  "picklistValues": [             // ← 選択肢値(StageName__c問題の検知)
    {"label": "担当者ビジネスMTG", "active": true},
    {"label": "フロント受注", "active": true}, ...
  ]
}
ポイントdescribe は設計図を読み取るだけ。SF管理画面でUI変更しても変更後の設計図に反映される → UI運用のままで検知できる

② 依存の地図(dependency-graph.json)=「何が倒れるかを引ける辞書」

「SFのこの項目を変えたら、どのBQテーブル・SQL・ダッシュボードのどのKPIが倒れるか」を機械が引ける地図(辞書)。SQL/GASをパースして自動生成し、手では持たない(CIで再生成=腐らせない)。

// 変更項目をキーに引くと、影響先(consumed_by)が一覧で返る
{
  "OrganizationalCoaching__c.StageName__c": {
    "type": "picklist",
    "使われている選択肢値": ["担当者ビジネスMTG", "フロント受注", "本契約受注"],
    "consumed_by": [
      { "経路": "B(GAS直結)",
        "資産": "management-cockpit/org-coaching.gs",
        "KPI": ["組織コーチング_ファネル各段階"] }
    ]
  },
  "Lead__c.SurveyLpConcerns__c": {
    "type": "picklist",
    "consumed_by": [
      { "経路": "A(SQL経由)", "資産": "sql/staging/staging_Lead__c.sql" },
      { "経路": "A(SQL経由)", "資産": "sql/analytics/integrated_customer_analytics.sql" },
      { "経路": "A(SQL経由)", "資産": "management-cockpit/carispi.gs", "KPI": ["キャリスピ商談フェーズ"] }
    ]
  }
}
使い方変更項目をキーに引く→ consumed_by が影響先一覧。これが「何をどう直すか提案」の事実の源。LLMはこの事実を文章化するだけで、依存を推測させない。
Section 5 · Implementation Gaps

実装論点:現状から理想形への差分

「当初の2ポイント案(①依頼フォーム連携 ②デプロイ前テスト)」で既に実現できている点も含め、理想形に対して何が足りないか=何を実装するかを差分で整理する。

論点現状(当初2点で実現済み含む)理想形への差分=実装すること
① 依存の地図(土台)無い。依存の地図そのものが存在しない。当初案の「事前用意の辞書」は着想として◎SQL+GASをパースして自動生成。Path A/B・選択肢値もカバー。これが全部の土台
② 自動差分検知(事後)無い。当初Point2は「デプロイ前テスト」を意図したが、SFはUI変更中心でデプロイが存在しないdescribe 毎時スナップ→差分に作り替え。人手非依存の安全網。リネームは「旧消滅+新出現」、選択肢値も差分
③ 事前トリガ(依頼拡張)フォーム→Backlog→Slack→Claude要件Q&Aは稼働中(当初Point1で実現済み・SYSDEVREQ-1679)SF項目変更を検知→影響をQ&Aにインライン提示+事前連携。Slack /sf-impact 追加
④ アクション層Slack/Backlog即実行可(西川/稲川ID既知)決定論の影響+Claude修正案を生成し自動起票・通知(LLMは提案文に限定)
UX観点(So Whatで要約) 新しいポータルを作らず、既存導線(Slack/フォーム)に溶かす。 SF変更者はCLIを使わない前提で、依頼Q&Aが自動で影響を出す+/sf-impactで即答。BQチームには「影響+修正案+課題ワンクリック」、依頼者の体験は劣化させない。
運用保守観点(So Whatで要約) 依存の地図はコードからCI再生成(手で持たない=腐らせない)。 検知はCloud Run Jobで毎時(日次ダッシュ更新前に通知)。前提はSF接続認証(Connected App/JWT)。リポ境界は「検知コア=raftel/インテイク=別リポ」。
QA上の急所(事故らせない) 偽陰性を最優先で潰す:①リネームは沈黙NULL化→差分で必ず捕捉、②選択肢値ハードコード→picklist値も差分、③静的パースで漏れる経路(動的補間/clasp外Sheets/KUZEN)は「未カバー」と正直に明示し段階拡張。偽陽性(通知疲れ)対策:地図に当たった変更のみ通知、99%+NULLの死蔵473項目は除外。受入条件=2026-04-16事故の再現で影響先が正しく出ること。
Section 6 · Roadmap

段階導入ロードマップ

0

Phase 0(土台): 依存の地図 + 検知エンジン

  • raftel SQL/コクピットGAS(CIでclone)をパース→ SF項目・選択肢値・Path A/B を抽出
Exit: 2026-04-16事故カラム投入→影響先(SQL群+4ダッシュボード)を正しく列挙
1

Phase 1(安全網): 自動差分検知+通知

  • describe 毎時スナップ→差分→照合→Slack通知。死蔵473項目は除外、BQ失敗監視も併設
Exit: SFテスト項目/選択肢値の変更→1時間以内にSlackアラート
2

Phase 2(提案+起票): アクション層

  • 影響先(決定論)+Claude修正案→Backlog自動起票・担当割当
Exit: アラートに「何をどう直すか」が付く
3

Phase 3(上流): 既存依頼インテイク拡張

  • フォームのClaude Q&AにSF影響ブランチ+Slack /sf-impact(前提: インテイク基盤リポ確立)
Exit: 依頼の入口でSF影響が見える/変更前セルフチェック可
+

(任意・おまけ): SFDX/GitHub化 + 契約ビュー層

  • SFをSFDX化して検知をデプロイ前ゲートへ昇格(下記おまけ章参照)。安定列名の契約ビューで結合を1箇所に集約
まず取る一手Phase 0→1 だけで「事故が激減する自動の安全網」が、データチーム側だけで完結して立ち上がる。ここが準備度×インパクトの高いクイックイン。
▼ ここから「おまけ(任意)」— 今回のアーキには必須ではない。価値を実証した後に効いてくる中長期の上積み。
Optional / おまけ

おまけ:SFDX / GitHub化 — 土台が活きる「もう一段上」

SFDXは、SFの設定(項目・フロー等)をコード化してGitHubで管理するやり方。今回の検知システムはSFDX無しで完結するが、SFDX化すると検知が「事後の網」→「デプロイ前ゲート」に昇格し、事故を構造的に潰せる。

BQ連携以外に、どんな恩恵があるか

UIのまま続けるリスク

  • 誰が・いつ・何を変えたか履歴が残らない
  • レビュー・承認なしで即本番反映
  • 変更前に影響もテストも確認できない
  • ロールバックが手作業・属人化

SFDX+GitHub管理の恩恵

  • 変更がコード化→履歴・差分・レビューが効く
  • デプロイ時にCIゲート=検知が事前ゲートに昇格
  • ロールバック・複数人並行が安全に
  • AIが差分を読んで自動レビュー・修正できる
どのくらいクリティカルか 今すぐ必須ではない。が、人とAIの分担を進め、AI代替活用度を本格的に上げる段で効く中長期の本丸。設定がコード化されて初めてAIがレビュー・修正・テストを肩代わりできる。まずデジセン内部でやりきり価値を示すのが先。

UI → SFDX へ移行するステップ(ざっくり)

ステップ内容工数感
1. 環境準備SF CLI + GitHubリポ + 接続認証数日(技術)
2. 現状をコード化既存の項目・フロー等を取り出してGit管理に載せる1〜2週(技術)
3. 運用切替+CIUI直変更をやめ「ブランチ→レビュー→デプロイ」へ。GitHub Actionsで自動チェック。+SFチームのトレーニング(最大の山)数週〜数ヶ月
4. 段階移行一部のオブジェクト/フローから試して拡大継続
越え方(他チームを巻き込む) 技術構築(1〜3)はエンジニア1人で1〜2ヶ月の桁。本当のコストはSFチームの習慣変更。だから正論で一気に押さず、①内部で価値実証 → ②低摩擦な接点(/sf-impact)だけ渡す → ③必要性を体感させる → ④段階移行。Whyを腑に落としてからHow。
Appendix

付録:再利用資産・検証・リスク

再利用する既存資産

SFスキーマ取得/picklistscripts/sf_utils.py
Slack/Backlog通知・起票scripts/slack_utils.py, scripts/backlog_utils.py
BQ SQL(パース対象)bq_schedule_query/sql/{staging,marts,analytics}/*.sql
ダッシュボードGAS(パース対象)mizukara-corp/management-cockpit/scripts/*.gs
既存インテイク参照Backlog SYSDEVREQ-1679、Slack C0851DE6QEB
CF/CI雛形・死蔵項目cloud_functions/slack_engagement_ingest/, docs/GitHubActions構築.md, docs/sf-null-rate-scan.md

検証方法

1ゴールデン再現: SurveyLpCurrentGoal__cStageName__c値 投入→影響SQL・4ダッシュボードが正しく出るか
2picklist差分: サンドボックスで選択肢値を1つリネーム→検知されるか
3describe差分: SFテスト項目変更の前後スナップ差分検知(Phase1 Exit)
4腐敗テスト: SQL/GASに新列追加PR→CIで地図が自動再生成されるか

未解決リスク・要確認

  • SF接続認証(Connected App/JWT)の整備可否=自動検知の前提(これだけはデータチーム側で要設定)
  • リポ配置の合意: 検知コア=raftel_gcp、インテイク拡張=新設リポ の境界でよいか
  • インテイク基盤リポ(琴哉さん)の確立タイミング=事前トリガ(Phase3)の前提
  • 未カバー消費先: clasp外Connected Sheets・KUZEN・n8n のカバー要否と優先度
  • SFDX化(おまけ): 着手するかは全社DX文脈での別途意思決定