エラー分類の方針
- 認証エラー: Apple Sign In・セッション期限切れ等、ログイン誘導が必要
- ビジネスエラー: ポイント不足・既投票・期間外等、UIでメッセージ表示
- ネットワークエラー: Supabase通信失敗、リトライ可能(RetryHelper活用)
- 整合性エラー: 非アトミック処理の途中失敗、原則 throws で上位に伝播
- StoreKitエラー: 購入失敗・検証失敗、StoreKit 2 標準エラーをラップ
定義済み Error 型
AuthError(認証)
enum AuthError: LocalizedError {
case invalidNonce
case credentialFetchFailed
case sessionExpired
case userNotFound
// ...
}
VoteError(投票)
enum VoteError: LocalizedError {
case insufficientPoints
case alreadyVoted
case rankingEnded
case rankingNotStarted
}
RankingServiceError(ランキング作成・更新)
enum RankingServiceError: LocalizedError {
case insufficientPoints(required: Int, current: Int)
case networkError
case unknown(String)
}
エラー一覧
| エラーID |
分類 |
発生条件 |
ユーザー表示 |
復旧方法 |
ロギング |
| RS-AUTH-01 |
認証 |
Apple Sign In キャンセル |
サイレント(再試行を促す) |
再ボタン押下 |
info |
| RS-AUTH-02 |
認証 |
nonce検証失敗 |
「サインインに失敗しました」 |
再試行 |
error |
| RS-AUTH-03 |
認証 |
セッション期限切れ |
ログイン画面へ自動遷移 |
再ログイン |
warning |
| RS-VOTE-01 |
ビジネス |
ポイント不足(投票・再投票) |
「ポイントが足りません(必要 N pt)」 |
動画視聴/購入で補充 |
info |
| RS-VOTE-02 |
ビジネス |
既に投票済み(Unique制約違反) |
「すでに投票済みです」 |
結果画面へ誘導 |
info |
| RS-VOTE-03 |
ビジネス |
ランキング期間外 |
「投票期間外です」 |
結果画面 or 戻る |
info |
| RS-CR-01 |
ビジネス |
ランキング作成時のポイント不足 |
「N pt 必要です(現在 M pt)」 |
下書き保存 or ポイント補充 |
info |
| RS-CR-02 |
整合性 |
作成途中失敗(非アトミック) |
「作成に失敗しました。下書きから再開できます」 |
下書き復元 |
error |
| RS-NET-01 |
ネットワーク |
Supabase通信失敗 |
「通信エラーが発生しました」 |
RetryHelperで自動リトライ(3回) |
warning |
| RS-SK-01 |
StoreKit |
購入失敗 |
「購入処理に失敗しました」 |
復元ボタン誘導 |
error |
| RS-SK-02 |
StoreKit |
verification失敗 |
「決済の検証に失敗しました」 |
サポート問い合わせ |
error |
| RS-PT-01 |
整合性 |
ログインボーナス二重付与検出 |
サイレント(既受領扱い) |
— |
warning |
UI 表示パターン
| 重要度 | 表示形式 | 例 |
| 低 | インラインメッセージ / Toast | 「すでに投票済みです」 |
| 中 | Alert ダイアログ | 「ポイント不足」「通信エラー」 |
| 高 | フルスクリーン誘導画面 | セッション期限切れ → LoginView |
非アトミック処理の方針
非アトミック注意:
RankingService.createRanking()(4ステップ)と
VoteService.castVote()(4ステップ)は途中失敗時に整合性が崩れる可能性。
- 失敗時は
cancelRefund アクションで補償処理
- 本番運用では Supabase Edge Function 化(トランザクション化)を推奨
RetryHelper の使い方
// 副作用なし処理のみ対象。指数バックオフで自動リトライ
try await RetryHelper.run(maxAttempts: 3, initialDelay: 0.5) {
try await supabase.fetchRanking(id: rankingId)
}
- 最大3回、初期遅延0.5秒、最大4秒
- POST/INSERT のような副作用ありの処理には使わない
変更履歴
| バージョン | 日付 | 変更内容 |
| 1.0 | 2026-05-09 | 初版作成(ソースコードからリバース) |