Files
aurora-admin/ROADMAP.md
T
aurora-admin e13049f5b9
Deploy to GitHub Pages / deploy (push) Failing after 2m30s
Regression / regression (push) Failing after 2m2s
feat(P5): 暗色模式真正实现(令牌31/对比度全过/10页实测/DARK32/预算292KB/回归1003)
2026-09-14 02:38:35 +08:00

46 KiB
Raw Blame History

Aurora Admin · 长期路线图与任务包

文档性质:交给执行模型的工程规划。每个任务包自带验收命令与失败判据,拿到即可开工,不需要再问。 基线版本:v1.4.1(2026-09-11) 规划人:海鸥(规划师角色) 更新约定:任务完成时在本文件对应任务包下追加 ✅ 完成于 <commit>,不要删原计划。


〇 · 交接约定(执行模型必读)

0.1 铁律(违反即返工)

  1. 零运行时依赖不可破:不引入 npm 运行时依赖。构建/测试脚本用 Node 内置能力或 PowerShell。package.json 的 dependencies 必须为空(devDependencies 可用)。
  2. build-site.ps1 必须 ASCII-only:PS5.1 按 ANSI 读无 BOM 文件,脚本里出现非 ASCII 字面量会被损坏。中文文案放 UTF-8 模板。
  3. 改结构要改模板:tests/<slug>.html 是生成物 —— 改它没用。改 tests/_template.html / tests/_index_template.html 后重跑 run-tests.ps1。
  4. 改样式要改内嵌层:演示页的内嵌 <style> 才是实际生效的样式(v1.4.0 教训:只改 frameworks/*.css 可能不生效,因为演示页不一定 link 它)。
  5. data.json 是 For Agents 的对外承诺:可以拆 data.js,但 data.json 必须保持完整(一次请求拿到全部)。破坏它是 breaking change。
  6. 单次改动后必须跑回归:tests/_collect.html 八次连跑,100% / 0 失败 / 0 超时 才算过。

0.2 禁止事项(做过即需回滚)

禁止 原因 正确做法
在 frameworks/ 里直接手工改出"更好看"的样式 frameworks/ 是规范原文的忠实实现,改动会破坏契约一致性 要改样式先改令牌,或走任务包流程
用 git reset --hard / git checkout . 清理 会丢用户改动 用 git stash 或定向还原
删除或改写 CHANGELOG.md 的历史条目 那是变更事实记录 只追加 [Unreleased] 或新版本段
修改 tests/report.json 的数值来"通过"验收 报告是生成物,改它等于伪造证据 修实际问题后重跑生成
为了通过验收而放宽断言判据 v1.3.1 曾出现"调松断言刷分"的诱惑 断言判据的修正必须附理由 + 反例
在规划未涉及的领域顺手重构 范围蔓延会让验收失焦 写成新任务包追加到本文件

0.3 环境与工具

项 说明
操作系统 Windows(开发)/ Linux(CI)。跨平台写法见下方「跨平台注意」
Shell Git Bash(开发)/ bash(CI)
Node ≥ 18(用到 node:sqlite 的任务需 ≥ 22)
构建 powershell -NoProfile -ExecutionPolicy Bypass -File build-site.ps1(Windows 专用)
回归 浏览器打开 tests/_collect.html,或 node tools/run-regression.mjs(需 playwright)
本地服务 node site/dev-server.js(端口 3311)

跨平台注意:

  • 后台启动服务:Windows Git Bash 用 node site/dev-server.js &,CI 用 node site/dev-server.js & sleep 3。不要用 start 或 nohup。
  • 路径分隔符:脚本里统一用 POSIX 风格(/),Node 的 path 模块会处理。
  • PowerShell 脚本只能在 Windows 跑。若 CI 需要构建,改写为 Node 脚本或加 runs-on: windows-latest。

0.4 失败升级路径

执行中遇到阻塞时,按这个顺序处理,不要停下来等:

情况 处理
验收命令本身有错(路径不对、语法不兼容) 修正命令使其能真实反映目标,在交付说明里写明修正了什么、为什么
目标不可达(如依赖的服务/网络不可用) 交付最强替代物 + 写明缺什么。例:无法 npm pack 则做本地 npm pack --dry-run 的等价检查
发现规划有事实错误(如"某字段占 89%"实际不是) 以实测为准,修正规划并在本文件标注「⚠️ 规划修正」
发现规划未覆盖的新缺口 写成新任务包追加到本文件,不在原任务里顺手修
连续两次尝试同一路径都失败 换策略而非重试。在交付说明里记录两次失败的原因

0.5 交付说明模板(每个任务包完成时提交)

## <任务 ID> 完成说明

**验收输出**(原样粘贴命令输出,不要转述):

<命令> <输出>


**改动文件**:
- <路径> — <做了什么>

**规划偏差**(若有):
- <规划里写的> → <实际的>,原因:<...>

**发现的新问题**(若有):
- <描述> → 已追加为任务包 <ID>

**回归**:100%(<总断言>/<通过>)/ 八次连跑一致 / 0 超时

一 · 现状基线(全部为实测数据)

1.1 资产规模

项 数量 测量方式
组件 79 components/index.json
5 端实现文件 395 ls frameworks/*.{html,css,jsx,vue2.vue,vue3.vue} 各 79
契约 JSON 79(全量) ls .design_library/aurora-admin/components/*.json
契约 usageHints 358 条 遍历契约累加
契约 unknowns 139 条 同上(现成的 FAQ 素材)
契约 doNotInvent 101 条 同上
设计令牌 75 个 site/data.json → tokens.length
i18n 字典 330 条 site/i18n.js
测试断言 961 条(12.2/页) tests/report.json
文档站路由 9 个 home/overview/guide/design/changelog/agents/component/scenario/tests

1.2 质量指标

项 值 说明
回归通过率 100% 八次连跑一致,0 失败 0 超时
N/A 断言 36(3.7%) 静态组件无交互面、单实例组件无多变体,已逐条核实
契约保真度 93.9% 逐字命中规格 余 22 条为同义改写,非发明
令牌语义错配 0 / 1313 处 属性与令牌角色全部匹配
i18n 质量 0 残留中文、0 未翻译 326 条字典
组件可换肤 79/79 逐组件改令牌比对样式签名

1.3 性能基线

指标 值 说明
文档站传输量 1247 KB 7 个资源
其中 data.js 1058 KB(85%) ← 最大优化目标
app.js 101 KB 未压缩
style.css 40 KB 未压缩
DOMContentLoaded 345 ms 本地 dev-server,线上更慢
每详情页额外 iframe 1 个 加载对应演示页

1.4 实测缺口(按严重度)

# 缺口 实测证据 影响
G1 无 LICENSE ls LICENSE → 不存在 法律上不可用,对外交付的硬阻塞
G2 无分发机制 无 package.json / 无 CDN / 无发布流程 用户拿不到,只能 clone 仓库
G3 CI 无测试 .github/workflows/ 只有 deploy-pages.yml 回归靠手动,质量无持续保障
G4 暗色模式是假的 令牌层 aa-dark 规则 0 条、组件层 0 条、仅站点骨架 7 条 CHANGELOG 曾称"补全",实为第 6 次声称≠实现
G5 跨端一致性无验证 5 端 395 文件,无任何自动比对 H5/React/Vue2/Vue3 视觉是否一致无从知晓
G6 data.js 1MB 占传输量 85% 首屏慢,移动端更差
G7 RTL 未支持 逻辑属性 0 处 / 物理属性 22 文件 阿拉伯语等市场不可用
G8 断言偏结构 12 项/页,多为"元素存在",无"点击后发生什么" 行为回归无覆盖

二 · 长期愿景与阶段划分

2.1 目标状态(12 个月)

一句话:从「一个做得很完整的组件库仓库」,变成「一个能被外部团队直接采用的设计系统产品」。

拆成四个可验证的终态:

  1. 可交付 —— 有许可证、有分发渠道、有 CI 保障,外部团队 5 分钟内能用上。
  2. 可信 —— 关键声称(暗色、跨端一致、无障碍)全部有自动化证据,不靠文档承诺。
  3. 完整 —— 覆盖国际化(含 RTL)、无障碍实测、性能预算。
  4. 生态 —— 设计工具链打通(Figma)、典型页面可直接复用、有版本发布节奏。

2.2 阶段划分与决策依据

阶段 主题 解决 决策依据
S1 可交付 G1 G2 G3 G6 前三个是对外交付的硬阻塞:没许可证不能商用,没分发拿不到,没 CI 质量会退化。G6 顺手做(data.js 占 85% 传输量,收益最大)
S2 可信 G4 G5 G8 都是「声称了但没证据」。G4 是第 6 次声称≠实现,必须先止血
S3 完整 G7 + 无障碍实测 RTL 与无障碍是竞品 7 家里的分水岭(3 家有 RTL)
S4 生态 Figma/模板/发布 前两阶段完成后,生态建设才有意义

为什么这个顺序:S1 是"能不能用",S2 是"能不能信",S3 是"够不够全",S4 是"好不好用"。顺序颠倒会做出没人敢用的产品。


三 · 任务包

格式:目标 → 依据 → 依赖 → 路径 → 步骤 → 验收 → 失败判据 每个任务包独立可执行,除标注依赖外互不阻塞。


S1-P1 · LICENSE 许可证 | 预算 ~10 min | 优先级 P0

目标:仓库根目录存在 LICENSE,明确授权范围,移除对外交付的法律阻塞。

依据:G1。CONTRIBUTING.md 与 README.md 都在讲如何贡献与使用,但没有许可证意味着默认保留所有权利,外部团队法务不会放行。

依赖:无。需用户确认许可证类型(见下方决策点)。

路径:LICENSE(新建)

步骤:

  1. 确认许可证类型。若用户未指定,默认 MIT(与本项目"零依赖、鼓励复用"的定位一致),并在交付说明里标注"如需变更请告知"。
  2. 写入标准 MIT 全文,版权行为 Copyright (c) 2026 Aurora Admin。
  3. 在 README.md 增加 ## 许可证 段,链接到 LICENSE。
  4. 在 CHANGELOG.md 的 [Unreleased] 下追加 ### Added — LICENSE。

验收:

# 文件存在且包含关键条款
test -f LICENSE && grep -q "MIT License" LICENSE && grep -q "WITHOUT WARRANTY" LICENSE && echo "LICENSE OK"

# README 有链接
grep -q "LICENSE" README.md && echo "README OK"

预期输出:

LICENSE OK
README OK

失败判据:任一条命令无输出,或 LICENSE 里出现非标准条款(自行增删免责声明)。

决策点(需用户输入):许可证类型。MIT 是默认推荐;若项目未来要商业化或要求衍生作品开源,应改 Apache-2.0 或 MPL-2.0。

✅ 完成(MIT,采用默认选择) — 验收输出:

LICENSE OK
README OK

同步改动:LICENSE(MIT 全文)、README.md(新增「许可证」段 + 版本号更新为 v1.4.1 + 指向本路线图)。 如需改为 Apache-2.0 / MPL-2.0:替换 LICENSE 全文,同步 README.md 与未来 package.json 的 license 字段即可,无其他联动。


S1-P2 · npm 分发 | 预算 ~2 h | 优先级 P0

目标:npm install aurora-admin-design 能拿到令牌 + 组件样式;<link> 可直接引 CDN。

依据:G2。当前用户只能 clone 整个仓库(5.1MB git + 2.6MB site),对"只想用几个组件"的人成本过高。

前置验证已完成(规划阶段实测):

假设 结果
npm 可用 ✅ v11.17.0
包名 aurora-admin-design 是否被占用 ✅ 未被占用(registry 返回 {"error":"Not found"})
colors_and_type.css 可否直接作 dist 令牌源 ✅ 含 :root、75 个令牌,可直接用
零依赖约束下能否构建 dist ✅ Node 内置能力足够(读写文件 + JSON)

依赖:S1-P1(package.json 需声明 license 字段)。

路径:

  • package.json(新建)
  • .npmignore(新建)
  • tools/build-dist.mjs(新建,产出分发产物)
  • dist/(构建产物,加入 .gitignore)

步骤:

  1. 建 package.json,关键字段:
    {
      "name": "aurora-admin-design",
      "version": "1.4.1",
      "description": "B 端中后台设计系统 · 79 组件 × 5 端 · 零运行时依赖",
      "license": "MIT",
      "main": "dist/tokens/tokens.css",
      "files": ["dist/", "README.md", "LICENSE"],
      "scripts": {
        "build": "node tools/build-dist.mjs",
        "test": "node tools/verify-dist.mjs"
      },
      "keywords": ["design-system", "admin", "css-variables", "design-tokens"],
      "sideEffects": ["*.css"]
    }
    
    注意:不声明任何 dependencies —— 这是硬约束。
  2. 写 tools/build-dist.mjs(Node ESM,零依赖),产出:
    • dist/tokens/tokens.css、tokens.json(复用 build-site.ps1 的产出)
    • dist/components/<slug>.css × 79 + dist/components/index.css(聚合)
    • dist/components/<slug>.html × 79(静态演示)
    • dist/README.md(用法速查,从主 README 节选)
    • dist/manifest.json(组件清单 + 版本 + 文件校验和)
  3. 写 .npmignore 排除 site/、tests/、frameworks/*.jsx|vue*、.github/、*.png。
  4. 在 README.md 增加「安装」段,给出 npm / CDN / 直接下载三种方式。

验收:

# 1) 构建产物齐全
node tools/build-dist.mjs
test -f dist/tokens/tokens.css && echo "tokens OK"
test -f dist/components/index.css && echo "aggregate OK"
test $(ls dist/components/*.css | wc -l) -ge 80 && echo "79 components + index OK"

# 2) 无运行时依赖(硬约束)
node -e "const p=require('./package.json'); if(p.dependencies) { console.error('FAIL: 不允许 dependencies'); process.exit(1) } console.log('zero-dep OK')"

# 3) 分发内容不含开发资产
# 注意:不能用 `npm pack | grep -q site/ && echo FAIL || echo OK` —— npm 不可用时 grep 也失败,会误报 OK
if npm pack --dry-run >/tmp/pack.txt 2>&1; then
  if grep -qE "site/|tests/" /tmp/pack.txt; then
    echo "FAIL: 打包含开发资产"; grep -E "site/|tests/" /tmp/pack.txt | head -3; exit 1
  fi
  echo "pack contents OK"
else
  echo "SKIP: npm 不可用(网络/未安装),此项需在有 npm 的环境补验"
fi

# 4) 产物可用(起本地服务,浏览器打开验证)
node -e "const fs=require('fs');const c=fs.readFileSync('dist/components/index.css','utf8');if(!c.includes('--au-color-brand'))process.exit(1);console.log('css usable OK')"

预期输出:

tokens OK
aggregate OK
79 components + index OK
zero-dep OK
pack contents OK
css usable OK

失败判据:

  • package.json 出现任何 dependencies
  • npm pack --dry-run 输出含 site/ 或 tests/
  • dist/components/*.css 少于 80 个

已知风险:npm pack 需要网络(首次可能要求登录)。若无网络,跳过第 3 条验收并在交付说明注明。


S1-P3 · CI 回归流水线 | 预算 ~1.5 h | 优先级 P0

目标:每次 push/PR 自动跑回归,失败则阻止合并;结果可在 GitHub Actions 页面看到。

依据:G3。当前只有部署 workflow,回归靠人工手动跑 _collect.html,质量随提交退化不可见。

依赖:无(可与 P1/P2 并行)。

路径:

  • .github/workflows/regression.yml(新建)
  • tools/run-regression.mjs(已存在,需改造为无网可用)

步骤:

  1. 现状:tools/run-regression.mjs 依赖 playwright(npm 包),与"零依赖"约束冲突。 解法:CI 里允许用 npx playwright(CI 环境的临时工具,不进 package.json 的 dependencies),或用 devDependencies + 在文档说明"CI 专用,运行时不依赖"。 推荐:把 playwright 放进 devDependencies(这是构建期工具,不违反"零运行时依赖")。
  2. 写 workflow:
    name: Regression
    on: [push, pull_request]
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - uses: actions/setup-node@v4
            with: { node-version: '20' }
          - run: npm i -D playwright && npx playwright install --with-deps chromium
          - run: node site/dev-server.js &
          - run: sleep 3
          - run: node tools/run-regression.mjs
          - uses: actions/upload-artifact@v4
            if: always()
            with: { name: regression-report, path: tests/report*.json }
    
  3. run-regression.mjs 需改造:目前是纯 Node 脚本,要确保它在 Linux 下也能找到报告输出路径(Windows 路径分隔符问题)。
  4. 增加失败阈值:passRate < 100 时 process.exit(1)。

验收:

# 本地模拟 CI 步骤
node site/dev-server.js & sleep 3
node tools/run-regression.mjs
echo "exit=$?"
# 期望 exit=0 且 passRate=100

推送后在 GitHub Actions 页面确认 workflow 跑绿(需用户操作)。

预期输出:

passRate 100% | pages 79 (all-pass 79) | assertions 925/925
written: tests/report.json, tests/report-junit.xml
exit=0

失败判据:

  • workflow 文件语法错误(用 actionlint 或 GitHub 页面报错验证)
  • 本地模拟跑出 exit != 0
  • passRate < 100 时没有 exit 1

已知风险:playwright install 在 CI 上约需 1-2 分钟,可通过缓存加速(后续优化项)。


S1-P4 · data.js 瘦身 | 预算 ~3 h | 优先级 P0

目标:site/data.js 从 991 KB 降到 < 150 KB(实测可达成 ~110 KB)。

依据:G6。实测 data.js = 1058 KB(传输量),占文档站总传输 85%。

已完成的诊断(无需重做):

data.json 体积构成(实测)
  总计: 991KB
  components   974KB  98.3%   ← 唯一大头
  changelog     12KB   1.2%
  tokens         5KB   0.5%

components[] 内部(单组件)
  .sources     15.7KB  ← 5 端源码全文
  .contract     0.8KB
  .specLines    0.2KB
  .files        0.2KB
  其余          <0.1KB

全部组件 .sources 合计: 888KB(占 data.json 的 89.6%)

结论:sources 字段(5 端源码全文,仅供详情页代码区展示)占了 89.6%。把它移出 data.js 改为按需 fetch,data.js 降到 ~110 KB(−89%)。

依赖:无。

路径:

  • build-site.ps1(改造产出:分文件写源码)
  • site/app.js(改造消费:按需 fetch + loading 态)
  • site/sources/<slug>/<kind>.txt(新增产出目录,79 × 5 = 395 个文件)
  • site/data.js / site/data.json(产出物,不手改)

步骤:

  1. 改造 build-site.ps1:
    • 新增:把每个组件的 5 端源码写到 site/sources/<slug>/<kind>.txt(kind ∈ html/css/jsx/vue2/vue3)
    • 修改:data.js 里 components[].sources 改为 sourcesRef: "sources/<slug>/"(只留路径,不留内容)
    • 保持 data.json 完整(For Agents 页承诺"一次请求拿到全部",不能破坏 —— 这是硬约束)
  2. 改造 app.js(见下方「已完成的依赖分析」)
  3. 验证 For Agents 承诺未破:data.json 仍然包含完整 sources。
已完成的依赖分析(执行前必读)

app.js 里有 10 处消费 c.sources,分三类,改造难度不同:

类别 A · 渲染期同步解析(难点,2 处)

位置 函数 用途
app.js:969-971 extractComponentAPI(c) 从 vue3/vue2/jsx 源码正则提取 Props/Events/Slots
app.js:1544 extractScenarios(c) 从 html 源码提取 <h2> 场景标题

这两个函数在渲染详情页时同步调用,依赖源码字符串立即可用。改成 fetch 后必须处理异步。

推荐解法:把「源码解析」的产物预计算进 data.js,而不是运行时 fetch 后再解析。

  • build-site.ps1 已经能读源码 → 顺手把 extractComponentAPI / extractScenarios 的结果写进 data.js
  • app.js 改为直接读预计算结果,这两个函数不再需要源码
  • 源码 fetch 只服务「代码展示」这一处需求

体积成本已实测(规划阶段验证过):

API 表(79 组件)     : 0.2 KB
场景标题(79 组件)   : 0.9 KB
合计新增              : 1.0 KB
sources 移除后节省    : 888 KB
净减少                : 887 KB

预计算产物只占 1 KB(原估 < 30KB,实测乐观 30 倍),代价可忽略。

这样做的好处:① 消除两处异步改造;② 解析逻辑从浏览器移到构建期(更快);③ 详情页首屏不再等源码下载。

类别 B · 代码展示(3 处,易改)

位置 用途
app.js:1635 Playground textarea 初值
app.js:1667 Playground 复位
app.js:1714/1722 代码区高亮渲染

改法:进详情页时 Promise.all 拉当前组件 5 个源码文件(或按需拉 tab 切换的那一个),拿到后填充。加 loading 占位。

类别 C · 判断可用性(2 处,用元数据替代)

位置 用途
app.js:1703-1704 判断哪些端有源码(决定 tab 显示)
app.js:1720 复制按钮取当前 tab 源码

改法:data.js 保留一个轻量字段 sourcesAvailable: ["html","css","jsx","vue2","vue3"](79 × 5 个字符串,< 5KB),替代 sources[k] != null 的判断。复制按钮改为从已缓存的 fetch 结果取。

分阶段执行建议
  1. 阶段 1:build-site.ps1 预计算 API/场景 → 写入 data.js;app.js 改读预计算结果。此时 sources 仍完整(先不瘦身),跑回归确认无回退。
  2. 阶段 2:build-site.ps1 分离源码到文件 + data.js 只留 sourcesRef 与 sourcesAvailable;app.js 改 fetch。
  3. 阶段 3:跑验收 + 浏览器实测(含断网兜底)。

验收:

# 1) 体积达标(实测应约 110KB)
node -e "
const fs=require('fs');
const core=fs.statSync('site/data.js').size;
console.log('data.js:', (core/1024).toFixed(0)+'KB');
if(core/1024 > 150) { console.error('FAIL: 超过 150KB 预算'); process.exit(1) }
console.log('budget OK');
"

# 2) 源码文件已分离(395 个)
# 注意:目录未创建时 ls 会报错到 stderr,这里显式兜底,让输出可读
n=$(ls site/sources/*/*.txt 2>/dev/null | wc -l)
echo "sources files: $n (期望 395)"
if [ "$n" -ne 395 ]; then
  echo "FAIL: 期望 395 个源码文件,实际 $n"
  echo "  提示:若目录不存在,说明 build-site.ps1 的分离逻辑未执行"
  exit 1
