8.7 KiB
8.7 KiB
Python 重构方案
本文档基于当前 Go 实现,给出迁移到 Python + FastAPI 的设计输入与建议顺序。本文档只讨论迁移方案,不代表已经开始实现。
重构原则
- 以当前 Go 实现为唯一事实来源
- 先保持对外行为兼容,再考虑内部清理和优化
- 明确区分“行为兼容”和“内部实现升级”
- 默认不把 Notion 纳入新的 Python 主版本目标,除非后续重新决策
- 尽量按模块迁移,并在模块之间建立清晰契约
目标形态
建议的 Python 目标架构:
- 用 FastAPI 提供 HTTP 路由,并自然生成 OpenAPI
- 业务逻辑按模块拆分到 service layer
- 外部系统对接放到 adapter layer
- SQLite 访问放到 repository layer
- 配置采用显式 settings model
- scheduler 是否内嵌在应用进程内,需要在启动语义明确后再决定
- 仅保留极轻量的服务端页面,用于 OAuth 跳转或简单配置
建议的 Python 模块边界
应用外壳层
- 职责:
- 读取 settings
- 依赖注入与对象装配
- 路由注册
- lifespan hooks
- scheduler 启停
- 在 FastAPI 中可对应:
main.py或 app factory- settings 类
Poo 领域模块
- 职责:
- 校验 poo record 输入
- 持久化 poo record
- 查询 latest poo
- 通过接口触发外部副作用
- 建议把副作用依赖抽象为端口:
PooRepositoryHomeAssistantPublisherHomeAssistantWebhookClient- 如有需要,可保留临时
LegacyPooMirror作为 Notion 过渡适配器
Location 领域模块
- 职责:
- 校验并持久化位置点
- 可保持简洁:
LocationRepositoryLocationService
Home Assistant 命令网关
- 职责:
- 暴露
/homeassistant/publish - 解析
target/action/content - 将命令分发到内部服务
- 暴露
- 兼容性注意:
- 第一阶段应保留当前
content的处理习惯,包括对字符串 payload 的兼容解析
- 第一阶段应保留当前
TickTick 集成模块
- 职责:
- OAuth start / callback
- token 存储
- task 查询
- 去重
- task 创建
- 建议:
- 把 token persistence 抽象成独立能力,而不是把“改写配置文件”直接塞进业务逻辑
Home Assistant 出站适配层
- 职责:
- 发布 sensor state
- 触发 webhook
- 该层小而独立,适合较早迁移
Legacy Notion 适配层
- 职责:
- 只在分析或过渡阶段表示当前行为
- 默认建议:
- 不放入 Python 第一版正式目标
- 如 cutover 期间确有需要,可以 feature flag 或独立迁移工具的方式暂存
实现前需要冻结的兼容契约
在正式编码前,建议先把以下当前行为写成明确契约:
API 契约
POST /poo/record的请求字段与当前“成功时空响应体”的行为POST /location/record的请求字段与数值解析行为POST /homeassistant/publish的 envelope 格式与支持的target/actionGET /ticktick/auth/code的成功 / 失败语义
副作用契约
POST /poo/record在什么时机会发布 Home Assistant sensorPOST /poo/record在什么条件下会触发 Home Assistant webhook- Home Assistant 消息如何映射为 TickTick task title 与 due date
- Home Assistant sensor payload 的结构
持久化契约
- 当前 SQLite 表名与主键
- 当前磁盘上的时间戳格式
- Python 第一阶段是否直接复用现有 DB 文件,还是做显式迁移
建议的迁移决策
决策 1:第一阶段保持对外 API 形状不变
原因:
- 当前 API 面很小
- 保持兼容能显著降低切换风险
- 即使保持兼容,FastAPI 仍然可以生成 OpenAPI 文档
决策 2:把内部 self-HTTP 改成直接服务调用
原因:
- 当前 Go 代码中的
localhost自调用,本质上是内部编排手段 - 这不是一个必须暴露给外部的契约
- Python 版改为直接函数 / service 调用,可以提升清晰度和可测试性
决策 3:先继续使用 SQLite
原因:
- 当前系统已经使用 SQLite
- 数据模型规模很小
- PostgreSQL 更适合作为 parity 之后的下一阶段演进
决策 4:默认不迁 Notion,但要明确记录影响
原因:
- 你已经明确表示 Notion 很可能不继续保留
- 当前 Notion 不是“代码里有但没在用”,而是真正参与运行逻辑
- 所以不能静默删除,而要在方案中写清楚删掉后有什么影响
决策 5:把 token / auth persistence 做成显式设计
原因:
- 当前 TickTick token 处理虽然可用,但运维上比较脆弱
- Python 重构是一个把这件事规范化的机会
建议迁移顺序
Phase 0:盘点与契约确认
- 完成当前系统 inventory
- 确认哪些当前行为是“必须兼容的契约”,哪些只是历史偶然实现
- 明确把 Notion 标为 non-migration scope,除非后续重新决定
Phase 1:Python 骨架与通用基础设施
- 建立 FastAPI app shell
- 定义 settings / config model
- 定义日志方案
- 定义 SQLite 访问方式
- 定义测试框架与 fixture 策略
- 定义 OpenAPI 生成与导出方式
这一阶段不需要大量迁移业务逻辑,只要搭好后续模块可持续迁入的基础即可。
Phase 2:先迁最独立、最稳定的业务模块
推荐优先迁移:location recorder
原因:
- 独立 SQLite 表
- 没有复杂外部副作用
- 没有 OAuth
- 没有 scheduler
这一阶段的交付物可以包括:
POST /location/record- 与现有 SQLite 兼容的写入逻辑
- 校验与 repository 的单元测试
- 基于临时 SQLite 的 integration test
Phase 3:迁移 Home Assistant 出站适配层
原因:
- 功能面小
- 能为后面的 poo 迁移做铺垫
这一阶段的交付物可以包括:
- sensor publish client
- webhook trigger client
- 针对请求格式与错误处理的 mock tests
Phase 4:迁移 TickTick adapter
原因:
- 相对自洽
- 在完成 Home Assistant 命令网关前就需要它
这一阶段的交付物可以包括:
- OAuth callback endpoint
- token persistence abstraction
- task 创建与去重行为
- 基于 mock HTTP 的集成式测试
Phase 5:迁移 Home Assistant 命令网关
原因:
- 这是外部 automations 的核心编排入口
- 在 location 与 TickTick adapter 准备好后,网关迁移会顺很多
这一阶段的交付物可以包括:
/homeassistant/publish- 兼容当前
target/action的分发逻辑 - 用进程内 service 调用替代 self-HTTP
- 把现有 Go 测试场景迁成 Python contract tests
Phase 6:迁移 poo recorder 核心,但默认不带 Notion
原因:
- 这是最复杂的模块
- 它既有本地 DB,又有 Home Assistant 副作用,当前还耦合 Notion
建议拆成两个子阶段:
-
phase 6a:
- 本地 poo DB
- latest poo 查询
- sensor publish
- 可选 webhook trigger
/poo/record/poo/latest
-
phase 6b:
- 如果 cutover 期间必须保留旧逻辑,再做一个临时 legacy Notion 兼容层
Phase 7:运维加固与切换验证
- 做 Go / Python 路由级契约比对
- 用现有 SQLite 文件或其副本做兼容验证
- 在 staging 环境手动验证 TickTick OAuth
- 用真实 Home Assistant automation payload 做验证
- 导出 OpenAPI YAML
- 再补容器化与部署方案
哪些模块适合先迁,哪些适合后迁
适合优先迁移
- location recorder
- Home Assistant 出站 client
- TickTick adapter
更适合后迁
- Home Assistant 命令网关
- poo recorder 核心
现状存在,但建议不迁
- Notion sync adapter
poo_recorder_helper的 Notion 表反转 CLIlocation_recorderhelper CLI 脚手架
建议的验证策略
Contract tests
- 基于当前 Go 行为建立 request / response fixtures
- 先把现有
homeassistant测试案例迁成 Python - 补上
poo与locationAPI 的契约测试
Integration tests
- 每个模块使用临时 SQLite DB
- Home Assistant 与 TickTick 出站流量通过 mock HTTP 替代
- 若仍保留 scheduler,则为其补定时行为测试
手工 staging 验证
- TickTick OAuth callback
- Home Assistant sensor 更新
- Home Assistant webhook 触发
- 当前真实自动化 payload 样例
开始实现前仍需明确的问题
- Python 第一阶段是否还要保留“缺少
notion.token就启动失败”的行为,还是直接把 Notion 变成可关闭能力? POST /location/record是否要继续保留“非法数字静默变成 0”的兼容行为?- TickTick token 在第一阶段是否继续写回 YAML,还是立即切到独立 token store?
- 当前 Home Assistant automations 是否真实依赖
content中的单引号 pseudo-JSON?
这些问题不影响当前 inventory,但会影响第一阶段“兼容到什么程度”的具体定义。