# 共同富裕项目 — 测试用例

> 依据：`共同富裕项目功能需求.md`、`共同富裕项目技术方案.md`  
> **接口 Base Path（示例）**：`/commonProsperity/project`；若含 `context-path` 或网关前缀须补齐。鉴权与若依一致（Cookie / Token）。

**通用前置（无特殊说明）**：具备本模块菜单与按钮权限的账号已登录；可先调 `POST /common/upload` 取得附件的 `url`、`fileName`（作 `filePath`）。**运营图片**：`jpg`/`jpeg`/`png`，单张 ≤10MB，**1～3 张**（必填）。**运营视频**：`mp4`（可扩展），≤100MB，选填。**封面**：`jpg`/`jpeg`/`png`，≤10MB，选填。**项目类型**：`1` 合作共赢、`2` 农文旅融合、`3` 认养农业。**发布状态**：`0` 未发布、`1` 已发布。

**界面（UI）测试**：借助 **Playwright** 启动 **Chromium**（与 **Google Chrome 同源内核**）；可配置 `channel: 'chrome'` 调用本机已安装的谷歌浏览器，模拟点击、输入、多图/视频选择与断言。

---

## 一、单元测试用例

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| GTFY-XM-UT-001 | 状态机 | 编辑守卫 | 单元测试 | JUnit5 | 仅未发布可改 | 无 | 调用 `canEdit(publishStatus)`：`0`→true，`1`→false | 与需求 §6 矩阵一致 |
| GTFY-XM-UT-002 | 状态机 | 删除守卫 | 单元测试 | JUnit5 | 仅未发布可删 | 无 | 调用 `canDelete`：`0`→true，`1`→false | 与 §5.4 一致 |
| GTFY-XM-UT-003 | 状态机 | 发布守卫 | 单元测试 | JUnit5 | 仅未发布可发布 | 无 | 调用 `canPublish`：`0`→true，`1`→false | 与 §5.6 一致 |
| GTFY-XM-UT-004 | 状态机 | 下架守卫 | 单元测试 | JUnit5 | 仅已发布可下架 | 无 | 调用 `canOffline`：`1`→true，`0`→false | 与 §5.6 一致 |
| GTFY-XM-UT-005 | 参数校验 | 项目名称长度 | 单元测试 | JUnit5 | 1～20 字 | 无 | 空串、1 字、20 字、21 字 | 空/21 失败；1～20 通过 |
| GTFY-XM-UT-006 | 参数校验 | 项目类型 | 单元测试 | JUnit5 | 仅 1～3 | 无 | `projectType` 为 1/3 通过；0、4、null 失败 | 与技术方案 §2.4 一致 |
| GTFY-XM-UT-007 | 参数校验 | 简介/内容字数 | 单元测试 | JUnit5 | 简介 1～50；内容 1～500 | 无 | 简介空/51 字；内容空/501 字 | 均失败；合法长度通过 |
| GTFY-XM-UT-008 | 参数校验 | 实施日期区间 | 单元测试 | JUnit5 | 结束≥开始 | 无 | `implEndDate`&lt;`implStartDate`；相等；合法区间 | 前者失败；后两者通过 |
| GTFY-XM-UT-009 | 运营图片 | 数量 1～3 | 单元测试 | JUnit5 | §5.1 | 无 | `operationImages` 为 0/1/3/4 项 | 0、4 失败；1、3 通过 |
| GTFY-XM-UT-010 | 运营图片 | sortOrder 唯一 | 单元测试 | JUnit5 | 同请求内不重复 | 无 | 两张图均为 `sortOrder=1` | 失败 |
| GTFY-XM-UT-011 | 附件校验 | 运营图后缀 | 单元测试 | JUnit5 | 白名单 | 无 | `.jpg` 通过；`.bmp` 拒绝 | 与 §3.4 一致 |
| GTFY-XM-UT-012 | 附件校验 | 视频/封面成对 | 单元测试 | JUnit5 | url/path 同有或同无 | 无 | 仅 `videoFileUrl` 无 path；视频/封面成对齐全 | 前者失败；后者通过 |
| GTFY-XM-UT-013 | 附件校验 | 视频后缀 | 单元测试 | JUnit5 | mp4 | 无 | `.mp4` 通过；`.avi` 拒绝 | 与 §3.4 一致 |
| GTFY-XM-UT-014 | Service | 新增初始状态 | 单元测试 | JUnit5+Mockito | 草稿 | 合法 Body（含 1 张运营图） | `insert(...)` | 主表 `publish_status=0`；子表 1 条；`publish_time` 空 |
| GTFY-XM-UT-015 | Service | 更新已发布拒绝 | 单元测试 | JUnit5+Mockito | 状态约束 | Mock `publish=1` | `update(...)` | 业务异常；主表与子表不写 |
| GTFY-XM-UT-016 | Service | 发布成功 | 单元测试 | JUnit5+Mockito | 上架 | Mock `publish=0` 且子表≥1 张 | `publish(id)` | `publish=1`；`publish_time` 非空 |
| GTFY-XM-UT-017 | Service | 发布缺运营图拒绝 | 单元测试 | JUnit5+Mockito | §5.6 | Mock 子表 0 条 | `publish(id)` | 失败；状态仍为 0 |
| GTFY-XM-UT-018 | Service | 下架成功回流 | 单元测试 | JUnit5+Mockito | 下架保留附件 | Mock `publish=1` | `offline(id)` | `publish=0`；`offline_time` 非空；子表与视频/封面字段保留 |
| GTFY-XM-UT-019 | Service | 未发布禁止下架 | 单元测试 | JUnit5+Mockito | 异常 | Mock `publish=0` | `offline(id)` | 失败；状态不变 |
| GTFY-XM-UT-020 | Service | 删除联动清文件 | 单元测试 | JUnit5+Mockito | §5.4 | `publish=0`；含 2 张子表 path+视频+封面 path | `remove(ids)` | 删主表+子表；Mock 验证对各 path 调用 `deleteFile` |
| GTFY-XM-UT-021 | Service | 替换运营图删旧 | 单元测试 | JUnit5+Mockito | §5.3 | `publish=0`；旧子表 path 已知 | `update` 换新 `operationImages` | 事务删旧子表再插；Mock 验证删除被移除的 `file_path` |
| GTFY-XM-UT-022 | Service | 下架不删文件 | 单元测试 | JUnit5+Mockito | §5.6 | `publish=1` | `offline(id)` | Mock 验证**未**调用 `deleteFile` |