fi
echo "split OK"

# 3) data.json 未缩水(For Agents 承诺不变 —— 硬约束)
node -e "
const d=require('./site/data.json');
const c=d.components.find(x=>x.slug==='button');
if(!c.sources||Object.keys(c.sources).length!==5) { console.error('FAIL: data.json 的 sources 被破坏'); process.exit(1) }
console.log('data.json intact OK');
"

# 4) data.js 里已无源码正文
node -e "
const d=require('./site/data.js')||{};
" 2>/dev/null || node -e "
const fs=require('fs');
const s=fs.readFileSync('site/data.js','utf8');
// 源码正文特征:不应再出现完整 HTML 文档
if(s.includes('<!DOCTYPE html>')) { console.error('FAIL: data.js 仍含源码正文'); process.exit(1) }
console.log('sources removed OK');
"

浏览器实测:

  • 打开 #/component/button,代码演示区正常显示
  • Network 面板出现 sources/button/html.txt 请求
  • 断网/404 情况下显示兜底提示而非空白

预期输出:

data.js: ~110KB
budget OK
sources files: 395
split OK
data.json intact OK
sources removed OK

失败判据:

  • data.js > 150 KB
  • site/sources/ 文件数 ≠ 395
  • data.json 的 sources 字段被动过(会破坏 For Agents 承诺)
  • 详情页代码区空白或报错

