# Plan: baota-pc-web-nuxt

**Author:** planner  
**Created:** 2026-08-13

## Context

### 原始需求

宝塔安装包需纳入 PC 端 Nuxt，前缀 `/web`，脚本启动，修改打包与初始化脚本。

### 访谈摘要

见 `.tasks/drafts/baota-pc-web-nuxt.md`。锁定：baseURL=/web/、Supervisor、仅宝塔、目录名 `web/`。

### 研究发现

- `deploy/baota/` 仅静态 admin/mobile；无 Nuxt。
- sibling `ECShopX_web-frontend` 已支持 `NUXT_PUBLIC_API_BASE` / `NUXT_INTERNAL_API_BASE`，缺 `app.baseURL` env。
- docker-lite 三端口模型不在本次范围。

### Advisor 审查

- Build；sibling baseURL 为 IN scope 前置。
- 须补 `NUXT_INTERNAL_API_BASE=http://127.0.0.1/api/h5app`。
- 测试用 shell 契约 + 夹具，勿强制 CI 全量 pnpm build。
- nginx `/web/` 在 `location /` 前；`proxy_pass` 无尾 `/`。

### 详细步骤计划（superpowers）

`docs/superpowers/plans/2026-08-13-baota-pc-web-nuxt.md`

---

## Work Objectives

### 核心目标

宝塔 zip 可部署 PC：`/web/` → Nuxt `:3000`，Supervisor 保活；admin/mobile/api 无回归。

### 交付物

1. `ECShopX_web-frontend/nuxt.config.ts`：`NUXT_APP_BASE_URL` → `app.baseURL`
2. `deploy/baota/nginx.rewrite`：`/web` 反代
3. `deploy/baota/pack.sh`：构建并打入 `web/.output/`
4. `deploy/baota/install.sh`：Node≥20 + `ecshopx-nuxt`
5. `deploy/baota/README.md`
6. `tests/deploy/baota/` shell 契约测试

### 完成定义

- `bash tests/deploy/baota/run-all.sh` 全绿
- 行为符合下方 Acceptance & Test Cases（用户审核锁定后）

### 必须项

- 目录名 `web/`；Supervisor env 含 PUBLIC + INTERNAL API；pack 注入 `/web/` baseURL

### 禁止项

- 改 docker-lite；PC 静态进 `public/web`；PM2/systemd 默认；默认写死 baseURL=/web/

---

## Task Flow

```
T1 契约脚手架+nginx RED → T2 nginx GREEN
T3 sibling baseURL RED→GREEN
T4 pack 契约 RED → T5 pack GREEN
T6 install 契约 RED → T7 install GREEN
T8 README
T9 run-all + 冒烟清单
```

并行：T3 可与 T1–T2 并行；T4 依赖 T3（逻辑依赖）；T6 可与 T4 并行。

---

## Acceptance & Test Cases

### 验收标准（WHEN/THEN）

| ID | 场景 | WHEN / THEN |
|----|------|-------------|
| A1 | 正常 | WHEN 读取打包后的 `nginx.rewrite` THEN 存在 `location ^~ /web/` 且 `proxy_pass http://127.0.0.1:3000;`（无尾 `/`），且该块位于兜底 `location /` 之前 |
| A2 | 正常 | WHEN `NUXT_APP_BASE_URL` 未设置 THEN `nuxt.config` 的 `app.baseURL` 解析为 `/` |
| A3 | 正常 | WHEN pack 以默认前端开关构建 PC THEN stage/zip 内存在 `web/.output/server/index.mjs` |
| A4 | 正常 | WHEN pack 构建 PC THEN 构建命令环境含 `NUXT_APP_BASE_URL=/web/` 与 `NUXT_PUBLIC_API_BASE=/api/h5app` |
| A5 | 正常 | WHEN install 在 Node≥20 且存在 `web/.output/server/index.mjs` 且有 Supervisor conf 目录 THEN 写入 `ecshopx-nuxt` 配置，command 为 `node .output/server/index.mjs`，directory 为 `${SITE_ROOT}/web` |
| A6 | 正常 | WHEN 查看 `ecshopx-nuxt` 环境变量 THEN 含 `NITRO_HOST=127.0.0.1`、`NITRO_PORT=3000`、`NUXT_PUBLIC_API_BASE=/api/h5app`、`NUXT_INTERNAL_API_BASE=http://127.0.0.1/api/h5app` |
| A7 | 正常 | WHEN install 成功结束 THEN 日志/输出含 PC 路径 `/web/` |
| A8 | 边界 | WHEN `PACK_FRONTEND=false` THEN pack 不要求、不复制 PC `.output`（与 admin/mobile 一并跳过） |
| A9 | 异常 | WHEN 安装机 Node 主版本 &lt;20 或无 node THEN install 对 PC 步骤 hard fail 并提示 |
| A10 | 异常 | WHEN 缺少 `web/.output/server/index.mjs` THEN install 对 PC 步骤 hard fail |
| A11 | 回归 | WHEN 检查 nginx.rewrite THEN `/admin/`、`/mobile/`、`/api/` 原有 location 仍存在 |
| A12 | 文档 | WHEN 阅读 README THEN 说明 `/web/`、打包 Node16+20、安装 Node≥20、Supervisor、`web/.output` |

### 测试用例（由场景推导）

