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

22 KiB
Raw Blame History

PRD — ephron.ren 全项目代码阅读后的完整优化清单

说明

本清单基于对 ephron.ren 远端 origin/main 的系统性源码阅读整理,不以当前本地工作树为准。

之所以强调这一点,是因为本地仓库当前状态与远端并不一致:

  • 本地 HEADorigin/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/coreports、config、health、sqlite、templating 等基础设施
    • shared/securitycookie、csrf、redirect、request_ip、network_safety、service_tokens
    • shared/governanceaudit_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
    • contractshared 协议、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. 数据与存储

  1. 让各服务只初始化自己拥有的业务表
  2. 建立统一 migration 入口和注册机制
  3. 区分 shared 表、auth 表、blog 表、prompt 表等 ownership
  4. 明确文件存储服务canvas/blog content与 sqlite 的边界

C. 认证与权限

  1. 抽 shared token verify / current user resolve helper
  2. 抽 shared admin guard skeleton
  3. 统一 service token 行为解释
  4. 统一 redirect / login jump / unauthorized response 约定
  5. 让服务只实现资源级权限,不重复协议级权限逻辑

D. 测试

  1. 将测试划分为 unit / contract / integration / script smoke
  2. 把脚本式测试从核心 pytest 回归集合中分离
  3. 减少 sys.modules['src.config'] 类测试补丁
  4. 建立统一 fixture / runtime helper
  5. 新增服务入口装配合同测试
  6. 新增配置兼容合同测试
  7. 新增 shared/service API 行为合同测试

E. 运维与部署

  1. 统一依赖声明,确保 shared factory 新增依赖覆盖开发/测试/部署链路
  2. 统一 README 与真实代码契约
  3. 明确开发启动、测试启动、生产启动三种模式
  4. 给 scripts 建立分类和统一调用方式
  5. 让 health 支持服务特有探针

F. 可维护性

  1. 分阶段清理 sys.path.insert(...)
  2. 统一 config summary 骨架,但不强行统一业务字段含义
  3. 降低 import-time 副作用
  4. 将启动阶段的重任务外移
  5. 统一 shared 与服务层的异常处理约定

G. 性能与运行时语义

  1. review blog 的 search index 启动构建策略,考虑外移
  2. review health response 语义,避免“数据库好=服务好”的误判
  3. review缓存/内容读取路径,减少重复 IO 和重复解析热点
  4. 评估 comments/likes/views/search 的存储与索引策略是否继续扩张会失控

八、建议实施顺序

整站层面不建议一次性全做,建议按风险和价值排序:

第一组:先收边界

  1. schema ownership / migration 归属梳理
  2. shared auth/service API/admin guard 协议层抽象
  3. 收敛核心入口 path hack

第二组:再稳测试

  1. 入口合同测试
  2. 测试分类与 fixture 统一
  3. 减少 patch 配置/patch module 风格测试

第三组:再治运行契约

  1. 依赖链统一
  2. README / scripts / 启动器 对齐
  3. health probe 模型升级

第四组:最后处理性能与脚本治理

  1. 启动重任务外移
  2. 脚本层分类
  3. 次级 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 协议统一
  • 测试分层
  • 运维契约对齐

而不是零散功能修补。

从整站视角看,只要先把这几条收住,后续新功能开发成本会明显下降,回归风险也会显著降低。