Files
homaroma/docs/website-cms-parity-plan.md
T
2026-10-01 05:49:58 +07:00

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.