# バッチ設計書 29-PersonalAccessTokens::ExpiredNotificationWorker

## 概要

本ドキュメントは、期限切れとなったパーソナルアクセストークンについて通知を送信するバッチ処理「PersonalAccessTokens::ExpiredNotificationWorker」の設計仕様を記載する。

### 本バッチの処理概要

本バッチは、当日有効期限が切れたパーソナルアクセストークン（PAT）のユーザーに対して、期限切れ通知メールを送信する処理を行う。期限切れ前の事前通知（ExpiringWorker）とは異なり、実際に期限が切れた当日に通知を行う。

**業務上の目的・背景**：パーソナルアクセストークンの有効期限が切れると、そのトークンを使用した認証は即座に失敗する。ユーザーに期限切れを通知することで、トークンの再発行を促し、認証失敗の原因を明確にする。特にCIパイプラインやAPIインテグレーションで使用されるトークンの場合、この通知により問題の早期発見と対応が可能になる。

**バッチの実行タイミング**：Cronジョブとして毎日実行される。当日期限切れとなったトークンを対象とする。

**主要な処理内容**：
1. 当日期限切れかつ未通知のトークンを持つユーザーを検索
2. 各ユーザーに対してNotificationServiceで期限切れ通知メールを送信
3. 処理対象のトークン名をメールに記載（最大100件）
4. 通知済みフラグ（after_expiry_notification_delivered）を更新

**前後の処理との関連**：ExpiringWorkerは期限切れ前（7日、30日、60日前）の事前通知を担当し、本ワーカーは期限切れ当日の通知を担当する。

**影響範囲**：personal_access_tokensテーブルの通知フラグ更新、メール送信。

## バッチ種別

通知配信 / セキュリティ運用

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | 日次（Cron） |
| 実行時刻 | システム設定による |
| 実行曜日 | 毎日 |
| 実行日 | - |
| トリガー | cron |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| データベース接続 | personal_access_tokensテーブルへのアクセスが可能であること |
| メール設定 | SMTPが設定されていること |

### 実行可否判定

特別な実行可否判定ロジックはなく、Cronスケジュールに従って実行される。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| args | 任意 | No | - | 使用しない（互換性のため） |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| personal_access_tokens | DB | トークン情報テーブル |
| users | DB | ユーザー情報テーブル |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| personal_access_tokens | DB | 通知フラグ更新 |
| メール | 通知 | ユーザーへの期限切れ通知メール |
| アプリケーションログ | ログ | 処理情報 |

### 出力ファイル仕様

ファイル出力なし

## 処理フロー

### 処理シーケンス

```
1. NotificationService初期化
2. ユーザー検索ループ
   └─ User.with_personal_access_tokens_expired_today.find_each
3. 各ユーザーのトークン処理
   └─ personal_access_tokens.without_impersonation.expired_today_and_not_notified
   └─ トークン名を最大100件まで取得
   └─ NotificationService.access_token_expired送信
   └─ ログ出力（User ID）
   └─ after_expiry_notification_delivered = true に更新
```

### フローチャート

```mermaid
flowchart TD
    A[バッチ開始] --> B[NotificationService初期化]
    B --> C[期限切れトークンユーザー検索]
    C --> D{ユーザーあり?}
    D -->|なし| Z[バッチ終了]
    D -->|あり| E[ユーザーコンテキスト設定]
    E --> F[未通知の期限切れトークン取得]
    F --> G[トークン名抽出 最大100件]
    G --> H[access_token_expired通知送信]
    H --> I[ログ出力]
    I --> J[通知フラグ更新]
    J --> K[次のユーザーへ]
    K --> D
```

## データベース操作仕様

### 操作別データベース影響一覧

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| ユーザー検索 | users | SELECT | 期限切れトークンを持つユーザー抽出 |
| トークン取得 | personal_access_tokens | SELECT | 当日期限切れの未通知トークン |
| 通知フラグ更新 | personal_access_tokens | UPDATE | 通知済みフラグ設定 |

### テーブル別操作詳細

#### users

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, email等 | with_personal_access_tokens_expired_today | find_eachでバッチ処理 |

#### personal_access_tokens

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| SELECT | id, name | expired_today_and_not_notified, without_impersonation | 最大100件 |
| UPDATE | after_expiry_notification_delivered | true | each_batchで更新 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | メール送信エラー | SMTP障害 | 例外発生、Sidekiqリトライ |
| - | データベースエラー | DB接続失敗 | 例外発生、Sidekiqリトライ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | Sidekiqデフォルト |
| リトライ間隔 | Sidekiqデフォルト |
| リトライ対象エラー | 一般的な例外 |

### 障害時対応

バッチ失敗時はSidekiqの標準リトライに委ねる。通知フラグが更新されていないトークンは次回実行時に再処理される。

## トランザクション仕様

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | ユーザー単位 |
| コミットタイミング | each_batch更新完了時 |
| ロールバック条件 | 更新失敗時 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | find_eachでバッチ処理（デフォルト1000件） |
| 目標処理時間 | 対象ユーザー数に依存 |
| メモリ使用量上限 | MAX_TOKENS: 100件/ユーザー |

## 排他制御

特別な排他制御はなし。idempotentではない。通知フラグで重複通知を防止。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| 情報ログ | 通知送信後 | "Notifying User {user_id} about expired tokens" |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| 処理失敗 | 継続的な失敗 | システム管理者 |
| メール送信エラー | 異常な発生率 | メールシステム管理者 |

## 備考

- feature_category: system_access
- data_consistency: always
- idempotent: false
- MAX_TOKENS: 1ユーザーあたり最大100トークンまでメール記載
- without_impersonation: なりすましトークンは対象外
- each_batch: 効率的なバッチ更新を使用
