docs: add complete unification optimization checklist

This commit is contained in:
Ubuntu
2026-05-16 15:13:58 +08:00
parent aebe281a05
commit babb2d9e3e

View File

@@ -0,0 +1,537 @@
# PRD — App Factory / Config Unification 完整优化清单
## 背景
`ephron.ren` 当前已经完成了一轮 app factory / config shared 化重构,远端相关主线提交为:
- `14484ca` — Add shared modules: app factory, config base, error handlers with tests
- `6d94b08` — Refactor all apps to use shared config and app factory
- `378a4e5` — Update home pages route and add test templates
现状不是“完全没做”,而是:
- shared 基础设施已经建立
- 五个服务已经基本接入 shared app/config 骨架
- 但整体状态仍停留在“完成了第一轮统一”,还没达到“结构稳定、依赖完整、验证闭环、后续不易漂移”的完成态
因此这份 PRD 不再按 Batch 1 / Batch 2 / follow-up 拆分,而是直接给出 **从当前状态到完成态的完整优化清单**
这份文档的目标是:开发只看这一份,就知道哪些必须改、哪些建议改、哪些不要顺手乱改,以及最后怎么验收。
---
## 总体结论
当前重构方向是对的,但还差四类关键补完:
1. **依赖契约没补齐**
- `shared.app_factory` 已把 `slowapi` 变成公共硬依赖
- 但测试/安装链路没有完全同步,导致服务入口级测试会直接 import 失败
2. **导入边界不稳定**
- `main.py` / `config.py` 乃至 route/service/test 里仍保留大量 `sys.path.insert(...)`
- 说明 shared 化了逻辑,但没收住模块边界
3. **admin 路由守卫仍是服务内私有实现**
- `home` 已有实际 guard
- 但 guard 骨架没 shared 化,未来其他服务继续扩展时很容易复制漂移
4. **验证层只证明了 shared 能跑,没充分证明服务入口能跑**
- 当前 shared tests 通过,不代表五个服务入口都可稳定导入/装配
---
## 优化目标
完成本清单后,应该达到以下状态:
1. 五个服务的 app 创建与 config 读取,已经统一且可维护
2. shared app factory 的依赖在开发、测试、部署三条链路中一致成立
3. Batch 2 涉及的 10 个 `main.py/config.py` 文件不再各自复制路径注入模板
4. `home` 的 admin 守卫公共骨架进入 shared 层,后续可供其他服务复用
5. `/health` 只由 shared app factory 统一归口
6. 测试不仅覆盖 shared 合同,还覆盖服务入口装配合同
7. 改完后可以明确说:这轮统一已经从“代码抽取”升级为“工程约束已建立”
---
## 非目标
本轮不要做以下事情:
- 不重写整站认证体系
- 不全量重构所有 route/service/test 的导入结构
- 不一次性把所有 auth/token 逻辑全部抽进 shared
- 不改业务权限模型
- 不改 service API 设计
- 不迁移仓库目录结构
- 不强制一步到位改成完整 package 化(如全面 pyproject/installable layout
- 不顺手做与本次重构无关的业务修复
原则很简单:**只修 app/config 统一后暴露出来的结构性缺口,不把这轮工作膨胀成全仓重构。**
---
## 一、必须修改P0 / P1
## P0-1. 补齐 `slowapi` 依赖契约
### 问题
`shared.app_factory.py` 已直接依赖:
- `slowapi._rate_limit_exceeded_handler`
- `slowapi.errors.RateLimitExceeded`
这意味着:
- 只要服务入口用 shared factory
- `slowapi` 就不再是“某服务可选依赖”
- 而是整个服务启动路径的公共硬依赖
复审中的实际验证结果也说明了这个问题:
```bash
python -m pytest tests/test_security_hardening.py tests/test_frontend_backend_reuse_contract.py -q
```
通过;但执行:
```bash
python -m pytest auth/tests/test_security_hardening.py auth/tests/test_login_redirect_flow.py -q
```
在 collection 阶段报:
```text
ModuleNotFoundError: No module named 'slowapi'
```
### 必须改什么
1. 检查项目实际依赖入口
- 根依赖文件
- 测试依赖入口
- 部署安装入口
2. 保证 `slowapi` 在这三条链路里都被安装
3. 如果存在多个 requirements 文件,必须统一,不允许某条链路漏掉
4. 若 CI 有单独安装脚本,也必须同步更新
### 验收标准
以下命令在标准开发环境中必须通过:
```bash
python -m pytest tests/test_security_hardening.py tests/test_frontend_backend_reuse_contract.py -q
python -m pytest auth/tests/test_security_hardening.py auth/tests/test_login_redirect_flow.py -q
```
且不允许再出现:
```text
ModuleNotFoundError: slowapi
```
---
## P0-2. `/health` 必须只保留 shared app factory 单一归口
### 问题
app factory 统一后的设计目标之一,就是 `/health` 由 shared factory 统一注册。
这件事必须做到“单一所有权”,否则后续一旦 health 响应结构升级,很容易出现某个服务还是旧实现。
当前重点确认点:
- `home/src/routes/pages.py` 不应再重复定义 `/health`
- 其他服务也不应在页面路由层残留重复 health endpoint
### 必须改什么
1. 全仓检查 `/health` 定义位置
2. 保留 shared app factory 中的统一实现
3. 删除各服务 pages/routes 中的重复实现
4. 保证最终每个服务的 `/health` 都来自同一装配路径
### 验收标准
- 服务层页面路由文件中不再重复定义 `/health`
- `GET /health` 行为仍与现有外部契约兼容
- 相关 shared / entrypoint tests 通过
---
## P1-1. 收敛 Batch 2 目标文件中的 `sys.path.insert(...)` 残留
### 问题
本轮 shared 化后,以下 10 个核心文件本身仍保留路径注入模板:
- `auth/src/config.py`
- `blog/src/config.py`
- `canvas/src/config.py`
- `prompt/src/config.py`
- `home/src/config.py`
- `auth/src/main.py`
- `blog/src/main.py`
- `canvas/src/main.py`
- `prompt/src/main.py`
- `home/src/main.py`
这说明当前统一只是“逻辑 shared 化”,不是“导入边界稳定化”。
### 必须改什么
本轮至少把这 10 个文件收住,不要求一次性清理全仓。
推荐两种方案里选一种:
#### 方案 A抽统一 import bootstrap helper推荐
例如新增:
- `shared/imports.py`
提供统一函数,例如:
```python
def ensure_project_root(file_path: str, levels: int = 3) -> None: ...
```
让入口/配置文件统一调用 helper不再各自复制
```python
project_root = Path(...)
if str(project_root) not in sys.path:
sys.path.insert(0, str(project_root))
```
#### 方案 B修正运行/测试约定,让入口文件不再自行改 path
如果当前项目运行方式允许,也可以通过统一 cwd / pytest path / uvicorn 启动约定来消除核心入口内的 path hack。
但从风险和改造成本看,本轮更推荐方案 A。
### 最低要求
至少保证上面列出的 10 个文件不再各自手写重复模板,哪怕先统一到一个 helper。
### 验收标准
- 10 个核心文件中不再散落重复的 path 注入模板
- 改完后这 10 个文件仍然可导入
- 不引入新的循环依赖
---
## P1-2. 将 home/admin 路由守卫的公共骨架提取到 shared
### 问题
当前 `home/src/routes/admin.py` 实际上已经有明确的服务端路由守卫:
- 未登录跳转 auth 登录页
- 带 redirect 返回
- 已登录但无权限则拒绝/跳转
- service token 禁止访问 home admin
这说明现在 **有 guard**,但它仍然是 `home` 服务内的私有实现。问题不在“有没有守卫”,而在“守卫骨架没有统一”。
如果未来 blog/canvas/prompt 继续加强 admin 规则,极容易再次复制 `_require_auth(...)` 模式,造成:
- 登录跳转策略漂移
- redirect 处理方式漂移
- service token admin 访问策略漂移
### 必须改什么
1.`shared/` 新增 admin guard helper命名可调整
2. helper 至少负责这三件事:
- 未登录时的登录跳转 URL 拼装
- service token 是否允许访问 admin 的统一策略
- 权限失败时的统一返回约定
3. `home/src/routes/admin.py` 改为消费 shared helper
4. 先落地 home不要求本轮同步改完所有服务 admin
### 不需要在本轮做的事
- 不要求把所有业务权限判断都抽进去
- 不要求统一所有服务特有的资源级权限逻辑
- 不要求一次性重写 blog/canvas/prompt 的 admin 认证结构
### 验收标准
- `home/src/routes/admin.py` 不再保留大段内联 guard 骨架模板
- shared helper 能表达登录跳转 / redirect / service token admin 禁入策略
- home 现有 admin 行为无回归
---
## P1-3. 补服务入口装配级合同测试
### 问题
当前 shared 测试通过,能证明:
- shared config base 基本可用
- shared error handlers 基本可用
- shared app factory 基本可用
但这不等于五个真实服务入口都还能导入、装配、挂 router、提供 `/health`
现在缺的是一类非常轻量但非常关键的测试:**服务入口装配合同测试**。
### 必须改什么
新增一组轻量测试,重点不是测业务,而是测“服务入口仍站得住”。
建议覆盖:
1. 五个服务入口都可导入
- `auth/src/main.py`
- `blog/src/main.py`
- `canvas/src/main.py`
- `prompt/src/main.py`
- `home/src/main.py`
2. 导入后存在 `app`
3. `app.routes` 中包含 `/health`
4. docs 开关仍符合 dev/prod 预期
5. static mount / router 注册没有在统一重构中丢失
### 验收标准
新增测试能在这些情况给出明确失败信号:
- shared factory 依赖缺失
- 入口导入断裂
- `/health` 丢失
- app factory 装配未生效
---
## 二、建议修改P2
这些不是“本轮不改就一定阻断”的问题,但建议一起纳入开发检查表。
## P2-1. 统一依赖声明与文档说明
### 建议改什么
1. 在依赖文件中明确标注 shared app factory 的新增公共依赖
2. 若项目有 README / 开发说明,补一句:
- 使用 shared app factory 的服务,需要安装公共依赖集
3. 若有部署脚本或 bootstrap 脚本,检查是否与 requirements 同步
### 目的
避免开发者只看代码不看变更背景,导致本地能跑 shared tests、却跑不动服务 tests。
---
## P2-2. 为 `ENV` / `ENVIRONMENT` 兼容关系补显式测试
### 背景
当前 `home` 仍兼容历史 `ENVIRONMENT`,这是对的,但兼容行为需要被明确测试下来,否则后面很容易被“顺手清理”掉。
### 建议增加的断言
至少覆盖:
1. 只设置 `ENVIRONMENT=development` 时,`home` 仍进入开发模式
2. 同时设置 `ENV=production``ENVIRONMENT=development` 时,以 `ENV` 为准
3. 未设置时默认回落到 `production`
### 目的
把“历史兼容”从口头约定变成测试契约。
---
## P2-3. 统一 config summary 输出风格,但不要统一业务字段含义
### 建议改什么
1. 保持 summary 打印格式统一
2. 但不要为了“字段看起来一样”而强行让各服务展示完全同一组字段
### 原则
- 统一的是打印骨架
- 不是每个服务必须展示完全一样的业务字段
例如:
- `blog` 仍应展示 `CONTENT_DIR` / `CACHE_DIR`
- `home` 仍应展示 `AUTH_BASE_URL` / `SERVICE_PORT`
### 目的
避免“形式统一”侵入业务语义。
---
## P2-4. 为后续全仓导入治理保留清单,但不要本轮扩大范围
### 已确认存在的后续技术债
除了 10 个核心文件外route/service/test 层仍有较多 `sys.path.insert(...)`
### 建议处理方式
- 本轮只在 PRD 中登记为后续项
- 不要在这轮顺手扩展到全仓清理
### 原因
这类改动跨面太大,容易把“当前可收敛的重构收尾”演变成“无法控风险的大扫除”。
---
## 三、明确不要修改的内容
以下内容在本轮必须明确禁止“顺手改”:
1. **不要重写业务权限模型**
- 例如 owner/admin/user 的权限体系
- 不属于 app/config 统一收尾范围
2. **不要把所有 auth/token 校验逻辑一次性抽到 shared**
- 当前只要求抽 admin guard 公共骨架
- 不是全站认证大重构
3. **不要一口气清理所有 `sys.path.insert(...)`**
- 只收缩 Batch 2 涉及的核心入口/配置文件
- 其余留待后续技术债专项
4. **不要改 service API / 路由外部契约**
- URL 不变
- 响应形态不因为这轮统一而改变
5. **不要顺手改目录结构**
- 不迁移为全量 package layout
- 不移动服务目录
6. **不要把 config 层业务逻辑抽进 shared**
- 例如 blog 的缓存目录创建
- canvas 的 content 目录自动创建
- 这些仍应由各服务自己负责
---
## 四、建议实施顺序
虽然这份文档不再按阶段写,但实际落地仍建议按风险从低到高推进:
### 1. 先补依赖契约
- 先解决 `slowapi` 安装链路
- 否则后续很多入口测试都没法真实验证
### 2. 再补入口合同测试
- 先建立“导入/装配级失败能被看见”的机制
- 避免边改边盲飞
### 3. 再收敛 10 个核心文件的 path hack
- 控制范围,不碰全仓
### 4. 再抽 home/admin guard 骨架
- 这是结构优化,不是依赖修复,放在后面更稳
### 5. 最后全量回归
- shared tests
- auth smoke
- home tests
- 新增 entrypoint tests
---
## 五、建议涉及文件
## 必改文件
- `shared/app_factory.py`
- `shared/config_base.py`(如需补 helper / 兼容逻辑 / 测试契约)
- `auth/src/main.py`
- `blog/src/main.py`
- `canvas/src/main.py`
- `prompt/src/main.py`
- `home/src/main.py`
- `auth/src/config.py`
- `blog/src/config.py`
- `canvas/src/config.py`
- `prompt/src/config.py`
- `home/src/config.py`
- 依赖声明文件(按项目实际结构)
## 建议新增文件
- `shared/imports.py` 或等价 helper
- `shared/admin_guard.py` 或等价 helper
- `tests/test_service_entrypoints.py` 或等价入口合同测试文件
## 只观察,不要求本轮修改
- `home/src/services/auth.py`
- 其他 route/service/test 中的历史 `sys.path.insert(...)`
- 任何 service API / 业务 handler 的功能逻辑
---
## 六、完整验收命令
至少执行并记录以下验证:
```bash
cd /home/ubuntu/ephron.ren
git fetch origin
python -m pytest tests/test_security_hardening.py tests/test_frontend_backend_reuse_contract.py -q
python -m pytest auth/tests/test_security_hardening.py auth/tests/test_login_redirect_flow.py -q
```
如果新增了入口合同测试,再执行:
```bash
python -m pytest tests/test_service_entrypoints.py -q
```
如果抽了 home admin guard helper再补
```bash
python -m pytest home/tests -q
```
如果有 shared 相关新增单测,也一并跑:
```bash
python -m pytest tests/test_shared_config_base.py tests/test_error_handlers.py tests/test_app_factory.py -q
```
---
## 七、完成定义
满足以下全部条件,才算这轮优化真正完成:
1. `slowapi` 在开发、测试、部署链路中都已被视为公共硬依赖
2. 服务入口级测试不再因 `slowapi` 缺失而 import 失败
3. `/health` 已统一归口到 shared app factory
4. Batch 2 涉及的 10 个核心 `main.py/config.py` 文件不再各自复制 path 注入模板,或至少统一到同一 helper
5. `home` 的 admin 路由守卫公共骨架已进入 shared 层
6. 新增服务入口装配合同测试,并实际通过
7. shared 层测试 + auth smoke + home 相关测试均通过
8. 外部行为未发生非预期变化:
- URL 不变
- docs_url 行为兼容
- static mount 行为兼容
- 404/500 页面行为兼容
---
## 八、一句话给开发的执行原则
这轮工作的本质不是“继续抽公共代码”,而是:
> 把已经做完的 shared 化,补成一套真正可依赖、可验证、可持续的工程约束。
判断标准也很明确:
- 不是“代码看起来更整洁了”
- 而是“入口真的能导入、依赖真的齐、guard 不再乱飘、测试真的能兜住回归”
做到这一点,这轮 app factory / config unification 才算真正收口。