# CMS production deployment

Next.js 16 + Refine admin UI for **Cổ Thư Kỳ Phổ**. Calls the shared NestJS backend (deploy backend first).

## Prerequisites

1. Backend live: `GET https://<api>/health` → `{ ok: true, database: "ok" }`
2. Backend `CORS_ALLOWED_ORIGINS` includes **CMS origin** (e.g. `https://cms.your-domain.com`)
3. SUPER_ADMIN (or MANAGER) account exists — email/password login only (no Google on CMS)

## Required environment variables

| Variable | Required | Notes |
|----------|----------|--------|
| `NEXT_PUBLIC_API_BASE_URL` | **Yes** | HTTPS API root, no trailing slash. **Not** localhost in production. |

**Do not** put backend secrets (`DATABASE_URL`, `JWT_*`, etc.) in the CMS app.

### Auth / cookie assumptions

| Topic | Behavior |
|-------|----------|
| Login | `POST /auth/login` with email + password |
| Access token | `localStorage.accessToken` → `Authorization: Bearer …` |
| Refresh | HttpOnly cookie from backend; `AuthGate` calls `POST /auth/refresh` on 401 |
| Logout | `POST /auth/logout` + clear `localStorage` |
| Google OAuth | **Not used** on CMS |
| Site API (`/cms/site/*`) | Bearer token; **401** → redirect `/login`; **403** → permission message |

## Deploy commands

From `cms/`:

```bash
npm ci
export NEXT_PUBLIC_API_BASE_URL=https://api.your-domain.com
npm run build
npm run start
```

| Step | Command |
|------|---------|
| Install | `npm ci` |
| Build | `npm run build` (validates production API URL) |
| Start | `npm run start` (port **3001** by default) |

Set `NEXT_PUBLIC_API_BASE_URL` **before** `npm run build` on the host (Next inlines `NEXT_PUBLIC_*` at build time).

## Health / smoke test checklist

### Infrastructure

- [ ] CMS URL loads (no 5xx)
- [ ] `NEXT_PUBLIC_API_BASE_URL` in browser DevTools → Network points to production API (not localhost)
- [ ] Backend `CORS_ALLOWED_ORIGINS` includes CMS origin

### Login

- [ ] Open `/login`
- [ ] Sign in as SUPER_ADMIN (or MANAGER)
- [ ] Redirect to `/dashboard`
- [ ] DevTools: `GET /auth/me` → 200 with `user` + `permissions`
- [ ] `localStorage.accessToken` present

### Site management (requires backend site CMS APIs)

**Menu** (`/dashboard/site/menu`) — MANAGER / SUPER_ADMIN (`site:menu:write`):

- [ ] List loads
- [ ] Create menu item (internal href e.g. `/tu-vi`)
- [ ] Toggle active / reorder
- [ ] Save without 403

**Pages** (`/dashboard/site/pages`) — AUTHOR+ for edit; MANAGER+ to publish:

- [ ] List shows pages + status
- [ ] Create page, add blocks, save draft
- [ ] Publish page
- [ ] Public: `GET https://<api>/site/pages/<slug>` returns published JSON

**Footer** (`/dashboard/site/footer`) — MANAGER / SUPER_ADMIN:

- [ ] Load company info + links
- [ ] Edit description / add link
- [ ] Public: `GET https://<api>/site/footer` reflects changes

### Public web verification

After CMS edits (allow ~60s if web uses ISR, or hard-refresh):

- [ ] Public web header menu matches CMS (or fallback if API empty)
- [ ] `https://<web>/pages/<slug>` renders published blocks
- [ ] Footer shows updated links/text

## Rollback notes

1. **Application:** redeploy previous CMS build artifact; env unchanged.
2. **Content:** site data lives in PostgreSQL via backend — rolling back CMS does not revert DB; use backend/admin to revert content if needed.
3. **Env mistake:** wrong `NEXT_PUBLIC_API_BASE_URL` requires **rebuild** (not just restart) because `NEXT_PUBLIC_*` is baked at build time.

## Related docs

- [`docs/deploy-cms-checklist.md`](docs/deploy-cms-checklist.md) — extended auth/CORS troubleshooting
- [`../backend/DEPLOYMENT.md`](../backend/DEPLOYMENT.md) — API deploy order
