docs: 长期路线图(ROADMAP.md,12 个可执行任务包)+ 执行 P1 LICENSE

规划师角色切换后的首份交付:把规划做成可交接工件,而非聊天里的建议。

ROADMAP.md 的形态
- 每个任务包含:目标 / 依据 / 依赖 / 精确路径 / 步骤 / 验收命令 / 预期输出 /
  失败判据。执行模型照做即可,不需要再问
- 附「交接约定」6 条(零依赖不可破、build-site.ps1 必须 ASCII-only、改结构要改
  模板、改样式要改内嵌层、验收以实测为准、单次改动跑八次回归)
- 附「验收总纲」5 条(给完整输出、跑八次回归、CHANGELOG 条目、ROADMAP 标记、
  新问题写成新任务包不顺手修)

基线全部实测(非估计)
- 资产:79 组件 / 395 端文件 / 79 契约 / 358 usageHints / 139 unknowns /
  101 doNotInvent / 75 令牌 / 330 字典 / 961 断言
- 回归 100%(八次连跑一致)/ 契约保真 93.9% / 令牌语义 0 错配 / i18n 0 残留
- 性能:文档站 1247KB,其中 data.js 1058KB(85%)
- 八项缺口(G1-G8)每项附实测证据

关键诊断(在规划里就完成,避免执行模型走弯路)
- data.json 体积实测拆解:sources 字段 888KB = 89.6%。拆出后 data.js
  991KB → ~110KB(−89%)。规划里的推测值已被实测替换

阶段划分与决策依据
- S1 可交付(LICENSE/npm/CI/data.js)→ S2 可信(暗色/跨端/行为断言)→
  S3 完整(RTL/FAQ)→ S4 生态(Figma/模板/发布)
- 顺序依据:S1 是「能不能用」,S2 是「能不能信」,S3 是「够不够全」,
  S4 是「好不好用」。颠倒会做出没人敢用的产品

顺带执行 P1(验证规划可落地)
- LICENSE:MIT 全文,README 新增许可证段与路线图链接,版本号校正为 v1.4.1
- 验收输出:LICENSE OK / README OK
- ROADMAP 对应任务包下追加完成标记(验证闭环机制可用)

回归:100%(961 断言 / 0 失败 / 79 页全通过)
This commit is contained in:
aurora-admin
2026-09-11 22:40:10 +08:00
parent ba3f3c53f9
commit d88cdf2324
3 changed files with 857 additions and 1 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Aurora Admin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+11 -1
View File
@@ -60,4 +60,14 @@ node tools/run-regression.mjs # headless 回归(需 npm i playwright)
## 版本
见 [CHANGELOG.md](./CHANGELOG.md)。当前 v1.2.0。
见 [CHANGELOG.md](./CHANGELOG.md)。当前 v1.4.1。
## 路线图
后续规划(可交付性、可信度、完整度、生态四阶段,含逐任务验收标准)见 [ROADMAP.md](./ROADMAP.md)。
## 许可证
[MIT](./LICENSE) © 2026 Aurora Admin
可自由用于商业项目、修改、再分发,仅需保留版权声明。如需变更许可证(例如 Apache-2.0 或 MPL-2.0),请参考 [ROADMAP.md](./ROADMAP.md) 的 S1-P1 任务包。
+825
View File
@@ -0,0 +1,825 @@
# Aurora Admin · 长期路线图与任务包
> **文档性质**:交给执行模型的工程规划。每个任务包自带验收命令与失败判据,拿到即可开工,不需要再问。
> **基线版本**:v1.4.1(2026-09-11)
> **规划人**:海鸥(规划师角色)
> **更新约定**:任务完成时在本文件对应任务包下追加 `✅ 完成于 <commit>`,不要删原计划。
---
## 〇 · 交接约定(执行模型必读)
1. **零依赖约束不可破**:不引入 npm 运行时依赖。构建/测试脚本用 Node 内置能力或 PowerShell。
2. **`build-site.ps1` 必须 ASCII-only**:PS5.1 按 ANSI 读无 BOM 文件,脚本里出现非 ASCII 字面量会被损坏。中文文案放 UTF-8 模板。
3. **改结构要改模板**:`tests/<slug>.html` 是生成物,改它没用 —— 改 `tests/_template.html` 后重跑 `run-tests.ps1`。
4. **改样式要改内嵌层**:演示页的**内嵌 `<style>`** 才是实际生效的样式(见 v1.4.0 教训)。只改 `frameworks/*.css` 可能不生效。
5. **验收以实测为准**:跑本文件给出的命令,把输出贴进交付说明。不要写"已完成"而不给证据。
6. **单次改动后必须跑回归**:`tests/_collect.html` 八次连跑,`100% / 0 失败 / 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`。
**验收**:
```bash
# 文件存在且包含关键条款
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),对"只想用几个组件"的人成本过高。
**依赖**:S1-P1(package.json 需声明 `license` 字段)。
**路径**:
- `package.json`(新建)
- `.npmignore`(新建)
- `tools/build-dist.mjs`(新建,产出分发产物)
- `dist/`(构建产物,加入 `.gitignore`)
**步骤**:
1. 建 `package.json`,关键字段:
```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 / 直接下载三种方式。
**验收**:
```bash
# 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 --dry-run 2>&1 | grep -q "site/" && echo "FAIL: 打包含 site/" || echo "pack contents OK"
# 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:
```yaml
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)`。
**验收**:
```bash
# 本地模拟 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`**:
- 详情页渲染代码区时 `fetch('sources/<slug>/<kind>.txt')`
- 加 loading 态(复用现有 `.demo-code` 样式)
- 加失败兜底(fetch 失败显示"源码加载失败"+ 重试按钮,不留空白)
3. **验证 For Agents 承诺未破**:`data.json` 仍然包含完整 `sources`。
**验收**:
```bash
# 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 个)
n=$(ls site/sources/*/*.txt 2>/dev/null | wc -l)
echo "sources files: $n"
test "$n" -eq 395 && 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 内置能力做简单压缩:去注释、去多余空白)。
**验收**:
```bash
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 的方法):
```bash
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`,在暗色令牌下重跑对比度检查。
**验收**:
```bash
# 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 }`
**验收**:
```bash
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. 定义行为断言协议(在演示页里声明):
```html
<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:*`)。
**验收**:
```bash
# 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`,检测是否还有物理属性的残留。
**验收**:
```bash
# 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` 的思路,纯前端)。
**验收**:
```bash
# 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`)。
**验收**:
```bash
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`。
---
## 四 · 风险登记
| 风险 | 影响 | 缓解 |
|---|---|---|
| 约束冲突: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 | 用户确认类型 |
| P2 | npm 分发 | S1 | **P0** | 2 h | P1 |
| P3 | CI 回归 | S1 | **P0** | 1.5 h | — |
| P4 | `data.js` 瘦身 | S1 | **P0** | 3 h | — |
| P5 | 暗色模式 | S2 | **P0** | 1 d | P4 |
| P6 | 跨端一致性验证 | S2 | **P0** | 1 d | P3 |
| P7 | 行为断言 | S2 | P1 | 1.5 d | — |
| P8 | RTL | S3 | P1 | 2 d | P5 |
| P9 | FAQ 页 | S3 | P2 | 1 d | — |
| P10 | Figma 资源 | S4 | P2 | 2 d | P2 |
| P11 | 模板页库 | S4 | P2 | 2 d | — |
| P12 | 版本发布流程 | S4 | P3 | 1 d | P2 |
**建议执行顺序**:P1 → P3 → P4 → P2 → P5 → P6(前六个是「可交付」与「可信」的地基)