Skip to content

Latest commit

 

History

History
383 lines (300 loc) · 14.2 KB

File metadata and controls

383 lines (300 loc) · 14.2 KB
feature_ids
F001
F002
F003
topics
architecture
maintenance
testing
release
github
gitcode
doc_kind guide
created 2026-07-25

维护与迭代指南

本文面向继续开发本项目的人,记录当前实现的模块边界、不可破坏的统计口径、常见改动的落点、验证方法和发布流程。

用户操作、Token 权限、统计口径及已知限制见 README.md。本文件与生产代码 index.html、生产代码测试 test.html 共同构成后续迭代的仓库内真相源。

1. 项目边界

当前交付物是一个可直接打开的静态单页应用:

  • 所有 HTML、CSS、JavaScript 和 favicon 都内联在 index.html
  • 无服务端、数据库、构建工具、运行时依赖或 CDN。
  • localStorage 只保存 Token、仓库和用户配置。
  • 当前查询投影只存在于页面内存;完整已合入 PR 在 http(s) 下按 PR 持久化到浏览器 IndexedDB,file:// 下使用页面内存缓存。
  • CSV 是统计结果的可移植持久交付物。
  • GitHub Pages 只托管静态文件;浏览器直接请求 GitHub / GitCode API。

除非需求明确改变产品形态,否则不要为局部功能引入后端、框架、第三方依赖或新的持久化服务。

当前发布基线

阶段 最终 SHA 浏览器测试 Review / 发布证据
F001 PR 代码变更统计 6523cc0 65 passed sol APPROVE
F002 Comments / Approve 与三类详情 b4b57a5 122 passed sol APPROVE,Pages 验收通过
最终 UI、导出诊断、Token 保存与隐私说明 876bec3 137 passed kimi APPROVE,Pages 验收通过
F003 已合入 PR 缓存与查询加速 b3b877a 222 passed kimi + Opus APPROVE;PR #1 已合入,Pages release gate open
完整性 bug 修复 + 分支配置 + since 优化 + 缓存清除 + 分支筛选 (pending) 254 passed Pages 部署中

本文创建时线上生产基线为 876bec3。后续发布应把新的最终 SHA、测试数量和线上验收结果补到本表或后续变更记录中。

2. 代码地图

index.html 仍是单文件,但 JavaScript 用固定 section comment 划分模块。查找这些标题即可定位:

Section 职责
Utilities HTML 转义、仓库 URL 解析、日期半开区间、并发限制器
Storage 版本化 localStorage 读写
CacheStore 版本化 merged PR cache;HTTP IndexedDB / file Memory 后端
ProviderRequestBudget 所有真实网络请求的平台级并发预算(GitHub 8 / GitCode 16)
CSV Helper RFC 4180 解析/生成、BOM、公式注入防护、下载
GitHub Provider 默认分支、merged PR、代码量、Comments、Reviews
GitCode Provider 默认分支、merged PR、代码量、Comments、当前有效 Approve
Statistics Engine 仓库去重、用户映射、活动聚合、筛选、完整性
Query Controller 查询编排、进度、取消、错误与部分统计传播
CSV Export 从当前可见投影导出汇总或明细
Token Management 保存、清除、测试并保存 Token
User CRUD / Repo Management 本地配置维护
Initialization 恢复配置、默认日期、事件绑定

主数据流:

localStorage(配置、用户)
  → collectFilters / buildRepoList
  → Provider.getDefaultBranch
  → Provider.fetchMergedPRs(仓库级发现 → PR cache hit / core hydration)
  → fetchCollaborationForPR(cache hit / Provider.fetchCollaboration → full-only cache write)
  → 规范化 activity
  → mapActivitiesToUsers
  → applyDisplayFilters
  → aggregate
  → 页面 / 汇总 CSV / 明细 CSV

页面和导出必须共享同一批筛选后的活动及汇总数据。不要在导出函数中另写一套业务筛选。

3. 持久化契约

配置使用两个版本化 localStorage Key:

code-statistics.config.v1
code-statistics.users.v1

等价数据形态:

// code-statistics.config.v1
{
  githubToken: "…",
  gitcodeToken: "…",
  repositories: [
    { url: "https://github.com/owner/repo", branch: "main" },
    { url: "https://gitcode.com/owner/repo", branch: "" }
    // 旧格式纯字符串仍兼容,normalizeRepoEntry() 自动迁移
  ]
}

// code-statistics.users.v1
[
  {
    user_key: "alice",
    display_name: "Alice",
    email: "alice@example.com",
    github_login: "alice-gh",
    gitcode_login: "alice-gc",
    enabled: true
  }
]

完整已合入 PR 使用 IndexedDB:

Database: code-statistics.pr-cache.v1
Object store: prs
Key: platform:repository-lowercase#pr-number
{
  schemaVersion: 1,
  cachedAt,
  platform,
  repository,
  prNumber,
  core,
  activities,       // raw activity;禁止 user_key / matched / display_name
  completeness: "full",
  partialReason: ""
}

