Skip to content

プロジェクト予算管理

概要

プロジェクト単位で予算上限を設定し、Issue報酬の消化状況をリアルタイムに把握する。予算超過・進捗遅延を早期検知してアラートを発行する。


1. プロジェクト予算上限の設定

1.1 予算設定ルール

項目説明
設定権限マネージャーのみ
設定タイミングプロジェクト作成時、または任意のタイミングで変更可能
単位
変更履歴全て記録(監査対応)

1.2 予算の構成

プロジェクト予算上限(budget_limit)
├── 確定済み消化額(confirmed_total)  ... confirmed + paid の報酬合計
├── 保留中消化額(pending_total)      ... pending の報酬合計
├── 予約済み消化額(active_total)     ... active の報酬合計
└── 残予算(remaining)               ... budget_limit - (confirmed_total + pending_total + active_total)

2. 消化額のリアルタイム集計ロジック

2.1 消化額の定義

sql
-- 消化額(支払い確定 + 保留中)
SELECT
  SUM(CASE WHEN status IN ('confirmed', 'paid') THEN amount ELSE 0 END)
    AS confirmed_total,
  SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END)
    AS pending_total,
  SUM(CASE WHEN status = 'active' THEN amount ELSE 0 END)
    AS active_total,
  SUM(CASE WHEN status IN ('confirmed', 'paid', 'pending', 'active') THEN amount ELSE 0 END)
    AS total_consumed
FROM rewards
WHERE project_id = :project_id;

2.2 各指標の算出

指標計算式
残予算budget_limit - (confirmed_total + pending_total + active_total)
予算消化率(confirmed_total + pending_total) / budget_limit * 100
Issue消化率completed_issues / total_issues * 100

注: 予算消化率の分子には active を含めない。確定的な消化(confirmed + pending)のみで算出する。active は参考値として別途表示する。

2.3 集計クエリ

sql
-- プロジェクト予算サマリー
SELECT
  p.id AS project_id,
  p.name AS project_name,
  p.budget_limit,
  COALESCE(r.confirmed_total, 0) AS confirmed_total,
  COALESCE(r.pending_total, 0) AS pending_total,
  COALESCE(r.active_total, 0) AS active_total,
  p.budget_limit - COALESCE(r.confirmed_total, 0)
    - COALESCE(r.pending_total, 0)
    - COALESCE(r.active_total, 0) AS remaining_budget,
  ROUND(
    (COALESCE(r.confirmed_total, 0) + COALESCE(r.pending_total, 0))
    * 100.0 / NULLIF(p.budget_limit, 0), 1
  ) AS budget_consumption_rate,
  ROUND(
    i.completed_count * 100.0 / NULLIF(i.total_count, 0), 1
  ) AS issue_completion_rate
FROM projects p
LEFT JOIN (
  SELECT
    project_id,
    SUM(CASE WHEN status IN ('confirmed', 'paid') THEN amount ELSE 0 END) AS confirmed_total,
    SUM(CASE WHEN status = 'pending' THEN amount ELSE 0 END) AS pending_total,
    SUM(CASE WHEN status = 'active' THEN amount ELSE 0 END) AS active_total
  FROM rewards
  GROUP BY project_id
) r ON r.project_id = p.id
LEFT JOIN (
  SELECT
    project_id,
    COUNT(*) AS total_count,
    COUNT(*) FILTER (WHERE status = 'closed') AS completed_count
  FROM issues
  GROUP BY project_id
) i ON i.project_id = p.id;

3. アラート設計

3.1 予算超過アラート

レベル条件アクション
注意予算消化率 >= 70%マネージャーに通知
警告予算消化率 >= 90%マネージャー + PMに通知
危険残予算 < 0(超過)新規Issue報酬設定をブロック、全関係者に通知

3.2 予算消化率 vs Issue消化率の乖離アラート

予算の消化ペースがIssue完了ペースを大きく上回っている場合、高額Issueへの偏りやスコープ変更の兆候と判断する。