为什么不直接压缩:gzip 能压到 ~200KB,但解析时间与内存占用仍在(1MB JSON 在低端机解析约 100-200ms)。且 Pages 默认已开 gzip,压缩不是增量收益。根治要减体积。


S1-P4b · 首屏资源优化 | 预算 ~2 h | 优先级 P1

目标:文档站首屏传输从 1247 KB 降到 < 300 KB。

依据:P4 完成后 data.js ~110KB,但 app.js 101KB + style.css 40KB 仍是未压缩文本。

依赖:S1-P4。

步骤:

  1. app.js(101KB 单文件)按路由拆分:首页逻辑与详情页逻辑分离,详情页按需加载。
  2. 关键 CSS 内联(首屏可见部分),其余异步加载。
  3. 加入 build-site.ps1 的产出:.min.js / .min.css(用 Node 内置能力做简单压缩:去注释、去多余空白)。

验收:

node -e "
const fs=require('fs');
const files=['site/data.js','site/app.js','site/style.css','site/i18n.js','.design_library/aurora-admin/colors_and_type.css'];
const total=files.reduce((s,f)=>s+fs.statSync(f).size,0);
console.log('首屏资源合计:', (total/1024).toFixed(0)+'KB');
if(total/1024>300){console.error('FAIL: 超过 300KB');process.exit(1)}
console.log('payload OK');
"

