# Web (public site) production deployment

Next.js 16 public app — deploy **after** backend API and (optionally) CMS content.

## Prerequisites

| Dependency | Requirement |
|------------|-------------|
| Backend | Live at `NEXT_PUBLIC_API_BASE_URL`; `GET /health` OK |
| CORS | Backend `CORS_ALLOWED_ORIGINS` includes **web** origin |
| CMS content | Menu/footer/pages via `/site/*` (seed or CMS edits) |
| SEO | Set `NEXT_PUBLIC_SITE_URL` for sitemap, canonical, JSON-LD |

## Required environment variables

| Variable | Production | Notes |
|----------|------------|--------|
| `NEXT_PUBLIC_API_BASE_URL` | **Required** | `https://api…` — no trailing slash, not localhost |
| `NEXT_PUBLIC_SITE_URL` | **Recommended** | `https://www…` — canonical, `/sitemap.xml`, `/robots.txt` |

**Build-time:** `NEXT_PUBLIC_*` is inlined at `npm run build` — change requires rebuild.

**Optional:** `NEXT_PUBLIC_BETA_PUBLIC_SURFACE`, `BETA_PUBLIC_SURFACE`, `BETA_STAFF_BYPASS_SECRET` — see [docs/beta-public-deploy-checklist.md](docs/beta-public-deploy-checklist.md).

## Backend public endpoints used

| Endpoint | Purpose |
|----------|---------|
| `GET /site/menu` | Header navigation (fallback: hardcoded nav in `betaVisibility.ts`) |
| `GET /site/footer` | Footer copy + links (fallback: hardcoded footer nav) |
| `GET /site/pages/:slug` | CMS pages at `/pages/[slug]` — **404** if draft/missing |
| `GET /posts`, `/fortune/*`, `/tu-vi/*`, etc. | Existing product features |

## Deploy commands

```bash
cd web
npm ci
export NEXT_PUBLIC_API_BASE_URL=https://api.your-domain.com
export NEXT_PUBLIC_SITE_URL=https://www.your-domain.com
npm run build
npm run start
```

| Step | Command |
|------|---------|
| Install | `npm ci` |
| Build | `npm run build` (validates API URL in production) |
| Start | `npm run start` or `npm run start:prod` (port **3002**) |

## Public smoke test checklist

### Infrastructure

- [ ] Homepage loads `https://<web>/`
- [ ] `https://<web>/robots.txt` returns rules + sitemap URL (when `NEXT_PUBLIC_SITE_URL` set)
- [ ] `https://<web>/sitemap.xml` lists key routes
- [ ] DevTools → no requests to `localhost:3000` from production origin

### CMS content (after CMS publish)

- [ ] Header reflects `GET /site/menu` (or fallback nav if API empty)
- [ ] Footer reflects `GET /site/footer` (or fallback)
- [ ] `https://<web>/pages/lien-he` — published CMS page renders
- [ ] Unpublished slug → **404**
- [ ] View page source / meta: `seoTitle` / `seoDescription` from CMS when set

### Core routes (must not break)

- [ ] `/` — homepage
- [ ] `/tu-vi` — Tử Vi flow
- [ ] `/gieo-que`, `/posts` as applicable
- [ ] `/about`, `/contact` legacy pages still work

### API failure fallback

- [ ] With API temporarily unreachable: site still loads; header/footer use hardcoded nav (not blank)

## CMS content dependency

1. Deploy backend + run migrations/seed.
2. Use CMS (**Quản lý website**) to publish menu, footer, pages.
3. Rebuild **not** required for content-only changes (web revalidates `/site/*` every ~60s via `revalidate: 60`).
4. Rebuild **is** required if you change `NEXT_PUBLIC_*` env vars.

## Rollback notes

1. Redeploy previous web build artifact.
2. Content rollback is via CMS/backend DB, not web deploy.
3. Wrong `NEXT_PUBLIC_API_BASE_URL` → fix env and **rebuild**.

## Related docs

- [docs/deploy-web-checklist.md](docs/deploy-web-checklist.md)
- [../backend/DEPLOYMENT.md](../backend/DEPLOYMENT.md)
- [../cms/DEPLOYMENT.md](../cms/DEPLOYMENT.md)
