通知戦略 — Severity / Channel / Source 設計
このドキュメントが Parky における通知設計の SSoT (Single Source of Truth)。 個別 source の手順 (Sentry alert rule / Synthetic healthcheck / Incident response) は 別 doc に詳細を持つが、Severity 区分・Channel 振り分け・Format 標準・Anti-pattern は すべて本 doc に従う。新規 alert を追加するときも本 doc の 4 軸 (severity / channel / format / dedup) を必ず守ること。
1. 設計原則 — 1 行で
Severity 4 段 (P0/P1/P2/P3) を Discord 4 channel に 1 対 1 マッピング。各 source は severity に応じて自動振り分け。Stripe 流 SLA + Linear 流 silent-by-default + Cloudflare 流 native notification のハイブリッド。1 人運用 / pre-launch に最適化。
2. Severity Taxonomy
| Severity | 名称 | 判断基準 | SLA | Mention |
|---|---|---|---|---|
| P0 | Critical | 本番 user 影響 / データ損失 / セキュリティ侵害 / 手動復旧必須 | 15 分以内 | @here 必須 |
| P1 | High | 本番一部影響 or 業務支障、放置で P0 化、自動 retry でしのげる | 4 時間以内 | なし |
| P2 | Info | 確認必要だが緊急ではない、自動回復済 or 進捗通知 | 翌営業日 | なし |
| P3 | Digest | 個別 alert は不要、定期サマリーで把握すれば十分 | 週次 review | なし |
判定フロー
- 本番 user に影響あるか? → Yes なら最低 P1、影響大 (全停止 / データ損失) なら P0
- 放置で P0 化するか? → Yes なら P1
- 個別に見る価値あるか? → Yes なら P2、No なら P3 (digest)
1 人運用での簡略化: P0 のみ通知音 ON / mention 有り。P1 はサイレント通知 (見たら対応)。 P2 / P3 は寝かせて朝チェック。これにより「夜中に起きる必要があるのは P0 のみ」が明確化する。
3. Discord Channel 設計
通知 channel は 2 軸構成 で設計する:
- A. Operational alert (4 channel) — システム異常・運用イベント。Severity (P0/P1/P2/P3) と 1 対 1 マッピング。
- B. Business workflow event (N channel, topic 別) — 業務フローのトリガー (新規 task / 申請 / 重要 user action 等)。severity ではなく topic で分類。
両者は 完全に分離 する。Business event を operational channel に混ぜると alert 疲れの典型 anti-pattern (Stripe / Linear で確立された原則)。
A. Operational alert channels (severity-based)
Severity と 1 対 1 マッピング。1 人運用なら source 別 (Sentry / GHA / CF) 分割よりも severity 別の方が認知負荷が低い (Linear / Vercel 同パターン)。
| Channel | Severity | Mention | 想定頻度 | 反応 SLA |
|---|---|---|---|---|
#parky-alerts |
P0 | @here 必須 |
月 0-3 件 | 15 分以内 |
#parky-ops |
P1 | なし | 週 5-20 件 | 4 時間以内 |
#parky-deploys |
P2 | なし | 日 2-10 件 | 翌営業日 |
#parky-insights |
P3 | なし | 週 1 件 + 月 1 件 | 週次 review |
B. Business workflow event channels (topic-based)
| Channel | Topic | Severity 相当 | Mention | 想定頻度 |
|---|---|---|---|---|
#parky-admin-tasks |
管理者向け新規 task / 緊急 task | P2 (info)、urgency=high で P1 相当 | なし | 日 1-10 件 |
将来追加候補 (launch 後):
Channel Topic #parky-owner-applications新規オーナー申請 / 書類提出 #parky-revenue大口決済 / 売上速報 #parky-signups新規ユーザー登録 (digest) #parky-supportサポート chat 着信
Business event channel の設計原則:
- 必ず severity を付与 (上表の "Severity 相当" 列) — 同じ format 標準を使い、視覚的に operational alert と一貫させる
- 1 topic = 1 channel (混ぜない) — 「タスク全部」じゃなく「admin タスク作成」「owner 申請」のように具体的に
- mention は基本 false — operational P0 だけが mention、business event は mute された情報源
- 新規 channel 追加時は本 doc の表に追記必須 — channel 数が増えすぎないようゲートする (5+ になったら統合検討)
- alert ではなく "event log" として扱う — 必ずしも対応必須ではなく、業務状況を見渡す目的
各 channel の用途まとめ
#parky-alerts (P0)
本番障害、データ損失、セキュリティ侵害、Critical CVE。15 分以内に確認 + Discord で「対応開始」リアクション or reply。
#parky-ops (P1)
業務に支障あるが緊急じゃない、修正計画立てる対象。営業時間内、4 時間以内に対応。
#parky-deploys (P2)
進捗確認、後追いで見ればよい情報。翌営業日に確認 OK、対応不要も多い。
#parky-insights (P3)
定期サマリー、傾向把握、business KPI。週次 review でまとめて見る。
4. Source × Channel × Action 完全表
新規 alert を追加するときは必ずこの表に行を足してから実装すること。各行が「① system / ② 頻度 / ③ check / ④ 条件 / ⑤ メッセージ / ⑥ channel / ⑦ action」の 7 軸を満たす。
P0 → #parky-alerts
| ① system | ② 頻度 | ③ check 対象 | ④ 条件 | ⑤ メッセージ内容 | ⑦ アクション |
|---|---|---|---|---|---|
| Sentry (parky-api prod) | 連続 (event drive) | error イベント数 | 5xx が 5分窓で 50件超 (=10/min) | [P0] parky-api 5xx burst (52/5min) + Sentry issue link + runbook |
即 Sentry 開く → wrangler tail → Worker rollback 判断 |
| Sentry (全 prod project) | 1時間粒度 | Error budget burn rate | 14.4× (1h で 30日 budget の 2% 焼失) | [P0] Error budget fast burn 14.4× + SLO link |
SLO doc → 障害源特定 → deploy freeze 検討 |
| Synthetic healthcheck | 5 分 cron | api.parky.co.jp/healthz |
連続 2 回 fail (5-10 分継続) | [P0] prod healthz down + workflow run link + runbook |
wrangler tail prod → Hyperdrive/R2 切り分け → status page 更新 |
| Cloudflare Notifications | リアルタイム | Workers script | platform-side outage | [P0] CF Workers outage detected + CF status link |
CF status page → ユーザー告知 |
| Cloudflare Notifications | リアルタイム | WAF / DDoS | 大規模攻撃検知 | [P0] WAF blocking surge + analytics link |
WAF rule 確認 → IP rate limit 判断 |
| Supabase Cron | 1 分粒度 | DB 接続 | prod DB 接続喪失 (test query fail) | [P0] Supabase prod DB unreachable + Supabase dashboard |
Supabase status → connection pool 確認 |
| GitHub security alert | リアルタイム | secret scan | secret leak detected (push に key 等) | [P0] Secret leaked in commit <sha> + GitHub Security tab link |
即 rotate → git history purge 判断 |
P1 → #parky-ops
| ① system | ② 頻度 | ③ check 対象 | ④ 条件 | ⑤ メッセージ内容 | ⑦ アクション |
|---|---|---|---|---|---|
| Sentry | 5 分粒度 | new issue rate | 新規 issue が 100/h 以上 | [P1] New high-volume issue + Sentry link |
issue triage → fix sprint に追加 |
| Sentry Performance | 1 時間粒度 | p95 latency | 通常比 +50% | [P1] p95 regression on /v1/... + Performance tab |
trace 確認 → 直近 deploy revert 判断 |
| Synthetic healthcheck | 5 分 cron | dev-api.parky.co.jp/healthz |
連続 2 回 fail | [P1] dev healthz down + run link |
dev wrangler tail → 修正 push |
| GHA (deploy-*-prod) | event drive | workflow conclusion | failure | [P1] prod deploy failed: <workflow> + run link + last commit |
run log 確認 → re-run or fix → re-merge |
| GHA (E2E / lint / drift) | event drive | main branch 連続 fail | 連続 3 回失敗 | [P1] CI failing on main: <workflow> + run link |
安定化 PR 作成、main の merge 凍結 |
| DLQ monitor | 5 分 cron | Cloudflare Queue dead letter | 蓄積 >10 件 | [P1] DLQ accumulating: <queue> (<n> messages) + summary |
dead letter 内容確認 → re-enqueue or 修正 |
| Cost monitor (週 1 cron) | 週 1 月曜朝 | 各 service quota | 80% 到達 (CF / Sentry / GH Actions / Supabase) | [P1] <service> quota at 80% (X / Y) |
使用パターン確認 → optimize or upgrade plan 判断 |
| Cloudflare Notifications | リアルタイム | R2 / KV quota | 80% 到達 | [P1] R2 storage at 80% (X GB / Y GB) |
古い object 削除 or plan upgrade |
| Dependabot | event drive | Critical CVE | 新規 Critical CVE 発見 | [P1] Critical CVE: <package> <version> + advisory link |
PR review → merge 判断 |
| Supabase Cron | 5 分 cron | connection pool | 使用率 >80% | [P1] Supabase pool 85% (90/100) |
slow query 探索、pool size 拡張判断 |
| Supabase Cron | 1 時間 cron | slow query | p99 >1s | [P1] Slow query spike: <query digest> |
EXPLAIN → index 追加 |
P2 → #parky-deploys
| ① system | ② 頻度 | ③ check 対象 | ④ 条件 | ⑤ メッセージ内容 | ⑦ アクション |
|---|---|---|---|---|---|
| GHA (deploy-*-prod) | event drive | workflow conclusion | success | [P2] prod deploy success: <workflow> + commit / changelog link |
任意で smoke test、通常は確認のみ |
| GHA (deploy-*-dev) | event drive | workflow conclusion | success / failure | [P2] dev deploy <result>: <workflow> + run link |
dev URL で動作確認 |
| Sentry | event drive | new low-volume issue | 新規 issue (<10/h) | [P2] New issue: <title> + Sentry link |
朝確認、優先度判定 |
| Sentry | event drive | regression | 解決済 issue が再発 | [P2] Regression: <title> + last fix commit |
該当 commit 調査 |
| Migration apply | event drive | DB migration 適用 | apply success | [P2] Migration applied: <filename> (env: <env>) |
適用ログ確認のみ |
| Workers Versioned Uploads (将来) | gradual rollout step | rollout 進捗 | 10% → 50% → 100% 遷移 | [P2] Rollout progressed: 10%→50% (<version>) |
error rate 増加なければ続行 |
| Dependabot | event drive | High / Medium CVE | 新規 High/Medium CVE | [P2] High CVE: <package> + advisory |
翌週の dep update PR にまとめる |
| Cloudflare Notifications | event drive | Pages / Worker deploy fail | platform-side fail | [P2] CF Pages deploy failed: <project> + CF dashboard |
CF UI で deploy log 確認 |
Business events → topic-based channels
| ① system | ② 頻度 | ③ check 対象 | ④ 条件 | ⑤ メッセージ内容 | ⑥ channel | ⑦ アクション |
|---|---|---|---|---|---|---|
BFF (bff/admin/tasks.ts) |
event drive | admin_tasks INSERT | is_new=true (xmax = 0 で判定) |
[P2] Admin task created: <task_kind> + ref_id / urgency / memo / due_at |
#parky-admin-tasks |
管理者ポータルで該当タスク確認 |
| BFF (owner inquiry submit) | event drive | 同上 (auto-task) | 同上 | [P2] Admin task created + applicant / lot / assets |
#parky-admin-tasks |
書類確認 + approve/reject 判断 |
| BFF future: owner application | event drive | owner_inquiries INSERT | 新規申請 | [P2] Owner application: <name> |
#parky-owner-applications (将来) |
LP 経由申請の review |
| BFF future: revenue | event drive | revenue_transactions INSERT | 1件 ≥ 1万円 | [P2] Big revenue: ¥X,XXX |
#parky-revenue (将来) |
大口決済の確認 |
| BFF future: signups | 日次 cron | app_users INSERT | 過去 24h 集計 | [P2] Daily signups: 12 |
#parky-signups (将来) |
集計 trend 確認 |
P3 → #parky-insights
| ① system | ② 頻度 | ③ check 対象 | ④ 条件 | ⑤ メッセージ内容 | ⑦ アクション |
|---|---|---|---|---|---|
| GHA cron (週 1 月曜朝) | 週 1 (cron) | Sentry top issues | 過去 7 日 sample | [P3] Weekly Sentry digest: top 10 / new N / resolved M + dashboard link |
月曜 review で確認、優先度割当 |
| GHA cron (週 1) | 週 1 | synthetic healthcheck history | 過去 7 日 fail rate | [P3] Weekly uptime: dev 99.7% / prod 100% |
trend 確認 |
| GHA cron (週 1) | 週 1 | GH Actions usage | 過去 7 日 minutes 消費 | [P3] GH Actions: 412 min used (Free 2000 残) |
圧縮検討タイミング |
| GHA cron (月 1, 1 日) | 月 1 | 全 service cost | 各 service 月額 | [P3] Monthly cost: CF $0 / Supabase $0 / Sentry $0 / Mapbox $X |
コスト review |
| Dependabot | 週 1 | Low CVE + outdated | 過去 7 日 まとめ | [P3] Weekly deps: 3 low CVE / 12 outdated + PR list |
週次でまとめて update PR |
| Supabase Cron | 週 1 | storage growth | 過去 7 日 増分 | [P3] DB storage: +120MB / week (total 480MB) |
scale plan 判断 |
| Business KPI (launch 後) | 週 1 | DAU/MAU/signup/revenue | 過去 7 日 集計 | [P3] Weekly KPI: DAU 1,234 / signup +56 / 駐車場登録 +12 |
trend 確認 |
5. Alert Format 標準
必須 field (1 つでも欠けたら NG)
| Field | 内容 | 例 |
|---|---|---|
| severity badge | title 先頭に [P0]/[P1]/[P2]/[P3] + 絵文字 |
:rotating_light: [P0] / :warning: [P1] / :information_source: [P2] / :bar_chart: [P3] |
| service | 影響を受けるシステム名 | parky-api (prod) / parky-admin (dev) |
| symptom | 1 行で症状を要約 | 5xx errors burst (52/min, threshold 10) |
| env | dev / stg / prod の明示 | env: prod |
| triggered_at | UTC + JST 両方記載 | 2026-04-29 10:23 JST (01:23 UTC) |
| runbook | 対応手順への直リンク | [runbook: incident-response.md#sev1](...) |
| dashboard / log | 該当する観測 dashboard URL | [Sentry issue](https://...) / [Workflow run](https://github.com/.../runs/123) |
任意 field
- owner: 主担当 (1 人運用なら省略 or
[email protected]固定) - related_alerts: 同 window で発火した別 alert ID (cascade 検知用)
- auto_resolve: 自動解決された時刻 (transient flap 等)
Discord embed の実例 (P0)
{
"content": "@here :rotating_light: **[P0] parky-api (prod) 5xx burst**",
"embeds": [{
"title": "Sentry alert: 5xx errors burst",
"color": 14431557,
"fields": [
{ "name": "Service", "value": "parky-api (prod)", "inline": true },
{ "name": "Env", "value": "prod", "inline": true },
{ "name": "Symptom", "value": "52 errors / 5min (threshold: 50)" },
{ "name": "Sentry", "value": "[Issue PARKY-123](https://parky-72.sentry.io/issues/123)" },
{ "name": "Runbook", "value": "[incident-response.md#sev1-checklist](https://github.com/...)" },
{ "name": "Triggered", "value": "2026-04-29 10:23 JST (01:23 UTC)", "inline": true }
],
"footer": { "text": "Parky Sentry alert · rule R-01" },
"timestamp": "2026-04-29T01:23:00Z"
}]
}
Discord embed 色コード (severity 視覚化)
| Severity | Decimal | Hex | 色 |
|---|---|---|---|
| P0 | 14431557 |
#DC2626 |
red |
| P1 | 15105570 |
#E67E22 |
orange |
| P2 | 3447003 |
#3498DB |
blue |
| P3 | 9807270 |
#95A5A6 |
gray |
6. Dedup / Suppression ルール
| ルール | 適用条件 | 挙動 |
|---|---|---|
| Frequency cap | 同一 alert rule | 5 分に最大 1 回 (Sentry の "At most once per X minutes" 機能で実装) |
| Flap retry | healthcheck / synthetic monitor | 連続 2 回 fail で初めて発火 (synthetic-healthcheck.yml 既存実装) |
| Auto-resolve | transient な障害 (5 分以内に回復) | 後続 message を thread reply で「自動回復」と通知、新規 alert は出さない |
| Maintenance window | 計画 deploy / migration 中 | 事前に gh workflow run notify-suppress.yml --duration 30m で全通知 mute (Phase 3) |
| Cascade suppression | 1 つの根本原因が複数 alert を発火 | 同 time window (5 分) で 5 件以上の alert は最初の 1 件のみ通知、残りは 5 alerts in window, see thread 形式に集約 |
| Severity dedup | 同 issue が P0 → 後で P1 にダウングレード | thread reply で severity 変化を通知、新規 alert は出さない |
| Dev fail tolerance | dev 環境の transient failure | 連続 5 回 fail で初めて P1 に格上げ (dev は壊れて当たり前を許容) |
夜中 mute は 1 人運用では不要: Stripe / GitHub は on-call rotation があるので "wake up only for P0" は意味あるが、Parky 1 人運用なら寝てる間の P0 も「起きてから」対応で OK。むしろ dedup を強くして「鳴ったら 100% 本物」状態を作る方が効果大。
7. Failure handling & resilience — Webhook 失敗時の振る舞い
設計判断: Discord 直 + retry + DLQ (P0 のみ email backup)
「より可用性の高い relay サービス (PagerDuty / Opsgenie / 自前 Worker) を経由する」案は delivery 目的だけなら採用しない。理由:
| 反対理由 | 詳細 |
|---|---|
| Relay 自体が SPOF | hop が増えると availability は乗算で減る (99.9% × 99.95% = 99.85%) |
| 可視性が落ちる | 失敗時「Discord/relay/Worker のどこ?」の切り分けに調査時間が増える |
| PagerDuty 等の本当の価値は配信ではない | on-call rotation / escalation / dedup / runbook 機能。最終 hop は結局 Discord/Slack/Email/SMS で同じ |
| コスト過大 | $9-19/user/mo を 1 人運用で払うなら Sentry Team plan upgrade の方が ROI 高い |
| 複雑さ vs 利益 | 多 hop で staging テスト難、設定 drift 発生しやすい |
採用するアーキテクチャは 3 層防御 + 多チャネル冗長化 (P0 のみ):
[Layer 1] Direct Discord webhook
↓ 失敗 (5xx / 429 / network error)
[Layer 2] Exponential backoff retry (3 attempts: 1s → 4s → 16s)
↓ 全失敗
[Layer 3] DLQ 永続化 (admin.notification_failures table)
+ P0 のみ email fallback (Resend, 別物理経路で送信)
↓ 後で
[Layer 4] 週次 cron が DLQ 集計 → #parky-insights に digest
故障モード別の挙動
| 故障モード | Layer 1 | Layer 2 (retry) | Layer 3 (DLQ + email) | 結果 |
|---|---|---|---|---|
| Discord rate limit (429) | 失敗 | retry 後成功 | 触らず | 数秒遅延だけ |
| Discord transient 5xx | 失敗 | retry 後成功 | 触らず | 数秒遅延だけ |
| Discord 完全停止 (SLA 99.95% = 22min/月) | 失敗 | 全 retry 失敗 | DLQ 記録 + (P0 なら email 送信) | DLQ で後で見える、P0 は email で届く |
| Webhook URL revoked | 失敗 (404) | retry しない (4xx 即 DLQ) | DLQ 記録 + (P0 なら email) | DLQ digest で気付く、P0 は email で届く |
| Worker → Discord network 障害 | 失敗 | retry で大半復旧 | 全失敗時のみ DLQ | ほぼ自動回復 |
| Payload 不正 (4xx) | 失敗 | retry しない | DLQ 記録 | dev で発見、prod に出さない |
| Discord + Email 同時停止 | 失敗 | 全 retry 失敗 | DLQ 記録のみ | 確率限りなく 0、対策不要 |
Retry policy (詳細)
| HTTP ステータス | Retry? | 理由 |
|---|---|---|
| 200 / 204 | しない | 成功 |
| 429 (rate limit) | する | Discord 30 msg/min/webhook 制限。指数 backoff で待つ |
| 5xx | する | Discord 側の transient |
| 408 / 499 (timeout) | する | network transient |
| 4xx (それ以外) | しない | payload 不正 / URL 失効、retry しても同じ |
| network error (fetch reject) | する | TLS / DNS transient |
Backoff: 1s → 4s → 16s (4× 倍増)。最大 3 回試行 = 21 秒以内に決着。
P0 backup email の設計
- 対象: severity =
P0のみ (P1/P2/P3 は DLQ 記録のみで email しない、過剰通知防止) - provider: 既存 Resend (
lib/transactional-email.ts)。物理経路が Discord と完全分離 (Resend 障害 ≠ Discord 障害) - 送信先:
[email protected](固定、複数人運用時に env で多人数化) - Subject:
[P0 BACKUP] <title>で先頭明示 (重複時の dedup 容易化) - Body: HTML + text 両対応、Discord embed と同じ field を平文化
- 失敗時の挙動: email も失敗したら DLQ の
fallback_email_sent=falseのまま、digest で目立つ - 将来拡張: 別 provider (SES / SendGrid) を二段目 fallback として追加検討、launch 後の規模次第
DLQ schema (admin.notification_failures)
| 列 | 型 | 用途 |
|---|---|---|
id |
UUID | PK |
attempted_at |
TIMESTAMPTZ | 最初の試行時刻 |
channel |
TEXT | ALERTS / OPS / DEPLOYS / INSIGHTS / ADMIN_TASKS |
severity |
TEXT | P0 / P1 / P2 / P3 |
title |
TEXT | alert title |
summary |
TEXT | 1 行要約 |
payload |
JSONB | full Discord payload (replay できる shape) |
error_message |
TEXT | 最後のエラー文字列 |
http_status |
INT | 最後の HTTP ステータス (network error は NULL) |
retry_count |
INT | 実施した retry 回数 |
status |
TEXT | failed / replayed_success / manual_acknowledged |
fallback_email_sent |
BOOLEAN | P0 backup email を送ったか |
source |
TEXT | sentry / gha / admin-task / etc. (debugging 用) |
created_at |
TIMESTAMPTZ | 作成時刻 |
週次 DLQ digest cron
- 配信先:
#parky-insights(P3) - 頻度: 毎週月曜 09:00 UTC (JST 18:00) — HOURLY スロット同居
- 内容: 過去 7 日 status='failed' の集計 (channel 別 / 件数 / top 3 エラーメッセージ)
- 集計後: 該当行の status を
manual_acknowledgedに更新 (再 digest 防止)
8. アンチパターン
新規 alert / channel 設計時に以下を作らないこと:
- 全部 1 channel に流す — P0 と info が同じ channel に並ぶと user は info の山から P0 を見つけられない、3 日で「もう見ない」状態に
@hereを P1/P2 で使う — @here が無意味化、本当の P0 で誰も気付かない、P0 のみ mention を厳守- 同じ事象を複数 source から重複通知 — 例: 5xx burst で Sentry alert + healthcheck + GHA E2E fail が同時発火 → 3 通知、Cascade suppression 必須
- Email + Discord 並行 — どちらか一本に絞る、Parky は Discord メイン、email は Sentry 個別 issue triage 用にだけ残す
- Runbook link なし — 「何が起きたか」だけ書いて「どうすればいいか」が無いと寝起き / 移動中に対応できない、全 alert に runbook link 必須
- 平文だけ (Discord embed 不使用) — 色 / icon / structured field がないと一瞥で severity 判別不可、必ず embed 形式
- Quiet hours を 1 人運用で強制 — on-call rotation があるなら意味あるが、1 人運用では結局自分で見るので mute しても意味薄い、むしろ dedup を強化
- Severity の判断を都度 — 各 alert で「これ P0?」を悩むのは時間の無駄、alert rule 作成時に severity を必ず固定、後で見直しは月次
9. テック企業ベンチマーク
| 会社 | Severity 段階 | Channel 戦略 | Dedup | 1 人運用への適用 |
|---|---|---|---|---|
| Stripe | SEV1/2/3 (15min/4h/24h SLA) | severity 別 Slack channel + PagerDuty escalation | Frequency cap + cascade detection | そのまま 4 段に拡張可、PagerDuty は不要 |
| GitHub | SEV1-4 + Public | service area × severity の matrix channels | Datadog + custom dedup | service area 分割は overkill、severity のみで十分 |
| Linear | P0/P1/P2/Info (silent-by-default) | severity 別 Slack 1 channel each + opt-in subscription | Linear notification engine | Parky の理想形に最も近い |
| Vercel | Critical / Warning / Info | internal: severity 3 channels / external: status page | Native dedup in Vercel platform | 3 channel 構成で OK、status page は launch 後 |
| Cloudflare | Critical / Warning / Info / Healthy | Notification destinations per severity (webhook / email / PagerDuty) | Per-rule frequency setting | built-in CF Notifications を活用 |
| Plaid | P0-P3 + Customer-facing | customer-facing: status page / internal: 5 channels | Datadog incident management | customer-facing は status page を将来検討 |
| Parky 採用 | P0/P1/P2/P3 (Stripe 準拠) | severity 別 4 Discord channels (Linear 同型) | Frequency cap + flap retry + cascade group | 1 人運用 / pre-launch 最適化 |
結論: Linear 流の severity-based 4 channel + Stripe 流の SLA + format 標準 + Cloudflare 流の native notification 活用 のハイブリッドを Parky で採用。
10. 実装ロードマップ
Phase 1 — 今週 (工数 2-3h)
- Discord channel 5 本作成:
#parky-alerts/#parky-ops/#parky-deploys/#parky-insights/#parky-admin-tasks - Webhook URL 5 本発行 → 1Password に保存
- Vault:
PJ|Parky - Item 名:
Discord Webhook|#parky-alerts/#parky-ops/#parky-deploys/#parky-insights/#parky-admin-tasks - Field:
url(secret)
- Vault:
- GH Secrets に登録:
DISCORD_WEBHOOK_ALERTS/DISCORD_WEBHOOK_OPS/DISCORD_WEBHOOK_DEPLOYS/DISCORD_WEBHOOK_INSIGHTS/DISCORD_WEBHOOK_ADMIN_TASKS- 既存
DISCORD_HEALTHCHECK_WEBHOOK_URLは廃止 →DISCORD_WEBHOOK_OPSに統合
- 既存
- Wrangler secrets に投入:
DISCORD_WEBHOOK_ADMIN_TASKSを dev / prod に。api/src/env/bindings.tsに型宣言済み。cd parky/api wrangler secret put DISCORD_WEBHOOK_ADMIN_TASKS --env dev wrangler secret put DISCORD_WEBHOOK_ADMIN_TASKS --env prod - Synthetic healthcheck workflow を severity-aware に改修: dev fail →
OPS/ prod fail →ALERTS - Reusable workflow
_notify-discord.yml作成: severity / channel / message を input に取り、適切な webhook + format で送信 - 全 prod deploy workflow に
if: failure()notify step 追加:_notify-discord.ymlを使いOPSへ送信 - Admin task 通知の動作確認: 管理者ポータルから新規 task 作成 →
#parky-admin-tasksに投稿されるか確認 (未投入なら warn log のみ)
Phase 2 — 1-2 週 (工数 4-6h)
- Sentry Discord native integration 設定: 2024+ で native 提供、12 alert rule 全てを severity に応じた channel に振り分け
- Cloudflare Notifications 設定: Workers outage / Pages deploy fail / R2 quota / WAF を該当 channel に webhook 配線
- DLQ monitor を
OPSへ統合:DLQ_WEBHOOK_URLをDISCORD_WEBHOOK_OPSに向け直し - Cost / Quota 監視 cron 作成: 週 1 回 GH Actions で各 service API を叩いて集計、80% 超過で
OPSへ - Dependabot 通知整理: GitHub Settings → Notifications → Dependabot を email デフォルト → repo 内 weekly digest 化
Phase 3 — 1 ヶ月 (工数 6-8h)
- Supabase 健全性監視: pg_cron で pool / slow query / RLS violation 集計 → BFF endpoint → Discord webhook
- Weekly digest workflow: 月曜朝に Sentry + GHA + uptime + cost を集約 →
INSIGHTSへ HTML サマリ - Business KPI digest (launch 後): signup / DAU / 駐車場登録 etc. →
INSIGHTS - Maintenance window mute:
scripts/notify/suppress.sh --duration 30mで全 webhook 一時無音化 - Status page (status.parky.co.jp): launch 後の customer-facing 透明性のため Better Uptime Public Status / Atlassian で構築
Phase 4 — 3 ヶ月 (工数 4h, 任意)
- Runbook automation: alert に Discord button (interactive component) 追加で "ack" / "runbook 開く" / "mute 30m" を 1 click 化
- Postmortem 自動雛形生成: P0 alert 解決後に GitHub Issue を自動生成、postmortem-template.md ベースで雛形プレフィル
11. コスト見積もり
| 項目 | 無料枠 | Parky 想定使用量 | 追加コスト |
|---|---|---|---|
| Discord webhook | 無制限 | 月 100-300 通知 | $0 |
| Sentry (Developer plan) | 5K errors/mo + 10K performance | pre-launch ~1K/mo / launch 後 5-30K/mo | launch 後超過時 $26/mo (Team) |
| GH Actions (private repo) | 2,000 min/mo | healthcheck 1,440 min + notify 100 min + digest 50 min ≈ 1,600 min/mo | Free 枠 80% (要圧縮) |
| Cloudflare Notifications | Workers Free / R2 Free 枠内 | monitor 数本 | $0 |
| Cloudflare Health Checks (本格化時) | Pro plan 必要 | 1 monitor (api.parky.co.jp) | $20/mo (Pro plan, 1 monitor 込) |
| Honeycomb (M-03 後) | 20M events/mo (Free) | pre-launch ~500K / launch 後 5-10M | $0 (Free 内) |
| Supabase (現 Free) | 500MB DB / 1GB bandwidth | schema 投入のみ、データ少 | launch 後 $25/mo (Pro plan + PITR) |
| Better Uptime / UptimeRobot (代替案) | 10 monitors (Free) | 2 monitor で十分 | $0 (Free 枠内、Cloudflare Pro 不要) |
段階別コスト
- Phase 1-2 (現状): $0/mo (Discord + GH Actions + Sentry Dev + CF Notifications + Better Uptime Free)
- launch 後 (~3 ヶ月): $25-50/mo (Supabase Pro + Sentry Team)
- scale 後 (~6 ヶ月): $100-150/mo (CF Pro / Honeycomb Pro / 専用 monitor 等)
GH Actions 圧縮策: synthetic healthcheck cron を 5 分 → 10 分間隔に変更で月使用 720 → 360 min。Better Uptime Free (10 monitors / 3 分間隔) に丸ごと移行すれば GH Actions 0 min に。
12. シナリオ別の挙動例
シナリオ A: 平常時 (ローンチ前)
- 月曜朝に
#parky-insightsで weekly digest 4-5 通 - 日中に
#parky-deploysで dev deploy 通知 5-10 通 #parky-ops#parky-alertsは基本無音
シナリオ B: dev healthcheck 1 回 fail
#parky-opsに[P1] dev healthz down1 通- 5 分後の次 cron で復活したら何も来ない (auto-resolve)
シナリオ C: prod に bad deploy
#parky-alertsに[P0] prod healthz down(synthetic healthcheck)#parky-alertsに[P0] 5xx burst(Sentry)- → cascade suppression で 2 通目以降は thread reply に集約
#parky-opsに[P1] prod deploy failed (post-deploy assert)(GHA)- 対応 → wrangler rollback → 5 分後 healthz 緑 →
#parky-alertsthread に「auto-resolved」reply
シナリオ D: Critical CVE (例: lodash 脆弱性)
#parky-opsに[P1] Critical CVE: [email protected]1 通 + Dependabot PR link- 翌営業日に PR review → merge →
#parky-deploysで deploy success 通知
13. 関連 doc
このドキュメントが SSoT。以下は本戦略に従って動く individual runbook:
- incident-response.md — P0/P1 発火時の対応フロー、SEV1/2/3 → P0/P1/P2 に整合
- sentry-alert-rules.md — Sentry 12 alert rule の severity 振り分け実装
- synthetic-healthcheck.md —
synthetic-healthcheck.ymlの channel routing - observability-hookup.md — Sentry / Honeycomb DSN 投入手順 + Discord native integration
- postmortem-template.md — P0 解決後の postmortem 雛形
- slo-error-budget.md — SLO 定義、burn rate alert の根拠
- secret-rotation.md — Webhook URL rotation を含む secret 全般
- logging.md — log level 設計 (alert 発火条件の判断材料)
監査根拠 (社内 work)
.work/parky/2026-04-29_001_parky_comprehensive_evaluation_v2.html— Operations 軸監査 (本戦略の動機).work/parky/2026-04-29_002_parky_notification_strategy.html— 本 doc の HTML 版 (visual reference)
変更履歴
- 2026-04-29: 初版作成。既存 3 つの通知配線 (Sentry alert / DLQ / synthetic healthcheck) を整理し、Severity 4 段 + Discord 4 channel の framework を確立。