154 lines
5.9 KiB
Markdown
154 lines
5.9 KiB
Markdown
# Website CMS Parity Plan
|
|
|
|
> **Platform implementation plan:** HomAroma page, content, and route references are reference-tenant parity targets unless the document explicitly describes a shared CMS contract.
|
|
|
|
## 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_BAR`
|
|
- `HERO`
|
|
- `CATEGORIES`
|
|
- `PRODUCTS`
|
|
- `PRODUCT_CAROUSEL`
|
|
- `BANNER`
|
|
- `TEXT`
|
|
- `RICH_TEXT`
|
|
- `NEWSLETTER`
|
|
- `EDITORIAL_TILE`
|
|
- `EDITORIAL_CAROUSEL`
|
|
- `HERO_ARTICLE`
|
|
- `SCENT_NOTES_BREAKDOWN`
|
|
- `QUOTE_CALLOUT`
|
|
- `ACCORDION`
|
|
- `CONTACT_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:
|
|
|
|
1. Fetch route business data on the server.
|
|
2. Fetch optional CMS layout page on the server.
|
|
3. Render `ANNOUNCEMENT_BAR` sections above page content.
|
|
4. Render `HERO` and `BANNER` sections as editable page header when present.
|
|
5. Render a safe hardcoded SSR fallback header when CMS header sections are missing.
|
|
6. Render route business content as SSR HTML.
|
|
7. 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:
|
|
- `about`
|
|
- `article`
|
|
- `category`
|
|
- `contact`
|
|
- `coupons`
|
|
- `faq`
|
|
- `order`
|
|
- `products`
|
|
- `profile`
|
|
- `search`
|
|
- `scent-guide`
|
|
- `shop`
|
|
- `track`
|
|
- `wishlist`
|
|
|
|
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_BAR`
|
|
- `HERO`
|
|
- `BANNER`
|
|
- `TEXT`
|
|
- `NEWSLETTER`
|
|
- `CATEGORIES`
|
|
- `PRODUCTS`
|
|
- `PRODUCT_CAROUSEL`
|
|
|
|
### Batch B: Content Blocks To Port From SPA
|
|
Website-local SSR-safe equivalents added:
|
|
- `EDITORIAL_TILE`
|
|
- `EDITORIAL_CAROUSEL`
|
|
- `HERO_ARTICLE`
|
|
- `SCENT_NOTES_BREAKDOWN`
|
|
- `QUOTE_CALLOUT`
|
|
- `ACCORDION`
|
|
- `CONTACT_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_FORM` for 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/website` route 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.
|