缓存规则:

  1. 只有当前 schema、结构一致且 core/activities 全部为 full 的条目可命中。
  2. schema 不匹配、结构损坏、partial 或 failed 一律 miss;损坏/旧 schema 条目在读取时删除。
  3. 已合入 PR 的 core + collaboration 整体不设时间 TTL;产品明确不追踪少数 merge 后评论/审批变化。
  4. http(s) 使用 IndexedDB;初始化失败时降级为当前页面 Memory,不影响统计正确性。file:// 不尝试 IndexedDB。
  5. IndexedDB 写入只在 readwrite transaction complete 后返回成功。
  6. 用户资料不是 cache key;用户变化只重新投影当前 raw activities,不使 PR cache 失效。

演进规则:

  1. 新增可选字段时必须为旧数据提供默认值。
  2. 破坏性结构变更必须使用新 Key(如 .v2)并实现可回滚迁移。
  3. 迁移完整成功前不得覆盖或删除旧 Key。
  4. Token 不得进入 URL、日志、CSV 或错误详情;界面只显示掩码。
  5. 清除浏览器站点数据会清除全部配置与 PR cache,此行为必须继续在界面和 README 中说明。

4. Provider 契约

每个平台 Provider 都必须实现以下边界:

testConnection(token)
getDefaultBranch(token, owner, repo, signal)
fetchMergedPRs(token, owner, repo, defaultBranch, startDate, endDate, signal, onProgress, cacheStore?)
fetchCollaboration(token, owner, repo, pr, signal, onProgress)

fetchMergedPRs 返回:

{
  prs: [
    {
      platform, repo, number, title, author,
      mergedAt, baseBranch,
      additions, deletions, changedFiles,
      completeness, url
    }
  ],
  partial: false,
  partialReason: "",
  cacheHits: 0,
  networkPRs: 0
}

fetchCollaboration 返回:

{
  activities: [/* 规范化 activity */],
  partial: false,
  partialReason: ""
}

规范化 activity 的稳定字段:

{
  activity_type: "development" | "comment" | "approval",
  platform,
  repository,
  pr_number,
  pr_title,
  pr_url,
  merged_at,
  actor_login,
  user_key,
  matched,
  display_name,
  event_at,
  source_type,
  source_id,
  activity_url,
  body_summary,
  additions,
  deletions,
  changed_files,
  completeness: "full" | "partial" | "failed",
  partial_reason
}

新增平台时应先适配这两个返回结构,不要让平台特有字段泄漏到 StatsEngine

5. 统计不变量

下列规则属于产品契约,修改前必须先更新需求与测试:

  1. 只统计合入仓库默认分支的已合并 PR。
  2. 日期按用户本地日期解释,内部使用 [开始日 00:00, 结束日次日 00:00)
  3. 三类活动都随 PR 的 merged_at 归入查询周期。
  4. 用户归属只按 platform + actor_login 匹配;邮箱不参与归属。
  5. 禁用用户不参与匹配,未匹配账号保留为独立诊断行。
  6. 开发 PR 的代码量只归 PR 作者;Comment 和 Approve 不增加代码量。
  7. 变更行 = 新增行 + 删除行净增行 = 新增行 - 删除行
  8. GitHub Comment 来源包含 issue comment、review comment、非空 review body。
  9. GitHub Approve 取同一 PR、同一用户最后一个决定性 Review 状态。
  10. GitCode Approve 只表示查询时 accept === true 的当前有效状态。
  11. 不同来源按 activity_type + source_type + source_id 去重。
  12. 失败、限流、字段不可解析或 too_large 不得静默当作 0;必须传播为“部分”或“失败”。
  13. 同一查询每个仓库只执行一次 PR 发现流程;协作来源按每个入选 PR 拉取一次。
  14. 汇总页面、详情和两种 CSV 必须遵守相同的平台、用户、仓库及用户范围筛选。
  15. cache hit 必须是同 schema、同 PR identity 的完整条目;partial/failed 不能命中。
  16. 缓存只保存 raw activity;用户归属永远从当前 users 重新投影。
  17. 所有实际网络请求必须经过 Provider _fetch 的共享预算;PR 内部 fan-out 不得绕过 GitHub 8 / GitCode 16 上限。
  18. 进度完成数只在 cache hit 或网络任务 settle 后递增;最终标题和仓库行不得保留“正在获取”。

6. 安全边界

  • 所有 API 或用户输入写入 innerHTML 前必须经过 escapeHtml
  • 外部链接保持 target="_blank"rel="noopener"
  • CSV 文本继续通过 CsvHelper.sanitize 防止公式注入。
  • Token 只能放在认证请求头,不得放进 query string。
  • 不在仓库、截图、测试夹具或文档中写入真实 Token。
  • file:// 页面直接请求平台 API;新增网络目标时必须在配置页和 README 明示。
  • API 失败信息可以展示状态和平台返回摘要,但不得拼入认证请求头或 Token。

7. 常见迭代怎么改

