US-001:注文確定時の在庫ロック
基本情報
| 項目 | 内容 |
|---|---|
| ID | US-001 |
| タイトル | 注文確定時にSKU単位で在庫を確実にロックしてオーバーセルを防止する |
ユーザーストーリー
As a 購入しようとする顧客
I want 注文確定時に選択した商品の在庫が確実に確保される
So that 同一SKUへの同時購入により在庫不足や二重販売が発生しない
日本語記述
購入しようとする顧客として、安心して購入を完了するために、注文確定時に選択した商品の在庫が確実に確保され、同一SKUへの同時購入により在庫不足や二重販売が発生しない仕組みが必要である。
背景・目的
ビジネス背景
ファッションECでは、セールやタイムセール時に秒間数千のリクエストが集中し、同一商品への同時注文が頻発する。在庫ロック機構が不十分だとオーバーセル(販売可能数を超えた受注)が発生し、顧客への謝罪・キャンセル対応が必要となり、ブランド信頼性の低下につながる。プロジェクト概要では「ピーク時における在庫整合性の保持」が最重要要件として定義されている。
ユーザーニーズ
- 顧客視点: 注文確定ボタンを押した時点で在庫が確保されていることを保証してほしい
- 運営視点: オーバーセルによる顧客対応コストとブランド毀損を回避したい
- 倉庫視点: 確定した注文数と実在庫が必ず一致していてほしい
現状の課題
- カート追加時の在庫チェックと注文確定時の在庫状況にタイムラグがある
- 複数ユーザーが同時に注文確定すると在庫数の更新競合が発生する
- 決済失敗時の在庫ロック解放が適切に行われない場合がある
受入基準(Acceptance Criteria)
機能要件
AC-1: 並列注文での在庫オーバーロック防止
Given SKU Aの利用可能在庫が10件、複数のユーザーが同時に購入処理を行っている
When 複数ユーザーが数量1で注文確定を同時に送信する(1000並列リクエスト)
Then 在庫はリクエスト順に順次ロックされ、最終的にロック数が利用可能在庫を超えない(合計ロック数 ≤ 10)
詳細説明:
- 在庫ロック処理はトランザクション内で実装
- データベースの楽観ロック(@Version)を使用
- 在庫不足で注文できなかったユーザーには明確なエラーメッセージを返す
- 在庫ロックIDを発行し、OrderLineに記録して追跡可能にする
AC-2: 在庫不足時の明確なエラー通知
Given SKU Aの利用可能在庫が0件
When ユーザーが注文確定を試みる
Then 「申し訳ありません。在庫不足のため注文できませんでした」というメッセージが表示される
詳細説明:
- エラーレスポンスには不足しているSKU情報を含める
- HTTPステータスコード409(Conflict)を返す
- 在庫ロックは一切行わない
- カート画面に戻り、在庫切れ商品をハイライト表示
AC-3: 決済失敗時の在庫ロック自動解放
Given 注文確定後に決済処理が失敗した
When 決済失敗イベントを受け取る
Then 該当注文で保持した在庫ロックは即時に解放され、在庫数が復元される
詳細説明:
- 在庫ロック解放はInventoryTransactionに記録
- 解放理由「決済失敗」を記録
- 注文ステータスを「キャンセル」に更新
- 顧客に決済失敗メールを送信
- 在庫解放は補償トランザクション(Saga パターン)で実装
AC-4: 冪等性の保証(重複リクエスト対策)
Given 同一リクエストの再送(ネットワークリトライ/クライアント再試行)が発生する
When 冪等キー(Idempotency-Key)を付与して再送される
Then 二重課金や二重ロックが発生せず、同一リクエストは一度だけ処理される
詳細説明:
- Idempotency-Keyをリクエストヘッダーで受け取る
- 既に処理済みのキーの場合は前回のレスポンスを返す
- Idempotency-Keyの有効期限は24時間
- データベースにIdempotency-Keyと処理結果を保存
AC-6: 高負荷時のパフォーマンス要件
Given ピーク時に秒間1000件の注文確定リクエストが発生
When 負荷試験を実施
Then 注文確定APIのP99レスポンスタイムが2秒以内
詳細説明:
- データベースコネクションプーリングを適切に設定
- 書き込みはデータベースに直接実施
非機能要件
パフォーマンス
- 在庫ロックAPIのP99レスポンスタイム: 2秒以内(ピーク時)
- 同一SKUへの1000並列ロックでデータ不整合が発生しない
- 冪等性チェックのオーバーヘッド: 50ms以内
セキュリティ
- ユーザーは自分の注文のみロック可能(認可チェック必須)
- 権限のないユーザーが他者の注文IDを指定した場合は403エラー
- Idempotency-Keyの予測不可能性(UUID v4推奨)
- 在庫操作の監査ログ記録
可用性
- 在庫サービスダウン時はサーキットブレーカーで注文を一時停止
- エラー時は顧客に再試行を促すメッセージを表示
- 在庫ロックの自動解放(24時間後に未決済の場合)
保守性
- 在庫ロック/解放の全操作を監査ログに記録
- 在庫不整合検知の自動アラート
- 定期的なバックグラウンド整合性チェックジョブ
- 在庫ロックIDによる追跡可能性
UI/UX要件
画面遷移
[カート画面] → [注文確認画面] → [注文確定処理中] → [注文完了画面]
↓
[在庫不足エラー画面]
インタラクション
- 注文確定ボタン押下時に確認ダイアログ表示
- 処理中はボタンを無効化し、二重送信を防止
- 在庫確保中はローディングスピナーとステータスメッセージを表示
- エラー時は在庫切れ商品を赤色でハイライト表示
依存関係
前提条件
- ユーザー認証機能が実装済み
- カート管理機能が実装済み
- SKUマスタが構築されている
- PostgreSQL(トランザクション分離レベル: READ COMMITTED以上)
依存するストーリー
- なし(最優先の基盤ストーリー)
ブロッカー
- なし
備考・コメント
設計上の決定事項
- 在庫ロックは楽観ロックを基本とする
- 決済は非同期処理とし、在庫ロックと分離(Saga パターン)
- 在庫ロックの有効期限は24時間(未決済の場合自動解放)
- 冪等性保証のためIdempotency-Keyを必須化
将来の拡張性
- リアルタイム在庫可視化ダッシュボード
- AIによる需要予測と在庫最適化
- 分散トランザクション(2PC)への移行検討