Storefront lane / provider 再設計方針¶
1. 目的¶
Storefront は会員制 B2B EC を正本としており、公開 Web 向けの SSG / shared cache 最適化だけでは受け入れ観点を満たしにくい。
本書は、Vite 実装へ移行した後も、route ごとの目的に合わせて provider と最適化方針を分ける基準を定める。
2. 基本方針¶
- 正本は
apps/storefront(Vite) である。旧apps/storefront-next実装は削除済み。 - Storefront 全体を 1 つの同質なアプリとして扱わず、lane 単位で最適化目標を分ける。
- 認証依存 route では、public page と同じ cache 発想を前提にしない。
layoutと global provider は、対象 route に必要な責務だけへ狭める。
2.1 切替後の命名状態¶
- 正本 (Vite):
apps/storefront/ritsubi-storefront - 旧
apps/storefront-next/ritsubi-storefront-next実装は 2026-05 に削除済み。
3. Lane 定義¶
3.1 Storefront lane¶
対象の例:
/(home — featured products と ProductCard を含む commerce surface)/products/search/products/[slug]/cart/checkout- 商品導線と一体の campaign route
優先する観点:
- 商品や価格など、主要情報の first visible を早く出すこと
- deep link で開いた時に、主要コンテンツが先に見えること
- 商品本体以外の付帯情報が後着しても、購入導線が阻害されないこと
- 顧客別の表示制御・価格・購入条件が前提のため、SPA shell を返す前に
activeCustomerを検証すること
受け入れ時に見る観察結果:
- 商品一覧で、ブランド一覧や付帯 UI より先に商品グリッドが見える
- 商品詳細で、主要画像・商品名・価格・購入可否が先に表示される
- カート / チェックアウトで、注文処理に不要な UI に待たされない
3.2 App lane¶
対象の例:
/account/*/quick-order- 今後の業務寄り一覧・フォーム・履歴画面
優先する観点:
- 画面内操作のしやすさ
- 状態保持、mutation 後の再表示、連続操作時の安定性
- SSR よりも interactive な利用体験
受け入れ時に見る観察結果:
- 一覧画面の絞り込みや更新操作が連続しても破綻しない
- 保存や再計算の結果が、画面遷移なしでも確認できる
- 顧客情報・注文情報が操作に必要な範囲で一貫して見える
3.3 Content lane¶
対象の例:
/articles/*/announcements/*/support/*/policies/*/pages/*/products/preview(Vendure Dashboard が発行する signed preview token で保護する商品プレビュー)
優先する観点:
- CMS コンテンツの表示安定性
- commerce / account 向け state を持ち込まない軽さ
- 運用担当者が内容更新後の反映を追いやすいこと
受け入れ時に見る観察結果:
- 記事・お知らせ・サポートページが、顧客状態に依存せず安定表示される
- content route に商品購入系の余計な待ち時間や UI が混ざらない
- 商品プレビューは通常の商品詳細ページと同じ表示構成を保つが、購入・同意確認・閲覧履歴記録などの副作用は発生しない
4. Provider 配置方針¶
4.0 認証境界¶
/_site配下は activeCustomer 必須 とする。/、/products、/search、/products/$slug、/campaigns/*、/collections/*、/cart、/checkout、/quick-order、/reservations、/account/*は cookie の存在だけでは描画しない。- Storefront Worker の navigation guard と browser route guard は、どちらも
/api/auth-session/validateStorefrontSession()経由で VendureactiveCustomer.idを確認する。stale cookie や削除済み customer は login redirect と cookie clear に倒す。 - 表示性能のために遅延してよいのは CMS shell、active order、下段 carousel、 product detail preload などの付帯 fetch であり、認証境界そのものは遅延・省略しない。
- 未認証公開面は
/_content配下へ明示的に分離する。公開例外を増やす場合は route をcontentRouteへ置き、商品・価格・顧客別表示制御に依存しないことを仕様に残す。 browse-shellや cookie-only session 判定のような軽量認証経路は使わない。過去の performance workaround を戻す場合も、activeCustomer検証を bypass してはいけない。
4.1 Root に残すもの¶
原則として、全 route に必要な軽量 provider のみを置く。
候補:
PublicConfigProviderDisableDarkThemeMockServiceWorkerProvider- 必要最小限の
TooltipProvider
期待結果:
- content route や KPI route でも、root 配下の client boot が増えすぎない
4.2 Storefront / content lane に置くもの¶
候補:
ConsentProviderCustomerProvider- 商品購入導線に必要な provider
期待結果:
- 商品・カート・チェックアウトでは必要な機能が使える
- 記事・お知らせ・サポートでも B2B chrome の顧客バーが必ず成立する
- signed preview 以外で顧客バー欠落を匿名 fallback として隠さない
4.3 App lane に置くもの¶
候補:
CustomerProvider- 顧客 / 注文 / mutation を前提にした state provider
期待結果:
/account/*や/quick-orderで顧客情報と注文情報を一貫して扱える- Storefront lane の KPI route に customer / active order query を持ち込まない
4.4 Signed preview に置かないもの¶
/products/preview は Vendure Dashboard が発行する signed preview token で保護する例外 route とし、
以下を持ち込まない。
CustomerProviderConsentProvider
期待結果:
- 商品プレビューでは認証済み顧客 chrome や購入系副作用を発生させない
/products/preview も content lane に含める。商品詳細と同じ構成を確認するため、
関連商品・購入共起・閲覧履歴などの表示セクションは通常ページと同じ描画経路を通す。
一方で、signed preview では ConsentProvider を mount しないため、
AddToCartButton のように購入 hooks / 同意 hooks を呼ぶコンポーネントを直接描画しない。
購入 CTA の位置は hook を使わない disabled 表示で保ち、プレビュー識別は本文へ専用
ブロックを差し込まず floating indicator に集約する。
5. Header の扱い¶
Headerは lane 再配置の制約点になるため、header 用の最小表示データと、account / cart 用の完全 customer context を分ける。- 具体的には、navigation guard で
activeCustomerが確認済みであることと、Header がactiveOrderの full context を初期表示で待たないことを分ける。 /productsはactiveOrder非依存 route として扱える状態を目標にするが、activeCustomer非依存 route にはしない。
受け入れ時に見る観察結果:
/productsで商品一覧の表示が先に出て、header の顧客情報待ちで遅くならない/account/*では必要な顧客表示・注文状態が引き続き見える
6. KPI route と計測¶
KPI route:
/products/products/[slug]/cart/checkout
最低限見る項目:
- Document TTFB
- first visible
- hydration 完了までの時間
- 初回 query 数
- 初回 JS 量
判断基準:
- 認証済み route では、shared cache の有無だけで良否を判断しない
- 主要コンテンツが先に見えるかどうかを優先する
7. 段階的な移行順¶
- lane 定義を文書で固定する
Headerの customer / order 依存を分解する- Storefront lane から不要な customer / order query を外す
- desktop の顧客バーをカート導線の正本にし、匿名右上カート fallback を外す
- signed preview だけ customer / consent provider を外す
8. 切替後の判断 (2026-05)¶
- Storefront 正本は Vite 実装 (
apps/storefront/ritsubi-storefront) へ移行済み - 旧
apps/storefront-next/ritsubi-storefront-next実装は 2026-05 に削除済み - Storefront の主戦場は「公開 Web」ではなく「認証済み storefront」である
- framework 置換だけでなく、lane 分割と provider 境界の整理を移行の前提条件として優先する
8.1 routing facade の現状¶
useRouter/usePathname/useSearchParamsの互換 hook は撤去済み。- 現在
apps/storefront/src/lib/router.tsxに残すのはLinkwrapper のみとする。 - 理由: 現行 codebase には string ベースの route 遷移(例:
/account/orders/${code},/products?collection=${slug})が広く残っており、TanStack Router の厳密な route literal typing へ一気に寄せると変更範囲が過大になるため。 - 今後
Linkwrapper を削除する条件は、主要 UI で使うtoを route object / typed param 化し、string route 依存が十分に減った時点とする。
8.2 legacy product route の扱い¶
- canonical product route は
/products/[slug]とする。 - 旧
/product/[slug]redirect route は削除済み。 - 新規実装・CMS 正規化・モック・テストでは
/product/を生成しない。 - WordPress / CMS 由来の内部リンクは
content-processor.tsで/products/へ正規化する。 - 今後
/product/へのアクセスが必要になった場合は、router へ戻す前に、どの upstream が旧 URL を出力しているかを先に修正する。
9. 昇格条件(完了済み)¶
以下を満たした状態で切替を実施した。
- 会員制 storefront の主要導線が Vite 側で成立していること
- 認証済み route に必要な query / mutation が TanStack Query ベースで揃っていること
- Playwright CT / 主要 Vitest / typecheck が Vite 側の正本導線で回ること
- docs / CI / just / Nx の
ritsubi-storefront参照を Vite 側へ移しても運用上の空白が生じないこと - 旧
apps/storefront-next実装は 2026-05 に削除済み。すべての検証・保守はapps/storefront(Vite) へ一本化されている。
10. 実施バックログ¶
本節は PLAN.md § 15(2026-05-01 バックログ)から移植し、lane 設計の正本としてここに集約したものです。
背景¶
- Storefront は会員制 catalog を正本としており、公開 Web 向けの SSG / shared cache 最適化より、認証済み request-time rendering の負荷抑制が重要である。
- 現状は route 単位の最適化が進んでいる一方、
apps/storefront/src/providers.tsx配下の global provider が広く効いており、/productsのような KPI route に account / app 寄りの client-side cost が混入している。 - Vite + TanStack Router を正本としたうえで、Storefront を lane ごとに責務分離して継続利用する方針を取る。
優先実施項目¶
| 優先度 | 領域 | 改善点 | 根拠 / 観測 | 実施方針 |
|---|---|---|---|---|
| P0 | Storefront 設計 | Storefront の route を storefront lane / app lane / content lane に分類する |
/products・商品詳細・カート・チェックアウトは first visible 重視、/account/*・/quick-order は操作性重視、記事/お知らせ/サポートは CMS / content 重視で、同一設計では最適化目標が衝突する。 |
本文書(§ 3 Lane 定義・§ 4 Provider 配置方針)を正本として lane 定義、対象 route、期待する観察結果を確定し、以後の UI/性能改善は lane 単位で判断する。 |
| P0 | Provider 境界 | global provider を root から棚卸しし、lane 単位に再配置する | apps/storefront/src/providers.tsx で CustomerProvider / ConsentProvider / Sentry UI provider が全 route に適用されており、signed preview に不要な hydration / query cost が混入する。 |
root には軽量 provider のみを残し、CustomerProvider は signed preview を除く site shell 全体で mount する。ConsentProvider は通常 site shell で mount し、signed preview だけ外す。 |
| P0 | Header / 顧客表示 | Header の customer / order 依存を分離し、顧客バー欠落を fallback で隠さない | Header が useCustomer() に依存しているため、provider を lane 配置へ動かす前提条件として「header 用最小データ」と「account / cart 用完全 context」の分離が必要。 |
header 用の最小 customer summary と full customer / active order context を別導線に分ける。desktop のカート導線は顧客バー内の cart summary を正本にし、匿名右上カート fallback は置かない。 |
| P1 | KPI 管理 | Storefront lane の性能指標を TTFB 単独から first visible / hydration / initial query 数へ拡張する |
会員制 catalog では shared cache より request-time work 削減が支配的で、TTFB のみでは /products の検索・絞り込み後 UX を十分に捉えられない。 |
§ 6 KPI route と計測の定義を基準として、Document TTFB、first visible、hydration 完了時間、初回 query 数、初回 JS 量を継続観測する。 |
| P1 | Route group 構成 | 既存 (site) / (protected) を lane 指向に再整理する |
現在の route group は認証保護の境界としては有効だが、storefront / app / content の最適化責務までは明示できていない。 | 必要に応じて storefront lane 用 route group を追加し、既存 (protected) は app lane の責務として再定義する。命名と境界は実装変更前に文書で確定する。 |
現状(2026-05-21 時点)¶
- lane 定義・Provider 配置方針・KPI route の定義は本文書で確定済み。
- signed preview の query 抑制:
CustomerContextProviderで/products/previewを signed preview と判定し、activeCustomerContext/activeOrderContextの 2 query をenabled: falseで skip する (apps/storefront/src/contexts/customer-context.tsx)。 - Header の customer 依存分離完了:
HeaderからuseCustomer()直接呼び出しを撤去し、customerStateprop 経由で受け取る形に変更 (apps/storefront/src/components/layout/header.tsx)。RootLayout内のSiteShellコンポーネントがcustomerStateを resolve して渡す責務を持つ。 - signed preview 以外で customer provider を mount:
RootLayoutは/products/preview以外の site shell をStorefrontCustomerProviders/ConsentProviderで wrap し、content route でも顧客バーを成立させる (apps/storefront/src/layout/root-layout.tsx)。root のNoopCustomerProviderは preview / SSR fallback のためだけに残す。 - lane 判定の SSoT:
apps/storefront/src/lib/storefront-lanes.tsにisContentLanePath/isAppLanePath/isStorefrontLanePathを集約し、CustomerContextとRootLayoutの双方が同一基準で動く。 - 残作業: home
/を独立 lane として明示する整理は未着手 (現状は非 content lane として storefront lane の provider 群を流用)。route group の物理的な再編 ((content)/(commerce)等) も未着手で、現状は path-prefix 判定で代替している。