mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 22:06:38 +08:00
feat: Update development guidelines and plan for ATSFlare V2
- Revised development guidelines to include new features for V2, such as Agent management and automatic discovery. - Expanded the data model to support agent tokens and discovery tokens. - Updated the development plan to reflect changes in Agent management, including CRUD operations and token replacement. - Enhanced the requirements for the second phase of development, focusing on security improvements and user experience.
This commit is contained in:
+61
-29
@@ -1,29 +1,61 @@
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Node struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
NodeID string `json:"node_id" gorm:"uniqueIndex;size:64;not null"`
|
||||
Name string `json:"name" gorm:"size:128;not null"`
|
||||
IP string `json:"ip" gorm:"size:64;not null"`
|
||||
AgentVersion string `json:"agent_version" gorm:"size:64;not null"`
|
||||
NginxVersion string `json:"nginx_version" gorm:"size:64"`
|
||||
Status string `json:"status" gorm:"size:16;not null;default:'offline'"`
|
||||
CurrentVersion string `json:"current_version" gorm:"size:32"`
|
||||
LastSeenAt time.Time `json:"last_seen_at"`
|
||||
LastError string `json:"last_error" gorm:"size:1024"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func ListNodes() (nodes []*Node, err error) {
|
||||
err = DB.Order("id desc").Find(&nodes).Error
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
func GetNodeByNodeID(nodeID string) (*Node, error) {
|
||||
node := &Node{}
|
||||
err := DB.Where("node_id = ?", nodeID).First(node).Error
|
||||
return node, err
|
||||
}
|
||||
package model
|
||||
|
||||
import "time"
|
||||
|
||||
type Node struct {
|
||||
ID uint `json:"id" gorm:"primaryKey"`
|
||||
NodeID string `json:"node_id" gorm:"uniqueIndex;size:64;not null"`
|
||||
Name string `json:"name" gorm:"size:128;not null"`
|
||||
IP string `json:"ip" gorm:"size:64;not null"`
|
||||
AgentToken string `json:"-" gorm:"size:128;uniqueIndex"`
|
||||
DiscoveryToken string `json:"-" gorm:"size:128;uniqueIndex"`
|
||||
AgentVersion string `json:"agent_version" gorm:"size:64;not null"`
|
||||
NginxVersion string `json:"nginx_version" gorm:"size:64"`
|
||||
Status string `json:"status" gorm:"size:16;not null;default:'offline'"`
|
||||
CurrentVersion string `json:"current_version" gorm:"size:32"`
|
||||
LastSeenAt time.Time `json:"last_seen_at"`
|
||||
LastError string `json:"last_error" gorm:"size:1024"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
func ListNodes() (nodes []*Node, err error) {
|
||||
err = DB.Order("id desc").Find(&nodes).Error
|
||||
return nodes, err
|
||||
}
|
||||
|
||||
func GetNodeByNodeID(nodeID string) (*Node, error) {
|
||||
node := &Node{}
|
||||
err := DB.Where("node_id = ?", nodeID).First(node).Error
|
||||
return node, err
|
||||
}
|
||||
|
||||
func GetNodeByID(id uint) (*Node, error) {
|
||||
node := &Node{}
|
||||
err := DB.First(node, id).Error
|
||||
return node, err
|
||||
}
|
||||
|
||||
func GetNodeByAgentToken(token string) (*Node, error) {
|
||||
node := &Node{}
|
||||
err := DB.Where("agent_token = ?", token).First(node).Error
|
||||
return node, err
|
||||
}
|
||||
|
||||
func GetNodeByDiscoveryToken(token string) (*Node, error) {
|
||||
node := &Node{}
|
||||
err := DB.Where("discovery_token = ?", token).First(node).Error
|
||||
return node, err
|
||||
}
|
||||
|
||||
func (node *Node) Insert() error {
|
||||
return DB.Create(node).Error
|
||||
}
|
||||
|
||||
func (node *Node) Update() error {
|
||||
return DB.Save(node).Error
|
||||
}
|
||||
|
||||
func (node *Node) Delete() error {
|
||||
return DB.Delete(node).Error
|
||||
}
|
||||
|
||||
+795
-790
File diff suppressed because it is too large
Load Diff
+446
-437
@@ -1,437 +1,446 @@
|
||||
# ATSFlare 开发规范
|
||||
|
||||
## 1. 适用范围
|
||||
|
||||
本规范适用于 ATSFlare 第一版与第二版阶段。
|
||||
|
||||
项目第一版已完成以下能力:
|
||||
|
||||
* 配置发布与同步
|
||||
* 节点心跳检测
|
||||
* Nginx 反向代理配置下发
|
||||
|
||||
第二版在此基础上新增以下能力:
|
||||
|
||||
* HTTPS/TLS 路由支持
|
||||
* 证书托管(手动导入与文件导入)
|
||||
* 域名管理与证书自动匹配(支持 `*.example.com`)
|
||||
* Agent Token 管理
|
||||
* 路由自定义请求头
|
||||
* 配置预览与变更摘要
|
||||
|
||||
当前明确仍不做:
|
||||
|
||||
* 多租户
|
||||
* WAF、限流、Bot、防刷
|
||||
* 百分比灰度发布
|
||||
* 节点分组与差异化下发
|
||||
* Redis、MQ、对象存储、Prometheus
|
||||
* 复杂缓存策略、证书自动签发、Purge、审批流
|
||||
* mid-tier、分层缓存、复杂策略编排
|
||||
|
||||
超出以上范围的需求,必须先更新设计文档,再开始编码。
|
||||
|
||||
## 2. 技术基线
|
||||
|
||||
### 2.1 Server
|
||||
|
||||
控制中心基于现有 `atsf_server` 开发:
|
||||
|
||||
* Web 框架:Gin
|
||||
* ORM:GORM
|
||||
* 数据库:SQLite
|
||||
* 前端:现有 `atsf_server/web`
|
||||
* 登录体系:沿用 gin-template 现有能力
|
||||
|
||||
约束:
|
||||
|
||||
* 默认不配置 `SQL_DSN`
|
||||
* 默认不配置 `REDIS_CONN_STRING`
|
||||
* 不为了 MVP 引入新的基础设施依赖
|
||||
|
||||
### 2.2 Agent
|
||||
|
||||
Agent 放在 `atsf_agent`,使用 Go 单体程序开发。
|
||||
|
||||
约束:
|
||||
|
||||
* 单二进制
|
||||
* systemd 运行
|
||||
* 优先调用独立 Nginx,不依赖系统全局 Nginx
|
||||
* 支持通过 `nginx_path` 显式指定独立 Nginx 可执行文件
|
||||
* 未指定 `nginx_path` 时,默认通过 Docker 启动独立 Nginx 容器
|
||||
* Agent 生成资源默认统一放在 `./data`,可通过 `data_dir` 统一覆盖
|
||||
* 负责本机 Nginx 路由配置写入、校验、reload、状态上报
|
||||
|
||||
### 2.3 Nginx 配置边界
|
||||
|
||||
第一版控制面只管理独立生成的 Nginx 路由配置文件,例如 `/etc/nginx/conf.d/atsflare_routes.conf`。第二版在此基础上增加证书托管能力。
|
||||
|
||||
第一版以下内容不纳入控制面:
|
||||
|
||||
* `nginx.conf`
|
||||
* 缓存策略
|
||||
* upstream 高级配置
|
||||
|
||||
第二版约束:
|
||||
|
||||
* 允许在控制面托管 TLS 证书并下发给节点
|
||||
* 仅支持证书导入(手动粘贴与文件导入),不做自动签发/续期
|
||||
* `nginx.conf`、缓存策略、upstream 高级配置仍保持节点本地静态配置
|
||||
|
||||
## 3. 仓库职责划分
|
||||
|
||||
### 3.1 `atsf_server`
|
||||
|
||||
负责:
|
||||
|
||||
* 管理端 UI
|
||||
* 管理端 API
|
||||
* Agent API
|
||||
* 数据存储
|
||||
* 配置渲染
|
||||
* 版本发布
|
||||
* 节点状态展示
|
||||
|
||||
### 3.2 `atsf_agent`
|
||||
|
||||
负责:
|
||||
|
||||
* 节点注册
|
||||
* 心跳上报
|
||||
* 拉取激活版本
|
||||
* 写入本地 Nginx 路由配置
|
||||
* 调用 `nginx -t` 和 `nginx -s reload`
|
||||
* 失败回滚
|
||||
* 上报应用结果
|
||||
* 管理独立 Nginx 路径或 Docker Nginx 容器
|
||||
|
||||
### 3.3 `docs`
|
||||
|
||||
负责:
|
||||
|
||||
* 设计边界
|
||||
* 开发规范
|
||||
* 开发计划
|
||||
* 部署与联调说明
|
||||
|
||||
## 4. 开发原则
|
||||
|
||||
所有实现都必须遵守以下原则:
|
||||
|
||||
* 先完成闭环,再做抽象。
|
||||
* 不为了"以后可能会支持"提前引入复杂模型。
|
||||
* Server 只管状态和配置,不直接 SSH 改节点。
|
||||
* Agent 是唯一落地入口。
|
||||
* 所有发布都是"新版本激活",不是在线覆盖编辑。
|
||||
* 第一版与第二版:所有节点默认拉同一份全量配置,不做节点分组差异化下发。
|
||||
* 能用 SQLite 解决的问题,不引入额外中间件。
|
||||
* 新功能优先复用现有 gin-template 结构,不平行造第二套框架。
|
||||
|
||||
## 5. 数据模型规范
|
||||
|
||||
第一版核心实体(已实现):
|
||||
|
||||
* `proxy_routes`
|
||||
* `config_versions`
|
||||
* `nodes`
|
||||
* `apply_logs`
|
||||
|
||||
第二版新增实体:
|
||||
|
||||
* `tls_certificates` — 证书托管
|
||||
* `managed_domains` — 域名管理与证书绑定
|
||||
* `agent_tokens` — Agent Token 管理
|
||||
|
||||
约束(全版本):
|
||||
|
||||
* 不新增 `zone`、`origin_pool`、`policy`、`deployment` 这类平台化对象
|
||||
* `proxy_routes` 一条域名只对应一个 `origin_url`
|
||||
* `config_versions` 必须保存完整快照和渲染后的 Nginx 路由配置
|
||||
* 激活版本全局只能有一个,不引入分组维度
|
||||
* 回滚通过"激活旧版本"实现,不直接修改历史记录
|
||||
* `agent_tokens` 中的 Token 值不可更新,只能创建或撤销
|
||||
* 域名到证书匹配必须支持精确匹配和通配符匹配(如 `*.example.com`)
|
||||
|
||||
如需新增表,必须先证明它服务于当前迭代版本的主链路。
|
||||
|
||||
## 6. Server 开发规范
|
||||
|
||||
### 6.1 分层约束
|
||||
|
||||
Server 代码按以下职责拆分:
|
||||
|
||||
* `controller/`: 参数解析、调用 service、返回 JSON
|
||||
* `service/`: 业务逻辑、校验、渲染、版本切换
|
||||
* `model/`: 数据表结构、查询和持久化
|
||||
* `router/`: 路由注册
|
||||
* `middleware/`: 认证、鉴权、限流等横切逻辑
|
||||
* `common/`: 通用工具和配置
|
||||
|
||||
禁止行为:
|
||||
|
||||
* controller 直接拼接复杂业务逻辑
|
||||
* controller 直接操作多个 model 形成事务链
|
||||
* middleware 承担业务逻辑
|
||||
* 为简单需求引入新的平台层抽象
|
||||
|
||||
### 6.2 API 约定
|
||||
|
||||
管理端和 Agent API 统一使用 JSON。
|
||||
|
||||
响应结构沿用现有模板风格:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
* 成功或失败都返回清晰 `message`
|
||||
* 列表接口返回稳定字段,不临时拼装结构
|
||||
* 新接口命名优先使用复数资源风格
|
||||
* Agent API 固定放在 `/api/agent/*`
|
||||
|
||||
### 6.3 鉴权规范
|
||||
|
||||
管理端:
|
||||
|
||||
* 继续复用 gin-template 的登录、角色和 session 体系
|
||||
|
||||
Agent(第一版):
|
||||
|
||||
* 预共享单 Token,来自环境变量
|
||||
* 请求头统一使用 `X-Agent-Token`
|
||||
* Agent 与管理端认证逻辑必须分开
|
||||
|
||||
Agent(第二版):
|
||||
|
||||
* Token 改为查 `agent_tokens` 表验证
|
||||
* 环境变量 Token 降级为 bootstrap 模式:数据库存在有效 Token 记录时,环境变量 Token 不再有效
|
||||
* Token 创建时生成随机值,不允许外部传入
|
||||
* Token 值不可更新,仅支持撤销(设 `is_active=false`)
|
||||
|
||||
注意:
|
||||
|
||||
* 不要让 Agent 接口走用户登录态
|
||||
* 不要把 Nginx 命令暴露成远程管理接口
|
||||
|
||||
### 6.4 数据库规范
|
||||
|
||||
SQLite 是唯一默认数据库。
|
||||
|
||||
要求:
|
||||
|
||||
* 新增模型后必须在 `model.InitDB()` 中加入 `AutoMigrate`
|
||||
* 不写 MySQL/PostgreSQL 特有 SQL
|
||||
* 不依赖外部迁移工具作为 MVP 前提
|
||||
* 时间字段统一使用 GORM 常规时间类型
|
||||
|
||||
### 6.5 发布与渲染规范
|
||||
|
||||
发布逻辑必须满足:
|
||||
|
||||
* 发布时读取全部启用的 `proxy_routes`
|
||||
* 生成完整的 Nginx 路由配置
|
||||
* 计算 checksum
|
||||
* 保存快照到 `config_versions`
|
||||
* 通过切换 `is_active` 激活版本
|
||||
|
||||
版本号格式固定为:
|
||||
|
||||
```text
|
||||
YYYYMMDD-NNN
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
20260309-001
|
||||
```
|
||||
|
||||
## 7. Agent 开发规范
|
||||
|
||||
### 7.1 模块边界
|
||||
|
||||
建议目录如下:
|
||||
|
||||
```text
|
||||
atsf_agent/
|
||||
cmd/agent/
|
||||
internal/config/
|
||||
internal/heartbeat/
|
||||
internal/sync/
|
||||
internal/nginx/
|
||||
internal/state/
|
||||
internal/httpclient/
|
||||
```
|
||||
|
||||
职责要求:
|
||||
|
||||
* `config`: 本地配置读取
|
||||
* `heartbeat`: 心跳请求和状态组装
|
||||
* `sync`: 检查版本、下载配置、触发应用
|
||||
* `nginx`: 封装 Nginx 校验、reload 和文件写入
|
||||
* `state`: 本地成功版本和运行状态缓存
|
||||
* `httpclient`: Server API 调用
|
||||
|
||||
### 7.2 行为规范
|
||||
|
||||
Agent 必须满足以下行为:
|
||||
|
||||
* 启动后生成或读取本地 `node_id`
|
||||
* 周期性心跳
|
||||
* 周期性检查激活版本
|
||||
* 发现新版本后先备份旧文件
|
||||
* 写入新路由配置文件
|
||||
* 先执行 `nginx -t`
|
||||
* 校验通过后执行 `nginx -s reload`
|
||||
* 失败时回滚备份并再次校验和 reload
|
||||
* 上报最终应用结果
|
||||
* 优先使用 `nginx_path`
|
||||
* 未配置 `nginx_path` 时自动准备并使用 Docker Nginx 容器
|
||||
* 启动时先校验本地路由文件 checksum 与控制面激活版本是否一致
|
||||
* Docker 模式启动时应重建容器,而不是继续复用异常停止的旧容器
|
||||
|
||||
### 7.3 容错规范
|
||||
|
||||
第一版最少保证:
|
||||
|
||||
* Server 不可用时,Nginx 继续使用旧配置
|
||||
* 下载失败时,不修改本地配置
|
||||
* 配置校验或 reload 失败时,自动尝试回滚
|
||||
* 本地状态文件损坏时,允许重新初始化,但不能删除正在生效的 Nginx 配置
|
||||
* Docker 容器异常停止时,启动阶段应自动重建容器并重新校验配置
|
||||
|
||||
### 7.4 外部命令规范
|
||||
|
||||
Agent 调用 Nginx 命令时必须:
|
||||
|
||||
* 明确记录执行命令和返回错误
|
||||
* 设置合理超时
|
||||
* 不依赖交互式输入
|
||||
* 不通过 shell 拼接不可信参数
|
||||
|
||||
## 8. 前端开发规范
|
||||
|
||||
MVP 前端只做最小管理界面,不重做整套后台。
|
||||
|
||||
要求:
|
||||
|
||||
* 继续使用现有 React 结构和 `semantic-ui-react`
|
||||
* 页面只增加 MVP 必需页面
|
||||
* 不额外引入新的大型前端框架
|
||||
* API 请求统一放在 `web/src/helpers/api.js` 或同类 helper 中
|
||||
* 页面状态优先保持简单,不提前引入复杂全局状态管理
|
||||
|
||||
第一版只需要以下页面:
|
||||
|
||||
* 反代规则页
|
||||
* 发布版本页
|
||||
* 节点状态页
|
||||
* 应用记录页
|
||||
|
||||
## 9. 代码风格规范
|
||||
|
||||
### 9.1 Go
|
||||
|
||||
* 保持 package 名称简短且小写
|
||||
* 错误必须显式处理,不允许静默吞错
|
||||
* 函数尽量只做一件事
|
||||
* 输入校验放在 controller 或 service 边界
|
||||
* 业务枚举值使用明确常量,不使用魔法字符串散落代码
|
||||
* 仅在复杂逻辑前添加简短注释,不写废话注释
|
||||
|
||||
### 9.2 命名
|
||||
|
||||
* 表名和模型名使用业务语义,不沿用模板示例语义
|
||||
* 统一使用 `route`, `version`, `node`, `apply log` 这些术语
|
||||
* 不混用 `client`、`edge`、`agent` 指代同一模块,统一叫 `agent`
|
||||
|
||||
### 9.3 日志
|
||||
|
||||
要求记录这些关键事件:
|
||||
|
||||
* 发布成功/失败
|
||||
* Agent 注册
|
||||
* 心跳异常
|
||||
* 配置下载失败
|
||||
* Nginx 校验或 reload 成功/失败
|
||||
* 回滚触发
|
||||
|
||||
日志内容要可定位问题,但不要打印敏感 Token。
|
||||
|
||||
## 10. 测试与验收规范
|
||||
|
||||
### 10.1 第一版最低测试要求(已完成)
|
||||
|
||||
Server 至少覆盖:
|
||||
|
||||
* `origin_url` 校验
|
||||
* `domain` 重复校验
|
||||
* Nginx 路由配置渲染结果
|
||||
* 激活版本切换逻辑
|
||||
* 节点在线状态判定逻辑
|
||||
|
||||
Agent 至少覆盖:
|
||||
|
||||
* 版本比较逻辑
|
||||
* 配置文件备份和回滚逻辑
|
||||
* `nginx -t` 或 `nginx -s reload` 失败分支
|
||||
* 本地状态文件读写
|
||||
|
||||
### 10.2 第二版新增测试要求
|
||||
|
||||
Server 新增覆盖:
|
||||
|
||||
* HTTPS server 块渲染正确性(`enable_https=true` 时生成 443 块,`redirect_http=true` 时生成重定向块)
|
||||
* HTTP-only 路由渲染结果不受 HTTPS 字段影响
|
||||
* 证书导入逻辑(手动导入、文件导入)和 PEM 校验逻辑
|
||||
* 域名证书匹配逻辑(精确匹配与 `*.example.com` 通配符匹配)
|
||||
* `custom_headers` 注入到渲染结果的正确性
|
||||
* `agent_tokens` 创建与查表验证逻辑
|
||||
* Token 撤销后验证失败
|
||||
* bootstrap Token 降级行为(数据库有 Token 时环境变量 Token 失效)
|
||||
* 预览接口不写库
|
||||
* diff 接口变更摘要计算正确性
|
||||
|
||||
### 10.3 联调验收标准(第一版,已完成)
|
||||
|
||||
1. 管理端新增反代规则并成功发布版本
|
||||
2. Agent 能检测到新版本并拉取
|
||||
3. Agent 成功写入 Nginx 路由配置文件
|
||||
4. Agent 成功执行 `nginx -t` 和 `nginx -s reload`
|
||||
5. 节点页能看到当前版本和最后心跳
|
||||
6. 当 reload 失败时,Agent 能回滚到旧配置并上报失败
|
||||
|
||||
### 10.4 联调验收标准(第二版)
|
||||
|
||||
1. 创建含 HTTPS 字段的路由并发布,Nginx 能以 HTTPS 正确转发
|
||||
2. 控制面可手动导入和文件导入证书,导入后可被路由选择
|
||||
3. 反代规则输入域名后可自动匹配证书,且支持 `*.example.com`
|
||||
4. 通过管理界面创建 Token,Agent 使用新 Token 成功访问
|
||||
5. 撤销 Token 后 Agent 请求返回 401
|
||||
6. 路由配置自定义头后,渲染结果包含对应指令
|
||||
7. 发布页预览展示正确渲染结果
|
||||
8. 变更摘要正确列出域名变化
|
||||
|
||||
## 11. 文档维护规范
|
||||
|
||||
出现以下情况时必须同步更新文档:
|
||||
|
||||
* 产品版本范围变化(V1 → V2 → V3)
|
||||
* API 发生破坏性变更
|
||||
* 数据模型新增或删除
|
||||
* Agent 本地文件路径变更
|
||||
* 部署方式变化
|
||||
* 新增或撤销对中间件/基础设施的依赖
|
||||
|
||||
优先更新:
|
||||
|
||||
* `docs/design.md`
|
||||
* `docs/development-guidelines.md`
|
||||
* `docs/development-plan.md`
|
||||
# ATSFlare 开发规范
|
||||
|
||||
## 1. 适用范围
|
||||
|
||||
本规范适用于 ATSFlare 第一版与第二版阶段。
|
||||
|
||||
项目第一版已完成以下能力:
|
||||
|
||||
* 配置发布与同步
|
||||
* 节点心跳检测
|
||||
* Nginx 反向代理配置下发
|
||||
|
||||
第二版在此基础上新增以下能力:
|
||||
|
||||
* HTTPS/TLS 路由支持
|
||||
* 证书托管(手动导入与文件导入)
|
||||
* 域名管理与证书自动匹配(支持 `*.example.com`)
|
||||
* Agent 管理与自动发现
|
||||
* 路由自定义请求头
|
||||
* 配置预览与变更摘要
|
||||
|
||||
当前明确仍不做:
|
||||
|
||||
* 多租户
|
||||
* WAF、限流、Bot、防刷
|
||||
* 百分比灰度发布
|
||||
* 节点分组与差异化下发
|
||||
* Redis、MQ、对象存储、Prometheus
|
||||
* 复杂缓存策略、证书自动签发、Purge、审批流
|
||||
* mid-tier、分层缓存、复杂策略编排
|
||||
|
||||
超出以上范围的需求,必须先更新设计文档,再开始编码。
|
||||
|
||||
## 2. 技术基线
|
||||
|
||||
### 2.1 Server
|
||||
|
||||
控制中心基于现有 `atsf_server` 开发:
|
||||
|
||||
* Web 框架:Gin
|
||||
* ORM:GORM
|
||||
* 数据库:SQLite
|
||||
* 前端:现有 `atsf_server/web`
|
||||
* 登录体系:沿用 gin-template 现有能力
|
||||
|
||||
约束:
|
||||
|
||||
* 默认不配置 `SQL_DSN`
|
||||
* 默认不配置 `REDIS_CONN_STRING`
|
||||
* 不为了 MVP 引入新的基础设施依赖
|
||||
|
||||
### 2.2 Agent
|
||||
|
||||
Agent 放在 `atsf_agent`,使用 Go 单体程序开发。
|
||||
|
||||
约束:
|
||||
|
||||
* 单二进制
|
||||
* systemd 运行
|
||||
* 优先调用独立 Nginx,不依赖系统全局 Nginx
|
||||
* 支持通过 `nginx_path` 显式指定独立 Nginx 可执行文件
|
||||
* 未指定 `nginx_path` 时,默认通过 Docker 启动独立 Nginx 容器
|
||||
* Agent 生成资源默认统一放在 `./data`,可通过 `data_dir` 统一覆盖
|
||||
* 负责本机 Nginx 路由配置写入、校验、reload、状态上报
|
||||
|
||||
### 2.3 Nginx 配置边界
|
||||
|
||||
第一版控制面只管理独立生成的 Nginx 路由配置文件,例如 `/etc/nginx/conf.d/atsflare_routes.conf`。第二版在此基础上增加证书托管能力。
|
||||
|
||||
第一版以下内容不纳入控制面:
|
||||
|
||||
* `nginx.conf`
|
||||
* 缓存策略
|
||||
* upstream 高级配置
|
||||
|
||||
第二版约束:
|
||||
|
||||
* 允许在控制面托管 TLS 证书并下发给节点
|
||||
* 仅支持证书导入(手动粘贴与文件导入),不做自动签发/续期
|
||||
* `nginx.conf`、缓存策略、upstream 高级配置仍保持节点本地静态配置
|
||||
|
||||
## 3. 仓库职责划分
|
||||
|
||||
### 3.1 `atsf_server`
|
||||
|
||||
负责:
|
||||
|
||||
* 管理端 UI
|
||||
* 管理端 API
|
||||
* Agent API
|
||||
* 数据存储
|
||||
* 配置渲染
|
||||
* 版本发布
|
||||
* 节点状态展示
|
||||
|
||||
### 3.2 `atsf_agent`
|
||||
|
||||
负责:
|
||||
|
||||
* 节点注册
|
||||
* 心跳上报
|
||||
* 拉取激活版本
|
||||
* 写入本地 Nginx 路由配置
|
||||
* 调用 `nginx -t` 和 `nginx -s reload`
|
||||
* 失败回滚
|
||||
* 上报应用结果
|
||||
* 管理独立 Nginx 路径或 Docker Nginx 容器
|
||||
|
||||
### 3.3 `docs`
|
||||
|
||||
负责:
|
||||
|
||||
* 设计边界
|
||||
* 开发规范
|
||||
* 开发计划
|
||||
* 部署与联调说明
|
||||
|
||||
## 4. 开发原则
|
||||
|
||||
所有实现都必须遵守以下原则:
|
||||
|
||||
* 先完成闭环,再做抽象。
|
||||
* 不为了"以后可能会支持"提前引入复杂模型。
|
||||
* Server 只管状态和配置,不直接 SSH 改节点。
|
||||
* Agent 是唯一落地入口。
|
||||
* 所有发布都是"新版本激活",不是在线覆盖编辑。
|
||||
* 第一版与第二版:所有节点默认拉同一份全量配置,不做节点分组差异化下发。
|
||||
* 能用 SQLite 解决的问题,不引入额外中间件。
|
||||
* 新功能优先复用现有 gin-template 结构,不平行造第二套框架。
|
||||
|
||||
## 5. 数据模型规范
|
||||
|
||||
第一版核心实体(已实现):
|
||||
|
||||
* `proxy_routes`
|
||||
* `config_versions`
|
||||
* `nodes`
|
||||
* `apply_logs`
|
||||
|
||||
第二版新增实体:
|
||||
|
||||
* `tls_certificates` — 证书托管
|
||||
* `managed_domains` — 域名管理与证书绑定
|
||||
|
||||
第二版扩展实体:
|
||||
|
||||
* `nodes` — 增加 `agent_token`、`discovery_token`,用于节点管理与自动发现
|
||||
|
||||
约束(全版本):
|
||||
|
||||
* 不新增 `zone`、`origin_pool`、`policy`、`deployment` 这类平台化对象
|
||||
* `proxy_routes` 一条域名只对应一个 `origin_url`
|
||||
* `config_versions` 必须保存完整快照和渲染后的 Nginx 路由配置
|
||||
* 激活版本全局只能有一个,不引入分组维度
|
||||
* 回滚通过"激活旧版本"实现,不直接修改历史记录
|
||||
* 域名到证书匹配必须支持精确匹配和通配符匹配(如 `*.example.com`)
|
||||
* `nodes.discovery_token` 仅用于首次接入,接入成功后必须失效
|
||||
* 删除节点必须立即使该节点凭证失效
|
||||
|
||||
如需新增表,必须先证明它服务于当前迭代版本的主链路。
|
||||
|
||||
## 6. Server 开发规范
|
||||
|
||||
### 6.1 分层约束
|
||||
|
||||
Server 代码按以下职责拆分:
|
||||
|
||||
* `controller/`: 参数解析、调用 service、返回 JSON
|
||||
* `service/`: 业务逻辑、校验、渲染、版本切换
|
||||
* `model/`: 数据表结构、查询和持久化
|
||||
* `router/`: 路由注册
|
||||
* `middleware/`: 认证、鉴权、限流等横切逻辑
|
||||
* `common/`: 通用工具和配置
|
||||
|
||||
禁止行为:
|
||||
|
||||
* controller 直接拼接复杂业务逻辑
|
||||
* controller 直接操作多个 model 形成事务链
|
||||
* middleware 承担业务逻辑
|
||||
* 为简单需求引入新的平台层抽象
|
||||
|
||||
### 6.2 API 约定
|
||||
|
||||
管理端和 Agent API 统一使用 JSON。
|
||||
|
||||
响应结构沿用现有模板风格:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
约束:
|
||||
|
||||
* 成功或失败都返回清晰 `message`
|
||||
* 列表接口返回稳定字段,不临时拼装结构
|
||||
* 新接口命名优先使用复数资源风格
|
||||
* Agent API 固定放在 `/api/agent/*`
|
||||
|
||||
### 6.3 鉴权规范
|
||||
|
||||
管理端:
|
||||
|
||||
* 继续复用 gin-template 的登录、角色和 session 体系
|
||||
|
||||
Agent(第一版):
|
||||
|
||||
* 预共享单 Token,来自环境变量
|
||||
* 请求头统一使用 `X-Agent-Token`
|
||||
* Agent 与管理端认证逻辑必须分开
|
||||
|
||||
Agent(第二版):
|
||||
|
||||
* 首次接入使用 `discovery_token`
|
||||
* 注册成功后下发节点专属 `agent_token`
|
||||
* 后续请求改为查 `nodes.agent_token` 验证
|
||||
* 不再依赖全局环境变量 Agent Token
|
||||
|
||||
注意:
|
||||
|
||||
* 不要让 Agent 接口走用户登录态
|
||||
* 不要把 Nginx 命令暴露成远程管理接口
|
||||
|
||||
### 6.4 数据库规范
|
||||
|
||||
SQLite 是唯一默认数据库。
|
||||
|
||||
要求:
|
||||
|
||||
* 新增模型后必须在 `model.InitDB()` 中加入 `AutoMigrate`
|
||||
* 不写 MySQL/PostgreSQL 特有 SQL
|
||||
* 不依赖外部迁移工具作为 MVP 前提
|
||||
* 时间字段统一使用 GORM 常规时间类型
|
||||
|
||||
### 6.5 发布与渲染规范
|
||||
|
||||
发布逻辑必须满足:
|
||||
|
||||
* 发布时读取全部启用的 `proxy_routes`
|
||||
* 生成完整的 Nginx 路由配置
|
||||
* 计算 checksum
|
||||
* 保存快照到 `config_versions`
|
||||
* 通过切换 `is_active` 激活版本
|
||||
|
||||
版本号格式固定为:
|
||||
|
||||
```text
|
||||
YYYYMMDD-NNN
|
||||
```
|
||||
|
||||
例如:
|
||||
|
||||
```text
|
||||
20260309-001
|
||||
```
|
||||
|
||||
## 7. Agent 开发规范
|
||||
|
||||
### 7.1 模块边界
|
||||
|
||||
建议目录如下:
|
||||
|
||||
```text
|
||||
atsf_agent/
|
||||
cmd/agent/
|
||||
internal/config/
|
||||
internal/heartbeat/
|
||||
internal/sync/
|
||||
internal/nginx/
|
||||
internal/state/
|
||||
internal/httpclient/
|
||||
```
|
||||
|
||||
职责要求:
|
||||
|
||||
* `config`: 本地配置读取
|
||||
* `heartbeat`: 心跳请求和状态组装
|
||||
* `sync`: 检查版本、下载配置、触发应用
|
||||
* `nginx`: 封装 Nginx 校验、reload 和文件写入
|
||||
* `state`: 本地成功版本和运行状态缓存
|
||||
* `httpclient`: Server API 调用
|
||||
|
||||
### 7.2 行为规范
|
||||
|
||||
Agent 必须满足以下行为:
|
||||
|
||||
* 启动后生成或读取本地 `node_id`
|
||||
* 未显式配置 `node_name` 时自动获取主机名
|
||||
* 未显式配置 `node_ip` 时自动获取本机 IP
|
||||
* 周期性心跳
|
||||
* 周期性检查激活版本
|
||||
* 发现新版本后先备份旧文件
|
||||
* 写入新路由配置文件
|
||||
* 先执行 `nginx -t`
|
||||
* 校验通过后执行 `nginx -s reload`
|
||||
* 失败时回滚备份并再次校验和 reload
|
||||
* 上报最终应用结果
|
||||
* 优先使用 `nginx_path`
|
||||
* 未配置 `nginx_path` 时自动准备并使用 Docker Nginx 容器
|
||||
* 启动时先校验本地路由文件 checksum 与控制面激活版本是否一致
|
||||
* Docker 模式启动时应重建容器,而不是继续复用异常停止的旧容器
|
||||
* 若本地 `agent_token` 为空且配置了 `discovery_token`,则应自动发起首次注册并完成 Token 置换
|
||||
|
||||
### 7.3 容错规范
|
||||
|
||||
第一版最少保证:
|
||||
|
||||
* Server 不可用时,Nginx 继续使用旧配置
|
||||
* 下载失败时,不修改本地配置
|
||||
* 配置校验或 reload 失败时,自动尝试回滚
|
||||
* 本地状态文件损坏时,允许重新初始化,但不能删除正在生效的 Nginx 配置
|
||||
* Docker 容器异常停止时,启动阶段应自动重建容器并重新校验配置
|
||||
|
||||
### 7.4 外部命令规范
|
||||
|
||||
Agent 调用 Nginx 命令时必须:
|
||||
|
||||
* 明确记录执行命令和返回错误
|
||||
* 设置合理超时
|
||||
* 不依赖交互式输入
|
||||
* 不通过 shell 拼接不可信参数
|
||||
|
||||
## 8. 前端开发规范
|
||||
|
||||
MVP 前端只做最小管理界面,不重做整套后台。
|
||||
|
||||
要求:
|
||||
|
||||
* 继续使用现有 React 结构和 `semantic-ui-react`
|
||||
* 页面只增加 MVP 必需页面
|
||||
* 不额外引入新的大型前端框架
|
||||
* API 请求统一放在 `web/src/helpers/api.js` 或同类 helper 中
|
||||
* 页面状态优先保持简单,不提前引入复杂全局状态管理
|
||||
|
||||
第一版只需要以下页面:
|
||||
|
||||
* 反代规则页
|
||||
* 发布版本页
|
||||
* 节点状态页
|
||||
* 应用记录页
|
||||
|
||||
## 9. 代码风格规范
|
||||
|
||||
### 9.1 Go
|
||||
|
||||
* 保持 package 名称简短且小写
|
||||
* 错误必须显式处理,不允许静默吞错
|
||||
* 函数尽量只做一件事
|
||||
* 输入校验放在 controller 或 service 边界
|
||||
* 业务枚举值使用明确常量,不使用魔法字符串散落代码
|
||||
* 仅在复杂逻辑前添加简短注释,不写废话注释
|
||||
|
||||
### 9.2 命名
|
||||
|
||||
* 表名和模型名使用业务语义,不沿用模板示例语义
|
||||
* 统一使用 `route`, `version`, `node`, `apply log` 这些术语
|
||||
* 不混用 `client`、`edge`、`agent` 指代同一模块,统一叫 `agent`
|
||||
|
||||
### 9.3 日志
|
||||
|
||||
要求记录这些关键事件:
|
||||
|
||||
* 发布成功/失败
|
||||
* Agent 注册
|
||||
* 心跳异常
|
||||
* 配置下载失败
|
||||
* Nginx 校验或 reload 成功/失败
|
||||
* 回滚触发
|
||||
|
||||
日志内容要可定位问题,但不要打印敏感 Token。
|
||||
|
||||
## 10. 测试与验收规范
|
||||
|
||||
### 10.1 第一版最低测试要求(已完成)
|
||||
|
||||
Server 至少覆盖:
|
||||
|
||||
* `origin_url` 校验
|
||||
* `domain` 重复校验
|
||||
* Nginx 路由配置渲染结果
|
||||
* 激活版本切换逻辑
|
||||
* 节点在线状态判定逻辑
|
||||
|
||||
Agent 至少覆盖:
|
||||
|
||||
* 版本比较逻辑
|
||||
* 配置文件备份和回滚逻辑
|
||||
* `nginx -t` 或 `nginx -s reload` 失败分支
|
||||
* 本地状态文件读写
|
||||
|
||||
### 10.2 第二版新增测试要求
|
||||
|
||||
Server 新增覆盖:
|
||||
|
||||
* HTTPS server 块渲染正确性(`enable_https=true` 时生成 443 块,`redirect_http=true` 时生成重定向块)
|
||||
* HTTP-only 路由渲染结果不受 HTTPS 字段影响
|
||||
* 证书导入逻辑(手动导入、文件导入)和 PEM 校验逻辑
|
||||
* 域名证书匹配逻辑(精确匹配与 `*.example.com` 通配符匹配)
|
||||
* `custom_headers` 注入到渲染结果的正确性
|
||||
* 节点创建、编辑、删除逻辑
|
||||
* `discovery_token` 首次接入成功后失效
|
||||
* 删除节点后 Agent 请求立即返回 401
|
||||
* Agent 自动探测主机名与 IP,且允许配置覆盖
|
||||
* Agent 首次注册成功后完成本地 token 置换
|
||||
* 预览接口不写库
|
||||
* diff 接口变更摘要计算正确性
|
||||
|
||||
### 10.3 联调验收标准(第一版,已完成)
|
||||
|
||||
1. 管理端新增反代规则并成功发布版本
|
||||
2. Agent 能检测到新版本并拉取
|
||||
3. Agent 成功写入 Nginx 路由配置文件
|
||||
4. Agent 成功执行 `nginx -t` 和 `nginx -s reload`
|
||||
5. 节点页能看到当前版本和最后心跳
|
||||
6. 当 reload 失败时,Agent 能回滚到旧配置并上报失败
|
||||
|
||||
### 10.4 联调验收标准(第二版)
|
||||
|
||||
1. 创建含 HTTPS 字段的路由并发布,Nginx 能以 HTTPS 正确转发
|
||||
2. 控制面可手动导入和文件导入证书,导入后可被路由选择
|
||||
3. 反代规则输入域名后可自动匹配证书,且支持 `*.example.com`
|
||||
4. 通过管理界面创建节点并生成 discovery token,Agent 使用 discovery token 成功接入
|
||||
5. 删除节点后 Agent 请求返回 401
|
||||
6. 路由配置自定义头后,渲染结果包含对应指令
|
||||
7. 发布页预览展示正确渲染结果
|
||||
8. 变更摘要正确列出域名变化
|
||||
|
||||
## 11. 文档维护规范
|
||||
|
||||
出现以下情况时必须同步更新文档:
|
||||
|
||||
* 产品版本范围变化(V1 → V2 → V3)
|
||||
* API 发生破坏性变更
|
||||
* 数据模型新增或删除
|
||||
* Agent 本地文件路径变更
|
||||
* 部署方式变化
|
||||
* 新增或撤销对中间件/基础设施的依赖
|
||||
|
||||
优先更新:
|
||||
|
||||
* `docs/design.md`
|
||||
* `docs/development-guidelines.md`
|
||||
* `docs/development-plan.md`
|
||||
|
||||
+20
-16
@@ -111,27 +111,30 @@ MVP 已于第一版完成。当前进入第二版迭代。
|
||||
* 通配符证书可匹配子域名(如 `api.example.com` 匹配 `*.example.com`)
|
||||
* 无匹配证书时前端给出明确提示
|
||||
|
||||
### V2 Phase 3: Agent Token 管理
|
||||
### V2 Phase 3: Agent 管理
|
||||
|
||||
目标:
|
||||
|
||||
* 支持多个命名 Token
|
||||
* Token 可通过管理界面创建和撤销
|
||||
* 中间件改为查库验证
|
||||
* 实现对节点的增删改查
|
||||
* 实现节点自动发现机制
|
||||
|
||||
|
||||
交付:
|
||||
|
||||
* `agent_tokens` 表与模型
|
||||
* agent-auth 中间件改造(查表验证)
|
||||
* 全局 Token 环境变量降级为 bootstrap 模式
|
||||
* Token CRUD API
|
||||
* 前端 Token 管理页
|
||||
* 移除全局 Token 环境变量, 节点不再通过该方式连接server
|
||||
* 引入自动发现TOKEN, 需要用户手动在节点页创建, 持有该TOKEN的节点会自动连接到SERVER
|
||||
* Node CRUD API
|
||||
* 前端 节点 管理页
|
||||
|
||||
完成标准:
|
||||
|
||||
* 新建 Token 后 Agent 可用该 Token 访问 Agent API
|
||||
* 撤销 Token 后 Agent 请求立即返回 401
|
||||
* 全局环境变量 Token 仅在数据库无有效记录时生效
|
||||
* 用户启动server后需要手动在节点页添加节点, 此时会生成随机TOKEN, 持有该TOKEN的节点可以加入server. server可以修改节点的名称
|
||||
* 用户可以编辑节点, 包括节点名
|
||||
* 删除节点后 Agent 请求立即返回 401
|
||||
* 节点配置文件不再要求填写节点名和IP地址, 节点名默认从主机名获取, IP也是自动获取. 手动指定则为覆盖
|
||||
* 节点配置文件agent_token为空, 自动发现TOKEN配置为server生成值后, 会自己向server注册, 注册后会进行TOKEN置换, 更新节点配置文件agent_token
|
||||
|
||||
|
||||
### V2 Phase 4: 路由自定义头
|
||||
|
||||
@@ -175,7 +178,7 @@ MVP 已于第一版完成。当前进入第二版迭代。
|
||||
|
||||
1. HTTPS/TLS 支持(对现有渲染链路影响最小,独立可测)
|
||||
2. 域名管理与证书自动匹配(与 HTTPS 强相关,尽早完成闭环)
|
||||
3. Agent Token 管理(安全性改善,早做早稳)
|
||||
3. Agent 管理(节点 CRUD + 自动发现 + token 置换)
|
||||
4. 路由自定义头(纯增量,对现有结构影响小)
|
||||
5. 配置预览与变更摘要(纯只读接口,最后补充)
|
||||
|
||||
@@ -205,10 +208,11 @@ MVP 已于第一版完成。当前进入第二版迭代。
|
||||
|
||||
### V2 Phase 3 检查项
|
||||
|
||||
* 可通过管理界面创建 Token
|
||||
* 新 Token 可被 Agent 使用
|
||||
* 撤销 Token 后访问立即失败
|
||||
* 全局 Token 环境变量在数据库有记录时失效
|
||||
* 可通过管理界面创建节点并生成 discovery token
|
||||
* Agent 可使用 discovery token 自动接入并完成 agent token 置换
|
||||
* 用户可编辑节点名并删除节点
|
||||
* 删除节点后 Agent 请求立即失败
|
||||
* Agent 在未显式配置节点名/IP 时可自动探测
|
||||
|
||||
### V2 Phase 4 检查项
|
||||
|
||||
|
||||
Reference in New Issue
Block a user