D ビジネス/PM — 手動レポート自動化 × OKR 設計 × KPI ツリー(GMV分解)× MoSCoW ロードマップ(MOps Bad→Good)

2026-06-11 (Day 66) 木曜 D: ビジネス/PM ★★★★☆ OKR / KPI ツリー / MoSCoW dbt + Looker Studio + Argo Workflows

概要

🎯

JTBD(Jobs to Be Done)で設計する

ユーザーが本当にやりたいのは「Excel を作ること」ではなく「キャンペーンの効果を判断して次の施策を決めること」。JTBD の視点で設計するとセルフサービスな BI ダッシュボードが正解になり、エンジニアのルーティン作業が不要になる。

📊

OKR は Output ではなく Outcome で設定する

「Looker Studio を構築する」は行動(Output)であり KR にならない。「ダッシュボード weekly active rate 80%」のように最終的な成果(Outcome)を KR に設定することで、ツール構築が目的化するのを防ぐ。

🌳

KPI ツリーで GMV のレバレッジポイントを特定する

GMV = 送信数 × 開封率 × CTR × CVR × AOV に分解することで、どの指標を 1% 改善したときの GMV インパクトが最大かを定量的に判断できる。ツリーなしに「開封率を上げよう」は根拠のない施策になる。

📋

MoSCoW で工数と価値のトレードオフを明示する

