# Web (Next.js) — checklist deploy production

Chuẩn bị **app public** (`web/`) cho beta/production. **CMS không** nằm trong repo này.

**Backend trước, web sau:** xem [`backend/docs/deploy-backend-checklist.md`](../../backend/docs/deploy-backend-checklist.md).

**QA auth (lặp lại được):** [`beta-auth-smoke-test.md`](./beta-auth-smoke-test.md).

---

## Phụ thuộc backend

1. API đã deploy, `DATABASE_URL` + migration + secrets OK.
2. **`GET <API>/health`** → `ok: true` (và tuỳ chọn `GET /health/db`).
3. **`CORS_ALLOWED_ORIGINS`** trên backend **gồm đúng origin web production** (ví dụ `https://www.example.com`) — CORS bật `credentials: true`; **không** dùng `*`.
4. **Google OAuth (nếu bật nút Google):**
   - **`WEB_AUTH_SUCCESS_REDIRECT_URL`** = `https://<web-domain>/auth/oauth-success` (khớp origin + path public web).
   - **`WEB_AUTH_ERROR_REDIRECT_URL`** = `https://<web-domain>/login` (khuyến nghị).
   - **Google Cloud “Authorized redirect URI”** = **`GOOGLE_OAUTH_CALLBACK_URL`** (URL **API**, ví dụ `https://api.example.com/auth/google/callback`) — **không** trỏ vào route Next.

---

## Biến môi trường (`web`)

Các biến `NEXT_PUBLIC_*` được **embed lúc build** — đổi giá trị production **cần build lại** artifact.

### Bắt buộc cho site gọi API

| Biến | Ghi chú |
|------|---------|
| `NEXT_PUBLIC_API_BASE_URL` | Gốc API (HTTPS production), **không** dấu `/` cuối. **Không** dùng `localhost` / `127.0.0.1` cho browser người dùng. |

### Tuỳ chọn (đã dùng trong code / `web/.env.example`)

| Biến | Ghi chú |
|------|---------|
| `NEXT_PUBLIC_SITE_URL` | Origin site public cho SEO / canonical (không `/` cuối). |
| `NEXT_PUBLIC_SOFT_LAUNCH_MODE` | Đặt `1` chỉ khi muốn bật cờ soft launch **client**; cần backend `SOFT_LAUNCH_MODE=1`. Mặc định an toàn: không set. |
| `NEXT_PUBLIC_BETA_PUBLIC_SURFACE` | `1` khi deploy **public beta surface** (giới hạn route công khai). Embed lúc build. |
| `BETA_PUBLIC_SURFACE` | **Server-only** — khuyến nghị `1` khi bật beta (đọc runtime; bổ sung cho một số môi trường). |
| `BETA_STAFF_BYPASS_SECRET` | **Server-only** — cookie staff nội bộ; không để lộ. |
| `SOFT_LAUNCH_ADMIN_SECRET` | **Server-only** — khớp backend nếu dùng trang soft-launch nội bộ. |

**Không** đưa secret API, JWT, hay database vào tên `NEXT_PUBLIC_*`.

Các biến debug (`NEXT_PUBLIC_DEBUG_*`, `NEXT_PUBLIC_TUVI_INTERPRETATION_DEBUG`, …) chỉ dùng khi dev; production beta nên để trống.

Tham chiếu mẫu: **`web/.env.example`**.

---

## Scripts npm

| Mục | Lệnh |
|-----|------|
| Cài đặt | `npm ci` hoặc `npm install` |
| Build production | `npm run build` |
| Start production | `npm run start` (mặc định cổng **3002** trong `package.json`) |
| Chỉ local | `npm run dev` — cổng **3002** |

**PaaS:** Nhiều nền tảng inject `PORT`. Script hiện tại là `next start -p 3002`; nếu host yêu cầu cổng động, cấu hình lệnh start trên platform (ví dụ `next start -p %PORT%` / `$PORT`) theo tài liệu host — không bắt buộc đổi `package.json` nếu host cho override command.

---

## Thứ tự deploy (khuyến nghị)

1. Đặt env trên platform (hoặc secrets CI).
2. `npm install` / `npm ci`.
3. `npm run build`.
4. `npm run start` (hoặc lệnh start tương đương trên host).
5. Kiểm tra nhanh trình duyệt:
   - `/login`
   - Đăng nhập Google (nếu bật) — về `/auth/oauth-success`, hash biến mất, session + OTP theo [`beta-auth-smoke-test.md`](./beta-auth-smoke-test.md).
   - `/verify-phone`
   - `/account`
6. Làm đủ smoke test auth (bên dưới).

---

## Smoke test thủ công (tóm tắt)

| Bước | Kỳ vọng |
|------|---------|
| Đăng nhập email/mật khẩu | JWT lưu client, redirect verify-phone nếu cần. |
| Google login | Consent → `/auth/oauth-success` → token lưu (xem checklist auth). |
| OTP | `/verify-phone` hoàn tất, `/auth/me` không còn `requiresPhoneVerification`. |
| Gate | `/account` — kiểm tra quyền sau khi SĐT đã xác minh. |
| Đăng xuất / đăng nhập lại | Header “Đăng xuất” xóa token local; đăng nhập lại ổn định. |

Chi tiết từng bước: [`beta-auth-smoke-test.md`](./beta-auth-smoke-test.md).

---

## Routes chính (sanity)

| Route | Ghi chú |
|-------|---------|
| `/` | Trang chủ |
| `/login` | Đăng nhập + Google |
| `/register` | Đăng ký |
| `/verify-phone` | OTP |
| `/auth/oauth-success` | OAuth callback fragment (Google) — client đọc `#accessToken` rồi gỡ hash |
| `/account` | Tài khoản beta |

---

## Ghi chú production / bảo mật (beta hiện tại)

- **Access token** đang lưu **`localStorage`** (hằng `WEB_ACCESS_TOKEN_STORAGE_KEY` trong `web-auth-client.ts` — giá trị `ctkp_web_access_token`) — chấp nhận rủi ro beta; **hardening sau** nên cân nhắc session chỉ cookie/httpOnly theo thiết kế API.
- **`/auth/oauth-success`** tạm nhận **`#accessToken=…`** trên URL; client **gỡ fragment ngay** sau khi đọc — không hiển thị token cho user.
- Chỉ dùng `NEXT_PUBLIC_*` cho dữ liệu **an toàn khi lộ** (URL API public, cờ tính năng). **Không** dùng `NEXT_PUBLIC_` cho secret.

---

## Liên quan

- Deploy API: [`backend/docs/deploy-backend-checklist.md`](../../backend/docs/deploy-backend-checklist.md)
- Beta surface + env chi tiết: [`beta-public-deploy-checklist.md`](./beta-public-deploy-checklist.md), [`beta-production-smoke-test.md`](./beta-production-smoke-test.md)
