diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 815d8aa..d5d01b2 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -13,6 +13,13 @@ The format loosely follows Keep a Changelog and can be adapted to the team's hab - Roadmap closing wave delivered — P8 batch-2 (③ account deletion + ④ static fallback catalog) and P3 reland (backup + observability), per owner's third directive 「实现 roadmap 所有待办事项」. Sub-repo commits: crearte-server `12b8ffb` (0.15.0 — migration 0011 tombstone column; AccountService deletion kernel: password re-check, works delisted, drafts removed with best-effort object delete, pending submissions auto-rejected, sessions invalidated via token_version, email/username rewritten to `deleted-@deleted.invalid`/`gone-` so the original address is immediately reusable, sole-admin self-deletion refused 409 `last_admin` shared with the P7 demote guard; `DELETE /api/auth/account` (204/400/401/409/410, `Cache-Control: no-store`); CLI `user delete ` passwordless operator path; CLI `catalog export --out DIR [--pretty]` emitting the exact StaticContentRepository contract — `index.json` schemaVersion 2 + `games/__.json`, virtual entries carry the bundle object, external entries omit it, cover/bundle.url empty when `STORAGE_S3_*` unset; `user set-role` gets `--by-id`) and crearte `7d5f338` (0.21.0 — AccountView fourth 「危险区:注销账号」 section: password + acknowledgement checkbox gate, busy lock, success → invalidate session → home, failure → alert row; `auth/client.ts` `deleteAccount` with the code-branching `toUserMessage`; AdminUsersView now localizes validation/not_found/internal (P7 copy tail pinned by tests, `7a54152`) and the 409 last_admin echo stays on the admin side — the account view deliberately shows the generic internal copy because the auth client normalizes unknown codes to `internal` and drops the backend message; review note about `AuthApiError` vs `UserManagementApiError` shape resolved in-test). crearte-deploy `12f7c10` (0.6.0) and crearte-server `d627e12` (0.16.0) reland P3 byte-for-byte via cherry-picks `7fcfe0e`/`6ffd1ee`/`93a3c70` whose originals had drifted off master during the rollback window: prod backup tooling (`scripts/backup.sh` pg_dump + mc-mirror with retention and manifest, `restore-drill.sh` against `db-test` only, `docs/BACKUP-RUNBOOK.md`, CI dry-run leg, compose `LOG_FORMAT`/`LOG_LEVEL` passthrough) and observability (stdlib `log` → `slog` mechanical migration across 30 sites incl. the P7/P8b2-new-surface files, per-request `http_request` middleware wired outside `gin.Recovery` so panic paths log status=500, hand-rolled `/metrics` exposition with http/go/pgpool families, `/healthz`+`/metrics` double-skipped, single-instance rate-limit tradeoff documented). P3M merge commit `cecfae1` reconciled the observability branch with the P8b2 surface (CHANGELOG top order 0.16.0→0.15.0, router/serve both-side wiring). Acceptance: server container four-green + fresh real-DB `-p 1 -count=1` (skip-guard grep 0, deletion-chain + observability suites PASS) on every leg; independent reviews PASS (P3S reviewer verified byte-level identity against `6ffd1ee`/`93a3c70`; frontend review returned PASS with two minor notes, pinned before merge as `7a54152`; server-side LOG_LEVEL case-sensitivity divergence between `config.applyLogging` and `observability.newLogger` deferred as a documented nit); branch-build curl smoke 14/14 PASS (wrong-pw 401 `invalid_credentials`, missing-pw 400, sole-admin 409 `last_admin` after verifying token rotation on role change, correct-pw 204 + `no-store`, old token 401, tombstone row fields, original email re-register 201, CLI `user delete` output shape, double-delete rejected, export schemaVersion 2); live-stack metrics smoke on the merged tree (request/duration counters with `nomatch` bucket, pgpool + go families, HELP/TYPE headers, both skips, slog JSON request lines). FE vitest 512 / vue-tsc clean / main e2e 71+1skip / noauth 4. Remaining manual tail for the owner: schedule `backup.sh` (cron or the runbook's systemd timer) and run `restore-drill.sh` against the real prod stack once it is up — this host has no prod stack running, so the drill leg ran against throwaway containers only. Roadmap: P0–P8 all closed; P8 remainder is ④'s render-side consumption (on demand) and nothing else is 待启动. - 路线图收口波次交付——P8 第二批(③账号注销 + ④静态兜底目录导出)与 P3 重落(备份 + 可观测),依 owner 第三条指令「实现 roadmap 所有待办事项」。子仓提交:crearte-server `12b8ffb`(0.15.0——迁移 0011 墓碑列;AccountService 注销内核:密码复核、名下作品全部下架、草稿删除含对象 best-effort、pending 投稿自动驳回、token_version 递增废全部会话、email/username 改写为 `deleted-@deleted.invalid`/`gone-` 使原邮箱即刻可复用、唯一 admin 自拒 409 `last_admin`(与 P7 降级护栏同源);`DELETE /api/auth/account`(204/400/401/409/410,`Cache-Control: no-store`);CLI `user delete ` 免密码运维通道;CLI `catalog export --out DIR [--pretty]` 按 StaticContentRepository 契约出 `index.json`(schemaVersion 2)+ `games/__.json`,virtual 带 bundle、external 省略、未配 `STORAGE_S3_*` 时 cover/bundle.url 置空仍可浏览;`user set-role` 加 `--by-id`)与 crearte `7d5f338`(0.21.0——AccountView 第四段「危险区:注销账号」:密码 + 知晓勾选双闸门、busy 锁、成功即清会话回首页、失败出 alert 行;`auth/client.ts` 加 `deleteAccount` 并分支 `toUserMessage` 文案;AdminUsersView 补齐 validation/not_found/internal 中文化(P7 文案尾,`7a54152` 钉桩),409 原文回显留在管理侧——账号页有意展示通用 internal 文案,因 auth client 将未知码归一并丢弃后端原文;审查提出的错误类型形状问题已在测试内钉清)。crearte-deploy `12f7c10`(0.6.0)与 crearte-server `d627e12`(0.16.0)以 cherry-pick `7fcfe0e`/`6ffd1ee`/`93a3c70` 字节级重放 P3——原提交在回滚窗口脱离 master:prod 备份件(`scripts/backup.sh` pg_dump + mc-mirror + 保留策略 + manifest、`restore-drill.sh` 只连 `db-test`、`docs/BACKUP-RUNBOOK.md`、CI dry-run 腿、compose 透传 `LOG_FORMAT`/`LOG_LEVEL`)与可观测(stdlib `log` 机械迁 `slog` 共 30 处含 P7/P8b2 新面、每请求 `http_request` 中间件挂在 `gin.Recovery` 外层使 panic 路径记 status=500、手写 `/metrics` 出 http/go/pgpool 三族、`/healthz` 与 `/metrics` 双跳过、限流单实例权衡入档)。P3M 合流提交 `cecfae1` 把可观测分支与 P8b2 面调和(CHANGELOG 顶序 0.16.0→0.15.0、router/serve 双侧接线保留)。验收:每腿容器四连绿 + 全新真库 `-p 1 -count=1`(skip 守卫 grep 0,注销链与 observability 套件 PASS);独立审查 PASS(P3S 审查员逐文件对 `6ffd1ee`/`93a3c70` 核到字节级一致;前端审查 PASS with notes——两条次要已合主前钉桩 `7a54152`;server 侧 `config.applyLogging` 与 `observability.newLogger` 的 LOG_LEVEL 大小写策略不一致按次要 deferred);分支真产物 curl 冒烟 14/14 PASS(错密码 401 `invalid_credentials`、缺密码 400、角色变更后先验 token 轮换再证唯一 admin 409 `last_admin`、对密码 204 + `no-store`、旧 token 401、墓碑行字段、原邮箱重注册 201、CLI `user delete` 输出形状、二次注销被拒、导出 schemaVersion 2);合主树实栈 metrics 冒烟(请求/耗时计数含 `nomatch` 桶、pgpool 与 go 族、HELP/TYPE 头、双跳过、slog JSON 请求行)。FE vitest 512 / vue-tsc 零错 / 主 e2e 71+1skip / noauth 4。留给 owner 的手动尾巴:按 runbook 给 `backup.sh` 排定时(cron 或 systemd timer),并在真 prod 栈起来后跑一次 `restore-drill.sh`——本机无 prod 栈在跑,演练腿只对一次性容器做过。路线图:P0–P8 全部闭合;P8 仅剩④的 render 端消费(按需),无待启动项。 +## [0.3.1] - 2026-10-01 + +### Done / 完成 + +- P9 UX batch-1 (browser feedback pack) delivered: crearte `26cd625` (0.22.0 — two-phase router-level `document.title`: `afterEach` static baseline over the full 19-name route table + refinement watches on exactly four data pages (game/catalog/docs/author), home deliberately kept as the bare `crearte 创艺` string so the existing e2e pin never moved; game-page `meta description` with 120-codepoint clipping, DEFAULT fallback and per-navigation reset back to default (review ISSUE-1 patched pre-merge, pinned by a router test); `StatePanel` skeletons honest at last — card variant 3→6 (≥1.5 rows at each 2/3/4-column breakpoint), new `lines` variant on the six non-grid consumers (eight instances incl. AdminView ×3), index.html gains the default description meta). Zero server/deploy changes. Acceptance: vitest 551 (baseline 512 + 39 new) / vue-tsc clean / build OK / main e2e 72+1skip incl. a new title leg / noauth 4. Independent review PASS with notes — ISSUE-1 (leave-game description not restored, spec D-C sub-clause) and ISSUE-2 (spec §1 said "seven non-grid pages", CreatorCenterView does not consume StatePanel — count is six; wording fixed in spec and changelog) both resolved before merge. B (keyboard/skip-link/mobile header) and C (dark mode) batches parked pending owner go-ahead. +- P9 UX 第一批(浏览器反馈包)交付:crearte `26cd625`(0.22.0——两段式路由级 `document.title`:`afterEach` 按 19 个路由名全表设静态基线 + 恰好四个数据页(作品/目录/文档/作者)watch 精化;home 有意保持裸 `crearte 创艺` 整串,既有 e2e 钉桩一字未动;作品页 `meta description` 截 120 码点、默认回落、每次导航复位(审查 ISSUE-1 合主前补钉并以 router 测试钉桩);`StatePanel` 骨架终诚实——cards 变体 3→6(2/3/4 列断点各≥1.5 行)、新增 `lines` 变体给六个非网格消费页(八实例含 AdminView×3);index.html 补默认 description)。server/deploy 零改动。验收:vitest 551(基线 512+新增 39)/ vue-tsc 零错 / build OK / 主 e2e 72+1skip(含新增标题腿)/ noauth 4。独立审查 PASS with notes——ISSUE-1(离开作品页 description 未恢复默认,spec D-C 子项)与 ISSUE-2(spec §1 写「7 个非网格页」,实际 CreatorCenterView 不消费 StatePanel,应为六个;spec 与 CHANGELOG 措辞已修正)均合主前处置。B(键盘/skip-link/移动端页头)与 C(暗色模式)两批挂账待 owner 发令。 + ## [0.2.9] - 2026-10-01 ### Chores / 杂务 diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 4868c5d..4a0e335 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -34,7 +34,7 @@ |---|--------|------|------| | P7 | 管理后台增强 | 用户列表 / 角色管理 UI(替代 CLI `user set-role`)+ 审计日志 | **完成**(server `ca24805` 0.12.0 / crearte `900f13a` 0.18.0,2026-09-30 合并推送。audit_log 表 0010 + 组中间件统一记录(owner 定稿:admin 路由收敛为组,Full-Path 模板入史,GET 也记,失败尝试照记,未遂 401/403 不记);用户列表/PATCH 角色/审计查询三端点;唯一 admin 降级 409 护栏 CLI/API 双覆盖;前端 /admin/users + /admin/audit 两页,降级确认双要点文案;本机六腿验收全绿:容器四连+fresh-DB `-count=1` 10 ok 零 FAIL 零 skip、废 token 端到端 401、护栏矩阵(非唯一降 OK/唯一降 CLI 拒+API 409)、审计流水含 409 失败尝试、真栈 full-loop 分支后端 1 passed×2、vitest 488/typecheck/admin-flow 6/主套件 68) | | P8 | 长尾打包 | 权限开关 UI 全量(`inlineStyle/wasm/coop/fullscreen/gamepad`)、后端 triage 小项(`games.Detail` 400 细分、admin 路由 slug 校验、approve 同名竞态测试)、账号注销、静态兜底目录、CHANGELOG 模板文案 | **第一批完成**(②⑤①,2026-10-01 合并推送:server `921443a` 0.14.0 / crearte `70ba10c` 0.20.0。容器四连+空库 `-count=1` 集成全绿(新竞态测试含,skip 守卫 0)+`-race` 竞态腿 PASS;curl 冒烟全中:detail 400 细分 user:/slug: 且双非法 user 优先、admin 四路非法 400 `invalid work id`、合法格式不存在仍 404;FE vitest 499/typecheck/admin-flow 7/主套件 70+1skip;双审 PASS(server PASS with notes—唯一 note 双非法优先级缺钉桩,已以 `ee5b960` 测试断言补上);deploy 零改动。**第二批完成(③账号注销+④静态兜底目录)**(2026-10-01 合并推送:server `12b8ffb` 0.15.0(迁移 0011 墓碑化删行、DELETE /api/auth/account 对密码注销、唯一 admin 409、user delete CLI、catalog export 出 schemaVersion=2 目录)+ crearte `7d5f338` 0.21.0(/account 危险区+deleteAccount 客户端+AdminUsersView 三码中文化钉桩)+。真库注销链集成+分支真产物 curl 冒烟 14 项全 PASS(墓碑行/邮箱复用/409/旧 token 作废/CLI delete/export schema);FE vitest 512/typecheck/主套件 71+1skip/noauth 4,双审 PASS with notes(前端 2 条次要已钉桩 `7a54152`,server 裁决项:LOG_LEVEL 大小写不一致—deferred)。余 ④的 render 消费端接入按需(feed 已交付)**,CHANGELOG 头部去模板腔两仓已随第一批完成、wrapper 头部不在 spec 范围 | -| P9 | UX 增强(第一批:浏览器反馈包) | 路由级 `document.title` 两段式(router `afterEach` 按 19 个 name 全表设静态基线 + 四个数据页 watch 数据后精化)+ 作品页 `meta description`(截 120 码点、默认回落)+ `StatePanel` 骨架对齐(cards 3→6 张、新增 `lines` 变体六页八实例)。零后端/部署改动 | **第一批实现完成(待验收)**(crearte 分支 `feat/p9-ux-titles`,`a196603`+`3f1de38`,2026-10-01;五腿:vitest 550 / vue-tsc 0 / build OK / 主套件 72+1skip / noauth 4。B 效率可访问 / C 暗色模式批次挂账) | +| P9 | UX 增强(第一批:浏览器反馈包) | 路由级 `document.title` 两段式(router `afterEach` 按 19 个 name 全表设静态基线 + 四个数据页 watch 数据后精化)+ 作品页 `meta description`(截 120 码点、默认回落)+ `StatePanel` 骨架对齐(cards 3→6 张、新增 `lines` 变体六页八实例)。零后端/部署改动 | **第一批完成**(2026-10-01 合并推送:crearte `26cd625` 0.22.0(`a196603`+`3f1de38`+审查补钉 `e9e4c56`)。五腿全绿:vitest **551**(基线 512+新增 39)/ vue-tsc 零错 / build OK / 主套件 72+1skip(含新增标题 e2e 腿,`landing.spec.ts` 首条兼容钉一字未动)/ noauth 4。独立审查 PASS with notes:ISSUE-1(离开作品页 description 未回落默认,spec D-C 子项)与 ISSUE-2(「七页」实为六页文案)均已在合主前补钉+补测。B 效率可访问 / C 暗色模式两批挂账待启动) | ## 排序理由 @@ -61,4 +61,4 @@ | P7 管理后台增强 | `docs/specs/2026-09-30-admin-console-design.md` | `docs/plans/2026-09-30-admin-console.md`(已执行,2026-09-30) | | P8 长尾打包(第一批:②⑤①) | `docs/specs/2026-10-01-p8-long-tail-design.md` | `docs/plans/2026-10-01-p8-long-tail.md`(第一批已执行,2026-10-01) | | P8 长尾打包(第二批:③④) | `docs/specs/2026-10-01-p8b2-deletion-catalog-design.md` | `docs/plans/2026-10-01-p8b2-account-catalog.md`(已执行,2026-10-01:server 0.15.0 / crearte 0.21.0) | -| P9 UX 第一批(浏览器反馈包) | `docs/specs/2026-10-01-p9-ux-browser-feedback-design.md` | `docs/plans/2026-10-01-p9-ux-browser-feedback.md`(第一批实现完成,待验收,2026-10-01:crearte `a196603`+`3f1de38`) | +| P9 UX 第一批(浏览器反馈包) | `docs/specs/2026-10-01-p9-ux-browser-feedback-design.md` | `docs/plans/2026-10-01-p9-ux-browser-feedback.md`(第一批已执行,2026-10-01:crearte 0.22.0) | diff --git a/docs/specs/2026-10-01-p9-ux-browser-feedback-design.md b/docs/specs/2026-10-01-p9-ux-browser-feedback-design.md index c9202b1..3544dba 100644 --- a/docs/specs/2026-10-01-p9-ux-browser-feedback-design.md +++ b/docs/specs/2026-10-01-p9-ux-browser-feedback-design.md @@ -11,7 +11,7 @@ - `document.title` 全站无人设置:任何页面浏览器标签恒为 `index.html:10` 的 `crearte 创艺`(`grep -rn "document.title" app/` 零命中)。 - `index.html` 无 `meta name=description`。 - `e2e/landing.spec.ts:6` 钉住 home 标题**恰为** `crearte 创艺` —— home 无后缀既是现状也是本设计的兼容约束。 -- `StatePanel.vue` 骨架 `v-for="n in 3"`,网格消费页实际 `sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4`(CatalogView:70、LandingView:62、AuthorView:36);骨架的游戏卡形状还被 7 个非网格页复用(Docs、Admin、AdminUsers、AdminAudit、SubmitList、CreatorCenter、Game 详情),加载瞬间显示的是「不存在的卡片」。 +- `StatePanel.vue` 骨架 `v-for="n in 3"`,网格消费页实际 `sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4`(CatalogView:70、LandingView:62、AuthorView:36);骨架的游戏卡形状还被 6 个非网格页复用(Docs、Admin、AdminUsers、AdminAudit、SubmitList、Game 详情;AdminView 内 3 实例共 8 实例。初稿误写 7 个含 CreatorCenter——审查 ISSUE-2 复核其不消费 StatePanel,已按实修正),加载瞬间显示的是「不存在的卡片」。 - 数据面锚点:`GameView` 有 `game.name/description`(`data/types.ts` Game extends GameSummary,description 可选);`CatalogView` 经 `useFilterState` 持 `state.q`(route.query 派生,天然响应);`DocsView` 有 `doc?.title`;`AuthorView` 有 works 列表→`authorDisplayName()`(labels.ts:21)与 `props.user` 兜底。 - 路由 19 个 name(router/index.ts),其中 8 个纯静态(login/register/account/creator/outbound/admin*/submit*)无数据精化需求。 @@ -21,8 +21,8 @@ |---|------|------|--------------| | D-A | title 所有权 | **两段式**:router `afterEach` 按路由名设静态基线;4 个数据页(game/catalog/docs/author)watch 数据后精化覆盖 | 游戏名/文档名是异步数据,纯 `meta.title` 方案拿不到;纯 watch 方案则导航瞬间标签页还是旧题。放弃全站 meta 表驱动。 | | D-B | home 标题 | 保持恰为 `crearte 创艺`(无后缀);其余页 `段 · crearte 创艺` | 不破坏 `landing.spec.ts:6` 既有钉桩与用户书签;也是品牌页的合理特例。 | -| D-C | description 范围 | **仅作品详情页**写 `game.description`(截 120 码点;缺省回落默认文案),离开该页恢复 index.html 默认 | SEO 增益主要落在可分享的作品页;全站 per-page description 属 YAGNI(SPA、无抓取压力)。 | -| D-D | 骨架策略 | cards 变体 **6 张**(3→6,覆盖 2/3/4 列断点各≥1.5 行);新增 `variant="lines"`(3 行横线、无封面纵横比结构)给 7 个非网格消费页 | 行数固定 6 而非按视口动态生成:列数已由 CSS 断点处理,JS 测视口属过度工程。放弃「所有页维持游戏卡」。 | +| D-C | description 范围 | **仅作品详情页**写 `game.description`(截 120 码点;缺省回落默认文案),离开该页恢复 index.html 默认(实现:router `afterEach` 每导航先 `setPageDescription('')` 回落,game 页再由 watch 精化——审查 ISSUE-1 补钉,router/index.test.ts 钉桩) | SEO 增益主要落在可分享的作品页;全站 per-page description 属 YAGNI(SPA、无抓取压力)。 | +| D-D | 骨架策略 | cards 变体 **6 张**(3→6,覆盖 2/3/4 列断点各≥1.5 行);新增 `variant="lines"`(3 行横线、无封面纵横比结构)给 6 个非网格消费页(共 8 实例) | 行数固定 6 而非按视口动态生成:列数已由 CSS 断点处理,JS 测视口属过度工程。放弃「所有页维持游戏卡」。 | | D-E | 仓库面 | 纯 crearte 前端;server/deploy 零改动;版本 0.22.0 | 全部为客户端 DOM 写操作。 | ## 3. 设计