Files
homaroma/implementation_plan.md
T
2026-10-01 05:49:58 +07:00

304 lines
15 KiB
Markdown

# Website SSR Migration Plan
> **Historical/reference-tenant plan:** This plan records the HomAroma website migration scope at the time it was written. Revalidate routes, tenant configuration, and completion status before applying it to another tenant.
## Goal
Upgrade `apps/website` into the Next.js SSR/SEO version of the current `apps/spa` experience.
`apps/spa` is the UX and behavior reference. `apps/website` is the only application implementation target for this migration.
## Scope
Allowed edit scope:
- `apps/website/**`
- planning or handoff documents such as this file
Do not edit without separate approval:
- `apps/spa/**`
- `apps/backend/**`
- `apps/admin/**`
- `packages/types/**`
If a correct fix requires backend, schema, shared types, admin CMS, or SPA changes, stop and report it as a blocker instead of using a workaround.
## Source Of Truth
- SPA route map: `apps/spa/src/App.tsx`
- SPA home CMS usage: `apps/spa/src/pages/HomePage.tsx`
- SPA dynamic renderer: `apps/spa/src/components/DynamicPageRenderer.tsx`
- Website API resolver: `apps/website/src/lib/api.ts`
- Website App Router pages: `apps/website/src/app/**`
- Backend CMS API contract, read-only reference only: `apps/backend/src/routes/pages.ts`
- Shared CMS payload schemas, read-only reference only: `packages/types/index.ts`
## Important Clarification
The SPA does not expose a frontend route named `/pages/home`.
The SPA route `/` renders `HomePage`, and `HomePage` calls the backend CMS API endpoint:
```text
GET ${API_BASE}/pages/home?lang=<current-language>
```
For `apps/website`, this means Next pages should keep public SEO routes such as `/`, `/shop`, `/category/[id]`, and `/products/[id]`, while using the same CMS API endpoint internally when needed.
## Migration Strategy
Do not copy the SPA wholesale into Next.
Use this pattern instead:
- Server components fetch SEO-critical data and render meaningful initial HTML.
- Client components handle cart, wishlist, LIFF, forms, filters, payment, and localStorage state.
- CMS section rendering is adapted into website-local components.
- Published single-segment CMS pages can be rendered through `/:slug` without replacing route-specific commerce pages.
- API/environment logic stays website-local and uses `NEXT_PUBLIC_API_URL` / `INTERNAL_API_URL`.
## Phase 1: Website Foundation Audit
Owner: `frontend-code-auditor` review only
Tasks:
- Build a route parity matrix between `apps/spa/src/App.tsx` and `apps/website/src/app/**`.
- Classify routes as `exists-needs-upgrade`, `missing`, `client-only-ok`, or `seo-critical`.
- Identify legacy classes, missing design tokens, hardcoded URLs, and silent API fallbacks in `apps/website`.
- Identify pages where current client-only fetch weakens SEO.
Deliverables:
- Route parity matrix.
- Website-only risk list.
- Recommended migration order.
## Phase 2: Website Data Layer
Owner: `frontend-lead`
Review: `frontend-code-auditor`
Tasks:
- Create or refine website-local fetch helpers under `apps/website/src/lib`.
- Separate server-safe fetch helpers from client-only fetch helpers.
- Ensure all helpers use `apps/website/src/lib/api.ts`.
- Add consistent handling for API failures without hiding important contract issues.
- Avoid importing runtime API constants from `@homaroma/types`.
Acceptance criteria:
- No edits outside allowed scope.
- API helpers work in Next server and client contexts as intended.
- No silent empty fallback on SEO-critical pages without an explicit fallback reason.
## Phase 3: CMS Dynamic Renderer For Website
Owner: `frontend-lead`
Review: `frontend-code-auditor`
Tasks:
- Create website-local dynamic page renderer under `apps/website/src/components`.
- Adapt these section types first:
- `ANNOUNCEMENT_BAR`
- `HERO`
- `CATEGORIES`
- `PRODUCTS`
- `PRODUCT_CAROUSEL`
- `BANNER`
- `TEXT`
- `NEWSLETTER`
- Split SSR-capable sections from client-only interactive sections.
- Keep payload guards local to `apps/website` if shared types are insufficient.
Acceptance criteria:
- Home page can render CMS sections from `/pages/home`.
- Unknown section types fail visibly in development logs, but do not crash production rendering.
- No broad `any` use unless isolated and documented as a temporary contract gap.
## Phase 4: SEO Route Migration
Owner: `frontend-lead`
Review: `frontend-code-auditor`
Migration order:
1. `/`
2. `/products/[id]`
3. `/shop`
4. `/category/[id]`
5. `/article/[slug]`
6. `/search`
Tasks:
- Convert SEO-critical content to server-rendered data where possible.
- Keep interactive controls as client islands.
- Add or preserve `generateMetadata` for pages that can provide SEO data.
- Generate fallback metadata from available API data if CMS metadata is unavailable.
Acceptance criteria:
- Initial HTML contains meaningful product/category/article/page content.
- Cart, wishlist, filters, and add-to-cart remain interactive.
- Build and lint pass for `apps/website`.
## Phase 5: Commerce And LINE OA Client Features
Owner: `frontend-lead`
Review: `frontend-code-auditor`
Flow QA: `qa-product-auditor`
Routes:
- `/checkout`
- `/order/[id]`
- `/track`
- `/wishlist`
- `/profile`
Tasks:
- Adapt SPA behavior into website-local client components.
- Add website-local auth, wishlist, and LIFF integration if needed.
- Keep SEO shell/server rendering where useful, but treat these routes as client-heavy flows.
- Use existing backend API endpoints without changing backend contracts.
Acceptance criteria:
- Checkout, order success, tracking, wishlist, and profile flows work on desktop and mobile.
- LINE OA/LIFF logic only runs on the client.
- Payment/order/upload failures have visible error states.
## Phase 6: Visual And UX Alignment
Owner: `ux-ui-designer` + `frontend-lead`
Review: `design-system-auditor`
Tasks:
- Align website visual language with SPA source of truth.
- Remove or replace legacy website-only classes that are not defined.
- Align navbar, footer, cart drawer, product card, loading states, empty states, and error states.
- Check mobile layout and common shopping flows.
Acceptance criteria:
- Website no longer mixes incompatible legacy dark/cyan styling with SPA visual language.
- UI remains readable and responsive.
- Design token usage is consistent within `apps/website`.
## Phase 7: Verification And Release Gate
Owner: `orchestrator`
Reviewers:
- `frontend-code-auditor`
- `qa-product-auditor`
- `design-system-auditor`
Required checks:
- `npm run build -w apps/website`
- `npm run lint -w apps/website`
- Manual route smoke test for SEO routes.
- Manual commerce flow test for checkout/order/tracking.
- Verify no files outside allowed scope were edited.
- Verify all blockers requiring backend/schema/shared type changes are reported, not worked around.
## Delegation Prompts
### Frontend Code Auditor
Use for Phase 1 and review gates.
```text
Review only. Do not edit files.
Inspect apps/website against apps/spa as reference.
Focus on route parity, SSR SEO risks, type/API contract risks, hardcoded values, missing states, and anti-patterns.
Allowed output: findings, severity, file paths, recommended fix, escalation needed.
```
### Frontend Lead
Use for implementation phases.
```text
Implement only inside apps/website.
Use apps/spa as UX and behavior reference, but do not edit apps/spa.
Do not edit apps/backend, apps/admin, or packages/types.
If the correct fix requires those areas, stop and report a blocker.
Preserve Next.js SSR for SEO-critical content and use client islands for interactive behavior.
```
### QA Product Auditor
Use after route groups are implemented.
```text
Review user flows only. Do not edit files unless explicitly asked.
Check broken flows, empty states, error states, mobile behavior, checkout/order/tracking/profile/wishlist flows, and release readiness.
```
### Design System Auditor
Use after visual alignment.
```text
Review visual consistency only. Do not edit files unless explicitly asked.
Check contrast, readability, missing classes, token usage, responsive layout, and SPA/website visual alignment.
```
## Open Decisions
- Should `apps/website` support locale-specific URL paths later, or keep language state client-side for now?
- Should dynamic CMS SEO metadata be generated only from existing API data in this migration?
- Should `apps/spa` remain the dedicated LINE OA app after website reaches parity, or should website eventually replace it?
- Should shared type/runtime cleanup be scheduled as a separate project after website-only migration?
- Should nested CMS paths such as `/campaign/summer` be supported, and if yes, what slug policy should admin/backend enforce to avoid collisions with business routes?
## Decisions
### Image Optimization
Decision: defer migration from `<img>` to `next/image` for M1.
Reason:
- Current image sources are mixed between local public paths such as `/images/...` and backend/CMS upload paths such as `/uploads/...`.
- `apps/website/next.config.ts` does not yet define final `images.remotePatterns` or production CDN/image host policy.
- Changing to `next/image` before image hosting is finalized can create broken remote image rendering or force premature config assumptions.
- M1 priority is SSR/SEO route parity, API correctness, visual cleanup, and build stability.
Current policy:
- Keep existing `<img>` usage for now.
- Treat `@next/next/no-img-element` warnings as accepted M1 optimization debt, not a release blocker.
- Revisit after production image domain/CDN and upload URL strategy are finalized.
Future acceptance criteria for `next/image` migration:
- Production image host or CDN is known.
- `apps/website/next.config.ts` has explicit `images.remotePatterns` for allowed hosts.
- Hero, product primary image, category hero, article cover, and CMS hero/banner images are migrated first.
- Lint still passes and images render in dev, preview, and production-like environments.
## Initial Milestone
M1: Website SEO Foundation
Target:
- Phase 1 complete.
- Phase 2 complete.
- Basic CMS renderer exists in `apps/website`.
- `/` and `/products/[id]` upgraded first.
- `apps/website` build/lint pass.
- `frontend-code-auditor` review passed.
Current status:
- Phase 1 route parity audit documented in `docs/website-route-parity-audit.md`.
- Website-local data helpers added under `apps/website/src/lib`.
- Website-local result helpers now expose API errors instead of converting every failure into an empty list.
- CMS layout parity is now wired for `/`, `/shop`, `/category/[id]`, `/products/[id]`, `/search`, `/scent-guide`, and `/coupons`.
- Published single-segment CMS pages now render through `apps/website/src/app/[slug]/page.tsx` with reserved slug collision protection.
- Website CMS renderer now supports SSR-safe editorial, article hero, scent notes, quote, FAQ accordion, and contact info blocks.
- `CONTACT_FORM` is intentionally deferred until a real submission endpoint/API owner is ready. Do not implement simulated submit behavior.
- `/track` now renders the tracking form, calls `POST /orders/track`, stores validated local order history, and consumes `track-order-layout` CMS sections.
- `/order/[id]` now exists as a read-only SSR order status page with item summary, status, tracking number, metadata, and `order-success-layout` CMS sections.
- `/wishlist` now exists with a website-local persisted wishlist store compatible with SPA `homaroma-wishlist`, product-card heart toggles, navbar counters, and `wishlist-layout` CMS sections.
- `/profile` now exists with SPA-compatible `homaroma-auth-storage`, member dashboard, order history, address CRUD, contact settings, navbar profile entry, and `profile-layout` CMS sections.
- `/checkout` now exists with a website-local client checkout, SPA-compatible cart/auth storage, `GET /settings`, `GET /promotions/active`, `POST /coupons/validate`, saved address support, points redemption, `POST /orders`, local order history, cart clearing, redirect to `/order/[id]`, and `checkout-layout` CMS sections.
Next implementation target:
- Run manual commerce QA for `/shop -> cart -> /checkout -> /order/[id] -> /track`.
- Confirm website LIFF initialization/auth bootstrap before treating `/profile` as fully production-ready.
- Extend `/order/[id]` payment/slip upload only after explicitly planning the payment side effects and QA gate.
- Escalate backend server-side pricing validation before treating checkout/payment as production-grade, because the current `POST /orders` contract trusts client totals, discounts, points, and shipping values.
- Basic website CMS renderer added under `apps/website/src/components/dynamic`.
- `/` now renders CMS sections from `/pages/home` internally.
- `/products/[id]` now uses website-local data helpers and avoids duplicate product fetch.
- `/shop`, `/category/[id]`, and `/search` now render product/category content on the server instead of client-only fetch.
- `/shop` preserves coupon handoff with a client-only localStorage bridge while keeping product content server-rendered.
- `/search` guards repeated `q` query params before trimming.
- Navbar, Footer, CartDrawer, and legacy content pages now use the website `pop-*` visual language instead of undefined dark/cyan/glass classes.
- CMS parity planning added in `docs/website-cms-parity-plan.md`.
- `/shop` now consumes `shop-layout` CMS sections for announcement, hero/banner, and bottom content around the SSR product grid.
- `/category/[id]` now consumes `category-layout` CMS sections for announcement, hero/banner, and bottom content around the SSR category product grid.
- `/products/[id]` now consumes `product-detail-layout` CMS sections for announcement and bottom content around the SSR product detail.
- `/search` now consumes `search-layout` CMS sections for announcement, hero/banner, and bottom content around SSR search results.
- `/scent-guide` now consumes `scent-guide-layout` CMS sections for announcement, hero/banner, and bottom content around the article index.
- `/scent-guide` now exposes article API failure separately from a legitimate empty article list.
- `/coupons` now consumes `coupons-layout` CMS sections for announcement, hero/banner, and bottom content around the SSR coupon grid.
- `/coupons` now exposes coupon API failure separately from a legitimate empty coupon list.
- `apps/website` CMS parity next target is CMS catch-all custom page support and remaining SPA-only block renderer parity.
- `apps/website` lint passes with warnings only.
- `apps/website` production build passes.
Remaining M1 follow-up:
- Final manual browser smoke test of upgraded website routes.
- Keep remaining `<img>` usage for M1 and schedule `next/image` as a later optimization pass after image hosting is finalized.
- Continue manual visual QA for Navbar, Footer, CartDrawer, and content pages across desktop/mobile breakpoints.