From d6c8d17ce78626f2d520d7a9a72c50bcd4bf1fd2 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 16 May 2026 15:22:42 +0800 Subject: [PATCH] docs: add full codebase optimization checklist for ephron.ren --- ...en-full-codebase-optimization-checklist.md | 730 ++++++++++++++++++ 1 file changed, 730 insertions(+) create mode 100644 prd-ephron-ren-full-codebase-optimization-checklist.md diff --git a/prd-ephron-ren-full-codebase-optimization-checklist.md b/prd-ephron-ren-full-codebase-optimization-checklist.md new file mode 100644 index 0000000..b8eb708 --- /dev/null +++ b/prd-ephron-ren-full-codebase-optimization-checklist.md @@ -0,0 +1,730 @@ +# 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 协议统一 +- 测试分层 +- 运维契约对齐 + +而不是零散功能修补。 + +从整站视角看,只要先把这几条收住,后续新功能开发成本会明显下降,回归风险也会显著降低。