---

## 二、接口测试用例

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| GTFY-XM-API-001 | 列表 | 默认分页排序 | 接口测试 | Postman/curl | §5.2 | 已登录；有数据 | `GET /commonProsperity/project/list` | `rows`≤20；`create_time` 倒序；含 `opImageCount` |
| GTFY-XM-API-002 | 列表 | 项目名称模糊 | 接口测试 | Postman | 名称模糊 | 已登录 | `projectName=` 片段 | 返回名称含该片段记录 |
| GTFY-XM-API-003 | 列表 | 项目类型筛选 | 接口测试 | Postman | 精确 | 有多类型数据 | `projectType=2` | 均为农文旅融合 |
| GTFY-XM-API-004 | 列表 | 发布状态筛选 | 接口测试 | Postman | §5.2 | 有已/未发布 | `publishStatus=0` / `1` | 与筛选一致 |
| GTFY-XM-API-005 | 列表 | 组合查询 | 接口测试 | Postman | 多条件 | 已登录 | projectName+projectType+publishStatus | 同时满足 |
| GTFY-XM-API-006 | 列表 | App 仅已发布 | 接口测试 | Postman | §8 多端 | 有未发布数据 | `publishStatus=1` | 无未发布记录 |
| GTFY-XM-API-007 | 新增 | 最小必填（1 图） | 接口测试 | Postman | 正常新增 | 已上传 1 张 jpg | `POST` 必填+`operationImages` 1 项 | `code` 成功；`publishStatus=0`；子表 1 条 |
| GTFY-XM-API-008 | 新增 | 含 3 图+视频+封面 | 接口测试 | Postman | 全附件 | 已上传合法文件 | `POST` 3 张图+mp4+封面 | 成功；主表与子表字段落库 |
| GTFY-XM-API-009 | 新增 | 名称非法 | 接口测试 | Postman | 1～20 | 已登录 | 名空/21 字 | 失败；无新记录 |
| GTFY-XM-API-010 | 新增 | 类型非法 | 接口测试 | Postman | 枚举 | 已登录 | `projectType=0` 或 `9` | 失败 |
| GTFY-XM-API-011 | 新增 | 简介/内容非法 | 接口测试 | Postman | 字数 | 已登录 | 简介空或 51 字；内容空或 501 字 | 失败 |
| GTFY-XM-API-012 | 新增 | 实施日期倒置 | 接口测试 | Postman | E≥S | 已登录 | 结束早于开始 | 失败；可读 `msg` |
| GTFY-XM-API-013 | 新增 | 运营图 0 张 | 接口测试 | Postman | 1～3 张 | 已登录 | `operationImages=[]` | 失败 |
| GTFY-XM-API-014 | 新增 | 运营图 4 张 | 接口测试 | Postman | 上限 | 已登录 | 数组 4 项 | 失败 |
| GTFY-XM-API-015 | 新增 | sortOrder 重复 | 接口测试 | Postman | 约束 | 已登录 | 两图同 `sortOrder` | 失败 |
| GTFY-XM-API-016 | 新增 | 视频仅 url 无 path | 接口测试 | Postman | 成对 | 已登录 | 仅 `videoFileUrl` | 失败 |
| GTFY-XM-API-017 | 详情 | 有效 id | 接口测试 | Postman | §5.5 | 已登录 | `GET /commonProsperity/project/{id}` | 含 `operationImages[]` 按 `sortOrder` 升序 |
| GTFY-XM-API-018 | 详情 | 无效 id | 接口测试 | Postman | 异常 | 已登录 | 不存在 id | 404 或业务失败 |
| GTFY-XM-API-019 | 修改 | 未发布成功 | 接口测试 | Postman | §5.3 | publish=0 | `PUT` 改简介 | 成功 |
| GTFY-XM-API-020 | 修改 | 已发布拒绝 | 接口测试 | Postman | 矩阵 | publish=1 | `PUT` | 失败；`msg` 含须下架类提示；数据不变 |
| GTFY-XM-API-021 | 修改 | 替换运营图 | 接口测试 | Postman | 删旧文件 | publish=0；原子表 path 已知 | `PUT` 换 2 张新图 | 成功；旧图 path 不可访问（抽查存储） |
| GTFY-XM-API-022 | 修改 | 删至 0 张图 | 接口测试 | Postman | §5.3 | publish=0 | `PUT` 空 `operationImages` | 失败 |
| GTFY-XM-API-023 | 修改 | 替换视频与封面 | 接口测试 | Postman | §5.3 | 原有视频/封面 | `PUT` 换新 url+path | 成功；旧视频/封面不可访问 |
| GTFY-XM-API-024 | 删除 | 未发布成功 | 接口测试 | Postman | §5.4 | publish=0 | `DELETE .../{ids}` | 成功；详情 404；子表无记录 |
| GTFY-XM-API-025 | 删除 | 已发布拒绝 | 接口测试 | Postman | 矩阵 | publish=1 | `DELETE` | 失败 |
| GTFY-XM-API-026 | 删除 | 批量删除 | 接口测试 | Postman | 批量 | 多条 publish=0 | `DELETE id1,id2` | 均不可查 |
| GTFY-XM-API-027 | 发布 | 未发布成功 | 接口测试 | Postman | §5.6 | publish=0；子表≥1 | `POST .../publish/{id}` | publish=1；`publishTime` 有值 |
| GTFY-XM-API-028 | 发布 | 已发布重复 | 接口测试 | Postman | 异常 | publish=1 | `POST .../publish/{id}` | 失败 |
| GTFY-XM-API-029 | 发布 | 子表 0 张拒绝 | 接口测试 | Postman | 前置校验 | 人为删子表后发布 | `POST .../publish/{id}` | 失败；仍为 0 |
| GTFY-XM-API-030 | 下架 | 已发布成功 | 接口测试 | Postman | §5.6 | publish=1 | `POST .../offline/{id}` | publish=0；`offlineTime` 有值；详情仍有 `operationImages` |
| GTFY-XM-API-031 | 下架 | 未发布拒绝 | 接口测试 | Postman | 约束 | publish=0 | `POST .../offline/{id}` | 失败 |
| GTFY-XM-API-032 | 端到端 | 全生命周期 | 接口测试 | Postman | §4 流程 | 已登录 | 新增(1图)→发布→下架→改(2图)→再发布→下架→删除 | 每步状态与矩阵一致；同 id |
| GTFY-XM-API-033 | 鉴权 | 未登录 | 接口测试 | curl | 安全 | 无 Token | `GET .../list` | 401 或统一未登录响应 |
| GTFY-XM-API-034 | 权限 | 无写权限 | 接口测试 | Postman | 越权 | 仅 list 权限 | `POST .../project` | 无权限失败 |
| GTFY-XM-API-035 | 响应 | 失败可读 | 接口测试 | Postman | §7 | 已登录 | 触发名称空、0 张图等 | Body 含 `code`、`msg`；`msg` 可区分 |
| GTFY-XM-API-036 | 上传 | 运营图超限（可选） | 接口测试 | Postman | §3.4 | 环境允许略超 10MB | `POST /common/upload` 或提交校验 | 明确大小/格式提示；业务表无脏数据 |