乖離度 = 予算消化率 - Issue消化率
条件レベル意味
乖離度 >= 20%警告予算消化が進捗に対して速すぎる
乖離度 >= 30%危険予算枯渇リスクが高い。PMへ即座にエスカレーション
乖離度 <= -20%情報Issue消化が予算消化を上回っている(健全)

乖離アラートの例

プロジェクト: Backend API開発
予算消化率: 65%
Issue消化率: 40%
乖離度: +25% ⚠️ 警告

→ 高額Issueが先に消化されている可能性。
  残Issueの報酬合計が残予算内に収まるか確認してください。

3.3 アラート判定ロジック

sql
-- 乖離アラート対象プロジェクト抽出
SELECT
  project_id,
  budget_consumption_rate,
  issue_completion_rate,
  (budget_consumption_rate - issue_completion_rate) AS divergence
FROM project_budget_summary
WHERE (budget_consumption_rate - issue_completion_rate) >= 20
ORDER BY divergence DESC;

4. 月次スナップショット保存

4.1 目的

  • 月末時点の予算状況を履歴として保存
  • 時系列での予算消化トレンド分析
  • 監査対応

4.2 スナップショットデータ

sql
-- 月次スナップショット保存(毎月末日バッチ実行)
INSERT INTO budget_snapshots (
  project_id,
  snapshot_date,
  budget_limit,
  confirmed_total,
  pending_total,
  active_total,
  remaining_budget,
  budget_consumption_rate,
  issue_total_count,
  issue_completed_count,
  issue_completion_rate,
  divergence,
  created_at
)
SELECT
  p.id,
  CURRENT_DATE,
  p.budget_limit,
  COALESCE(r.confirmed_total, 0),
  COALESCE(r.pending_total, 0),
  COALESCE(r.active_total, 0),
  p.budget_limit - COALESCE(r.confirmed_total, 0)
    - COALESCE(r.pending_total, 0) - COALESCE(r.active_total, 0),
  ROUND((COALESCE(r.confirmed_total, 0) + COALESCE(r.pending_total, 0))
    * 100.0 / NULLIF(p.budget_limit, 0), 1),
  COALESCE(i.total_count, 0),
  COALESCE(i.completed_count, 0),
  ROUND(COALESCE(i.completed_count, 0) * 100.0 / NULLIF(i.total_count, 0), 1),
  ROUND((COALESCE(r.confirmed_total, 0) + COALESCE(r.pending_total, 0))
    * 100.0 / NULLIF(p.budget_limit, 0), 1)
  - ROUND(COALESCE(i.completed_count, 0) * 100.0 / NULLIF(i.total_count, 0), 1),
  NOW()
FROM projects p
LEFT JOIN (/* rewards集計サブクエリ */) r ON r.project_id = p.id
LEFT JOIN (/* issues集計サブクエリ */) i ON i.project_id = p.id;

4.3 budget_snapshots テーブル

カラム説明
idUUID主キー
project_idUUIDFK: projects.id
snapshot_dateDATEスナップショット日
budget_limitINTEGER予算上限
confirmed_totalINTEGER確定済み消化額
pending_totalINTEGER保留中消化額
active_totalINTEGER予約済み消化額
remaining_budgetINTEGER残予算
budget_consumption_rateDECIMAL予算消化率(%)
issue_total_countINTEGER全Issue数
issue_completed_countINTEGER完了Issue数
issue_completion_rateDECIMALIssue消化率(%)
divergenceDECIMAL乖離度(%)
created_atTIMESTAMP作成日時

5. データモデル(予算関連)

5.1 projects テーブル(予算カラム追加)

カラム説明
budget_limitINTEGER予算上限(円)
budget_alert_thresholdINTEGERアラート閾値(%)。デフォルト70

5.2 budget_change_logs テーブル

カラム説明
idUUID主キー
project_idUUIDFK: projects.id
previous_limitINTEGER変更前の予算上限
new_limitINTEGER変更後の予算上限
changed_byUUIDFK: users.id
reasonTEXT変更理由
created_atTIMESTAMP変更日時