コンテンツにスキップ

Slack MCP Agent — データモデル設計

v1.8 / 2026-05-08

既存プロトタイプの DDL (Schema Version 1) を基盤に、MVP 追加要件を反映した完全なデータモデルを定義する。
docs/architecture.md Section 7、docs/mvp-spec.md Section 11 と整合。


1. ER 図

erDiagram
    tenants ||--o{ tasks : "1:N"
    tenants ||--|| settings : "1:1"
    tenants ||--o{ integrations : "1:N"
    tenants ||--o{ hr_employees : "1:N"
    tenants ||--o{ hr_snapshots : "1:N"
    tenants ||--o{ hr_flags : "1:N"
    tenants ||--o{ routing_decisions : "1:N"
    tenants ||--o{ monthly_reports : "1:N"
    hr_snapshots ||--o{ hr_flags : "1:N"
    tenants ||--o{ tool_permissions : "1:N"
    tenants ||--o{ audit_logs : "1:N"
    tasks ||--o{ prompts : "1:N (versioned)"
    tasks ||--o{ processes : "1:N (versioned)"
    tasks ||--o{ executions : "1:N"
    tasks ||--o{ slack_messages : "1:N"
    prompts ||--|| processes : "1:1"
    processes ||--o{ executions : "1:N"

    tenants {
        TEXT id PK "ULID"
        TEXT name
        TEXT slug UK
        TEXT agent_id "将来用"
        TEXT vault_id "将来用"
    }
    tasks {
        TEXT id PK "ULID"
        TEXT tenant_id FK
        TEXT title
        TEXT status "TaskStatus enum"
        TEXT source "channel / agent_container"
        TEXT routing_tier "A / B / C"
        TEXT slack_channel
        TEXT slack_thread_ts
    }
    prompts {
        TEXT id PK "ULID"
        TEXT task_id FK
        INTEGER version
        TEXT content
        TEXT status "PromptStatus enum"
        TEXT rejection_reason
    }
    processes {
        TEXT id PK "ULID"
        TEXT task_id FK
        TEXT prompt_id FK
        INTEGER version
        TEXT steps "JSON"
        TEXT status "ProcessStatus enum"
        TEXT rejection_reason
    }
    executions {
        TEXT id PK "ULID"
        TEXT task_id FK
        TEXT process_id FK
        TEXT session_id
        TEXT status "ExecutionStatus enum"
        TEXT results "JSON"
        TEXT cancelled_by
    }
    slack_messages {
        TEXT id PK "ULID"
        TEXT task_id FK
        TEXT card_type
        TEXT message_ts
    }
    audit_logs {
        TEXT id PK "ULID"
        TEXT tenant_id FK
        TEXT timestamp
        TEXT action
        TEXT details "JSON"
    }
    settings {
        TEXT id PK "ULID"
        TEXT tenant_id FK "UNIQUE"
        TEXT config "JSON"
    }
    integrations {
        TEXT id PK "ULID"
        TEXT tenant_id FK
        TEXT provider
        TEXT status
        TEXT credentials "JSON encrypted"
    }
    hr_employees {
        TEXT id PK "ULID"
        TEXT tenant_id FK
        TEXT freee_employee_id
        TEXT login_email
        TEXT slack_user_id "NULL allowed"
        TEXT status
    }
    hr_snapshots {
        TEXT id PK "ULID"
        TEXT tenant_id FK
        TEXT target_date
        TEXT snapshot_kind
        TEXT payload_json "JSON"
    }
    hr_flags {
        TEXT id PK "ULID"
        TEXT tenant_id FK
        TEXT snapshot_id FK
        TEXT target_date
        TEXT flag_kind
        TEXT severity
        TEXT resolved_at
    }
    routing_decisions {
        TEXT id PK "ULID"
        TEXT tenant_id FK
        TEXT target_kind
        TEXT target_id
        TEXT decision "A / B / C"
        TEXT decision_source
        TEXT reason_json "JSON"
        TEXT decided_at
    }
    monthly_reports {
        TEXT id PK "ULID"
        TEXT tenant_id FK
        TEXT report_month
        TEXT title
        TEXT metrics_json "JSON"
        TEXT status "draft / delivered"
    }
    tool_permissions {
        TEXT id PK "ULID"
        TEXT tenant_id FK
        TEXT tool_name
        INTEGER allowed
    }

リレーション一覧

関係 FK
tenants tasks 1:N tasks.tenant_id → tenants.id
tenants settings 1:1 settings.tenant_id → tenants.id (UNIQUE)
tenants integrations 1:N integrations.tenant_id → tenants.id
tenants hr_employees 1:N hr_employees.tenant_id → tenants.id
tenants hr_snapshots 1:N hr_snapshots.tenant_id → tenants.id
tenants hr_flags 1:N hr_flags.tenant_id → tenants.id
tenants routing_decisions 1:N routing_decisions.tenant_id → tenants.id
tenants monthly_reports 1:N monthly_reports.tenant_id → tenants.id
hr_snapshots hr_flags 1:N hr_flags.snapshot_id → hr_snapshots.id
tenants tool_permissions 1:N tool_permissions.tenant_id → tenants.id
tenants audit_logs 1:N audit_logs.tenant_id → tenants.id
tasks prompts 1:N prompts.task_id → tasks.id
tasks processes 1:N processes.task_id → tasks.id
tasks executions 1:N executions.task_id → tasks.id
tasks slack_messages 1:N slack_messages.task_id → tasks.id
prompts processes 1:1 processes.prompt_id → prompts.id
processes executions 1:N executions.process_id → processes.id

2. テーブル定義

2.1 tenants

テナント管理。MVP はシングルテナント (default)。

カラム 制約 説明
id TEXT PK (ULID) テナント ID
name TEXT NOT NULL 表示名
slug TEXT NOT NULL, UNIQUE URL スラッグ
agent_id TEXT Managed Agent 定義 ID (将来用)
vault_id TEXT Vault ID (将来用)
created_at TEXT NOT NULL, DEFAULT now 作成日時 (ISO 8601)
updated_at TEXT NOT NULL, DEFAULT now 更新日時

2.2 tasks

L1 出力のタスク。パイプラインのルートエンティティ。

カラム 制約 説明
id TEXT PK (ULID) タスク ID
tenant_id TEXT NOT NULL, FK → tenants 所属テナント
title TEXT NOT NULL L1 が抽出したタイトル
description TEXT NOT NULL, DEFAULT '' L1 が抽出した説明
priority TEXT NOT NULL, DEFAULT 'medium' low / medium / high / urgent
task_type TEXT NOT NULL, DEFAULT 'standard' standard / urgent / faq
status TEXT NOT NULL, DEFAULT 'extracted' TaskStatus enum
source TEXT NOT NULL, DEFAULT 'channel' channel / agent_container (MVP は channel のみ書き込み、agent_container は Post-MVP)
routing_tier TEXT NOT NULL, DEFAULT 'B' 最新の処理区分。A = AI 自動、B = AI 補助 + 人レビュー、C = 人対応必須
slack_channel TEXT NOT NULL Slack channel ID
slack_thread_ts TEXT NOT NULL Slack thread timestamp
created_at TEXT NOT NULL, DEFAULT now 作成日時
updated_at TEXT NOT NULL, DEFAULT now 更新日時

インデックス: - idx_tasks_tenant ON (tenant_id) - idx_tasks_status ON (status) - idx_tasks_created_at ON (created_at DESC) -- 一覧ソート用

2.3 prompts

L2 出力の実行方針。タスクごとにバージョン管理。

カラム 制約 説明
id TEXT PK (ULID) プロンプト ID
task_id TEXT NOT NULL, FK → tasks 親タスク
version INTEGER NOT NULL, DEFAULT 1 バージョン番号
content TEXT NOT NULL, DEFAULT '' 実行方針テキスト
status TEXT NOT NULL, DEFAULT 'generating' PromptStatus enum
approved_by TEXT 承認者 (Slack user ID)
approved_at TEXT 承認日時
rejection_reason TEXT 却下理由
rejected_by TEXT 却下者 (Slack user ID)
created_at TEXT NOT NULL, DEFAULT now 作成日時

制約: - UNIQUE (task_id, version) -- タスク内で版番号は一意

インデックス: - idx_prompts_task ON (task_id)

2.4 processes

L3 出力のステップ計画。タスクごとにバージョン管理。

カラム 制約 説明
id TEXT PK (ULID) プロセス ID
task_id TEXT NOT NULL, FK → tasks 親タスク
prompt_id TEXT NOT NULL, FK → prompts 基にしたプロンプト
version INTEGER NOT NULL, DEFAULT 1 バージョン番号
steps TEXT NOT NULL, DEFAULT '[]' JSON: ステップ配列
status TEXT NOT NULL, DEFAULT 'generating' ProcessStatus enum
approved_by TEXT 承認者
approved_at TEXT 承認日時
rejection_reason TEXT 却下理由
rejected_by TEXT 却下者
created_at TEXT NOT NULL, DEFAULT now 作成日時

steps JSON 構造:

[
  {
    "stepId": "step-1",
    "order": 1,
    "tool": "list_employees",
    "toolInput": { "department": null, "status": "active" },
    "description": "従業員一覧を取得する",
    "expectedOutput": "従業員のリスト"
  }
]

制約: - UNIQUE (task_id, version)

インデックス: - idx_processes_task ON (task_id)

2.5 executions

L4 の実行記録。1 プロセスに対して複数回実行可能 (再実行)。

カラム 制約 説明
id TEXT PK (ULID) 実行 ID
task_id TEXT NOT NULL, FK → tasks 親タスク
process_id TEXT NOT NULL, FK → processes 実行したプロセス
session_id TEXT Managed Agent Session ID
status TEXT NOT NULL, DEFAULT 'pending' ExecutionStatus enum
current_step INTEGER NOT NULL, DEFAULT 0 現在のステップ番号
results TEXT NOT NULL, DEFAULT '[]' JSON: ステップ実行結果
error TEXT エラーメッセージ
cancelled_by TEXT 中止者 (Slack user ID)
cancelled_at TEXT 中止日時
started_at TEXT 実行開始日時
completed_at TEXT 実行完了日時

results JSON 構造:

[
  {
    "stepId": "step-1",
    "tool": "list_employees",
    "status": "completed",
    "result": { "count": 42 },
    "duration_ms": 800,
    "started_at": "2026-04-18T14:35:00Z",
    "completed_at": "2026-04-18T14:35:00.800Z"
  }
]

インデックス: - idx_executions_task ON (task_id) - idx_executions_process ON (process_id)

2.6 slack_messages

Slack カードの message_ts と DB エンティティのマッピング。chat.update で書き換える際に使用。

カラム 制約 説明
id TEXT PK (ULID) レコード ID
task_id TEXT NOT NULL, FK → tasks 親タスク
card_type TEXT NOT NULL task_card / prompt_card / process_card / execution_card / faq_card
channel TEXT NOT NULL Slack channel ID
message_ts TEXT NOT NULL Slack message timestamp
created_at TEXT NOT NULL, DEFAULT now 作成日時

インデックス: - idx_slack_messages_task ON (task_id)

2.7 audit_logs (MVP 新規)

全操作の監査ログ。

カラム 制約 説明
id TEXT PK (ULID) ログ ID
tenant_id TEXT NOT NULL, FK → tenants テナント
timestamp TEXT NOT NULL イベント発生日時
actor_type TEXT NOT NULL user / system / agent
actor_id TEXT Slack user ID or 空
action TEXT NOT NULL アクション種別 (下記参照)
resource_type TEXT NOT NULL task / prompt / process / execution / settings / integration
resource_id TEXT 対象リソースの ID
details TEXT DEFAULT '{}' JSON: 補足情報

アクション種別:

action actor_type トリガー
task.created system L1 完了
prompt.approved user Slack [承認]
prompt.rejected user Slack [却下]
process.approved user Slack [承認]
process.rejected user Slack [却下]
execution.started system L4 開始
execution.completed system L4 正常完了
execution.failed system L4 異常終了
execution.cancelled user [中止]
faq.escalated_to_hr user FAQ カードの HR に確認する
settings.updated user Web 設定保存
integration.connected user OAuth 接続完了
integration.disconnected user [切断]

インデックス: - idx_audit_logs_tenant_ts ON (tenant_id, timestamp DESC) -- 一覧フィルタ用 - idx_audit_logs_action ON (action)

2.8 settings (MVP 新規)

テナント設定。1 テナント 1 レコード。

カラム 制約 説明
id TEXT PK (ULID) レコード ID
tenant_id TEXT NOT NULL, FK → tenants, UNIQUE テナント (1:1)
config TEXT NOT NULL, DEFAULT '{}' JSON: 設定値
updated_at TEXT NOT NULL, DEFAULT now 最終更新日時
updated_by TEXT 更新者

config JSON 構造:

{
  "name": "HR AI Agent",
  "slug": "default",
  "prompt_approval_required": true,
  "process_approval_required": true,
  "model": "claude-sonnet-4-6",
  "l4_timeout_seconds": 360,
  "auto_approve_tools": true,
  "faq_knowledge_text": "# リモートワーク規程\n前営業日18時までに申請する。"
}

faq_knowledge_text は社内ハウスルール FAQ 一次回答に使う Markdown ナレッジ。Web settings は settings.config を merge 更新し、未編集キーを保持する。

2.9 integrations (MVP 新規)

外部サービス接続情報。

カラム 制約 説明
id TEXT PK (ULID) レコード ID
tenant_id TEXT NOT NULL, FK → tenants テナント
provider TEXT NOT NULL freee / google / slack
status TEXT NOT NULL, DEFAULT 'disconnected' connected / disconnected / error
credentials TEXT DEFAULT '{}' JSON (暗号化): OAuth トークン等
metadata TEXT DEFAULT '{}' JSON: プロバイダー固有情報
connected_at TEXT 接続日時
updated_at TEXT NOT NULL, DEFAULT now 更新日時

制約: - UNIQUE (tenant_id, provider) -- テナント内でプロバイダーは一意

2.10 hr_employees (MVP 新規)

freee 従業員 ID と Slack UserID を対応付ける人物マスタ。後続の個別通知(リマインド、エスカレーション等)は、freee 従業員 ID または Slack UserID からこのテーブルを経由して通知先を解決する。

カラム 制約 説明
id TEXT PK (ULID) レコード ID
tenant_id TEXT NOT NULL, FK → tenants テナント
freee_employee_id TEXT NOT NULL freee 従業員 ID
login_email TEXT NOT NULL freee employee_group_memberships.login_email
slack_user_id TEXT NULL Slack users.lookupByEmail で解決した UserID。未登録・メール不一致時は NULL
display_name TEXT NOT NULL, DEFAULT '' freee 側表示名
department TEXT NOT NULL, DEFAULT '' freee 部署名または employee group 名
status TEXT NOT NULL, DEFAULT 'active' active / retired / on_leave
synced_at TEXT NOT NULL 最終同期日時
created_at TEXT NOT NULL, DEFAULT now 作成日時
updated_at TEXT NOT NULL, DEFAULT now 更新日時

制約: - UNIQUE (tenant_id, freee_employee_id) -- freee 従業員はテナント内で一意

インデックス: - idx_hr_employees_tenant ON (tenant_id) - idx_hr_employees_login_email ON (tenant_id, login_email) - idx_hr_employees_slack_user ON (tenant_id, slack_user_id)

運用ルール: - 初期 MVP は sync_hr_employees の手動実行で初回構築・差分更新を行う。将来のスケジューラ基盤は同じ job 関数を呼び出す。 - 入社時は freee 側登録後に同期し、Slack 未登録やメール不一致があれば手動で補正する。 - 退社済みは同期時に status='retired' として保持し、削除は手動運用で行う。 - 休職中は status='on_leave' または最も近い正規化値として保持する。 - 複数 Slack アカウントが疑われる場合でも、exact email に対する users.lookupByEmail の結果を正とし、曖昧なケースは手動修正に回す。

2.11 hr_snapshots (MVP 新規)

日次 HR パイプラインの取得結果を保存するスナップショット。取得元 API のレスポンスをそのまま固定化するのではなく、後続ジョブが参照できる最小正規化 JSON として payload_json に保持する。

カラム 制約 説明
id TEXT PK (ULID) レコード ID
tenant_id TEXT NOT NULL, FK → tenants テナント
target_date TEXT NOT NULL 対象日 (YYYY-MM-DD)
snapshot_kind TEXT NOT NULL attendance / employee 等の種別
payload_json TEXT NOT NULL, DEFAULT {"schema_version":1,"records":[]} JSON: { "schema_version": 1, "records": [] }
source TEXT NOT NULL, DEFAULT 'scheduler' 作成元
created_at TEXT NOT NULL, DEFAULT now 作成日時

制約: - UNIQUE (tenant_id, target_date, snapshot_kind) -- 同一日・同一種別のスナップショットは 1 件

インデックス: - idx_hr_snapshots_tenant_date ON (tenant_id, target_date DESC) - idx_hr_snapshots_unique_kind ON (tenant_id, target_date, snapshot_kind)

2.12 hr_flags (MVP 新規)

日次 HR パイプラインの差分検出や異常検知結果を保存するフラグ。resolved_at が NULL のものを未解決として扱う。

カラム 制約 説明
id TEXT PK (ULID) レコード ID
tenant_id TEXT NOT NULL, FK → tenants テナント
snapshot_id TEXT FK → hr_snapshots, NULL allowed 根拠スナップショット
target_date TEXT NOT NULL 対象日 (YYYY-MM-DD)
flag_kind TEXT NOT NULL missing_clockin / leave_expiring 等の種別
severity TEXT NOT NULL, DEFAULT 'info' info / warning / critical
payload_json TEXT NOT NULL, DEFAULT '{}' JSON: 判定根拠や対象従業員 ID
resolved_at TEXT NULL 解決日時。NULL は未解決
created_at TEXT NOT NULL, DEFAULT now 作成日時

インデックス: - idx_hr_flags_tenant_date ON (tenant_id, target_date DESC) - idx_hr_flags_unresolved ON (tenant_id, resolved_at)

Lane B payload contract:

hr_snapshots.snapshot_kind='attendance_daily' は日次勤怠レコードを保持し、打刻エラー検出で参照する。 hr_snapshots.snapshot_kind='attendance_monthly' は月次勤怠サマリを保持し、前月差異と36協定チェックで参照する。 通常運用では Lane B scheduler jobs が freee 勤怠を取得してこれらのスナップショットを作成する。

月次レコードは employee_id, month, total_minutes, overtime_minutes, holiday_work_minutes, paid_leave_days を最小項目とする。検出結果は hr_flags.flag_kindmissing_clock_in, missing_clock_out, zero_minute_work, over_24h_work, holiday_work, monthly_overtime_spike, agreement_36_* を保存する。 36協定では単月、年次、2〜6ヶ月平均、45時間超過月数を決定的ロジックで判定し、違反は severity='critical' とする。

Lane C payload contract:

hr_snapshots.snapshot_kind='payroll_proration_draft' は日割り計算ドラフトを保持する。 hr_snapshots.snapshot_kind='payroll_monthly' は月次給与明細(前月/当月比較の入力)を保持する。 hr_snapshots.snapshot_kind='payroll_diff_explanation' は差異説明ドラフトを保持する。 hr_snapshots.snapshot_kind='payroll_violation_risk' は法令リスク候補を保持する。

hr_flags.flag_kind には payroll_large_difference, minimum_wage_risk, overtime_limit_risk, social_insurance_risk, insufficient_data_risk を保存する。 Lane Cの hr_flags は全件 routing_tier='C' を前提に作成し、最終判断は人間が行う。

Lane A payload contract:

Lane A 通知の重複送信防止では hr_flags を marker として利用する。 代表例:

  • lane_a_attendance_closing_notified
  • lane_a_missing_clockin_notified
  • lane_a_missing_clockin_escalated
  • lane_a_paid_leave_notified_60d / 30d / 10d / 7d
  • leave_expiring_7d_escalation

2.13 routing_decisions (MVP 新規)

A/B/C ルーティングの判定履歴。tasks.routing_tier は最新値のみを保持し、このテーブルは適用ルール名と根拠 JSON を監査・Phase 2 の AI ルーティング昇格で参照する。 AI 判定は decision_source='ai' として追加保存し、低リスク側への降格は反映しない。

カラム 制約 説明
id TEXT PK (ULID) レコード ID
tenant_id TEXT NOT NULL, FK → tenants テナント
target_kind TEXT NOT NULL task / hr_flag 等の対象種別
target_id TEXT NOT NULL 対象レコード ID
decision TEXT NOT NULL A / B / C
decision_source TEXT NOT NULL, DEFAULT 'rules' rules / 将来の ai
reason_json TEXT NOT NULL, DEFAULT '{}' JSON: applied_rule, task_type, flag_kind, severity
decided_at TEXT NOT NULL 判定日時

インデックス: - idx_routing_decisions_target ON (tenant_id, target_kind, target_id, decided_at) - idx_routing_decisions_decision ON (tenant_id, decision)

2.14 monthly_reports

月次 HR 業務完了レポート。Lane A/B の通知・検知・スナップショット・タスク状態を月単位で集計し、HR レビュー用 draft として保存する。

カラム 制約 説明
id TEXT PK (ULID) レポート ID
tenant_id TEXT NOT NULL, FK → tenants 所属テナント
report_month TEXT NOT NULL 対象月 YYYY-MM
title TEXT NOT NULL 表示タイトル
body TEXT NOT NULL, DEFAULT '' Slack/Web 表示本文
metrics_json TEXT NOT NULL, DEFAULT '{}' 集計指標 JSON
status TEXT NOT NULL, DEFAULT 'draft' draft / delivered
slack_channel TEXT 投稿先チャンネル
slack_message_ts TEXT レビューカードの Slack timestamp
delivered_by TEXT 配信済みにした Slack user ID
delivered_at TEXT 配信済み日時
created_at TEXT NOT NULL 作成日時
updated_at TEXT NOT NULL 更新日時

制約・インデックス: - UNIQUE (tenant_id, report_month) -- 同一月の再生成は上書き - idx_monthly_reports_tenant_month ON (tenant_id, report_month DESC) - idx_monthly_reports_status ON (tenant_id, status)

2.15 tool_permissions

ツール実行権限 (Post-MVP で活用)。

カラム 制約 説明
id TEXT PK (ULID) レコード ID
tenant_id TEXT NOT NULL, FK → tenants テナント
tool_name TEXT NOT NULL ツール名
allowed INTEGER NOT NULL, DEFAULT 1 1=許可, 0=禁止
constraints TEXT NOT NULL, DEFAULT '{}' JSON: 制約条件
created_at TEXT NOT NULL, DEFAULT now 作成日時
updated_at TEXT NOT NULL, DEFAULT now 更新日時

制約: - UNIQUE (tenant_id, tool_name)


3. 状態遷移図

3.1 TaskStatus

stateDiagram-v2
    [*] --> extracted
    extracted --> running : L4 実行開始
    extracted --> cancelled : タスク取消
    running --> completed : L4 正常完了
    running --> failed : L4 異常終了
    running --> cancelled : 中止ボタン
    failed --> running : 再実行ボタン
    completed --> [*]
    failed --> [*]
    cancelled --> [*]
遷移元 遷移先 トリガー
extracted running L4 実行開始
extracted cancelled 承認前にタスク取消
running completed L4 正常完了
running failed L4 異常終了
running cancelled [中止] ボタン
failed running [再実行] ボタン

3.2 PromptStatus

stateDiagram-v2
    [*] --> generating
    generating --> pending_approval : L2 完了
    pending_approval --> approved : 承認ボタン
    pending_approval --> rejected : 却下ボタン
    rejected --> [*] : 新 version を generating で作成
    approved --> [*]
遷移元 遷移先 トリガー
generating pending_approval L2 完了、content 書込
pending_approval approved [承認] ボタン
pending_approval rejected [却下] ボタン

3.3 ProcessStatus

PromptStatus と同一パターン。

遷移元 遷移先 トリガー
generating pending_approval L3 完了、steps 書込
pending_approval approved [承認] ボタン
pending_approval rejected [却下] ボタン

3.4 ExecutionStatus

stateDiagram-v2
    [*] --> pending
    pending --> running : Session 作成完了
    running --> completed : Session idle + summary
    running --> failed : Session error / timeout
    running --> cancelled : 中止ボタン
    completed --> [*]
    failed --> [*]
    cancelled --> [*]
遷移元 遷移先 トリガー
pending running Session 作成完了
running completed Session idle + summary
running failed Session error / timeout
running cancelled [中止] ボタン

4. マイグレーション戦略

4.1 現状 (Schema Version 1)

プロトタイプの DDL。tenants, tasks, prompts, processes, executions, slack_messages, tool_permissions の 7 テーブル + インデックス。

4.2 MVP (Schema Version 2)

Version 1 からの差分:

-- Schema Version 2: MVP additions

-- tasks: source カラム追加
ALTER TABLE tasks ADD COLUMN source TEXT NOT NULL DEFAULT 'channel';

-- prompts: 却下理由カラム追加
ALTER TABLE prompts ADD COLUMN rejection_reason TEXT;
ALTER TABLE prompts ADD COLUMN rejected_by TEXT;

-- processes: 却下理由カラム追加
ALTER TABLE processes ADD COLUMN rejection_reason TEXT;
ALTER TABLE processes ADD COLUMN rejected_by TEXT;

-- executions: 中止カラム・ステータス追加
ALTER TABLE executions ADD COLUMN cancelled_by TEXT;
ALTER TABLE executions ADD COLUMN cancelled_at TEXT;

-- audit_logs (新規)
CREATE TABLE IF NOT EXISTS audit_logs (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL REFERENCES tenants(id),
    timestamp TEXT NOT NULL,
    actor_type TEXT NOT NULL,
    actor_id TEXT,
    action TEXT NOT NULL,
    resource_type TEXT NOT NULL,
    resource_id TEXT,
    details TEXT NOT NULL DEFAULT '{}'
);
CREATE INDEX IF NOT EXISTS idx_audit_logs_tenant_ts
    ON audit_logs(tenant_id, timestamp DESC);
CREATE INDEX IF NOT EXISTS idx_audit_logs_action
    ON audit_logs(action);

-- settings (新規)
CREATE TABLE IF NOT EXISTS settings (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL REFERENCES tenants(id),
    config TEXT NOT NULL DEFAULT '{}',
    updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now')),
    updated_by TEXT
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_settings_tenant
    ON settings(tenant_id);

-- integrations (新規)
CREATE TABLE IF NOT EXISTS integrations (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL REFERENCES tenants(id),
    provider TEXT NOT NULL,
    status TEXT NOT NULL DEFAULT 'disconnected',
    credentials TEXT NOT NULL DEFAULT '{}',
    metadata TEXT NOT NULL DEFAULT '{}',
    connected_at TEXT,
    updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now'))
);
CREATE UNIQUE INDEX IF NOT EXISTS idx_integrations_tenant_provider
    ON integrations(tenant_id, provider);

-- tasks: 作成日時降順インデックス追加
CREATE INDEX IF NOT EXISTS idx_tasks_created_at
    ON tasks(created_at DESC);

-- executions: process_id インデックス追加
CREATE INDEX IF NOT EXISTS idx_executions_process
    ON executions(process_id);

4.3 Phase 0 人物マスタ (Schema Version 3)

Version 2 からの差分:

-- Schema Version 3: HR employee master

CREATE TABLE IF NOT EXISTS hr_employees (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL REFERENCES tenants(id),
    freee_employee_id TEXT NOT NULL,
    login_email TEXT NOT NULL,
    slack_user_id TEXT,
    display_name TEXT NOT NULL DEFAULT '',
    department TEXT NOT NULL DEFAULT '',
    status TEXT NOT NULL DEFAULT 'active',
    synced_at TEXT NOT NULL,
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now')),
    updated_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now')),
    UNIQUE (tenant_id, freee_employee_id)
);

CREATE INDEX IF NOT EXISTS idx_hr_employees_tenant
    ON hr_employees(tenant_id);
CREATE INDEX IF NOT EXISTS idx_hr_employees_login_email
    ON hr_employees(tenant_id, login_email);
CREATE INDEX IF NOT EXISTS idx_hr_employees_slack_user
    ON hr_employees(tenant_id, slack_user_id);

4.4 Phase 0 スケジューラ基盤 (Schema Version 4)

Version 3 からの差分:

-- Schema Version 4: scheduler snapshots and flags

CREATE TABLE IF NOT EXISTS hr_snapshots (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL REFERENCES tenants(id),
    target_date TEXT NOT NULL,
    snapshot_kind TEXT NOT NULL,
    payload_json TEXT NOT NULL DEFAULT '{"schema_version":1,"records":[]}',
    source TEXT NOT NULL DEFAULT 'scheduler',
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now'))
);
CREATE INDEX IF NOT EXISTS idx_hr_snapshots_tenant_date
    ON hr_snapshots(tenant_id, target_date DESC);
CREATE UNIQUE INDEX IF NOT EXISTS idx_hr_snapshots_unique_kind
    ON hr_snapshots(tenant_id, target_date, snapshot_kind);

CREATE TABLE IF NOT EXISTS hr_flags (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL REFERENCES tenants(id),
    snapshot_id TEXT REFERENCES hr_snapshots(id),
    target_date TEXT NOT NULL,
    flag_kind TEXT NOT NULL,
    severity TEXT NOT NULL DEFAULT 'info',
    payload_json TEXT NOT NULL DEFAULT '{}',
    resolved_at TEXT,
    created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%f+00:00', 'now'))
);
CREATE INDEX IF NOT EXISTS idx_hr_flags_tenant_date
    ON hr_flags(tenant_id, target_date DESC);
CREATE INDEX IF NOT EXISTS idx_hr_flags_unresolved
    ON hr_flags(tenant_id, resolved_at);

payload_json の最小 contract:

{
  "schema_version": 1,
  "records": []
}

4.5 Phase 1 A/B/C ルーティング (Schema Version 5)

Version 4 からの差分:

-- Schema Version 5: rule-based routing decisions

ALTER TABLE tasks ADD COLUMN routing_tier TEXT NOT NULL DEFAULT 'B';

CREATE TABLE IF NOT EXISTS routing_decisions (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL REFERENCES tenants(id),
    target_kind TEXT NOT NULL,
    target_id TEXT NOT NULL,
    decision TEXT NOT NULL,
    decision_source TEXT NOT NULL DEFAULT 'rules',
    reason_json TEXT NOT NULL DEFAULT '{}',
    decided_at TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_routing_decisions_target
    ON routing_decisions(tenant_id, target_kind, target_id, decided_at);
CREATE INDEX IF NOT EXISTS idx_routing_decisions_decision
    ON routing_decisions(tenant_id, decision);

reason_json の例:

{
  "applied_rule": "task_type.standard",
  "task_type": "standard"
}

4.6 マイグレーション実行

既存の _MIGRATIONS dict にバージョンを追加し、migrate() で自動適用:

SCHEMA_VERSION = 5

_MIGRATIONS: dict[int, str] = {
    1: "...(既存)...",
    2: "...(MVP additions)...",
    3: "...(HR employee master)...",
    4: "...(scheduler snapshots and flags)...",
    5: "...(routing decisions)...",
}

5. データフロー

5.1 パイプライン実行時の書込順序

1. tasks       INSERT (status: extracted, routing_tier: A/B/C)
2. routing_decisions INSERT (target_kind: task, decision_source: rules)
3. audit_logs  INSERT (action: routing.decided)
4. slack_messages INSERT (card_type: task)
5. prompts     INSERT (status: generating)
6. slack_messages INSERT (card_type: prompt)
7. prompts     UPDATE (content, status: pending_approval)
8. audit_logs  INSERT (action: task.created)

--- 承認後 ---
9. prompts     UPDATE (status: approved, approved_by, approved_at)
10. audit_logs  INSERT (action: prompt.approved)
11. processes   INSERT (status: generating)
12. slack_messages INSERT (card_type: process)
13. processes   UPDATE (steps, status: pending_approval)

--- 承認後 ---
14. processes   UPDATE (status: approved)
15. audit_logs  INSERT (action: process.approved)
16. tasks       UPDATE (status: running)
17. executions  INSERT (status: pending)
18. slack_messages INSERT (card_type: execution)
19. executions  UPDATE (status: running, started_at)
20. audit_logs  INSERT (action: execution.started)

--- 完了 ---
21. executions  UPDATE (status: completed, results, completed_at)
22. tasks       UPDATE (status: completed)
23. audit_logs  INSERT (action: execution.completed)

5.2 人物マスタ同期時の書込順序

1. freee employees                  SELECT via API
2. freee employee_group_memberships SELECT via API
3. Slack users.lookupByEmail        login_email ごとに解決
4. hr_employees                     INSERT/UPDATE by (tenant_id, freee_employee_id)

Slack 未登録・メール不一致の場合は slack_user_id = NULL で保存し、warning log を出す。Lane A 個別通知系処理は hr_employees.slack_user_id が NULL の場合、運用チャンネルへのフォールバック通知で補う。


変更履歴

日付 バージョン 変更内容
2026-04-18 v1.0 初版作成
2026-04-20 v1.1 tasks.source の利用範囲(MVP は channel のみ)を注記。実装の SCHEMA_VERSION=2 に整合済みであることを確認
2026-04-29 v1.2 hr_employees 人物マスタ、Schema Version 3、freee login_email と Slack UserID の同期運用を追加
2026-04-29 v1.3 hr_snapshots / hr_flags、Schema Version 4、スケジューラ基盤の保存先を追加
2026-04-29 v1.4 tasks.routing_tier / routing_decisions、Schema Version 5、A/B/C ルーティング履歴を追加
2026-05-05 v1.5 Lane B の勤怠異常、月次差異、36協定、AIルーティング昇格で使う snapshot / flag payload contract を追加
2026-05-06 v1.6 Lane C の給与日割り・差異・説明・法令リスクで使う snapshot / flag payload contract を追加
2026-05-06 v1.7 Lane A の通知 marker (hr_flags) と未紐付け時フォールバック運用を追加
2026-05-08 v1.8 monthly_reportsfaq task type、FAQ/レポート用 settings key を追加