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

5.9 KiB

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.