Initial commit: RSS platform phase 1 skeleton with code review fixes
Features: - FastAPI + SQLAlchemy 2.0 async + PostgreSQL/pgvector + Redis backend - Vue 3 + TypeScript + Element Plus frontend - JWT auth with access/refresh tokens and revocation - Admin/member RBAC - RSS feed CRUD and article listing - Settings management with Fernet encryption for sensitive values - Redis distributed lock service - Alembic initial migration - Docker Compose development environment Fixes from code review: - Fix DB session leak in dependency injection - Restrict registration to admin only - Add default admin password warning - Implement JWT refresh tokens and jti blacklist - Strengthen password policy - Use func.count for pagination totals - Replace NullPool with AsyncAdaptedQueuePool - Remove init_db from lifespan to enforce alembic migrations - Add request_id middleware and logging filter - Fix vite.config.ts env loading - Add frontend token refresh interceptor - Add Vue error handler Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,390 @@
|
||||
# RSS 平台代码审核报告
|
||||
|
||||
- 审核对象:`/home/congsh/workspace/dev/rssWorkFlow`
|
||||
- 技术栈:FastAPI + Vue 3 + PostgreSQL + Redis + MinIO
|
||||
- 审核范围:后端核心 / API / 模型 / 服务 / 前端 / 部署配置
|
||||
- 评级标准:P0(必须立即修复) / P1(生产前修复) / P2(建议优化)
|
||||
|
||||
---
|
||||
|
||||
## 一、P0:严重缺陷(必须立即修复)
|
||||
|
||||
### 1. 数据库会话资源泄露
|
||||
|
||||
`backend/app/api/deps.py:18-21`
|
||||
|
||||
```python
|
||||
async def get_db() -> AsyncSession:
|
||||
async for session in _get_db():
|
||||
return session
|
||||
```
|
||||
|
||||
`_get_db()` 是 `async generator`,正常依赖注入会通过 `yield` 让 FastAPI 接管 session 生命周期。但这里用 `async for` + `return`,`finally` 中的 `await session.close()` 永远不会被执行,session 一直被占用,连接池最终耗尽。
|
||||
|
||||
修复:
|
||||
|
||||
```python
|
||||
async def get_db():
|
||||
async for session in _get_db():
|
||||
yield session
|
||||
```
|
||||
|
||||
或者直接复用 `database.py:23` 的 `get_db`,避免二次包装。
|
||||
|
||||
### 2. `/auth/register` 接口存在越权
|
||||
|
||||
`backend/app/api/v1/auth.py:16-40`
|
||||
|
||||
- 任何未登录用户都可调用注册接口
|
||||
- `UserCreate.role` 未做限制,可直接传 `"admin"` 创建管理员账号
|
||||
|
||||
修复:在 `register` 加上 `current_user: User = Depends(get_current_admin)`,或对 `role` 字段做白名单(普通用户只能注册 `member`),并限制注册端点的访问(首次部署后关闭或改为邀请制)。
|
||||
|
||||
### 3. 默认管理员弱口令 + 凭证入仓
|
||||
|
||||
- `.env` 与 `.env.example` 内容完全一致,且包含 `SECRET_KEY=change-me-...` 和 `DEFAULT_ADMIN_PASSWORD=admin`
|
||||
- `.env` 已存在本地仓库(虽然 `.gitignore` 写了 `.env`,但若曾误提交则泄露)
|
||||
- `main.py:40-58` 启动时如果无用户则创建 `admin/admin`,且无强制改密流程
|
||||
|
||||
修复:
|
||||
1. 在 `main.py:40-58` 增加「首次启动时检查默认密码,若仍为 `admin/admin` 则在 health 端点暴露 warning」
|
||||
2. 增加「首次登录强制修改密码」逻辑
|
||||
3. 仓库 `.env` 不可提交任何真实凭证;CI 校验 `SECRET_KEY` 不能等于占位值
|
||||
|
||||
### 4. JWT 设计与刷新机制缺失
|
||||
|
||||
`backend/app/core/auth.py`
|
||||
|
||||
- 无 refresh token
|
||||
- `ACCESS_TOKEN_EXPIRE_MINUTES=480`(8 小时)过长且无续签
|
||||
- payload 没有 `iat` / `jti`,无主动吊销机制(用户被禁后 token 仍可用 8 小时)
|
||||
- payload 中带 `role` 字段(`auth.py:68`)后端已查 DB 重新加载,覆盖逻辑没问题,但字段冗余且易引发误解
|
||||
|
||||
修复:拆分 access (15min) + refresh (7d) + 引入 `jti` 维护吊销集合(Redis 黑名单)。
|
||||
|
||||
---
|
||||
|
||||
## 二、P1:安全风险(生产前需修复)
|
||||
|
||||
### 5. CORS dev fallback 使用通配
|
||||
|
||||
`backend/main.py:78-85`
|
||||
|
||||
```python
|
||||
else:
|
||||
app.add_middleware(CORSMiddleware, allow_origins=["*"], ...)
|
||||
```
|
||||
|
||||
只要 `CORS_ALLOWED_ORIGINS` 为空就放开 `*`,生产环境如果忘记配置即全放开。`allow_credentials=False` 缓解了,但 `allow_methods=["*"]` + `allow_headers=["*"]` 仍过于宽松。
|
||||
|
||||
修复:开发态也强制要求配置 `CORS_ALLOWED_ORIGINS`,缺失时启动失败或显式 `WARNING`。
|
||||
|
||||
### 6. 密码强度弱
|
||||
|
||||
`backend/app/schemas/user.py:16`
|
||||
|
||||
```python
|
||||
password: str = Field(..., min_length=6, max_length=128)
|
||||
```
|
||||
|
||||
6 位纯数字即可。
|
||||
|
||||
修复:最少 8/10 位 + 至少字母+数字的复杂度校验。
|
||||
|
||||
### 7. 缺少登录限流与审计
|
||||
|
||||
- 无失败次数限制(存在暴力破解风险)
|
||||
- 无登录/关键操作审计日志
|
||||
|
||||
修复:基于 Redis 接入 slowapi 或自实现 IP+用户维度限流;关键操作(改密、改 admin、删除 feed)落审计表。
|
||||
|
||||
### 8. 敏感设置未加密落库
|
||||
|
||||
`backend/app/services/settings_service.py:105-133`
|
||||
|
||||
非 admin 调用 `list_settings(mask_sensitive=True)` 时返回 `real_value=null`,逻辑正确。但 `OPENAI_API_KEY` 等敏感值在 `apply_db_settings_to_config` 写入内存时是明文——OK;问题是未在 settings_service 中对 `value` 做加密落库,DB 泄露即明文 API Key 泄露。
|
||||
|
||||
修复:使用 `cryptography.fernet` 加密存储敏感设置。
|
||||
|
||||
### 9. RSS Feed URL 缺少 SSRF 防护
|
||||
|
||||
`feed.py:15` `String(2048)` 看似够用,但 `HttpUrl` 在 `feed.py:8` 校验仅做 URL 格式校验,没有 `https://` 强制,没有 `SSRF` 防护(后端抓取时可能请求内网地址)。
|
||||
|
||||
修复:抓取时强制 `https`/`http`,并维护 IP 黑名单或代理出口策略。
|
||||
|
||||
---
|
||||
|
||||
## 三、P1:性能与正确性
|
||||
|
||||
### 10. 分页计数全量拉取
|
||||
|
||||
`backend/app/api/v1/feeds.py:39-40` 与 `articles.py:40-41`
|
||||
|
||||
```python
|
||||
count_result = await db.execute(select(Feed.id).select_from(query.subquery()))
|
||||
total = len(count_result.scalars().all())
|
||||
```
|
||||
|
||||
把每条 ID 都取回 Python 再 `len()`,表大时是灾难。应该用 `func.count()`:
|
||||
|
||||
```python
|
||||
from sqlalchemy import func
|
||||
count_query = select(func.count()).select_from(query.subquery())
|
||||
total = (await db.execute(count_query)).scalar_one()
|
||||
```
|
||||
|
||||
### 11. 数据库连接池策略不当
|
||||
|
||||
`backend/app/core/database.py:7-12`
|
||||
|
||||
```python
|
||||
engine = create_async_engine(..., poolclass=NullPool)
|
||||
```
|
||||
|
||||
`NullPool` 适合 serverless/单次执行,但 Docker 长驻服务中会每次请求都创建/销毁 Postgres 连接,TPS 高时延显著。应改为默认 `AsyncAdaptedQueuePool`(带 `pool_size` + `max_overflow`)。
|
||||
|
||||
### 12. lifespan 中 init_db 与 alembic 冲突
|
||||
|
||||
`backend/main.py:24`
|
||||
|
||||
```python
|
||||
await init_db() # Base.metadata.create_all
|
||||
```
|
||||
|
||||
启动时用 `create_all` 自动建表,会绕过 alembic 迁移;表结构偏离后将无法再用 `alembic upgrade` 演进。
|
||||
|
||||
修复:移除 `init_db()` 调用,统一通过 `make migrate` 走 alembic。`init_default_settings` 也应在迁移脚本或独立 seed 任务中执行。
|
||||
|
||||
### 13. 数据库迁移命名不合规
|
||||
|
||||
`backend/alembic/versions/001_initial_schema.py`
|
||||
|
||||
Alembic 推荐 `xxxxxx_initial_schema.py` 哈希前缀。缺少前缀会导致 `alembic history` 出现歧义、`autogenerate` 比较报错。
|
||||
|
||||
### 14. task_runtime Redis hash 字段类型不严谨
|
||||
|
||||
`app/services/task_runtime.py`
|
||||
|
||||
`update_progress` 把 `current`/`total` 存为字符串,`get_progress` 再 `int()`。如果 key 在 `update_progress` 之前被外部写为 `int`,会被覆盖为字符串,行为不统一。建议明确约定。
|
||||
|
||||
---
|
||||
|
||||
## 四、P2:代码质量
|
||||
|
||||
### 15. get_current_user 双重读取 Authorization
|
||||
|
||||
`backend/app/api/deps.py:30-37`
|
||||
|
||||
`HTTPBearer(auto_error=False)` 已处理,又手动再 `request.headers.get("Authorization")`。是冗余逻辑,建议只保留一种。
|
||||
|
||||
### 16. rbac.has_permission 语义模糊
|
||||
|
||||
`backend/app/core/rbac.py:26-30`
|
||||
|
||||
```python
|
||||
def has_permission(user: User, required_role: Role) -> bool:
|
||||
if user.role == Role.ADMIN:
|
||||
return True
|
||||
return user.role == required_role
|
||||
```
|
||||
|
||||
返回 `True` 当用户是 admin,无论 `required_role` 是什么——这其实是「admin 拥有所有权限」的语义,但函数命名是「是否有某角色权限」,容易误用。需在 docstring 中明确:返回值等价于 `user.role == ADMIN or user.role == required_role`。
|
||||
|
||||
### 17. require_admin 与 get_current_admin 重复实现
|
||||
|
||||
`rbac.py:16-23` 与 `deps.py:80-87` 做同一件事,应统一从一处导入。
|
||||
|
||||
### 18. 缺少统一日志 request_id 注入
|
||||
|
||||
`backend/app/core/logging.py:6` 定义了 `request_id_var: ContextVar`,但没有 ASGI 中间件去赋值 `request_id`,所有日志的 `[%s]` 始终是空字符串,request_id 形同虚设。
|
||||
|
||||
修复:添加 ASGI middleware 从 header `X-Request-ID` 读取或生成 UUID,写入 `ContextVar`。
|
||||
|
||||
### 19. 健康检查端点无认证
|
||||
|
||||
`backend/app/api/v1/health.py`
|
||||
|
||||
返回了 `db`、`redis` 状态字符串,可被外部用于探测内网拓扑。建议:
|
||||
|
||||
- 基础 `/health` 仅返回 `ok/degraded`
|
||||
- 详细诊断使用 `/health/db`、`/health/redis` 并在生产加 `Depends(get_current_admin)`
|
||||
|
||||
### 20. 前端 vite.config.ts 误用 process.env
|
||||
|
||||
`frontend/vite.config.ts:17,22`
|
||||
|
||||
```ts
|
||||
target: process.env.VITE_API_BASE_URL || 'http://localhost:8000'
|
||||
```
|
||||
|
||||
Vite 在 Node 端运行时 `process.env` 通常取不到 `VITE_*` 变量(这些只在客户端 `import.meta.env` 中存在)。应改用 `loadEnv`:
|
||||
|
||||
```ts
|
||||
import { defineConfig, loadEnv } from 'vite'
|
||||
export default defineConfig(({ mode }) => {
|
||||
const env = loadEnv(mode, process.cwd(), '')
|
||||
return { server: { proxy: { '/api': { target: env.VITE_API_BASE_URL || 'http://localhost:8000' } } } }
|
||||
})
|
||||
```
|
||||
|
||||
### 21. 前端路由守卫在 token 失效但 user 缓存存在时的中间态
|
||||
|
||||
`frontend/src/router/index.ts:38-57`
|
||||
|
||||
`authStore.isAuthenticated` 要求 `token && user` 都有值。F5 刷新时:localStorage 有 token 但 Pinia 中 `user` 为 null——通过 `fetchUser()` 重新拉取,正常。
|
||||
|
||||
但如果 **user 已被禁用** 且 token 仍有效,则 `get_current_user` 抛 403,前端会 `authStore.logout()`。**如果服务器端 `is_active` 没及时同步**(集群场景),会出现 token 在内存有效、DB 无效的中间态。建议每次路由切换都强制重新校验。
|
||||
|
||||
### 22. 前端 token 存 localStorage
|
||||
|
||||
`frontend/src/stores/auth.ts:7,19`
|
||||
|
||||
XSS 风险:恶意脚本可读 `localStorage.getItem('token')`。生产建议:access token 走 httpOnly cookie,或限制 token 权限到只读。
|
||||
|
||||
### 23. axios 拦截器 401 硬跳页
|
||||
|
||||
`frontend/src/api/index.ts:29-33`
|
||||
|
||||
401 时直接 `window.location.href = '/login'`,硬刷路由。如果某些请求是登录后业务请求(如 fetchMe 失败),会突然跳页而不是返回错误。考虑在 store 层处理跳转。
|
||||
|
||||
### 24. Dashboard 拉 1000 条数据统计
|
||||
|
||||
`frontend/src/views/DashboardView.vue:46`
|
||||
|
||||
```ts
|
||||
const res = await feedsApi.list({ limit: 1000 })
|
||||
```
|
||||
|
||||
后端 `PaginationParams.limit` 没有上限,前端传多少就返回多少。数据大时慢。应该让后端提供专用统计接口。
|
||||
|
||||
### 25. 前端无全局错误边界
|
||||
|
||||
没有 `app.config.errorHandler`、没有 `<ErrorBoundary>` 组件,单个组件报错会白屏。
|
||||
|
||||
修复:
|
||||
|
||||
```ts
|
||||
app.config.errorHandler = (err, instance, info) => {
|
||||
console.error('Unhandled error:', err, info)
|
||||
// 接入 Sentry 等
|
||||
}
|
||||
```
|
||||
|
||||
### 26. 分页参数未做边界校验
|
||||
|
||||
`feeds.py` 等处的 `PaginationParams.skip/limit` 无 max 限制,恶意请求 `limit=99999999` 会拉全表。
|
||||
|
||||
修复:`limit: int = Field(50, ge=1, le=200)`。
|
||||
|
||||
### 27. Dockerfile 细节
|
||||
|
||||
- `backend.Dockerfile` `pip install -e .` 但 production 阶段又 `COPY backend/`,无 `.dockerignore` 容易把 .env/数据卷带进去
|
||||
- `frontend.Dockerfile` 用 `npm install` 应改 `npm ci` 以保证 lock 一致
|
||||
- 无 production 多阶段构建(目前 `Dockerfile` 有 production stage 但 `docker-compose.yml` 只用 `development`)
|
||||
|
||||
### 28. tests/conftest.py 自定义 event_loop 已弃用
|
||||
|
||||
`backend/tests/conftest.py:11-15`
|
||||
|
||||
```python
|
||||
@pytest.fixture(scope="session")
|
||||
def event_loop():
|
||||
loop = asyncio.get_event_loop_policy().new_event_loop()
|
||||
...
|
||||
```
|
||||
|
||||
pytest-asyncio 0.23+ 已标记为 deprecated,改为 `asyncio_mode = "auto"` + `event_loop_policy` fixture 或升级到 `pytest-asyncio` 0.23+ 推荐做法。
|
||||
|
||||
### 29. 测试覆盖率几乎为零
|
||||
|
||||
仅 2 个测试(密码哈希 + 用户创建),没有 API endpoint 集成测试、没有任何前端测试。CI 缺失。
|
||||
|
||||
建议:补 FastAPI `TestClient` 集成测试 + 至少 RBAC 权限矩阵测试;前端至少加 Vitest 单测覆盖 stores + 一个 E2E(Playwright)。
|
||||
|
||||
### 30. 文档缺失
|
||||
|
||||
`docs/` 目录为空,README 引用的「设计文档」「开发步骤」路径指向 `/home/congsh/workspace/chat/`,仓内 `docs/` 没文件——文档随项目仓库丢失风险。
|
||||
|
||||
修复:将 `/home/congsh/workspace/chat/rss-platform-design.md` 与 `rss-platform-dev-plan.md` 移到 `docs/` 下并更新 README 引用路径。
|
||||
|
||||
---
|
||||
|
||||
## 五、修复优先级汇总
|
||||
|
||||
| 优先级 | 文件 | 问题 | 建议改动 |
|
||||
|--------|------|------|----------|
|
||||
| P0 | `backend/app/api/deps.py:18-21` | DB session 泄露 | 改为 `async for ... yield session` 或直接复用 `database.get_db` |
|
||||
| P0 | `backend/app/api/v1/auth.py:16-40` | 注册越权 | 加 admin 鉴权 + role 白名单 |
|
||||
| P0 | `backend/main.py:40-58` | 默认弱口令 | 首次启动检查、强制改密 |
|
||||
| P0 | `backend/app/core/auth.py` | 无 refresh / jti | 拆分 access/refresh + Redis 黑名单 |
|
||||
| P1 | `backend/main.py:78-85` | CORS 通配 fallback | 移除或启动 fail-fast |
|
||||
| P1 | `backend/app/schemas/user.py:16` | 密码长度 6 | 改为 10 + 复杂度校验 |
|
||||
| P1 | `backend/app/api/v1/feeds.py:39` & `articles.py:40` | `len()` 计数 | 改 `func.count()` |
|
||||
| P1 | `backend/app/core/database.py:7-12` | NullPool | 改默认连接池 |
|
||||
| P1 | `backend/main.py:24` | `init_db` 绕过 alembic | 删除 init_db,统一 alembic |
|
||||
| P2 | `frontend/vite.config.ts:17,22` | `process.env` 错用 | 改 `loadEnv` |
|
||||
| P2 | `backend/app/core/logging.py` | request_id 形同虚设 | 加 ASGI 中间件赋值 |
|
||||
| P2 | `frontend/src/stores/auth.ts` | localStorage 存 token | 改 httpOnly cookie 或加 CSP |
|
||||
| P2 | 整体 | 缺少测试与 CI | 补 pytest + Vitest + Playwright + GH Actions |
|
||||
|
||||
---
|
||||
|
||||
## 六、值得肯定的点
|
||||
|
||||
- 整体结构清晰,模块边界(core / models / schemas / services / api)划分合理
|
||||
- 模型层 `UUIDMixin` + `TimestampMixin` 抽象良好
|
||||
- Alembic + Pydantic Settings + async SQLAlchemy 2.0 类型注解到位
|
||||
- 前端 Pinia + 路由守卫 + axios 拦截器规范
|
||||
- 用 Pydantic 的 `HttpUrl`、`Field(ge/le)`、`min_length` 在请求侧就校验
|
||||
- 使用 `lifespan` 替代 deprecated 的 `on_event`
|
||||
|
||||
---
|
||||
|
||||
## 七、修复记录(2026-06-15)
|
||||
|
||||
本次根据本报告对 `rssWorkFlow` 代码进行了选择性修复,覆盖 P0 / P1 / 部分 P2 项。
|
||||
|
||||
### 已修复
|
||||
|
||||
| 优先级 | 问题 | 修复文件 | 修复内容 |
|
||||
|--------|------|----------|----------|
|
||||
| P0 | DB session 资源泄露 | `backend/app/api/deps.py` | `get_db` 改为 `async for ... yield session`,由 FastAPI 管理生命周期 |
|
||||
| P0 | `/auth/register` 越权 | `backend/app/api/v1/auth.py` | 注册接口改为仅 admin 可调用;schema 限制 role 白名单 |
|
||||
| P0 | 默认管理员弱口令 | `backend/main.py`, `.env.example`, `backend/app/api/v1/health.py` | 启动时检测 admin/admin 并在 `/health` 返回 warning;文档增加安全提示 |
|
||||
| P0 | JWT 无 refresh/jti | `backend/app/core/auth.py`, `backend/app/api/v1/auth.py`, `backend/app/schemas/user.py`, `backend/app/core/config.py` | access/refresh 双 token;token 携带 jti/type/iat;支持 Redis 黑名单吊销 |
|
||||
| P1 | CORS dev fallback 通配 | `backend/main.py` | 移除 `*` fallback,默认使用 `http://localhost:5173`;生产必须显式配置 |
|
||||
| P1 | 密码强度不足 | `backend/app/schemas/user.py` | 密码要求 8-128 位且至少包含字母和数字 |
|
||||
| P1 | 分页计数全量拉取 | `backend/app/api/v1/feeds.py`, `backend/app/api/v1/articles.py` | 改用 `select(func.count())` |
|
||||
| P1 | 数据库连接池策略 | `backend/app/core/database.py` | 移除 `NullPool`,改用 `AsyncAdaptedQueuePool`(pool_size=10, max_overflow=20) |
|
||||
| P1 | lifespan 中 init_db 绕过 alembic | `backend/main.py`, `backend/app/core/database.py` | 移除 `init_db()` 调用与函数定义,统一由 alembic 管理 schema |
|
||||
| P1 | 敏感设置未加密 | `backend/app/services/settings_service.py`, `backend/app/core/config.py`, `backend/pyproject.toml` | 使用 Fernet 加密敏感配置项(`OPENAI_API_KEY`、`API_TOKEN`),明文/加密兼容 |
|
||||
| P1 | 健康检查暴露拓扑 | `backend/app/api/v1/health.py` | `/health/db`、`/health/redis` 增加 admin 鉴权 |
|
||||
| P2 | vite.config.ts 误用 process.env | `frontend/vite.config.ts` | 改用 `loadEnv` 读取环境变量 |
|
||||
| P2 | request_id 未注入 | `backend/app/core/logging.py`, `backend/main.py` | 新增 ASGI middleware,从 header 读取或生成 request_id |
|
||||
| P2 | pytest event_loop 弃用 | `backend/tests/conftest.py` | 移除自定义 `event_loop` fixture,依赖 `asyncio_mode = "auto"` |
|
||||
| P2 | 前端无错误边界 | `frontend/src/main.ts` | 添加 `app.config.errorHandler` |
|
||||
| P2 | 分页参数无上限 | `backend/app/schemas/common.py` | `skip >= 0`、`1 <= limit <= 200` |
|
||||
| P2 | 文档未随仓库管理 | `docs/design.md`, `docs/dev-plan.md`, `README.md` | 将设计文档与开发步骤复制到 `docs/`,README 引用更新 |
|
||||
| P2 | 前端 token 无刷新 | `frontend/src/stores/auth.ts`, `frontend/src/api/index.ts`, `frontend/src/api/auth.ts`, `frontend/src/types/index.ts` | 存储 refresh_token;401 时自动刷新,失败再跳转登录 |
|
||||
|
||||
### 未修复 / 留待后续
|
||||
|
||||
- 登录限流与审计日志(P1):建议后续接入 slowapi 或自实现 Redis 限流,并新增 `audit_logs` 表。
|
||||
- Dockerfile 多阶段与 `.dockerignore` 优化(P2):当前阶段先用 dev 构建,production 镜像与构建 CI 留待部署阶段完善。
|
||||
- 测试覆盖率与 CI(P2):已留好 pytest / Vitest / Playwright 接入点,后续阶段补充集成测试与 GitHub Actions。
|
||||
- SSRF 防护(P1):RSS 抓取任务尚未实现,抓取模块中加入 URL 校验、IP 黑名单、代理出口策略。
|
||||
|
||||
### 验证
|
||||
|
||||
- 后端全部 Python 文件 `py_compile` 通过
|
||||
- `init_db` 已无引用
|
||||
- 前端 TypeScript 文件已完成同步修改(因无 node_modules,未运行 `tsc`)
|
||||
|
||||
### 运行建议
|
||||
|
||||
1. `cd /home/congsh/workspace/dev/rssWorkFlow`
|
||||
2. `cp .env.example .env` 并修改 `SECRET_KEY`、默认管理员密码、生成 `SETTINGS_ENCRYPTION_KEY`
|
||||
3. `make dev`
|
||||
4. `docker-compose exec backend alembic upgrade head`
|
||||
5. 访问前端登录,验证 `/health` 无安全警告
|
||||
- Dockerfile 多阶段构建思路正确
|
||||
+1120
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,536 @@
|
||||
# RSS 信息处理平台:开发步骤文档
|
||||
|
||||
> 版本:v1.0
|
||||
> 日期:2026-06-15
|
||||
> 配套文档:`rss-platform-design.md`
|
||||
|
||||
---
|
||||
|
||||
## 一、总体策略
|
||||
|
||||
### 1.1 开发原则
|
||||
|
||||
| 原则 | 说明 |
|
||||
|------|------|
|
||||
| **渐进式重构** | 不是一次性推翻重写,而是逐步迁移现有能力 |
|
||||
| **先跑通再优化** | 先让核心流程(抓取→清洗→AI→存储)跑起来,再扩展高级功能 |
|
||||
| **数据先行** | 先确定数据模型和迁移方案,再写业务逻辑 |
|
||||
| **可回滚** | 每个阶段都保留回退到旧系统的能力 |
|
||||
| **测试护航** | 关键模块必须有单元测试和接口测试 |
|
||||
|
||||
### 1.2 阶段划分
|
||||
|
||||
```
|
||||
阶段一:基础骨架(4-5 周)
|
||||
→ 技术选型确认、项目结构、PostgreSQL 迁移、Docker 环境、基础 API
|
||||
|
||||
阶段二:核心流程(4-5 周)
|
||||
→ RSS 抓取、清洗流水线、去重插件、AI 摘要/分类/Tag/打分、任务调度
|
||||
|
||||
阶段三:产出与聊天(3-4 周)
|
||||
→ Skill 系统、日报任务、聊天窗口、引用链接
|
||||
|
||||
阶段四:自优化与工业化(3-4 周)
|
||||
→ 自优化调度器、去重算法自优化、监控、日志、备份
|
||||
|
||||
阶段五:规模化与优化(持续)
|
||||
→ 性能优化、OpenSearch、分库分表、服务拆分
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、阶段一:基础骨架(Week 1-5)
|
||||
|
||||
### 目标
|
||||
搭建可运行的基础平台,完成数据库迁移、Docker 环境、用户鉴权、基础 API。
|
||||
|
||||
### 任务清单
|
||||
|
||||
#### Week 1:项目初始化与技术选型确认
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 2.1.1 创建 monorepo | 在 `/home/congsh/workspace/dev/rss-platform` 初始化项目 | `README.md`、`Makefile`、`docker-compose.yml` |
|
||||
| 2.1.2 确定目录结构 | 按模块划分目录 | 见下方目录结构 |
|
||||
| 2.1.3 选择并锁定依赖版本 | Python 3.12、FastAPI、SQLAlchemy 2.0、Celery、PostgreSQL、Redis | `backend/requirements.txt` |
|
||||
| 2.1.4 配置代码质量工具 | ruff、black、pytest、pre-commit | `.pre-commit-config.yaml`、`pyproject.toml` |
|
||||
| 2.1.5 创建 Docker 基础镜像 | 后端、前端、PostgreSQL、Redis、MinIO | `Dockerfile`、`docker-compose.dev.yml` |
|
||||
|
||||
**推荐目录结构:**
|
||||
```
|
||||
rss-platform/
|
||||
├── backend/
|
||||
│ ├── app/
|
||||
│ │ ├── core/ # 配置、日志、异常、鉴权
|
||||
│ │ ├── models/ # SQLAlchemy 模型
|
||||
│ │ ├── schemas/ # Pydantic 模型
|
||||
│ │ ├── api/ # API 路由
|
||||
│ │ ├── services/ # 业务服务
|
||||
│ │ ├── tasks/ # Celery 任务
|
||||
│ │ ├── plugins/ # 插件接口与加载器
|
||||
│ │ ├── ai/ # AI 调用、Provider 路由
|
||||
│ │ ├── skills/ # Skill 加载与执行
|
||||
│ │ ├── search/ # 检索服务
|
||||
│ │ ├── chat/ # 聊天引擎
|
||||
│ │ └── optimization/ # 自优化
|
||||
│ ├── alembic/ # 数据库迁移
|
||||
│ ├── tests/
|
||||
│ └── main.py
|
||||
├── frontend/
|
||||
│ ├── src/
|
||||
│ │ ├── views/
|
||||
│ │ ├── components/
|
||||
│ │ ├── api/
|
||||
│ │ ├── stores/
|
||||
│ │ └── router/
|
||||
│ └── package.json
|
||||
├── plugins/
|
||||
│ └── deduplication/
|
||||
├── docker/
|
||||
│ ├── backend.Dockerfile
|
||||
│ ├── frontend.Dockerfile
|
||||
│ └── docker-compose.yml
|
||||
├── docs/
|
||||
└── scripts/
|
||||
├── migrate_from_sqlite.py
|
||||
└── init_dev_env.sh
|
||||
```
|
||||
|
||||
#### Week 2:PostgreSQL 数据模型与迁移
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 2.2.1 设计并创建核心表 | users、feeds、raw_articles、cleaned_articles、article_references、skills 等 | `backend/app/models/` |
|
||||
| 2.2.2 配置 Alembic | 初始化迁移工具 | `alembic.ini`、baseline migration |
|
||||
| 2.2.3 编写 SQLite → PostgreSQL 迁移脚本 | 从 rssKeeper + dataClean 导出并导入 | `scripts/migrate_from_sqlite.py` |
|
||||
| 2.2.4 验证迁移数据完整性 | 对比条数、关键字段抽样 | 迁移报告 |
|
||||
| 2.2.5 配置 pgvector 扩展 | 安装并创建向量表 | `article_embeddings` 表 |
|
||||
|
||||
#### Week 3:FastAPI 基础与鉴权
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 2.3.1 FastAPI 项目骨架 | lifespan、中间件、异常处理、日志 | `backend/main.py` |
|
||||
| 2.3.2 JWT 鉴权 | 登录、注册、Token 刷新、API Key | `backend/app/core/auth.py` |
|
||||
| 2.3.3 简单 RBAC | admin / member 角色 | `backend/app/core/rbac.py` |
|
||||
| 2.3.4 CORS 安全配置 | 白名单、关闭 credentials | `backend/main.py` |
|
||||
| 2.3.5 健康检查与 OpenAPI | `/health`、`/openapi.json` | API 文档 |
|
||||
|
||||
#### Week 4:配置中心与锁服务
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 2.4.1 配置中心 | 环境变量 + DB 覆盖 + 版本化 | `backend/app/core/settings.py` |
|
||||
| 2.4.2 Redis 连接 | 缓存、锁、消息队列 | `backend/app/core/redis.py` |
|
||||
| 2.4.3 分布式锁服务 | 任务锁、文章锁 | `backend/app/services/lock_service.py` |
|
||||
| 2.4.4 任务运行时状态 | 进度追踪、任务日志 | `backend/app/services/task_runtime.py` |
|
||||
| 2.4.5 日志与请求 ID | 结构化日志、request_id | `backend/app/core/logging.py` |
|
||||
|
||||
#### Week 5:前端基础与管理后台
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 2.5.1 Vue 3 + TS 项目初始化 | Vite、Element Plus、Pinia、Vue Router | `frontend/` |
|
||||
| 2.5.2 登录页 | JWT 登录、API Key 管理 | `LoginView.vue` |
|
||||
| 2.5.3 RSS 源管理页 | 列表、添加、编辑、删除 | `FeedsView.vue` |
|
||||
| 2.5.4 文章列表页 | 分页、筛选 | `ArticlesView.vue` |
|
||||
| 2.5.5 Docker Compose 联调 | 全栈本地启动 | `docker-compose.yml` |
|
||||
|
||||
### 阶段一交付物
|
||||
- [ ] 可本地 `docker-compose up` 运行的基础平台
|
||||
- [ ] PostgreSQL 数据库 + 迁移脚本
|
||||
- [ ] JWT 鉴权 + 简单 RBAC
|
||||
- [ ] RSS 源 CRUD + 文章列表
|
||||
- [ ] 分布式锁服务
|
||||
|
||||
### 阶段一里程碑
|
||||
**M1:基础平台骨架完成,可管理 RSS 源和查看文章列表。**
|
||||
|
||||
---
|
||||
|
||||
## 三、阶段二:核心流程(Week 6-10)
|
||||
|
||||
### 目标
|
||||
实现抓取→清洗→去重→AI 处理→存储的完整流水线。
|
||||
|
||||
### 任务清单
|
||||
|
||||
#### Week 6:RSS 抓取迁移与增强
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 3.6.1 迁移抓取逻辑 | 从 rssKeeper `rss_fetcher.py` 迁移 | `backend/app/services/feed_fetcher.py` |
|
||||
| 3.6.2 Celery 抓取任务 | `fetch_feed_task`、`fetch_all_feeds_task` | `backend/app/tasks/feeds.py` |
|
||||
| 3.6.3 Celery Beat 调度 | 按 Feed 间隔注册定时任务 | `backend/app/tasks/scheduler.py` |
|
||||
| 3.6.4 抓取失败重试 | 指数退避、死信队列 | 重试装饰器 |
|
||||
| 3.6.5 Feed 健康度统计 | 复用 rssKeeper 逻辑 | `backend/app/services/health_checker.py` |
|
||||
|
||||
#### Week 7:清洗流水线
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 3.7.1 数据标准化 | URL 规范化、HTML 清洗、时间标准化 | `backend/app/services/normalizer.py` |
|
||||
| 3.7.2 正文提取 | 优先 RSS content,fallback 原文页 | `backend/app/services/content_extractor.py` |
|
||||
| 3.7.3 清洗任务 Celery 化 | `process_raw_article_task` | `backend/app/tasks/pipeline.py` |
|
||||
| 3.7.4 内容 hash 与语言检测 | 用于后续去重 | 辅助字段 |
|
||||
| 3.7.5 清洗状态机 | pending → processing → cleaned / failed | `processing_status` |
|
||||
|
||||
#### Week 8:去重插件系统
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 3.8.1 定义插件接口 | `DeduplicationPlugin` | `backend/app/plugins/base.py` |
|
||||
| 3.8.2 实现默认去重插件 | URL + 标题 exact + TF-IDF 内容相似 | `plugins/deduplication/current.py` |
|
||||
| 3.8.3 插件加载器 | 动态 import + 热加载 | `backend/app/plugins/loader.py` |
|
||||
| 3.8.4 引用关系写入 | `article_references` + `reference_links` | 去重服务 |
|
||||
| 3.8.5 去重任务接口 | 手动触发、查看结果 | `/api/tasks/deduplicate` |
|
||||
| 3.8.6 插件版本元数据 | `metadata.json` | 版本管理 |
|
||||
|
||||
#### Week 9:AI 处理中心
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 3.9.1 AI Provider 配置模型 | openai / anthropic / gemini / local | `backend/app/models/ai_provider_config.py` |
|
||||
| 3.9.2 AI 任务配置模型 | 每个任务独立配置 | `backend/app/models/ai_task_config.py` |
|
||||
| 3.9.3 LiteLLM/自封装多供应商路由 | 统一调用接口 | `backend/app/ai/client.py` |
|
||||
| 3.9.4 AI 摘要任务 | 复用 dataClean `summarizer.py` | `backend/app/tasks/ai_tasks.py` |
|
||||
| 3.9.5 AI 分类任务 | 从规则分类迁移到 AI 分类 | `backend/app/tasks/ai_tasks.py` |
|
||||
| 3.9.6 AI Tag 任务 | AI 打标签 | `backend/app/tasks/ai_tasks.py` |
|
||||
| 3.9.7 AI 打分任务 | heat/importance/composite | `backend/app/tasks/ai_tasks.py` |
|
||||
|
||||
#### Week 10:流水线编排与任务调度
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 3.10.1 流水线编排器 | 组合抓取→清洗→去重→AI 处理 | `backend/app/services/pipeline_orchestrator.py` |
|
||||
| 3.10.2 任务进度追踪 | 复用 dataClean `task_progress.py` | `backend/app/services/task_progress.py` |
|
||||
| 3.10.3 手动/定时任务互斥 | Redis 锁 + Celery | 调度服务 |
|
||||
| 3.10.4 仪表盘统计 API | 文章数、分类分布、任务状态 | `/api/stats` |
|
||||
| 3.10.5 前端仪表盘 | 统计卡片、任务进度 | `DashboardView.vue` |
|
||||
|
||||
### 阶段二交付物
|
||||
- [ ] RSS 自动抓取 + Celery 调度
|
||||
- [ ] 清洗流水线
|
||||
- [ ] 去重插件系统(默认实现 + 热加载)
|
||||
- [ ] AI 摘要/分类/Tag/打分
|
||||
- [ ] 流水线编排与任务进度
|
||||
|
||||
### 阶段二里程碑
|
||||
**M2:核心流程跑通,一篇文章从 RSS 抓取到 AI 处理完成可自动化执行。**
|
||||
|
||||
---
|
||||
|
||||
## 四、阶段三:产出与聊天(Week 11-14)
|
||||
|
||||
### 目标
|
||||
实现 Skill 系统、日报任务、聊天窗口、引用链接。
|
||||
|
||||
### 任务清单
|
||||
|
||||
#### Week 11:Skill 系统基础
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 4.11.1 Skill 数据模型 | skills、skill_versions | 数据库表 |
|
||||
| 4.11.2 Skill 加载与执行 | 解析 prompt、schema、tools | `backend/app/skills/loader.py` |
|
||||
| 4.11.3 内置默认 Skills | 摘要、分类、Tag、打分、日报、聊天 | `backend/app/skills/defaults/` |
|
||||
| 4.11.4 Skill CRUD API | 创建、修改、导入、导出、恢复默认 | `/api/skills/*` |
|
||||
| 4.11.5 Skill 管理前端 | 编辑器、导入导出 | `SkillsView.vue` |
|
||||
|
||||
#### Week 12:日报任务系统
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 4.12.1 OutputTask 模型 | task + skill + filter + schedule | 数据库表 |
|
||||
| 4.12.2 日报生成任务 | 复用 dataClean `brief.py`,改为 Skill 驱动 | `backend/app/tasks/output_tasks.py` |
|
||||
| 4.12.3 数据筛选 DSL | 时间、分类、Tag、分数过滤 | Filter builder |
|
||||
| 4.12.4 多种日报类型 | 科技观察、综合日报等 | 多个 OutputTask |
|
||||
| 4.12.5 日报前端 | 列表、详情、重新生成 | `BriefsView.vue` |
|
||||
|
||||
#### Week 13:聊天引擎
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 4.13.1 聊天数据模型 | sessions、messages | 数据库表 |
|
||||
| 4.13.2 聊天 API | 创建会话、发送消息、历史记录 | `/api/chat/*` |
|
||||
| 4.13.3 Tool 调用框架 | 搜索文章、获取文章详情、调用外部 API | `backend/app/chat/tools.py` |
|
||||
| 4.13.4 引用链接解析 | 从 AI 输出提取标记并映射链接 | `backend/app/chat/references.py` |
|
||||
| 4.13.5 聊天前端 | 对话界面、引用渲染 | `ChatView.vue` |
|
||||
|
||||
#### Week 14:工具与产出集成
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 4.14.1 外部 API Tool | 调用用户配置的 HTTP API | `fetch_external_api` tool |
|
||||
| 4.14.2 产出导出 | Markdown、JSON、邮件 | `backend/app/services/exporters.py` |
|
||||
| 4.14.3 聊天中运行 Skill | 用户选择 Skill 进行专项对话 | Skill selector |
|
||||
| 4.14.4 会话上下文管理 | 窗口大小、历史摘要 | Context manager |
|
||||
| 4.14.5 集成测试 | 端到端聊天流程 | `tests/test_chat.py` |
|
||||
|
||||
### 阶段三交付物
|
||||
- [ ] Skill 系统(CRUD + 默认 Skills)
|
||||
- [ ] 可配置的日报任务系统
|
||||
- [ ] 聊天窗口(支持 Tool 调用和引用链接)
|
||||
- [ ] 外部 API Tool
|
||||
|
||||
### 阶段三里程碑
|
||||
**M3:平台具备 AI 产出能力,日报和聊天均可调用 Skills 生成带引用链接的内容。**
|
||||
|
||||
---
|
||||
|
||||
## 五、阶段四:自优化与工业化(Week 15-18)
|
||||
|
||||
### 目标
|
||||
实现每日凌晨 2 点自优化、去重算法自优化、监控、备份、日志。
|
||||
|
||||
### 任务清单
|
||||
|
||||
#### Week 15:自优化调度器
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 5.15.1 自优化数据收集 | 收集最近执行样例、历史优化记录 | `backend/app/optimization/collector.py` |
|
||||
| 5.15.2 Prompt/Skill 优化器 | 用 AI 评审并生成候选 Prompt | `backend/app/optimization/prompt_optimizer.py` |
|
||||
| 5.15.3 优化器自评逻辑 | 候选 vs 当前版本评分 | 评估服务 |
|
||||
| 5.15.4 自动发布机制 | 保存新版本、自动生效 | 发布服务 |
|
||||
| 5.15.5 优化日志 | `optimization_logs` 表 + API | 留痕 |
|
||||
|
||||
#### Week 16:去重算法自优化
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 5.16.1 去重算法优化器 | 分析样例生成候选算法代码 | `backend/app/optimization/dedup_optimizer.py` |
|
||||
| 5.16.2 算法版本备份 | 自动生成 `.bak` | 版本管理 |
|
||||
| 5.16.3 算法热加载与回滚 | 失败自动回滚 | 插件加载器增强 |
|
||||
| 5.16.4 算法性能评估 | 运行时间、内存、误判漏判 | 评估服务 |
|
||||
| 5.16.5 手动回滚 API | `/api/admin/deduplication/rollback` | 管理接口 |
|
||||
|
||||
#### Week 17:监控与可观测性
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 5.17.1 Prometheus 指标 | 任务数、AI 调用数、延迟、失败率 | `/metrics` |
|
||||
| 5.17.2 Grafana 仪表盘 | 系统状态、任务状态、AI 成本 | `docker/grafana/` |
|
||||
| 5.17.3 Sentry 集成 | 错误追踪 | 配置 |
|
||||
| 5.17.4 日志聚合 | Loki 或文件日志 | 日志配置 |
|
||||
| 5.17.5 告警规则 | 任务失败、AI 调用异常 | Alert rules |
|
||||
|
||||
#### Week 18:备份、安全与部署
|
||||
|
||||
| 任务 | 说明 | 产出 |
|
||||
|------|------|------|
|
||||
| 5.18.1 PostgreSQL 自动备份 | 每日备份、保留策略 | `scripts/backup_db.sh` |
|
||||
| 5.18.2 对象存储备份 | 插件、导出产物备份 | 备份脚本 |
|
||||
| 5.18.3 安全加固 | API 限流、密码策略、敏感配置加密 | 安全文档 |
|
||||
| 5.18.4 生产 Docker Compose | 多 Worker 配置 | `docker-compose.prod.yml` |
|
||||
| 5.18.5 部署文档 | 完整部署步骤 | `docs/deployment.md` |
|
||||
|
||||
### 阶段四交付物
|
||||
- [ ] 每日 2:00 自优化调度器
|
||||
- [ ] 去重算法自优化 + 版本回滚
|
||||
- [ ] Prometheus + Grafana 监控
|
||||
- [ ] 自动备份方案
|
||||
- [ ] 生产部署文档
|
||||
|
||||
### 阶段四里程碑
|
||||
**M4:平台具备工业化能力,可无人值守运行并自动优化。**
|
||||
|
||||
---
|
||||
|
||||
## 六、阶段五:规模化与持续优化(Week 19+)
|
||||
|
||||
### 目标
|
||||
根据实际数据量和负载进行性能优化和架构扩展。
|
||||
|
||||
### 任务清单
|
||||
|
||||
| 任务 | 说明 | 时机 |
|
||||
|------|------|------|
|
||||
| 6.1 迁移到 OpenSearch | 当 PG tsvector 性能不足时 | 10万+ 文章 |
|
||||
| 6.2 向量检索优化 | 使用专用向量库(Qdrant/Milvus) | 需要语义检索时 |
|
||||
| 6.3 去重算法升级 | LSH/MinHash/Embedding | 日增 5000+ 时 |
|
||||
| 6.4 数据库读写分离 | 主从复制 | 读压力高时 |
|
||||
| 6.5 按时间分库 | 历史数据归档 | 50万+ 文章 |
|
||||
| 6.6 服务拆分 | 拆分为 feed-service、ai-service 等 | 团队扩大时 |
|
||||
| 6.7 缓存层优化 | Redis 缓存热门查询、文章 | 读压力大时 |
|
||||
| 6.8 AI 调用成本优化 | 缓存 Embedding、批量调用、模型降级 | AI 成本高时 |
|
||||
|
||||
---
|
||||
|
||||
## 七、关键依赖清单
|
||||
|
||||
### 7.1 Python 后端
|
||||
|
||||
```txt
|
||||
fastapi==0.115.0
|
||||
uvicorn[standard]==0.30.0
|
||||
sqlalchemy[asyncio]==2.0.31
|
||||
asyncpg==0.29.0
|
||||
alembic==1.13.2
|
||||
psycopg2-binary==2.9.9
|
||||
celery==5.4.0
|
||||
redis==5.0.7
|
||||
pydantic==2.8.2
|
||||
pydantic-settings==2.3.4
|
||||
python-jose[cryptography]==3.3.0
|
||||
passlib[bcrypt]==1.7.4
|
||||
python-multipart==0.0.9
|
||||
httpx==0.27.0
|
||||
feedparser==6.0.11
|
||||
beautifulsoup4==4.12.3
|
||||
lxml==5.2.2
|
||||
scikit-learn==1.5.1
|
||||
numpy==1.26.4
|
||||
openai==1.35.0
|
||||
litellm==1.41.0
|
||||
langdetect==1.0.9
|
||||
watchdog==4.0.1
|
||||
prometheus-client==0.20.0
|
||||
sentry-sdk==2.7.0
|
||||
pytest==8.2.2
|
||||
pytest-asyncio==0.23.7
|
||||
```
|
||||
|
||||
### 7.2 前端
|
||||
|
||||
```json
|
||||
{
|
||||
"vue": "^3.4.0",
|
||||
"vue-router": "^4.3.0",
|
||||
"pinia": "^2.1.0",
|
||||
"element-plus": "^2.7.0",
|
||||
"axios": "^1.7.0",
|
||||
"typescript": "^5.4.0",
|
||||
"marked": "^13.0.0",
|
||||
"dompurify": "^3.1.0"
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 基础设施
|
||||
|
||||
| 组件 | 版本 | 用途 |
|
||||
|------|------|------|
|
||||
| PostgreSQL | 16+ | 主数据库 |
|
||||
| Redis | 7+ | 缓存、锁、消息队列 |
|
||||
| MinIO | latest | 对象存储 |
|
||||
| Prometheus | latest | 指标采集 |
|
||||
| Grafana | latest | 监控仪表盘 |
|
||||
|
||||
---
|
||||
|
||||
## 八、测试策略
|
||||
|
||||
### 8.1 单元测试
|
||||
|
||||
| 模块 | 测试重点 |
|
||||
|------|----------|
|
||||
| `plugins/deduplication` | URL/标题/内容去重、代表文章选择 |
|
||||
| `app/services/normalizer` | URL 规范化、HTML 清洗 |
|
||||
| `app/ai/client` | 多 Provider 路由、Fallback |
|
||||
| `app/skills/loader` | Skill 解析、Schema 校验 |
|
||||
| `app/chat/references` | 引用标记解析与链接映射 |
|
||||
| `app/services/lock_service` | 锁获取/释放/超时 |
|
||||
|
||||
### 8.2 集成测试
|
||||
|
||||
| 模块 | 测试重点 |
|
||||
|------|----------|
|
||||
| `/api/feeds` | CRUD、抓取触发 |
|
||||
| `/api/tasks/deduplicate` | 去重任务全流程 |
|
||||
| `/api/chat/sessions` | 创建会话、发送消息 |
|
||||
| `/api/output-tasks` | 创建任务、手动运行 |
|
||||
| `/api/admin/deduplication/rollback` | 算法回滚 |
|
||||
|
||||
### 8.3 端到端测试
|
||||
|
||||
- 发布 RSS → 抓取 → 清洗 → 去重 → AI 处理 → 日报生成
|
||||
- 聊天中提问 → 检索文章 → AI 回答 → 验证引用链接
|
||||
|
||||
---
|
||||
|
||||
## 九、里程碑与验收标准
|
||||
|
||||
| 里程碑 | 时间 | 验收标准 |
|
||||
|--------|------|----------|
|
||||
| M1 基础骨架 | Week 5 | `docker-compose up` 可运行;可管理 Feed;可查看文章列表;JWT 鉴权可用 |
|
||||
| M2 核心流程 | Week 10 | 一条 RSS 文章能自动完成:抓取→清洗→去重→AI 摘要/分类/Tag/打分 |
|
||||
| M3 产出与聊天 | Week 14 | 可创建日报任务并生成日报;可在聊天中提问并获得带引用链接的回答 |
|
||||
| M4 自优化与工业化 | Week 18 | 每日 2:00 自优化成功执行并留痕;去重算法可热加载和回滚;监控可用 |
|
||||
| M5 规模化 | 持续 | 根据数据量完成 OpenSearch/分库等扩展 |
|
||||
|
||||
---
|
||||
|
||||
## 十、风险与应对
|
||||
|
||||
| 风险 | 阶段 | 影响 | 应对 |
|
||||
|------|------|------|------|
|
||||
| SQLite → PostgreSQL 迁移复杂 | 阶段一 | 高 | 编写迁移脚本 + 数据校验 + 保留旧系统 |
|
||||
| Celery 任务状态丢失 | 阶段二 | 中 | 使用 Redis 持久化 + 任务结果 backend |
|
||||
| 去重插件热加载失败 | 阶段二/四 | 高 | 失败自动回滚上一个 `.bak` |
|
||||
| AI 自优化产生劣质结果 | 阶段四 | 中 | 优化器自评 + 版本化 + 不自动删除旧版本 |
|
||||
| AI 调用成本高 | 全程 | 中 | 多供应商路由 + Fallback + 结果缓存 |
|
||||
| 前端 TypeScript 迁移成本 | 阶段一 | 低 | 新平台前端直接用 TS,旧前端代码逐步重写 |
|
||||
| 数据量增长超预期 | 阶段五 | 中 | 分区表 + 预留 OpenSearch/向量库扩展路径 |
|
||||
|
||||
---
|
||||
|
||||
## 十一、交付文档清单
|
||||
|
||||
| 文档 | 负责阶段 | 状态 |
|
||||
|------|----------|------|
|
||||
| 本开发步骤文档 | 全程 | ✅ |
|
||||
| 架构设计文档 | 全程 | ✅ `rss-platform-design.md` |
|
||||
| API 接口详细文档 | 阶段一~三 | 待编写 |
|
||||
| Skill 开发指南 | 阶段三 | 待编写 |
|
||||
| 自优化机制说明 | 阶段四 | 待编写 |
|
||||
| Docker 部署手册 | 阶段一/四 | 待编写 |
|
||||
| 数据迁移手册 | 阶段一 | 待编写 |
|
||||
| 运维监控手册 | 阶段四 | 待编写 |
|
||||
|
||||
---
|
||||
|
||||
## 十二、后续建议
|
||||
|
||||
1. **先验证核心假设**:在阶段二结束前,用真实 RSS 源跑一周,观察去重效果和 AI 输出质量。
|
||||
2. **Prompt 工程优先于自优化**:初期先人工调优 Prompt,阶段四再引入自优化。
|
||||
3. **保留旧系统并行运行**:直到阶段三结束,旧 rssKeeper + dataClean 可继续服务,降低切换风险。
|
||||
4. **建立反馈闭环**:即使不自优化,也要先收集用户对 AI 产出的反馈数据。
|
||||
5. **控制 AI 成本**:为每个任务设置预算上限和模型降级策略。
|
||||
|
||||
---
|
||||
|
||||
## 十三、快速启动命令(预期)
|
||||
|
||||
```bash
|
||||
# 1. 克隆项目
|
||||
cd /home/congsh/workspace/dev
|
||||
git clone <new-repo-url> rss-platform
|
||||
cd rss-platform
|
||||
|
||||
# 2. 启动基础设施
|
||||
docker-compose -f docker-compose.dev.yml up -d postgres redis minio
|
||||
|
||||
# 3. 初始化数据库
|
||||
cd backend
|
||||
alembic upgrade head
|
||||
python scripts/migrate_from_sqlite.py \
|
||||
--rsskeeper-db /path/to/rsskeeper.db \
|
||||
--dataclean-db /path/to/dataclean.db
|
||||
|
||||
# 4. 启动后端
|
||||
uvicorn main:app --reload --port 8000
|
||||
|
||||
# 5. 启动前端
|
||||
cd ../frontend
|
||||
npm install
|
||||
npm run dev
|
||||
|
||||
# 6. 启动 Celery Worker
|
||||
cd ../backend
|
||||
celery -A app.tasks worker -Q default,fetch,ai -l info
|
||||
celery -A app.tasks beat -l info
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*本文档与 `rss-platform-design.md` 配套使用,开发过程中应根据实际情况迭代更新。*
|
||||
Reference in New Issue
Block a user