proto-prd-diff.html 8 KB
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" /><meta name="viewport" content="width=device-width,initial-scale=1" />
<title>原型 · PRD diff 面板 · LemonBoss PRD</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,300;9..144,500;9..144,700&family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="assets/shell.css" />
</head>
<body data-page="proto-prd-diff.html">
<div class="shell">
  <aside id="sidebar"></aside>
  <main class="page">
    <header class="page-head">
      <div class="crumb"><span class="pill">04 · PROTO</span><span class="sep">/</span><span>PRD diff 面板</span></div>
      <h1>PrdDiffPanel · 文档版本差异</h1>
      <p class="deck">展示「本轮反馈引入了什么」。section 级粒度的 diff(不做行级),符合「PRD 修改即增删 section」的写入约束。</p>
    </header>
    <article class="body">

      <section>
        <h2>线框</h2>
        <div class="mock">
          <div class="topbar">
            <span class="dot" style="background:#FF5F57"></span>
            <span class="dot" style="background:#FEBC2E"></span>
            <span class="dot" style="background:#28C840"></span>
            <span class="url">PrdDiffPanel · rev 3 vs rev 2</span>
          </div>
          <svg viewBox="0 0 1100 480" width="100%" role="img" aria-label="PrdDiffPanel wireframe">
            <rect width="1100" height="480" fill="#fff" stroke="#dcd5c4"/>
            <rect x="0" y="0" width="1100" height="48" fill="#0E0E10"/>
            <text x="20" y="32" font-family="Fraunces" font-size="16" fill="#FAF7F1">PRD · 项目 p-731042</text>
            <text x="900" y="32" font-family="JetBrains Mono" font-size="11" fill="#86827a">rev 3 vs rev 2</text>

            <rect x="20" y="68" width="80" height="24" rx="12" fill="#fff" stroke="#0E0E10"/><text x="60" y="84" font-family="JetBrains Mono" font-size="10" text-anchor="middle">all</text>
            <rect x="108" y="68" width="80" height="24" rx="12" fill="#E2F2EA" stroke="#0E8C5A"/><text x="148" y="84" font-family="JetBrains Mono" font-size="10" text-anchor="middle" fill="#0E8C5A">+ added</text>
            <rect x="196" y="68" width="80" height="24" rx="12" fill="#FFF6CC" stroke="#8a6b00"/><text x="236" y="84" font-family="JetBrains Mono" font-size="10" text-anchor="middle" fill="#8a6b00">~ changed</text>
            <rect x="284" y="68" width="80" height="24" rx="12" fill="#FCE7E2" stroke="#C7341A"/><text x="324" y="84" font-family="JetBrains Mono" font-size="10" text-anchor="middle" fill="#C7341A">– removed</text>

            <text x="900" y="84" font-family="JetBrains Mono" font-size="10" fill="#3B3B40" text-anchor="end">由 yibo@2026-05-13 10:31 触发</text>

            <rect x="20" y="110" width="1060" height="80" rx="6" fill="#E2F2EA" stroke="#0E8C5A"/>
            <text x="34" y="130" font-family="JetBrains Mono" font-size="11" fill="#0E8C5A" font-weight="700">+ Section data-rev="3"</text>
            <text x="34" y="148" font-family="Fraunces" font-size="14" fill="#0E0E10">OAuth 登录</text>
            <text x="34" y="170" font-family="JetBrains Mono" font-size="11" fill="#3B3B40">支持 GitHub OAuth。Token 自动刷新 ≤ 5s。</text>
            <text x="34" y="186" font-family="JetBrains Mono" font-size="10" fill="#6c6c6c">→ 影响 Unit:oauth-be · oauth-fe · auth-mw(新增)</text>

            <rect x="20" y="200" width="1060" height="80" rx="6" fill="#FFF6CC" stroke="#8a6b00"/>
            <text x="34" y="220" font-family="JetBrains Mono" font-size="11" fill="#8a6b00" font-weight="700">~ Section data-rev="1" 修改(来自 rev 3 的影响)</text>
            <text x="34" y="238" font-family="Fraunces" font-size="14" fill="#0E0E10">登录</text>
            <text x="34" y="260" font-family="JetBrains Mono" font-size="11" fill="#3B3B40">原:邮箱密码登录 → 新:邮箱密码登录 + OAuth 备选</text>
            <text x="34" y="276" font-family="JetBrains Mono" font-size="10" fill="#6c6c6c">→ 影响 Unit:auth-be(contract 不变, hash 不变, 不 reset)</text>

            <rect x="20" y="290" width="1060" height="60" rx="6" fill="#fff" stroke="#dcd5c4"/>
            <text x="34" y="312" font-family="JetBrains Mono" font-size="11" fill="#3B3B40">  Section data-rev="2"(未变)</text>
            <text x="34" y="330" font-family="Fraunces" font-size="14" fill="#0E0E10">个人主页</text>
            <text x="34" y="346" font-family="JetBrains Mono" font-size="10" fill="#6c6c6c">→ 影响 Unit:profile-be · profile-fe(未变)</text>

            <text x="20" y="382" font-family="JetBrains Mono" font-size="10" fill="#3B3B40">Changelog</text>
            <text x="34" y="402" font-family="JetBrains Mono" font-size="11" fill="#0E0E10">rev 1 · init · 邮箱密码登录</text>
            <text x="34" y="420" font-family="JetBrains Mono" font-size="11" fill="#0E0E10">rev 2 · yibo · + 个人主页</text>
            <text x="34" y="438" font-family="JetBrains Mono" font-size="11" fill="#0E0E10">rev 3 · yibo · + GitHub OAuth</text>

            <rect x="930" y="445" width="150" height="28" rx="14" fill="#fff" stroke="#0E0E10"/>
            <text x="1005" y="463" font-family="JetBrains Mono" font-size="11" text-anchor="middle">open full PRD ↗</text>
          </svg>
        </div>
      </section>

      <section>
        <h2>三色 diff 标记</h2>
        <table class="dense">
          <thead><tr><th>类型</th><th>颜色</th><th>判定</th><th>影响 Unit</th></tr></thead>
          <tbody>
            <tr><td><b>added</b></td><td>emerald</td><td>新 section data-rev 等于当前 rev</td><td>可能新增多个 Unit</td></tr>
            <tr><td><b>changed</b></td><td>amber</td><td>section data-rev 旧但被新需求隐含修改</td><td>需要 Architect 标注 + 影响 contract_hash 时才 reset</td></tr>
            <tr><td><b>removed</b></td><td>red</td><td>新 PRD 不再包含的 section(罕见)</td><td>对应 Unit 整体归档到 history/removed/</td></tr>
            <tr><td><b>unchanged</b></td><td>灰底</td><td>正文不变</td><td>不动</td></tr>
          </tbody>
        </table>
      </section>

      <section>
        <h2>怎么实现 diff</h2>
        <p>客户端用 <code>diff-dom</code>,section 粒度。算法:</p>
        <ol>
          <li>对 newHtml 和 oldHtml 分别用 <code>DOMParser.parseFromString</code></li>
          <li>枚举每个 <code>section[data-rev]</code> 在双方的存在性 + textContent hash</li>
          <li>三态分类:only-new = added · only-old = removed · 同 id 不同 hash = changed</li>
          <li>渲染时为每条 section 包一层 wrapper 标记色</li>
        </ol>
        <p>选 section 级而非 token 级,是为了贴合 PM Agent 的写入约束 — 它的修改本来就是 section 粒度。</p>
      </section>

      <section>
        <h2>切 rev 控件</h2>
        <p>顶部默认 "rev N vs rev N-1",可下拉切换:</p>
        <ul>
          <li>"rev 3 vs rev 0" — 看从 init 到现在的累积</li>
          <li>"rev 3 vs rev 2" — 默认</li>
          <li>"rev 3 only" — 单看本 rev 新增</li>
        </ul>
      </section>

      <section>
        <h2>影响 Unit 提示</h2>
        <p>每个 diff section 下方一行 <code>→ 影响 Unit: ...</code>。来源:</p>
        <pre class="code">unitRegistry.<span class="n">diffWithSDD</span>(pid)
<span class="c">// → { added: ['oauth-be','oauth-fe'], changed: [], removed: [] }</span></pre>
        <p>把 added/changed/removed 列表渲染在对应 diff 行下面,让人类一眼知道「这个反馈引发了哪几个 Unit 入队」。</p>
      </section>

    </article>
    <nav class="prev-next"></nav>
    <footer class="site"><div><b>Section</b>04 · Prototype</div><div><b>Page</b>proto-prd-diff.html</div></footer>
  </main>
</div>
<script src="assets/shell.js"></script>
</body>
</html>