S2-P5 · 暗色模式真正实现 | 预算 ~1 天 | 优先级 P0

目标:html.aa-dark 下,79 个组件的演示页全部正常反色,对比度仍满足 WCAG AA。

依据:G4。实测令牌层 aa-dark 规则 0 条、组件层 0 条,只有站点骨架 7 条。CHANGELOG.md 的 v1.1.1 条目称"暗色模式令牌映射补全"—— 这是第 6 次声称≠实现。

依赖:S1-P4(体积优化后改 app.js 更清爽,非硬依赖)。

路径:

  • .design_library/aurora-admin/colors_and_type.css(加暗色令牌组)
  • site/style.css(清理原有的 7 条临时规则)
  • frameworks/*.html 的内嵌样式(若需微调)
  • tests/_runtime.js(增加暗色断言)

步骤:

  1. 设计暗色令牌组(在 colors_and_type.css 里加 html.aa-dark 块):
    • 背景层:page-bg #14161C → card-bg #1C1F26 → table-header-bg #22262E(三层递进)
    • 文字层:text-title #E8EAED → text-body #C9CDD4 → text-secondary #9CA3AF → text-placeholder #6B7280
    • 边框:border #2A2F38、border-strong #363B45
    • 品牌色:向白提亮(#2F54EB 在深底上对比度不足),推荐 #5B7CF5 系列
    • 语义色:同样提亮(#2E7D0A → #4CAF50 一类)
  2. 每个色值都要算对比度,写脚本验证(复用 v1.3.1 的方法):
    node -e "
    // 对每个暗色令牌算 WCAG 对比度,全部 ≥4.5:1(文字)或 ≥3:1(图标)
    "
    
  3. 演示页反色策略:v1.4.0 的注释说"演示 iframe 保持浅色,避免样例反色失真"。这条策略要么:
    • A:改成可配置 —— 站点暗色时演示页也反色(更真实,但要确保反色后不难看)
    • B:保持浅色,但在设计规范页显式说明这是有意设计 推荐 A,因为用户开暗色就是想整体变暗,局部刺眼是体验倒退。若选 A,需给演示页传 ?theme=dark 或用 postMessage 通知。
  4. 加断言:_runtime.js 增加 matrix:dark-contrast,在暗色令牌下重跑对比度检查。

验收:

# 1) 令牌组存在且完整
grep -q "html.aa-dark" .design_library/aurora-admin/colors_and_type.css && echo "dark tokens OK"
node -e "
const css=require('fs').readFileSync('.design_library/aurora-admin/colors_and_type.css','utf8');
const m=css.match(/html\.aa-dark\s*\{([^}]+)\}/s);
if(!m){console.error('FAIL: 无暗色令牌组');process.exit(1)}
const n=(m[1].match(/--au-/g)||[]).length;
console.log('暗色令牌数:', n);
if(n<15){console.error('FAIL: 令牌数不足(预期 ≥15)');process.exit(1)}
"

# 2) 浏览器实测(关键验收)
# 打开 http://127.0.0.1:3311/site/index.html,切暗色模式,
# 逐个打开至少 10 个组件详情页,确认无「白底黑字残留」

浏览器实测项:

  • 首页 / 总览 / 设计规范 / 组件详情 全部正常反色
  • 任意 10 个组件演示页反色后对比度可读
  • 截图对比(交付说明附 3 张暗色截图)

预期输出:

dark tokens OK
暗色令牌数: 20+(预期 ≥15)

失败判据:

  • 暗色令牌数 < 15
  • 任一页面出现"白底 + 白字"或"黑底 + 黑字"
  • 对比度脚本报出 < 4.5:1 的文字

已知风险:79 个演示页的内嵌样式是硬编码过令牌化的(v1.4.0 完成),所以理论上改令牌就能全局生效 —— 这是 v1.4.0 打下的地基,本次直接受益。


S2-P6 · 跨端一致性自动验证 | 预算 ~1 天 | 优先级 P0

目标:能自动回答「H5 / React / Vue2 / Vue3 四个实现是否视觉一致」,并给出差异截图。

依据:G5。5 端 395 个文件,但从来没人验证过它们是否真的一致。契约里写的"各端视觉一致"是纯声称。

依赖:S1-P3(需要 CI 环境跑 Playwright)。

路径:

  • tools/verify-cross-platform.mjs(新建)
  • tools/render-harness/(新建,把 React/Vue 组件渲染成静态 HTML)
  • tests/cross-platform-report.json(产出)

步骤:

  1. 难点:React/Vue 组件需要构建才能渲染(.jsx/.vue 不能直接在浏览器跑)。 零依赖解法:
    • 方案 A:用 CDN 版 React/Vue(<script src="unpkg.com/react">)+ @babel/standalone 在浏览器里编译 JSX。缺点:依赖 CDN 可用性。
    • 方案 B:更推荐 —— 只做结构性比对而非像素比对。提取各端的 className 集合与 DOM 结构,比对差异。不要求渲染,纯静态分析。
    • 方案 C:混合 —— 结构比对为主,挑选 6 个核心组件做像素比对(核心组件的 CDN 依赖可接受)。
  2. 推荐方案 B + 抽样 C:
    • 全部 79 组件:静态提取 class 集合与结构骨架,diff 各端
    • 6 个核心组件(button/input/select/table/card/modal):CDN 渲染 + 截图比对
  3. 输出报告:{ slug, platforms: {h5:[...classes], react:[...], vue2:[...], vue3:[...]}, diffs:[...], severity }

验收:

node tools/verify-cross-platform.mjs
node -e "
const r=require('./tests/cross-platform-report.json');
console.log('检查组件:', r.total);
console.log('完全一致:', r.identical);
console.log('有差异  :', r.differing);
console.log('差异样本:', JSON.stringify(r.samples.slice(0,3),null,1));
"

预期输出:一份报告,明确列出哪些组件的哪些端存在 class/结构差异。

失败判据:

  • 脚本报错或无输出
  • 报告里 total < 79
  • 差异项没有具体说明(只说"不一致"而不给差异内容)

重要说明:这个任务的产出可能揭露一批真实的不一致。这不是失败 —— 是这项任务的价值。发现的差异应作为新任务包列出,不在本任务内顺手修(避免范围蔓延)。


S2-P7 · 行为断言 | 预算 ~1.5 天 | 优先级 P1

目标:测试从"元素存在"升级到"交互后发生什么",覆盖点击/输入/键盘的真实行为。

依据:G8。当前 12 项/页断言多为结构性(元素存在、有 aria、对比度达标),没有任何一条验证"点了按钮会怎样"。

依赖:无。

路径:

  • tests/_runtime.js(扩展断言引擎)
  • tests/_behaviors.js(新建,行为断言库)

步骤:

  1. 定义行为断言协议(在演示页里声明):
    <button data-behavior="click-toggles-class:.aa-modal|is-open">打开弹窗</button>
    
  2. 实现常见行为模式:
    • click-toggles-class:<selector>|<class> — 点击切换类
    • click-sets-attr:<selector>|<attr>|<value> — 点击设属性
    • input-updates:<selector>|<text> — 输入后状态变化
    • keyboard-activates:<key> — 键盘触发
    • focus-trap:<container> — 弹窗焦点锁定
  3. 在 6 个核心组件(button/modal/select/input/table/tabs)的演示页里标注行为断言作为试点。
  4. 断言结果并入现有报告结构(matrix:behavior:*)。

验收:

# 1) 行为断言库存在且语法正确
node --check tests/_behaviors.js && echo "syntax OK"

# 2) 6 个试点组件有行为断言
grep -l "data-behavior" frameworks/{Button,Modal,Select,Input,Table,Tabs}.html | wc -l
# 期望输出 6

# 3) 回归里出现行为断言
# 跑 _collect.html,检查 report.json 的 failureKinds 含 matrix:behavior:*

浏览器实测:点击弹窗按钮后,is-open 类被添加(观察 DOM)。

预期输出:

syntax OK
6

失败判据:

  • 试点组件少于 6 个
  • 行为断言在回归报告里不出现
  • 断言只是"元素存在"换个名字(无实际交互逻辑)

S3-P8 · RTL 支持 | 预算 ~2 天 | 优先级 P1

目标:<html dir="rtl"> 时布局正确镜像,无错位。

依据:G7。逻辑属性 0 处,物理属性(margin-left 等)出现在 22 个文件。竞品 7 家里 3 家有 RTL。

依赖:S2-P5(暗色完成后改样式更安全,减少冲突)。

路径:

  • frameworks/*.css(22 个含物理属性的文件)
  • frameworks/*.html 内嵌样式
  • .design_library/aurora-admin/colors_and_type.css(如需要在文档说明约定)

步骤:

  1. 批量迁移物理→逻辑属性:
    物理 逻辑
    margin-left margin-inline-start
    margin-right margin-inline-end
    padding-left/right padding-inline-start/end
    left / right(定位) inset-inline-start/end
    text-align: left/right text-align: start/end
    border-left/right border-inline-start/end
  2. 注意例外:图标方向类(箭头、返回)需要 transform: scaleX(-1) 而非属性迁移。
  3. 写一个 RTL 演示页:site/scenario/user-management-rtl.html,用于人工验收。
  4. 增加 RTL 断言:matrix:rtl-safe,检测是否还有物理属性的残留。

验收:

# 1) 物理属性清零
n=$(grep -l "margin-left\|margin-right\|padding-left\|padding-right" frameworks/*.css 2>/dev/null | wc -l)
echo "剩余物理属性文件: $n"
test "$n" -eq 0 && echo "RTL migration OK"

# 2) 逻辑属性已使用
grep -l "margin-inline\|padding-inline\|inset-inline" frameworks/*.css | wc -l
# 期望 ≥ 22

浏览器实测:user-management-rtl.html 加 dir="rtl",确认布局镜像无错位(附截图)。

预期输出:

剩余物理属性文件: 0
RTL migration OK
22+

失败判据:

  • 仍有物理属性残留
  • RTL 下出现元素重叠/溢出
  • 图标方向错误(如右箭头在 RTL 下仍指右)

S3-P9 · FAQ 页 | 预算 ~1 天 | 优先级 P2

目标:新增 #/faq 页,自动聚合 139 条 unknowns + 101 条 doNotInvent,形成可检索的问答。

依据:契约里已有 240 条结构化条目,现成素材没被利用。Ant Design 每组件 FAQ 是行业惯例。

依赖:无。

路径:

  • site/app.js(新增 renderFaq)
  • site/index.html(导航加 FAQ 链接)
  • site/i18n.js(文案)

步骤:

  1. build-site.ps1 已把 contract 注入 data.js(字段 unknowns / doNot),直接消费即可。
  2. 渲染两种视图:
    • 按组件:每个组件列出它的 unknowns("规范未明示")与 doNotInvent("不要自行发明")
    • 按分类:把相似的 unknowns 聚类(如"最大宽度""省略方式"跨多个组件出现)
  3. 加搜索过滤(复用 _runtime 的思路,纯前端)。

验收:

# 1) 路由可达
curl -s http://127.0.0.1:3311/site/index.html | grep -q 'href="#/faq"' && echo "nav OK"
# 2) 数据完整注入
node -e "
const d=require('./site/data.json');
const u=d.components.reduce((s,c)=>s+((c.contract&&c.contract.unknowns)||[]).length,0);
const dn=d.components.reduce((s,c)=>s+((c.contract&&c.contract.doNot)||[]).length,0);
console.log('unknowns:',u,'doNotInvent:',dn);
if(u<139||dn<101){console.error('FAIL: 契约数据缺失');process.exit(1)}
console.log('data OK');
"

浏览器实测:#/faq 显示 79 个组件的条目,搜索"宽度"能过滤出相关项。

预期输出:

nav OK
unknowns: 139 doNotInvent: 101
data OK

失败判据:条目数少于 139/101,或页面空白。


S4-P10 · Figma 资源 | 预算 ~2 天 | 优先级 P2

目标:产出可导入 Figma 的变量集与组件描述,设计师能直接用同一套令牌。

依据:竞品标配 Figma/Sketch 资源。本项目已有 site/tokens/figma.json(Tokens Studio 格式),但没有 Figma Variables 原生格式。

依赖:S1-P2(需稳定的令牌导出管线)。

路径:

  • tools/export-figma.mjs(新建)
  • dist/figma/(产出)

步骤:

  1. 产出 Figma Variables JSON(与 Tokens Studio 格式不同,是 Figma 原生 API 格式):
    • 色彩变量 → { "color": { "brand": { "type": "COLOR", "value": {...} } } }
    • 数值变量(间距/圆角/字号)→ FLOAT
    • 建立 Light / Dark 两种 mode(呼应 S2-P5)
  2. 产出组件清单 Markdown(供设计师建组件时参考):每个组件的变体维度 + 尺寸 + 状态。
  3. 写导入说明(dist/figma/README.md)。

验收:

node tools/export-figma.mjs
node -e "
const v=require('./dist/figma/variables.json');
const colors=Object.keys(v.color||{}).length;
console.log('色彩变量:', colors);
console.log('模式:', Object.keys(v.modes||{}).join(', '));
if(!v.modes||!v.modes.Dark){console.error('FAIL: 缺少 Dark 模式');process.exit(1)}
console.log('figma export OK');
"

预期输出:

色彩变量: 24+
模式: Light, Dark
figma export OK

失败判据:无 Dark 模式、变量数明显少于令牌数、JSON 不符合 Figma Variables 结构。


S4-P11 · 模板页库 | 预算 ~2 天 | 优先级 P2

目标:从 1 个场景页扩展到 5 个典型后台页面模板,展示组件组合用法。

依据:现有 site/scenario/user-management.html 是唯一的组合示范。模板页是"能否直接用"的关键 —— 用户要的不是组件,是页面。

依赖:无。

路径:site/scenario/*.html(新增 4 个)

步骤:

  1. 选定 4 个典型场景(覆盖不同组件组合):
    • login.html — 登录页(输入类组件 + 表单校验)
    • dashboard.html — 数据看板(图表 + 指标卡 + 表格)
    • order-list.html — 列表管理(表格 + 筛选 + 分页 + 批量操作)
    • settings.html — 设置页(Tab + 表单 + 开关组)
  2. 每个模板页只用现有令牌与 components.css,纯 HTML + 原生 JS(零依赖)。
  3. 加到首页入口与 sitemap。

验收:每个模板页在浏览器实测可交互(筛选、分页、提交有反馈),附截图。

失败判据:页面白屏、交互无效、用了非项目内的样式。


S4-P12 · 版本发布流程 | 预算 ~1 天 | 优先级 P3

目标:有明确的 SemVer 发布流程与自动化。

依赖:S1-P2。

步骤:

  1. tools/release.mjs:从 CHANGELOG 提取版本 → 更新 package.json → 打 tag → 提示推送。
  2. 文档化到 CONTRIBUTING.md。

四 · 显式不做(及理由)

这份清单同样重要 —— 没有它,执行模型会以为"漏了",或者在错误的时机自作主张。

不做 理由 什么条件下应该做
不引入打包器(Vite / Rollup / esbuild) 破除零依赖约束的代价远大于收益;本项目的卖点就是"打开 HTML 就能用" 若未来要发布 ESM/CJS 模块化包,先评估是否需要独立仓库
不做像素级视觉回归(全量) 79 组件 × 5 端 = 395 张基准图,维护成本极高且易误报(抗锯齿/字体渲染差异) P6 已包含「6 个核心组件抽样像素比对」,够用
不做 SSR / SSG 文档站是纯静态 SPA,爬虫需求已由 site/components/*.html 薄壳 + sitemap 解决 若 SEO 成为核心指标,再评估
不做多主题商店(Ant Design 式) 已有 6 套预设 + 令牌导出,改色能力已足够;主题商店是运营功能非工程功能 产品化阶段(S4 之后)
不重写 app.js 2064 行单文件虽不理想,但功能正确、回归 100%。重构风险 > 收益 若某任务包因它受阻(如 P4 代码拆分),局部改造而非重写
不改 frameworks/ 的视觉 那是规范原文的忠实实现,改了会破坏契约一致性 只有规格原文变更时才同步
不做 Storybook 集成 与零依赖冲突,且 Playground(v1.2.0)已覆盖在线试玩需求 不考虑
不做 React/Vue 单元测试(Jest/Vitest) 与零依赖冲突;跨端一致性靠 P6 的静态比对 + 抽样渲染 若组件逻辑复杂化到静态分析无法覆盖

五 · 未解问题(需用户或后续规划决策)

这些问题我作为规划师无法单方面决定,列出供决策。

# 问题 影响面 我的建议
Q1 是否发布到 npm? 涉及包名占用、发布权、后续维护承诺 S1-P2 建议发。当前无分发渠道是最大阻塞,且 npm 上同名包大概率未被占用
Q2 目标用户是谁? 内部团队 / 开源社区 / 商业化产品,三者的优先级与验收标准不同 全局 建议先按「内部团队 + 开源复用」定位(对应 S1-S2 的优先级)
Q3 是否有设计团队协作? 若没有,S4-P10 的 Figma 产出无人使用 S4-P10 建议推迟到有设计资源时再做,或降级为「Figma Variables JSON 导出」只做工程侧
Q4 是否需要 RTL? 取决于是否有中东/希伯来语市场 S3-P8 若无明确市场,降级为 P2 或推迟。迁移成本高(22 个文件)
Q5 性能预算的底线是多少? 我定的 300KB 是经验值 S1-P4b 建议以「3G 网络首屏可交互 < 3s」反推预算
Q6 暗色模式下演示 iframe 是否反色? 两种都有道理 S2-P5 建议反色(用户开暗色就是要整体变暗),但需人工验收视觉

六 · 风险登记

风险 影响 缓解
约束冲突:CI 需要 Playwright,但"零依赖" 中 明确区分运行时依赖(保持零)与构建/测试依赖(可引入 devDependencies),并在 README 写清
S2-P6 暴露大量跨端不一致 中 已在任务包里说明"发现即价值",差异作为新任务列出,不顺手修
暗色反色后视觉倒退 中 强制对比度脚本验证 + 人工截图验收
RTL 迁移破坏现有布局 中 迁移后跑八次回归;逐文件比对渲染截图
data.js 拆分影响 For Agents 承诺 高 明确要求 data.json 保持完整,只拆 data.js
用户未确认许可证类型 中 默认 MIT 并在交付说明标注"如需变更请告知"

七 · 验收总纲

任一任务包完成,必须同时满足:

  1. 给出验收命令的完整输出(不是"我以为跑过了")
  2. 跑八次回归:100% / 0 失败 / 0 超时
  3. CHANGELOG.md 有对应条目([Unreleased] 下)
  4. 本文件对应任务包下追加 ✅ 完成于 <commit-hash>
  5. 若发现新问题:写成新任务包追加到本文件,不在原任务里顺手修

附 · 执行状态总览

执行模型看这里:找下一个可开工的任务。状态为「待开始」且依赖已满足的最优先任务就是你的目标。

ID 任务 阶段 优先级 预算 依赖 状态
P1 LICENSE S1 P0 10 min — ✅ 已完成(MIT)
P2 npm 分发 S1 P0 2 h P1 ✅ ✅ 已完成(dist 构建 + npm pack 115.9KB)
P3 CI 回归 S1 P0 1.5 h — ✅ 已完成(workflow + runner 重构 + exit code)
P4 data.js 瘦身 S1 P0 3 h — ✅ 已完成(data.js 98KB/sources 395/data.json 完整/回归 1003/1003,见 c65a69c)
P5 暗色模式 S2 P0 1 d P4 ✅ ✅ 已完成(令牌组31/对比度10项≥4.5/10页实测/DARK VERIFY 32/32/首屏292KB/回归1003/1003,Q6选A)
P6 跨端一致性验证 S2 P0 1 d P3 ⚪ 待 P3
P7 行为断言 S2 P1 1.5 d — 🟢 可开工(优先级低于 P2-P4)
P8 RTL S3 P1 2 d P5 ⚪ 待 P5
P9 FAQ 页 S3 P2 1 d — 🟢 可开工(优先级低)
P10 Figma 资源 S4 P2 2 d P2 ⚪ 待 P2
P11 模板页库 S4 P2 2 d — 🟢 可开工(优先级低)
P12 版本发布流程 S4 P3 1 d P2 ⚪ 待 P2

推荐执行顺序

P3(CI,无依赖最快见效)
 → P4(瘦身,收益最大)
 → P2(分发,解除交付阻塞)
 → P5 + P6(可信度双支柱)
 → P7 → P8 → P9 → P10 → P11 → P12

为什么 P3 排第一:它是唯一能让后续所有改动自动受保护的任务 —— 有了 CI,其他任务的质量不再依赖人工记得跑回归。

为什么 P4 第二:实测净减 887 KB(991KB → ~110KB),收益/成本比最高,且依赖分析已完成。

并行机会:P2 与 P4 互不阻塞,可由两个模型同时做。P3 完成后应立即合并,让后续任务都在 CI 保护下。


附 · 规划修正记录

执行中发现规划与实际不符时,以实测为准,在此登记。

日期 任务 规划原写 实测 处理
2026-09-11 P4 data.js 目标 < 400 KB(推测 sources 是最大头) sources 实测占 89.6%(888KB/991KB);拆出后可达 ~110KB 目标改为 < 150 KB,策略与体积数据全部替换为实测
2026-09-11 P4 预计算 API 表估算 < 30 KB 实测 1.0 KB(比估算乐观 30 倍) 更新为实测值
2026-09-11 P2 包名可用性未知 registry 查询:aurora-admin-design 未被占用 补入「前置验证已完成」
2026-09-11 P4 只说「改成 fetch」,未识别难点 app.js 有 10 处消费 sources,其中 2 处是渲染期同步解析 补入「依赖分析」与三阶段执行建议
2026-09-11 P2/P4 验收命令有 3 处会误判(npm 不可用时误报 OK 等) 实测触发 已改写为显式判断 exit code