Files
ephron-ren-prd/prd-ephron-ren-full-codebase-optimization-checklist.md

731 lines
22 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 — ephron.ren 全项目代码阅读后的完整优化清单
## 说明
本清单基于对 `ephron.ren` **远端 `origin/main`** 的系统性源码阅读整理,不以当前本地工作树为准。
之所以强调这一点,是因为本地仓库当前状态与远端并不一致:
- 本地 `HEAD``origin/main` 存在 ahead/behind 分叉
- 本地还存在不在 `origin/main` 中的文件(例如 `prompt/tests/test_settings_validation_regression.py`
因此,本 PRD 的结论全部以 **`origin/main` 可验证代码** 为依据,避免把本地漂移状态误判为正式项目现状。
本次阅读重点覆盖:
- 顶层入口与项目运行骨架
- `shared/` 全部核心 Python 模块
- 五个服务的 `src/` 关键入口、routes、services
- 全局 tests 与各服务代表性 tests
- 必要的 scripts 层职责分布
阅读方式不是逐个文档回顾,而是**以 Python 代码为主、以测试和脚本为辅助**,用于形成项目层面的结构优化结论。
---
## 一、执行摘要
当前 `ephron.ren` 项目已经从早期多服务 MVP 演进到一个拥有:
- 五个 FastAPI 服务home/auth/blog/canvas/prompt
- 一层共享模块shared
- 一批管理脚本scripts
- 混合测试体系(全局 + 各服务)
的中型单仓项目。
它已经具备一定工程化基础:
- 统一启动器
- shared 安全头 / cookie / CSRF / 审计 / ports / rate limit 等公共模块
- app factory / config base 共享化的第一轮落地
- service token / audit event / RBAC 等基础治理能力
但通读代码后可以明确判断:
> 这个项目当前的主要矛盾已经不是“功能缺失”,而是**结构进入半统一状态后,边界没有完全收紧**。
也就是说:
- shared 已经出现,但没有真正成为单一权威层
- 服务之间已经开始收敛,但仍保留大量复制变体
- 测试已经很多,但测试结构并不稳定
- 运维脚本已经存在,但项目契约在代码、文档、脚本三层之间有漂移
因此,本清单的核心不是列零散 bug而是给出 **整站层面需要收口的工程性优化项**
---
## 二、代码规模与结构概览
基于 `origin/main` 的粗略统计:
- `shared/`17 个 Python 文件,约 1492 行
- `auth/src/`17 个 Python 文件,约 4369 行
- `auth/tests/`9 个 Python 文件,约 1851 行
- `auth/scripts/`7 个 Python 文件,约 1384 行
- `blog/src/`21 个 Python 文件,约 5734 行
- `blog/tests/`8 个 Python 文件,约 913 行
- `blog/scripts/`8 个 Python 文件,约 973 行
- `canvas/src/`10 个 Python 文件,约 2208 行
- `canvas/tests/`3 个 Python 文件,约 702 行
- `home/src/`9 个 Python 文件,约 1007 行
- `home/tests/`2 个 Python 文件,约 400 行
- `home/scripts/`2 个 Python 文件,约 362 行
- `prompt/src/`18 个 Python 文件,约 4293 行
这说明项目已经明显超出“小型 MVP”范畴进入了
- 多服务
- 多存储模型
- 多种认证形态
- 多种测试风格
- 多种运维入口
并存的复杂系统阶段。
此时最重要的不是继续叠功能,而是**统一边界、清理漂移、建立工程约束**。
---
## 三、总体问题地图
通读代码后,当前整站问题可以归纳为六大类:
1. **架构边界问题**shared 化进行到一半,责任分层尚不稳定
2. **数据与模式归属问题**:数据库 schema ownership 漂移,跨服务边界模糊
3. **认证与权限问题**:跨服务 auth/helper 重复实现guard 逻辑分散
4. **测试体系问题**:测试风格混杂,很多测试在替结构问题兜底
5. **运维与部署契约问题**代码、README、scripts、依赖链之间存在漂移
6. **性能与运行时语义问题**:部分启动逻辑、缓存、健康检查和 IO 设计仍偏“功能优先”而非“系统优先”
下面按优先级展开。
---
## 四、P0必须优先处理的系统性问题
## P0-1. Shared 层已经成为基础设施核心,但还没有真正成为单一权威层
### 现象
项目已经有大量 shared 模块:
- `shared/security_headers.py`
- `shared/limiter.py`
- `shared/health.py`
- `shared/csrf.py`
- `shared/cookie_utils.py`
- `shared/request_ip.py`
- `shared/service_tokens.py`
- `shared/auth_users.py`
- `shared/redirect_codec.py`
- `shared/audit_log.py`
- `shared/audit_events.py`
- `shared/config_base.py`
- `shared/error_handlers.py`
- `shared/app_factory.py`
这已经说明 shared 不是辅助目录,而是事实上的基础设施层。
但代码同时又显示出明显的“半统一态”:
- 各服务仍自己写 path hack
- 各服务仍各自保留 auth helper 变体
- 各服务仍自行拼装部分 guard / token / DB 逻辑
- 测试大量依赖服务内 patch / import 注入来运行
### 问题本质
项目已经决定走 shared 化,但还没有把这个决定贯彻为**稳定架构边界**。
现在的 shared 更像:
- “可复用模块集合”
而不是:
- “明确的公共协议层和基础设施层”
### 优化建议
1. 把 shared 的职责重新定义清楚,至少分三层:
- **shared/core**ports、config、health、sqlite、templating 等基础设施
- **shared/security**cookie、csrf、redirect、request_ip、network_safety、service_tokens
- **shared/governance**audit_log、audit_events、auth_users
2. 明确服务层只允许:
- 组合 shared
- 实现服务自己的业务逻辑
3. 禁止服务层重复实现 shared 已经承担的协议逻辑
4. 为 shared 层补一个“模块边界文档 + import 约束清单”
### 价值
这一步不是美化目录,而是让项目从“共享了一些代码”变成“建立了共享层权威”。
---
## P0-2. 数据库 schema ownership 已经漂移Prompt 服务承担了不属于自己的数据库中枢职责
### 现象
`prompt/src/services/db.py` 不仅初始化 prompt 自己的表:
- `prompts`
- `prompt_versions`
- `collections`
- `collection_items`
- `settings`
- `test_audit_log`
还在同一个模块里初始化:
- `blog_collections`
- `blog_collection_items`
### 这为什么严重
这不是简单的“顺手建表”,而是**服务边界被数据库初始化逻辑穿透了**。
直接后果:
1. Prompt 服务在事实层面成了跨域 schema bootstrap owner
2. Blog 的集合表不再由 Blog 自己的模块负责
3. 后续如果 blog collections 结构要演进,维护者必须去 prompt/db 里改
4. 新人很难从目录结构直觉判断“哪个服务拥有哪张表”
5. 迁移/部署/排障都会误导
### 优化建议
1. 重新定义数据库模式归属:
- `auth` 拥有用户/角色/权限/邀请/service account 相关表
- `prompt` 拥有 prompts / prompt_versions / prompt collections / settings / prompt audit
- `blog` 拥有 blog_collections 等 blog 相关表
- 全局共享表必须明确标注为 shared schema
2. 不允许某个服务的 `db.py` 去创建另一个服务的业务表
3. 建立统一的 migration / schema registration 机制:
- 可以是根级 `scripts/migrate_database.py` 调度各服务注册器
- 或 shared schema registry
4. 把“建表逻辑”和“运行时 connection helper”拆开
- `db.py` 负责连接和轻量 helper
- schema 初始化由独立 migration 层负责
### 价值
这是整站层面最需要收口的一条,不然项目继续增长后,数据库会先于代码架构失控。
---
## P0-3. 认证/权限协议在跨服务间被重复实现,风险在于未来持续漂移
### 现象
多个服务都存在自己的 auth service
- `auth/src/services/auth.py`
- `blog/src/services/auth.py`
- `canvas/src/services/auth.py`
- `home/src/services/auth.py`
- `prompt/src/services/auth.py`
虽然它们都围绕同一 cookie/token 协议,但实现并不完全统一。
常见重复内容包括:
- token verify
- get_auth_user
- require_admin_role
- require_permission
- service actor 识别
- admin guard / redirect 逻辑
### 问题
这不是“代码重复”这么简单,而是**认证协议重复实现**。
一旦协议升级,比如:
- token 字段变化
- current DB role 解释变化
- service token 行为变化
- handoff_to_human 规则变化
多个服务必须同步修改,否则就会出现行为漂移。
### 优化建议
1. 抽出一层 shared auth protocol helper
- token verify
- current user resolve
- current role/permission resolve
2. 抽 shared admin guard skeleton
- 登录跳转
- redirect 编解码
- service token 能否访问 admin 的统一策略
3. 服务层只保留:
- 各自业务资源上的权限要求
- 各自页面跳转的 UI 差异
4. 统一 `service actor` 的语义,不要每个 service_api 都自己再包一层近似实现
### 价值
认证和权限如果不先统一协议层,将来每个服务都能“看起来能用,但行为不完全一致”。这是最难排查的线上问题类型之一。
---
## P0-4. 当前测试体系已经在为结构债务兜底,必须先治理测试边界
### 现象
测试中出现多种明显信号:
1. 大量 `sys.path.insert(...)`
2. 大量 `sys.modules['src.config'] = mock_config`
3. 既有真实入口测试,也有内存 SQLite 模拟测试
4. 一些 tests 更像脚本式 smoke file而不是稳定单测
5. 有些测试在 patch import path 后才跑得起来
### 问题本质
这说明测试体系并不只是“多样”,而是:
> 结构不稳定,测试在替结构问题兜底。
当测试必须大量:
- 改路径
- 改模块缓存
- patch 配置模块
- patch 连接层
才能运行时,往往意味着:
- 模块边界不清晰
- 初始化副作用太强
- 配置/数据库/依赖注入方式不够健康
### 优化建议
1. 重新分层测试:
- **unit**:纯函数/纯 service helper
- **contract**shared 协议、entrypoint 装配、cookie/redirect/security headers 合同
- **integration**:服务路由 + 临时 DB / 文件系统
- **script smoke**:脚本独立,不混在核心单测里
2. 把脚本式测试文件从核心 pytest 回归层剥离
3. 减少 `sys.modules['src.config']` 风格 patch改为显式配置注入或 fixture
4. 建立统一测试 helper
- temp DB
- temp content dir
- service runtime bootstrap
5. 明确哪些 tests 允许 mock哪些必须走真实入口
### 价值
如果不先治理测试边界,后续任何重构都会因为“测试全在 patch 系统内部结构”而变得高风险。
---
## 五、P1高优先级结构优化
## P1-1. `sys.path.insert(...)` 仍然是整站普遍现象,说明模块边界和运行契约都不稳定
### 现象
根入口、五个服务 main/config、routes、services、tests、scripts 中广泛存在 `sys.path.insert(...)`
这意味着项目当前默认运行模型仍然是:
- 依赖 cwd
- 依赖相对路径
- 依赖手动往 `sys.path` 注入仓库根或服务根
### 问题
这会导致:
- 测试和运行环境对 cwd 高度敏感
- 一旦目录结构调整,影响面极大
- 局部脚本行为难预测
- 本地与 CI、服务与脚本之间的 import 语义不稳定
### 优化建议
1. 先收敛核心入口(根 `main.py` + 5 个服务 `main.py/config.py`
2. 再收敛服务内 routes/services 的 path 注入
3. 最后收敛 tests/scripts
4. 推荐建立统一 bootstrap helper 或显式包运行约定
5. 长期建议迁移到更稳定的 package/import 结构
### 价值
这是整站工程可维护性的基础设施问题,不解决的话 shared 化永远会停在“看起来统一”。
---
## P1-2. Root `main.py` 已承担启动器职责,但与服务/文档/环境管理之间的契约仍旧脆弱
### 现象
`main.py`
- 负责 5 个服务统一拉起
- 自己处理 Windows / conda / venv / Python 路径探测
- 自己检查 `.env`
- 通过 subprocess + uvicorn 启动每个服务
这是一个“越来越重的启动器”。
### 问题
1. 环境选择逻辑混在业务启动器里
2. 文档、服务真实依赖、启动脚本之间的契约分散
3. 统一启动器既是开发工具,又试图兼容生产模式
4. 一旦某个服务需要特殊启动参数,根 `main.py` 会继续膨胀
### 优化建议
1. 明确 root `main.py` 的角色:
- 仅作为开发/本地一键启动器
- 不承担生产部署入口的抽象责任
2. 把环境探测逻辑拆出去
- 例如单独的 runtime/bootstrap helper
3. 用配置声明服务列表,而不是在代码里硬编码越来越多的服务元数据
4. README 明确区分:
- 开发启动
- 测试启动
- 生产部署
### 价值
避免根 `main.py` 继续演变成“全能脚本”。
---
## P1-3. `shared/health.py` 当前统一检查 sqlite但没有表达“每个服务的真实健康语义”
### 现象
`shared/health.py` 当前统一返回:
- service
- uptime
- database status
而所有服务都走这一套。
### 问题
这在格式统一上是好的,但语义上过度简化:
- `canvas` 主要是文件存储,但 health 只看 DB
- `blog` 的 search index / content dir 状态不在 health 中
- `prompt` 对外部 LLM provider 的依赖也不在 health 中
- `home` 的 content state 也不在 health 中
也就是说health 现在更像:
- “进程 + sqlite 基本可用”
而不是:
- “服务核心依赖健康”
### 优化建议
1. 保留 shared health response 骨架
2. 允许每个服务注册自己的 health probes
3. 将 health 结构设计为:
- shared baseline
- service-specific checks
4. 区分:
- `ok`
- `degraded`
- `error`
### 价值
这能显著提升运维判断质量避免“health 绿了但服务关键功能其实坏了”。
---
## P1-4. Service API 在 blog/canvas/prompt 三个服务中存在明显的重复模式,应该抽共享骨架
### 现象
三个 service API 都有相似结构:
- bearer token 识别
- actor 权限检查
- own draft / manageable state 判断
- 审计记录
- create / edit / delete / publish / unpublish
其中大量逻辑只是资源字段不同,本质模式一致。
### 问题
这类“高度相似但不完全相同”的复制是最危险的:
- 现在看还能维护
- 再迭代 2~3 次就会出现细节漂移
- 测试也会不断复制
### 优化建议
1. 抽 service API shared skeleton
- require_service_actor
- permission check helpers
- audit emit helper
- draft/manageable state helper interface
2. 资源特有逻辑通过回调/策略注入
3. 保持每个服务自己的 resource serializer
### 价值
这不是为了“抽象好看”,而是为了避免 blog/canvas/prompt 在未来演化出三套近似但不兼容的 draft workflow。
---
## P1-5. README / docs / 代码现状之间存在持续漂移,需要把“文档同步”从手工习惯变成约束
### 现象
顶层 README 仍然保留部分旧叙述,例如:
- `home/.env` 使用 `ENVIRONMENT`,其他服务使用 `ENV`
而代码实际上已经进入:
- shared config base
- `home` 兼容 `ENVIRONMENT`,但系统已有 `ENV` 主路径
类似漂移在多服务项目中会越来越常见。
### 优化建议
1. 把运行契约文档集中到一份单一权威说明
2. README 只保留高层入口,不重复易漂移细节
3. 与代码强耦合的配置/依赖契约,尽量让测试检查而不是只写文档
4. 把“更新 README”纳入涉及运行契约改动的 PR checklist
### 价值
减少“文档看起来对,但代码其实已经变了”的维护成本。
---
## 六、P2中优先级改进项
## P2-1. 启动时副作用偏多,部分初始化逻辑应继续外移
### 现象
示例:
- blog 启动时会检查并构建 search index
- prompt 启动时初始化 DB
- auth 启动时初始化 DB
### 问题
这种模式在开发期方便,但会导致:
- 启动时间与副作用不可预测
- 失败原因混在应用启动里
- 多进程/并发启动场景下更脆弱
### 优化建议
1. 区分“必须阻塞启动的初始化”和“可外移的预热任务”
2. search index 这类工作更适合显式脚本 / 后台任务 / 管理命令
3. DB migration 与 table bootstrap 应从服务启动逻辑继续拆离
---
## P2-2. 审计体系方向正确,但日志职责还可进一步统一
### 现象
项目已经有:
- `shared/audit_log.py`
- `shared/audit_events.py`
- service API 中的记录逻辑
- prompt service test audit log
### 问题
目前审计能力分成:
- 传统文本审计日志
- 结构化 event 记录
- 各服务局部 audit 表
这三类并存,但归属和用途界限还不够清楚。
### 优化建议
1. 明确区分:
- 运维审计日志
- 结构化安全事件
- 业务行为记录
2. 不同用途采用不同存储模型,但命名/入口统一
3. 避免某服务自己再长出第四套审计语义
---
## P2-3. Script 层数量已经不小,但还缺少明确分类
### 现象
根 scripts + 各服务 scripts 中,已经有相当多的管理脚本。
### 问题
这些脚本有的负责:
- DB init
- 迁移
- backup
- health
- audit rotate
- cache clear
- 校验工具
但当前更多是“文件集合”,不是“清晰操作面”。
### 优化建议
1. 给脚本分层:
- init
- migrate
- maintenance
- diagnose
- admin
2. 为每类脚本建立统一 CLI 约定
3. 减少“功能可用,但脚本发现与使用成本高”的问题
---
## P2-4. 多服务配置约定仍有历史兼容包袱,建议逐步统一为显式配置模型
### 现象
- `home` 仍兼容 `ENVIRONMENT`
- 其他服务走 `ENV`
- 各服务 config summary 字段不完全一致
- 部分服务仍自己决定目录存在性和默认值策略
### 建议
1. 保留兼容,但把兼容行为写进测试
2. 明确哪些配置是全局契约,哪些是服务局部契约
3. 配置模块尽量只做“读取 + 校验”,不做过多隐式推导
---
## 七、按维度汇总的完整优化清单
下面给出可以直接交给开发的总清单版本。
## A. 架构与边界
1. 重构 shared 目录为更清晰的核心/安全/治理分层
2. 定义 shared 为公共权威层,而不是可选工具箱
3. 清理服务内重复的 auth/token/helper 骨架
4. 统一 service API shared skeleton
5. 建立更清晰的 schema ownership 归属关系
6. 把 DB migration/bootstrap 从单个服务 `db.py` 中抽离
7. 收敛根 `main.py` 的职责,只保留开发启动器定位
## B. 数据与存储
8. 让各服务只初始化自己拥有的业务表
9. 建立统一 migration 入口和注册机制
10. 区分 shared 表、auth 表、blog 表、prompt 表等 ownership
11. 明确文件存储服务canvas/blog content与 sqlite 的边界
## C. 认证与权限
12. 抽 shared token verify / current user resolve helper
13. 抽 shared admin guard skeleton
14. 统一 service token 行为解释
15. 统一 redirect / login jump / unauthorized response 约定
16. 让服务只实现资源级权限,不重复协议级权限逻辑
## D. 测试
17. 将测试划分为 unit / contract / integration / script smoke
18. 把脚本式测试从核心 pytest 回归集合中分离
19. 减少 `sys.modules['src.config']` 类测试补丁
20. 建立统一 fixture / runtime helper
21. 新增服务入口装配合同测试
22. 新增配置兼容合同测试
23. 新增 shared/service API 行为合同测试
## E. 运维与部署
24. 统一依赖声明,确保 shared factory 新增依赖覆盖开发/测试/部署链路
25. 统一 README 与真实代码契约
26. 明确开发启动、测试启动、生产启动三种模式
27. 给 scripts 建立分类和统一调用方式
28. 让 health 支持服务特有探针
## F. 可维护性
29. 分阶段清理 `sys.path.insert(...)`
30. 统一 config summary 骨架,但不强行统一业务字段含义
31. 降低 import-time 副作用
32. 将启动阶段的重任务外移
33. 统一 shared 与服务层的异常处理约定
## G. 性能与运行时语义
34. review blog 的 search index 启动构建策略,考虑外移
35. review health response 语义,避免“数据库好=服务好”的误判
36. review缓存/内容读取路径,减少重复 IO 和重复解析热点
37. 评估 comments/likes/views/search 的存储与索引策略是否继续扩张会失控
---
## 八、建议实施顺序
整站层面不建议一次性全做,建议按风险和价值排序:
### 第一组:先收边界
1. schema ownership / migration 归属梳理
2. shared auth/service API/admin guard 协议层抽象
3. 收敛核心入口 path hack
### 第二组:再稳测试
4. 入口合同测试
5. 测试分类与 fixture 统一
6. 减少 patch 配置/patch module 风格测试
### 第三组:再治运行契约
7. 依赖链统一
8. README / scripts / 启动器 对齐
9. health probe 模型升级
### 第四组:最后处理性能与脚本治理
10. 启动重任务外移
11. 脚本层分类
12. 次级 IO/缓存/索引优化
---
## 九、完成定义
当以下条件同时成立时,才能说 `ephron.ren` 从“多服务功能可用”进入“整站工程结构稳定”:
1. shared 成为清晰的公共权威层
2. 数据库 schema ownership 明确,单服务不再越界建表
3. 认证/权限协议不再跨服务重复实现
4. 测试体系不再依赖大量结构性 patch 才能跑起来
5. 启动、依赖、文档、脚本的运行契约一致
6. health / migration / scripts / shared app factory 都有明确职责边界
---
## 十、最终结论
如果只看功能,这个项目已经能跑很多东西;但如果看长期维护,它最需要的不是再堆功能,而是:
> 把已经出现的“shared、RBAC、service API、统一启动、统一测试”这些好方向真正收敛成稳定边界。
现在最大的风险不是“缺模块”,而是:
- 模块已经有了,但边界还不够硬
- shared 已经有了,但权威性还不够强
- 测试已经很多了,但结构还不够稳
这也是为什么本清单的重点会落在:
- 架构边界
- schema ownership
- auth 协议统一
- 测试分层
- 运维契约对齐
而不是零散功能修补。
从整站视角看,只要先把这几条收住,后续新功能开发成本会明显下降,回归风险也会显著降低。