# エラーハンドリング標準

[目的: エラーの分類・形式・伝播・ログ記録・監視のしかたを統一する]

## 基本方針
- 可能な箇所では早期に失敗（fail fast）させる。システム境界では穏やかに劣化させる
- スタック全体で一貫したエラー形式（人間にも機械にも読める）にする
- 既知のエラーは発生源の近くで処理し、未知のエラーはグローバルハンドラに委ねる

## 分類（発生源によって処理を決める）
- クライアント: 入力／バリデーション／ユーザー操作の問題 → 4xx
- サーバー: システム障害／想定外の例外 → 5xx
- ビジネス: ルール／状態の違反 → 4xx（例: 409）
- 外部: サードパーティ／ネットワーク障害 → 文脈を添えて 5xx または 4xx にマップする

## エラー形式（唯一の正規フォーマット）
```json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "人間が読めるメッセージ",
    "requestId": "trace-id",
    "timestamp": "ISO-8601"
  }
}
```
原則: コードは安定した enum にする、シークレットを含めない、トレース情報を含める。

## 伝播（どこで変換するか）
- API 層: ドメインエラー → HTTP ステータス + 正規ボディ に変換する
- サービス層: 型付きのビジネスエラーを投げる。文字列ベースのエラーを避ける
- データ／外部層: プロバイダのエラーを、安全で対処可能なコードでラップする
- 未知のエラー: グローバルハンドラまで伝播 → 500 + 汎用メッセージ

パターンの例:
```typescript
try { return await useCase(); }
catch (e) {
  if (e instanceof BusinessError) return respondMapped(e);
  logError(e); return respondInternal();
}
```

## ログ記録（ノイズより文脈を）
記録する: 操作、userId（取得できれば）、code、message、スタック、requestId、最小限の文脈。
記録しない: パスワード、トークン、シークレット、完全な PII、機微なデータを含むボディ全体。
レベル: ERROR（障害）、WARN（回復可能／境界ケース）、INFO（主要イベント）、DEBUG（診断）。

## リトライ（安全なときのみ）
リトライする条件: ネットワーク／タイムアウト／一時的な 5xx かつ 操作が冪等であること。
リトライしない: 4xx、ビジネスエラー、非冪等なフロー。
戦略: 指数バックオフ + ジッター、試行回数に上限。冪等性キーを要求する。

## 監視とヘルス
追跡する: コード／カテゴリ別のエラー率、レイテンシ、飽和度。スパイクや SLI 違反でアラートする。
ヘルスを公開する: `/health`（live）、`/health/ready`（ready）。エラーをトレースに紐付ける。

---
_パターンと意思決定に焦点を当てること。実装の詳細や網羅的な一覧は記載しない。_
