PROJECT_SPEC

这是仓库内的需求与口径文档(原文:docs/PROJECT_SPEC.md)。

# zjutjh 个人贡献看板(今年)- 项目需求与实现规格

## 1. 背景与目标

做一个**每个人都可以查看自己**在 GitHub 组织 `zjutjh` 下仓库的代码贡献情况的 Web 应用,即使该用户**不是组织成员**也可以使用(前提:对私有仓库必须由用户本人授权且拥有访问权限)。

本项目只覆盖“今年”(按 `Asia/Shanghai` 时区切年)。

## 2. 范围(MVP)

### 2.1 支持的贡献类型

- **Commit 贡献(所有分支)**
  - 时间口径:按 `committedDate` 统计今年范围内的提交
  - 分支口径:统计仓库 `refs/heads/*` 下所有分支
  - 去重:同一提交 `SHA(oid)` 在多个分支出现只计一次
  - 排除:**不计入 merge commit**(`parents > 1`)
- **PR 贡献**
  - 口径:今年内创建的 PR 数量(唯一 PR)
- **Code Review 贡献**
  - 口径:今年内“review 过的 PR 数量”(按 `pullRequest.id` 去重,不按 review 次数)

### 2.2 不在 MVP 范围

- Issue 贡献与 Issue/PR 评论统计
- 组织内排行榜/对比(仅“只看自己”)
- 基于代码内容的 AI 代码质量点评(本期只发送统计)

## 3. 权限与隐私

### 3.1 私有仓库访问边界

- 私有仓库数据只能来自**用户自己的 GitHub OAuth 授权**,且仅统计该用户 Token **可访问**的 `zjutjh/*` 仓库。

### 3.2 AI 数据边界(豆包)

- AI 点评只发送**统计/聚合指标**(纯数字 + 少量枚举),**不发送**仓库名、PR 标题/描述、链接、代码、diff、文件名等任何可能暴露私有信息的内容。

## 4. 交互与页面(MVP)

- 登录:GitHub OAuth 登录
- Dashboard(默认 org=`zjutjh`,默认今年)
  - 总览卡片:Commits / PRs / Reviewed PRs
  - 趋势图:按周聚合(今年每周)
  - Top Repos:按贡献量排序(支持切换指标)
  - 仓库明细表:每仓库三项指标
  - Commit 扫描进度:异步任务进度条(仓库/分支级进度)
  - AI 点评:展示一段中文总结 + 3-5 条建议(仅基于统计)

## 5. 数据来源与计算口径

### 5.1 仓库清单(含私有)

以“用户视角”拉取最稳:

- GitHub REST:`GET /user/repos?visibility=all&affiliation=collaborator,organization_member,owner&per_page=100&page=n`
- 过滤:`repo.owner.login === "zjutjh"`

### 5.2 PR / Review(推荐 GraphQL)

- GraphQL:`viewer.contributionsCollection(organizationID, from, to)`
  - PR:遍历 `pullRequestContributions` 得到 PR 列表并计数/按仓库聚合/按周聚合
  - Review:遍历 `pullRequestReviewContributions`,对 `pullRequest.id` 去重得到“review 过的 PR 数”

### 5.3 Commit(所有分支 + 去 merge)

对每个可访问仓库:

1. 列出分支 `refs/heads/*`(GraphQL `repository.refs(refPrefix: "refs/heads/")`)
2. 用分支 tip `committedDate` 过滤:tip < yearStart(UTC)直接跳过该分支
3. 对剩余分支:
   - `ref(name).target... on Commit { history(since, until, author:{id/emails}) { nodes { oid committedDate parents { totalCount } } } }`
4. 规则:
   - `parents.totalCount > 1` 视为 merge commit,丢弃
   - 其余按 `oid` 做 Set 去重后计数
   - 以 `committedDate` 做周聚合(按 Asia/Shanghai 分桶)

> 注意:作者匹配优先使用 `emails`(来自 `GET /user/emails` 的已验证邮箱);避免仅用 userId 导致漏统计。

## 6. 技术栈(定稿)

- Web:Next.js(App Router)+ React + TypeScript
- UI:Tailwind CSS + shadcn/ui(可选)+ ECharts
- 认证:Auth.js/NextAuth(GitHub OAuth)
- GitHub API:Octokit(REST + GraphQL)+ throttling/retry
- 异步任务:BullMQ + Redis
- 数据库:PostgreSQL + Prisma
- AI:豆包(火山方舟 Ark)OpenAI 兼容接口
- 部署:Docker Compose(web + worker + postgres + redis)

## 7. 关键后端接口(建议)

- `POST /api/snapshots/recompute`:触发今年快照计算(返回 jobId)
- `GET /api/jobs/:id`:查询任务进度/状态
- `GET /api/snapshots/current`:获取今年快照(若无则返回需要 recompute)
- `POST /api/ai/commentary`:对当前快照生成 AI 点评(只基于统计)

## 8. AI 点评输出规范(只发送统计)

输入:`InsightMetrics`(纯统计指标)

输出:结构化 JSON(便于渲染与缓存)

```json
{
  "summary": "…",
  "highlights": ["…"],
  "risks": ["…"],
  "actions": ["…"],
  "confidence": 0.0
}
```

校验:服务端用 schema 校验;不合法则重试一次;仍失败则降级模板文案。

## 9. 配置(环境变量)

### GitHub OAuth

- `GITHUB_CLIENT_ID`
- `GITHUB_CLIENT_SECRET`
- `NEXTAUTH_URL`
- `NEXTAUTH_SECRET`

### 数据库/队列

- `DATABASE_URL`(Postgres)
- `REDIS_URL`

### 豆包(火山方舟 Ark)

- `ARK_API_KEY`
- `ARK_BASE_URL`(默认:`https://ark.cn-beijing.volces.com/api/v3`)
- `ARK_ENDPOINT_ID`(`ep-...`,作为 model 传入)
- `AI_TIMEOUT_MS`(可选)
- `AI_MAX_RETRIES`(可选,默认 2)