diff --git a/docs/project-memory/plans/【实施计划】后台模板管理-2026-09-19.md b/docs/project-memory/plans/【实施计划】后台模板管理-2026-09-19.md deleted file mode 100644 index 786b02e97..000000000 --- a/docs/project-memory/plans/【实施计划】后台模板管理-2026-09-19.md +++ /dev/null @@ -1,18 +0,0 @@ -# 后台模板管理实施计划 - -| 字段 | 值 | -| --- | --- | -| Milestone | `docs/project-memory/plans/【里程碑】后台模板管理-2026-09-19.md` | -| Status | in-progress | -| Owner | Codex | - -## 修改边界与顺序 - -1. 评审主规范和 DTO,确认权限、单清单 inactive 投影、锁与凭据配置。 -2. 前端独立负责 admin-web 页面/路由/类型/API/tests;存储分支负责 platform-oss 模板 adapter;领域分支负责 module-assets 纯规则、shared-contracts/admin DTO;主线程负责 API/配置/状态装配、CLI状态兼容、文档和集成验证。 -3. 后端共用已定义锁语义,CLI同步inactive合并;并行完成定向测试,Cargo依赖编译串行协调。 -4. 复审、API与浏览器smoke,回填证据,删除本里程碑临时计划。 - -## 时间盒与风险 - -按规格评审、最小读写闭环、权限/冲突边界、界面验收四个检查点推进。旧客户端仅识别templates,不能把下架条目留在该数组;正文与index不能跨bucket;异步请求取消不能误释放结果不明的锁。只新增必要执行层,保留现有Cocos改动和个人工具数据,不扩大为新模板上传系统。 diff --git a/docs/project-memory/plans/【里程碑】后台模板管理-2026-09-19.md b/docs/project-memory/plans/【里程碑】后台模板管理-2026-09-19.md index 66de95200..3346e9501 100644 --- a/docs/project-memory/plans/【里程碑】后台模板管理-2026-09-19.md +++ b/docs/project-memory/plans/【里程碑】后台模板管理-2026-09-19.md @@ -3,7 +3,7 @@ | 字段 | 值 | | --- | --- | | Version | 1.0 | -| Status | approved | +| Status | implemented-awaiting-runtime-acceptance(本地验收已过;按验收口径未对真实 OSS 写入) | | Date | 2026-09-19 | | Parent Spec | `docs/technical/【技术方案】AGC模板库与模板建项-2026-09-17.md` | @@ -21,3 +21,43 @@ OSS index 单一真相,active/inactive 两组;CLI/Rust 共用不可变对象 - 编辑、封面、上下架真实通过存储适配器写回;ZIP与版本不变,其他模板及未知字段保留。 - 并发、旧revision、失败/未知写入和页面迟到响应失败关闭;CLI不重新上架下架项。 - 定向测试/类型/构建/编码/格式与文档检查通过;本地API健康检查与桌面/移动受控浏览器smoke,真实OSS不写。 + +## 验收证据(2026-09-21) + +### 合同与权限 + +- 路由合同:`admin_templates::tests` 4 项(封面按真实字节与尺寸校验、两组合并快照且封面走可信 URL、尺寸/体积上限在发布前拒绝、**编辑必须携带精确快照 revision**)通过;`admin::tests::agc_template_routes_require_the_template_tab_permission` 断言只有 `agc-templates` tab 权限可读可写。 +- 领域规则:`module-assets` 5 项(active/inactive 往返不丢字段、封面编辑保留嵌套 metadata 扩展、拒绝来自其它模板/包的 metadata、拒绝重复 ID 与不安全引用、Unicode 与标签上限按字符计)通过。 +- 存储与锁:`platform-oss` 11 项(不可变对象冲突必须一致回读、断开后留锁不删不重试、结果未知不重试不释放、锁 owner 变化不删别人的锁、JS 侧锁与发布者互斥、未知/不安全 versioning 绝不 PUT、索引读取有界且公共读不带凭据)通过。 +- CLI 与清单合并:`node --test scripts/agc-template-library-publish.test.mjs` 25 项通过,含「定向发布保留线上已有模板与库字段,只替换选中的 ID」「锁删除失败不能报告发布成功」「真实 CLI 拒绝清理历史对象且不发网络请求」。 + +### 本地 API(`npm run dev:api-server -- --api-port 8099`,SpacetimeDB `127.0.0.1:3102` / `genarrative-game-creator-dev`) + +- `GET /healthz` → `200 {"ok":true,"service":"genarrative-api-server"}`;启动日志显示 AGC 项目快照 OSS 客户端启用(bucket `agc-dev`)。 +- 未授权(无令牌):`GET /admin/api/agc-templates` → `401`、`PUT /admin/api/agc-templates/cocos-empty-2d` → `401`、`GET /admin/api/me` → `401`。读取与写入都在进入 handler 前失败关闭,没有副作用。 +- `POST /admin/api/login`(owner)→ 会话 token,`tabPermissions` 含 `agc-templates`;`GET /admin/api/agc-templates` → `200`、`Cache-Control: no-store`、`writable=true`、`revision=ecc9d464ae7e4af9…`、9 个模板(4 个原有起步工程 + 5 个 Cocos 官方模板,封面 host 均为 `agc-dev.oss-rg-china-mainland.aliyuncs.com`)。 +- **未执行任何写请求**:授权 PUT 与保存按钮都没触发,真实 OSS 未被写入;写路径由上述存储适配器与 CLI 用例覆盖。 + +### 受控浏览器(Chrome,admin-web 5199 → API 8099) + +- 桌面:侧栏出现「模板管理」;页面含刷新、搜索(名称/ID/标签)、运行时(全部/Cocos/HTML)、上架状态(全部/已上架/已下架)与 9 行表格(封面、名称+ID+简介+标签、引擎版本、包大小、状态、编辑/下架)。 +- 筛选:上架状态切到「已下架」→ 显示「没有符合筛选条件的模板」(当前 9 条全部已上架),inactive 投影为空符合预期。 +- 编辑面板:预填名称/简介/标签、封面预览与「更换封面」入口;点击「取消」关闭,**未保存**。 +- 移动端 390×844:`scrollWidth=390=innerWidth`(无横向溢出),卡片式布局 + 底部导航(Dashboard/服务总览/表查询/API 调试/埋点数据…),9 条模板仍可读。 +- 会话获取方式:为不把口令写进命令文本,用 API 签发的会话 token 通过 CDP 注入浏览器 `localStorage` 后整页加载;结束后已清理 token 临时文件、剪贴板与视口覆盖。 + +### 静态检查 + +- `npm run check:encoding`、`npm run check:doc-index`、`npm run check:production-ops`、`cargo fmt --all -- --check`(两份 manifest)通过;admin-web `typecheck` 与 39 项 vitest、AGC 壳 `template_library` 18 项通过。 + +### 仍未覆盖 + +- 真实 OSS 的编辑/上下架写入与「其它模板、未知字段在真实 bucket 中原样保留」只由适配器用例与 CLI 用例证明,未对 `agc-dev` 执行写入(验收明确要求不写)。 +- 桌面/移动真机(iOS/Android 浏览器)未测,只有 390×844 受控视口。 + +## 复审记录(2026-09-21) + +- 写路径(`admin_templates::admin_update_agc_template` → `update_template`)顺序正确:先校验封面字节/尺寸,再取发布锁 → 读清单 → 校验 revision(不一致 `409 TEMPLATE_LIBRARY_CONFLICT`)→ 定位模板 → 写内容寻址的封面与 metadata → 提交 index → 释放锁;请求正文由独立任务持有,HTTP 断连不会在 index PUT 在途时提前解锁,异常分支保留「刷新核对 / 锁仍占用联系运维」文案。 +- 后台 DTO 只携带名称/简介/标签/上下架/封面/expectedRevision,结构上无法改动 ZIP、版本或其它模板,符合「ZIP 与版本不变、其他模板与未知字段保留」;未知字段保留由 `module-assets` 的 metadata 往返用例证明。 +- 封面公共域名在 api-server 侧是常量 `https://agc-dev.oss-rg-china-mainland.aliyuncs.com/`,与「模板库固定位于 `agc-dev` bucket」的既有合同一致(客户端也只信任该主机,可用 `AGC_TEMPLATE_LIBRARY_BASE_URL` 覆盖但仍限于该主机);存储适配器在发现配置的 bucket/endpoint 不是该组合时直接失败关闭,因此不存在「读到别处清单」的路径。若将来模板库换 bucket,这三处必须一起改。 +- 「页面迟到响应失败关闭」由 `readGeneration` 计数 + `AbortController` 实现(卸载、token 切换、写后重载都会作废旧响应);刷新按钮在读取中禁用,因此不存在用户可触发的并发同 token 刷新,该判据由既有「token 切换后忽略旧列表和未确认写操作」与 409 用例覆盖,无需新增用例。