Storefront route 責務境界と Quick Order selected 仕様¶
このドキュメントは、apps/storefront/src/routes/account.*.tsx の thin re-export パターンと、
apps/storefront/src/lib/quick-order.ts の evaluateQuickOrderLine における 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 の
componentexport - page-content への props 受け渡し (loader からの値や fallback flag)
- 必要なら
ContentShell+PageHeaderのレイアウト骨格 (account.profile.tsx/account.password.tsx/account.gift.tsx等の breadcrumb 固定)
これにより、router.tsx の beforeLoad で完結した 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.ts の
expectScreenReaderH1() と 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.tsxのbeforeLoadauth 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.ts の evaluateQuickOrderLine は、各行の
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を強制していた。 - 新仕様:
errorはreadyと同じく「ユーザー操作後の state」と見なし、selectedを保持する。 - 該当 unit test は
apps/storefront/src/lib/quick-order.test.tsのevaluateQuickOrderLinedescribe 内に回帰防止ケースを 4 件追加済み: error -> readyでselected=falseを保持error -> readyでselected=trueを保持pending -> readyでselected=trueを defaultempty -> readyでselected=trueを default
関連¶
- 監査向け auth 導線:
docs/03-implementation/frontend/index.md「認証導線(現行)」 - GraphQL fragment list/detail 分離:
graphql-fragment-strategy.md - mock E2E vs real E2E の方針: ルート
AGENTS.md「実装ガードレール」