You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iTi-Flask/.grill/iti-flask-framework-refacto...

56 lines
4.7 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Grill: iTi-Flask 框架重构
Date: 2026-05-08
## Intent
iTi-Flask 要成为多个长期业务项目复用的后端基座。它需要提供稳定的系统域、模块边界、服务调用实践和项目模板,同时不承载具体业务逻辑。
## Constraints
- 业务项目必须依赖版本化 Git tag不复制框架源码。
- 业务项目可以扩展框架,但不能修改或覆盖框架实现。
- 框架保留系统域 API并作为核心默认能力。
- 框架必须保持轻量。它不是微服务平台。
- 生产只从 `main` 发布。
- Python 基线是 `>=3.11`
- 第一版服务调用只支持 HTTP JSON。
- 第一版任务运行器是单进程能力。
- 前端构建产物不作为框架内容发布。
- 运行时数据库和生成物不是源码资产。
## Key decisions
- Decision: 使用 Python 包 + Copier 模板。Reason: 多个业务项目需要共享运行时代码和一致项目骨架。Alternative considered: 只用 Copier 复制代码。
- Decision: 先用 Git tag 发布。Reason: 在私有 PyPI 建立前,私有 Git tag 已够用。Alternative considered: 本地路径依赖或一开始就上私有 PyPI。
- Decision: 系统域留在 core并默认启用。Reason: 用户、角色、菜单、部门、字典、配置、文件、认证、审计日志和用户扩展属性是后台基座共同能力。Alternative considered: 把系统域拆成独立包。
- Decision: 业务项目只能扩展框架行为。Reason: 直接覆盖会破坏后续升级。Alternative considered: 本地覆盖和 monkey patch。
- Decision: ERP 离开 core成为独立 Gateway 服务。Reason: ERP 是多个业务系统共享的 Monitor API 和 ODBC 解释层应只有一个口径。Alternative considered: ERP 作为 core module 或每个项目各接一次。
- Decision: 框架同时支持进程内 module 和 service client。Reason: module 是代码边界service 是部署边界。Alternative considered: 全部微服务化。
- Decision: module 跨调用走 facade。Reason: 保留 Python 调用的简单性同时避免穿透内部实现。Alternative considered: module 之间全走 HTTP 或随意 import。
- Decision: 业务项目模型集中在结构化 `models/` 树中,并保留一条 migration 流。Reason: 降低重复 migrations同时支持多人按 module 协作。Alternative considered: module 自有 migrations。
- Decision: migrations 版本化并提交。Reason: 多人开发和生产升级需要可复现数据库历史。Alternative considered: 忽略 migrations 和手工改库。
- Decision: 业务项目使用 `main` 做生产、`dev` 做集成、个人分支做开发。Reason: migration 顺序必须在生产前收敛。Alternative considered: 生产从个人分支发布。
- Decision: migration 文件名使用日期时间、revision 和 message slug。Reason: 作者名放在自由 message 中不强制业务域格式。Alternative considered: 固定 domain/action message 格式。
- Decision: 框架系统迁移复制或同步到业务项目 migrations。Reason: 生产只保留一个 `flask db upgrade` 路径。Alternative considered: 框架和业务两套迁移命令。
- Decision: seed 使用 Python幂等只写系统初始数据。Reason: 运行时 SQLite 文件不是源码资产MySQL 等数据库应由代码初始化。Alternative considered: 保留 dev 数据库或使用 JSON/SQL seed。
- Decision: 后台 API 可以保留 envelope 和业务失败 HTTP 200。服务 API 使用真实 HTTP 状态码。Reason: 重试、熔断和监控需要真实状态码语义。Alternative considered: 所有 API 都继续 HTTP 200。
- Decision: 同时保留显式 module protocol 和现有 runtime plugin 思路。Reason: 业务模块是稳定应用代码插件是部署时可选扩展。Alternative considered: 只保留插件扫描或不保留插件能力。
- Decision: 第一阶段必须让 service client 和 task runner 可用。Reason: 架构要可验证不能只停在契约。Alternative considered: 第一阶段只写契约。
## Surfaced assumptions
- ERP 不是普通业务逻辑,而是面向既有外部系统的公共 Gateway。
- 团队更常用个人 Git 分支,而不是严格功能分支。
- 历史上可能存在手工生产库变更,但目标纪律是 migration-based。
- 开发和生产后续可能使用 MySQL 或其它数据库,所以 SQLite 快照不是可靠 seed 策略。
- 轻量微服务只服务于职责边界、协作和复用,不追求 service mesh、服务发现、分布式事务或平台复杂度。
## Out of scope
- 服务发现。
- Kubernetes service mesh。
- 分布式事务。
- Saga 编排。
- gRPC。
- 消息总线平台。
- 自动弹性伸缩平台。
- 多租户网关。
- 完整 async service client。
- 分布式任务锁或 exactly-once 保证。
- 内置前端后台应用。