# OpenFlare → Wavelet 后端迁移计划 > **文档类型**:实现计划(Implementation Plan) > **创建日期**:2026-06-18 > **状态**:实施中(阶段 5 收尾;控制台 `/api/v1/d/*` + 新前端已落地,legacy 兼容层已撤销) --- ## 1. 目标与背景 ### 1.1 需求背景 OpenFlare 当前控制面基于 `openflare-server`(Gin + GORM 单体),与 Wavelet 全栈脚手架在认证、任务、配置、可观测性等基础设施上存在大量重叠。为降低长期维护成本、复用 Wavelet 平台能力,需将 **OpenFlare 业务域**迁移至 Wavelet 框架,同时: 1. **阶段一(本计划核心)**:保留旧前端(`openflare-server/web`)可联调的 **原始 API 路径**(`/api/*`),完成「旧前端 + 新后端」验证。 2. **重叠职能遵循新框架**:用户系统、登录、OAuth、验证码、系统配置、文件上传、推送、任务调度等 **一律复用 Wavelet 内置实现**,禁止在 OpenFlare 业务包中重写。 3. **Agent / Relay / Flared 协议不变**:节点侧二进制与通信协议保持兼容,仅 Server 实现迁移。 ### 1.2 开发范围(Scope) | 范围内(In Scope) | 范围外(Out of Scope) | |---|---| | `openflare-server` 全部 HTTP API 迁移至 `Wavelet/` | `openflare-agent`、`openflare-relay`、`openflared` 代码迁移 | | 重叠模块复用 Wavelet 内置能力 + 兼容适配层 | 多租户、细粒度 RBAC(超出 OpenFlare 单租户边界) | | 数据模型与 goose SQL 迁移(PG + SQLite 双份) | 英文文档同步 | | 旧路径 `/api/*` 兼容注册 | 阶段二新前端路径改造(见前端迁移计划) | | OpenFlare 定时任务(**过渡**:API 主进程内 cron;**目标**:后续迁入统一任务框架) | Wavelet 框架核心文件修改(`v1/user.go` 等禁止改动) | | `pkg/geoip`、`pkg/render/openresty`、`pkg/protocol` 复用 | 微信登录长期维护(评估后降级或适配) | ### 1.3 迁移总原则 ```mermaid flowchart TB subgraph Phase1["阶段一:旧前端联调"] OldWeb["openflare-server/web"] CompatAPI["/api/* 兼容路由层"] WaveletCore["Wavelet 内置模块\nuser/oauth/cap/admin"] OFBiz["OpenFlare 业务模块\nproxy/waf/node/..."] OldWeb --> CompatAPI CompatAPI --> WaveletCore CompatAPI --> OFBiz end subgraph Phase2["阶段二:新前端(见前端计划)"] NewWeb["Wavelet/frontend"] NewWeb --> V1API["/api/v1/*"] V1API --> WaveletCore V1API --> OFBiz end ``` | 原则 | 说明 | |---|---| | **框架优先** | 严格遵守 `Wavelet/AGENTS.md` Guardrails;Skills 以 `/Users/ryan/DEV/Go/Wavelet/.claude/skills/` 为准 | | **路径兼容** | 阶段一所有旧前端调用的 `/api/*` 路径保持不变 | | **实现复用** | 重叠功能调用 Wavelet `internal/apps/*` Logic,不复制代码 | | **路由隔离** | 业务路由仅注册于 `v1/custom.go`、`root/custom.go`;兼容层单独 `legacy` 包 | | **数据独立** | OpenFlare 表使用 `of_` 前缀或保持原表名;**禁止修改** `w_users` 等框架表 | | **响应信封** | 新实现统一 `{ error_msg, data }`;兼容层对旧前端做字段/结构适配 | --- ## 2. 架构设计与关键决策 ### 2.1 目标目录结构(迁移后) ``` Wavelet/ ├── internal/ │ ├── apps/ │ │ ├── user/ # ✅ 复用(禁止重写) │ │ ├── oauth/ # ✅ 复用 │ │ ├── cap/ # ✅ 复用 │ │ ├── admin/ # ✅ 复用 │ │ ├── upload/ # ✅ 复用(Pages 部署包摄取) │ │ └── openflare/ # 🆕 OpenFlare 业务域根包 │ │ ├── legacy/ # 🆕 /api/* 兼容 Handler(阶段一) │ │ ├── compat/ # 🆕 响应/鉴权/角色适配 │ │ ├── proxy_route/ # 代理规则 │ │ ├── origin/ # 源站 │ │ ├── config_version/# 配置版本 + 渲染 │ │ ├── node/ # 节点管理 │ │ ├── agent/ # Agent API │ │ ├── relay/ # Relay API │ │ ├── flared/ # Tunnel Client API │ │ ├── waf/ # WAF │ │ ├── tls/ # TLS/ACME/DNS │ │ ├── managed_domain/ │ │ ├── pages/ # Pages 静态托管 │ │ ├── dashboard/ # 仪表盘聚合 │ │ ├── observability/ # 可观测性查询(v1 单表) │ │ ├── tasks/ # 🆕 定时/后台任务集中目录(主进程 cron) │ │ ├── apply_log/ │ │ ├── option/ # OpenFlare 专有 Option(非框架 SystemConfig) │ │ ├── update/ # 服务自更新 │ │ ├── uptimekuma/ # Uptime Kuma 集成 │ │ ├── geoip/ # GeoIP 查询服务 │ │ └── websocket/ # Agent/Relay/Flared/升级 WS Hub │ ├── model/ │ │ ├── users.go # ✅ 框架表(不修改) │ │ └── openflare_*.go # 🆕 OpenFlare 实体 │ ├── db/migrator/goose/ │ │ ├── postgres/ # 🆕 of_* 表 SQL │ │ └── sqlite/ │ └── router/ │ ├── v1/custom.go # 🆕 注册 /api/v1/custom/openflare/* │ └── root/custom.go # 🆕 Webhook/WS 等根路径 ├── pkg/ # 从仓库根迁入或 go.mod replace │ ├── geoip/ # 复用 OpenFlare pkg/geoip │ ├── render/openresty/ # 复用配置渲染引擎 │ └── protocol/ # 复用节点协议 └── internal/bootstrap/ # API 启动时注册并运行 openflare/tasks ``` ### 2.2 关键架构决策 | 决策点 | 选定方案 | 理由 | |---|---|---| | API 路径(阶段一) | 在 `apiGroup` 下新增 `/api` 直连组(非 `/v1`),注册全部旧路径 | 旧前端零改动联调 | | API 路径(阶段二) | 新前端逐步切至 `/api/v1/custom/openflare/*` 或规范化 REST | 符合 Wavelet 规范 | | 用户/登录 | **复用** `internal/apps/user` + `oauth`;`legacy` 层做路径与 Token 桥接 | 避免双套用户体系 | | 认证 Token 桥接 | 阶段一同时支持 `OpenFlare-Token`(JWT)与 Wavelet Session/AccessToken;登录后 legacy 层签发兼容 JWT 或映射到 AccessToken | 旧前端依赖 Header Token | | 角色模型 | OpenFlare `role(1/10/100)` 映射为 Wavelet `is_admin` + 扩展字段 `of_role`(SystemConfig 或用户扩展表) | Wavelet 仅 bool admin;Root 权限需扩展 | | 系统配置 | OpenFlare `options` 表保留(70+ 热加载项);框架 `system_configs` 仅放 Wavelet 平台项 | 业务配置语义不同,避免强行合并 | | 定时任务(OpenFlare) | **当前**:`openflare/tasks` + `robfig/cron`,随 `wavelet api` / `wavelet all` 在 API 进程内运行;**后续**:迁入统一任务框架(文件按 job 拆分,便于替换 registry) | 阶段一优先功能完备;与 Wavelet Asynq Worker/Scheduler 解耦 | | 数据库迁移 | Wavelet goose SQL(postgres + sqlite 双份);默认库名 `openflare`;SQLite→PG 一次性迁移脚本待补 | 与框架迁移机制一致 | | 可观测存储 | **v1 单表**(`of_node_*` 无 `_00`~`_09` 分片);历史分片数据需 ETL;后续可评估 ClickHouse 或恢复分片 | 降低迁移复杂度,满足当前联调与中小规模部署 | | 进程部署 | Wavelet 生产仍建议 `api` + `worker` + `scheduler` 三进程;**OpenFlare 业务 cron 仅需 API 进程** | 框架任务与 OpenFlare cron 职责分离 | | 前端嵌入 | 阶段一继续托管 `openflare-server/web/build`;阶段二切换 `Wavelet/frontend` embed | 分阶段降低风险 | ### 2.3 鉴权兼容设计 ```mermaid sequenceDiagram participant FE as 旧前端 participant LEG as legacy/auth 适配 participant USR as apps/user participant OF as openflare/* Logic FE->>LEG: POST /api/user/login LEG->>USR: Login(ctx, credentials) USR-->>LEG: Session + User LEG-->>FE: JWT OpenFlare-Token(兼容) FE->>LEG: GET /api/proxy-routes/ + OpenFlare-Token LEG->>LEG: 校验 JWT / 映射 AccessToken LEG->>OF: ListProxyRoutes(ctx, user) OF-->>LEG: results LEG-->>FE: 旧格式 ApiEnvelope ``` | OpenFlare 鉴权 | Wavelet 目标 | 适配位置 | |---|---|---| | `OpenFlare-Token` JWT | Session / AccessToken | `openflare/compat/auth.go` | | `UserAuth` role≥1 | `oauth.LoginRequired()` | legacy 中间件 | | `AdminAuth` role≥10 | `LoginRequired` + `of_role≥10` | legacy 中间件 | | `RootAuth` role≥100 | `LoginAdminRequired` + `of_role≥100` | legacy 中间件 | | `X-Agent-Token` | 保持不变 | `openflare/agent/middleware.go` | | `X-Tunnel-Token` | 保持不变 | `openflare/flared/middleware.go` | | Cap PoW `/api/cap/:scope/*` | `apps/cap` + scope 映射 | `openflare/legacy/cap.go` | --- ## 3. 功能模块迁移总览 ### 3.1 模块分类 | 类别 | 处理方式 | 模块数 | |---|---|---| | **A. 直接复用 Wavelet** | 不迁移代码,仅适配路径/响应 | 12 | | **B. 兼容适配层** | 薄 Handler 包装 Wavelet Logic | 8 | | **C. 完整迁移 OpenFlare 业务** | 重写为 Wavelet 规范(Handler+Logic+errs) | 15 | | **D. 基础设施迁移** | 定时任务(主进程 cron)、WS Hub、可观测单表 | 6 | --- ## 4. 模块 A:直接复用 Wavelet(禁止重写) | # | 旧模块 | 旧 API 前缀 | Wavelet 复用位置 | 阶段一兼容路径 | 迁移动作 | |---|---|---|---|---|---| | A1 | 密码登录 | `POST /api/user/login` | `internal/apps/user` | 保持 | legacy Handler 委托 `user.Login` | | A2 | 登出 | `GET /api/user/logout` | `internal/apps/user` | 保持 | legacy 委托 + 清 JWT | | A3 | 当前用户 | `GET /api/user/self` | `internal/apps/user` | 保持 | 字段映射 `role/display_name` | | A4 | 更新资料 | `POST /api/user/self/update` | `PUT /api/v1/user/profile` | 保持旧路径 | legacy 转发 | | A5 | 修改密码 | — | `POST /api/v1/user/change-password` | 设置页适配 | 前端阶段二切路径 | | A6 | 邮箱验证码 | `GET /api/verification` | `POST /api/v1/user/send-email-code` | 保持/映射 | legacy 参数适配 | | A7 | OAuth 通用 | `/api/oauth/:source/*` | `internal/apps/oauth` | 保持 | 回调 URL 配置更新 | | A8 | 外部账号 | `/api/oauth/external-accounts` | `oauth.ListExternalAccounts` | 保持 | 响应字段映射 | | A9 | 用户管理 Admin | `/api/user/` CRUD | `internal/apps/admin/user` | 保持 | role 字段双向映射 | | A10 | 认证源 CRUD | `/api/auth-sources/` | `admin/auth_source` | 保持 | legacy CRUD 包装 | | A11 | 验证码 Cap | `/api/cap/:scope/*` | `internal/apps/cap` | 保持 | scope→scene 映射 | | A12 | 服务自更新 | `/api/update/*` | `admin/updater` | 保持 | 升级逻辑对齐 Wavelet updater | **目标代码位置(适配层)**: | 文件 | 职责 | |---|---| | `internal/apps/openflare/legacy/auth_user.go` | 用户登录/登出/self/注册 | | `internal/apps/openflare/legacy/auth_oauth.go` | OAuth 路径兼容 | | `internal/apps/openflare/legacy/auth_admin.go` | 用户管理、认证源 | | `internal/apps/openflare/legacy/cap.go` | Cap scope 兼容 | | `internal/apps/openflare/legacy/update.go` | 升级 API 兼容 | | `internal/apps/openflare/compat/auth.go` | JWT↔Session/Token、角色解析 | | `internal/apps/openflare/compat/response.go` | Wavelet 信封 → 旧 ApiEnvelope | **明确不复用/需评估**: | 项 | 说明 | |---|---| | 微信登录 `GET /api/oauth/wechat` | Wavelet 无内置;阶段一保留 legacy 实现或标记废弃 | | 注册 `POST /api/user/register` | 旧实现返回「非法请求」;对齐 Wavelet `POST /api/v1/user/register` | | GitHub 旧回调 `GET /api/oauth/github` | 迁移到通用 OAuth 源 | --- ## 5. 模块 B:兼容适配(薄包装) | # | 旧模块 | 旧路径 | Wavelet 对齐能力 | 目标 Logic 位置 | |---|---|---|---|---| | B1 | 系统状态 | `GET /api/status` | `health` + `config/public` + 自定义 | `openflare/legacy/status.go` | | B2 | 公告 | `GET /api/notice` | Option/SystemConfig | `openflare/option/logics.go` | | B3 | 关于 | `GET /api/about` | Option | `openflare/option/logics.go` | | B4 | 密码重置 | `/api/reset_password`, `POST /api/user/reset` | `user` 邮件能力 | `openflare/legacy/password_reset.go` | | B5 | 系统选项 | `GET/POST /api/option/*` | 保留 `of_options` 表 | `openflare/option/` | | B6 | SMTP/邮件 | Option 内嵌 | `pkg/mail` + admin 配置 | 通过 `option` 读写 + `mail` 发送 | | B7 | 限流 | 中间件 | `risk_control` + Redis | `openflare/compat/ratelimit.go` | | B8 | Swagger | `GET /swagger/*` | 框架 Swagger | `root/custom.go` 或沿用 root | --- ## 6. 模块 C:OpenFlare 核心业务(完整迁移) ### 6.1 代理与源站 | # | 功能 | 旧路径 | 目标 Logic | 目标 Model | 目标路由注册 | |---|---|---|---|---|---| | C1 | 代理规则列表 | `GET /api/proxy-routes/` | `openflare/proxy_route/logics.go` | `model/openflare_proxy_route.go` | `legacy/proxy_route.go` | | C2 | 代理规则详情 | `GET /api/proxy-routes/:id` | 同上 | 同上 | 同上 | | C3 | 创建代理规则 | `POST /api/proxy-routes/` | 同上 | 同上 | 同上 | | C4 | 更新代理规则 | `POST /api/proxy-routes/:id/update` | 同上 | 同上 | 同上 | | C5 | 删除代理规则 | `POST /api/proxy-routes/:id/delete` | 同上 | 同上 | 同上 | | C6 | 源站列表 | `GET /api/origins/` | `openflare/origin/logics.go` | `model/openflare_origin.go` | `legacy/origin.go` | | C7 | 源站 CRUD | `GET/POST /api/origins/:id/*` | 同上 | 同上 | 同上 | **迁移源文件对照**: | 旧文件 | 新文件 | |---|---| | `openflare-server/internal/controller/proxy_route.go` | `openflare/proxy_route/routers.go` | | `openflare-server/internal/service/proxy_route.go` | `openflare/proxy_route/logics.go` | | `openflare-server/internal/controller/origin.go` | `openflare/origin/routers.go` | | `openflare-server/internal/service/origin.go` | `openflare/origin/logics.go` | ### 6.2 配置版本与发布 | # | 功能 | 旧路径 | 目标 Logic | 依赖 | |---|---|---|---|---| | C8 | 版本列表 | `GET /api/config-versions/` | `openflare/config_version/logics.go` | `pkg/render/openresty` | | C9 | 激活版本 | `GET /api/config-versions/active` | 同上 | | | C10 | 预览配置 | `GET /api/config-versions/preview` | 同上 | | | C11 | Diff | `GET /api/config-versions/diff` | 同上 | | | C12 | 版本详情 | `GET /api/config-versions/:id` | 同上 | | | C13 | 发布 | `POST /api/config-versions/publish` | 同上 | | | C14 | 激活 | `POST /api/config-versions/:id/activate` | 同上 | listener 通知 Agent | | C15 | 清理 | `POST /api/config-versions/cleanup` | 同上 | | **目标文件**: | 路径 | 职责 | |---|---| | `internal/apps/openflare/config_version/logics.go` | 快照构建、渲染、checksum | | `internal/apps/openflare/config_version/routers.go` | HTTP Handler | | `internal/apps/openflare/config_version/renderer.go` | 封装 `pkg/render/openresty` | | `internal/model/openflare_config_version.go` | `of_config_versions` 表 | ### 6.3 节点管理 | # | 功能 | 旧路径 | 目标 Logic | |---|---|---|---| | C16 | 节点列表 | `GET /api/nodes/` | `openflare/node/logics.go` | | C17 | 创建节点 | `POST /api/nodes/` | 同上 | | C18 | 更新/删除 | `POST /api/nodes/:id/update|delete` | 同上 | | C19 | Bootstrap Token | `GET/POST /api/nodes/bootstrap-token/*` | 同上 | | C20 | Agent 升级 | `POST /api/nodes/:id/agent-update` | 同上 + `openflare/update/` | | C21 | 强制同步 | `POST /api/nodes/:id/force-sync` | 同上 + WS 通知 | | C22 | OpenResty 重启 | `POST /api/nodes/:id/openresty-restart` | 同上 | | C23 | 可观测性 | `GET /api/nodes/:id/observability` | `openflare/observability/logics.go` | | C24 | 健康事件清理 | `POST /api/nodes/:id/observability/cleanup` | 同上 | | C25 | Agent 版本查询 | `GET /api/nodes/:id/agent-release` | `openflare/node/agent_release.go` | **目标 Model**:`model/openflare_node.go`(表 `of_nodes`,或保留 `nodes`) ### 6.4 Agent / Relay / Flared API(节点协议) | # | 功能 | 旧路径 | 目标 Logic | 认证中间件 | |---|---|---|---|---| | C26 | Agent 注册 | `POST /api/agent/nodes/register` | `openflare/agent/logics.go` | `AgentRegisterAuth` | | C27 | Agent 心跳 | `POST /api/agent/nodes/heartbeat` | 同上 | `AgentAuth` | | C28 | Agent WS | `GET /api/agent/ws` | `openflare/websocket/agent_hub.go` | `AgentAuth` | | C29 | 拉取配置 | `GET /api/agent/config-versions/active` | `openflare/agent/config.go` | `AgentAuth` | | C30 | Pages 包下载 | `GET /api/agent/pages/deployments/:id/package` | `openflare/pages/agent.go` | `AgentAuth` | | C31 | WAF IP 同步 | `POST /api/agent/waf/ip-groups/sync` | `openflare/waf/agent_sync.go` | `AgentAuth` | | C32 | 应用日志上报 | `POST /api/agent/apply-logs` | `openflare/apply_log/logics.go` | `AgentAuth` | | C33 | Relay 心跳 | `POST /api/relay/heartbeat` | `openflare/relay/logics.go` | `RelayAuth` | | C34 | Relay WS | `GET /api/relay/ws` | `openflare/websocket/relay_hub.go` | `RelayAuth` | | C35 | Flared 心跳 | `POST /api/flared/heartbeat` | `openflare/flared/logics.go` | `TunnelAuth` | | C36 | Flared 配置 | `GET /api/flared/config/active` | 同上 | `TunnelAuth` | | C37 | Flared 应用日志 | `POST /api/flared/apply-log` | 同上 | `TunnelAuth` | | C38 | Flared WS | `GET /api/flared/ws` | `openflare/websocket/flared_hub.go` | `TunnelAuth` | **迁移源**:`openflare-server/internal/controller/agent.go`、`relay.go`、`flared.go`、`service/node*.go` ### 6.5 WAF | # | 功能 | 旧路径 | 目标 Logic | |---|---|---|---| | C39 | IP 组列表 | `GET /api/waf/ip-groups` | `openflare/waf/ip_group.go` | | C40 | IP 组 CRUD | `POST /api/waf/ip-groups/*` | 同上 | | C41 | IP 组同步 | `POST /api/waf/ip-groups/:id/sync` | 同上 + `tasks/waf_ip_group_sync` cron | | C42 | IP 组测试 | `POST /api/waf/ip-groups/test` | 同上 | | C43 | 规则组列表 | `GET /api/waf/rule-groups` | `openflare/waf/rule_group.go` | | C44 | 规则组 CRUD | `POST /api/waf/rule-groups/*` | 同上 | | C45 | 规则组站点绑定 | `POST /api/waf/rule-groups/:id/sites` | 同上 | | C46 | 站点规则组 | `GET/POST /api/waf/sites/:route_id/rule-groups` | `openflare/waf/site_binding.go` | **目标 Model**: | 模型 | 表名 | |---|---| | `OpenFlareWAFRuleGroup` | `of_waf_rule_groups` | | `OpenFlareWAFIPGroup` | `of_waf_ip_groups` | | `OpenFlareWAFRuleGroupBinding` | `of_waf_rule_group_bindings` | ### 6.6 TLS / ACME / DNS / 托管域名 | # | 功能 | 旧路径 | 目标 Logic | |---|---|---|---| | C47 | 托管域名 CRUD | `/api/managed-domains/*` | `openflare/managed_domain/` | | C48 | SNI 匹配 | `GET /api/managed-domains/match` | 同上 | | C49 | TLS 证书 CRUD | `/api/tls-certificates/*` | `openflare/tls/` | | C50 | 证书内容 | `GET /api/tls-certificates/:id/content` | 同上 | | C51 | ACME 申请/续期 | `POST /api/tls-certificates/apply|renew` | 同上 + `lego` | | C52 | ACME 转换 | `POST /api/tls-certificates/:id/convert-acme` | 同上 | | C53 | 文件导入 | `POST /api/tls-certificates/import-file` | 同上 + `upload.Ingest` | | C54 | DNS 账号 CRUD | `/api/dns-accounts/*` | `openflare/tls/dns_account.go` | | C55 | 默认 ACME 账号 | `GET /api/acme-accounts/default` | `openflare/tls/acme_account.go` | **迁移源**:`openflare-server/internal/service/certificate*.go`、`acme*.go`、`dns*.go` ### 6.7 Pages 静态托管 | # | 功能 | 旧路径 | 目标 Logic | 备注 | |---|---|---|---|---| | C56 | 项目 CRUD | `/api/pages/*` | `openflare/pages/logics.go` | | | C57 | 部署列表 | `GET /api/pages/:id/deployments` | 同上 | | | C58 | 部署上传 | `POST .../deployments/upload` | 同上 | 使用 `upload.Ingest` | | C59 | 激活部署 | `POST .../activate` | 同上 | 触发 config_version 变更 | | C60 | 删除部署 | `POST .../delete` | 同上 | `upload.Remove` | | C61 | 部署文件清单 | `GET /api/pages/deployments/:id/files` | 同上 | | ### 6.8 仪表盘与可观测性 | # | 功能 | 旧路径 | 目标 Logic | |---|---|---|---| | C62 | 仪表盘总览 | `GET /api/dashboard/overview` | `openflare/dashboard/logics.go` | | C63 | 访问日志查询 | `GET /api/access-logs/` | `openflare/observability/access_log.go` | | C64 | 折叠日志 | `GET /api/access-logs/folds` | 同上 | | C65 | IP 汇总 | `GET /api/access-logs/ip-summary` | 同上 | | C66 | IP 趋势 | `GET /api/access-logs/ip-summary/trend` | 同上 | | C67 | 访问日志清理 | `POST /api/access-logs/cleanup` | 同上 | | C68 | 应用日志 | `GET /api/apply-logs/` | `openflare/apply_log/logics.go` | | C69 | 应用日志清理 | `POST /api/apply-logs/cleanup` | 同上 | | C70 | GeoIP 查询 | `POST /api/option/geoip/lookup` | `openflare/geoip/logics.go` | | C71 | 数据库清理 | `POST /api/option/database/cleanup` | `openflare/tasks/database_cleanup.go` | **可观测存储(v1)**:goose 单表 `of_node_system_profiles`、`of_node_metric_snapshots`、`of_node_request_reports`、`of_node_health_events`、`of_node_obs_openresty`、`of_node_obs_frps`、`of_node_obs_frpc`、`of_node_access_logs`(迁移 `202606190010`~`012`)。访问日志查询/聚合已实装于 `model/openflare_access_log.go`。 ### 6.9 运维集成与定时任务 | # | 功能 | 旧路径 / 调度 | 实现位置 | 调度(当前) | |---|---|---|---|---| | C72 | UptimeKuma 同步 | `POST /api/uptimekuma/sync`;Cron 每分钟检查间隔 | `openflare/uptimekuma/sync.go` | `tasks/uptimekuma_sync.go` `* * * * *` | | C73 | SSL 自动续期 | Cron 每日 00:00 | `openflare/tls/obtain.go` + `tasks/ssl_renew.go` | `0 0 * * *` | | C74 | WAF IP 组同步 | Cron 每 5 分钟;`POST .../ip-groups/:id/sync` | `openflare/waf/ip_group_sync.go` | `@every 5m` | | C75 | 可观测数据自动清理 | Cron 每日 03:00(`DatabaseAutoCleanupEnabled`) | `openflare/tasks/database_cleanup.go` | `0 3 * * *` | **任务注册**:各 job 在 `init()` 中 `registerJob`;`bootstrap.Init(API)` 调用 `tasks.Start`。WAF job 经 `waf/register_tasks.go` 注册以避免 import cycle。 --- ## 7. 数据模型迁移清单 ### 7.1 框架表(复用,不迁移数据结构) | Wavelet 表 | 用途 | OpenFlare 映射 | |---|---|---| | `w_users` | 用户 | 替代 `users` | | `w_access_tokens` | API Token | 替代 `users.token` 长期使用 | | `w_auth_sources` | 认证源 | 替代 `auth_sources` | | `w_external_accounts` | 外部账号 | 替代 `external_accounts` | | `system_configs` | 平台配置 | 仅 Wavelet 平台项 | ### 7.2 OpenFlare 业务表(goose 新建) | 旧表名 | 新表名建议 | 迁移优先级 | Model 文件 | |---|---|---|---| | `options` | `of_options` | P0 | `openflare_option.go` | | `origins` | `of_origins` | P1 | `openflare_origin.go` | | `proxy_routes` | `of_proxy_routes` | P1 | `openflare_proxy_route.go` | | `config_versions` | `of_config_versions` | P1 | `openflare_config_version.go` | | `nodes` | `of_nodes` | P1 | `openflare_node.go` | | `managed_domains` | `of_managed_domains` | P2 | `openflare_managed_domain.go` | | `tls_certificates` | `of_tls_certificates` | P2 | `openflare_tls_certificate.go` | | `acme_accounts` | `of_acme_accounts` | P2 | `openflare_acme_account.go` | | `dns_accounts` | `of_dns_accounts` | P2 | `openflare_dns_account.go` | | `pages_projects` | `of_pages_projects` | P2 | `openflare_pages_project.go` | | `pages_deployments` | `of_pages_deployments` | P2 | `openflare_pages_deployment.go` | | `pages_deployment_files` | `of_pages_deployment_files` | P2 | `openflare_pages_deployment_file.go` | | `waf_rule_groups` | `of_waf_rule_groups` | P2 | `openflare_waf_rule_group.go` | | `waf_ip_groups` | `of_waf_ip_groups` | P2 | `openflare_waf_ip_group.go` | | `waf_rule_group_bindings` | `of_waf_rule_group_bindings` | P2 | `openflare_waf_binding.go` | | `apply_logs` | `of_apply_logs` | P1 | `openflare_apply_log.go` | | `node_system_profiles` | `of_node_system_profiles` | P1 | `openflare_node_profile.go` | | `node_health_events` | `of_node_health_events` | P2 | `openflare_health_event.go` | | `node_metric_snapshots_XX` | `of_node_metric_snapshots`(v1 单表) | ✅ | `openflare_observability.go` | | `node_request_reports_XX` | `of_node_request_reports`(v1 单表) | ✅ | 同上 | | `node_access_logs_XX` | `of_node_access_logs`(v1 单表 + 复合索引) | ✅ | `openflare_access_log.go` | | `node_observation_openresties_XX` | `of_node_obs_openresty`(v1 单表) | ✅ | `openflare_observability.go` | | `node_observation_frps_XX` | `of_node_obs_frps`(v1 单表) | ✅ | 同上 | | `node_observation_frpcs_XX` | `of_node_obs_frpc`(v1 单表) | ✅ | 同上 | ### 7.3 数据迁移脚本 | 脚本 | 路径 | 说明 | |---|---|---| | 用户迁移 | `support-files/migration/migrate_users.go` | `users` → `w_users`,角色映射 | | 业务数据迁移 | `support-files/migration/migrate_openflare_data.go` | 全表批量迁移 | | SQLite→PG | Wavelet 启动检测 + 一次性导入 | 参考旧 `openflare-server` 逻辑 | --- ## 8. 分阶段实施计划 ### 阶段 0:基建准备(1–2 周)— ✅ 已完成 | 任务 ID | 任务 | 产出 | 验收标准 | |---|---|---|---| | B0-1 | 在 `Wavelet/go.mod` 添加 `pkg/geoip`、`pkg/render`、`pkg/protocol` 引用 | go.mod replace | `go build ./...` 通过 | | B0-2 | 创建 `internal/apps/openflare/` 骨架 | 包结构 | 符合 AGENTS.md | | B0-3 | 实现 `compat/auth.go`、`compat/response.go` | 鉴权/响应适配 | 单元测试覆盖 | | B0-4 | 注册 legacy 路由组 | `legacy/register*.go` | `/api/status` 可访问 | | B0-5 | bootstrap 注册 OpenFlare 后台任务 | `bootstrap.go` + `openflare/tasks` | API 启动后 cron 注册日志可见 | | B0-6 | 同步 Wavelet Skills 到开发环境 | `.claude/skills/` | AI 开发可用 | | B0-7 | 编写 OpenFlare 业务设计补充文档 | `docs/design/openflare-wavelet-integration.md` | 待评审(可选) | ### 阶段 1:认证与用户联调(1 周)— ✅ 已完成 | 任务 ID | 任务 | 依赖 | |---|---|---| | B1-1 | legacy 用户登录/登出/self | B0-3 | | B1-2 | OAuth 路径兼容 | A7 | | B1-3 | Cap scope 兼容 | A11 | | B1-4 | 用户管理 Admin CRUD 兼容 | A9 | | B1-5 | 认证源 CRUD 兼容 | A10 | | B1-6 | 密码重置流程 | B4 | | B1-7 | **旧前端登录联调** | B1-1~B1-6 | **验收**:旧前端 `/login` 可登录,`OpenFlare-Token` 可访问 `/api/user/self`。 ### 阶段 2:核心链路(2–3 周)— ✅ 已完成 | 任务 ID | 模块 | API 数 | |---|---|---| | B2-1 | Option 读写 + 热加载 | 4 | | B2-2 | Origin CRUD | 5 | | B2-3 | ProxyRoute CRUD | 5 | | B2-4 | ConfigVersion 全链路 | 8 | | B2-5 | Node 管理 | 10 | | B2-6 | Agent API + WS | 7 | | B2-7 | ApplyLog | 2 | **验收**:创建节点 → 创建规则 → 发布配置 → Agent 拉取并回报 apply-log。 ### 阶段 3:安全与证书(2 周)— ✅ 已完成 | 任务 ID | 模块 | 状态 | |---|---|---| | B3-1 | WAF 规则组 + IP 组 + 站点绑定 | ✅ | | B3-2 | Agent WAF 同步(heartbeat + `/waf/ip-groups/sync`) | ✅ | | B3-3 | TLS 证书 + ACME(lego DNS-01)+ DNS | ✅ | | B3-4 | ManagedDomain | ✅ | | B3-5 | SSL 续期定时任务 | ✅ `tasks/ssl_renew.go` | ### 阶段 4:扩展能力(2–3 周)— ✅ 已完成(v1 单表) | 任务 ID | 模块 | 状态 | |---|---|---| | B4-1 | Pages 托管 + Agent 包下载 | ✅ | | B4-2 | Relay + Flared API + WS + 观测持久化 | ✅ | | B4-3 | Dashboard 聚合 | ✅ | | B4-4 | 可观测性单表 + Agent heartbeat 写入 | ✅ | | B4-5 | 访问日志查询/清理 | ✅ | | B4-6 | UptimeKuma 集成(API + cron) | ✅ | ### 阶段 5:运维与收尾(1 周)— 进行中 | 任务 ID | 任务 | 状态 | |---|---|---| | B5-1 | 服务自更新兼容 | ✅ | | B5-2 | GeoIP 查询 + Agent Geo 自动更新 | ✅ | | B5-3 | 数据迁移脚本与文档 | ⏳ 待实现 `support-files/migration/` | | B5-4 | `make swagger` + `make code-check` 全绿 | ⏳ | | B5-5 | 全量 API 回归(对照旧后端 120+ 端点) | ⏳ | | B5-6 | Handover 文档 | ✅ 见 `handover-openflare-backend-migration.md` | --- ## 9. 具体文件变更清单(汇总) ### 9.1 新建文件(核心) ``` Wavelet/internal/apps/openflare/ ├── legacy/ # 阶段一 /api/* Handler(约 20 个文件) ├── compat/ # 鉴权、响应、限流适配(约 5 个文件) ├── proxy_route/ # routers.go + logics.go + errs.go ├── origin/ ├── config_version/ ├── node/ ├── agent/ ├── relay/ ├── flared/ ├── waf/ ├── tls/ ├── managed_domain/ ├── pages/ ├── dashboard/ ├── observability/ ├── apply_log/ ├── option/ ├── update/ ├── uptimekuma/ ├── geoip/ ├── tasks/ # 定时/后台任务(主进程 cron,后续可迁框架) └── websocket/ Wavelet/internal/model/openflare_*.go # 业务实体 + access_log 查询 Wavelet/internal/db/migrator/goose/ # postgres/ + sqlite/;of_* 至 202606190012 Wavelet/internal/apps/openflare/legacy/ # RegisterRoutes 委派 Wavelet/internal/bootstrap/bootstrap.go # RegisterOpenFlareBackgroundTasks + tasks.Start Wavelet/support-files/migration/ # 数据迁移工具(待建) ``` ### 9.2 修改文件(仅允许范围内) | 文件 | 修改内容 | |---|---| | `internal/router/v1/custom.go` | 注册 `/api/v1/custom/openflare/*`(阶段二) | | `internal/router/root/custom.go` | WebSocket、特殊根路径 | | `internal/router/router.go` | 调用 `RegisterLegacyRoutes`(仅增加一行委派) | | `internal/bootstrap/*.go` | 注册 OpenFlare 任务与监听器 | | `go.mod` | 添加 OpenFlare pkg 依赖 | | `config.example.yaml` | OpenFlare 相关配置项 | ### 9.3 禁止修改 ``` internal/router/v1/v1.go internal/router/v1/user.go internal/router/v1/admin.go internal/apps/user/*(除公开 Logic 调用) internal/apps/oauth/*(除公开 Logic 调用) internal/model/users.go ``` --- ## 10. 验证计划 ### 10.1 自动化测试 ```bash cd Wavelet make code-check go test ./internal/apps/openflare/... -v go test ./internal/apps/openflare/compat/... -v ``` | 测试类型 | 覆盖 | |---|---| | 单元测试 | config_version 快照构建、WAF IP 解析、compat 鉴权 | | 集成测试 | legacy 登录 → CRUD 规则 → 发布 → Agent 拉取 | | 迁移测试 | SQLite 旧库 → Wavelet 新 schema 校验 | | 回归测试 | 120+ API 端点对照表逐项 curl | ### 10.2 旧前端联调清单 | 场景 | 路径 | 预期 | |---|---|---| | 登录 | `/login` | 获取 Token,跳转首页 | | 仪表盘 | `/` | 数据加载 | | 节点创建 | `/node` | Bootstrap Token 显示 | | 规则发布 | `/proxy-route` → `/config-version` | 发布成功 | | WAF | `/waf` | 规则组 CRUD | | 证书 | `/website/certificate` | ACME 申请 | | 设置 | `/setting` | Option 读写 | | 升级 | 顶栏 | WS 日志流 | ### 10.3 Agent 协议验证 ```bash # Agent 心跳 curl -X POST http://127.0.0.1:3000/api/agent/nodes/heartbeat \ -H "X-Agent-Token: " -d '{...}' # 拉取配置 curl http://127.0.0.1:3000/api/agent/config-versions/active \ -H "X-Agent-Token: " ``` --- ## 11. 风险与缓解 | 风险 | 影响 | 缓解措施 | |---|---|---| | JWT vs Session 双轨 | 旧前端鉴权失败 | compat 层统一;充分测试 | | 角色三级 vs is_admin | Root 权限丢失 | `of_role` 扩展字段 | | 70+ Option 热加载 | 配置行为不一致 | 保留 OptionMap 机制 | | 旧环境 10 分片观测数据 | 无法直接挂载单表 schema | v1 采用单表;提供 ETL 脚本(待 B5-3);新部署无影响 | | 微信登录无 Wavelet 原生 | 部分用户无法登录 | 评估废弃或独立 legacy | | 三进程部署运维复杂度 | 部署失败 | 提供 docker-compose 与 `wavelet all` 开发模式 | | WebSocket Hub 迁移 | 节点掉线 | 保持 Hub 接口不变,充分压测 | --- ## 12. API 端点完整对照表(openflare-server → Wavelet 当前实现) > **2026-06-19 更新**:阶段一 `internal/apps/openflare/legacy/` 已撤销。下表「当前路径」列反映 Wavelet 实码;路由注册见 `internal/router/v1/openflare/register_*.go`,Handler 见 `internal/apps/openflare/*/routers.go`。 ### 12.1 路径前缀对照 | 类别 | 旧路径前缀(openflare-server) | 当前路径前缀(Wavelet) | 响应格式 | |---|---|---|---| | 管理控制台 | `/api/` | `/api/v1/d/` | `{error_msg, data}` | | Agent 协议 | `/api/agent/*` | `/api/v1/agent/*` | `{success, message, data}` | | Relay 协议 | `/api/relay/*` | `/api/v1/relay/*` | 同上 | | Tunnel 协议 | `/api/flared/*` | `/api/v1/tunnel/*` | 同上(`flared` 更名为 `tunnel`) | | 用户/OAuth/Cap | `/api/user/*`、`/api/oauth/*`、`/api/cap/*` | `/api/v1/user/*`、`/api/v1/oauth/*`、`/api/cap/*` | Wavelet 标准 | | 认证源/用户管理 | `/api/auth-sources/*`、`/api/user/*`(Admin) | `/api/v1/admin/*` | Wavelet 标准 | 列表端点通过 `apiutil.RegisterCollection` 同时注册无尾斜杠与有尾斜杠路径。 ### 12.2 平台层端点(复用 Wavelet,无旧 `/api/*` 兼容) | 方法 | 旧路径 | 当前路径 | 实现位置 | 备注 | |---|---|---|---|---| | GET | `/api/verification` | `POST /api/v1/user/send-email-code` | `apps/user` | 方法变更 | | GET | `/api/reset_password` | `—` | `apps/user` | 未映射旧路径 | | POST | `/api/user/reset` | `—` | `apps/user` | 未映射旧路径 | | POST | `/api/user/register` | `POST /api/v1/user/register` | `apps/user` | | | POST | `/api/user/login` | `POST /api/v1/user/login` | `apps/user` | | | GET | `/api/user/logout` | `POST /api/v1/user/logout` | `apps/user` | 方法变更 | | GET | `/api/user/self` | `GET /api/v1/user/profile` | `apps/user` | 路径变更 | | POST | `/api/user/self/update` | `PUT /api/v1/user/profile` | `apps/user` | 方法变更 | | POST | `/api/user/self/delete` | `—` | `apps/user` | 未实现 | | GET | `/api/user/token` | `GET /api/v1/user/access-tokens` | `apps/user` | | | GET | `/api/user/` | `GET /api/v1/admin/users` | `apps/admin/user` | | | GET | `/api/user/search` | `—` | `apps/admin/user` | 未实现 | | GET | `/api/user/:id` | `GET /api/v1/admin/users/:id` | `apps/admin/user` | | | POST | `/api/user/` | `POST /api/v1/admin/users` | `apps/admin/user` | | | POST | `/api/user/manage` | `—` | `apps/admin/user` | 未实现 | | POST | `/api/user/update` | `PUT /api/v1/admin/users/:id` | `apps/admin/user` | 方法变更 | | POST | `/api/user/:id/delete` | `DELETE /api/v1/admin/users/:id` | `apps/admin/user` | 方法变更 | | GET | `/api/oauth/:source/authorize` | `GET /api/v1/oauth/:source/authorize` | `apps/oauth` | | | GET | `/api/oauth/:source/callback` | `GET /api/v1/oauth/:source/callback` | `apps/oauth` | | | POST | `/api/oauth/link-existing` | `POST /api/v1/oauth/link-existing` | `apps/oauth` | | | GET | `/api/oauth/external-accounts` | `GET /api/v1/oauth/external-accounts` | `apps/oauth` | | | POST | `/api/oauth/external-accounts/:id/delete` | `DELETE /api/v1/oauth/external-accounts/:id` | `apps/oauth` | 方法变更 | | POST | `/api/cap/:scope/challenge` | `POST /api/cap/challenge` | `apps/cap` | scope 改 body | | POST | `/api/cap/:scope/redeem` | `POST /api/cap/redeem` | `apps/cap` | scope 改 body | | GET | `/api/auth-sources/` | `GET /api/v1/admin/auth-sources` | `apps/admin/auth_source` | | | POST | `/api/auth-sources/` | `POST /api/v1/admin/auth-sources` | `apps/admin/auth_source` | | | POST | `/api/auth-sources/:id/update` | `PUT /api/v1/admin/auth-sources/:id` | `apps/admin/auth_source` | 方法变更 | | POST | `/api/auth-sources/:id/delete` | `DELETE /api/v1/admin/auth-sources/:id` | `apps/admin/auth_source` | 方法变更 | | POST | `/api/auth-sources/:id/toggle` | `POST /api/v1/admin/auth-sources/:id/toggle` | `apps/admin/auth_source` | | ### 12.3 管理控制台端点(`/api/v1/d/*`) | 方法 | 旧路径 | 当前路径 | 实现位置 | 备注 | |---|---|---|---|---| | GET | `/api/status` | `/api/v1/d/status` | `openflare/option/routers.go` | | | GET | `/api/notice` | `/api/v1/d/notice` | `openflare/option/routers.go` | | | GET | `/api/about` | `/api/v1/d/about` | `openflare/option/routers.go` | | | GET | `/api/option/` | `/api/v1/d/option/` | `openflare/option/routers.go` | | | POST | `/api/option/update` | `/api/v1/d/option/update` | `openflare/option/routers.go` | | | POST | `/api/option/update-batch` | `/api/v1/d/option/update-batch` | `openflare/option/routers.go` | | | POST | `/api/option/geoip/lookup` | `/api/v1/d/option/geoip/lookup` | `openflare/option/routers.go` | | | POST | `/api/option/database/cleanup` | `/api/v1/d/option/database/cleanup` | `openflare/option/routers.go` | | | GET | `/api/proxy-routes/` | `/api/v1/d/proxy-routes/` | `openflare/proxy_route/routers.go` | | | GET | `/api/proxy-routes/:id` | `/api/v1/d/proxy-routes/:id` | `openflare/proxy_route/routers.go` | | | POST | `/api/proxy-routes/` | `/api/v1/d/proxy-routes/` | `openflare/proxy_route/routers.go` | | | POST | `/api/proxy-routes/:id/update` | `/api/v1/d/proxy-routes/:id/update` | `openflare/proxy_route/routers.go` | | | POST | `/api/proxy-routes/:id/delete` | `/api/v1/d/proxy-routes/:id/delete` | `openflare/proxy_route/routers.go` | | | GET | `/api/origins/` | `/api/v1/d/origins/` | `openflare/origin/routers.go` | | | GET | `/api/origins/:id` | `/api/v1/d/origins/:id` | `openflare/origin/routers.go` | | | POST | `/api/origins/` | `/api/v1/d/origins/` | `openflare/origin/routers.go` | | | POST | `/api/origins/:id/update` | `/api/v1/d/origins/:id/update` | `openflare/origin/routers.go` | | | POST | `/api/origins/:id/delete` | `/api/v1/d/origins/:id/delete` | `openflare/origin/routers.go` | | | GET | `/api/config-versions/` | `/api/v1/d/config-versions/` | `openflare/config_version/routers.go` | | | GET | `/api/config-versions/active` | `/api/v1/d/config-versions/active` | `openflare/config_version/routers.go` | | | GET | `/api/config-versions/preview` | `/api/v1/d/config-versions/preview` | `openflare/config_version/routers.go` | | | GET | `/api/config-versions/diff` | `/api/v1/d/config-versions/diff` | `openflare/config_version/routers.go` | | | GET | `/api/config-versions/:id` | `/api/v1/d/config-versions/:id` | `openflare/config_version/routers.go` | | | POST | `/api/config-versions/publish` | `/api/v1/d/config-versions/publish` | `openflare/config_version/routers.go` | | | POST | `/api/config-versions/:id/activate` | `/api/v1/d/config-versions/:id/activate` | `openflare/config_version/routers.go` | | | POST | `/api/config-versions/cleanup` | `/api/v1/d/config-versions/cleanup` | `openflare/config_version/routers.go` | | | GET | `/api/nodes/` | `/api/v1/d/nodes/` | `openflare/node/routers.go` | | | POST | `/api/nodes/` | `/api/v1/d/nodes/` | `openflare/node/routers.go` | | | GET | `/api/nodes/bootstrap-token` | `/api/v1/d/nodes/bootstrap-token` | `openflare/node/routers.go` | | | POST | `/api/nodes/bootstrap-token/rotate` | `/api/v1/d/nodes/bootstrap-token/rotate` | `openflare/node/routers.go` | | | GET | `/api/nodes/:id/agent-release` | `/api/v1/d/nodes/:id/agent-release` | `openflare/node/routers.go` | | | POST | `/api/nodes/:id/update` | `/api/v1/d/nodes/:id/update` | `openflare/node/routers.go` | | | POST | `/api/nodes/:id/delete` | `/api/v1/d/nodes/:id/delete` | `openflare/node/routers.go` | | | POST | `/api/nodes/:id/agent-update` | `/api/v1/d/nodes/:id/agent-update` | `openflare/node/routers.go` | | | POST | `/api/nodes/:id/openresty-restart` | `/api/v1/d/nodes/:id/openresty-restart` | `openflare/node/routers.go` | | | POST | `/api/nodes/:id/force-sync` | `/api/v1/d/nodes/:id/force-sync` | `openflare/node/routers.go` | | | GET | `/api/nodes/:id/observability` | `/api/v1/d/nodes/:id/observability` | `openflare/observability/routers.go` | | | POST | `/api/nodes/:id/observability/cleanup` | `/api/v1/d/nodes/:id/observability/cleanup` | `openflare/observability/routers.go` | | | GET | `/api/waf/ip-groups` | `/api/v1/d/waf/ip-groups` | `openflare/waf/routers.go` | | | GET | `/api/waf/ip-groups/:id` | `/api/v1/d/waf/ip-groups/:id` | `openflare/waf/routers.go` | | | POST | `/api/waf/ip-groups` | `/api/v1/d/waf/ip-groups` | `openflare/waf/routers.go` | | | POST | `/api/waf/ip-groups/test` | `/api/v1/d/waf/ip-groups/test` | `openflare/waf/routers.go` | | | POST | `/api/waf/ip-groups/:id/update` | `/api/v1/d/waf/ip-groups/:id/update` | `openflare/waf/routers.go` | | | POST | `/api/waf/ip-groups/:id/delete` | `/api/v1/d/waf/ip-groups/:id/delete` | `openflare/waf/routers.go` | | | POST | `/api/waf/ip-groups/:id/sync` | `/api/v1/d/waf/ip-groups/:id/sync` | `openflare/waf/routers.go` | | | GET | `/api/waf/rule-groups` | `/api/v1/d/waf/rule-groups` | `openflare/waf/routers.go` | | | GET | `/api/waf/rule-groups/:id` | `/api/v1/d/waf/rule-groups/:id` | `openflare/waf/routers.go` | | | POST | `/api/waf/rule-groups` | `/api/v1/d/waf/rule-groups` | `openflare/waf/routers.go` | | | POST | `/api/waf/rule-groups/:id/update` | `/api/v1/d/waf/rule-groups/:id/update` | `openflare/waf/routers.go` | | | POST | `/api/waf/rule-groups/:id/delete` | `/api/v1/d/waf/rule-groups/:id/delete` | `openflare/waf/routers.go` | | | POST | `/api/waf/rule-groups/:id/sites` | `/api/v1/d/waf/rule-groups/:id/sites` | `openflare/waf/routers.go` | | | GET | `/api/waf/sites/:route_id/rule-groups` | `/api/v1/d/waf/sites/:route_id/rule-groups` | `openflare/waf/routers.go` | | | POST | `/api/waf/sites/:route_id/rule-groups` | `/api/v1/d/waf/sites/:route_id/rule-groups` | `openflare/waf/routers.go` | | | GET | `/api/managed-domains/` | `/api/v1/d/managed-domains/` | `openflare/tls/routers.go` | | | GET | `/api/managed-domains/match` | `/api/v1/d/managed-domains/match` | `openflare/tls/routers.go` | | | POST | `/api/managed-domains/` | `/api/v1/d/managed-domains/` | `openflare/tls/routers.go` | | | POST | `/api/managed-domains/:id/update` | `/api/v1/d/managed-domains/:id/update` | `openflare/tls/routers.go` | | | POST | `/api/managed-domains/:id/delete` | `/api/v1/d/managed-domains/:id/delete` | `openflare/tls/routers.go` | | | GET | `/api/tls-certificates/` | `/api/v1/d/tls-certificates/` | `openflare/tls/routers.go` | | | GET | `/api/tls-certificates/:id` | `/api/v1/d/tls-certificates/:id` | `openflare/tls/routers.go` | | | GET | `/api/tls-certificates/:id/content` | `/api/v1/d/tls-certificates/:id/content` | `openflare/tls/routers.go` | | | POST | `/api/tls-certificates/` | `/api/v1/d/tls-certificates/` | `openflare/tls/routers.go` | | | POST | `/api/tls-certificates/:id/update` | `/api/v1/d/tls-certificates/:id/update` | `openflare/tls/routers.go` | | | POST | `/api/tls-certificates/:id/update-acme` | `/api/v1/d/tls-certificates/:id/update-acme` | `openflare/tls/routers.go` | | | POST | `/api/tls-certificates/:id/convert-acme` | `/api/v1/d/tls-certificates/:id/convert-acme` | `openflare/tls/routers.go` | | | POST | `/api/tls-certificates/import-file` | `/api/v1/d/tls-certificates/import-file` | `openflare/tls/routers.go` | | | POST | `/api/tls-certificates/:id/delete` | `/api/v1/d/tls-certificates/:id/delete` | `openflare/tls/routers.go` | | | POST | `/api/tls-certificates/apply` | `/api/v1/d/tls-certificates/apply` | `openflare/tls/routers.go` | | | POST | `/api/tls-certificates/:id/renew` | `/api/v1/d/tls-certificates/:id/renew` | `openflare/tls/routers.go` | | | GET | `/api/acme-accounts/default` | `/api/v1/d/acme-accounts/default` | `openflare/tls/routers.go` | | | GET | `/api/dns-accounts/` | `/api/v1/d/dns-accounts/` | `openflare/tls/routers.go` | | | POST | `/api/dns-accounts/` | `/api/v1/d/dns-accounts/` | `openflare/tls/routers.go` | | | POST | `/api/dns-accounts/:id/update` | `/api/v1/d/dns-accounts/:id/update` | `openflare/tls/routers.go` | | | POST | `/api/dns-accounts/:id/delete` | `/api/v1/d/dns-accounts/:id/delete` | `openflare/tls/routers.go` | | | GET | `/api/pages/` | `/api/v1/d/pages/` | `openflare/pages/routers.go` | | | GET | `/api/pages/:id` | `/api/v1/d/pages/:id` | `openflare/pages/routers.go` | | | POST | `/api/pages/` | `/api/v1/d/pages/` | `openflare/pages/routers.go` | | | POST | `/api/pages/:id/update` | `/api/v1/d/pages/:id/update` | `openflare/pages/routers.go` | | | POST | `/api/pages/:id/delete` | `/api/v1/d/pages/:id/delete` | `openflare/pages/routers.go` | | | GET | `/api/pages/:id/deployments` | `/api/v1/d/pages/:id/deployments` | `openflare/pages/routers.go` | | | POST | `/api/pages/:id/deployments/upload` | `/api/v1/d/pages/:id/deployments/upload` | `openflare/pages/routers.go` | | | POST | `/api/pages/:id/deployments/:did/activate` | `/api/v1/d/pages/:id/deployments/:did/activate` | `openflare/pages/routers.go` | | | POST | `/api/pages/:id/deployments/:did/delete` | `/api/v1/d/pages/:id/deployments/:did/delete` | `openflare/pages/routers.go` | | | GET | `/api/pages/deployments/:did/files` | `/api/v1/d/pages/deployments/:did/files` | `openflare/pages/routers.go` | | | GET | `/api/dashboard/overview` | `/api/v1/d/dashboard/overview` | `openflare/dashboard/routers.go` | | | GET | `/api/apply-logs/` | `/api/v1/d/apply-logs/` | `openflare/apply_log/routers.go` | | | POST | `/api/apply-logs/cleanup` | `/api/v1/d/apply-logs/cleanup` | `openflare/apply_log/routers.go` | | | GET | `/api/access-logs/` | `/api/v1/d/access-logs/` | `openflare/observability/routers.go` | | | GET | `/api/access-logs/folds` | `/api/v1/d/access-logs/folds` | `openflare/observability/routers.go` | | | GET | `/api/access-logs/folds/ip-summary` | `/api/v1/d/access-logs/folds/ip-summary` | `openflare/observability/routers.go` | | | GET | `/api/access-logs/ip-summary` | `/api/v1/d/access-logs/ip-summary` | `openflare/observability/routers.go` | | | GET | `/api/access-logs/ip-summary/trend` | `/api/v1/d/access-logs/ip-summary/trend` | `openflare/observability/routers.go` | | | POST | `/api/access-logs/cleanup` | `/api/v1/d/access-logs/cleanup` | `openflare/observability/routers.go` | | | POST | `/api/uptimekuma/sync` | `/api/v1/d/uptimekuma/sync` | `openflare/option/routers.go` | | | GET | `/api/update/latest-release` | `/api/v1/d/update/latest-release` | `openflare/update/routers.go` | | | GET | `/api/update/logs/ws` | `/api/v1/d/update/logs/ws` | `openflare/update/routers.go` | | | POST | `/api/update/manual-upload` | `/api/v1/d/update/manual-upload` | `openflare/update/routers.go` | | | POST | `/api/update/manual-upgrade` | `/api/v1/d/update/manual-upgrade` | `openflare/update/routers.go` | | | POST | `/api/update/upgrade` | `/api/v1/d/update/upgrade` | `openflare/update/routers.go` | | ### 12.4 节点协议端点(`/api/v1/agent|relay|tunnel/*`) | 方法 | 旧路径 | 当前路径 | 实现位置 | 备注 | |---|---|---|---|---| | POST | `/api/agent/nodes/register` | `/api/v1/agent/nodes/register` | `openflare/agent/routers.go` | | | GET | `/api/agent/ws` | `/api/v1/agent/ws` | `openflare/agent/routers.go` | | | POST | `/api/agent/nodes/heartbeat` | `/api/v1/agent/nodes/heartbeat` | `openflare/agent/routers.go` | compat 信封 | | GET | `/api/agent/config-versions/active` | `/api/v1/agent/config-versions/active` | `openflare/agent/routers.go` | | | GET | `/api/agent/pages/deployments/:id/package` | `/api/v1/agent/pages/deployments/:deployment_id/package` | `openflare/agent/routers.go` | 参数名变更 | | POST | `/api/agent/waf/ip-groups/sync` | `/api/v1/agent/waf/ip-groups/sync` | `openflare/agent/routers.go` | | | POST | `/api/agent/apply-logs` | `/api/v1/agent/apply-logs` | `openflare/agent/routers.go` | | | POST | `/api/relay/heartbeat` | `/api/v1/relay/heartbeat` | `openflare/relay/routers.go` | compat 信封 | | GET | `/api/relay/ws` | `/api/v1/relay/ws` | `openflare/relay/routers.go` | | | POST | `/api/flared/heartbeat` | `/api/v1/tunnel/heartbeat` | `openflare/flared/routers.go` | 路径更名 tunnel | | GET | `/api/flared/config/active` | `/api/v1/tunnel/config/active` | `openflare/flared/routers.go` | 路径更名 tunnel | | POST | `/api/flared/apply-log` | `/api/v1/tunnel/apply-log` | `openflare/flared/routers.go` | 路径更名 tunnel | | GET | `/api/flared/ws` | `/api/v1/tunnel/ws` | `openflare/flared/routers.go` | 路径更名 tunnel | --- ## 13. 里程碑与交付物 | 里程碑 | 时间 | 交付物 | |---|---|---| | M1 基建就绪 | 第 2 周 | 骨架代码 + compat 层 + 设计文档 | | M2 认证联调 | 第 3 周 | 旧前端可登录使用 | | M3 核心链路 | 第 6 周 | 节点+规则+发布+Agent 闭环 | | M4 安全证书 | 第 8 周 | WAF+TLS 全功能 | | M5 全量功能 | 第 11 周 | 120+ API 全通过 | | M6 生产就绪 | 第 12 周 | 迁移脚本 + 部署文档 + Handover | ---