477 lines
12 KiB
Markdown
477 lines
12 KiB
Markdown
# Home 页新增“开源贡献”板块与后台可编辑支持 PRD
|
||
|
||
## 背景
|
||
|
||
用户希望在 `https://www.ephron.ren/` 首页新增一个独立板块:**开源贡献**,并且该板块内容必须能够在 Home 后台中编辑、保存草稿、发布,不接受只改前台模板的静态实现。
|
||
|
||
本 PRD 基于 `origin/main` 最新源码分析,覆盖 Home 的:
|
||
- 公共渲染模板
|
||
- Admin 编辑模板
|
||
- content schema
|
||
- 草稿 / 发布链路
|
||
- 兼容策略
|
||
- 测试要求
|
||
|
||
---
|
||
|
||
## 现状分析
|
||
|
||
### 1. 首页当前内容结构
|
||
|
||
当前 Home 页公共模板位于:
|
||
- `home/templates/index.html`
|
||
|
||
当前页面主区块顺序大致为:
|
||
1. Hero
|
||
2. 工作经历
|
||
3. 项目经验
|
||
4. 技术栈
|
||
5. 页脚
|
||
6. 联系方式弹窗
|
||
|
||
其中内容类区块已经形成清晰模式:
|
||
- `experience`:时间线列表
|
||
- `projects`:时间线列表 + tags + 可选 badge
|
||
- `skills`:分类列表
|
||
|
||
### 2. Home 内容 schema 当前主结构
|
||
|
||
当前 `home/src/services/content.py` 中 HomeContent 及默认内容模板包含:
|
||
|
||
```python
|
||
hero
|
||
experience
|
||
projects
|
||
skills
|
||
contact
|
||
footer
|
||
```
|
||
|
||
当前**没有** `open_source` 或同义字段。
|
||
|
||
### 3. 后台编辑页当前主结构
|
||
|
||
后台模板位于:
|
||
- `home/templates/admin/index.html`
|
||
|
||
当前后台已提供以下可编辑区块:
|
||
- Hero
|
||
- 工作经历
|
||
- 项目经验
|
||
- 技术栈
|
||
- 联系方式
|
||
- 页脚
|
||
|
||
其 JS 通过 `initialContent` + 各类 `renderXxx()`、`addXxx()`、`updateXxx()`、`removeXxx()` 管理动态列表,再通过 `collectFormData()` 汇总为完整 `content_json`。
|
||
|
||
### 4. Draft / Publish 机制已存在
|
||
|
||
Home Admin 已支持:
|
||
- 保存草稿
|
||
- 发布内容
|
||
- 丢弃草稿
|
||
|
||
相关服务链路位于:
|
||
- `home/src/routes/admin.py`
|
||
- `home/src/services/content.py`
|
||
|
||
所以本次需求不应走“单独 API”或“静态 hardcode”路线,而应纳入现有 content schema。
|
||
|
||
---
|
||
|
||
## 问题定义
|
||
|
||
如果只是简单在前台首页插入一个“开源贡献”区块,会有以下问题:
|
||
|
||
1. **后台无法维护**
|
||
- 用户明确要求后台可修改
|
||
- 只改模板会让内容写死在代码里
|
||
|
||
2. **不进入草稿 / 发布流程**
|
||
- 无法像其他首页内容一样先保存草稿再发布
|
||
|
||
3. **与 Home 当前内容架构不一致**
|
||
- Home 当前是 schema 驱动 + admin 驱动
|
||
- 新区块也应遵循同样模式
|
||
|
||
4. **历史内容兼容问题**
|
||
- 线上已有 `content_json` 一定不包含新字段
|
||
- 如果不做 normalize,可能出现模板取值缺失或后台初始值异常
|
||
|
||
---
|
||
|
||
## 目标
|
||
|
||
### 产品目标
|
||
在首页新增一个独立的 **开源贡献** 板块,用于展示用户的开源贡献记录。
|
||
|
||
### 后台目标
|
||
管理员可在 Home 后台中:
|
||
- 新增开源贡献条目
|
||
- 编辑开源贡献条目
|
||
- 删除开源贡献条目
|
||
- 标记草稿 / 已发布条目(如果沿用当前列表编辑模式)
|
||
- 保存草稿
|
||
- 发布
|
||
|
||
### 技术目标
|
||
将“开源贡献”纳入 Home 的统一内容 schema,而不是写死在模板中。
|
||
|
||
---
|
||
|
||
## 核心设计判断
|
||
|
||
## 为什么建议新增独立 `open_source` 区块,而不是复用 `projects`
|
||
|
||
虽然“开源贡献”看起来和“项目经验”都属于列表,但我**不建议复用 `projects`**,原因如下:
|
||
|
||
1. **语义不同**
|
||
- 项目经验是个人项目 / 研究 / 比赛 /工程经历
|
||
- 开源贡献是对外部开源生态的参与记录
|
||
|
||
2. **展示重心不同**
|
||
- 项目经验偏“我做了什么项目”
|
||
- 开源贡献偏“我向哪些项目贡献了什么”
|
||
|
||
3. **后台认知更清晰**
|
||
- 管理员能清楚区分两类信息
|
||
- 避免未来在同一列表中混入不同语义的数据
|
||
|
||
4. **后续扩展更容易**
|
||
- 以后可独立增加 repo 链接、PR 链接、贡献类型、状态标签等
|
||
|
||
### 结论
|
||
**本次建议新增独立字段:`open_source`**
|
||
|
||
---
|
||
|
||
## 数据结构设计
|
||
|
||
### 建议新增主字段
|
||
|
||
在 Home content 顶层新增:
|
||
|
||
```json
|
||
"open_source": []
|
||
```
|
||
|
||
### 单条条目建议结构
|
||
|
||
建议最小结构如下:
|
||
|
||
```json
|
||
{
|
||
"title": "Hermes Agent",
|
||
"role": "提交 PR 修复 MiMo reasoning_content",
|
||
"date": "2026.05",
|
||
"description": [
|
||
"向上游提交并推动合并 MiMo reasoning_content 修复",
|
||
"补充兼容性验证与使用说明"
|
||
],
|
||
"tags": ["Python", "Hermes", "Open Source"],
|
||
"link": "https://github.com/NousResearch/hermes-agent/pull/25358",
|
||
"is_draft": false
|
||
}
|
||
```
|
||
|
||
### 字段说明
|
||
|
||
- `title`
|
||
- 开源项目名 / 仓库名 / 贡献对象名
|
||
- `role`
|
||
- 一句话说明贡献类型或身份
|
||
- 例如:修复 PR、功能贡献、文档维护、Issue triage
|
||
- `date`
|
||
- 贡献时间,沿用当前 Home 的字符串时间格式
|
||
- `description`
|
||
- 多条描述,后台可按“每行一条”编辑
|
||
- `tags`
|
||
- 技术标签或贡献类型标签
|
||
- `link`
|
||
- 对外链接,建议指向 PR / repo / profile / issue
|
||
- `is_draft`
|
||
- 若沿用现有列表项 draft 切换机制,则保留该字段
|
||
|
||
### 为什么建议有 `link`
|
||
|
||
因为“开源贡献”天然需要外部证明入口:
|
||
- GitHub PR
|
||
- 仓库主页
|
||
- 个人 Profile
|
||
|
||
如果没有链接,板块很容易退化成纯文字陈列。
|
||
|
||
---
|
||
|
||
## 服务层改造
|
||
|
||
### 必改文件
|
||
- `home/src/services/content.py`
|
||
|
||
### 要求
|
||
|
||
#### 1. 扩展默认 schema
|
||
在 `_get_empty_content()` 中新增:
|
||
|
||
```python
|
||
"open_source": []
|
||
```
|
||
|
||
#### 2. 扩展 normalize
|
||
在 `_normalize_content()` 中补:
|
||
|
||
```python
|
||
content.setdefault("open_source", [])
|
||
```
|
||
|
||
#### 3. 兼容性原则
|
||
旧内容没有 `open_source` 时:
|
||
- 首页应正常打开
|
||
- 后台应正常打开
|
||
- 不要求先清洗数据库历史内容
|
||
|
||
---
|
||
|
||
## 前台首页改造
|
||
|
||
### 必改文件
|
||
- `home/templates/index.html`
|
||
|
||
### 板块位置建议
|
||
建议插入在:
|
||
- **项目经验之后**
|
||
- **技术栈之前**
|
||
|
||
推荐顺序:
|
||
1. 工作经历
|
||
2. 项目经验
|
||
3. **开源贡献**
|
||
4. 技术栈
|
||
|
||
### 原因
|
||
|
||
1. 信息层级更合理
|
||
- 工作 / 项目 / 开源 属于“经历与实践”一组
|
||
- 技术栈更适合作为总结性能力列表放在后面
|
||
|
||
2. 开源贡献不应放到页脚附近
|
||
- 会显得像附属信息,而不是正式内容资产
|
||
|
||
### 渲染方式建议
|
||
|
||
建议复用当前 `timeline-item` 风格,保持页面一致性。
|
||
|
||
示意结构:
|
||
|
||
```jinja2
|
||
{% if content.open_source %}
|
||
<section class="section">
|
||
<h2 class="section-title">开源贡献</h2>
|
||
{% for item in content.open_source if not item.get('is_draft', False) %}
|
||
<div class="timeline-item">
|
||
<div class="timeline-header">
|
||
<div>
|
||
<h3 class="timeline-title">{{ item.title }}</h3>
|
||
<p class="timeline-company">{{ item.role }}</p>
|
||
</div>
|
||
<span class="timeline-date">{{ item.date }}</span>
|
||
</div>
|
||
<div class="timeline-content">
|
||
<ul>
|
||
{% for bullet in item.bullets %}
|
||
<li>{{ bullet }}</li>
|
||
{% endfor %}
|
||
</ul>
|
||
{% if item.tags %}
|
||
<div class="project-tags">
|
||
{% for tag in item.tags %}
|
||
<span class="project-tag">{{ tag }}</span>
|
||
{% endfor %}
|
||
</div>
|
||
{% endif %}
|
||
{% if item.link %}
|
||
<a href="{{ item.link }}" target="_blank" rel="noopener" class="project-badge project-badge-link">查看贡献</a>
|
||
{% endif %}
|
||
</div>
|
||
</div>
|
||
{% endfor %}
|
||
</section>
|
||
{% endif %}
|
||
```
|
||
|
||
### 说明
|
||
|
||
- 样式可直接复用 `timeline-item`、`project-tags`、`project-badge`
|
||
- 不建议本次重新发明一套视觉组件
|
||
- 重点是内容建模与后台可维护性,而不是视觉重构
|
||
|
||
---
|
||
|
||
## 后台管理页改造
|
||
|
||
### 必改文件
|
||
- `home/templates/admin/index.html`
|
||
|
||
### 建议新增一个完整 Section
|
||
在“项目经验”和“技术栈”之间新增:
|
||
|
||
- 板块标题:`开源贡献`
|
||
- 列表容器:`<div id="openSourceList"></div>`
|
||
- 添加按钮:`+ 添加开源贡献`
|
||
|
||
### 建议沿用现有动态列表编辑模式
|
||
即仿照:
|
||
- `renderProjects()`
|
||
- `addProject()`
|
||
- `removeProject()`
|
||
- `updateProject()`
|
||
- `toggleProjectDraft()`
|
||
|
||
新增一组:
|
||
- `renderOpenSource()`
|
||
- `addOpenSource()`
|
||
- `removeOpenSource(index)`
|
||
- `updateOpenSource(index, field, value)`
|
||
- `updateOpenSourceBullets(index, value)`
|
||
- `updateOpenSourceTags(index, value)`
|
||
- `toggleOpenSourceDraft(index)`(若保留每项草稿状态)
|
||
|
||
### 单条后台表单建议字段
|
||
|
||
- 项目 / 仓库名称(title)
|
||
- 贡献角色 / 一句话说明(role)
|
||
- 时间(date)
|
||
- 描述(每行一条)
|
||
- 标签(逗号分隔)
|
||
- 外部链接(link)
|
||
|
||
### collectFormData 必须同步补充
|
||
|
||
```js
|
||
open_source: initialContent.open_source,
|
||
```
|
||
|
||
否则后台加了 UI 也不会进入 `content_json`。
|
||
|
||
---
|
||
|
||
## 命名一致性要求
|
||
|
||
当前代码中存在一个值得注意的事实:
|
||
- 前台项目区渲染使用的是 `project.bullets`
|
||
- 但示例数据文件中很多项目仍然是 `description`
|
||
|
||
这说明 Home 当前已有一定字段漂移历史。
|
||
|
||
### 本次 PRD 的要求
|
||
对于“开源贡献”,字段命名必须从一开始就统一,不要再制造第二套字段名。
|
||
|
||
建议直接统一使用:
|
||
- `bullets` 作为前台 / 后台 / 存储字段名
|
||
|
||
而不是:
|
||
- 后台叫 `description`
|
||
- 前台叫 `bullets`
|
||
- 示例数据再写成第三种
|
||
|
||
### 结论
|
||
**开源贡献条目统一使用 `bullets`,不要引入 `description`。**
|
||
|
||
---
|
||
|
||
## 测试要求
|
||
|
||
### 必改文件
|
||
- `home/tests/test_admin_permissions.py`
|
||
或 Home 对应测试文件
|
||
|
||
### 建议至少补 4 类测试
|
||
|
||
#### 1. Admin 渲染测试
|
||
后台页面应出现:
|
||
- `openSourceList`
|
||
- `添加开源贡献`
|
||
- 对应字段输入结构
|
||
|
||
#### 2. 首页渲染测试
|
||
当 `open_source` 有已发布数据时:
|
||
- 首页应显示 `开源贡献` 标题
|
||
- 应显示条目标题 / 链接
|
||
|
||
#### 3. 空列表隐藏测试
|
||
当 `open_source` 为空时:
|
||
- 首页不应显示空板块
|
||
|
||
#### 4. 旧 schema 兼容测试
|
||
当历史内容没有 `open_source` 字段时:
|
||
- 首页正常打开
|
||
- 后台正常打开
|
||
|
||
### 可选补充
|
||
如果你们继续沿用每项 `is_draft`:
|
||
- 测试首页不会渲染 `open_source` 中 `is_draft=true` 的条目
|
||
|
||
---
|
||
|
||
## 验收标准
|
||
|
||
### 前台
|
||
1. 首页新增 `开源贡献` 板块
|
||
2. 板块位于“项目经验”之后、“技术栈”之前
|
||
3. 存在数据时正常渲染条目
|
||
4. 条目链接可打开外部页面
|
||
5. 无数据时不显示空板块
|
||
|
||
### 后台
|
||
1. 管理页新增“开源贡献”编辑区块
|
||
2. 支持新增 / 编辑 / 删除条目
|
||
3. 保存草稿后刷新后台可回显
|
||
4. 发布后首页可见
|
||
5. 丢弃草稿后未发布修改可撤销
|
||
|
||
### 兼容性
|
||
1. 历史 `content_json` 没有 `open_source` 字段时不报错
|
||
2. 不要求先手工迁移历史数据库内容
|
||
|
||
---
|
||
|
||
## 非目标
|
||
|
||
本次 PRD 不包含:
|
||
- 从 GitHub API 自动拉取开源贡献
|
||
- 统计贡献数量、Star、PR 数等自动指标
|
||
- 把开源贡献和项目经验合并
|
||
- 新增单独的 Home Service API
|
||
- 重做首页视觉风格
|
||
|
||
---
|
||
|
||
## 实施顺序建议
|
||
|
||
1. 先改 `home/src/services/content.py`
|
||
- schema 默认值
|
||
- normalize 兼容
|
||
2. 再改 `home/templates/admin/index.html`
|
||
- 新区块 UI
|
||
- 新增 JS 列表管理逻辑
|
||
- 更新 `collectFormData()`
|
||
3. 最后改 `home/templates/index.html`
|
||
- 新区块渲染
|
||
4. 补测试
|
||
|
||
这样可以避免先改模板后 schema 未补齐导致的半更新问题。
|
||
|
||
---
|
||
|
||
## 结论
|
||
|
||
“开源贡献”不是单纯新增一段 HTML,而是一个完整的 **Home 内容模型扩展**。
|
||
|
||
要满足“前台显示 + 后台可改 + 草稿发布 + 历史兼容”,最小闭环必须同时覆盖:
|
||
- schema
|
||
- normalize
|
||
- admin 区块
|
||
- 前台渲染
|
||
- 测试
|
||
|
||
建议采用独立 `open_source` 列表区块,而不是复用 `projects`。这样语义更清晰,也更利于后续继续扩展你的开源履历展示。 |