# Plan: Consolidate 4 storefronts into one server-rendered multi-tenant Next.js app

## Context

You maintain 4 separate Next.js storefronts (Sobkaha, Multicart, Bonik, Balmy), each with
multiple numbered page layouts, all sharing the same business logic via a copy-pasted
`context` library (`gitlab.com/jr_reda/context.git`). You want **one** project that:

1. Serves all layouts as a single unified storefront (layouts are variants, not separate themes).
2. Hides API calls from the browser network tab.
3. Is strongly SEO-optimized.
4. Uses state-of-the-art, standard tech.

### Key findings from the current code

- **Sobkaha is already the most-evolved project.** It has the exact consolidation pattern you
  want: a layout registry (`src/layouts/registry.js`) mapping a layout number (1–14) to
  lazy-loaded (`next/dynamic`) shell/Home/Product components, with a `_template` for adding more.
  The layout number is resolved per tenant from the API via `useLayout` / `SettingProvider`.
- **Stack is already modern**: Next.js 16.2.9, React 19, Tailwind 4, React Compiler enabled.
- **The blocker is the deployment model.** `next.config` uses `output: "export"` (static HTML)
  copied into `C:/xampp/htdocs/markattynextBuild` and served by Apache. This makes goals #2 and #3
  **impossible as-is**:
  - No server runtime → all data is fetched **client-side via REST `fetch`** to the Mobikul backend
    (`{protocol}{tenantDomain}/mobikulhttp/v2/{endpoint}`), authenticated with an `api-token` header
    = `process.env.API_KEY`. The single choke point is `getEndpointData()` in
    `src/context/helpers/domain/DomainContext.js`; the key and upstream URL are currently shipped to
    the browser (via `next.config` `env`) and visible in every request. (`apollo.js` is **dead
    code** — REST is the real data layer — delete it during the migration.)
  - Exported HTML are empty shells; layout + content load client-side at runtime → crawlers see
    near-empty pages (weak SEO).
- Tenant is resolved client-side from `window.location.host` (`markattyDomain.js`); ~18 client
  context providers wrap the app in `_app.js`.

### Decisions (recommended)

- **Continue on the Sobkaha repo** — do **not** start from scratch. It already embodies the target
  architecture; the other 3 projects' layouts get ported in as new registry entries. This is a
  **migration**, not a rewrite — all feature/layout components are reused.
- **Hosting → run as a Node server** (`next start` behind Nginx on a VPS, or Vercel). This is
  mandatory for goals #2 and #3. Drop `output: "export"` and the `move-export.js` Apache drop.
- **Architecture → migrate to the App Router** (current Next.js standard). Server Components +
  Route Handlers/Server Actions deliver hidden APIs and the Metadata API delivers best-in-class SEO.
  Pages Router and App Router can coexist, so migrate route-by-route.
- **Shared `context` → internal workspace package** (`packages/context`, imported as
  `@markatty/context`). Ends the copy-paste; versioned with the app.

### Performance answer (your question #1)

A larger codebase will **not** hurt runtime performance. The registry already code-splits each
layout with `next/dynamic`, so the browser only downloads the **active** layout's chunk regardless
of how many layouts exist. Larger impact is on **build/dev time**, mitigated by Turbopack (Next 16
default) and the existing per-layout split. Net: safe to consolidate.

---

## Implementation

### Phase 0 — Repo + tooling foundation

- Convert the repo to npm/pnpm **workspaces**; move `src/context` → `packages/context`
  (`@markatty/context`). Update the `@/context/*` imports (in `_app.js` and across features) to the
  package name. Other 3 repos can keep consuming the same package until decommissioned.
- Split env: move `API_KEY`, `API_URL`, GraphQL endpoint into **server-only** env (no
  `NEXT_PUBLIC_`). Remove them from `next.config` `env` block (currently shipped to the client).
- Remove `output: "export"`, `distDir`, `assetPrefix`, and the `move-export.js` build step. Switch
  the build target to a Node server (`next build` + `next start`), or Vercel.

### Phase 1 — App Router foundation (prove with one route)

- Create `src/app/` with a root `layout.jsx` + a `Providers` client component that wraps the
  existing context providers from `_app.js` ('use client'), receiving server-fetched initial state.
- Add **middleware** (`middleware.js`) that resolves the tenant from the `Host` header (replacing
  client-side `markattyDomain.js`), fetches store settings (layout number, branch, currency, theme
  tokens) server-side, and forwards them via request headers / a server context.