---

## 三、界面测试用例（UI）

**测试工具**：**Playwright** + **Chromium**（`channel: 'chrome'` 时使用本机 **Google Chrome**）。步骤映射：`page.goto`、`locator.fill`、`locator.click`、`setInputFiles`、`expect`；确认框：`page.on('dialog')` 或 `getByRole('button', { name: /确定|确认/ })`。

| 用例编号 | 测试模块 | 测试项 | 测试类型 | 测试工具 | 测试目的 | 前置条件 | 测试步骤 | 预期结果 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| GTFY-XM-UI-001 | 列表 | 默认分页排序 | UI 测试 | Playwright+Chrome | §5.2 | 已登录；数据>20 | 进入「共同富裕项目」菜单 | 默认每页 20；创建时间新在前 |
| GTFY-XM-UI-002 | 列表 | 项目名称模糊 | UI 测试 | Playwright+Chrome | 名称模糊 | 存在名称含关键词记录 | 输入项目名称→查询 | 表格含该行 |
| GTFY-XM-UI-003 | 列表 | 项目类型筛选 | UI 测试 | Playwright+Chrome | 精确 | 多类型均有数据 | 选「认养农业」→查询 | 类型列均为认养农业 |
| GTFY-XM-UI-004 | 列表 | 发布状态筛选 | UI 测试 | Playwright+Chrome | §5.2 | 有已/未发布 | 分别筛「未发布」「已发布」 | 状态列与筛选一致 |
| GTFY-XM-UI-005 | 列表 | 组合与重置 | UI 测试 | Playwright+Chrome | 恢复条件 | 已多条件筛选 | 查询→重置 | 条件清空；恢复默认列表 |
| GTFY-XM-UI-006 | 列表 | 操作按钮矩阵 | UI 测试 | Playwright+Chrome | §6 | 准备未发布、已发布各一条 | 逐行查看操作列 | 未发布：编辑/发布/删除；已发布：下架；已发布无编辑/删除/发布 |
| GTFY-XM-UI-007 | 列表 | 运营图数量展示 | UI 测试 | Playwright+Chrome | §5.2 | 有 1 张、3 张图的项目 | 查看列表列 | 显示 `opImageCount` 或等价提示正确 |
| GTFY-XM-UI-008 | 新增 | 最小必填主流程 | UI 测试 | Playwright+Chrome | §5.1 | 已登录 | 新增→填名称/类型/简介/内容/实施起止日→上传 1 张运营图→提交 | 成功；列表「未发布」 |
| GTFY-XM-UI-009 | 新增 | 含 3 图+视频+封面 | UI 测试 | Playwright+Chrome | 全附件 | 已登录 | 上传 3 张 jpg、mp4、封面→提交 | 成功；详情可见图序与视频 |
| GTFY-XM-UI-010 | 新增 | 名称空或超长 | UI 测试 | Playwright+Chrome | 异常 | 已登录 | 名称留空或 21 字→提交 | 校验失败 |
| GTFY-XM-UI-011 | 新增 | 名称 20 字边界 | UI 测试 | Playwright+Chrome | 上限 | 已登录 | 名称 20 字+其余合法→提交 | 成功 |
| GTFY-XM-UI-012 | 新增 | 类型必选 | UI 测试 | Playwright+Chrome | 约束 | 可清空类型时 | 不选类型→提交 | 必选提示 |
| GTFY-XM-UI-013 | 新增 | 简介/内容超长 | UI 测试 | Playwright+Chrome | 字数 | 已登录 | 简介>50 或内容>500 字→提交 | 失败 |
| GTFY-XM-UI-014 | 新增 | 实施日期倒置 | UI 测试 | Playwright+Chrome | E≥S | 已登录 | 结束早于开始→提交 | 校验失败 |
| GTFY-XM-UI-015 | 新增 | 无运营图提交 | UI 测试 | Playwright+Chrome | 1～3 张 | 已登录 | 不上传运营图→提交 | 失败；提示至少 1 张 |
| GTFY-XM-UI-016 | 新增 | 运营图超 3 张 | UI 测试 | Playwright+Chrome | 上限 | 组件允许多选时 | 尝试上传第 4 张 | 前端限制或提交失败 |
| GTFY-XM-UI-017 | 新增 | 图片/视频非法格式 | UI 测试 | Playwright+Chrome | §5.1 | 准备 .bmp、.avi | `setInputFiles`→提交 | 拒绝或明确错误 |
| GTFY-XM-UI-018 | 新增 | 视频封面选填 | UI 测试 | Playwright+Chrome | 选填 | 已登录 | 仅 1 张运营图、不传视频封面→提交 | 成功 |
| GTFY-XM-UI-019 | 详情 | 字段完整 | UI 测试 | Playwright+Chrome | §5.5 | 含视频封面记录 | 点「详情」 | 名称、类型、简介、内容、日期、运营图列表、视频、封面、发布状态齐全 |
| GTFY-XM-UI-020 | 详情 | 运营图预览顺序 | UI 测试 | Playwright+Chrome | sortOrder | 3 张不同序 | 开详情 | 展示顺序与 `sortOrder` 一致 |
| GTFY-XM-UI-021 | 详情 | 已发布只读 | UI 测试 | Playwright+Chrome | §5.5 | 已发布记录 | 开详情 | 无「保存」；可有「下架」 |
| GTFY-XM-UI-022 | 修改 | 未发布编辑成功 | UI 测试 | Playwright+Chrome | §5.3 | 未发布 | 编辑→改简介→保存 | 列表/详情已更新 |
| GTFY-XM-UI-023 | 修改 | 已发布禁止编辑 | UI 测试 | Playwright+Chrome | 矩阵 | 已发布 | 尝试编辑或保存 | 无编辑入口或须下架提示 |
| GTFY-XM-UI-024 | 修改 | 清空必填失败 | UI 测试 | Playwright+Chrome | 异常 | 未发布 | 清空名称或删光运营图→保存 | 校验失败 |
| GTFY-XM-UI-025 | 修改 | 替换运营图 | UI 测试 | Playwright+Chrome | §5.3 | 未发布；原有 2 图 | 编辑→换 1 张新图→保存 | 详情为 1 张新图；旧 URL 失效 |
| GTFY-XM-UI-026 | 修改 | 替换视频与封面 | UI 测试 | Playwright+Chrome | §5.3 | 原有视频封面 | 编辑换新 mp4、png→保存 | 详情为新资源 |
| GTFY-XM-UI-027 | 发布 | 未发布发布成功 | UI 测试 | Playwright+Chrome | §5.6 | 未发布、≥1 图 | 点「发布」→确认 | 状态「已发布」 |
| GTFY-XM-UI-028 | 发布 | 已发布无发布钮 | UI 测试 | Playwright+Chrome | 矩阵 | 已发布行 | 查看操作列 | 「发布」隐藏或禁用 |
| GTFY-XM-UI-029 | 下架 | 已发布下架成功 | UI 测试 | Playwright+Chrome | §5.6 | 已发布 | 点「下架」→确认 | 「未发布」；记录与附件仍在 |
| GTFY-XM-UI-030 | 下架 | 未发布无下架钮 | UI 测试 | Playwright+Chrome | 约束 | 未发布行 | 查看操作列 | 无「下架」 |
| GTFY-XM-UI-031 | 发布下架 | 下架后再发布闭环 | UI 集成 | Playwright+Chrome | §4 步骤 6 | 完成 UI-029 | 编辑（可选换图）→再发布 | 再次「已发布」；同一 id |
| GTFY-XM-UI-032 | 删除 | 未发布删除成功 | UI 测试 | Playwright+Chrome | §5.4 | 未发布 | 删除→确认 | 列表无该行 |
| GTFY-XM-UI-033 | 删除 | 已发布禁删 | UI 测试 | Playwright+Chrome | 矩阵 | 已发布 | 尝试删除 | 按钮不可用或提示先下架 |
| GTFY-XM-UI-034 | 删除 | 取消删除 | UI 测试 | Playwright+Chrome | 确认框 | 未发布 | 删除→取消 | 行仍在 |
| GTFY-XM-UI-035 | 删除 | 删后附件失效 | UI 测试 | Playwright+Chrome | 存储清理 | 删前复制运营图 URL | 删除后新标签打开 | 不可访问或 404 |
| GTFY-XM-UI-036 | 端到端 | 全生命周期串联 | UI 集成 | Playwright+Chrome | §4 | 可新建 | 新增(1图)→发布→下架→改→再发布→下架→删除 | 每步状态与按钮矩阵一致 |
| GTFY-XM-UI-037 | 权限 | 只读账号 | UI 测试 | Playwright+Chrome | §8 | 无 add/edit/remove/publish/offline | 登录进模块 | 无对应按钮或操作拒绝 |
| GTFY-XM-UI-038 | 类型 | 三类均可发布 | UI 测试 | Playwright+Chrome | §2.1 | 已登录 | 各建类型 1/2/3 一条并筛选 | 筛选正确；均可走发布流 |
| GTFY-XM-UI-039 | 错误提示 | 业务失败可读 | UI 测试 | Playwright+Chrome | §7 | 已登录 | 对已发布强行保存或 0 图提交 | Message 含明确原因 |

