通知設定カスタマイズ
概要
ユーザーが通知の受信方法を柔軟にカスタマイズできる設定機能を定義する。 チャネル別ON/OFF、通知頻度(即時/ダイジェスト)、Quiet Hours(通知抑制時間帯)を提供し、通知疲れを防止する。
1. 通知設定データモデル
user_notification_settings テーブル
user_notification_settings
├── id: UUID (PK)
├── user_id: FK → users (UNIQUE)
├── global_enabled: boolean (default true)
├── quiet_hours_enabled: boolean (default false)
├── quiet_hours_start: time (default '22:00')
├── quiet_hours_end: time (default '08:00')
├── timezone: varchar (default 'Asia/Tokyo')
├── digest_enabled: boolean (default false)
├── digest_schedule: enum (DAILY_MORNING, DAILY_EVENING, WEEKLY) (default DAILY_MORNING)
├── digest_time: time (default '09:00')
├── created_at: timestamp
└── updated_at: timestampuser_notification_channel_settings テーブル
user_notification_channel_settings
├── id: UUID (PK)
├── user_id: FK → users
├── channel: enum (SLACK, DISCORD, EMAIL, IN_APP)
├── enabled: boolean (default true)
├── created_at: timestamp
└── updated_at: timestamp
UNIQUE(user_id, channel)user_notification_trigger_settings テーブル
user_notification_trigger_settings
├── id: UUID (PK)
├── user_id: FK → users
├── trigger_type: enum (全トリガー種別)
├── channel: enum (SLACK, DISCORD, EMAIL, IN_APP)
├── enabled: boolean (default: マトリクスのデフォルト値)
├── frequency: enum (INSTANT, DIGEST, OFF) (default INSTANT)
├── created_at: timestamp
└── updated_at: timestamp
UNIQUE(user_id, trigger_type, channel)2. 設定画面UI仕様
2.1 グローバル設定
┌─────────────────────────────────────────────────┐
│ 通知設定 │
├─────────────────────────────────────────────────┤
│ │
│ ■ 全体設定 │
│ │
│ 通知を受け取る [====ON====] │
│ │
│ タイムゾーン [Asia/Tokyo ▼] │
│ │
│ ■ Quiet Hours(通知抑制時間) │
│ │
│ Quiet Hoursを有効にする [====ON====] │
│ 開始時刻 [22:00] │
│ 終了時刻 [08:00] │
│ ※ Critical通知はQuiet Hours中も配信されます │
│ │
│ ■ ダイジェスト配信 │
│ │
│ ダイジェストを有効にする [===OFF====] │
│ 配信スケジュール [毎朝 9:00 ▼] │
│ │
└─────────────────────────────────────────────────┘2.2 チャネル別設定
┌─────────────────────────────────────────────────┐
│ チャネル別受信設定 │
├─────────────────────────────────────────────────┤
│ │
│ チャネル ステータス アクション │
│ ───────────────────────────────────────── │
│ Slack 接続済み [====ON====] │
│ Discord 接続済み [====ON====] │
│ メール verified [====ON====] │
│ プラットフォーム 常時有効 [====ON====] │
│ │
│ ※ Slack/Discordの連携は「アカウント連携」 │
│ ページから設定してください │
│ │
└─────────────────────────────────────────────────┘2.3 トリガー別詳細設定
┌──────────────────────────────────────────────────────────────┐
│ 通知タイプ別設定 │
├──────────────────────────────────────────────────────────────┤
│ │
│ ▼ Issue ライフサイクル │
│ │
│ 通知タイプ Slack Discord メール PF内 頻度 │
│ ───────────────────────────────────────────────────── │
│ 新規Issue公開 ― [✓] [✓] [✓] 即時 ▼ │
│ Issue着手 [✓] ― [ ] [✓] 即時 ▼ │
│ MR提出 [✓] ― [ ] [✓] 即時 ▼ │
│ レビューFB ― [✓] [✓] [✓] 即時 ▼ │
│ 承認・報酬確定 [✓] [✓] [✓] [✓] 即時 ▼ │
│ 期限アラート(24h前) [✓] [✓] [✓] [✓] 即時 ▼ │
│ 予算超過アラート [✓] ― [✓] [✓] 即時 ▼ │
│ レビュー滞留(3日) [✓] ― [✓] [✓] 即時 ▼ │
│ │
│ ▼ 補助通知 │
│ │
│ コメント追加 [ ] [ ] [ ] [✓] DG ▼ │
│ Issue取り下げ ― [✓] [✓] [✓] 即時 ▼ │
│ 報酬支払完了 ― [✓] [✓] [✓] 即時 ▼ │
│ 新規プロジェクト ― [✓] [ ] [✓] DG ▼ │
│ │
│ [✓] = 有効 [ ] = 無効 ― = 変更不可(対象外) │
│ 頻度: 即時 = リアルタイム / DG = ダイジェスト │
│ │
│ [ デフォルトに戻す ] [ 保存する ] │
│ │
└──────────────────────────────────────────────────────────────┘3. 設定API
エンドポイント
| Method | Path | 説明 |
|---|---|---|
| GET | /api/v1/users/me/notification-settings | 現在の通知設定取得 |
| PUT | /api/v1/users/me/notification-settings | グローバル設定更新 |
| GET | /api/v1/users/me/notification-settings/channels | チャネル別設定取得 |
| PUT | /api/v1/users/me/notification-settings/channels/{channel} | チャネル別設定更新 |
| GET | /api/v1/users/me/notification-settings/triggers | トリガー別設定取得 |
| PUT | /api/v1/users/me/notification-settings/triggers | トリガー別設定一括更新 |
| POST | /api/v1/users/me/notification-settings/reset | デフォルトにリセット |
リクエスト/レスポンス例
GET /api/v1/users/me/notification-settings
json
{
"global_enabled": true,
"quiet_hours": {
"enabled": true,
"start": "22:00",
"end": "08:00"
},
"timezone": "Asia/Tokyo",
"digest": {
"enabled": false,
"schedule": "DAILY_MORNING",
"time": "09:00"
},
"channels": {
"SLACK": { "enabled": true, "connected": true },
"DISCORD": { "enabled": true, "connected": true },
"EMAIL": { "enabled": true, "verified": true },
"IN_APP": { "enabled": true }
},
"triggers": [
{
"trigger_type": "ISSUE_PUBLISHED",
"settings": {
"SLACK": { "enabled": false, "frequency": "INSTANT", "editable": false },
"DISCORD": { "enabled": true, "frequency": "INSTANT", "editable": true },
"EMAIL": { "enabled": true, "frequency": "DIGEST", "editable": true },
"IN_APP": { "enabled": true, "frequency": "INSTANT", "editable": false }
}
}
]
}PUT /api/v1/users/me/notification-settings/triggers
json
{
"triggers": [
{
"trigger_type": "ISSUE_PUBLISHED",
"channel": "EMAIL",
"enabled": false,
"frequency": "OFF"
},
{
"trigger_type": "COMMENT_ADDED",
"channel": "DISCORD",
"enabled": true,
"frequency": "DIGEST"
}
]
}4. 通知配信ロジック
配信判定フロー
[通知イベント発生]
│
▼
[対象ユーザー特定] ← マトリクスのロール定義
│
▼
[グローバル設定チェック]
│ global_enabled = false → 配信しない
▼
[チャネル別設定チェック]
│ channel.enabled = false → そのチャネルをスキップ
▼
[トリガー別設定チェック]
│ trigger.enabled = false → そのチャネルをスキップ
│ trigger.frequency = DIGEST → ダイジェストキューに追加
│ trigger.frequency = INSTANT → 即時配信
▼
[Quiet Hoursチェック]
│ Quiet Hours内 AND 優先度 ≠ CRITICAL → ダイジェストキューに追加
│ Quiet Hours外 OR 優先度 = CRITICAL → 即時配信
▼
[配信実行]優先度によるオーバーライド
一部の通知は、ユーザー設定に関係なく配信を強制する。
| 優先度 | オーバーライドルール |
|---|---|
| CRITICAL | Quiet Hours を無視して即時配信。チャネルOFF設定は尊重する。 |
| HIGH | Quiet Hours 中はダイジェストに回す。ユーザー設定を尊重。 |
| MEDIUM | 全てのユーザー設定を尊重。 |
| LOW | 全てのユーザー設定を尊重。デフォルトでダイジェスト。 |
5. ダイジェスト配信
ダイジェスト集約ルール
| 設定 | 配信タイミング | 集約期間 |
|---|---|---|
| DAILY_MORNING | 毎朝 (設定時刻) | 前日の設定時刻〜当日の設定時刻 |
| DAILY_EVENING | 毎夕 (設定時刻) | 当日朝〜当日の設定時刻 |
| WEEKLY | 毎週月曜 (設定時刻) | 前週月曜〜当週月曜 |
ダイジェストメッセージ形式
メール:
件名: [Issue Outsource] 通知ダイジェスト - 2026/03/28
━━━━━━━━━━━━━━━━━━━━━━━
📋 新規Issue (3件)
━━━━━━━━━━━━━━━━━━━━━━━
• #142 React コンポーネントリファクタリング - ¥15,000 (期限: 4/5)
• #143 API エラーハンドリング改善 - ¥8,000 (期限: 4/3)
• #144 テストカバレッジ向上 - ¥12,000 (期限: 4/7)
━━━━━━━━━━━━━━━━━━━━━━━
💬 コメント (5件)
━━━━━━━━━━━━━━━━━━━━━━━
• #140 に田中さんからコメント: "LGTMです!細かい..."
• #141 に佐藤さんからコメント: "修正方針について..."
...他3件
━━━━━━━━━━━━━━━━━━━━━━━
詳細はプラットフォームでご確認ください:
https://outsource.example.com/notificationsSlack/Discord: 同様の構造をBlock Kit / Embedで表現する(1メッセージにまとめる)。
6. アカウント連携
Slack連携
- プラットフォーム設定画面で「Slackと連携」ボタンをクリック
- Slack OAuth認可フローを実行
- ユーザーのSlack IDを
user_external_accountsテーブルに保存 - 以降、Slack通知はそのユーザーへのDM or チャネルメンションで配信
Discord連携
- プラットフォーム設定画面で「Discordと連携」ボタンをクリック
- Discord OAuth2認可フローを実行
- ユーザーのDiscord IDを
user_external_accountsテーブルに保存 - 以降、Discord通知はサーバー内でのメンション or DMで配信
user_external_accounts テーブル
user_external_accounts
├── id: UUID (PK)
├── user_id: FK → users
├── provider: enum (SLACK, DISCORD, GITLAB)
├── external_id: varchar (Slack/Discord ユーザーID)
├── external_username: varchar
├── access_token: varchar (encrypted)
├── refresh_token: varchar (encrypted, nullable)
├── token_expires_at: timestamp (nullable)
├── connected_at: timestamp
├── created_at: timestamp
└── updated_at: timestamp
UNIQUE(user_id, provider)7. 管理者設定
システム全体の通知設定
管理者は以下をシステムレベルで制御できる。
| 設定項目 | 説明 | デフォルト |
|---|---|---|
| 通知送信の有効/無効 | システム全体の通知を一時停止 | 有効 |
| デフォルトチャネル設定 | 新規ユーザーの初期チャネル設定 | マトリクスに準拠 |
| ダイジェスト配信可否 | ダイジェスト機能の有効/無効 | 有効 |
| Quiet Hours 強制設定 | 全ユーザーに適用するQuiet Hours | 無効 |
| 最大リトライ回数 | 配信失敗時の最大リトライ | 3回 |
| リトライ間隔 | リトライ間のバックオフ設定 | 5分, 10分, 30分 |
通知テンプレート管理
管理者はプラットフォーム管理画面から通知テンプレートを編集可能。
- テンプレートはYAML形式で管理
- プレースホルダー変数一覧をUIで確認可能
- プレビュー機能で送信前に表示を確認
- バージョン管理(テンプレート変更履歴を保持)
8. 通知ログ・監査
notification_logs テーブル
notification_logs
├── id: UUID (PK)
├── notification_id: FK → notifications
├── channel: enum
├── status: enum (PENDING, SENT, DELIVERED, FAILED, BOUNCED)
├── error_message: text (nullable)
├── retry_count: int
├── external_message_id: varchar (Slack ts / Discord message_id)
├── sent_at: timestamp
├── delivered_at: timestamp (nullable)
├── created_at: timestamp
└── updated_at: timestamp管理ダッシュボード指標
| 指標 | 説明 |
|---|---|
| 配信成功率 | チャネル別の配信成功率 |
| 平均配信遅延 | トリガー発生〜配信完了の平均時間 |
| ダイジェスト利用率 | ダイジェスト設定を有効にしているユーザーの割合 |
| チャネル別利用率 | 各チャネルの有効化率 |
| エラー発生率 | 配信失敗率とエラー種別内訳 |
| Quiet Hours 利用率 | Quiet Hoursを設定しているユーザーの割合 |