2スプリントの制約内で最大価値を届けるには「今回やらないこと(Won't Have)」を明示して合意する。Could Have を backlog に置き「なぜ今やらないか」を説明できることが PM スキルの核心。

問題

ECサイトの MOps チームは、毎週手動で「キャンペーン効果レポート」を Excel で作成しマーケ部門に共有している。現状の作業フローには 5つのプロセス上の問題 が潜んでいる。問題点を全て洗い出し、プロダクト思考 × データドリブン × OKR/KPI 設計 の観点で、自動化ロードマップと KPI ツリーを設計せよ。

制約・前提条件

  • 技術スタック: BigQuery, dbt, Looker Studio, Argo Workflows, Cloud Run, Pub/Sub
  • 予算: エンジニア工数 2スプリント(4週間)以内
  • ステークホルダー: マーケ部門マネージャー(非エンジニア)、配信マネージャー、エンジニア TL
  • KPI として「開封率」「CVR(クリック→購入)」「GMV 貢献額」「ROI」を追跡したい
  • 個人情報(メールアドレス)は BigQuery の列レベルセキュリティで保護済み
期待する回答形式: 問題点の列挙(番号付き)+ OKR設計 + KPI ツリー(GMV分解)+ 自動化ロードマップ(MoSCoW)+ 成功指標

悪い作業フロー (Before)

この週次レポートフローには 5つのプロセス上の問題 が隠れています。
bad_report_flow — 手動 Excel レポートフロー(毎週月曜)
毎週月曜の手動作業フロー:

# 問題①: 手動 SQL 実行 → CSV(15分)
エンジニアが BigQuery Console を開く
→ 毎週同じ SQL を手動コピペして実行
→ 結果を CSV にダウンロード

# 問題②: VLOOKUP による手動結合(30分)
マーケ担当が Excel に CSV を貼り付け
→ VLOOKUP でキャンペーン名と ID を結合
→ バージョン管理なし・ヒューマンエラーリスク大

# 問題③: Excel グラフ → PowerPoint(60分)
毎週同じグラフを手動で作り直す
→ 開封率・CTR・CVR・GMV の棒グラフ 4枚
→ PowerPoint に貼り付けてファイル命名

# 問題④: メール手動配信(BCC管理)
配信マネージャー・マーケ部門マネージャーに手動メール
→ 送付先 BCC を手で管理
→ 漏れ・誤送信リスクあり

# 問題⑤: 翌日に追加依頼(60分)
「先週比もほしい」と翌日連絡が来る
→ 要件定義漏れ → 再度手作業

合計: 約 2.5時間/週
関与者: エンジニア1名 + マーケ担当1名
問題点サマリー(5点)
1手動 SQL 実行・CSV ダウンロード — 繰り返し可能な処理がコード化されておらず、エンジニアがルーティン作業に毎週 15 分を消費。dbt + Argo Workflows CronWorkflow で自動化すべき
2VLOOKUP による手動結合 — データ結合ロジックが Excel に依存し、バージョン管理不可・ヒューマンエラーリスクがある。dbt の mart モデルで事前結合・テスト済みデータを提供すべき
3Excel グラフ → PowerPoint の手動作業 — 非エンジニアが自己解決できないツールセット。Looker Studio でセルフサービス化し、マーケが直接フィルタ・ドリルダウンできる状態にすべき
4メール手動配信(BCC 管理) — 送付先管理が属人化・手動であり漏れ・誤送信リスクがある。Looker Studio のスケジュール配信で自動化すべき
5要件定義漏れ(「先週比」が未実装) — 翌日の追加依頼は初期要件定義でステークホルダーの情報ニーズを聞き出せていなかったことを示す。6W3H ヒアリングで「月曜朝一番に見たい数字は何か」を問うべき

ヒント(段階的開示)

ヒント1 — 方向性
手動フローの最大の問題は「繰り返し可能な作業がコード化されていない」こと。エンジニアがルーティン作業に時間を取られるのはプロダクト開発の機会損失。「追加依頼が翌日に来る」という事実は、ダッシュボードを見れば自己解決できる質問がレポートのフォーマット不足で発生していることを示す。プロダクト思考では「ユーザーが本当に欲しいのは何か(JTBD)」を起点に設計する。
ヒント2 — アプローチ
  • 問題①: 手動 SQL 実行 → dbt CronWorkflow(Argo Workflows)で毎朝自動実行
  • 問題②: VLOOKUP 結合 → dbt の mart モデル(mart_campaign_kpi_weekly)で事前結合
  • 問題③: Excel グラフ → Looker Studio ダッシュボード(セルフサービス化)
  • 問題④: メール手動配信 → Looker Studio のスケジュール配信機能
  • 問題⑤: 「先週比」= LAG() ウィンドウ関数で dbt モデルに最初から実装
  • OKR: O = 「意思決定サイクルを週次→日次に短縮」、KR = 工数ゼロ + active rate 80%+
  • KPI ツリー: GMV = 送信数 × 開封率 × CTR × CVR × AOV で分解
ヒント3 — 設計の骨格
OKR 設計:
  O: MOps データ活用により、キャンペーン意思決定サイクルを
     週次 → 日次に短縮する
  KR1: レポート作成工数 2.5h/週 → 0h/週(自動化達成)
  KR2: 施策リードタイム(気づき→実施)7日 → 2日
  KR3: GMV 月次 KPI 達成率 85%(ベースライン 75%)
  KR4: ダッシュボード weekly active rate 80%以上

KPI ツリー(GMV 分解):
  GMV = 送信数 × 開封率 × CTR × CVR × AOV
    ├── 送信数:  セグメント精度 × 配信除外率管理
    ├── 開封率:  件名 A/B テスト × 送信時刻最適化
    ├── CTR:     CTA 配置 × パーソナライゼーション
    ├── CVR:     LP 速度 × クーポン割引率
    └── AOV:     バンドル提案 × レコメンド精度

MoSCoW(2スプリント):
  Must:   dbt mart モデル + CronWorkflow(Sprint 1)
  Should: Looker Studio ダッシュボード + スケジュール配信(Sprint 2)
  Could:  A/B テスト統計検定 / BigQuery ML 統合
  Won't:  リアルタイムストリーミング / ML 自動トレーニング

問題点分析(5点)

#問題点分類改善方法
1手動 SQL 実行・CSV ダウンロード(毎週 15分)自動化dbt + Argo CronWorkflow で毎朝自動実行
2VLOOKUP 手動結合(バージョン管理なし・エラーリスク)データ品質dbt mart モデルで事前結合 + Unit Tests
3Excel → PowerPoint の手動グラフ作成(60分/週)効率化Looker Studio セルフサービスダッシュボード
4メール手動配信(BCC 管理・属人化)信頼性Looker Studio スケジュール配信で自動化
5要件定義漏れ(先週比が未実装 → 翌日追加依頼)PM スキル6W3H ヒアリング + 前週比を dbt に最初から実装

アーキテクチャ図 — Bad フロー vs Good フロー

Bad フロー(手動 Excel レポート) ① エンジニアが手動で BQ SQL 実行 → CSV(15分/週) 毎週同じ SQL をコピペして実行 → 繰り返し可能な作業がコード化されていない エンジニアの開発時間を週 15 分奪う機会損失 ② Excel VLOOKUP でキャンペーン名と手動結合(30分/週) 結合ロジックが Excel に依存 → バージョン管理不可・ヒューマンエラーリスク VLOOKUP の参照先を間違えると KPI が全て誤った値になる ③ Excel グラフ作成 → PowerPoint 貼り付け(60分/週) 毎週同じグラフを手動で作り直す → 非エンジニアが自己解決できないツール マーケ担当者は自分でフィルタ・ドリルダウンができない ④ メール手動配信(BCC で送付先を手動管理) 属人化した BCC 管理 → 漏れ・誤送信・担当者異動時の引き継ぎ問題 人が増えるたびに手動で BCC リストを更新する必要がある ⑤ 翌日追加依頼「先週比がほしい」(60分/週・追加) 要件定義フェーズで「何を判断したいか」を聞き出せていなかった 6W3H ヒアリング未実施 → ステークホルダーの情報ニーズを網羅できていない 合計: 2.5時間/週の手作業コスト エンジニア + マーケ担当 2名が毎週消耗 年間 130時間 = エンジニア約 3週間分の機会損失 Good フロー(自動化 × セルフサービス BI) ① dbt CronWorkflow(Argo)で毎朝 07:00 自動実行 mart_campaign_kpi_daily: 日次 KPI(開封率/CTR/CVR/GMV + 前日比) mart_campaign_kpi_weekly: 週次 KPI(+ WoW前週比 / MoM前月比 を LAG で実装) 失敗時: Pub/Sub → Cloud Run → Slack 通知で即座に検知 ② dbt mart モデルで事前結合(VLOOKUP 廃止) ref('stg_campaigns') × ref('stg_orders') を SQL で結合 → 毎回同じ結果 dbt 1.8 Unit Tests で正常系/NULL/ゼロ送信数を自動検証 ③ Looker Studio ダッシュボード(セルフサービス BI) KPI スコアカード(GMV / 開封率 / CTR / CVR)+ 前週比 Scorecard マーケ担当がキャンペーン名・期間でフィルタ・ドリルダウンを自己解決 「先週比」を最初から実装 → 翌日追加依頼ゼロ ④ Looker Studio スケジュール配信で自動メール 毎週月曜 09:00 → 配信マネージャー・マーケマネージャーに自動送信 送付先は Looker Studio の設定で管理 → 属人化解消・漏れ・誤送信ゼロ ⑤ 6W3H 要件定義ヒアリングで追加依頼をゼロにする 「月曜朝一番に見たい数字は?」「その数字を見て何を判断する?」を事前確認 前週比・前月比・累計・予算比を要件として洗い出してから開発開始 dbt モデルに WoW/MoM カラムを最初から実装(LAG ウィンドウ関数) 成果: レポート工数 2.5h/週 → 0h/週 ① 自動化 ② データ品質保証 ③ セルフサービス BI ④ 自動配信 ⑤ 要件漏れゼロ → マーケが毎日データで意思決定 自動化

KPI ツリー — GMV 分解

GMV(月次貢献額) KR3: 月次 KPI 達成率 85% = 送信数 × 開封率 × CTR × CVR × AOV 送信数 セグメント精度 × 除外リスト 開封率(20%) 件名 A/B × 送信時刻最適化 CTR(3%) CTA 配置 × パーソナライズ CVR(8%) LP 速度 × クーポン割引率 AOV(¥4,200) バンドル × レコメンド セグメントビルダー精度 購買傾向スコア活用 配信除外精度 解除/バウンス管理 件名 A/B テスト 勝率 60%以上を維持 最適送信時刻 コホート別分析 CTA ボタン最適化 配置・色・文言 パーソナライズ精度 レコメンドアルゴリズム LP 読込速度 Core Web Vitals クーポン割引率 ROI との兼ね合い バンドル商品設計 送料無料閾値設定 クロスセル精度 関連商品レコメンド mart_campaign_kpi_daily / weekly 全 KPI カラム + WoW(前週比)LAG カラム + MoM(前月比)をこのモデルで提供

模範解答

■ Objective(四半期)
  MOps データ活用により、キャンペーン意思決定サイクルを
  「週次レポート依存」から「毎日データを見て即断できる体制」へ転換する

■ Key Results(3ヶ月後の計測指標)

  KR1: キャンペーンレポート作成工数 2.5h/週 → 0h/週
       計測方法: Jira チケット工数ログ(エンジニア)で確認
       現在値: 2.5h/週、目標: 0h/週
       ⚠️ NOTE: 「Looker Studio を構築する」は行動(Output)であり KR にならない
              「工数ゼロ」という成果(Outcome)を KR に設定する

  KR2: キャンペーン施策の気づき→実施リードタイム 7日 → 2日 以内
       計測方法: Jira の「アイデア起票日」→「キャンペーン配信日」の平均日数
       現在値: 平均 7日(週次レポート待ちが 5日を占める)

  KR3: GMV 貢献額の月次 KPI 達成率 85%以上(ベースライン: 75%)
       計測方法: mart_campaign_kpi_monthly.kpi_achievement_rate カラム
       計算式: SUM(actual_gmv) / SUM(target_gmv) × 100

  KR4: マーケ担当者のダッシュボード weekly active rate 80%以上
       計測方法: Looker Studio の利用統計レポート(設定 > スケジューラー > 利用統計)
       現在値: 0%(ダッシュボードが存在しないため)

■ カスケード(組織 → チーム → 個人)
  会社 OKR:    ECサイト GMV 前年比 +20%
    └── MOps チーム OKR: キャンペーン ROI を前年比 1.5倍に向上
          └── エンジニア個人 OKR: データ活用基盤の自動化率 100%(レポート工数ゼロ)
■ Must Have(Sprint 1 / 1〜2週目)
  ─────────────────────────────────────────────────────────────────────────
  M1: dbt mart モデル作成(mart_campaign_kpi_daily + mart_campaign_kpi_weekly)
    - 開封率・CTR・CVR・GMV の集計
    - 前週比カラム(WoW: LAG ウィンドウ関数)を最初から実装 ← 問題⑤の再発防止
    - 前月比カラム(MoM)も同様に実装
    - dbt 1.8 Unit Tests: 正常系 / ゼロ送信数 / NULL セグメント の3ケース以上
    - schema.yml: not_null テスト + unique_combination_of_columns テスト

  M2: Argo Workflows CronWorkflow 設定
    - 日次: 毎朝 07:00 JST(schedule: "0 22 * * *" UTC)→ mart_campaign_kpi_daily 更新
    - 週次: 毎週月曜 07:00 JST(schedule: "0 22 * * 0" UTC)→ mart_campaign_kpi_weekly 更新
    - 失敗時: Pub/Sub トピック publish → Cloud Run サブスクライバー → Slack #mops-alerts

■ Should Have(Sprint 2 / 3〜4週目)
  ─────────────────────────────────────────────────────────────────────────
  S1: Looker Studio ダッシュボード構築
    - KPI Scorecard: GMV / 開封率 / CTR / CVR(前週比の Δ% を色付きで表示)
    - キャンペーン別ファネル図(送信数 → 開封 → クリック → 購入の漏れ可視化)
    - フィルタ: キャンペーン名・送信日・商品カテゴリ(マーケが自己解決できる設計)
    - Blend Data: mart_campaign_kpi_daily JOIN campaign_master(名称表示)

  S2: Looker Studio スケジュール配信
    - 毎週月曜 09:00 → 配信マネージャー + マーケ部門マネージャーに PDF 自動送信
    - 送付先リストは Looker Studio の「スケジューラー設定」で管理(BCC 廃止)

  S3: マーケ担当者向け 1ページドキュメント(Notion)
    - ダッシュボードの見方・フィルタの使い方・FAQ 5問

■ Could Have(バックログ / 優先度中)
  ─────────────────────────────────────────────────────────────────────────
  C1: A/B テスト結果の統計的有意性チェック(χ²検定 / z-test)をダッシュボードに追加
  C2: BigQuery ML(ARIMA_PLUS)による GMV 予測トレンドライン表示
  C3: セグメント別 LTV 予測モデルの Looker Studio 統合

■ Won't Have(今回スコープ外 / 明示的に合意)
  ─────────────────────────────────────────────────────────────────────────
  W1: リアルタイムストリーミング分析(Pub/Sub → BigQuery Storage Write API)
      理由: 日次バッチで十分な意思決定サイクル。インフラコスト対効果が低い
  W2: 送信時刻最適化の ML 自動トレーニングパイプライン
      理由: 2スプリントで完成させるには範囲が広すぎる。Could Have に格下げ
  W3: 全メール配信の個人別最適化(1to1 マーケティング)
      理由: PII 管理・同意管理・BigQuery ML 統合が必要。専用スプリントが必要
-- models/mart/mart_campaign_kpi_weekly.sql
-- キャンペーン別 週次 KPI(開封率・CTR・CVR・GMV + 前週比・前月比)
-- 問題⑤の再発防止: WoW・MoM を最初から実装

{{
  config(
    materialized='incremental',
    incremental_strategy='insert_overwrite',
    partition_by={
      'field': 'week_start',
      'data_type': 'date',
      'granularity': 'day'
    },
    cluster_by=['campaign_id'],
    on_schema_change='fail'
  )
}}

WITH weekly_base AS (
  SELECT
    DATE_TRUNC(sent_date, WEEK(MONDAY))   AS week_start,
    campaign_id,
    COALESCE(campaign_name, '未設定')     AS campaign_name,  -- NULL 保護
    SUM(sent_count)                        AS sent_count,
    SUM(open_count)                        AS open_count,
    SUM(click_count)                       AS click_count,
    SUM(order_count)                       AS order_count,
    SUM(gmv_amount)                        AS gmv_amount,
    SUM(discount_amount)                   AS total_discount,
    SAFE_DIVIDE(SUM(discount_amount), NULLIF(SUM(gmv_amount + discount_amount), 0))
                                           AS discount_rate
  FROM {{ ref('stg_campaign_events') }}
  {% if is_incremental() %}
  WHERE sent_date >= DATE_SUB(
    (SELECT MAX(week_start) FROM {{ this }}),
    INTERVAL 14 DAY  -- 2週間ルックバック(遅延データ対応)
  )
  {% endif %}
  GROUP BY 1, 2, 3
),

with_rates AS (
  SELECT
    *,
    SAFE_DIVIDE(open_count,  sent_count)   AS open_rate,   -- 開封率
    SAFE_DIVIDE(click_count, open_count)   AS ctr,         -- クリック率
    SAFE_DIVIDE(order_count, click_count)  AS cvr,         -- CVR
    SAFE_DIVIDE(gmv_amount,  order_count)  AS aov,         -- 平均注文単価

    -- ──── 前週比(LAG ウィンドウ関数)← 問題⑤の再発防止 ────
    LAG(gmv_amount,  1) OVER (PARTITION BY campaign_id ORDER BY week_start)
      AS prev_week_gmv,
    LAG(open_count,  1) OVER (PARTITION BY campaign_id ORDER BY week_start)
      AS prev_week_open_count,
    LAG(order_count, 1) OVER (PARTITION BY campaign_id ORDER BY week_start)
      AS prev_week_order_count
  FROM weekly_base
)

SELECT
  week_start,
  campaign_id,
  campaign_name,
  sent_count,
  open_count,
  click_count,
  order_count,
  gmv_amount,
  total_discount,
  discount_rate,
  open_rate,
  ctr,
  cvr,
  aov,

  -- 前週比(WoW: Week over Week)
  SAFE_DIVIDE(gmv_amount - prev_week_gmv, NULLIF(prev_week_gmv, 0))
    AS wow_gmv_change,          -- Looker Studio の Scorecard の Δ% に使用
  SAFE_DIVIDE(
    SAFE_DIVIDE(open_count,  sent_count) -
    SAFE_DIVIDE(prev_week_open_count, LAG(sent_count, 1) OVER (PARTITION BY campaign_id ORDER BY week_start)),
    NULLIF(SAFE_DIVIDE(prev_week_open_count, LAG(sent_count, 1) OVER (PARTITION BY campaign_id ORDER BY week_start)), 0)
  )                             AS wow_open_rate_change,

  CURRENT_TIMESTAMP()           AS _loaded_at
FROM with_rates

dbt 1.8 Unit Tests(schema.yml)

# models/mart/schema.yml(unit_tests ブロック)
unit_tests:
  - name: test_mart_campaign_kpi_weekly_normal
    description: 正常系: 2週分のデータで前週比を正しく計算するか検証
    model: mart_campaign_kpi_weekly
    given:
      - input: ref('stg_campaign_events')
        rows:
          # 前週
          - {sent_date: "2026-06-01", campaign_id: "CMP-001", campaign_name: "梅雨セール",
             sent_count: 1000, open_count: 200, click_count: 30, order_count: 6,
             gmv_amount: 30000, discount_amount: 3000}
          # 今週
          - {sent_date: "2026-06-08", campaign_id: "CMP-001", campaign_name: "梅雨セール",
             sent_count: 1200, open_count: 276, click_count: 42, order_count: 9,
             gmv_amount: 45000, discount_amount: 4500}
    expect:
      rows:
        - {week_start: "2026-06-08", campaign_id: "CMP-001",
           sent_count: 1200, open_count: 276, gmv_amount: 45000}

  - name: test_mart_campaign_kpi_weekly_zero_sent
    description: 送信数ゼロの場合、open_rate / ctr / cvr が NULL になるか検証(SAFE_DIVIDE)
    model: mart_campaign_kpi_weekly
    given:
      - input: ref('stg_campaign_events')
        rows:
          - {sent_date: "2026-06-08", campaign_id: "CMP-002", campaign_name: "テスト",
             sent_count: 0, open_count: 0, click_count: 0, order_count: 0,
             gmv_amount: 0, discount_amount: 0}
    expect:
      rows:
        - {campaign_id: "CMP-002", open_rate: null, ctr: null, cvr: null, aov: null}

  - name: test_mart_campaign_kpi_weekly_null_name
    description: campaign_name が NULL の場合 '未設定' に変換されるか検証(COALESCE)
    model: mart_campaign_kpi_weekly
    given:
      - input: ref('stg_campaign_events')
        rows:
          - {sent_date: "2026-06-08", campaign_id: "CMP-003", campaign_name: null,
             sent_count: 500, open_count: 100, click_count: 15, order_count: 3,
             gmv_amount: 15000, discount_amount: 1500}
    expect:
      rows:
        - {campaign_id: "CMP-003", campaign_name: "未設定", sent_count: 500}

成功指標とアラート設定

指標計測方法目標値アラート閾値
レポート作成工数Jira チケット工数ログ0h/週>30分/週で確認
施策リードタイムJira: 起票日→配信日の平均2日以内>5日でレビュー
ダッシュボード WARLooker Studio 利用統計80%以上<60%で改善検討
dbt パイプライン成功率DataDog Monitor(CronWorkflow)99%以上<95%でアラート
GMV KPI 達成率mart_campaign_kpi_monthly85%以上<75%でレビュー
ダッシュボード freshnessDataDog: _loaded_at の鮮度監視2時間以内>4時間でアラート

リスクと対策

リスク影響対策
R1: マーケ担当者がダッシュボードを使わないKR4 未達週次「ダッシュボード輪読会」を1ヶ月実施し習慣化。Slack に Looker Studio URL を毎朝自動投稿
R2: dbt モデルのデータ品質問題KPI 数値が誤る → 信頼失墜dbt Unit Tests + generic tests + DataDog freshness 監視 + 週次データ品質レビュー
R3: 追加要件の scope creep2スプリント超過MoSCoW で優先順位を可視化し Could Have を backlog に積む。スプリントレビューで優先度を再判断
R4: Looker Studio が BigQuery コストを増加させる月次 GCP コスト超過mart テーブルに partition_by + cluster_by を設定しパーティション剪定を有効化

6W3H ステークホルダーヒアリングテンプレート

# キャンペーンレポート 要件定義ヒアリングシート(6W3H)

## Who: 誰がこのレポートを使うか?
- 主要ユーザー: 配信マネージャー、マーケ部門マネージャー
- 副次ユーザー: エンジニア TL(dbt モデルの品質確認)

## What: 何を見たいか?(← ここで「先週比」を漏らさないための質問)
- KPI: 開封率・CTR・CVR・GMV 貢献額・ROI・割引率
- 比較軸: 前週比・前月比・予算比・キャンペーン間比較
- 粒度: 日次 / 週次 / 月次
- ドリルダウン: キャンペーン名 → 商品カテゴリ → ユーザーセグメント

## When: いつ見るか?
- 定期レポート: 毎週月曜 09:00(週次振り返りミーティング前)
- 臨時確認: 配信後 24時間(効果の速報確認)
- リアルタイム性: 日次バッチで十分か?(→ Yes: コスト削減可)

## Where: どこで見るか?
- デバイス: PC(主)/ スマホ(モバイル対応必要?)
- ツール: Looker Studio ダッシュボード + 週次 PDF メール配信

## Why: なぜそのKPIが重要か?
- GMV: キャンペーン ROI の最終指標
- 開封率: セグメント精度・件名 A/B テストの評価軸
- CVR: LP 改善・クーポン設計の評価軸

## How: どのように意思決定するか?
- 「開封率が先週比 -5% なら件名 A/B テストを起動」
- 「CVR が 5%を下回ったらクーポン割引率を +5% 検討」
- 「GMV KPI 達成率が 75%を下回ったら TL にエスカレーション」

## How many: どのくらいの規模か?
- 月間キャンペーン本数: 約 30〜50 本
- 送信リスト規模: 最大 50 万件/送信
- ダッシュボード利用者数: 5〜10 名

## How much: コストはどれくらい許容できるか?
- BQ クエリコスト: 月 ¥5,000 以内
- 開発工数: エンジニア 2スプリント(4週間)以内

## ─── 追加確認(「先週比」漏れ防止の必須質問)───────────────────────────
Q: 「月曜の朝一番に見たい数字は何ですか?」
A: GMV と開封率 → 「先週より上がったか下がったか」を一目で知りたい
   ↑ ここで「前週比が欲しい」が判明 → mart モデルに WoW カラムを最初から実装

Q: 「その数字を見て次に何をしますか?」
A: 開封率が低ければ件名 A/B テストを起動 / CVR が低ければ LP 確認
   ↑ ダッシュボードに「判断のための文脈」(比較軸・閾値線)を追加する設計に反映

ポイント解説

1 JTBD(Jobs to Be Done)でプロダクトを設計する
ユーザーが「Excel レポートを作ってほしい」と言うとき、本当にやりたいのは「レポートを作ること(手段)」ではなく「キャンペーンの効果を判断して次の施策を決めること(目的)」。JTBD フレームワークでは「誰が・どんな状況で・何を達成したいか・なぜ今の手段では不十分か」を問う。手段レベルで設計すると「より良い Excel を作る」になり、目的レベルで設計すると「セルフサービス BI ダッシュボード」になる。
2 OKR の KR は Output(行動)ではなく Outcome(成果)で設定する
「Looker Studio ダッシュボードを構築する」は Output(行動)であり KR にならない。ダッシュボードを構築しても誰も使わなければ意味がない。「マーケ担当者の weekly active rate 80%以上」という Outcome を KR にすることで、ツール構築が目的化するのを防ぎ「使われるダッシュボード」を設計する動機が生まれる。OKR は「測定可能・期限付き・挑戦的」の3条件を満たすことが重要。
3 KPI ツリーでレバレッジポイントを定量判断する
GMV = 送信数 × 開封率 × CTR × CVR × AOV に分解することで、どの指標を 1% 改善したときの GMV インパクトが最大かを計算できる。例: 送信数が 100万通・開封率 20%・CTR 3%・CVR 8%・AOV ¥4,200 のとき、CVR を 1% 上げると GMV が CVR/現CVR = 1/8 = 12.5% 増加し、AOV を 1% 上げると 1% 増加。CVR のレバレッジが最大と判断できる。ツリーなしに「開封率を上げよう」は根拠のない施策になる。
4 MoSCoW で「今回やらないこと」を明示して合意する
Won't Have を明示することが MoSCoW の最も重要な機能。「A/B テストの統計的有意性チェック(χ²検定)は価値があるが今回はやらない。理由: 2スプリントに収まらない」という合意を事前にとることで、スプリント中の scope creep を防ぐ。「今やらない理由」を説明できることが PM スキルの核心であり、Could Have を backlog に積んで次のスプリントレビューで優先度を再評価するプロセスが重要。
5 「追加依頼を防ぐ」要件定義スキル
「先週比がほしい」という翌日の追加依頼は、初期ヒアリングで防げた。「月曜の朝一番に見たい数字は何ですか?」→「GMV が先週より上がったか下がったか」という回答から、前週比が必要だと判明する。このヒアリングを行わずに開発を開始したことが根本原因。6W3H フレームワーク(Who/What/When/Where/Why/How/How many/How much)でステークホルダーの情報ニーズを網羅的に洗い出す。技術的には dbt モデルに LAG(gmv_amount, 1) OVER (PARTITION BY campaign_id ORDER BY week_start) を最初から実装することで、翌日の再作業を回避できる。

実務への応用

  • dbt mart + Looker Studio の連携: mart_campaign_kpi_weeklywow_gmv_change(前週比)・mom_gmv_change(前月比)カラムを最初から実装しておくことで、Looker Studio 側でカスタム計算フィールドを増やす手間を削減できる。複雑なロジックは dbt 側で処理し、Looker Studio は「表示」に専念させる設計が保守性を高める。
  • Argo Workflows CronWorkflow: schedule: "0 22 * * 0"(UTC 日曜 22:00 = JST 月曜 07:00)で週次 dbt run を定期実行。successfulJobsHistoryLimit: 3failedJobsHistoryLimit: 3 を設定して Argo UI のログゴミを防ぐ。retryStrategy.limit: "2" で失敗時の自動再試行も実装する。
  • OKR のカスケード: 会社 OKR「GMV 前年比 +20%」→ MOps チーム OKR「キャンペーン ROI 1.5倍」→ エンジニア個人 OKR「データ活用基盤の自動化率 100%」というカスケードを意識して設計すると、個人の作業が会社目標に紐づき優先順位の説明が容易になる。四半期ごとに OKR の達成度を振り返り、KR の設定が適切だったかを評価するレトロスペクティブを実施する。
  • Looker Studio スケジュール配信のコスト管理: スケジュール配信は毎回 BigQuery にクエリを発行する。partition_by=week_start + cluster_by=[campaign_id] を設定しておくことで、週次レポートのスキャン量を直近 4週分に限定できる。配信頻度と BQ コストのトレードオフを考慮した設計が必要。

今日のまとめ

手動レポートの自動化は「ツールを作ること」が目的ではなく「ステークホルダーが毎日データを見て意思決定できる状態を作ること」が目的であり、KPI ツリー(GMV 分解)と OKR(成果指標)を起点に MoSCoW でスコープを絞ることで、2スプリントの制約内で最大価値を届けるプロダクト設計が可能になる。

「先週比がほしい」という追加依頼を防ぐためには、初期要件定義で「月曜の朝一番に見たい数字は何か」と問うことが最も効果的な PM スキルであり、dbt の LAG() ウィンドウ関数で前週比を最初から実装することで技術的な再作業コストをゼロにできる。

自己評価

自分の回答

気づき・メモ