| 用例 ID | 对应 | 描述 | 类型 | 边界说明 |
|---------|------|------|------|----------|
| TC-N1 | A1,A11 | `test-nginx-web-location.sh` grep `/web`、无尾 `/`、顺序、admin/mobile/api 仍在 | 正常+回归 | 错误形态 `3000/` 必须失败 |
| TC-B1 | A2 | `test-nuxt-baseurl-config.sh` 断言 `NUXT_APP_BASE_URL \|\| '/'` | 正常 | 禁止写死 `'/web/'` 为唯一值 |
| TC-P1 | A3,A4 | `test-pack-web-hooks.sh` 断言 pack.sh 含 WEB_FRONTEND_DIR、env、pnpm、web/.output | 正常 | 脚本级契约；全量 build 手工可选 |
| TC-P2 | A8 | 文档/代码审阅或 grep：`PACK_FRONTEND=false` 早退覆盖 PC | 边界 | 空前端开关 |
| TC-I1 | A5,A6,A7 | `test-install-nuxt-supervisor.sh` 断言 program/env/成功文案 | 正常 | — |
| TC-I2 | A9,A10 | 代码审阅：`require_node20` 与 index.mjs 检查后 `exit 1` | 异常 | 无 node、低版本、缺产物 |
| TC-D1 | A12 | README 关键词人工/grep 检查 | 正常 | — |
| TC-R1 | — | `run-all.sh` 聚合全部契约 | 正常 | — |

---

## TODOs

### TODO-1 [RED] nginx 契约测试脚手架

- **What to do:** 创建 `tests/deploy/baota/` 夹具、`run-all.sh`、`test-nginx-web-location.sh`（含 A11 回归 grep）
- **Must NOT do:** 此时不改 `nginx.rewrite`
- **Parallelizable:** 可与 TODO-3 并行
- **References:** Acceptance A1,A11；TC-N1；superpowers Task 1
- **Verification:** 跑 nginx 测试 → 失败（RED）
- **验收/用例:** A1,A11 / TC-N1

### TODO-2 [GREEN] 实现 nginx `/web`

- **What to do:** 按 spec 插入 location；Upgrade 头；位置在兜底 `location /` 前
- **Must NOT do:** `proxy_pass` 加尾 `/`；改动 admin/mobile/api 语义
- **Parallelizable:** 否（依赖 TODO-1）
- **References:** superpowers Task 2
- **Verification:** TC-N1 转绿
- **验收/用例:** A1,A11 / TC-N1

### TODO-3 [RED→GREEN] sibling `app.baseURL`

- **What to do:** 契约测试 `test-nuxt-baseurl-config.sh`；改 `ECShopX_web-frontend/nuxt.config.ts`
- **Must NOT do:** 默认写死 `/web/`；改 docker-lite
- **Parallelizable:** 可与 TODO-1/2 并行
- **References:** superpowers Task 3
- **Verification:** TC-B1 绿
- **验收/用例:** A2 / TC-B1

### TODO-4 [RED] pack.sh 契约测试

- **What to do:** `test-pack-web-hooks.sh`
- **Must NOT do:** 此时不改 pack.sh
- **Parallelizable:** 依赖 TODO-3 语义就绪后实现，测试可先写
- **References:** superpowers Task 4
- **Verification:** RED
- **验收/用例:** A3,A4,A8 / TC-P1,TC-P2

### TODO-5 [GREEN] 实现 pack.sh PC

- **What to do:** `WEB_FRONTEND_DIR`、Node20+pnpm build、复制 `web/.output/`、断言 index.mjs；`PACK_FRONTEND` 同开同关
- **Must NOT do:** 把 PC 拷进 `public/web`；打入完整源码树
- **Parallelizable:** 否（依赖 TODO-4）
- **References:** superpowers Task 5
- **Verification:** TC-P1 绿；可选手工 pack
- **验收/用例:** A3,A4,A8 / TC-P1,TC-P2

### TODO-6 [RED] install.sh 契约测试

- **What to do:** `test-install-nuxt-supervisor.sh`（含 INTERNAL_API）
- **Must NOT do:** 此时不改 install.sh
- **Parallelizable:** 可与 TODO-4 并行
- **References:** superpowers Task 6
- **Verification:** RED
- **验收/用例:** A5–A7,A9,A10 / TC-I1,TC-I2

### TODO-7 [GREEN] 实现 install.sh Nuxt Supervisor

- **What to do:** `require_node20`、`_write_nuxt_conf`、成功页 `/web/`；复用 conf_dir 探测
- **Must NOT do:** PM2；静默跳过缺 Node（须 hard fail）
- **Parallelizable:** 否
- **References:** superpowers Task 7
- **Verification:** TC-I1 绿；审阅 TC-I2
- **验收/用例:** A5–A7,A9,A10 / TC-I1,TC-I2

### TODO-8 README

- **What to do:** 更新路径表、包结构、Node、Supervisor、3000 端口、INTERNAL_API 说明
- **Must NOT do:** 声称改了 docker-lite
- **Parallelizable:** 可与后期并行
- **References:** superpowers Task 8
- **Verification:** TC-D1
- **验收/用例:** A12 / TC-D1

### TODO-9 汇总验证

- **What to do:** `run-all.sh`；diff 审阅无回归
- **Must NOT do:** 无证据声称完成
- **Parallelizable:** 否
- **References:** superpowers Task 9
- **Verification:** TC-R1 全绿
- **验收/用例:** 全部

---

## 测试用例审核

请确认上方 **Acceptance & Test Cases** 是否通过。通过后回复「测试用例审核通过」或「开始执行」；若需高精度 Reviewer 审查请说明。