---

## Playwright 与谷歌浏览器（实施提示）

- 安装：`npm i -D @playwright/test`；`npx playwright install chromium`；本机 Chrome：`npx playwright install chrome`，配置 `channel: 'chrome'`。  
- `playwright.config.ts` 示例：`use: { channel: 'chrome', headless: false, locale: 'zh-CN', baseURL: 'http://localhost:80' }`。  
- 登录复用：`test.beforeAll` 登录一次，`storageState: 'auth.json'`。  
- 菜单：侧栏 `getByText('共同富裕项目')` 或 `goto('/commonProsperity/project')`（以实际路由为准）。  
- 多图上传：对运营图 `input[type=file]` 多次 `setInputFiles` 或组件内「继续添加」至第 3 张。  
- 视频：`setInputFiles('fixtures/demo.mp4')`；按钮：`getByRole('button', { name: /新增|发布|下架|删除/ })`。

---

## 覆盖对照

| 类别 | 单元 UT | 接口 API | 界面 UI |
| --- | --- | --- | --- |
| 正常流程 | UT-014、016、018、020～021 | API-001～008、017、019、021、023～027、030、032 | UI-001～009、011、018～022、025～027、029、031～032、036、038 |
| 异常流程 | UT-005～013、015、017、019 | API-009～016、018、020、022、025、028～029、031、033～036 | UI-010、012～017、023～024、028、030、033～034、039 |
| 业务约束/矩阵 | UT-001～004、015、017、019、022 | API-020、025、028～031、034 | UI-006、021、023、028、030、033、036～037 |

