# 设计:需求溯源索引体系 (Requirement Provenance Index)

- **日期**:2026-07-06
- **项目**:TVU Pack(docs 项目,无构建工具链;Node v24 + Python 3.14 可用)
- **目标**:让 AI / 人快速定位「某个需求的效果图在哪个设计里做的」,以及反向「给 Jira / Slack / Miro / Figma 节点 → 找到需求 + 相关文档」,**免全局搜索**;并妥善承载「同一需求跨时期的逻辑修改/补充」。
- **背景**:现状 design-record 把 Jira/Figma 字段散在正文,格式不统一,只能 grep;且 83059/Preset R 这类新逻辑此前无文档、只活在 Figma 注释里。

## 问题与目标

1. 需求来源多样(Jira / Slack / Miro / 裸版本号 / 口头),**不能以 Jira key 当主键**。
2. 需要**一个免全局搜索的入口**做双向定位。
3. 同一需求的 **design-record 与 handoff** 要能关联、一起被查到。
4. 索引**不能靠手维护**(会像 STATUS.md 一样腐烂)——必须从文档派生。
5. 这套标准要**回流到 tvu-design-system 消费产品项目标准**(真源),供其他消费产品复用。

## 方案总览

三层:**(A) 文档 frontmatter(真源)→ (B) 派生索引(脚本生成)→ (C) 起手约定 + 真源回写**。

### A. Frontmatter schema v2 —— design-record + handoff 两类文档都带

```yaml
id: preset-r-go-live        # 稳定 slug,主键;同一需求的 design-record 与 handoff 共用同一 id
title: Go-Live 选 R / Preset R
doc_type: design-record     # design-record | handoff —— 索引据此分列/打标
status: in-dev              # requirement | in-dev | QA | delivered
target_release: "8.3"       # 可选
last_updated: 2026-07-06    # YYYY-MM-DD
sources:                    # 0..N,typed;ref 必填、url 可选
  - { type: jira, ref: "V4-2309", url: "https://tvunetworks.atlassian.net/browse/V4-2309" }
  - { type: slack, ref: "thread 1782972570.160449 @CSC0M4V34", url: "https://tvunetworks.slack.com/archives/CSC0M4V34/p1782972570160449" }
figma:                      # 可选
  file: 0054ib0nLmt27bC3QlGDl7
  nodes:
    - { id: "8062:8070", label: "单源 Go-Live 选 R (V3)", url: "https://www.figma.com/design/0054ib0nLmt27bC3QlGDl7/...?node-id=8062-8070" }
```

字段契约:
- `id`(必填):`[a-z0-9-]+` slug,需求级稳定主键。**同一需求的多篇文档(spec + handoff)共用同一 id**,索引据此归组。
- `title`(必填)。
- `doc_type`(必填):`design-record` | `handoff`。
- `status`(必填):`requirement` | `in-dev` | `QA` | `delivered`。
- `target_release`(可选):字符串,如 `"8.3"`。
- `last_updated`(必填):`YYYY-MM-DD`。
- `sources`(必填,可空数组):每项 `{type, ref, url?}`。`type` ∈ `jira|slack|miro|bug|email|verbal|doc|other`;`ref` 必填(人可读定位串,链接失效也能找回);`url` 可选。
- `figma`(可选):`{file, nodes:[{id, label, url}]}`。

**source-agnostic 关键点**:主键是 slug 不是 Jira;`url` 可选、`ref` 必填 → Slack/Jira/Miro/裸版本号/口头都能记,链接烂了不单点失效。

### B. 索引生成器 —— 零依赖 Node 脚本