- Migrate the **home route** end-to-end as the proof: `app/page.jsx` (or `app/(store)/page.jsx`)
  resolves the layout number server-side and renders the registry's Home component. Keep the
  registry (`src/layouts/registry.js`); `next/dynamic` still splits per layout under App Router.

### Phase 2 — BFF: hide the APIs (goal #2)

- Relocate `getEndpointData()` (the single REST choke point in `DomainContext.js`) to the **server**:
  a server-only fetch wrapper that injects the `api-token`/`API_KEY` and the upstream Mobikul base
  URL, so neither ever reaches the browser.
- **Reads** (product, category, home data) are fetched inside Server Components via that wrapper.
- **Mutations** (add to cart, login, checkout, wishlist — the `checkout/*`, `catalog/*` endpoints)
  go through **Server Actions** or Route Handlers under `app/api/*` that proxy to Mobikul. The
  browser then only ever calls same-origin `/api/...`; the upstream `/mobikulhttp/v2/*` URL and
  `API_KEY` never reach the client.
- Refactor client context providers (cart/wishlist/etc.) to call these same-origin endpoints instead
  of fetching Mobikul directly.
- Delete the dead `apollo.js`.

### Phase 3 — Migrate remaining routes

- Port route-by-route from `src/pages/*` to `src/app/*`: `product/[id]`, `categories/[slug]`,
  `cart`, `checkout`, `account`, `compare`, `search`, `wishlist`, `about`, `contact`. Reuse existing
  feature components in `src/features/*`; mark interactive ones `'use client'`. Delete each Pages
  Router route as its App Router equivalent lands.

### Phase 4 — SEO (goal #3)

- `generateMetadata` per route (title/description/canonical/OpenGraph) from server data; set
  `metadataBase` per tenant from the resolved host.
- Render product/category pages with SSR or **ISR** (`revalidate`) so crawlers get full HTML.
- Port existing `ProductSEO.jsx` / `ProductSchemaMicrodata.jsx` into **JSON-LD** structured data
  (Product, BreadcrumbList, Organization).
- Add dynamic, per-tenant `app/sitemap.js` and `app/robots.js`.

### Phase 5 — Absorb the other 3 projects' layouts

- For each unique layout in Multicart/Bonik/Balmy, copy it into `src/layouts/layout-N/` following
  `src/layouts/_template`, and add one entry to `src/layouts/registry.js`
  (`AVAILABLE_LAYOUTS` + `importers`). No theme branching — they all become numbered layouts in the
  one project, selected by the API's layout number.

### Phase 6 — Cutover

- Point tenant domains at the Node server (reverse proxy / Vercel). Decommission the Apache static
  drop and archive the 3 old repos once their layouts are ported and verified.

---

## Critical files

- `next.config.mjs` — remove static export + client-exposed `env`.
- `packages/context/*` (from `src/context/*`) — shared logic as a package.
- `src/context/helpers/domain/DomainContext.js` — `getEndpointData()` REST choke point; move
  server-side + add `app/api` proxies. Delete dead `helpers/apollo.js`.
- `src/layouts/registry.js`, `src/layouts/_template/*` — layout registry (kept; extended in Phase 5).
- `src/context/hooks/useLayout.js`, `helpers/theme-setting/SettingProvider.js` — layout resolution,
  moved server-side via middleware.
- `src/pages/_app.js` → `src/app/layout.jsx` + `Providers` client component.
- `src/context/utils/markattyDomain.js` → middleware-based server tenant resolution.
- `src/features/product/ProductSEO.jsx`, `ProductSchemaMicrodata.jsx` → `generateMetadata` + JSON-LD.

## Verification

- **Hidden APIs**: run `next start`, open DevTools → Network. Confirm product/category data renders
  in the initial HTML (View Source) and the browser makes only same-origin `/api/*` calls — no
  `/mobikulhttp/v2/*` URL or `API_KEY`/`api-token` present in any request or JS bundle
  (`grep` the build output).
- **SEO**: `curl` a product URL and confirm full content + `<title>`/meta/JSON-LD in the raw HTML;
  validate with Rich Results Test; confirm `/sitemap.xml` and `/robots.txt` resolve per tenant.
- **Multi-tenant + layouts**: hit the app under two different tenant hosts; confirm each renders its
  configured layout number, and that only the active layout's JS chunk loads (Network tab).
- **Performance**: `next build` and compare per-route First Load JS; confirm adding layouts doesn't
  grow the home route's bundle (per-layout splitting intact). Run Lighthouse for SEO/perf scores.
