コンテンツにスキップ

Storefront route 責務境界と Quick Order selected 仕様

このドキュメントは、apps/storefront/src/routes/account.*.tsx の thin re-export パターンと、 apps/storefront/src/lib/quick-order.tsevaluateQuickOrderLine における selected 状態遷移を明文化する。Issue #875 (route 責務境界 / auth fallback) と Issue #876 (quick-order selected) の正本。

route ↔ page-content の責務境界

原則

apps/storefront/src/routes/account.*.tsx薄い re-export に限定する。 画面ロジックは components/pages/* または components/account/* 配下の page-content コンポーネントに集約し、route 側は次のみを担う:

  • TanStack Router の component export
  • page-content への props 受け渡し (loader からの値や fallback flag)
  • 必要なら ContentShell + PageHeader のレイアウト骨格 (account.profile.tsx / account.password.tsx / account.gift.tsx 等の breadcrumb 固定)

これにより、router.tsxbeforeLoad で完結した auth guard と、画面側の data fetching / fallback を物理的に分離する。route ファイルを CSR と SSR で共有しやすくし、 mock E2E と real E2E の双方から page-content を直接マウントできるようにすることが目的。

h1 と document.title の責務境界

Storefront の page-content は、画面内の <h1> と browser tab の document.title を 別々の責務として扱う。

  • <h1>: page landmark / screen reader / ページ内ナビゲーションの名前。必要に応じて sr-only にしてよいが、サイト名 suffix は含めない。
  • document.title: browser tab / 履歴表示の名前。各 page-content の usePageMetadata()formatStorefrontPageTitle() 経由で ページ名 | リツビ 形式へ整形する。

テストでは apps/storefront/src/test-utils/page-metadata.tsexpectScreenReaderH1()expectPageMetadata() を使い、h1 と title の期待値を 混同しない。title の suffix を個別 spec で文字列連結しない。

各 account route の現状分類

route 役割 内部委譲先
account.tsx マイページ index components/pages/account-page-content
account.profile.tsx 会員情報 (read-only) components/account/account-profile
account.password.tsx パスワード変更 components/auth/password-change-form
account.orders.tsx 注文履歴一覧 components/pages/account-orders-page-content
account.orders.$code.tsx 注文詳細 同上配下
account.favorites.tsx お気に入り components/account/favorites-page-content
account.gift.tsx ギフト券登録 components/account/gift-code-form
account.gift-cards.tsx ギフト券残高 同上配下
account.addresses.tsx / account.billing.tsx / account.payments.tsx 各種設定 components/account/*

account.payments.tsx / account.gift-cards.tsx / account.orders.$code.tsx 等は 個別の test (*.test.tsx) を持つ。残りの route は thin re-export のため、route 単体の unit を増やすより page-content 側の test に寄せる方針とする。

auth fallback 責務 (account.favorites.tsx)

設計意図

account.favorites.tsx は次の 1 行だけを担う:

return <FavoritesPageContent serverAuthenticated={true} />;
  • serverAuthenticated={true} の意味: Storefront の cookie ベース session は CSR でも常に読み出せる前提のため、route 単独で 「server 側で認証済みだったか」を厳密に判定する責務は持たない。常に true を渡すことで、 FavoritesPageContent 側の server-authenticated retry path (shouldRetryServerAuthenticatedSession 分岐) を有効にし、CSR 直アクセス時に cookie からの session 復元を一度試させる。
  • 復元に失敗した場合の責務は FavoritesPageContent 内の effect:
  • authStatus === "anonymous" に確定したら /auth/login (pathname が /account/favorites のときのみ) または / に navigate する。
  • route ファイルでは redirect/guard を入れないrouter.tsxbeforeLoad auth guard と components/auth/auth-gate.tsx (CSR 補助) の二段構えに任せる。

なぜ route ではなく page-content で fallback するか

  • favorites は useCustomer() + useQuery(["favorites"]) を CSR 後着で解決する。 route の同期コードでは「cookie はあるが server validation 未完了」の状態を 判別できない。
  • serverAuthRefreshPending 中はローディング UI を出して、認証 race 中の白画面 / 即時 navigate を避ける必要があり、これは page-content 側でしか表現できない。
  • 監査向け確認は docs/03-implementation/frontend/index.md の「認証導線」を正本にし、 ここでは route 責務境界の説明に留める。

Quick Order selected 状態遷移仕様

apps/storefront/src/lib/quick-order.tsevaluateQuickOrderLine は、各行の status 遷移に応じて selected を以下のように決定する。

前回 status 今回 status selected 決定ルール 意図
empty ready true (新規 default) 行に有効入力が初めて入ったので submit 候補に入れる
pending ready true (新規 default) SKU resolve 完了は「新規入力扱い」とする
ready ready 直前の line.selected を保持 ユーザーが手動でチェックを外していたら尊重する
error ready 直前の line.selected を保持 error 行を uncheck → 訂正したときに再チェックされないようにする (Issue #876)
any empty / pending / error false に強制 送信不可な行を選択状態のまま残さない

実装は preserveUserSelection = line.status === "ready" || line.status === "error" で 判定し、true なら line.selected を保持、false なら true を default として返す。

history (Issue #876 で変更した点)

  • 旧仕様: error → ready 遷移時も selected: true を強制していた。
  • 新仕様: errorready と同じく「ユーザー操作後の state」と見なし、selected を保持する。
  • 該当 unit test は apps/storefront/src/lib/quick-order.test.tsevaluateQuickOrderLine describe 内に回帰防止ケースを 4 件追加済み:
  • error -> readyselected=false を保持
  • error -> readyselected=true を保持
  • pending -> readyselected=true を default
  • empty -> readyselected=true を default

関連

  • 監査向け auth 導線: docs/03-implementation/frontend/index.md 「認証導線(現行)」
  • GraphQL fragment list/detail 分離: graphql-fragment-strategy.md
  • mock E2E vs real E2E の方針: ルート AGENTS.md 「実装ガードレール」