Files
OpenFlare/docs/development-guidelines.md
T

233 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# OpenFlare 开发规范
本文档描述 OpenFlare `1.0.0` 正式版之后的开发基线。
超出 [docs/design.md](./design.md) 边界的需求,必须先更新设计文档。
## 1. 技术基线
### 1.1 Server
`openflare_server` 继续作为单体控制面:
* Go 1.24+
* Gin
* GORM
* SQLite / PostgreSQL
* 现有登录体系
### 1.2 Agent
`openflare_agent` 继续作为 Go 单体程序:
* Go 1.24+
* 单二进制
* 节点本地执行
* `openresty_path` 优先
* 无 `openresty_path` 时默认 Docker OpenResty
### 1.3 Frontend
前端基线以 `openflare_server/web` 为准:
* Next.js 15 App Router
* React 19
* TypeScript
* Tailwind CSS 4
* TanStack Query
* React Hook Form + Zod
* Zustand 仅用于轻量客户端状态
前端细则见 [docs/frontend-development-guidelines.md](./frontend-development-guidelines.md)。
## 2. 分层与目录约束
### 2.1 Server
* `controller/`:参数解析、调用 service、返回响应
* `service/`:业务逻辑、校验、事务编排、渲染
* `model/`:模型定义与持久化
* `router/`:路由注册
* `middleware/`:认证、鉴权、限流等横切逻辑
* `common/`:配置、全局状态与初始化入口
* `utils/`:纯工具函数与通用 helper
禁止:
* 在 `controller/` 堆积业务逻辑
* 在 `middleware/` 实现业务流程
* 为简单需求新增平台层抽象
### 2.2 Agent
保持现有模块边界:
* `config`
* `heartbeat`
* `sync`
* `openresty`
* `state`
* `httpclient`
* `protocol`
* `internal/updater`
要求:
* 每个模块职责单一
* 外部命令调用集中封装
* 状态落盘与配置落盘分离
### 2.3 Frontend
前端分层保持:
* `app/`
* `features/`
* `components/`
* `lib/`
* `store/`
* `types/`
要求:
* 页面路由与布局放在 `app/`
* API 请求统一收敛到 `lib/api/`
* 业务逻辑优先放在 `features/`
## 3. 数据模型规范
当前有效实体:
* `proxy_routes`
* `origins`
* `config_versions`
* `nodes`
* `node_system_profiles`
* `apply_logs`
* `tls_certificates`
* `managed_domains`
* `node_request_reports`
* `node_access_logs`
* `node_metric_snapshots`
* `traffic_analytics_rollups`
* `node_health_events`
* `options`
通用约束:
* 不新增平台化对象,除非设计文档明确要求
* `origins` 仅作为可复用源站地址目录,字段保持轻量;协议、端口、路径与查询参数继续归属具体 `proxy_routes`
* `proxy_routes` 以“网站配置”作为聚合边界,必须包含唯一 `site_name` 与非空 `domains` 列表;数据库内部 `id` 可继续作为技术主键,但不能替代 `site_name` 的业务唯一性
* `proxy_routes.domains` 中的每个域名都必须全局唯一;列表第一项视为主域名,创建时若未显式填写 `site_name`,则默认使用主域名
* `proxy_routes` 继续允许保存一个或多个上游地址用于负载均衡,但不引入独立 `origin_pool`
* 迁移期如保留遗留 `domain` 字段,只能作为 `domains[0]` 的兼容镜像;新代码不得继续以该字段作为唯一业务输入
* `proxy_routes` 如关联 `origins`,必须同时保存可直接渲染的 `origin_url`;源站地址变更时,由 service 负责同步更新引用该源站的规则快照
* `proxy_routes` 的上游统一使用 named `upstream` + keepalive;单上游如带 base path 或 query,应在 `proxy_pass` 上补回 URI,多上游仅允许纯 `scheme://host[:port]`
* `proxy_routes.origin_host` 为可选字段,仅用于覆盖回源 `Host` 请求头,不引入新的平台化对象
* 流量限制、反向代理与缓存配置当前都归属站点级 `proxy_routes`,同一网站内不拆分域名级差异配置
* HTTPS 的启停仍由站点级 `proxy_routes` 控制,但证书绑定必须通过与 `domains` 平行的 `domain_cert_ids` 记录逐域名保存;未绑定证书的域名不得参与 HTTPS 渲染
* `proxy_routes.cert_ids` 仅作为站点级证书集合与兼容镜像,必须由 `domain_cert_ids` 推导生成;`cert_id` 继续作为首个已使用证书的兼容镜像
* `config_versions` 必须保存完整快照与渲染结果
* 全局同时只能有一个激活版本
* 回滚通过重新激活旧版本实现
* `nodes` 只保留控制面状态与低频摘要
* 观测数据必须按节点与时间窗口关联
* 快照与聚合结果采用追加式模型,不覆盖历史
* 原始访问明细必须有受控保留策略
### 3.1 数据库版本与迁移
* 任何涉及表结构、索引、列类型、分表规则或内部持久化元数据的修改,都必须同步提升数据库版本号
* 数据库版本号定义在 `openflare_server/model`,不得只依赖 `AutoMigrate` 隐式升级存量数据库
* 每次提升数据库版本号时,必须补充从上一版本升级到新版本的显式迁移方法
* 迁移方法必须包含升级后的校验逻辑;只有校验通过,才能写入新的数据库版本记录
* 新包启动后必须先检查数据库当前版本,再按顺序逐步升级到目标版本;禁止跳过中间升级步骤直接写目标版本
* 空库初始化可以直接建立当前版本结构,但初始化完成后仍必须执行同版本校验,并落库当前数据库版本
* 数据库版本元数据属于内部控制信息,必须保存在独立内部表中,不能混入业务配置表
* 如果迁移失败或校验失败,启动流程必须中止,且不得提升数据库版本记录
* 涉及数据库版本变更的提交,必须补充对应的迁移测试或等效回归测试
## 4. API 与鉴权规范
### 4.1 API
* 管理端与 Agent API 统一使用 JSON
* 成功与失败都必须返回清晰 `message`
* Agent API 固定放在 `/api/agent/*`
* 总览与节点详情优先使用专用聚合接口
* 管理端变更类接口统一使用 `POST`;只读接口使用 `GET`
统一响应结构:
```json
{
"success": true,
"message": "",
"data": {}
}
```
### 4.2 鉴权
管理端:
* 继续复用现有登录、角色与 Session
Agent:
* 正式请求统一使用节点专属 `agent_token`
* 首次接入可使用全局 `discovery_token`
* 请求头统一使用 `X-Agent-Token`
禁止:
* 暴露远程 shell 或任意命令执行入口
* 在日志中打印完整 Token
* 允许绕过占位符约束保存不可渲染的主配置模板
## 5. 发布与运行规范
发布逻辑必须保持以下事实:
* 发布时读取全部启用的 `proxy_routes`
* 同时读取 OpenResty 主配置参数、反代性能参数与缓存参数
* 生成完整 OpenResty 配置
* 计算 `checksum`
* 写入 `config_versions`
* 通过切换 `is_active` 激活版本
版本约束:
* 版本号格式固定为 `YYYYMMDD-NNN`
* 不在线修改历史版本
* 不做按节点分组的差异化版本
* 预览与 diff 是只读能力,不产生发布记录
Agent 必须满足:
* 启动后读取或生成本地 `node_id`
* 周期性心跳与同步
* 常规同步优先依据 heartbeat 返回的版本摘要判断
* 发现新版本时先备份旧文件
* 写入主配置、路由配置与必要证书文件
* 写入新配置后以运行态恢复为目标执行激活,Docker 模式优先重建容器并确认容器保持运行
* 新配置激活失败时必须先尝试用目标配置恢复运行,再回滚到旧配置并重新拉起 OpenResty
* 回滚后 OpenResty 恢复正常时上报警告;回滚后仍无法恢复运行时上报失败
* 某个目标 `version + checksum` 一旦应用失败并回退,Agent 必须在本地状态中阻断该目标的重复应用;只有远端激活版本或 checksum 发生变化时,才允许再次尝试
## 6. 测试与交付要求
* 关键业务逻辑必须有单元测试或等效回归测试
* Agent 主链路修改必须验证同步、应用与回滚
* 前端页面至少覆盖加载态、空态、错误态与成功反馈
* Go 版本调整时,同步检查 `go.mod`、Dockerfile 与 CI 工作流
## 7. 文档维护要求
当以下内容变化时,必须同步更新对应文档:
* 产品范围或系统边界变化:更新 `docs/design.md`
* 开发约束、接口约定、测试基线变化:更新本文档
* 前端工程约束变化:更新 `docs/frontend-development-guidelines.md`
* 配置项或部署方式变化:更新 `docs/app-config.md`、`docs/deployment.md` 与 `README.md`