新增一个平台

  1. 扩展 parseRepoUrl 和仓库平台展示。
  2. 增加 Token 配置、测试连接和版本化存储字段。
  3. 实现完整 Provider 契约,输出规范化 PR 与 activity。
  4. runQuery 中只增加 Provider 选择,不复制查询编排。
  5. 为用户模型增加该平台账号字段及 CSV 导入兼容。
  6. 增加分页、限流、字段缺失、部分失败和用户匹配测试。
  7. 更新 README 的权限、网络目标、口径和限制。

新增一种活动或指标

  1. 先定义归属用户、时间口径、去重键和完整性传播。
  2. Provider 只负责生成新的规范化 activity。
  3. StatsEngine.aggregate 增加聚合,不在 UI 临时计算业务口径。
  4. 同步汇总列、详情、CSV 字段和空态。
  5. 用固定夹具覆盖“只有该活动、没有开发 PR”的用户。

修改筛选或导出

  1. 优先修改 StatsEngine.applyDisplayFilters 或可见数据投影。
  2. 页面、详情和 CSV 都消费该投影。
  3. 至少覆盖 matched / all / unmatched × platform × user × repo
  4. 检查 partial/failed 诊断只跟随当前可见仓库,不生成空平台行。

修改本地数据结构

  1. 写旧数据加载测试。
  2. 增加迁移,不直接改变旧 Key 的语义。
  3. 验证刷新后配置仍在、失败迁移不丢数据。
  4. 更新本文件“持久化契约”和 README 的用户可见说明。

修改 PR cache

  1. 先修改 CACHE_SCHEMA_VERSION 与 entry validation 测试;不在旧 schema 上猜测兼容。
  2. 缓存只接受 full 数据,禁止为了命中率放宽 partial/failed 门禁。
  3. 不把 user_keymatcheddisplay_name 或 Token 写入 entry。
  4. IndexedDB mutation 必须等待 transaction complete;用 close → reopen 测试持久性。
  5. 同步 README 的协议边界与隐私披露。

修改 UI

  1. 保持“配置 / 用户信息 / 统计数据”三个一级页签。
  2. 保持单文件与无外部静态资源。
  3. 桌面优先,同时检查窄屏布局、键盘操作、空态和错误态。
  4. 若修改 DOM 标识或文案,同步 test.html 的生产 DOM 断言。

8. 测试与质量门禁

测试页通过隐藏 iframe 加载真实 index.html,不是复制生产函数。

启动本地静态服务器:

python3 -m http.server 8901 --bind 127.0.0.1

然后访问:

http://127.0.0.1:8901/test.html

F003 fresh-context 处置后的开发分支基线为 222 passed, 0 failed;新增行为时测试总数应增加,不应通过删除断言维持全绿。

静态检查:

sed -n '/^<script>$/,/^<\/script>$/p' index.html | sed '1d;$d' | node --check -
sed -n '/^<script>$/,/^<\/script>$/p' test.html | sed '1d;$d' | node --check -
git diff --check

行为变更采用红绿流程:

  1. test.html 增加能复现问题或表达新契约的失败断言。
  2. 确认旧生产代码失败。
  3. 修改 index.html
  4. 用同一断言确认转绿,再跑全部测试。

浏览器手工验收至少覆盖:

  • 成功测试 Token 后自动保存;失败测试不覆盖旧 Token。
  • 用户和仓库 CRUD,刷新页面后仍可恢复。
  • 日期、平台、用户、仓库、用户范围组合筛选。
  • 开发 PR / Comments / 审核 PR 三个详情标签及键盘操作。
  • 汇总和明细 CSV 与当前页面一致,且不含 Token。
  • 单仓库失败、部分统计、取消查询时其他状态不被伪装成完整。
  • 浏览器控制台无新增错误。

9. Review 与发布

任何代码或测试行为变更都需要非作者 Review,且 Review 必须覆盖准备发布的最终 SHA。

建议流程:

  1. 建立功能分支或隔离 checkout。
  2. 红测试 → 实现 → 全量测试 → 静态检查。
  3. 由非作者复核原始需求、完整 diff、测试和浏览器行为。
  4. Review 明确 APPROVE 后再合入或推送 main
  5. main 更新会触发 .github/workflows/deploy.yml
  6. Deploy to GitHub Pages 成功后,再检查线上页面包含本次变更。

查看部署:

gh run list --commit "$(git rev-parse HEAD)" --limit 5

线上地址:

https://mindfn.github.io/code-statistics/

部署成功不等于功能验收完成;至少做一次线上 smoke test。若 Actions 失败,线上仍是上一次成功版本。

10. 文档同步清单

每次迭代完成前逐项检查:

  • 用户操作、权限、口径或限制变化 → 更新 README.md
  • 模块边界、数据契约、扩展方式或门禁变化 → 更新本文件。
  • 生产行为变化 → 更新 test.html
  • API 行为变化 → 更新 Provider、失败传播测试及已知限制。
  • 发布后 → 记录最终 SHA、测试结果和线上验收证据。

docs/features/docs/discussions/feature-specs/ 已纳入版本控制;产品口径变更必须同步 feature truth,不能只改 README 或生产代码。