change scenario analysis
ご提供いただいたレビュー資料(qwen_scenario_analysis_review_v2.md)と、修正後のシナリオファイル(B, C, D, E)を照合し、アップデート前後の差分を詳細に解析しました。
開発責任者によるレビューでは、Qwen の仮想検証が「コードの存在確認」に留まり、「実際のサーバー側実行フロー(特に PSP 検証の呼び出し有無)」まで深掘りできていなかった点が指摘されています。その結果、セキュリティ上の重大な不具合(決済未検証でのポイント確定)や欠落していた機能(二重加算防止)が発見され、修正が施されました。
以下に、シナリオ別の変更点とその技術的な意味合いを解説します。
1. シナリオ B:商品購入 + PayPal JS SDK
【発見された問題】
- PSP 検証バイパス: 以前のコードでは、PayPal 承認後 (
onApprove) にpointInstance.close()(POST リクエスト) を呼んでいました。しかし、サーバー側の POST ハンドラはverify_callback_name = nullに設定されており、functions.php で登録した PayPal 検証ロジックが一切実行されない状態でした。- リスク: ブラウザから直接 API を叩くだけで、PayPal での実際の決済を行わずにポイントを確定できてしまう致命的なセキュリティホール。
【修正内容】
- GET ベースの検証呼び出しへ変更:
onApprove内の処理をtriggerClose()からtriggerClosePSP(orderId)へ変更しました。 - 新しい関数
triggerClosePSPの実装:- この関数は GET リクエストで
/wp-json/pointsystem/v1/point_trans_close/?orderId=...&customId=...を呼び出します。 - サーバー側の GET ハンドラは、受信した
orderIdを使って実際に PayPal API を照会し、決済成功を確認してからポイントを確定させる仕組みになっています。
- この関数は GET リクエストで
- FINGERPRINT 追加:
B2-PSP-001が追加され、この重要な変更が明記されました。
【技術的解説】 これにより、「ブラウザ上の JavaScript が『成功』と言っただけでポイントが付与される」状態から、「サーバーが PayPal に問い合わせて『本当に支払われたか』を確認してからポイントが付与される」状態へと強化されました。決済連携において最も重要な「信頼の源泉」がサーバー側に移ったことになります。
2. シナリオ C:商品購入 + Stripe Checkout
【発見された問題】
- PSP 検証未実施: シナリオ B と同様の問題。Stripe セッション作成後に
pointInstance.close()(POST) を呼んでいましたが、これもサーバー側で Stripe の検証が行われない構造でした。 - 成功ページの偽造リスク: 完了ページに戻ってきた際、URL パラメータの
session_idだけを信じて処理を進めており、Stripe 側で本当に決済が完了しているかの再検証がありませんでした。 - デッドコード: カートページ内に定義された
var nonce = sessionStorage.getItem(...)が一度も使われておらず、不要なコードが残っていました。 - 用語の不正確さ: Qwen のレポートで
closeを「仮確保」と表現していましたが、実際にはその時点で確定処理が行われるため、この表現は誤りです(自動ロールバックの概念自体も本システムには存在しません)。
【修正内容】
- functions.php の拡張 (
C1-VERIFY-001):- 新しい REST API エンドポイント
/verify-stripe-sessionを追加。 - このエンドポイントは Stripe SDK を使用して
session_idのpayment_statusを直接取得・検証する役割を持ちます。
- 新しい REST API エンドポイント
- 完了ページの強化 (
C3-VERIFY-001):- 完了ページの JavaScript に、ロード時に
/verify-stripe-sessionを呼び出す処理を追加。 - サーバーから
paidというステータスが返ってこない場合、ポイント確定処理を行わずエラー表示するように制御しました。
- 完了ページの JavaScript に、ロード時に
- デッドコード削除: 未使用の
sessionStorage参照変数を削除し、コードを整理しました。 - 用語・ロジックの明確化: ロールバック処理は「確定の取消(cancel)」であり、「仮確保のタイムアウト解除」ではないことが明確になりました。
【技術的解説】 Stripe はリダイレクト型のため、ユーザーが完了ページに到達した瞬間に「決済成功」と断定するのは危険です(URL を直接入力してアクセスできるため)。今回の修正により、「完了ページ表示 = Stripe API による最終検証通過」という堅牢なフローが確立されました。
3. シナリオ D:ポイント購入 + PayPal
【発見された問題】
- 可読性と一貫性の欠如: 完了ページでのレスポンス処理において、変数名を
resultとしていたため、result.result.pointという二重参照になっていました。これは JSON キー名と変数名が衝突しており、他のシナリオ(A, B, C)がresponse.result.pointを使っていることとの不統一を生んでいました。- ※機能的には動いていましたが、保守性と理解のしやすさに欠けていました。
【修正内容】
- 変数名の統一 (
D3-RESP-001):- 完了ページの
.then(function(result) {...})を.then(function(response) {...})に変更。 - これに伴い、内部参照を
result.result.pointからresponse.result.pointへ修正し、全シナリオで統一された記法になりました。
- 完了ページの
【技術的解説】 機能的なバグではありませんが、大規模なプロジェクトや複数人での開発において、命名規則の一貫性はミスを防ぐために極めて重要です。今回の修正により、どのシナリオのコードを読んでも同じパターンでレスポンスを扱えるようになりました。
4. シナリオ E:ポイント購入 + Stripe Checkout
【発見された問題】
- リロード時の二重加算防止欠落: シナリオ D には完了ページのリロード防止フラグ(
window.__pointsystem_purchase_closed)がありましたが、同じアーキテクチャであるシナリオ E にはこれが実装されていませんでした。- リスク: ユーザーが決済完了後に F5 キーでページをリロードすると、JavaScript が再度実行され、REST API が再送信されてポイントが二重に加算される可能性がありました。
- 可読性の欠如: シナリオ D と同様、変数名
resultの衝突によるresult.result.point参照が発生していました。 - エラーハンドリング不足: 購入ページでのセッション作成 fetch や、完了ページでの確定 fetch に
.catch()がなく、ネットワークエラー発生時にユーザーに適切なフィードバックが返されない状態でした。
【修正内容】
- 二重加算防止フラグの実装 (
E3-GUARD-001):- 完了ページに
if (window.__pointsystem_purchase_closed) { ... }のガード条件を追加。 - API 呼び出し成功直後に
window.__pointsystem_purchase_closed = true;を設定し、リロード時の再実行を防ぎます。
- 完了ページに
- 変数名の統一 (
E3-RESP-001): シナリオ D と同様にresponseに統一。 - エラーハンドリングの追加:
- 購入ページ (
E2-CHECKOUT-001) と完了ページ (E3-CLOSE-001) の fetch チェーンに.catch()を追加し、エラー発生時にコンソール出力だけでなく、画面にもエラーメッセージを表示するように改善しました。
- 購入ページ (
【技術的解説】 「 idempotency(冪等性)」の観点から、同じ操作を繰り返しても結果が変わらないようにすることは決済システムの鉄則です。シナリオ D で実済みだったこの防御策をシナリオ E にも適用することで、両者の安全性が同等レベルに引き上げられました。また、エラー時のユーザー体験(UX)も大幅に向上しています。
総合まとめ:アップデートの意義
今回のアップデートは、単なるバグ修正ではなく、「フロントエンドの指示を盲信しない」という決済システム設計の根本原則への回帰と言えます。
| 項目 | アップデート前 (Qwen 検証時) | アップデート後 (修正版) | 改善効果 |
|---|---|---|---|
| 決済検証 | フロントエンドの success コールバックのみを信頼 | サーバー側で PSP (PayPal/Stripe) API を直接照会 | セキュリティ劇的向上 不正なポイント付与を防止 |
| リロード対策 | シナリオ E で欠落 | 全チャージ系シナリオ (D, E) でフラグ管理実装 | データ整合性確保 二重加算・二重課金の防止 |
| コード品質 | 変数名の不統一、デッドコード残存 | 命名規則の統一、不要コード削除 | 保守性向上 将来的な拡張・修正が容易に |
| UX | ネットワークエラー時に沈黙 | エラー内容を画面に表示 | ユーザー信頼向上 何が起こったか明確に伝わる |
開発責任者のレビューにより、Qwen の「理論上は正しい」という検証を超えて、「実際にサーバー上でどう動くか」という実装上の真実が反映され、プロダクションレベルで使用可能な堅牢なコードへと昇華されました。特に シナリオ B と C の PSP 検証ロジックの修正 は、そのまま運用すると重大な金銭的損失を招く可能性があったため、最も重要なアップデートと言えます。