Files
ephron-ren-prd/prd-collection-enhancements.md

390 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PRD集合功能增强
## 一、问题分析
### 问题 1集合详情页不显示已收录文章
**页面**`https://blog.ephron.ren/collections/data-structure`
**现象**:集合详情页显示「该集合暂无文章」,但实际上已有文章被收录到该集合。
**根因分析**
路由代码 `blog/src/routes/pages.py` 第 488-519 行:
```python
for item in collection.get("items", []):
post = get_post_by_slug(item["post_slug"], include_drafts=False)
if post:
items.append({...})
```
可能原因:
1. `blog_collection_items` 表中没有对应数据
2. 文章 slug 与集合中记录的 `post_slug` 不匹配
3. 文章是草稿状态但使用了 `include_drafts=False`
**需要验证**:查询数据库确认 `blog_collection_items` 表是否有数据。
---
### 问题 2全部文章列表不显示集合归属
**页面**`https://blog.ephron.ren/posts`
**现象**:文章列表只显示置顶、日期、标签、草稿标记,不显示文章所属的集合。
**用户期望**:已收录到集合的文章应在全部文章列表中显示集合标记(类似标签),方便识别哪些文章已被组织到集合中。
---
### 问题 3新建文章/提示词时无法选择集合
**页面**
- Blog`https://blog.ephron.ren/admin/new`
- Prompt`https://prompt.ephron.ren/admin/new`
**现象**:新建文章/提示词时,只能先创建内容,再手动编辑集合添加。
**用户期望**:创建时即可选择加入已有集合,提升内容组织效率。
---
## 二、需求详情
### 需求 1修复集合详情页文章显示
**优先级**P0Bug 修复)
**验收标准**
- [ ] 访问 `/collections/{key}` 能正确显示已收录的文章
- [ ] 文章按 `sort_order` 排序显示
- [ ] 显示文章标题、摘要、备注
- [ ] 空集合显示「该集合暂无文章」
**技术方案**
1. 检查并修复 `blog_collection_items` 表数据
2. 确保 `get_post_by_slug` 在包含草稿时能正确返回
3. 添加日志排查 slug 匹配问题
---
### 需求 2全部文章列表显示集合标记
**优先级**P1功能增强
**验收标准**
- [ ] 文章列表中,已收录到集合的文章显示集合标记
- [ ] 标记可点击,跳转到集合详情页
- [ ] 一篇文章可属于多个集合,显示所有集合标记
- [ ] 未收录到任何集合的文章不显示标记
**UI 设计**
```
文章标题 📌 置顶
摘要内容...
2025-01-01 [标签1] [标签2] [集合A] [集合B] 草稿
```
集合标记样式:
- 背景色:`var(--accent-glow)`(蓝色半透明)
- 文字色:`var(--accent)`
- 圆角:`4px`
- 前缀图标:`📁``📚`
**技术方案**
1.`pages.py``posts_list` 函数中,批量查询文章的集合归属
2. 使用 `get_all_collection_post_slugs()` 或更高效的批量查询
3. 将集合信息传递给模板
4. 模板中渲染集合标记
**API 变更**
```python
# 新增批量查询函数
def get_posts_collections(post_slugs: list[str]) -> dict[str, list[dict]]:
"""
批量查询多篇文章的集合归属
返回: {post_slug: [{key, title}, ...]}
"""
```
---
### 需求 3新建文章/提示词时选择集合
**优先级**P1功能增强
#### 3.1 Blog 新建文章
**页面**`/admin/new`
**验收标准**
- [ ] 新建文章表单增加「选择集合」下拉框
- [ ] 支持多选(可加入多个集合)
- [ ] 显示集合名称和已有文章数量
- [ ] 提交时自动创建 `blog_collection_items` 记录
- [ ] 权限控制:需要 `blog.post.create_draft` 权限
**UI 设计**
```html
<div class="form-group">
<label>加入集合(可选)</label>
<select name="collection_keys" multiple class="input">
<option value="">-- 不加入集合 --</option>
<option value="data-structure">数据结构 (5篇)</option>
<option value="algorithm">算法 (3篇)</option>
</select>
<span class="hint">按住 Ctrl/Cmd 可多选</span>
</div>
```
**技术方案**
1. `admin.py``new_collection_page` 函数传递集合列表
2. 表单增加 `collection_keys` 字段(数组)
3. `create_new_post` 函数处理集合关联
4. 调用 `add_item_to_collection` 创建关联记录
**API 变更**
```python
# POST /admin/new 新增字段
collection_keys: list[str] = Form(default=[]) # 集合 key 列表
```
#### 3.2 Prompt 新建提示词
**页面**`/admin/new`
**验收标准**
- [ ] 新建提示词表单增加「选择集合」下拉框
- [ ] 支持多选
- [ ] 提交时自动创建 `collection_items` 记录
- [ ] 权限控制:需要 `prompt.create` 权限
**技术方案**:同 Blog修改 Prompt 服务的 `admin.py` 和相关模板。
#### 3.3 API 创建文章/提示词
**Blog Service API**
```python
# POST /api/service/posts
{
"title": "文章标题",
"content": "...",
"tags": ["tag1"],
"collection_keys": ["col1", "col2"] # 新增
}
```
**Prompt Service API**
```python
# POST /api/service/prompts
{
"key": "prompt-key",
"title": "提示词标题",
"content": "...",
"collection_keys": ["col1", "col2"] # 新增
}
```
**验收标准**
- [ ] API 支持 `collection_keys` 参数
- [ ] 参数可选,默认为空数组
- [ ] 自动创建集合关联记录
- [ ] 集合不存在时忽略(不报错)
- [ ] 权限检查:需要对应集合的编辑权限
---
## 三、数据模型
### Blog 集合表结构
```sql
-- 集合主表
CREATE TABLE blog_collections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
description TEXT DEFAULT '',
cover_image TEXT DEFAULT '',
created_by TEXT,
is_active INTEGER DEFAULT 1,
created_at DATETIME DEFAULT (datetime('now')),
updated_at DATETIME DEFAULT (datetime('now'))
);
-- 集合关联表
CREATE TABLE blog_collection_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
collection_key TEXT NOT NULL,
post_slug TEXT NOT NULL,
sort_order INTEGER DEFAULT 0,
note TEXT DEFAULT '',
created_at DATETIME DEFAULT (datetime('now')),
FOREIGN KEY (collection_key) REFERENCES blog_collections(key) ON DELETE CASCADE,
UNIQUE(collection_key, post_slug)
);
```
### Prompt 集合表结构
```sql
-- 集合主表
CREATE TABLE collections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
key TEXT UNIQUE NOT NULL,
title TEXT NOT NULL,
description TEXT DEFAULT '',
created_by TEXT,
is_active INTEGER DEFAULT 1,
created_at DATETIME DEFAULT (datetime('now')),
updated_at DATETIME DEFAULT (datetime('now'))
);
-- 集合关联表
CREATE TABLE collection_items (
id INTEGER PRIMARY KEY AUTOINCREMENT,
collection_key TEXT NOT NULL,
prompt_key TEXT NOT NULL,
sort_order INTEGER DEFAULT 0,
note TEXT DEFAULT '',
created_at DATETIME DEFAULT (datetime('now')),
FOREIGN KEY (collection_key) REFERENCES collections(key) ON DELETE CASCADE,
UNIQUE(collection_key, prompt_key)
);
```
---
## 四、与 Prompt 集合逻辑的差异
| 特性 | Blog 集合 | Prompt 集合 |
|------|----------|------------|
| 内容类型 | 文章Markdown | 提示词(模板) |
| 主键 | `post_slug`(文件名) | `prompt_key`(数据库 key |
| 创建方式 | 文件系统扫描 | 数据库插入 |
| 集合显示 | 需求2全部文章列表显示集合标记 | 已有:全部提示词列表显示集合标记 |
| 创建时选择集合 | 需求3新建时可选 | 需求3新建时可选 |
**关键差异**
- Blog 文章是文件系统驱动,集合关联是后加的
- Prompt 提示词是数据库驱动,集合关联是原生支持
---
## 五、实施计划
### Phase 1Bug 修复(需求 1
**时间**0.5 天
**任务**
1. [ ] 检查 `blog_collection_items` 表数据
2. [ ] 修复数据不一致问题
3. [ ] 验证集合详情页正常显示
### Phase 2全部文章显示集合标记需求 2
**时间**1 天
**任务**
1. [ ] 实现 `get_posts_collections()` 批量查询函数
2. [ ] 修改 `pages.py``posts_list` 函数
3. [ ] 修改 `index.html` 模板
4. [ ] 测试多集合、空集合场景
### Phase 3新建时选择集合需求 3
**时间**1.5 天
**任务**
1. [ ] Blog修改 `admin.py``new.html`
2. [ ] Prompt修改 `admin.py``new.html`
3. [ ] Blog API修改 Service API 支持 `collection_keys`
4. [ ] Prompt API修改 Service API 支持 `collection_keys`
5. [ ] 测试权限控制和边界场景
---
## 六、测试用例
### 需求 1 测试
| 编号 | 测试内容 | 预期结果 |
|------|---------|---------|
| T-001 | 访收录有文章的集合详情页 | 显示文章列表 |
| T-002 | 访问空集合详情页 | 显示「该集合暂无文章」 |
| T-003 | 文章排序 | 按 sort_order 升序 |
| T-004 | 草稿文章 | 不显示(公开页) |
### 需求 2 测试
| 编号 | 测试内容 | 预期结果 |
|------|---------|---------|
| T-010 | 已收录文章显示集合标记 | 显示蓝色标记 |
| T-011 | 未收录文章 | 不显示集合标记 |
| T-012 | 点击集合标记 | 跳转到集合详情页 |
| T-013 | 文章属于多个集合 | 显示多个标记 |
| T-014 | 搜索结果中显示 | 同样显示集合标记 |
### 需求 3 测试
| 编号 | 测试内容 | 预期结果 |
|------|---------|---------|
| T-020 | Blog 新建选择集合 | 自动关联到集合 |
| T-021 | Blog 新建不选集合 | 正常创建,不关联 |
| T-022 | Blog API 带 collection_keys | 自动关联 |
| T-023 | Prompt 新建选择集合 | 自动关联到集合 |
| T-024 | Prompt API 带 collection_keys | 自动关联 |
| T-025 | 集合 key 不存在 | 忽略,不报错 |
| T-026 | 权限不足 | 返回 403 |
---
## 七、风险与依赖
### 风险
1. **数据一致性**Blog 文章删除后,`blog_collection_items` 中的关联记录可能成为孤立数据
2. **性能影响**:全部文章列表需要额外查询集合信息,可能增加数据库压力
3. **权限复杂性**:创建文章时选择集合需要同时检查文章和集合的权限
### 依赖
1. 需求 1 是需求 2 的前提(集合详情页必须能正常显示)
2. 需求 3 依赖现有集合 CRUD 功能
3. Blog 和 Prompt 服务的集合逻辑独立,可并行开发
---
## 八、相关代码位置
### Blog 服务
- 集合详情路由:`blog/src/routes/pages.py` 第 488-519 行
- 文章列表路由:`blog/src/routes/pages.py` 第 120-160 行
- Admin 新建路由:`blog/src/routes/admin.py` 第 431-497 行
- Service API 路由:`blog/src/routes/service_api.py`
- 集合服务层:`blog/src/services/blog_collections.py`
- 集合详情模板:`blog/templates/collection_detail.html`
- 文章列表模板:`blog/templates/index.html`
- Admin 新建模板:`blog/templates/admin/new.html`
### Prompt 服务
- Admin 新建路由:`prompt/src/routes/admin.py`
- Service API 路由:`prompt/src/routes/service_api.py`
- 集合服务层:`prompt/src/services/collections.py`
- Admin 新建模板:`prompt/templates/admin/new.html`
---
## 九、验收标准汇总
- [ ] 集合详情页正确显示已收录文章
- [ ] 全部文章列表显示集合标记
- [ ] 新建文章时可选择加入集合
- [ ] 新建提示词时可选择加入集合
- [ ] API 创建支持 `collection_keys` 参数
- [ ] 权限控制正确
- [ ] 边界场景处理(空集合、不存在的 key、重复关联