Files
ephron-ren-prd/prd-app-factory-config-unification-batch2.md

10 KiB
Raw Permalink Blame History

PRD: App Factory + Config 统一重构PR1 Batch 2

背景

PR1 Batch 1 已完成并通过验证,已落地:

  • shared/config_base.py
  • shared/error_handlers.py
  • shared/app_factory.py
  • tests/test_shared_config_base.py
  • tests/test_error_handlers.py
  • tests/test_app_factory.py

当前 Batch 1 已验证通过,共 26 个测试通过,说明 shared 基础骨架已经可用。

接下来的 Batch 2 不再新增基础模块,而是把这些 shared 能力真正接入五个服务

  1. 改造五个服务的 config.py
  2. 改造五个服务的 main.py
  3. 调整必要的兼容测试与行为验证

这一批是 PR1 中真正高风险的部分,因为它会影响现有服务启动与运行行为。


Batch 2 目标

本批次完成后,应该达到:

  1. 五个服务 config.py 改为复用 shared config helper
  2. 五个服务 main.py 改为通过 shared app factory 创建 app
  3. home 继续兼容历史 ENVIRONMENT
  4. /health 只保留统一实现,不产生重复注册
  5. 外部行为保持兼容:
    • URL 不变
    • docs_url 行为不变
    • static 挂载策略不被误改
    • 404/500 页面行为兼容

非目标

这一批不做

  • 不收敛 sys.path.insert
  • 不改数据库 migration 归属
  • 不改 service API
  • 不调整目录结构
  • 不统一所有 config 展示字段的内容

原因:这一批的核心任务是接入 shared 骨架,不是扩大范围做结构总清理。


批次顺序建议

为了降低回归风险,建议不要一次性全量乱序改。

先改 config.py

顺序建议:

  1. auth/src/config.py
  2. blog/src/config.py
  3. canvas/src/config.py
  4. prompt/src/config.py
  5. home/src/config.py 最后

原因:

  • homeENVIRONMENT 历史兼容包袱,特殊性最强
  • 先处理标准服务,再处理兼容服务,排障更容易

再改 main.py

顺序建议:

  1. canvas/src/main.py
  2. prompt/src/main.py
  3. blog/src/main.py
  4. auth/src/main.py
  5. home/src/main.py 最后

原因:

  • canvasprompt 相对简单
  • blog/auth 启动逻辑与历史 handler 更复杂
  • home 还涉及重复 /health,最容易出兼容问题

Step 5改造五个服务 config.py

涉及:

  • auth/src/config.py
  • blog/src/config.py
  • canvas/src/config.py
  • home/src/config.py
  • prompt/src/config.py

目标:

  • 删除重复的 .env / required / optional / env mode helper
  • 改为复用 shared/config_base.py
  • 保持各服务专属字段与校验逻辑不变

5.1 auth/src/config.py

保留内容

  • AUTH_SECRET_KEY
  • DATABASE_PATH
  • COOKIE_DOMAIN
  • COOKIE_NAME
  • TOKEN_MAX_AGE
  • PROJECT_ROOT
  • TEMPLATES_DIR
  • validate_config()

改造方式

  • load_service_env(_project_root) 替换本地 .env 加载逻辑
  • get_required_env() / get_optional_env() 替换本地 helper
  • 用 shared summary helper 统一打印机制

注意事项

  • validate_config() 的行为不能漂移
  • 现有 auth 的输出字段尽量保持一致,避免影响排障习惯

5.2 blog/src/config.py

保留内容

  • AUTH_SECRET_KEY
  • TOKEN_MAX_AGE
  • CONTENT_DIR
  • CACHE_DIR
  • SEARCH_INDEX_DIR
  • COOKIE_NAME
  • PROJECT_ROOT
  • STATIC_DIR
  • TEMPLATES_DIR

改造方式

  • 替换 env helper 为 shared helper
  • 保留:
    • CONTENT_DIR 存在性检查
    • CACHE_DIR.mkdir(...)
    • SEARCH_INDEX_DIR.mkdir(...)

注意事项

  • 不要把目录初始化逻辑抽进 shared 层
  • blog 目录语义应继续由 blog 自己负责

5.3 canvas/src/config.py

保留内容

  • AUTH_SECRET_KEY
  • TOKEN_MAX_AGE
  • CONTENT_DIR
  • COOKIE_NAME
  • PROJECT_ROOT
  • TEMPLATES_DIR

改造方式

  • 替换 env helper 为 shared helper
  • 保留 CONTENT_DIR 不存在时自动创建的行为

注意事项

  • 不能把当前行为从“自动创建”改成“配置报错退出”
  • 这点和 blog 不同,不能硬统一

5.4 prompt/src/config.py

保留内容

  • AUTH_SECRET_KEY
  • TOKEN_MAX_AGE
  • DATABASE_PATH
  • PROJECT_ROOT
  • TEMPLATES_DIR
  • validate_config()

改造方式

  • 替换 env helper 为 shared helper
  • 暂时不扩大范围去彻底修 prompt 的 import 结构

注意事项

  • 这一批只做 config 接入,不顺手改 import 体系
  • 避免把单个 PR 变成“顺便半重构”

5.5 home/src/config.py

这是本批 config.py 里最需要小心的一个。

保留内容

  • STATIC_DIR
  • TEMPLATES_DIR
  • COOKIE_NAME
  • SERVICE_PORT
  • AUTH_PORT
  • AUTH_BASE_URL
  • AUTH_LOGIN_URL
  • validate_config()

改造方式

  • 使用 resolve_environment(legacy_key="ENVIRONMENT")
  • ENV 成为统一主字段
  • 兼容历史 ENVIRONMENT

