Webhook 仕様書

外部サービスへのイベント送信

ステータス: Draft / 作成日: 2026-05-27 PR #10 — 依存: コア(並行実装可)


1. データモデル

webhooks

カラム 制約 説明
id UUID PK  
project_id UUID NOT NULL, FK→projects CASCADE  
url VARCHAR(2048) NOT NULL 送信先 URL
secret VARCHAR NOT NULL HMAC-SHA256 署名用シークレット(作成時のみ平文返却、以降はマスク)
events VARCHAR[] NOT NULL 有効にするイベント名
is_active BOOLEAN NOT NULL DEFAULT true 連続失敗時に自動 false
created_by UUID NOT NULL, FK→users  
created_at TIMESTAMPTZ NOT NULL DEFAULT now()  

webhook_deliveries

カラム 制約 説明
id UUID PK  
webhook_id UUID NOT NULL, FK→webhooks CASCADE  
event VARCHAR NOT NULL  
payload JSONB NOT NULL 送信ペイロード
status_code INT NULLABLE HTTP レスポンスコード
attempt SMALLINT NOT NULL DEFAULT 1 リトライ回数(最大 5)
delivered_at TIMESTAMPTZ NULLABLE 成功時のみ
created_at TIMESTAMPTZ NOT NULL DEFAULT now()  

2. マイグレーション

CREATE TABLE webhooks (
    id UUID PRIMARY KEY,
    project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    url VARCHAR(2048) NOT NULL,
    secret VARCHAR NOT NULL,
    events VARCHAR[] NOT NULL,
    is_active BOOLEAN NOT NULL DEFAULT true,
    created_by UUID NOT NULL REFERENCES users(id),
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE webhook_deliveries (
    id UUID PRIMARY KEY,
    webhook_id UUID NOT NULL REFERENCES webhooks(id) ON DELETE CASCADE,
    event VARCHAR NOT NULL,
    payload JSONB NOT NULL,
    status_code INT,
    attempt SMALLINT NOT NULL DEFAULT 1,
    delivered_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

3. イベント一覧

イベント トリガー
task.created タスク作成
task.updated タスクのフィールド変更(差分のみ)
task.deleted タスク削除
task.archived / task.unarchived アーカイブ操作
comment.created コメント投稿
github.pr_linked PR リンク追加
github.pr_merged PR マージ
sprint.started / sprint.completed スプリント状態変化

4. ペイロード仕様

リクエストヘッダー:

X-Task-Event: task.created
X-Task-Signature: sha256=<HMAC-SHA256-hex>
Content-Type: application/json

署名検証(受信側):

HMAC-SHA256(secret, raw_request_body) == X-Task-Signature の値

task.created

{
  "event": "task.created",
  "timestamp": "2026-05-27T10:00:00Z",
  "project_id": "uuid",
  "task": {
    "id": "uuid", "seq_id": 42,
    "title": "OAuth 対応を実装する",
    "priority": "high",
    "status": "Backlog",
    "assignees": [{ "user_id": "uuid", "role": "primary" }],
    "hard_deadline": "2026-06-10T00:00:00Z",
    "created_by": "uuid"
  }
}

task.updated(差分のみ)

{
  "event": "task.updated",
  "timestamp": "2026-05-27T11:30:00Z",
  "project_id": "uuid",
  "task_id": "uuid",
  "updated_by": "uuid",
  "changes": [
    { "field": "priority", "old_value": "medium", "new_value": "high" },
    { "field": "status",   "old_value": "Backlog", "new_value": "In Progress" }
  ]
}

task.deleted

{
  "event": "task.deleted",
  "timestamp": "2026-05-27T12:00:00Z",
  "project_id": "uuid",
  "task_id": "uuid",
  "deleted_by": "uuid"
}

5. リトライ

  • 2xx 以外のレスポンス: 指数バックオフで最大 5 回
    • 1 回目: 即時 / 2 回目: 30s / 3 回目: 5m / 4 回目: 30m / 5 回目: 2h
  • 5 回連続失敗: webhooks.is_active = false に設定し、テナントオーナーへメール通知
  • 配信履歴(webhook_deliveries)は 90 日後に自動パージ

6. API

メソッド パス 説明
GET /webhooks 一覧(secret はマスク表示)
POST /webhooks 作成(secret は作成時のみ平文返却)
PUT /webhooks/{id} 更新
DELETE /webhooks/{id} 削除
POST /webhooks/{id}/toggle 有効 / 無効切替
GET /webhooks/{id}/deliveries 配信履歴
POST /webhooks/{id}/deliveries/{did}/redeliver 手動再送

POST /webhooks リクエスト:

{
  "url": "https://example.com/webhook",
  "secret": "my-secret-token",
  "events": ["task.created", "task.updated", "task.deleted"]
}

7. フロントエンド(Phase B)

/tenants/{tid}/projects/{pid}/settings/webhooks

一覧・作成・配信履歴確認・手動再送の UI。