- 路径:`docs/scripts/build-request-index.mjs`。
- 行为:扫 `docs/specs/*.md` + `docs/handoffs/*.md`,抽 frontmatter,**按 `id` 合并**(一个需求聚合其 spec + handoff),生成两个产物。
- **frontmatter 解析零依赖**:脚本内置一个受控 YAML-子集解析器(处理本 schema 的标量 / typed list / 嵌套 figma 结构),不装 npm。文档 frontmatter 采用块式 YAML(可读),解析器只需覆盖本 schema 用到的语法子集。
- 产物 1 `docs/REQUEST-INDEX.md`(人读表,按需求归组):列 = id｜title｜sources(徽章 `JIRA V4-2309`·`Slack`·`#8.3`)｜figma 节点(可点链接)｜文档(design-record + handoff 链接)｜status｜target｜updated。
- 产物 2 `docs/request-index.json`(机器数组):每需求一对象,含 `id/title/status/target_release/sources/figma/docs[]`(docs[] 列出该需求的 spec + handoff 路径与 doc_type)。
- 幂等、确定性排序(按 `last_updated` 倒序,同日按 id)。校验:缺必填字段 / id 非法 / doc_type 非枚举 → 脚本报警列出问题文件,不静默。

### C. 起手约定 + 真源回写

- `docs/FIGMA_LINKS.md` 顶部加一段(文件名保留,避免断引用):
  > **AI 起手先读 `docs/REQUEST-INDEX.md`** 定位需求↔Jira/Slack/Figma↔文档;改动任何 design-record / handoff 后跑 `node docs/scripts/build-request-index.mjs` 重生成索引。
- **回流真源(tvu-design-system,maintainer scope,动前再确认)**:
  - design-record 模板 `templates/consumer-product/docs/specs/_feature-design-record.template.md` 顶部加 frontmatter 头;handoff 模板同样补(无则新建 handoff 模板)。
  - `build-request-index.mjs` 纳入 consumer-product 模板(scaffold 出来即带)。
  - 约定写进 `code-conventions.md` / `design-process.md`(真源):两类文档必带 v2 frontmatter + wrap-up 跑索引脚本 + 起手读索引。

### D. 回填

- 给现有 **9 篇 `docs/specs/`** + **全部 `docs/handoffs/`** 补 v2 frontmatter(从正文抽 id/title/sources/figma/status/日期)。
- **同一需求的 spec 与 handoff 用同一 slug 关联**(例:v4-2312、v4-2285-2286、fb-10014、v4-1865、v4-2259 等,spec 和对应 handoff 归到同一 id)。
- 跑生成器 → 产出首版 `REQUEST-INDEX.md` + `request-index.json`。

## 组件边界

| 单元 | 职责 | 依赖 |
|---|---|---|
| frontmatter schema | 每篇文档的机器可读元数据(真源) | 无 |
| `build-request-index.mjs` | 扫描 + 解析 + 合并 + 出 md/json | 只读 docs/specs, docs/handoffs;Node 内置 fs |
| `REQUEST-INDEX.md` / `request-index.json` | 派生产物(不手改) | 由脚本生成 |
| FIGMA_LINKS.md 约定段 | 起手指路 | 指向索引 + 脚本 |
| tvu-design-system 模板/约定 | 让标准可复用 | 另一 repo |

## 非目标 (YAGNI)

- 不做 watch/自动重生成(手动跑脚本 or wrap-up 跑,足够)。
- 不做索引的 Web UI。
- decisions/ / retrospects/ / audits/ 暂不纳入 frontmatter/索引(只 design-record + handoff)。
- 不改现有 design-record 的正文结构,只加 frontmatter 头。

## 风险 / 边界

- **解析器脆性**:自写 YAML 子集解析器可能对格式偏差敏感 → 缓解:schema 受控 + 脚本对不合规文件报警(不静默跳过)。
- **spec↔handoff slug 对齐**:回填时需人判断哪些 spec 与 handoff 是同一需求 → 回填时逐一核对,拿不准的单列不强合。
- **真源回写跨 repo**:tvu-design-system 有独立 commit+push gitea 纪律,作为独立一步、动前确认。

## 验收

1. 9 篇 specs + 全部 handoffs 都有合规 v2 frontmatter,脚本校验 0 报警。
2. `node docs/scripts/build-request-index.mjs` 幂等生成 REQUEST-INDEX.md + request-index.json;同一需求的 spec+handoff 归在一行/一对象。
3. FIGMA_LINKS.md 顶部有起手约定段。
4. tvu-design-system 模板 + 约定已回写(独立步、确认后)。
5. 抽查:给一个 Jira key / Figma 节点 ID,能在索引里一步定位到需求 + 文档,无需全局搜索。