---

## 功能需求追溯（自查）

| 需求章节 | 要点 | 主要对应用例 |
| --- | --- | --- |
| §5.1 新增 | 名称/类型/简介/内容/日期、运营图 1～3、视频封面选填、初始未发布 | UT-005～014；API-007～016；UI-008～018 |
| §5.2 列表 | 名称模糊、类型、发布状态、分页排序、opImageCount | API-001～006；UI-001～007 |
| §5.3 修改 | 仅未发布；替换删旧文件；不可 0 图 | UT-001、015、021；API-019～023；UI-022～026 |
| §5.4 删除 | 仅未发布；删主表+子表+存储 | UT-002、020；API-024～026；UI-032～035 |
| §5.5 详情 | 字段完整、图序、已发布只读 | API-017；UI-019～021 |
| §5.6 发布/下架 | 发布前置≥1 图；下架保留附件 | UT-003～004、016～019、022；API-027～031；UI-027～031 |
| §6 矩阵 | 五类操作权限 | UT-001～004；UI-006、021、023、028、030、033、036 |
| §7 错误约定 | code/msg 可读 | API-035；UI-039 |
| §8 App | 仅 `publishStatus=1` | API-006 |

---

## 修订记录

| 版本 | 说明 |
| --- | --- |
| 1.0 | 初版：单元 22、接口 36、UI 39；含运营图子表、视频/封面；Playwright+Chrome；Base Path `/commonProsperity/project` |
