暗黙の分岐や例外処理を、根拠となるソース参照とともに整理する
仕様書が残っていないシステムでも、コードのリバースエンジニアリングにより、業務ルール、画面遷移、外部連携、未解決事項を移行可能な単位で可視化します。
REGEN* DELIVERABLE SAMPLES
Regen*のフェーズ0で、ソースコードのリバースエンジニアリングから「仕様書」と「移行計画」の成果物に落とし込んだサンプルです。
REGEN* DELIVERABLE SAMPLES
コードと実際の動作を照合し、移行判断に使える仕様書へ再構成した成果物です。
EXECUTIVE SUMMARY
仕様書が残っていないシステムでも、コードのリバースエンジニアリングにより、業務ルール、画面遷移、外部連携、未解決事項を移行可能な単位で可視化します。
条件分岐、計算、権限、状態遷移を整理します。
画面構成、操作、入力チェック、エラー時の挙動を復元します。
参照コードと、追加確認が必要な論点を明示します。
ソースコードと実際の動作から、システム全体、機能、画面、業務フローを段階的に復元します。用途ごとに情報を分け、更新しやすい仕様書として整理します。
※ features/ は F001_Auth 〜 F066_AdminTransactionConfig、screens/ は SCR001_Homepage 〜 SCR272_TopbarProps。各フォルダ内のファイル構成は共通です。
| ネームスペース | 目的 | ライフサイクル | 対象読者 |
|---|---|---|---|
system/ |
担当者が読むシステム概要 | AIが初稿を作成し、担当者が確認・編集 | 全員 |
generated/ |
ルート・データ・機能・要件の解析結果一覧 | 再生成可能(手動編集はしない) | rebuild-spec 内部 |
flows/ |
複数機能にまたがるビジネスフロー | AIが初稿を作成し、担当者が確認・承認 | BA / アーキテクト |
features/ |
機能ごとの詳細仕様(4ファイル、読者別) | F### 単位で生成 | Dev / BA / QA |
screens/ |
画面ごとの仕様(13セクション構成) | SCR### 単位で生成 | Dev UI / QA |
| 属性 | 型 | 制約 | 説明 |
|---|---|---|---|
id | int | PK, NOT NULL, AUTO_INCREMENT | サロゲートPK |
uuid | binary(16) | NOT NULL, UNIQUE | グローバルUUID |
ident | varchar(255) | UNIQUE | サブドメイン識別子 |
domain | varchar(255) | — | カスタムドメイン |
MODEL001(Community)を筆頭に50以上のエンティティを収録。ERD は Mermaid 形式で掲載。
| 要件ID | 利用者が実現したいこと | 種別 | 優先度 | 関連画面 |
|---|---|---|---|---|
US001_BrowseListings | 出品の検索結果を閲覧する | ui 画面 | P1 | SCR001, SCR060 |
US002_FilterListings | カテゴリ・価格・場所で絞り込む | ui 画面 | P1 | SCR001, SCR060 |
US003_ViewListingDetail | 出品の詳細を確認する | ui 画面 | P1 | SCR061 |
124件の US### コードを収録。ui 型(画面あり)と system 型(バックグラウンド)に分類。
| 処理ID | 処理名 | 役割 |
|---|---|---|
BL046 | MarketplaceLookup | ホスト/サブドメインからコミュニティを特定 |
BL047 | MarketplaceHostFromCustomHeader | カスタムヘッダーがある場合にホスト情報を上書き |
BL048 | EnforceSsl | 本番環境でHTTPをHTTPSへ転送 |
BL050 | CustomCookieRenamer | テナント分離のためCookie名を変更 |
BL052 | SessionContextMiddleware | セッション情報をリクエストへ追加 |
全ルートにミドルウェア BL046〜BL052 が適用される。Handler/Indirect BL### で直接・間接トリガーを記録。
| 画面ID | 画面名 | 認証 | 処理 | URL |
|---|---|---|---|---|
SCR001_Homepage | ホーム/検索 | pub(公開) | homepage#index | GET / |
SCR060_ListingsBrowse | 出品一覧 | pub(公開) | listings#index | GET /listings |
SCR061_ListingDetail | 出品詳細 | pub(公開) | listings#show | GET /listings/:id |
SCR091_PreauthorizeCheckout | 決済の事前承認 | auth(ログイン必須) | preauthorize_transactions#new | GET /listings/:id/initiate |
182画面を収録。pub / auth / admin / super の4認証レベル。
Mermaid フローチャートで全主要ナビゲーションパスを図示。ガード条件付き。
| 権限ID | 権限 | 方式 | 適用箇所 |
|---|---|---|---|
PERM001_ViewPublicScreens | 公開画面の閲覧 | route-guard(ルート制御) | ApplicationController#before_action |
PERM002_LoginRequired | ログイン必須 | route-guard(ルート制御) | ApplicationController#ensure_logged_in |
PERM003_AdminRequired | 管理者権限必須 | route-guard(ルート制御) | EnsureAdmin#ensure_is_admin |
PERM004_SuperAdminRequired | 全体管理者権限必須 | route-guard(ルート制御) | EnsureAdmin#ensure_is_superadmin |
PERM005_BannedUserBlocked | 利用停止ユーザーを拒否 | route-guard(ルート制御) | ApplicationController#cannot_access_if_banned |
53件の PERM### コードを収録。4ロール(visitor / member / admin / global_admin)の権限マトリクス。
| 機能ID | 機能名 | 種別 | 優先度 | 関連画面 |
|---|---|---|---|---|
F001 | Auth認証 | ui 画面 | P0 | SCR020, SCR021… |
F018 | TransactionInitiate取引開始 | ui 画面 | P0 | SCR090, SCR091… |
F019 | TransactionLifecycle取引ライフサイクル | mixed 複合 | P0 | SCR093, SCR125… |
F020 | TransactionPayPalFlowPayPal決済フロー | mixed 複合 | P2 | SCR095〜SCR101 |
F051 | TransactionStateMachine取引状態管理 | background バックグラウンド | P0 | — |
66機能を収録。優先度はP0(最重要)〜P3(低)の4段階、種別は画面/バックグラウンド/複合の3種類です。
| HTTP | パス | 処理 | 認証 | 説明 |
|---|---|---|---|---|
GET | / | homepage#index | pub(公開) | ホームページ |
GET | /listings/:id/initiate | preauthorize_transactions#new | auth(ログイン必須) | 決済の事前承認を開始 |
POST | /webhooks/paypal_ipn | paypal_ipn#ipn_hook | pub(公開) | PayPal IPN Webhookを受信 |
POST | /bounces | amazon_bounces#notification | pub(公開) | Amazon SESのバウンス通知 |
全ルートに (/:locale) オプションスコープ付き。pub / auth / admin / super 凡例。
| 分類 | 件数 | 主な処理 |
|---|---|---|
queue-worker(キューワーカー) | 43 | メール送信、画像処理、Sphinx差分更新、決済コールバック |
mail(メール) | 5 | 取引、会話、会員管理、ニュースレター |
integration(外部連携) | 6 | Stripe、PayPal、SES、S3、Google Maps、Intercom |
middleware (Rack)(ミドルウェア) | 7 | MarketplaceLookup、HSTS、ロケール、robots |
state-machine(状態管理) | 1 | TransactionProcessStateMachine(Statesman) |
webhook(Webhook) | 2 | PayPal IPN、Amazon SESバウンス |
scheduled-job / queue-worker / event-listener 等の10種類の BL タイプを定義。
| レスポンス型 | 定義元 | 説明 |
|---|---|---|
FlashRedirectResponse | app/controllers/application_controller.rb | Rails標準リダイレクトと通知/エラー表示 |
HTMLPageResponse | app/views/ | サーバー側で描画するHAML/ERBテンプレート |
JSONResponse | app/controllers/int_api/ | int_api/でJSONを直接返す |
TopbarPropsJSON | app/controllers/topbar_api_controller.rb | Reactトップバーへ渡すJSONデータ |
opt-in 生成(--api-contracts)。int_api/ と ui_api/ のみ JSON を返す。
| コード | 意味 | 定義元 |
|---|---|---|
F### | Feature(機能) | generated/feature-list.md |
US### | User story | generated/user-stories.md |
SCR### / REG### | 画面 / 画面内リージョン | generated/screen-list.md |
PERM### | 権限 | generated/permissions-matrix.md |
BL### | Behavior Logic(バックグラウンド) | generated/behavior-logic.md |
FR/BR/SM/ALG/INT/DEC | 機能仕様内のロジック種別 | features/*/technical-spec.md |
解析の第1段階で生成する、140行のシステム概要です。何をする事業のシステムなのか、どんな決まりで動いているのかを先に示し、その後に技術構成を並べます。
| 対象システム | 10年以上にわたり開発されてきたオープンソースのマーケットプレイス基盤 |
|---|---|
| 生成日 | 2026-06-04 |
| 構成 | マルチテナント型マーケットプレイス(Railsモノリス+一部React) |
事業者が自社のマーケットプレイスを開設・運営するための基盤です。事業者はサブドメイン(例:example-market.example.com)ごとに独立したマーケットプレイスを持ち、扱う商材に合わせて出品フォームの項目、カテゴリ、決済手段、手数料を設定します。出品者は商品やサービスを登録し、購入者はそれを検索して予約・購入します。代金は Stripe または PayPal で決済され、運営者は取引額に応じた手数料を受け取ります。
出品と取引の状態は、検索インデックス、取引メール、運営管理画面、外部連携(PayPal IPN、SES バウンス通知)へ波及します。取引の状態遷移と決済の整合が崩れると、売上と入金の記録がずれるため、刷新時はこの2点の新旧一致確認が要点になります。
本書の対象範囲は、受領したソース約1,478ファイルをリバースエンジニアリングして復元した66機能/182画面です。記述はすべてソースコード(source of truth)から抽出しており、コードだけでは確定できない点は各仕様書の「追加確認が必要な事項」に列挙しています。
個々の機能を読む前に押さえておく、全体に共通する決まりです。
| 共通原則 | 業務内容 |
|---|---|
| 事業者単位のデータ分離 | リクエストのサブドメイン/ドメインから Rack ミドルウェア MarketplaceLookup が事業者(Community)を特定し、ApplicationController の fetch_community が以降のクエリをその事業者に限定する。別の事業者のデータは参照できない。 |
| 取引は状態遷移で管理 | 取引の進行は TransactionProcessStateMachine(Statesman)が管理し、initiated → preauthorized → paid → confirmed と進む。rejected/canceled/refunded/disputed への分岐も状態として持つ。変更は TransactionTransition に履歴として残り、いつ何が起きたか追跡できる。 |
| 決済は事前承認してから確定 | 購入の時点では決済を確定させず事前承認(preauthorize)にとどめ、取引が成立した時点で確定(キャプチャ)する。決済手段は TransactionService::Gateway が Transaction#payment_gateway を見て Stripe/PayPal/フリー(決済不要)に振り分ける。 |
| 出品項目は事業者が定義 | 出品の型(ListingShape)、カテゴリ(Category)、任意項目(CustomField)を事業者ごとに設定できる。同じ基盤でも、扱う商材によって入力項目が変わる。 |
| 権限は所属で決まる | 利用者の役割は CommunityMembership(メンバー/管理者/バン)として事業者ごとに持つ。運営管理画面は EnsureAdmin が管理者に限定する。同じ人物が、ある事業者では購入者、別の事業者では運営者になり得る。 |
| 時間のかかる処理は非同期 | メール送信、出品画像の変換、検索インデックスの更新、決済コールバックは delayed_job(43ジョブ)で画面処理から切り離す。画面はすぐに応答を返し、結果は通知や再読込で反映される。 |
対象は、Ruby on Rails のモノリスとして長年運用されてきたマルチテナント型のマーケットプレイス基盤です。備える機能は、出品、検索、予約、売買、メッセージ、Stripe/PayPal決済、運営管理、ランディングページ編集。
基本構成は Rails モノリスです。検索や空き状況カレンダーなど、操作性が求められる一部の画面だけに React 16 を組み込み、react_on_rails で連携しています。各リクエストのサブドメインから Rack ミドルウェアが事業者(Community)を特定し、その事業者に属するデータだけを扱います。
スケール指標:ソースファイル約1,478件、コントローラ136件、モデル100件、サービス176件、バックグラウンドジョブ43件、マイグレーション897件、ビュー1,018件。
取引の状態遷移(Statesman): initiated → preauthorized → payment_intent_requires_action → paid → confirmed | rejected | canceled | refunded | errored | disputed
※ overview.md のコアドメインモデルを図示
| 背景 | 複数の独立したマーケットプレイスが、厳格なデータ分離を維持しながら一つの Rails プロセスを共有する必要があります。 |
|---|---|
| 採用方針 | MarketplaceLookup Rack ミドルウェアが、すべてのリクエストに対してリクエストのサブドメイン/ドメインから Community を解決し、request.env[:current_marketplace] に注入します。ApplicationController は fetch_community before_action を介してこれを読み取り、すべてのクエリをスコープします。 |
| 理由 | Rails スタックの前でテナント解決を一元化できます。 |
| トレードオフ | すべてのリクエストにミドルウェアのオーバーヘッドが生じます。ただしコミュニティの参照は Rails キャッシュを経由します。 |
| 背景 | 異なる API 仕様を持つ2つの商用ゲートウェイ(Stripe、PayPal)と、決済不要の出品向けの「フリー」モードが存在します。 |
|---|---|
| 採用方針 | TransactionService::Gateway が Transaction#payment_gateway を参照し、StripeService、PaypalService、FreeService のいずれかに処理を振り分けます。 |
| 理由 | ゲートウェイ固有のロジックを共通インターフェースの背後に閉じ込められます。 |
| トレードオフ | アダプター層のぶん処理の追跡が一段深くなります。また PayPal はレガシーの Classic API を使っています。 |
| 背景 | 画面の大半は HAML/ERB によるサーバーサイドレンダリングです。検索、トップバー、空き状況カレンダー、初期設定など、操作性が必要な部分だけに React を使っています。 |
|---|---|
| 採用方針 | 6つの react_on_rails エントリーポイントを、サーバーサイドレンダリングとクライアント側のハイドレーションの両方に登録しています。 |
| 理由 | React のコストを負担するのは操作性が必要な部分だけで済みます。 |
| トレードオフ | Webpack バンドルがクライアント用とサーバー用の2系統になり、ビルド手順が複雑になります。また React 16 はサポートが終了しています。 |
| 採用方針 | admin/(29コントローラー)がコミュニティの基本設定を扱い、admin2/(57コントローラー)がダッシュボード、デザイン、SEO、アナリティクス、詳細設定を扱います。 |
|---|---|
| 理由 | 段階的に移していくことで、管理画面の大規模な作り直しを避けられました。 |
| トレードオフ | どの管理機能がどちらにあるのか分かりにくく、一部の設定が両方の画面に重複しています。 |
| 採用方針 | delayed_job を ActiveRecord バックエンド(MySQL のキューテーブル)で運用しています。非同期処理は43のジョブでカバーされています。 |
|---|---|
| 理由 | キュー専用のインフラを別に用意する必要がありません。 |
| トレードオフ | 処理量が増えると、MySQL をキューとして使う構成が性能上の頭打ちになります。 |
| 認証 | Devise 5(bcrypt によるメール/パスワード)+ Facebook、Google OAuth2、LinkedIn OpenID への OmniAuth。 |
|---|---|
| 権限管理 | CommunityMembership(メンバー/管理者/バン)によるロールベース。EnsureAdmin コンサーンが管理者専用ルートを適用。 |
| データ保護 | パスワードは bcrypt でハッシュ化。Stripe/PayPal シークレットはコミュニティ設定に保存。 |
| API保護 | Rails の protect_from_forgery による CSRF 保護。レート制限に rack-attack gem。 |
| コンテンツ保護 | disarm_custom_head_script before_action が管理者が注入した JS をサニタイズ。 |
| 現在の構成 | 単一の Rails モノリス。ロードバランサー配下の複数 Passenger ワーカーによる水平スケーリング。 |
|---|---|
| 拡張方針 | ステートレスなアプリ層。ファイルアップロードは S3 にオフロード。フラグメントキャッシングに Redis。 |
| 性能上の懸念 | 書き込みが多い負荷下での MySQL 支援ジョブキュー。React 16 の SSR バンドルがリクエストごとに CPU コストを追加。 |
| 分類 | 件数 | 例 |
|---|---|---|
| キューワーカー(delayed_job) | 43ジョブ | メール送信、画像処理、Sphinx差分更新、決済コールバック |
| メール配信 | 5メーラー | 取引、会話、コミュニティ参加、ニュースレター |
| 外部API連携 | 6ラッパー | Stripe、PayPal、SES、S3、Google Maps、Intercom |
| ミドルウェア(Rack) | 7件 | MarketplaceLookup、HSTS、ロケール、robots |
| 状態管理 | 1件 | TransactionProcessStateMachine(Statesman) |
| 受信Webhook | 2件 | PayPal IPN、Amazon SESバウンス |
| 定期実行ジョブ | cronで実行 | Sphinx全件再インデックス、プラン有効期限の確認 |
| 画面アプリ | 使用箇所 |
|---|---|
| SearchPageApp | 出品の閲覧・検索ページ |
| TopbarApp | サイト共通ナビゲーション |
| ManageAvailabilityApp | カレンダー形式の空き状況管理 |
| ListingWorkingHoursApp | 出品ごとの営業時間設定 |
| OnboardingGuideApp | マーケットプレイス開設ウィザード |
| OnboardingTopBarApp | オンボーディング進捗表示 |
これらの画面は内部 JSON API(/int_api/)からデータを取得し、トップバーには /ui_api/topbar_props が表示データを返します。
機能仕様の4ファイル構成。読者別に分離 — BA向けのビジネスコンテキストから開発者向けの技術仕様まで。
PayPal決済では、購入者がいったんマーケットプレイスを離れ、PayPal上で支払いを承認してから戻ります。そのため、承認結果が届くまでの待機状態と、失敗・キャンセル時の戻り先を明確に扱う必要があります。この仕様では、処理中画面、エラー時の再試行、キャンセル時の復帰、出品者によるPayPal受取設定までを一つの流れとして整理しています。
※ business-context.md の購入者フローを図示
| 課金契約の要件 | すべての PayPal 売り手が課金契約ステップを完了する必要があるか、特定の支払いタイプにのみ必要かは完全に確認されていない。 |
|---|---|
| ポーリング時間 | 「処理中」待機画面にかかる時間と、購入者に表示されるタイムアウトがあるかどうかはソースコードから確認されていない。 |
| 優先度 | P2 |
|---|---|
| 種別 | mixed |
| 生成日 | 2026-06-04 |
この機能ID(F020)は、PayPal決済に固有の画面とバックグラウンド処理をまとめたものです。対象には、処理状況を確認する待機画面、決済成功・キャンセル後の復帰画面、処理完了を確定する画面、出品者のPayPal受取設定画面が含まれます。
| 値 | 表示・処理 | 確認条件 | 保存先・結果 |
|---|---|---|---|
paypal | PayPal 操作ステータスポーリングページ、成功/キャンセル返却ページ、注文パーミッション/請求同意画面がすべて適用される | コミュニティが PayPal 対応済みである必要がある(PaypalHelper.community_ready_for_payments?)。未対応の場合は 400 Bad Request | PaypalPayment レコード。非同期追跡用に process_token が保存される |
stripe | これらの画面はいずれも適用されない。Stripe は同期的な 3DS フローを使用する | — | — |
none | これらの画面はいずれも適用されない | — | — |
| 値 | 表示・処理 | 確認条件 | 保存先・結果 |
|---|---|---|---|
preauthorized | トランザクション通常ライフサイクル(F019) | — | 売り手が受け入れ/拒否可能 |
pending_ext | 外部 PayPal キャプチャ保留中 | — | paid または rejected へ遷移 |
errored | PayPal 処理失敗後のエラー状態 | — | 最終状態 |
| 仕様ID | 内容 | エンドポイント/処理 | 検証可能 |
|---|---|---|---|
| FR-001 | JSON経由でPayPalの処理状況を定期確認する | GET /transactions/op_status/:process_token → PaypalService::CheckoutOrdersController#paypal_op_status | あり |
| FR-002 | PayPalからの成功復帰を処理し、待機画面を表示する | GET /paypal_service/checkout_orders/success → #success | あり |
| FR-003 | PayPalからのキャンセル復帰を処理する | GET /paypal_service/checkout_orders/cancel → #cancel | あり |
| FR-004 | 取引処理の状況を定期確認する | GET /transactions/transaction_op_status/:process_token → TransactionsController#transaction_op_status | あり |
| FR-005 | 非同期処理の完了後に取引を確定する | GET /transactions/finalize_processed/:process_token → TransactionsController#finalize_processed | あり |
| FR-006 | PayPalの注文処理権限の申請を開始する | GET /:person_id/paypal_account/ask_order_permission → PaypalAccountsController#ask_order_permission | あり |
| FR-007 | PayPalの請求同意申請を開始する | GET /:person_id/paypal_account/ask_billing_agreement → PaypalAccountsController#ask_billing_agreement | あり |
| 関連要件 | FR-001, FR-002, FR-003 |
|---|---|
| 根拠ソース | app/controllers/paypal_service/checkout_orders_controller.rb:4-8 |
| ルール | PaypalHelper.community_ready_for_payments?(@current_community.id) が true でなければならない。false の場合、render body: nil, status: :bad_request(HTTP 400)でリダイレクトなし。 |
unless PaypalHelper.community_ready_for_payments?(community.id) render body: nil, status: :bad_request end
| 関連要件 | FR-002 |
|---|---|
| ルール | params[:token] が存在しなければならない。空白の場合 → error_not_found_path にリダイレクト。 |
return redirect_to error_not_found_path if params[:token].blank?
| 関連要件 | FR-005 |
|---|---|
| ルール | proc_status[:success] && proc_status[:data][:completed] の両方が true でなければならない。 |
unless proc_status[:success] && proc_status[:data][:completed] redirect_to error_not_found_path end
| 関連要件 | FR-007 |
|---|---|
| ルール | 請求同意をリクエストする前に、アカウントの order_permission_state が :verified でなければならない。 |
case m_account[:order_permission_state] when Some(:verified) # 請求同意リクエストに進む else redirect_to action: ask_order_permission end
| 関連要件 | FR-006, FR-007 |
|---|---|
| ルール | PaypalHelper.community_ready_for_payments?(@current_community) が true でなければならない。そうでない場合 → person_payment_settings_path にリダイレクト。 |
| 種別 | flow |
|---|---|
| 対象画面 | SCR096_PayPalSuccess |
if response[:success] redirect_to transaction_created_path(transaction_id: ...) else case paypal_error_code when "10486" → redirect to PayPal retry URL when "13113" → flash buyer_cannot_pay_error; redirect to listing when "10417" → flash transaction_cannot_complete; redirect to listing when "10425" → flash seller_express_checkout_disabled; redirect to listing when "payment-review" → flash warning pending_review_error; redirect to listing else → flash generic_error; redirect to listing end end
| 種別 | flow |
|---|---|
| 対象画面 | SCR095_PayPalOpStatus |
proc_status = paypal_payments_service.create(community_id, token, force_sync: false)
if proc_status[:success]
render "paypal_service/success", layout: false, locals: {
op_status_url: paypal_op_status_path(process_token),
redirect_url: success_processed_path(process_token, listing_id)
}
else
flash[:error] = t("paypal.generic_error")
redirect_to search_path
end
| 種別 | flow |
|---|---|
| 対象画面 | SCR101_PayPalAskBillingAgreement |
case m_account[:order_permission_state]
when Some(:verified) → proceed: request billing agreement URL; render json: {redirect_url:}
else → redirect_to action: ask_order_permission
| 変更前 | 変更後 | 条件 | 実行結果 |
|---|---|---|---|
| polling | completed | proc_status.completed == true | JS がリダイレクトをトリガーする |
| polling | polling | completed == false | ポーリング間隔を継続 |
※ technical-spec.md の SM-001_PayPalProcessToken の主要遷移を抜粋して図示
| 関連要件 | FR-002 |
|---|---|
| 計算量 | O(1) — 線形スイッチ |
説明: 既知の PayPal エラーコードをユーザー向けメッセージとリダイレクト先にマッピングする。コード 10486 = 資金不足;13113 = 購入者が支払い不可;10417 = トランザクション完了不可;10425 = 売り手の Express Checkout が無効;payment-review = 保留中のレビュー警告。
case paypal_error_code when "10486" → redirect response_data[:redirect_url] # PayPal retry when "13113" → flash buyer_cannot_pay; redirect listing when "10417" → flash transaction_cannot_complete; redirect listing when "10425" → flash seller_express_checkout_disabled; redirect listing when :"payment-review" → flash pending_review_warning; redirect listing else → flash generic_error; log unhandled; redirect listing
| 種別 | api-call |
|---|---|
| 接続先 | PaypalService::API::API.payments.create(PayPal Express Checkout) |
| 送信内容 | community_id, PayPal token, force_sync: false |
| 失敗時の処理 | !proc_status[:success] → 汎用エラーをフラッシュ;検索にリダイレクト |
| 接続先 | PaypalService::API::API.payments.request_cancel |
|---|---|
| 失敗時の処理 | !pp_result[:success] → キャンセルエラーをフラッシュ;検索にリダイレクト |
| 接続先 | PaypalService::API::API.accounts.request(パーミッションリクエスト) |
|---|---|
| 送信内容 | community_id, person_id, callback_url, country |
| 失敗時の処理 | redirect_url が空白 → 「リダイレクト URL を取得できませんでした」をフラッシュ |
| 接続先 | PaypalService::API::API.accounts.billing_agreement_request |
|---|---|
| 送信内容 | community_id, person_id, description, success_url, cancel_url |
10486 → 購入者が PayPal リトライ URL にリダイレクトask_order_permission がリダイレクト URL を返す → JSON {redirect_url} がクライアントに返される| 処理の流れ | 購入者が PayPal で認可しサクセス URL に戻った後、#success が paypal_payments_service.create を force_sync: false でトリガーする。成功した場合、op_status_url と redirect_url の locals 付きで paypal_service/success を layout: false でレンダリングする。ブラウザの JavaScript が op_status_url を completed: true になるまでポーリングし、その後 redirect_url(success_processed エンドポイント)にリダイレクトする。 |
|---|---|
| 優先度の根拠 | すべての非同期 PayPal トランザクションに必要な中間ステップ;これがなければトランザクション作成がファイナライズされない。 |
| 単独での確認方法 | PayPal チェックアウトを完了 → スピナーページが表示され、数秒以内に確認に自動リダイレクトされることを確認する。 |
受け入れシナリオ:
success が発火すると、結果 op_status_url 付きのポーリングスピナーがレンダリングされ、JS が完了までポーリングした後リダイレクトする。paypal_payments_service.create が失敗した場合、操作 購入者が戻ると、結果 汎用エラーをフラッシュ表示し検索にリダイレクト。| 対応する要件 | FR-001 (PayPal 操作ステータスをポーリング), FR-002 (PayPal 成功リターンを処理) |
|---|---|
| 適用する業務ルール | BR-001_CommunityPayPalReadiness, BR-002_PayPalTokenRequired |
| 状態遷移 | SM-001 polling → completed → redirecting |
| 検証シナリオ | SC-001 |
| 処理の流れ | ポーリング完了後、ブラウザは success_processed_path にリダイレクトされる。#success_processed はファイナライズされたプロセスステータスを取得し、handle_proc_result を呼び出し、成功時は transaction_created_path にリダイレクトするか、エラーコード固有のパスにディスパッチする。 |
|---|---|
| 優先度の根拠 | PayPal 決済確認の最終ステップ;これがなければトランザクションが停滞して見える。 |
| 単独での確認方法 | PayPal 認可とポーリング後、ユーザーがトランザクション確認ページに着地することを確認する。 |
受け入れシナリオ:
success_processed が発火すると、結果 トランザクション確認にリダイレクト。10486 の場合、結果 PayPal リトライ URL にリダイレクト。13113 の場合、結果 「購入者が支払いできません」エラーをフラッシュ表示しリスティングにリダイレクト。| 対応する要件 | FR-005 (処理済みトランザクションをファイナライズ) |
|---|---|
| 適用する業務ルール | BR-003_ProcessTokenMustComplete |
| 検証シナリオ | SC-003 |
| 処理の流れ | 購入者が PayPal で「キャンセル」をクリックすると、cancel URL に戻る。#cancel が paypal_payments_service.request_cancel を呼び出して保留中の決済を無効化する。成功時、「決済がキャンセルされました」フラッシュが表示され、購入者はリスティングページにリダイレクトされる。 |
|---|---|
| 優先度の根拠 | PayPal 上の孤立した決済認可を防止する;購入者にクリーンな終了を提供する。 |
| 単独での確認方法 | PayPal チェックアウトの途中でキャンセル → 購入者が「決済がキャンセルされました」通知付きでリスティングページに着地することを確認する。 |
受け入れシナリオ:
| 対応する要件 | FR-003 (PayPal キャンセルリターンを処理) |
|---|---|
| 適用する業務ルール | BR-001_CommunityPayPalReadiness |
| 検証シナリオ | SC-002 |
| 処理の流れ | ユーザーが ask_order_permission にアクセスする。コミュニティの準備状況がチェックされる。accounts_api.request が呼び出され、PayPal パーミッションリダイレクト URL を取得する。成功時、クライアントに JSON {redirect_url} を返す(JS がユーザーを PayPal パーミッションページにリダイレクト)。リターン時、permissions_verified コールバックがアカウント作成を完了する。 |
|---|---|
| 優先度の根拠 | PayPal 売り手アカウント設定の最初のステップ — 請求同意をリクエストする前に完了する必要がある。 |
| 単独での確認方法 | 売り手として決済設定を訪問し、PayPal 接続を開始 → PayPal パーミッションページへのリダイレクトを確認する。 |
受け入れシナリオ:
ask_order_permission にアクセスすると、結果 リダイレクト URL が JSON として返され、クライアントが PayPal にリダイレクトする。| 対応する要件 | FR-006 (PayPal 注文パーミッションを開始) |
|---|---|
| 適用する業務ルール | BR-005_PayPalCommunityReadyForPermissions |
| 検証シナリオ | SC-006 |
| 処理の流れ | ユーザーが ask_billing_agreement にアクセスする。注文パーミッションステートがチェックされ、:verified でなければならない。検証済みの場合、accounts_api.billing_agreement_request が呼び出され、請求同意リダイレクト URL を取得する。JSON {redirect_url} を返す。リターン時、billing_agreement_success が請求同意レコードを作成する。 |
|---|---|
| 優先度の根拠 | PayPal 売り手設定の2番目のステップ — 定期的/事前承認された支払い機能に必要。 |
| 単独での確認方法 | 注文パーミッション検証後、請求同意を開始 → PayPal 請求同意ページへのリダイレクトを確認する。 |
受け入れシナリオ:
ask_billing_agreement にアクセスすると、結果 リダイレクト URL が返され、クライアントが PayPal にリダイレクトする。ask_order_permission にリダイレクトし前のステップを完了させる。| 対応する要件 | FR-007 (PayPal 請求同意を開始) |
|---|---|
| 適用する業務ルール | BR-004_PayPalOrderPermissionPrerequisite, BR-005_PayPalCommunityReadyForPermissions |
| 検証シナリオ | SC-005 |
| 条件 | 期待する動作 |
|---|---|
token パラメータなしで PayPal 成功 URL にアクセス | エラー/not-found ページにリダイレクト。「お探しのページは存在しません。」 |
| 購入者が PayPal から戻った時にコミュニティの PayPal が未設定 | HTTP 400 が返される。リダイレクトなし。なし(400 のボディは空白) |
PayPal エラーコード 10486(資金不足/アカウント間違い) | レスポンスデータからの PayPal リトライ URL にリダイレクト。なし — PayPal がメッセージを処理する |
PayPal エラーコード 10425(販売者の Express Checkout が無効) | エラー付きでリスティングにリダイレクト。メッセージは allow_free_conversations? により変化 |
| PayPal でユーザーが請求同意をキャンセル | billing_agreement_cancel が同意を無効化し決済設定にリダイレクト。「請求同意がキャンセルされました。」 |
PayPal アカウント制限(エラーコード 520009) | 「アカウント制限」メッセージ付きで flash_error_and_redirect_to_settings。「お使いの PayPal アカウントは制限されています。」 |
| データ名 | テーブル | 主な列 | 画面の目的 |
|---|---|---|---|
| Transaction | transactions | id, current_state, payment_gateway, community_id, listing_id | PayPal 非同期フローで追跡されるコアトランザクション |
| PaypalPayment | paypal_payments | id, transaction_id | トランザクションに紐づく PayPal 固有の決済レコード |
| Community | communities | id, country | PayPal 手数料 URL とロケールに使用される国コード |
| Person | people | id | PayPal アカウントを設定する販売者 |
| 成果物 | ファイル | 参照コード | レビュー状況 |
|---|---|---|---|
| システム概要 | system-overview.md | — | 確認済み |
| ルート一覧 | docs/generated/route-list.md | — | 確認済み |
| 機能一覧 | feature-list.md | F020 | 確認済み |
| 画面遷移 | docs/generated/screen-flow.md | — | 確認済み |
| 利用者視点の要件 | user-stories.md | US068, US069, US070, US100, US101 | 確認済み |
| 画面一覧 | screen-list.md | SCR095, SCR096, SCR097, SCR098, SCR099, SCR100, SCR101 | 確認済み |
| バックグラウンドロジック | docs/generated/behavior-logic.md | — | 確認済み |
| エンティティ | data-model.md | DISC-011, DISC-012 | 確認済み |
| 権限マトリクス | permissions-matrix.md | — | 確認済み |
paypal_service/success ビューテンプレートには、op_status_url を定期的に呼び出すクライアントサイドのポーリング JavaScript が含まれている。このテンプレートは読み取っていないが、JS ポーリングロジックはコントローラーから渡される locals に基づいて推定している。SCR098_TransactionOpStatus と SCR099_FinalizeProcessed は TransactionsController#transaction_op_status と #finalize_processed に対応する — これらは PayPal フローと同じスピナーテンプレートを共有するが、ゲートウェイ非依存(Stripe 非同期フローでも使用される)。PaypalHelper.community_ready_for_payments? は保存されたコミュニティ PayPal 設定に対する同期チェックであり、before_action 中に外部 API コールは行われない。| 処理名 | ファイル | 画面の目的 |
|---|---|---|
CheckoutOrdersController#success | paypal_service/checkout_orders_controller.rb:11-38 | PayPal リターンハンドラー+非同期スピナーレンダリング |
CheckoutOrdersController#success_processed | paypal_service/checkout_orders_controller.rb:41-51 | ポーリング後のファイナライズ+エラーコードディスパッチ |
CheckoutOrdersController#cancel | paypal_service/checkout_orders_controller.rb:53-61 | キャンセルトークン無効化+リダイレクト |
CheckoutOrdersController#paypal_op_status | paypal_service/checkout_orders_controller.rb:64-76 | JSON ポーリングエンドポイント |
PaypalAccountsController#ask_order_permission | paypal_accounts_controller.rb:14-36 | 販売者パーミッション開始 |
PaypalAccountsController#ask_billing_agreement | paypal_accounts_controller.rb:38-73 | 販売者請求同意開始 |
TransactionsController#transaction_op_status | transactions_controller.rb:208-225 | 汎用(非 PayPal)操作ステータスポーリング |
TransactionsController#finalize_processed | transactions_controller.rb:197-206 | 非同期完了後の汎用ファイナライズ |
| ポーリング間隔 | paypal_service/success のクライアントサイド JS ポーリング間隔は読み取っていない — 固定間隔なのか指数バックオフなのか不明。 |
|---|---|
| SCR098 vs SCR095 | 両方とも操作ステータスのスピナーを表示するが、一方は PayPal 固有、もう一方は汎用。それぞれが表示される正確な条件の確認が必要。 |
| 請求同意の必要性 | 請求同意がすべての PayPal 事前認証トランザクションに必要なのか、定期的なもののみなのかはコードから確認されていない。 |
| 画面名 | 表示内容 | 可能な操作 |
|---|---|---|
| PayPal Operation Status | PayPal 決済が非同期で処理されている間、進捗インジケーター付きのスピナー/ローディングページが表示される | 待機 — 処理完了時にページが自動リダイレクトされる。手動操作は不要 |
| PayPal Payment Success | PayPal 認証後、最終的なトランザクションレコードが確認されるまで表示される短い中間ページ(同じスピナーテンプレート) | 待機 — トランザクション確認画面に自動リダイレクト |
| PayPal Payment Cancelled | 購入者が PayPal でキャンセルした後のリダイレクト先。表示ページなし(リスティングへの即時リダイレクト) | なし — 「決済がキャンセルされました」通知付きの自動リダイレクト |
| Transaction Operation Status | 非同期トランザクション操作用の汎用スピナーページ(PayPal 固有ではない) | 待機 — 操作完了時に自動リダイレクト |
| Finalize Processed Transaction | 非同期プロセストークンの完了を確認する中間リダイレクトページ | なし — トランザクション詳細またはエラーページへの即時リダイレクト |
| PayPal Permissions Initiation | 販売者アカウント設定ステップ 1 — リダイレクト URL を返す。表示ページなし(クライアントへの JSON レスポンス) | なし — PayPal パーミッションページへの自動リダイレクト |
| PayPal Billing Agreement Request | 販売者アカウント設定ステップ 2 — リダイレクト URL を返す。表示ページなし(クライアントへの JSON レスポンス) | なし — PayPal 請求同意ページへの自動リダイレクト |
| 発生条件 | システムの動作 | 利用者への表示 |
|---|---|---|
token パラメータなしで PayPal 成功 URL にアクセス | エラー/not-found ページにリダイレクト | 「お探しのページは存在しません。」 |
| 購入者が戻った時にコミュニティの PayPal 設定が設定されていない | before-action が空のボディで HTTP 400 を返す。リダイレクトなし | なし(空の 400 レスポンス) |
PayPal エラーコード 10486 — 購入者が間違ったアカウントを使用または残高不足 | レスポンスデータに含まれる PayPal リトライ URL にリダイレクト | なし — PayPal が自サイト上でメッセージを処理 |
PayPal エラーコード 13113 — 購入者のアカウントがこの支払いを行えない | フラッシュエラー。リスティングページにリダイレクト | 「購入者の PayPal アカウントではこの支払いを行えません。PayPal カスタマーサービスにお問い合わせください。」 |
PayPal エラーコード 10417 — トランザクションを完了できない | フラッシュエラー。リスティングページにリダイレクト | 「このトランザクションは完了できません。」 |
PayPal エラーコード 10425 — 売り手が Express Checkout を有効にしていない | フラッシュエラー(文言は allow_free_conversations? により異なる)。リスティングにリダイレクト | 「売り手が PayPal Express Checkout を有効にしていません。」 |
PayPal の payment-review ステータス | フラッシュ警告(エラーではない)。リスティングにリダイレクト | 「支払いは PayPal による審査待ちです。」 |
| 未処理の PayPal エラーコード | フラッシュ汎用エラー。サーバー側で警告がログ記録。リスティングにリダイレクト | 「PayPal で問題が発生しました。もう一度お試しください。」 |
購入者が PayPal でキャンセルし request_cancel が失敗 | フラッシュキャンセルエラー。検索にリダイレクト | 「PayPal 支払いのキャンセル中に問題が発生しました。もう一度お試しください。」 |
finalize_processed 発火時にプロセストークンがまだ完了していない | エラー/not-found ページにリダイレクト | 「お探しのページは存在しません。」 |
売り手が確認済み注文権限なしで ask_billing_agreement にアクセス | ステップ 1 を完了するために ask_order_permission にリダイレクト | なし — 通知せずにリダイレクト |
| 権限または課金契約の PayPal API が空のリダイレクト URL を返す | フラッシュエラー。支払い設定にリダイレクト | 「PayPal のリダイレクト URL を取得できませんでした。もう一度お試しください。」 |
PayPal アカウントにエラーコード 570058(アカウント未認証) | permissions_verified コールバックで固有のフラッシュエラー | 「あなたの PayPal アカウントは認証されていません。」 |
PayPal アカウントにエラーコード 520009(アカウント制限) | コールバックで固有のフラッシュエラー | 「あなたの PayPal アカウントは制限されています。」 |
個々の画面仕様に入る前に、どんな画面が何のためにあるのかを一覧で確認できます。全182画面のうち代表10画面を抜粋しています。
| 収録画面数 | 182画面(pub/auth/admin/super の4認証レベル) |
|---|---|
| 画面IDの付け方 | SCR###_PascalCaseName。ルーティングと画面の対応をコードから抽出して採番。 |
| ステータスの意味 | 確定=ソースから読み取れた内容のみで記述。要確認=コードだけでは判断できず、各仕様書の「追加確認が必要な事項」に記載。 |
※ 表は横にスクロールできます。
| 画面ID | 画面名 | 種別 | 利用者 | ステータス | 目的・概要 |
|---|---|---|---|---|---|
SCR001Homepage | ホーム/検索 | 画面 | 購入者 | 確定 | 事業者のトップページ。ランディングページが有効な場合はそちらを表示し、無効なら検索画面を表示する。未ログインでも閲覧可(pub)。homepage#index/GET / |
SCR060ListingsBrowse | 出品一覧 | 画面 | 購入者 | 確定 | キーワード・カテゴリ・価格・場所で絞り込み、結果を一覧表示。未ログインでも閲覧可(pub)。SearchPageApp(React)で描画。listings#index/GET /listings |
SCR061ListingDetail | 出品詳細 | 画面 | 購入者 | 確定 | 出品内容と事業者が定義した任意項目、空き状況カレンダーを表示し、予約または問い合わせへ進む。未ログインでも閲覧可(pub)。listings#show/GET /listings/:id |
SCR091PreauthorizeCheckout | 決済の事前承認 | 画面 | 購入者 | 確定 | 予約内容と料金内訳を確認し、Stripeカードまたは PayPal で事前承認を開始する。取引成立までは決済を確定させない。ログイン必須(auth)。GET /listings/:id/initiate |
SCR095OperationStatus | 操作ステータス | サブ画面 | 購入者 | 要確認 | 非同期処理の完了待ちを表示する汎用のスピナー画面。SCR098との使い分けがソースから確定できない。 |
SCR096PayPalSuccess | PayPal 決済成功 | 画面 | 購入者 | 確定 | PayPal 認可後の成功処理。エラーコード(10486/13113/10417/10425)ごとに再試行・出品へ戻すなどへ分岐する。 |
SCR098PayPalOpStatus | PayPal 操作ステータス | サブ画面 | 購入者 | 要確認 | PayPal 操作の完了をポーリングして待つ画面。ポーリング間隔とタイムアウトがソースから確定できない。 |
SCR118TransactionThread | 取引のやりとり | 画面 | 購入者 出品者 |
確定 | 取引の状態表示とスレッド形式のメッセージ送受信。取引の完了・キャンセル申請もこの画面から行う。 |
SCR140AdminCommunitySettings | 運営:基本設定 | 画面 | 運営者 | 確定 | admin/(29コントローラー)側のコミュニティ基本設定。EnsureAdmin により管理者に限定。 |
SCR201AdminTransactions | 運営:取引管理 | 画面 | 運営者 | 確定 | admin2/(57コントローラー)側の取引一覧・手数料設定・返金処理。同じ設定がSCR140側と重複する箇所がある。 |
※ 認証レベル・コントローラー・URLは全182画面ぶん同じ形式で出力されます。
13セクション構成の画面仕様。認証済み購入者が事前承認トランザクションを開始する画面。
URL: GET /listings/:listing_id/initiate
| 画面ID | SCR091_PreauthorizeCheckout |
|---|---|
| 種別 | 単体画面 |
| URL | GET /listings/:listing_id/initiate |
| 生成日 | 2026-06-04 |
認証済みの購入者が出品物の詳細と価格を確認し、任意でメッセージを入力し、Stripe カードまたは PayPal で支払いを送信して出品物の事前承認トランザクションを開始する。
画面上部に出品タイトルを表示し、その下に予約内容・料金内訳と支払いフォームを並べます。フォームでは、出品者へのメッセージ入力、取引条件への同意、StripeカードまたはPayPalの選択を行います。実装上は #new_message_form.centered-section にまとめられています。
海辺のコテージ・2泊3日
出品者:Sample Host
神奈川県・海まで徒歩3分
コードから復元した画面イメージです。実際の決済操作はできません。
| ID | リージョン名 | スクロール | 主な構成要素 |
|---|---|---|---|
| R1 | タイトル | なし | content_for :title_header経由の見出し |
| R2 | 出品・料金情報 | なし | _price_break_downによる料金内訳 |
| R3 | 取引フォーム | あり | _stripe_payment、同意欄、PayPalボタン |
凡例:必須=入力必須/任意=省略可/—=表示のみ(入力なし)。「表示条件」が空欄の項目は常時表示。
※ 表は横にスクロールできます。
| No. | 項目名(表示名) | コントロール | 入力 | 表示条件 | 制約・業務ルール(根拠) |
|---|---|---|---|---|---|
| R1 タイトル | |||||
| 1 | 出品タイトル | 見出しリンク | — | listing.title を表示し、出品詳細(SCR061)へ遷移。見出しの操作ラベルは action_button_label で切り替わる。 |
|
| R2 出品・料金情報 | |||||
| 2 | 出品者名 | ラベル | — | コントローラーから受け取る author の表示名。 |
|
| 3 | 予約日(開始/終了) | ラベル | — | 予約型の出品のみ | start_on/end_on はルートパラメーター(非表示)で受け取り、duration は両者から算出。 |
| 4 | 料金内訳(小計・配送料・サービス料・合計) | ラベル | — | 各金額が設定されている場合のみ行を表示 | いずれも算出値。表示は MoneyViewUtils.to_humanized を通す。購入者サービス料は buyer_fee、運営手数料は fee。 |
| R3 取引フォーム | |||||
| 5 | 出品者へのメッセージ | テキストエリア | 任意 | 未入力でも送信可。#new_message_form 内の textarea。桁数制限はソースから確定できない(要確認)。 |
|
| 6 | キャンセルポリシーと取引条件への同意 | チェックボックス | 必須 | transaction_agreement_in_use が true のとき |
未チェックで送信すると transaction_agreement.required_error を表示して送信を中止。「Read more」で同意文をライトボックス表示。 |
| 7 | 決済手段の選択 | ボタン(クレジットカード/PayPal) | 必須 | stripe_in_use/paypal_in_use の設定により表示が変化 |
両方無効なら決済不可。片方のみ有効ならその手段に固定。両方有効ならカードを既定にし PayPal を併記。 |
| 8 | カード番号 | Stripe Elements | 必須 | カード決済を選択したとき | カード情報は画面上でトークン化し、stripe_payment_method_id をフォームに挿入してから送信。カード番号自体は自社サーバーへ送らない。 |
| 9 | 有効期限 / セキュリティコード | Stripe Elements | 必須 | カード決済を選択したとき | 不正・期限切れは stripe.card_declined/stripe.expired_card を #card-errors(role="alert")に表示。 |
| 10 | 支払いボタン(合計額を表示) | ボタン | — | 押下でフォームを AJAX 送信。送信中は submitInProgress/inProgress ガードにより再クリックを受け付けない。 |
|
| 11 | 配送方法 | ラジオボタン | 必須 | 配送を扱う出品のみ | 未選択で送信すると select_delivery_method を表示。<label> 要素は付与済み。 |
購入者は、出品内容、予約日、料金内訳、合計金額を確認します。
必要に応じて出品者へメッセージを入力し、キャンセルポリシーと取引条件に同意します。
利用可能な決済方法から、カードまたはPayPalを選びます。
カード情報をトークン化して送信します。
PayPal決済としてフォームを送信します。
送信中は処理状態を表示し、結果に応じて次の画面へ進みます。
redirect_url処理状況を確認op_status_url本人認証stripe_payment_intent.requires_action confirm_intent_path| 判断箇所 | 条件 | 画面上の結果 | 根拠 |
|---|---|---|---|
| Step 4 | stripe_in_use == false && paypal_in_use == false | 支払いボタンが描画されない;フォームを送信できない | initiate.haml:58-82 |
| Step 4 | stripe_in_use && !paypal_in_use | Stripe カード要素のみ表示 | initiate.haml:58-63 |
| Step 5 | paypal_in_use && !stripe_in_use | PayPal ボタンのみ表示 | initiate.haml:65-69 |
| Step 5 | paypal_in_use && stripe_in_use | Stripe と「or pay with PayPal」の両方が表示 | initiate.haml:71-79 |
| Step 3 | transaction_agreement_in_use | 同意チェックボックスが描画される;バリデーションでチェックが必要 | initiate.haml:47-48 |
| Step 9 | Stripe 3DS 失敗 / カードエラー | エラーメッセージがフラッシュで表示;スピナー非表示 | stripe_payment.js:99-104 |
| Step 7 | サーバーが error_msg を返す | ST.utils.showError でエラー表示;フォームが再有効化 | transaction.js:29 |
※ SCR091 spec.md に復元した条件分岐と画面状態から、主要な流れを抜粋して図示
| 項目 | 表示ラベル | 根拠 | 形式 | 未設定時 |
|---|---|---|---|---|
listing.title | 出品タイトル(見出しリンク+詳細) | URLパラメーター → DB | 文字列 | 該当なし(画面表示に必須) |
author 表示名 | 出品者名 | コントローラーから受け取る値 | 文字列 | 該当なし |
listing_price | 1日/夜/時間/単位あたりの価格 | コントローラーローカル | MoneyViewUtils.to_humanized | nil の場合は非表示 |
start_on / end_on | 予約日 | ルートパラメーター(非表示フィールド) | l date, format: :long_with_abbr_day_name | nil の場合は非表示 |
duration | 予約日数/夜数/時間数 | 開始/終了から算出 | 整数+複数形化されたラベル | nil の場合は非表示 |
subtotal | 小計 | 算出 | MoneyViewUtils.to_humanized | nil の場合は非表示 |
shipping_price | 配送料 | 算出 | MoneyViewUtils.to_humanized | nil の場合は非表示 |
total | 合計 | 算出 | MoneyViewUtils.to_humanized | nil の場合は非表示 |
fee | サービス料 | 算出 | -MoneyViewUtils.to_humanized(fee) | ゼロの場合は非表示 |
buyer_fee | 購入者サービス料 | 算出 | MoneyViewUtils.to_humanized | ゼロ/nil の場合は非表示 |
paypal_expiration_period | 「You will be charged」通知 | コントローラーローカル | 整数(日数) | 支払いなしの場合は非表示 |
action_button_label | 見出しの操作ラベル | コントローラーから受け取る値(i18n) | 文字列 | 該当なし |
| 状態 | 発生条件 | 画面表示 | 可能な操作 | 根拠 |
|---|---|---|---|---|
| submitting (PayPal) | PayPal ボタンクリック / フォーム送信 | .paypal-button-loading-img スピナー表示、再送信ブロック | なし | transaction.js:94 |
| submitting (Stripe) | 「Pay with card」クリック | スピナー表示、inProgress=true | なし | stripe_payment.js:146 |
| error | サーバーまたは Stripe エラーレスポンス | ST.utils.showError フラッシュメッセージ;スピナー非表示;フォーム再有効化 | 再試行 | stripe_payment.js:99-104 |
| stripe card error | エラーを含む Stripe カード要素の変更イベント | #card-errors ラベルにインラインエラーテキスト | カード入力を修正 | stripe_payment.js:28-37 |
| 3DS action required | stripe_payment_intent.requires_action | Stripe.js が 3DS モーダルを開く(外部) | 3DS チャレンジを完了 | stripe_payment.js:56-93 |
| success/redirect | redirect_url を受信 | JS がブラウザをリダイレクト | なし | transaction.js:55-56 |
| 処理状況の確認中 | op_status_url を受信 | 要確認 ポーリング中もスピナーを表示 | なし | transaction.js:8-15 |
| 項目 | 種別 | 必須 | 制約 | エラー表示 |
|---|---|---|---|---|
contract_agreed | checkbox | yes (if transaction_agreement_in_use) | チェック必須 | t("error_messages.transaction_agreement.required_error") |
shipping_address[name] | テキスト | stripe_shipping_required の場合は必須 | stripe-shipping-address 属性により必須チェックを実行 | 要確認 標準の必須エラー |
shipping_address[street1] | テキスト | stripe_shipping_required の場合は必須 | 同上 | 要確認 |
shipping_address[postal_code] | テキスト | stripe_shipping_required の場合は必須 | 同上 | 要確認 |
| カード入力欄 | Stripe.js要素 | stripe_in_use の場合は必須 | Stripeがカード情報を検証 | #card-errors にエラーを表示 |
| エンドポイント | POST /listings/:listing_id/initiated |
|---|---|
| 成功時 | 200 → JSON {redirect_url} または {op_status_url, op_error_msg} または {stripe_payment_intent: {...}} |
| エラー時 | 200 JSON {error_msg} → ST.utils.showError で表示。具体的には: invalid_parameters、select_delivery_method、dates_not_available、transaction_agreement.required_error、double_booking_payment_voided、stripe.card_declined、stripe.expired_card |
| 根拠ソース | app/controllers/preauthorize_transactions_controller.rb:40-64 |
| エンドポイント | POST /listings/:listing_id/preauthorize_transactions/:id/stripe_confirm_intent |
|---|---|
| 成功時 | 200 → JSON {success: true, redirect_url} → JS がリダイレクト |
| エラー時 | 200 JSON {error: t("error_messages.stripe.generic_error")} → showError で表示 |
| 根拠ソース | app/controllers/preauthorize_transactions_controller.rb:66-97 |
| 操作したときの挙動 | 根拠ソース |
|---|---|
PayPal ボタンをクリックすると payment_type が "paypal" に設定され、AJAX 経由でフォームが送信される | initiate.haml:93-108 |
「Pay with card」(Stripe)をクリックするとカードをトークン化し、stripe_payment_method_id を挿入してからフォームの AJAX 送信をトリガーする | stripe_payment.js:135-168 |
AJAX 送信中は、支払いボタンの再クリックがブロックされる(submitInProgress / inProgress ガード) | transaction.js:75, stripe_payment.js:137 |
| 「Read more」リンクをクリックするとトランザクション同意コンテンツがライトボックスモーダルで開く | _transaction_agreement_checkbox.haml:7 |
| 確認項目 | 状況 | 備考 |
|---|---|---|
| ARIA roles/labels | partial | #card-errors に role="alert" あり;フォームの他の要素には明示的な ARIA なし |
| Keyboard navigation | not implemented | 明示的な tabindex や keydown ハンドラーなし;標準的なブラウザタブ順序 |
| Focus management | unmanaged | モーダル/ライトボックスに autofocus やフォーカストラップなし |
| Screen reader compatibility | partial | 配送フィールドに <label> 要素あり;カードエラーに role="alert" あり |
[NO_A11Y_DETECTED] — 本番リリース前にアクセシビリティ監査が必要。
| 条件 | 種別 | 表示内容 | 備考 |
|---|---|---|---|
stripe_in_use | auth/feature | Stripe カード要素、配送先住所フィールド | 迂回した場合の影響:Stripe 支払いパスが利用不可 |
paypal_in_use && !stripe_in_use | auth/feature | PayPal のみのボタン行 | 迂回した場合の影響:PayPal のみの支払いパスが利用不可 |
paypal_in_use && stripe_in_use | auth/feature | 「Or pay with PayPal」行+PayPal 画像ボタン | 迂回した場合の影響:二重支払い選択が非表示 |
@current_community.transaction_agreement_in_use | auth | _transaction_agreement_checkbox パーシャル | 迂回した場合の影響:同意が得られない可能性、法的リスク |
stripe_shipping_required | auth/feature | Stripe パーシャル内の配送先住所フィールド | 迂回した場合の影響:配送先住所が収集されない |
quantity が存在する | feature | hidden_field_tag :quantity | ユーザーへの影響なし |
per_hour が true | feature | start_time、end_time、per_hour 非表示フィールド | ユーザーへの影響なし |
| 条件 | 種別 | 未適用時の影響 |
|---|---|---|
before_action :ensure_logged_in | auth | ログイン通知とともにリダイレクト |
before_action :ensure_listing_is_open | permission | 出品物がクローズ済みの場合、フラッシュエラーとともにリダイレクト |
before_action :ensure_listing_author_is_not_current_user | permission | リダイレクト;自己トランザクションを防ぐ |
before_action :ensure_authorized_to_reply | permission | 出品物がユーザーに見えない場合、検索にリダイレクト |
before_action :ensure_can_receive_payment | permission | 売り手の支払いが設定されていない場合、出品物にリダイレクト |
app/views/listing_conversations/initiate.haml:1-109app/views/transactions/_price_break_down.haml:1-102app/views/listing_conversations/_stripe_payment.haml:1-68app/views/listing_conversations/_transaction_agreement_checkbox.haml:1-14app/controllers/preauthorize_transactions_controller.rb:1-439app/assets/javascripts/transaction.js:1-130app/assets/javascripts/stripe_payment.js:1-173config/routes.rb:117-135画面仕様は全182画面ぶん同じ形式で出力されます。ここでは代表的な4画面を抜粋しています。
SCR060_ListingsBrowse 検索条件・絞り込みから一覧表示まで(MOD-04 発見・検索)
キーワードと条件で絞り込み
該当 128件 / 並び順:おすすめ
コードから復元した画面イメージです。実際の操作はできません。
SCR061_ListingDetail 出品内容・任意項目・予約カレンダー(MOD-03 リスティング管理)
神奈川県・海まで徒歩3分
8月24日 〜 8月26日(2泊)
コードから復元した画面イメージです。実際の操作はできません。
SCR118_TransactionThread 取引の状態とスレッド形式のやりとり(MOD-06 メッセージング)
海辺のコテージ・8月24日〜26日
コードから復元した画面イメージです。実際の操作はできません。
SCR201_AdminTransactions 運営者向けの取引管理と手数料設定(MOD-09 / MOD-10)
運営者向け管理画面
| 取引ID | 出品 | 購入者 | 金額 | 状態 | 操作 |
|---|---|---|---|---|---|
| TX-24188 | 海辺のコテージ | K. Tanaka | ¥39,600 | キャプチャ済み | |
| TX-24187 | 離れの一棟貸し | M. Sato | ¥31,900 | 承認済み | |
| TX-24186 | 海が見える工房 | Y. Ito | ¥10,780 | 紛争提起 |
コードから復元した画面イメージです。実際の操作はできません。
TECHNICAL DETAILS
ここからは、業務用語、状態遷移、全機能の一覧を確認できます。移行設計や追加ヒアリングの論点を洗い出す際に使用する情報です。
解析の第4段階(--glossary)で生成します。全760行・76語のうち、決済フローと事前承認画面に関係する20語を掲載しています。
全760行収録 — 下記は他サンプル(F020、SCR091)との関連度が高い20語を選定した抜粋。
| 用語 | 定義 | 技術上の別名 | 関連機能 |
|---|---|---|---|
| Auto-Confirmation | 買い手が手動で受領確認を行わなかった場合、設定された日数経過後にシステムがトランザクションを完了済みとし、売り手への支払いを自動的にリリースするアクション。 | Community.automatic_confirmation_after_days | F019, F051, F052, F066 |
| Billing Agreement (PayPal) | マーケットプレイスが将来のトランザクションにおいて売り手の PayPal アカウントから手数料を徴収することを許可する PayPal の同意。PayPal 売り手設定の第2ステップとして必要。 | billing_agreements table; PaypalAccount | F020, F027, F060 |
| Booking | トランザクションに紐付けられた日付または時間帯の予約レコード。 | MODEL014 | F014, F018, F019, F051 |
| Community | プラットフォーム上で動作する単一のマーケットプレイスインスタンス。各コミュニティは独自のサブドメイン、メンバー、リスティング、カテゴリ、決済設定を持つ。 | MODEL001 | F001, F004, F005, F031, F034, F058 |
| Community Membership | ユーザーとコミュニティの関係を表し、ステータス(承認済み、保留中、利用禁止)と権限(投稿権限、管理者ロール)を保持する。 | MODEL003; status (DISC-005) | F001, F003, F004, F017, F028, F039 |
| Confirmation (Transaction) | 買い手が商品またはサービスを受け取ったことを確認する操作。これにより売り手への支払いが実行される。 | Transaction.current_state = 'confirmed' (DISC-011) | F019, F042, F051, F052, F066 |
| Conversation | 2人以上の参加者間のメッセージスレッド。リスティングやトランザクションに任意で紐付けられる。 | MODEL015 | F022, F023, F043 |
| Listing | マーケットプレイスメンバーが投稿する商品またはサービス。マーケットプレイスの主要コンテンツ単位。 | MODEL005 | F011, F012, F013, F014, F015, F016, F017, F018, F041 |
| Listing Shape / Order Type | リスティングのトランザクションモデルを定義するテンプレート — 販売、レンタル、サービス予約、無料交換のいずれかを指定する。 | MODEL006 (ListingShape) | F011, F037 |
| Listing State | approved = 検索に表示され取引可能 / approval_pending = 管理者レビュー待ち / approval_rejected = 却下済み | Listing.state (DISC-006) | F011, F017, F041 |
| Order Permission (PayPal) | マーケットプレイスが売り手に代わって注文を処理することを許可する PayPal の同意。PayPal 売り手アカウント設定の第1ステップ。 | order_permissions table; PaypalAccount | F020, F027, F060 |
| Payment Gateway | マーケットプレイスが使用する外部決済処理業者 — Stripe または PayPal。 | PaymentSettings.payment_gateway (DISC-020) | F025, F045, F059, F060 |
| Payment Process | 決済のキャプチャタイミング。preauthorize(資金を保留し売り手が承認した時点でキャプチャ)または postpay(配送後に課金)。 | TransactionProcess.process (DISC-015) | F018, F019, F051, F059, F066 |
| Person | システムに登録されたユーザー。コミュニティごとに一意のユーザー名で識別される。 | MODEL002 | F001, F006, F007, F008 |
| Preauthorization | 買い手の決済カードまたは PayPal 残高に対して、即座に課金せずに資金を確保するホールド。 | Transaction.current_state = 'preauthorized' (DISC-011) | F018, F019, F051, F059 |
| Review / Testimonial | トランザクション後に一方の当事者がもう一方に対して残す評価と任意のコメント。受け手のプロフィールに公開表示される。 | MODEL023 (Testimonial); grade (0.0–1.0) | F024, F044 |
| Transaction | 特定のリスティングに対する買い手と売り手の間の取引。開始から決済、完了またはキャンセルまでのライフサイクル全体を包含する。 | MODEL011 | F018, F019, F021, F042, F051 |
| Transaction Agreement | トランザクション確定前に買い手が同意する必要のある任意のテキスト。マーケットプレイス管理者が法的条件を設定するために使用する。 | Community.transaction_agreement_in_use | F018, F066 |
| Transaction Process | リスティングシェイプに対して利用可能な決済タイミングモデル(なし、事前認可、後払い)のコミュニティレベル定義。 | MODEL013; process (DISC-015) | F037, F051 |
| Transaction States | initiated / preauthorized / paid / confirmed / canceled / rejected / refunded / disputed / errored / free — ステートマシンによって制御されるライフサイクル状態。 | Transaction.current_state (DISC-011) | F019, F042, F051 |
Statesman gem を使ったトランザクション状態遷移。10ノード、12エッジ。confirmed が唯一の成功終端ノード。
generated/feature-list.md より自動抽出。各機能はさらに4つのドキュメントに展開されます。
REGEN* DELIVERABLE SAMPLES
上の仕様書で可視化した依存関係とリスクをもとに、段階的な移行計画へ落とし込みます。
EXECUTIVE SUMMARY
一括移行は行わず、3つのウェーブに分けます。各ウェーブの終了時に品質ゲートを設け、次へ進むかを判断します。
依存関係、技術リスク、事業価値から順序を決めます。
ウェーブごとの期間と、次へ進むための判定基準を示します。
決済、検索、非同期処理など、移行前に検証すべき領域を明確にします。
S1 — 現状 vs ターゲットスタック対応図(見本値)
※ 最終選定はアセスメントで確定。
このプロセスがRegen*の中核です。「新システムが動く」だけでは十分ではありません。事前に定義したテストケースで、新旧の結果がすべて一致したことを確認してからリリースします。本ページでは、この新旧の動作一致を「パリティ」と呼び、「パリティ100%」は定義済みテストケースがすべて一致した状態を指します。
S7 — 新旧の動作が一致することを段階ごとに確認する流れ(見本)。TDDによる単体テスト生成(③)は実装(④)より先に行います。すべての品質確認を通過した後、新旧一致の最終確認(⑥)と担当者による受け入れテストを経てリリースします。
機能・画面単位の開発では、TDDと標準の品質確認を繰り返します。一定数の機能が完成した段階で新旧比較テストを実行し、担当者による受け入れテストへ進めるかを判断します。
仕様から生成した単体テストだけでは、現行システムの暗黙的な動作をすべて捉え切れない場合があります。新旧比較テストを追加することで、移行後の見落としを減らします。
| 層 | 目的 | タイミング | 合格基準 |
|---|---|---|---|
| TDDによる単体テスト(新系) | 新実装の正しさ(仕様への準拠) | 実装前に生成、実装と同時進行 | すべての単体テストが成功 = 実装完了条件 |
| 新旧比較テスト(新旧両系) | 新旧の振る舞い同等性 | 品質ゲート通過後・リリース直前 | 100% 一致 = マージ・リリース条件 |
移行前に解決必須の技術負債・リスク集中点。6件を特定し、影響モジュールと対応方針を確定。
| # | ホットスポット | 根拠(エビデンス) | 影響モジュール | 対応方針 |
|---|---|---|---|---|
| H-01 | React 16.1.1 EOL + react_on_rails 13 | 6 entry points、2バンドル Webpack 構成 | MOD-04, 03, 08 | App Router RSC へ段階移行、Webpack → Next.js bundler 統合 |
| H-02 | Sphinx + ts-delayed-delta 全文検索 | 別デーモン、delta 再インデックス delayed_job 経由 | MOD-04 | Meilisearch(JP tokenizer)へ置換、インデックス再構築 parity 検証 |
| H-03 | MySQL上のdelayed_job(ActiveRecord) | 43 ジョブ、タイマー 3本(BL001/002/003) | MOD-05, 10, 08, 03 | BullMQ/Redisへ移行し、ジョブ種別ごとに比較テスト基盤を構築 |
| H-04 | PayPal Classic API(IPN + legacy REST) | IPN webhook、BillingAgreement、OrderPermission | MOD-05, 07 | 非推奨 → PayPal Orders v2 REST + Webhooks 移行 |
| H-05 | 管理画面 2系統(admin/ 29 + admin2/ 57 controllers) | SCR140–SCR177 + SCR180–SCR242、同一設定の重複 | MOD-08, 09, 10 | MOD-08 移行時に単一 Next.js Admin UI へ統合 |
| H-06 | kt-paperclip + ActiveStorage 共存 | 出品画像 Paperclip、landing ページ資産 ActiveStorage | MOD-03, 09 | S3 パス監査後に ActiveStorage 一本化 |
現状アーキテクチャ(§2)の主要データはシステムソースファイル・設計ドキュメント・実コードから確認済み。
66機能を、共通して使うデータ、認証範囲、取引フローのつながりを基準に整理し、10の移行モジュールに分けます。
| 移行ID | 名称 | 対象機能ID | 画面数 | サイズ |
|---|---|---|---|---|
| MOD-01 | 認証・テナント基盤 Auth & Tenant Foundation |
F001F002F003F004F058 |
11 | M |
| MOD-02 | プロフィール・ソーシャル User Profile & Social |
F006–F010F029 |
11 | M |
| MOD-03 | リスティング管理 Listing Management |
F011–F014F017 |
6 | L |
| MOD-04 | リスティング発見・検索 Listing Discovery & Search |
F015F016F030 |
20 | L |
| MOD-05 | トランザクション・決済 Transactions & Payments |
F018–F021F051F055F059F060 |
12 | XL |
| MOD-06 | メッセージング・レビュー Messaging & Reviews |
F022F023F024 |
9 | M |
| MOD-07 | 決済設定 Payment Account Settings |
F025F026F027 |
3 | S |
| MOD-08 | マーケットプレイス設定 Marketplace Setup & Admin Config |
F005F028F031F034–F038F047F064–F066 |
~35 | XL |
| MOD-09 | ブランディング・CMS・SEO Branding, CMS & SEO |
F032F033F048F049F062 |
~22 | L |
| MOD-10 | 管理オペレーション Admin Operations & Platform |
F039–F046F050F052–F054F056F057F061F063 |
~28 | XL |
画面数は SCR 番号ベース集計。サンプル#1「182画面仕様」はスペック登録数(計上方法が異なる)。
A → B = A は B に依存(B が先に移行済みである必要がある)
S2 — 依存関係グラフ(見本)。MOD-05 ↔ MOD-06 の準循環はデータ層では真の循環なし(MOD-05 先行で解消可能)。
S3 — リスク×価値散布図(見本値)。円サイズ = モジュール規模。
まず、他機能への依存が少ない基盤モジュールを選びます。次に、技術リスクと事業価値を比較して順序を調整し、決済領域は並行稼働、運用系は最終ウェーブに配置します。
S4 — ウェーブ計画スイムレーン(見本値)。黄帯 = MOD-05 並行稼働期間。◆ = ゲート(通過条件は下表参照)。
| ウェーブ | ◆ ゲート完了条件(要約) |
|---|---|
| W0 | 旧バックエンドで定義済み振る舞いテストがすべて成功・ベースライン記録済み・rewrites 全ルート転送確認 |
| W1 | 定義済みテストが100%一致・重大障害0件・本番相当の通信で新旧を7日間比較 ※新旧比較を強化する方法の一例です。適用範囲は、体制やシステムの複雑さに応じて決定します。 |
| W2 | 各モジュールの定義済みテストが100%一致・認証領域の移行完了・PayPal Orders v2への移行計画を確定 |
| W3 | 検索結果が事前に定めた許容範囲内で一致・対象モジュールの定義済みテストが100%一致・管理画面の機能を統合 |
| W4 | 全取引フローの定義済みテストが100%一致・本番相当の通信で14日以上比較・重大障害0件・切り戻し手順を確認 |
| W5 | 全10モジュールの定義済みテストが100%一致・旧システムの全URLを新システムで処理・旧システムを停止して保管 |
ロールバック共通: Next.js rewrites の当該パスを Rails origin へ切り戻すだけで即時ロールバック可能。
TECHNICAL DETAILS
ここからは、モジュールごとの移行方針、新旧システムを共存させる構成、品質ゲートの運用、後続ウェーブを効率化する仕組みを詳しく確認できます。
※工数は Takumi による AI コード生成(仕様を起点)を前提とした、レビュー・テスト中心の見本値です。
| 対象機能ID | F001, F002, F003, F004, F058 |
|---|---|
| 移行対応 | Devise+OmniAuth → Auth.js(devise-jwt ブリッジ経由)/RackAttack → Next.js middleware rate-limit/MarketplaceLookup → middleware.ts テナントリゾルバー/legacy_encrypted_password → SHA256→bcrypt 段階移行 |
| 新旧比較の方法 | 標準の品質確認サイクル+固有対応:統一Cookieドメイン下でのセッション継続テスト、テナントリゾルバーのサブドメイン別レスポンス比較 |
| ロールバック | rewrites で Auth.js ルートを Rails Devise origin へ切戻し(1行変更) |
| サイズ / 工数 | M / 3–4人週(見本値) |
| 対象機能ID | F006, F007, F008, F009, F010, F029 |
|---|---|
| 移行対応 | HAML server-render → Next.js App Router RSC/FollowerRelationship CRUD → API Route Handler/CustomFieldValue polymorphic → Prisma @map アノテーション//:username バニティ URL → catch-all + generateStaticParams |
| 新旧比較の方法 | 標準確認+個別対応: バニティ URL ルーティング一致確認、CustomFieldValue 多態的読取比較 |
| ロールバック | /:username, /profile/* パスを Rails origin へ rewrite 切戻し |
| サイズ / 工数 | M / 3–4人週(見本値) |
| 対象機能ID | F011, F012, F013, F014, F017 |
|---|---|
| 移行対応 | ManageAvailabilityApp(React 16 island)→ App Router RSC+Client Component/ListingWorkingHoursApp → 同上/int_api blocked-dates → API Route Handler/kt-paperclip ListingImage → S3 パス監査後 ActiveStorage 相当 |
| 新旧比較の方法 | 標準確認+個別対応: カレンダー UI 操作後の blocked-dates API 結果比較、ListingImage S3 URL 一致確認 |
| ロールバック | /listings/* 管理パスを Rails origin へ切戻し |
| サイズ / 工数 | L / 5–7人週(見本値) |
| 対象機能ID | F015, F016, F030 |
|---|---|
| 移行対応 | SearchPageApp(React 16 + Redux)→ App Router RSC+Client Component/Sphinx + ts-delayed-delta → Meilisearch(JP tokenizer)/マップピン JSON → API Route Handler/静的エラーページ → Next.js 静的ページ |
| 新旧比較の方法 | 標準確認+個別対応:検索順位の差と関連度の許容範囲を事前に定めて比較します。地図ピンの座標とまとめ方も確認します。 |
| ロールバック | /s/* /listings/* 検索パスを Rails origin へ切戻し |
| サイズ / 工数 | L / 5–7人週(見本値) |
| 対象機能ID | F018, F019, F020, F021, F051, F055, F059, F060 |
|---|---|
| 移行対応 | Statesman 10状態ステートマシン → TypeScript 状態マシン(XState 等)+新旧比較/PayPal Classic IPN → PayPal Orders v2 REST Webhooks/delayed_job タイマー(BL001/002/003)→ BullMQ delayed jobs/Stripe 5.55 → Stripe 最新 SDK |
| 新旧比較の方法 | 標準確認+個別対応:非同期IPN Webhookと自動タイマー(BL001/002/003)には、同期処理とは別の比較テスト基盤を構築。取引の状態遷移(10状態)を全経路で比較し、14日以上のシャドートラフィックで決済金額・ステータスの一致を確認してから本番へ切り替える。 |
| ロールバック | /transactions/* /checkout/* パスを Rails origin へ即時切戻し(フラグ付リリースで追加粒度) |
| サイズ / 工数 | XL / 10–14人週(見本値) |
| 対象機能ID | F022, F023, F024 |
|---|---|
| 移行対応 | Conversation/Message CRUD → API Route Handler+RSC/Testimonial → Server Action/スレッドメッセージング UI → Client Component(WebSocket or polling) |
| 新旧比較の方法 | 標準確認+個別対応:メッセージの読み書きと、取引開始時のConversation初期化を新旧で比較します。 |
| ロールバック | /messages/* /reviews/* パスを Rails origin へ切戻し |
| サイズ / 工数 | M / 3–4人週(見本値) |
| 対象機能ID | F025, F026, F027 |
|---|---|
| 移行対応 | Stripe Connect OAuth → API Route Handler+OAuth redirect/PayPal BillingAgreement → PayPal Orders v2 出品者オンボーディング(Classic API 非推奨対応)/PaymentSettings CRUD → Prisma |
| 新旧比較の方法 | 標準確認+個別対応: OAuth redirect コールバック URL の state/code 検証一致。PayPal フローは Orders v2 に変更されるため「旧 IPN 流入なし」をルーティングレベルで遮断後に新旧比較。 |
| ロールバック | /payment_accounts/* パスを Rails origin へ切戻し |
| サイズ / 工数 | S / 2–3人週(見本値) |
| 対象機能ID | F005, F028, F031, F034–F038, F047, F064–F066 |
|---|---|
| 移行対応 | OnboardingGuideApp(React 16 island)→ App Router RSC/admin/ 29 controllers + admin2/ 57 controllers → 単一 Next.js Admin UI(統合)/Category/CustomField/ListingShape 管理 API → API Route Handler/MarketplaceConfigurations → Prisma |
| 新旧比較の方法 | 標準確認+個別対応: admin/ と admin2/ で重複する設定画面の機能等価性確認(旧系2パスの合計が新系1パスで網羅されていること)。FeatureFlag 書込みの即時反映確認。 |
| ロールバック | /admin/* /admin2/* パスを Rails origin へ切戻し |
| サイズ / 工数 | XL / 10–14人週(見本値) |
| 対象機能ID | F032, F033, F048, F049, F062 |
|---|---|
| 移行対応 | Mercury in-place editor → ヘッドレス CMS(またはカスタムブロックエディタ)/LandingPageVersion JSON renderer → Next.js ISR/SSG ランディングページ/SEO メタタグ → Next.js Metadata API/GTM/GA → next/script |
| 新旧比較の方法 | 標準確認+個別対応: ランディングページ HTML のメタタグ/OG タグ一致確認(SEO 回帰防止)。Lighthouse スコア差分を閾値以内に収める。kt-paperclip LandingPage assets → S3 パス統一後に新旧比較。 |
| ロールバック | /landing/* /p/* ブランドパスを Rails origin へ切戻し |
| サイズ / 工数 | L / 5–7人週(見本値) |
| 対象機能ID | F039–F046, F050, F052–F054, F056, F057, F061, F063 |
|---|---|
| 移行対応 | 管理モデレーション(Listing/Transaction/Conversation/Review)→ Next.js Admin API Route Handler/一括メール/ニュースレター → BullMQ email job/データエクスポート → BullMQ export job + S3/SES bounce webhook → API Route Handler/delayed_job 20+種 → BullMQ 移行 |
| 新旧比較の方法 | 標準確認+個別対応:20種以上のバックグラウンドジョブに対し、ジョブ種別ごとの比較テスト基盤を構築。一括メールの送信件数とバウンスイベント処理件数の一致を確認する。 |
| ロールバック | /admin/* 管理オペレーションパスを Rails origin へ切戻し |
| サイズ / 工数 | XL / 10–14人週(見本値) |
移行完了前のある時点における共存アーキテクチャ。Next.js rewrites がプロキシ層として機能し、移行済みパスは新系、未移行パスは旧系で処理する。
S5 — 移行中共存アーキテクチャ(見本)。赤ノード = Next.js proxy(全リクエストの入口)。点線 = 移行後に有効化。dual-write 禁止。
ここでは、品質ゲートで必ず守る5つの運用ルールを示します。具体的な確認手順は、「新旧の動作が一致することを、段階ごとに確認する」で説明しています。
| ウェーブ | ◆ ゲート条件(要約) |
|---|---|
| W0 | 旧バックエンドで定義済み振る舞いテストがすべて成功・ベースライン記録済み |
| W1 | 定義済みテストが100%一致・重大障害0件・本番相当の通信で7日間比較 |
| W2 | 各モジュールの定義済みテストが100%一致・認証領域の移行完了 |
| W3 | 検索結果が許容範囲内で一致・対象モジュールの定義済みテストが100%一致・管理画面を統合 |
| W4 | 全取引フローの定義済みテストが100%一致・本番相当の通信で14日以上比較・重大障害0件・切り戻し手順を確認 |
| W5 | 全10モジュールの定義済みテストが100%一致・旧システムの全URLを新システムで処理・旧システムを停止 |
各ゲートの運用詳細(TDD → 実装 → 品質ゲート → 新旧一致の最終確認の順序)は §新旧の動作が一致することを、段階ごとに確認する を参照。
モジュール移行が進むにつれ、Takumiエンジンと比較テスト基盤への投資が蓄積し、後続モジュールの移行を効率化できます。
S6 — 移行を重ねるほど、次のウェーブが進めやすくなる(見本値)。MOD-05 は高リスク並行稼働のため一時減速。最大約3倍(見本値)。
本ページは実案件を参考に構成した成果物サンプルです。