11 KiB
11 KiB
PRD:集合功能增强
一、问题分析
问题 1:集合详情页不显示已收录文章
页面:https://blog.ephron.ren/collections/data-structure
现象:集合详情页显示「该集合暂无文章」,但实际上已有文章被收录到该集合。
根因分析:
路由代码 blog/src/routes/pages.py 第 488-519 行:
for item in collection.get("items", []):
post = get_post_by_slug(item["post_slug"], include_drafts=False)
if post:
items.append({...})
可能原因:
blog_collection_items表中没有对应数据- 文章 slug 与集合中记录的
post_slug不匹配 - 文章是草稿状态但使用了
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:修复集合详情页文章显示
优先级:P0(Bug 修复)
验收标准:
- 访问
/collections/{key}能正确显示已收录的文章 - 文章按
sort_order排序显示 - 显示文章标题、摘要、备注
- 空集合显示「该集合暂无文章」
技术方案:
- 检查并修复
blog_collection_items表数据 - 确保
get_post_by_slug在包含草稿时能正确返回 - 添加日志排查 slug 匹配问题
需求 2:全部文章列表显示集合标记
优先级:P1(功能增强)
验收标准:
- 文章列表中,已收录到集合的文章显示集合标记
- 标记可点击,跳转到集合详情页
- 一篇文章可属于多个集合,显示所有集合标记
- 未收录到任何集合的文章不显示标记
UI 设计:
文章标题 📌 置顶
摘要内容...
2025-01-01 [标签1] [标签2] [集合A] [集合B] 草稿
集合标记样式:
- 背景色:
var(--accent-glow)(蓝色半透明) - 文字色:
var(--accent) - 圆角:
4px - 前缀图标:
📁或📚
技术方案:
- 在
pages.py的posts_list函数中,批量查询文章的集合归属 - 使用
get_all_collection_post_slugs()或更高效的批量查询 - 将集合信息传递给模板
- 模板中渲染集合标记
API 变更:
# 新增批量查询函数
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 设计:
<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>
技术方案:
admin.py的new_collection_page函数传递集合列表- 表单增加
collection_keys字段(数组) create_new_post函数处理集合关联- 调用
add_item_to_collection创建关联记录
API 变更:
# 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:
# POST /api/service/posts
{
"title": "文章标题",
"content": "...",
"tags": ["tag1"],
"collection_keys": ["col1", "col2"] # 新增
}
Prompt Service API:
# POST /api/service/prompts
{
"key": "prompt-key",
"title": "提示词标题",
"content": "...",
"collection_keys": ["col1", "col2"] # 新增
}
验收标准:
- API 支持
collection_keys参数 - 参数可选,默认为空数组
- 自动创建集合关联记录
- 集合不存在时忽略(不报错)
- 权限检查:需要对应集合的编辑权限
三、数据模型
Blog 集合表结构
-- 集合主表
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 集合表结构
-- 集合主表
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 1:Bug 修复(需求 1)
时间:0.5 天
任务:
- 检查
blog_collection_items表数据 - 修复数据不一致问题
- 验证集合详情页正常显示
Phase 2:全部文章显示集合标记(需求 2)
时间:1 天
任务:
- 实现
get_posts_collections()批量查询函数 - 修改
pages.py的posts_list函数 - 修改
index.html模板 - 测试多集合、空集合场景
Phase 3:新建时选择集合(需求 3)
时间:1.5 天
任务:
- Blog:修改
admin.py和new.html - Prompt:修改
admin.py和new.html - Blog API:修改 Service API 支持
collection_keys - Prompt API:修改 Service API 支持
collection_keys - 测试权限控制和边界场景
六、测试用例
需求 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 |
七、风险与依赖
风险
- 数据一致性:Blog 文章删除后,
blog_collection_items中的关联记录可能成为孤立数据 - 性能影响:全部文章列表需要额外查询集合信息,可能增加数据库压力
- 权限复杂性:创建文章时选择集合需要同时检查文章和集合的权限
依赖
- 需求 1 是需求 2 的前提(集合详情页必须能正常显示)
- 需求 3 依赖现有集合 CRUD 功能
- 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、重复关联)