必测要求

  • 只设置 ENVIRONMENT=development 时,仍进入开发模式
  • 同时设置 ENV=productionENVIRONMENT=development 时,以 ENV 为准

注意事项

  • 这里不要用“看起来统一”破坏历史兼容
  • AUTH_BASE_URL / AUTH_LOGIN_URL 逻辑必须保持不变

Step 6改造五个服务 main.py

涉及:

  • auth/src/main.py
  • blog/src/main.py
  • canvas/src/main.py
  • home/src/main.py
  • prompt/src/main.py

目标:

  • 删除重复的 app 创建与通用装配逻辑
  • 改为统一通过 shared.app_factory.create_service_app(...)

每个服务应保留:

  • service 专属 lifespan
  • router 列表
  • 标题/描述/version
  • templates/static 路径
  • service_name

6.1 canvas/src/main.py

建议先改这个,因为最简单。

要保留

  • validate_config()
  • print_config_summary()
  • canvas 专属 lifespan
  • pages/admin/service_api routers

要替换

  • 手写 FastAPI(...)
  • 手写 install_security_headers(app)
  • 手写 limiter 装配
  • 手写 static mount
  • 手写 error handlers
  • 手写 /health

注意事项

  • static_dir 传入时必须兼容“目录存在才挂载”策略

6.2 prompt/src/main.py

要保留

  • init_db()
  • print_config_summary()
  • prompt 专属 routers

注意事项

  • app factory 只负责 app 壳,不负责 prompt 特有 db 初始化
  • db 初始化仍放在 prompt 自己 lifespan 里

6.3 blog/src/main.py

要保留

  • search index 启动检查逻辑
  • print_config_summary()
  • blog 专属 routers

注意事项

  • 这批不要顺手优化“搜索索引启动阻塞”问题
  • 只做 app factory 接入,保持当前行为

6.4 auth/src/main.py

要保留

  • init_db()
  • _build_login_target() 与 root redirect 逻辑
  • print_config_summary()
  • auth 专属 routers

注意事项

  • auth 有较多 redirect / login 细节,这批只做 app 壳替换,不改 redirect 语义

6.5 home/src/main.py

这是本批 main.py 中最需要小心的一个。

必做

  • 将 app 创建迁到 factory
  • 处理 /health 重复定义

推荐做法

  • 删除 home/src/routes/pages.py 中的 /health
  • 统一由 app factory 提供 /health

原因

如果两处都保留,会出现:

  • 路由重复
  • 行为漂移
  • 后续 health 契约难统一

注意事项

  • home 是兼容包袱最多的服务,建议最后处理

需要补的验证

一、config 层验证

建议至少验证:

python -m pytest tests/test_security_hardening.py -q
python -m pytest auth/tests -q
python -m pytest blog/tests -q
python -m pytest canvas/tests -q
python -m pytest home/tests -q
python -m pytest prompt/tests -q

重点确认:

  • homeENVIRONMENT 兼容逻辑仍然成立
  • 各服务 config import 后不会报错

二、main.py 接入验证

建议验证:

  • 所有服务仍能创建 app
  • dev 模式 /docs 仍可用
  • /health 正常
  • API 404 返回 JSON
  • 页面 404/500 继续使用模板
  • static 挂载策略不漂移

如本地可启动,建议:

python main.py --reload

手动检查:

  • home / auth / blog / canvas / prompt 均可启动
  • 任意不存在 API 路径返回 JSON 404
  • 任意不存在页面返回模板 404

必须特别注意的 4 个坑

1. 不要扩大范围改 import 结构

这批不要顺手去处理 sys.path.insert

原因:

  • 会扩大变更面
  • 增加排障难度
  • 混淆“是 app factory 接入问题,还是 import 重构问题”

2. 不要把 print_config_summary() 内容硬统一

共享层只应统一打印机制,而不是强行让所有服务显示完全同样的字段。

原因:

  • 每个服务关注的关键字段不同
  • 一刀切会损失调试价值

3. API 500 JSON 化属于“标准化改进”,要显式说明

Batch 1 中 shared error handler 已将 API 500 规范成 JSON

{"detail": "Internal Server Error"}

development 模式可额外包含:

{"detail": "Internal Server Error", "error": "..."}

这是合理改进,但应在实现说明中显式标注,避免被误解为无意行为变化。


4. home/src/routes/pages.py/health 不能双留

如果 app factory 已统一提供 /health,就不能再保留 home pages 里的那份。

这是本批次最可能引发路由重复问题的点。


建议提交拆分

建议至少拆成 4 个 commit

  1. refactor: migrate auth/blog/canvas/prompt config modules to shared helpers
  2. refactor: migrate home config module with ENVIRONMENT compatibility
  3. refactor: migrate canvas/prompt/blog/auth main modules to shared app factory
  4. refactor: migrate home main module to shared app factory and unify health endpoint

这样更方便分批 review 和定位问题。


完成定义

Batch 2 完成后,必须满足:

  • 五个服务 config.py 已接入 shared/config_base.py
  • 五个服务 main.py 已接入 shared/app_factory.py
  • home 兼容 ENVIRONMENT
  • /health 统一且无重复注册
  • static 挂载策略保持兼容
  • API 404/500 与页面 404/500 行为符合预期
  • 所有相关测试通过

后续建议

Batch 2 完成后,下一步就可以进入:

  1. PR1 收尾复查
  2. PR2shared/service_api/*tests/helpers/*
  3. PR3处理 import 结构与 sys.path.insert
  4. PR4统一 DB schema / migration ownership

这才是合理的节奏:先把 shared app/config 真正接上,再继续更深的结构治理。