5.7 KiB
Website CMS Parity Plan
Goal
Bring apps/website closer to the Page Builder CMS behavior already used by apps/spa, while preserving Next.js SSR/SEO behavior.
The website should not copy SPA client rendering wholesale. It should use CMS layout sections for editable marketing/content areas, and keep SEO-critical commerce data server-rendered.
Scope
Allowed implementation scope:
apps/website/**docs/**implementation_plan.md
Do not edit without separate approval:
apps/spa/**apps/admin/**apps/backend/**packages/types/**
If a correct fix requires backend, admin, schema, or shared type changes, report it as a blocker instead of patching around it in website code.
Current Website CMS Support
Supported in apps/website:
/fetches/pages/home- Website-local
DynamicPageRenderer - Supported SSR-safe blocks:
ANNOUNCEMENT_BARHEROCATEGORIESPRODUCTSPRODUCT_CAROUSELBANNERTEXTRICH_TEXTNEWSLETTEREDITORIAL_TILEEDITORIAL_CAROUSELHERO_ARTICLESCENT_NOTES_BREAKDOWNQUOTE_CALLOUTACCORDIONCONTACT_INFO
Not fully supported yet:
- Client-island block:
CONTACT_FORM
- Nested CMS custom pages such as
/campaign/summer - Route layout CMS parity for shop/category/product/search/coupons/scent guide
Route Layout Matrix
| SPA route | Website route | CMS slug | Status | Implementation notes |
|---|---|---|---|---|
/ |
/ |
home |
supported-m1 | Server-rendered CMS sections. |
/shop |
/shop |
shop-layout |
supported-m1 | Renders announcement/hero/bottom CMS sections around SSR product grid. |
/category/:id |
/category/[id] |
category-layout |
supported-m1 | Renders announcement/hero/bottom CMS sections around SSR category product grid. |
/products/:id |
/products/[id] |
product-detail-layout |
supported-m1 | Renders announcement/bottom CMS sections around SSR product detail. |
/search |
/search |
search-layout |
supported-m1 | Renders announcement/hero/bottom CMS sections around SSR search form and results. |
/scent-guide |
/scent-guide |
scent-guide-layout |
supported-m1 | Renders announcement/hero/bottom CMS sections around article index and exposes article API error state. |
/coupons |
/coupons |
coupons-layout |
supported-m1 | Renders announcement/hero/bottom CMS sections around SSR coupon grid and exposes coupon API error state. |
/track |
/track |
track-order-layout |
later-phase | Depends on track flow migration. |
/wishlist |
none | wishlist-layout |
later-phase | Depends on wishlist route migration. |
/order/:id |
none | order-success-layout |
later-phase | Depends on order success flow migration. |
/:slug |
[slug] |
page slug | supported-m1 | Server-renders published CMS pages by slug with reserved route collision guard. |
CMS Layout Rendering Pattern
For SEO-critical routes, use this structure:
- Fetch route business data on the server.
- Fetch optional CMS layout page on the server.
- Render
ANNOUNCEMENT_BARsections above page content. - Render
HEROandBANNERsections as editable page header when present. - Render a safe hardcoded SSR fallback header when CMS header sections are missing.
- Render route business content as SSR HTML.
- Render remaining CMS sections below the business content.
This keeps marketing-controlled content editable without making product/category/search content client-only.
Custom CMS Page Policy
M1 supports single-segment CMS pages through apps/website/src/app/[slug]/page.tsx.
Reserved slugs are intentionally blocked from CMS catch-all rendering:
aboutarticlecategorycontactcouponsfaqorderproductsprofilesearchscent-guideshoptrackwishlist
Why:
- Existing Next routes should keep their route-specific SSR behavior and metadata.
- Commerce/auth routes should not be silently replaced by CMS content.
- Nested CMS paths need an explicit admin/backend slug policy before website supports them.
Block Support Roadmap
Batch A: Layout Blocks Already Present
Use existing website renderer:
ANNOUNCEMENT_BARHEROBANNERTEXTNEWSLETTERCATEGORIESPRODUCTSPRODUCT_CAROUSEL
Batch B: Content Blocks To Port From SPA
Website-local SSR-safe equivalents added:
EDITORIAL_TILEEDITORIAL_CAROUSELHERO_ARTICLESCENT_NOTES_BREAKDOWNQUOTE_CALLOUTACCORDIONCONTACT_INFO
Batch C: Client-Island Blocks
Add only after explicit route needs are clear:
CONTACT_FORM- newsletter submit behavior
- any block requiring browser state, localStorage, LIFF, auth, or cart state
CONTACT_FORM should not simulate successful submission without a real API contract. Keep it unsupported until the website contact submission behavior is defined.
Decision:
- Defer
CONTACT_FORMfor now because the submission endpoint is not ready. - Do not render a fake successful submission state.
- Do not create a website-only endpoint workaround.
- Revisit only when backend/admin/API ownership for contact submissions is confirmed.
Acceptance Criteria
apps/websiteroute still renders SEO-critical content on the server.- CMS layout failure does not break commerce content.
- Published single-segment CMS pages can render through
/:slug. - API/data failure for commerce content is visible and not collapsed into a fake empty state.
- Unsupported block types are logged in development and documented in this plan.
- Lint and production build pass for
apps/website. - No files outside allowed scope are modified.
Current Next Step
Skip CONTACT_FORM for now and continue with missing website flows such as checkout, order success, tracking, wishlist, and profile.