This commit is contained in:
ryan
2026-06-18 15:42:06 +08:00
parent 99738bbc17
commit 3366edb3a1
3 changed files with 1555 additions and 0 deletions
@@ -0,0 +1,804 @@
# OpenFlare → Wavelet 后端迁移计划
> **文档类型**:实现计划(Implementation Plan)
> **创建日期**:2026-06-18
> **状态**:规划中
> **前置阅读**:[`Wavelet/AGENTS.md`](../../Wavelet/AGENTS.md)、[`docs/guideline/Constraints.md`](../guideline/Constraints.md)、[`docs/design/architecture.md`](../design/architecture.md)
---
## 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/*` 兼容注册 | 阶段二新前端路径改造(见前端迁移计划) |
| Cron/异步任务迁移至 Asynq + Scheduler | 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/ # 可观测性 + 分片
│ │ ├── 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/ # 注册 OpenFlare 任务/监听器
```
### 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 平台项 | 业务配置语义不同,避免强行合并 |
| 定时任务 | UptimeKuma、WAF IP 同步、SSL 续期、DB 清理 → Asynq Periodic Task | 符合 Wavelet 多进程模型 |
| 数据库迁移 | Wavelet goose SQL(postgres + sqlite 双份);提供 SQLite→PG 一次性迁移脚本 | 与框架迁移机制一致 |
| 可观测分片 | 保留 10 分片策略;评估 ClickHouse 或继续 PG/SQLite 分片 | 访问量大时可用 Wavelet ClickHouse |
| 进程部署 | 生产必须 `api` + `worker` + `scheduler` 三进程 | Wavelet 架构要求 |
| 前端嵌入 | 阶段一继续托管 `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→Asynq、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` | 同上 + Asynq 任务 |
| 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/observability/cleanup.go` |
**分片表迁移**:保留 10 分片(`_00`~`_09`),迁移至 goose SQL;评估后续接入 ClickHouse。
### 6.9 运维集成
| # | 功能 | 旧路径 | 目标 Logic | 任务类型 |
|---|---|---|---|---|
| C72 | UptimeKuma 同步 | `POST /api/uptimekuma/sync` | `openflare/uptimekuma/logics.go` | Asynq periodic |
| C73 | SSL 自动续期 | Cron 每日 | `openflare/tls/renew_task.go` | Asynq periodic |
| C74 | WAF IP 订阅同步 | Cron 5min | `openflare/waf/sync_task.go` | Asynq periodic |
| C75 | 可观测数据自动清理 | Cron | `openflare/observability/cleanup_task.go` | Asynq periodic |
---
## 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_XX` | P3 | `openflare_metric_snapshot.go` |
| `node_request_reports_XX` | `of_node_request_reports_XX` | P3 | `openflare_request_report.go` |
| `node_access_logs_XX` | `of_node_access_logs_XX` | P3 | `openflare_access_log.go` |
| `node_observation_openresties_XX` | `of_node_obs_openresty_XX` | P3 | `openflare_obs_openresty.go` |
| `node_observation_frps_XX` | `of_node_obs_frps_XX` | P3 | `openflare_obs_frps.go` |
| `node_observation_frpcs_XX` | `of_node_obs_frpc_XX` | P3 | `openflare_obs_frpc.go` |
### 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` | 鉴权/响应适配 | 单元测试覆盖 JWT 校验 |
| B0-4 | 注册 legacy 路由组 `RegisterLegacyRoutes(apiGroup)` | `router/legacy.go` | `/api/status` 可访问 |
| B0-5 | bootstrap 注册 OpenFlare 模块 | `bootstrap/openflare.go` | worker/scheduler 可启动 |
| 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 同步 |
| B3-3 | TLS 证书 + ACME + DNS |
| B3-4 | ManagedDomain |
| B3-5 | SSL 续期 Asynq 任务 |
### 阶段 4:扩展能力(2–3 周)
| 任务 ID | 模块 |
|---|---|
| B4-1 | Pages 托管 + Agent 包下载 |
| B4-2 | Relay + Flared API + WS |
| B4-3 | Dashboard 聚合 |
| B4-4 | 可观测性 + 分片表 |
| B4-5 | 访问日志查询/清理 |
| B4-6 | UptimeKuma 集成 |
### 阶段 5:运维与收尾(1 周)
| 任务 ID | 任务 |
|---|---|
| B5-1 | 服务自更新兼容 |
| B5-2 | GeoIP 查询 |
| B5-3 | 数据迁移脚本与文档 |
| B5-4 | `make swagger` + `make code-check` 全绿 |
| B5-5 | 全量 API 回归(对照旧后端 120+ 端点) |
| B5-6 | 编写 Handover 文档 |
---
## 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/
└── websocket/
Wavelet/internal/model/openflare_*.go # 约 20 个实体
Wavelet/internal/db/migrator/goose/ # postgres/ + sqlite/ 双份 SQL
Wavelet/internal/router/legacy.go # RegisterLegacyRoutes
Wavelet/internal/bootstrap/openflare.go # 任务/事件注册
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://localhost:8000/api/agent/nodes/heartbeat \
-H "X-Agent-Token: <token>" -d '{...}'
# 拉取配置
curl http://localhost:8000/api/agent/config-versions/active \
-H "X-Agent-Token: <token>"
```
---
## 11. 风险与缓解
| 风险 | 影响 | 缓解措施 |
|---|---|---|
| JWT vs Session 双轨 | 旧前端鉴权失败 | compat 层统一;充分测试 |
| 角色三级 vs is_admin | Root 权限丢失 | `of_role` 扩展字段 |
| 70+ Option 热加载 | 配置行为不一致 | 保留 OptionMap 机制 |
| 10 分片表迁移复杂 | 观测数据丢失 | 分阶段迁移;先 schema 后历史数据 |
| 微信登录无 Wavelet 原生 | 部分用户无法登录 | 评估废弃或独立 legacy |
| 三进程部署运维复杂度 | 部署失败 | 提供 docker-compose 与 `wavelet all` 开发模式 |
| WebSocket Hub 迁移 | 节点掉线 | 保持 Hub 接口不变,充分压测 |
---
## 12. API 端点完整对照表(旧 → 新实现位置)
> 路径阶段一保持不变;实现位置为 Wavelet 代码落点。
| 方法 | 路径 | 新实现包 | 阶段 |
|---|---|---|---|
| GET | `/api/status` | `openflare/legacy/status.go` | 1 |
| GET | `/api/notice` | `openflare/legacy/status.go` | 1 |
| GET | `/api/about` | `openflare/legacy/status.go` | 1 |
| GET | `/api/verification` | `openflare/legacy/auth_user.go` | 1 |
| GET | `/api/reset_password` | `openflare/legacy/password_reset.go` | 1 |
| POST | `/api/user/reset` | `openflare/legacy/password_reset.go` | 1 |
| POST | `/api/user/register` | `openflare/legacy/auth_user.go` | 1 |
| POST | `/api/user/login` | `openflare/legacy/auth_user.go` | 1 |
| GET | `/api/user/logout` | `openflare/legacy/auth_user.go` | 1 |
| GET | `/api/user/self` | `openflare/legacy/auth_user.go` | 1 |
| POST | `/api/user/self/update` | `openflare/legacy/auth_user.go` | 1 |
| POST | `/api/user/self/delete` | `openflare/legacy/auth_user.go` | 1 |
| GET | `/api/user/token` | `openflare/legacy/auth_user.go` | 1 |
| GET | `/api/user/` | `openflare/legacy/auth_admin.go` | 1 |
| GET | `/api/user/search` | `openflare/legacy/auth_admin.go` | 1 |
| GET | `/api/user/:id` | `openflare/legacy/auth_admin.go` | 1 |
| POST | `/api/user/` | `openflare/legacy/auth_admin.go` | 1 |
| POST | `/api/user/manage` | `openflare/legacy/auth_admin.go` | 1 |
| POST | `/api/user/update` | `openflare/legacy/auth_admin.go` | 1 |
| POST | `/api/user/:id/delete` | `openflare/legacy/auth_admin.go` | 1 |
| GET | `/api/oauth/:source/authorize` | `openflare/legacy/auth_oauth.go` | 1 |
| GET | `/api/oauth/:source/callback` | `openflare/legacy/auth_oauth.go` | 1 |
| POST | `/api/oauth/link-existing` | `openflare/legacy/auth_oauth.go` | 1 |
| GET | `/api/oauth/external-accounts` | `openflare/legacy/auth_oauth.go` | 1 |
| POST | `/api/oauth/external-accounts/:id/delete` | `openflare/legacy/auth_oauth.go` | 1 |
| POST | `/api/cap/:scope/challenge` | `openflare/legacy/cap.go` | 1 |
| POST | `/api/cap/:scope/redeem` | `openflare/legacy/cap.go` | 1 |
| GET | `/api/option/` | `openflare/option/routers.go` | 2 |
| POST | `/api/option/update` | `openflare/option/routers.go` | 2 |
| POST | `/api/option/update-batch` | `openflare/option/routers.go` | 2 |
| POST | `/api/option/geoip/lookup` | `openflare/geoip/routers.go` | 4 |
| POST | `/api/option/database/cleanup` | `openflare/observability/routers.go` | 4 |
| GET | `/api/auth-sources/` | `openflare/legacy/auth_admin.go` | 1 |
| POST | `/api/auth-sources/` | `openflare/legacy/auth_admin.go` | 1 |
| POST | `/api/auth-sources/:id/update` | `openflare/legacy/auth_admin.go` | 1 |
| POST | `/api/auth-sources/:id/delete` | `openflare/legacy/auth_admin.go` | 1 |
| POST | `/api/auth-sources/:id/toggle` | `openflare/legacy/auth_admin.go` | 1 |
| GET | `/api/proxy-routes/` | `openflare/proxy_route/routers.go` | 2 |
| GET | `/api/proxy-routes/:id` | `openflare/proxy_route/routers.go` | 2 |
| POST | `/api/proxy-routes/` | `openflare/proxy_route/routers.go` | 2 |
| POST | `/api/proxy-routes/:id/update` | `openflare/proxy_route/routers.go` | 2 |
| POST | `/api/proxy-routes/:id/delete` | `openflare/proxy_route/routers.go` | 2 |
| GET | `/api/origins/` | `openflare/origin/routers.go` | 2 |
| GET | `/api/origins/:id` | `openflare/origin/routers.go` | 2 |
| POST | `/api/origins/` | `openflare/origin/routers.go` | 2 |
| POST | `/api/origins/:id/update` | `openflare/origin/routers.go` | 2 |
| POST | `/api/origins/:id/delete` | `openflare/origin/routers.go` | 2 |
| GET | `/api/config-versions/` | `openflare/config_version/routers.go` | 2 |
| GET | `/api/config-versions/active` | `openflare/config_version/routers.go` | 2 |
| GET | `/api/config-versions/preview` | `openflare/config_version/routers.go` | 2 |
| GET | `/api/config-versions/diff` | `openflare/config_version/routers.go` | 2 |
| GET | `/api/config-versions/:id` | `openflare/config_version/routers.go` | 2 |
| POST | `/api/config-versions/publish` | `openflare/config_version/routers.go` | 2 |
| POST | `/api/config-versions/:id/activate` | `openflare/config_version/routers.go` | 2 |
| POST | `/api/config-versions/cleanup` | `openflare/config_version/routers.go` | 2 |
| GET | `/api/nodes/` | `openflare/node/routers.go` | 2 |
| POST | `/api/nodes/` | `openflare/node/routers.go` | 2 |
| GET | `/api/nodes/bootstrap-token` | `openflare/node/routers.go` | 2 |
| POST | `/api/nodes/bootstrap-token/rotate` | `openflare/node/routers.go` | 2 |
| GET | `/api/nodes/:id/agent-release` | `openflare/node/routers.go` | 2 |
| POST | `/api/nodes/:id/update` | `openflare/node/routers.go` | 2 |
| POST | `/api/nodes/:id/delete` | `openflare/node/routers.go` | 2 |
| POST | `/api/nodes/:id/agent-update` | `openflare/node/routers.go` | 2 |
| POST | `/api/nodes/:id/openresty-restart` | `openflare/node/routers.go` | 2 |
| POST | `/api/nodes/:id/force-sync` | `openflare/node/routers.go` | 2 |
| GET | `/api/nodes/:id/observability` | `openflare/observability/routers.go` | 4 |
| POST | `/api/nodes/:id/observability/cleanup` | `openflare/observability/routers.go` | 4 |
| POST | `/api/agent/nodes/register` | `openflare/agent/routers.go` | 2 |
| GET | `/api/agent/ws` | `openflare/websocket/agent.go` | 2 |
| POST | `/api/agent/nodes/heartbeat` | `openflare/agent/routers.go` | 2 |
| GET | `/api/agent/config-versions/active` | `openflare/agent/routers.go` | 2 |
| GET | `/api/agent/pages/deployments/:id/package` | `openflare/pages/agent.go` | 4 |
| POST | `/api/agent/waf/ip-groups/sync` | `openflare/waf/agent.go` | 3 |
| POST | `/api/agent/apply-logs` | `openflare/apply_log/routers.go` | 2 |
| POST | `/api/relay/heartbeat` | `openflare/relay/routers.go` | 4 |
| GET | `/api/relay/ws` | `openflare/websocket/relay.go` | 4 |
| POST | `/api/flared/heartbeat` | `openflare/flared/routers.go` | 4 |
| GET | `/api/flared/config/active` | `openflare/flared/routers.go` | 4 |
| POST | `/api/flared/apply-log` | `openflare/flared/routers.go` | 4 |
| GET | `/api/flared/ws` | `openflare/websocket/flared.go` | 4 |
| GET | `/api/waf/ip-groups` | `openflare/waf/routers.go` | 3 |
| GET | `/api/waf/ip-groups/:id` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/ip-groups` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/ip-groups/test` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/ip-groups/:id/update` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/ip-groups/:id/delete` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/ip-groups/:id/sync` | `openflare/waf/routers.go` | 3 |
| GET | `/api/waf/rule-groups` | `openflare/waf/routers.go` | 3 |
| GET | `/api/waf/rule-groups/:id` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/rule-groups` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/rule-groups/:id/update` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/rule-groups/:id/delete` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/rule-groups/:id/sites` | `openflare/waf/routers.go` | 3 |
| GET | `/api/waf/sites/:route_id/rule-groups` | `openflare/waf/routers.go` | 3 |
| POST | `/api/waf/sites/:route_id/rule-groups` | `openflare/waf/routers.go` | 3 |
| GET | `/api/managed-domains/` | `openflare/managed_domain/routers.go` | 3 |
| GET | `/api/managed-domains/match` | `openflare/managed_domain/routers.go` | 3 |
| POST | `/api/managed-domains/` | `openflare/managed_domain/routers.go` | 3 |
| POST | `/api/managed-domains/:id/update` | `openflare/managed_domain/routers.go` | 3 |
| POST | `/api/managed-domains/:id/delete` | `openflare/managed_domain/routers.go` | 3 |
| GET | `/api/tls-certificates/` | `openflare/tls/routers.go` | 3 |
| GET | `/api/tls-certificates/:id` | `openflare/tls/routers.go` | 3 |
| GET | `/api/tls-certificates/:id/content` | `openflare/tls/routers.go` | 3 |
| POST | `/api/tls-certificates/` | `openflare/tls/routers.go` | 3 |
| POST | `/api/tls-certificates/:id/update` | `openflare/tls/routers.go` | 3 |
| POST | `/api/tls-certificates/:id/update-acme` | `openflare/tls/routers.go` | 3 |
| POST | `/api/tls-certificates/:id/convert-acme` | `openflare/tls/routers.go` | 3 |
| POST | `/api/tls-certificates/import-file` | `openflare/tls/routers.go` | 3 |
| POST | `/api/tls-certificates/:id/delete` | `openflare/tls/routers.go` | 3 |
| POST | `/api/tls-certificates/apply` | `openflare/tls/routers.go` | 3 |
| POST | `/api/tls-certificates/:id/renew` | `openflare/tls/routers.go` | 3 |
| GET | `/api/acme-accounts/default` | `openflare/tls/routers.go` | 3 |
| GET | `/api/dns-accounts/` | `openflare/tls/routers.go` | 3 |
| POST | `/api/dns-accounts/` | `openflare/tls/routers.go` | 3 |
| POST | `/api/dns-accounts/:id/update` | `openflare/tls/routers.go` | 3 |
| POST | `/api/dns-accounts/:id/delete` | `openflare/tls/routers.go` | 3 |
| GET | `/api/pages/` | `openflare/pages/routers.go` | 4 |
| GET | `/api/pages/:id` | `openflare/pages/routers.go` | 4 |
| POST | `/api/pages/` | `openflare/pages/routers.go` | 4 |
| POST | `/api/pages/:id/update` | `openflare/pages/routers.go` | 4 |
| POST | `/api/pages/:id/delete` | `openflare/pages/routers.go` | 4 |
| GET | `/api/pages/:id/deployments` | `openflare/pages/routers.go` | 4 |
| POST | `/api/pages/:id/deployments/upload` | `openflare/pages/routers.go` | 4 |
| POST | `/api/pages/:id/deployments/:did/activate` | `openflare/pages/routers.go` | 4 |
| POST | `/api/pages/:id/deployments/:did/delete` | `openflare/pages/routers.go` | 4 |
| GET | `/api/pages/deployments/:did/files` | `openflare/pages/routers.go` | 4 |
| GET | `/api/dashboard/overview` | `openflare/dashboard/routers.go` | 4 |
| GET | `/api/apply-logs/` | `openflare/apply_log/routers.go` | 2 |
| POST | `/api/apply-logs/cleanup` | `openflare/apply_log/routers.go` | 2 |
| GET | `/api/access-logs/` | `openflare/observability/routers.go` | 4 |
| GET | `/api/access-logs/folds` | `openflare/observability/routers.go` | 4 |
| GET | `/api/access-logs/folds/ip-summary` | `openflare/observability/routers.go` | 4 |
| GET | `/api/access-logs/ip-summary` | `openflare/observability/routers.go` | 4 |
| GET | `/api/access-logs/ip-summary/trend` | `openflare/observability/routers.go` | 4 |
| POST | `/api/access-logs/cleanup` | `openflare/observability/routers.go` | 4 |
| POST | `/api/uptimekuma/sync` | `openflare/uptimekuma/routers.go` | 4 |
| GET | `/api/update/latest-release` | `openflare/legacy/update.go` | 5 |
| GET | `/api/update/logs/ws` | `openflare/websocket/update.go` | 5 |
| POST | `/api/update/manual-upload` | `openflare/legacy/update.go` | 5 |
| POST | `/api/update/manual-upgrade` | `openflare/legacy/update.go` | 5 |
| POST | `/api/update/upgrade` | `openflare/legacy/update.go` | 5 |
---
## 13. 里程碑与交付物
| 里程碑 | 时间 | 交付物 |
|---|---|---|
| M1 基建就绪 | 第 2 周 | 骨架代码 + compat 层 + 设计文档 |
| M2 认证联调 | 第 3 周 | 旧前端可登录使用 |
| M3 核心链路 | 第 6 周 | 节点+规则+发布+Agent 闭环 |
| M4 安全证书 | 第 8 周 | WAF+TLS 全功能 |
| M5 全量功能 | 第 11 周 | 120+ API 全通过 |
| M6 生产就绪 | 第 12 周 | 迁移脚本 + 部署文档 + Handover |
---
## 14. 参考文档
- [`Wavelet/AGENTS.md`](../../Wavelet/AGENTS.md)
- [`docs/design/architecture.md`](../design/architecture.md)
- [`docs/design/agent-design.md`](../design/agent-design.md)
- [`docs/guideline/Constraints.md`](../guideline/Constraints.md)
- 旧后端源码:`openflare-server/internal/`
- 子智能体分析报告:本计划编制依据(2026-06-18)
@@ -0,0 +1,744 @@
# OpenFlare → Wavelet 前端迁移计划
> **文档类型**:实现计划(Implementation Plan)
> **创建日期**:2026-06-18
> **状态**:规划中
> **前置阅读**:[`Wavelet/AGENTS.md`](../../Wavelet/AGENTS.md)、[`docs/plan/20260618-openflare-wavelet-backend-migration.md`](./20260618-openflare-wavelet-backend-migration.md)
> **依赖**:后端阶段一(旧路径 `/api/*` 兼容)完成后启动;阶段二可与后端阶段五并行
---
## 1. 目标与背景
### 1.1 需求背景
OpenFlare 管理控制台当前位于 `openflare-server/web/`(Next.js 15 + 静态导出嵌入 Go)。Wavelet 提供现代化全栈前端脚手架 `Wavelet/frontend/`(Next.js 16 + shadcn/ui + 完整 Admin 基建)。
迁移目标:
1. 将 OpenFlare **全部业务 UI** 按 Wavelet 设计风格重写,统一视觉与交互。
2. **复用 Wavelet 内置页面与组件**(布局、认证、设置、用户管理、Admin 基建),不重写平台能力。
3. 重叠职能(登录、用户、OAuth、Access Token、系统设置)**直接对接 Wavelet `/api/v1/*` API**,不再使用 `OpenFlare-Token`。
4. OpenFlare 业务 API 阶段一切至 `/api/*`(后端兼容层);阶段二逐步规范化。
### 1.2 开发范围
| 范围内 | 范围外 |
|---|---|
| `openflare-server/web` 全部页面/功能迁移 | 文档站 `docs/` VitePress 改造 |
| Wavelet 布局/导航扩展 | Wavelet 框架核心页面逻辑修改 |
| OpenFlare 业务 Service 层新建 | 旧前端继续长期并存(迁移完成后废弃) |
| 静态导出 / embed 部署方案确认 | Agent/Relay/Flared 节点侧 UI |
| E2E 测试迁移 | 英文界面 |
### 1.3 迁移总原则
| 原则 | 说明 |
|---|---|
| **框架组件优先** | 使用 `Wavelet/frontend/components/ui/*`,禁止复制旧 `components/ui` 11 个自建组件 |
| **服务层规范** | 所有 API 调用经 `lib/services/`,继承 `BaseService` |
| **页面规范** | 遵循 AGENTS.md:`h1 text-2xl font-semibold tracking-tight`,单文件 ≤600 行 |
| **重叠不重写** | 登录/注册/用户管理/认证源/AccessToken 用 Wavelet 现成页面 |
| **业务新建** | OpenFlare 独有功能在 `app/(main)/openflare/` 新建 |
| **参考标杆** | 复杂页面参考 `/admin/database` 拆分模式、`/admin/demo` 组件用法 |
---
## 2. 现状与目标对照
### 2.1 技术栈对照
| 维度 | 旧前端 `openflare-server/web` | 目标 `Wavelet/frontend` |
|---|---|---|
| Next.js | 15 App Router | 16 App Router |
| React | 19 | 19 |
| CSS | Tailwind 4 | Tailwind 4 |
| UI 库 | 自建 11 组件 + HeroUI 混合 | shadcn/Radix 40+ |
| 图表 | ECharts | Recharts(必要时保留 ECharts) |
| 数据请求 | 原生 fetch | Axios + BaseService |
| 状态 | Context + Zustand + React Query | UserContext + React Query |
| 认证 | `OpenFlare-Token` localStorage | Session Cookie + AccessToken |
| API 路径 | `/api/*` | `/api/v1/*` + `/api/*`(业务) |
| 构建 | `output: 'export'` 嵌入 Go | `build:embed` 或 standalone |
| 路由详情 | `?id=` 查询参数 | 优先查询参数(保持静态兼容) |
### 2.2 目录结构对照
**旧前端(迁移源)**:
```
openflare-server/web/
├── app/(dashboard)/ # 18 个控制台路由
├── app/(public)/ # 7 个公开路由
├── features/ # 15 个业务模块(核心逻辑)
├── components/ # 布局 + 轻量 UI
└── lib/api/ # fetch 客户端
```
**目标前端(迁移目标)**:
```
Wavelet/frontend/
├── app/(auth)/ # ✅ 复用:login, register
├── app/(main)/
│ ├── home/ # 改造为 OpenFlare 仪表盘或重定向
│ ├── settings/ # ✅ 复用 + 扩展 OpenFlare 个人设置
│ ├── admin/ # ✅ 复用平台 Admin
│ └── openflare/ # 🆕 OpenFlare 业务路由根
│ ├── page.tsx # 仪表盘 /
│ ├── nodes/ # 节点
│ ├── proxy-routes/ # 代理规则
│ ├── pages/ # Pages 托管
│ ├── websites/ # 网站/证书
│ ├── waf/ # WAF
│ ├── origins/ # 源站
│ ├── config-versions/ # 配置发布
│ ├── access-logs/ # 访问日志
│ ├── performance/ # 性能调优
│ ├── apply-logs/ # 应用日志
│ └── components/ # 跨页面 OpenFlare 子组件
├── components/ # ✅ 复用框架组件
├── lib/services/
│ ├── index.ts # 注册 openflare 服务
│ └── openflare/ # 🆕 业务 API 服务
│ ├── types.ts
│ ├── proxy-route.service.ts
│ ├── node.service.ts
│ └── ...
└── lib/navigation/ # 🆕 侧栏导航配置
```
---
## 3. 功能板块迁移总览
### 3.1 三类处理方式
| 类别 | 数量 | 策略 |
|---|---|---|
| **F-A 直接复用 Wavelet** | 10 板块 | 不改页面,仅改导航/文案/配置 |
| **F-B 扩展 Wavelet 页面** | 5 板块 | 在现有页面增加 OpenFlare 配置块 |
| **F-C 新建 OpenFlare 页面** | 12 板块 | 按 Wavelet 风格完整重写 |
```mermaid
flowchart LR
subgraph Reuse["F-A 复用"]
Login["/login"]
Settings["/settings/*"]
AdminUsers["/admin/users"]
end
subgraph Extend["F-B 扩展"]
AdminSystem["/admin/system"]
AdminSettings["/admin/settings"]
AdminUpdater["升级能力"]
end
subgraph New["F-C 新建"]
Dashboard["/openflare"]
Nodes["/openflare/nodes"]
Routes["/openflare/proxy-routes"]
WAF["/openflare/waf"]
end
Reuse --> WaveletCore["Wavelet /api/v1"]
Extend --> MixedAPI["/api/v1 + /api"]
New --> OpenFlareAPI["/api/* 业务 API"]
```
---
## 4. F-A:直接复用 Wavelet(禁止重写)
| # | 旧路径/模块 | Wavelet 目标 | 迁移动作 | API 切换 |
|---|---|---|---|---|
| FA-1 | `/login` | `app/(auth)/login` | 删除旧登录页;导航指向 Wavelet | `/api/v1/user/login` |
| FA-2 | `/reset`, `/user/reset` | `app/(auth)/` 密码重置流 | 复用 Wavelet 重置流程 | `/api/v1/user/*` |
| FA-3 | 注册(若开放) | `app/(auth)/register` | 复用 | `/api/v1/user/register` |
| FA-4 | Cap PoW | `components/auth/cap-widget.tsx` | 直接引用 | `/api/cap/*` 或 `/api/v1/cap/*` |
| FA-5 | OAuth 回调 | `app/(auth)/` + OAuth 组件 | 回调 URL 改 Wavelet 格式 | `/api/v1/oauth/*` |
| FA-6 | `/user` 用户管理 | `app/(main)/admin/users` | **修复**:纳入侧栏导航 | `/api/v1/admin/users` |
| FA-7 | Access Token | `app/(main)/settings/access-token` | 复用 | `/api/v1/user/access-tokens` |
| FA-8 | 个人资料 | `app/(main)/settings/profile` | 复用 | `/api/v1/user/self` + `profile` |
| FA-9 | 修改密码 | `app/(main)/settings/security` | 复用 | `/api/v1/user/change-password` |
| FA-10 | 外观主题 | `app/(main)/settings/appearance` | 复用 Wavelet 40+ 主题 | 本地 |
**需删除的旧代码**:
```
openflare-server/web/features/auth/ # 整体废弃(保留类型参考)
openflare-server/web/app/(public)/login/
openflare-server/web/app/(public)/reset/
openflare-server/web/app/(dashboard)/user/ # 改用 /admin/users
openflare-server/web/lib/api/auth-token.ts # 改用 Session
```
---
## 5. F-B:扩展 Wavelet 现有页面
| # | 旧功能 | 旧位置 | Wavelet 扩展位置 | 扩展内容 |
|---|---|---|---|---|
| FB-1 | 运维设置 | `/setting` 运维 Tab | `app/(main)/admin/settings` 或 `admin/system` | Agent 心跳阈值、GeoIP Provider、OpenResty 默认参数 |
| FB-2 | 系统设置 | `/setting` 系统 Tab | `admin/system` + `new-setting` skill | 登录开关、SMTP(若未覆盖)、公告 |
| FB-3 | 认证源 CRUD | `/setting` 系统 Tab | `admin/` 已有 `auth-source` 组件 | 确认 API 对齐;移除旧 modal |
| FB-4 | 数据库清理 | `/setting` 数据库 Tab | `admin/database` 或 `admin/settings` | 观测数据保留天数、手动清理按钮 |
| FB-5 | 服务升级 | 顶栏 `version-upgrade-modal` | 复用 `admin/updater` 能力 | 增加 OpenFlare 发版渠道 stable/preview |
**实现路径**:
| 文件 | 职责 |
|---|---|
| `app/(main)/admin/settings/components/openflare-ops.tsx` | 运维参数表单 |
| `app/(main)/admin/system/` 新增 KV | OpenFlare Option 映射为 SystemConfig(可选) |
| `lib/services/openflare/option.service.ts` | 读写 `/api/option/*` |
| `components/layout/app-sidebar.tsx` | 增加 OpenFlare 设置入口 |
---
## 6. F-C:新建 OpenFlare 业务页面(完整重写)
### 6.1 页面路由映射表
| # | 旧路由 | 新路由 | 页面文件 | 优先级 | 复杂度 |
|---|---|---|---|---|---|
| FC-1 | `/` | `/openflare` 或 `/home` 改造 | `app/(main)/openflare/page.tsx` | P0 | 高 |
| FC-2 | `/node` | `/openflare/nodes` | `openflare/nodes/page.tsx` | P0 | 很高 |
| FC-3 | `/node/detail?id=` | `/openflare/nodes/detail` | `openflare/nodes/detail/page.tsx` | P0 | 很高 |
| FC-4 | `/proxy-route` | `/openflare/proxy-routes` | `openflare/proxy-routes/page.tsx` | P0 | 很高 |
| FC-5 | `/proxy-route/detail?id=&section=` | `/openflare/proxy-routes/detail` | `openflare/proxy-routes/detail/page.tsx` | P0 | 极高 |
| FC-6 | `/config-version` | `/openflare/config-versions` | `openflare/config-versions/page.tsx` | P0 | 高 |
| FC-7 | `/waf` | `/openflare/waf` | `openflare/waf/page.tsx` | P1 | 很高 |
| FC-8 | `/waf/ip-groups` | `/openflare/waf/ip-groups` | `openflare/waf/ip-groups/page.tsx` | P1 | 高 |
| FC-9 | `/website` | `/openflare/websites` | `openflare/websites/page.tsx` | P1 | 高 |
| FC-10 | `/website/detail?id=` | `/openflare/websites/detail` | `openflare/websites/detail/page.tsx` | P1 | 高 |
| FC-11 | `/website/certificate` | `/openflare/websites/certificates` | `openflare/websites/certificates/page.tsx` | P1 | 很高 |
| FC-12 | `/website/dns-account` | `/openflare/websites/dns-accounts` | `openflare/websites/dns-accounts/page.tsx` | P1 | 中 |
| FC-13 | `/pages` | `/openflare/pages` | `openflare/pages/page.tsx` | P2 | 中 |
| FC-14 | `/pages/detail?id=` | `/openflare/pages/detail` | `openflare/pages/detail/page.tsx` | P2 | 中 |
| FC-15 | `/origin` | `/openflare/origins` | `openflare/origins/page.tsx` | P2 | 低 |
| FC-16 | `/origin/detail?id=` | `/openflare/origins/detail` | `openflare/origins/detail/page.tsx` | P2 | 低 |
| FC-17 | `/access-log` | `/openflare/access-logs` | `openflare/access-logs/page.tsx` | P2 | 高 |
| FC-18 | `/apply-log?node_id=` | `/openflare/apply-logs` | `openflare/apply-logs/page.tsx` | P2 | 低 |
| FC-19 | `/performance` | `/openflare/performance` | `openflare/performance/page.tsx` | P2 | 中 |
| FC-20 | `/about` | `/docs` 或 `/openflare/about` | 复用 docs 或新建 | P3 | 低 |
### 6.2 各板块详细迁移说明
#### FC-1 总览仪表盘
| 项 | 旧实现 | 新实现 |
|---|---|---|
| 源文件 | `features/dashboard/components/dashboard-page.tsx` | `openflare/page.tsx` + `components/dashboard-overview.tsx` |
| 服务 | `features/dashboard/api.ts` | `lib/services/openflare/dashboard.service.ts` |
| API | `GET /api/dashboard/overview` | 同左(阶段一) |
| 图表 | ECharts `TrendChart`, `RankChart` | Recharts 或保留 ECharts(世界地图建议保留 ECharts/geoJSON) |
| 组件 | `world-stage` 世界地图 | `openflare/components/world-map.tsx` |
| 关键指标 | 流量/容量/节点健康/24h 趋势 | 完整保留 |
**子组件拆分**:
```
openflare/components/dashboard/
├── overview-stats.tsx # 顶部指标卡片(Stat Card 模式)
├── traffic-trend-chart.tsx # 流量趋势
├── capacity-trend-chart.tsx # 容量趋势
├── node-health-table.tsx # 节点健康列表
├── geo-distribution.tsx # 国家分布
└── world-map.tsx # 世界地图
```
#### FC-2/FC-3 节点管理
| 项 | 说明 |
|---|---|
| 源文件 | `features/nodes/components/nodes-page.tsx`(列表)、`node-detail-page.tsx`(1800+ 行)、`relay-detail-page.tsx`、`tunnel-detail-page.tsx` |
| 新结构 | 列表页 ≤400 行;详情按 `node_type` 拆三个子组件 |
| API 服务 | `node.service.ts` |
| 关键功能 | 三类型筛选、Bootstrap Token、Agent 升级、强制同步、OpenResty 重启、安装命令、5s 轮询 |
| 对话框 | 使用 `Sheet`/`Dialog` 替代旧 `app-modal` |
**详情页拆分**:
```
openflare/nodes/detail/
├── page.tsx
└── components/
├── edge-node-detail.tsx # edge_node
├── relay-node-detail.tsx # tunnel_relay
├── tunnel-node-detail.tsx # tunnel_client
├── node-observability.tsx # 可观测性 Tab
├── node-actions.tsx # 操作按钮组
└── install-command.tsx # 安装命令生成
```
**API 映射**:
| 功能 | API |
|---|---|
| 列表 | `GET /api/nodes/` |
| 创建/更新/删除 | `POST /api/nodes/` 等 |
| Bootstrap | `GET/POST /api/nodes/bootstrap-token/*` |
| Agent 升级 | `POST /api/nodes/:id/agent-update` |
| 可观测 | `GET /api/nodes/:id/observability` |
| 应用日志 | `GET /api/apply-logs/?node_id=` |
#### FC-4/FC-5 代理规则
| 项 | 说明 |
|---|---|
| 源文件 | `proxy-routes-page.tsx`、`proxy-route-config-page.tsx`(1400+ 行) |
| 新结构 | 列表 + 详情 6 Section Tab |
| Section | `domains`、`limits`、`proxy`、`cache`、`waf`、`auth` |
**详情 Tab 组件**:
```
openflare/proxy-routes/detail/components/
├── domain-section.tsx
├── limits-section.tsx
├── proxy-section.tsx
├── cache-section.tsx
├── waf-section.tsx
├── auth-section.tsx
├── publish-diff-drawer.tsx # 发布前 diff
└── route-header.tsx
```
**API 映射**:
| 功能 | API |
|---|---|
| CRUD | `/api/proxy-routes/*` |
| 关联数据 | `/api/managed-domains/`、`/api/pages/`、`/api/nodes/`、`/api/tls-certificates/` |
| WAF 绑定 | `/api/waf/sites/:routeId/rule-groups` |
| 发布 | `GET /api/config-versions/diff`、`POST /api/config-versions/publish` |
#### FC-6 配置发布
| 项 | 说明 |
|---|---|
| 源文件 | `features/config-versions/components/config-versions-page.tsx` |
| 功能 | 版本列表、快照查看、预览、diff、发布、激活、清理 |
| UI 模式 | `Table` + `Sheet` 预览 + `Dialog` 确认发布 |
#### FC-7/FC-8 WAF
| 项 | 说明 |
|---|---|
| 源文件 | `waf-page.tsx`(规则组)、`ip-groups-page.tsx` |
| 新路由 | `/openflare/waf` + `/openflare/waf/ip-groups` |
| 复杂 UI | 规则条目 Modal、PoW Tab、站点批量绑定 Drawer |
| 参考 | `/admin/demo` 的 Form/Table 模式 |
**子组件**:
```
openflare/waf/components/
├── rule-group-table.tsx
├── rule-group-form.tsx
├── rule-entry-dialog.tsx
├── rule-list-section.tsx
├── pow-config-panel.tsx
├── site-apply-sheet.tsx
├── ip-group-table.tsx
├── ip-group-form.tsx
└── ip-group-sync-button.tsx
```
#### FC-9~FC-12 网站与证书
| 页面 | 源文件 | 关键 Modal |
|---|---|---|
| 托管域名列表 | `websites-page.tsx` | 创建/编辑 Dialog |
| 域名详情 | `website-detail-page.tsx` | 证书关联、WAF 绑定 |
| 证书管理 | `certificate-page.tsx` | ACME 申请、续期、导入、转换 |
| DNS 账号 | `dns-account-page.tsx` | 多厂商表单 |
**API**:`/api/managed-domains/*`、`/api/tls-certificates/*`、`/api/dns-accounts/*`、`/api/acme-accounts/default`
#### FC-13/FC-14 Pages 静态托管
| 功能 | 说明 |
|---|---|
| 项目 CRUD | Table + Dialog |
| 部署上传 | 使用 Wavelet 上传组件 + XHR 进度 |
| 部署管理 | 版本列表、激活、删除 |
| API | `/api/pages/*` |
#### FC-15/FC-16 源站
| 功能 | 说明 |
|---|---|
| 简单 CRUD | 列表 + 详情,低复杂度 |
| API | `/api/origins/*` |
#### FC-17 访问日志
| Tab | API |
|---|---|
| 明细 | `GET /api/access-logs/` |
| 时间折叠 | `GET /api/access-logs/folds` |
| IP 汇总 | `GET /api/access-logs/ip-summary` |
| IP 趋势 | `GET /api/access-logs/ip-summary/trend` |
| 清理 | `POST /api/access-logs/cleanup` |
**UI**:`DataTable` + 筛选器 + 趋势图(Recharts)
#### FC-18 应用日志
| 功能 | 说明 |
|---|---|
| 按节点筛选 | `?node_id=` 查询参数 |
| 入口 | 节点详情页跳转 |
| API | `GET /api/apply-logs/` |
#### FC-19 性能调优
| 功能 | 说明 |
|---|---|
| 源文件 | `features/performance/` + `settings-page` 运维重叠部分 |
| 内容 | OpenResty 全局参数表单 |
| 预览 | `GET /api/config-versions/preview` |
| API | `GET/POST /api/option/*` |
---
## 7. Service 层迁移清单
### 7.1 新建服务文件
| 服务文件 | basePath | 对应旧 `features/*/api.ts` |
|---|---|---|
| `dashboard.service.ts` | `/api/dashboard` | `features/dashboard/api.ts` |
| `node.service.ts` | `/api/nodes` | `features/nodes/api.ts` |
| `proxy-route.service.ts` | `/api/proxy-routes` | `features/proxy-routes/api.ts` |
| `config-version.service.ts` | `/api/config-versions` | `features/config-versions/api.ts` |
| `waf.service.ts` | `/api/waf` | `features/waf/api.ts` |
| `website.service.ts` | `/api/managed-domains` | `features/websites/api.ts` |
| `tls-certificate.service.ts` | `/api/tls-certificates` | `features/tls-certificates/api.ts` |
| `dns-account.service.ts` | `/api/dns-accounts` | `features/dns-accounts/api.ts` |
| `acme-account.service.ts` | `/api/acme-accounts` | `features/acme-accounts/api.ts` |
| `pages.service.ts` | `/api/pages` | `features/pages/api.ts` |
| `origin.service.ts` | `/api/origins` | `features/origins/api.ts` |
| `access-log.service.ts` | `/api/access-logs` | `features/access-logs/api.ts` |
| `apply-log.service.ts` | `/api/apply-logs` | `features/apply-logs/api.ts` |
| `option.service.ts` | `/api/option` | `features/settings/api.ts` |
| `update.service.ts` | `/api/update` | `features/update/api.ts` |
| `types.ts` | — | 汇总 TypeScript 类型 |
### 7.2 服务注册
```typescript
// lib/services/index.ts 新增
import { openflareDashboardService } from './openflare/dashboard.service';
// ...
const services = {
// ... 现有 Wavelet 服务
openflareDashboard: openflareDashboardService,
openflareNode: openflareNodeService,
// ...
};
```
### 7.3 API 客户端适配
| 阶段 | 认证方式 | Base URL |
|---|---|---|
| 阶段一(过渡期) | Session Cookie(Wavelet 登录)+ 业务 API 同域 | `/api` |
| 阶段二(稳定) | Session + 可选 AccessToken | `/api` + `/api/v1` |
**注意**:移除 `OpenFlare-Token` localStorage 逻辑;统一使用 Wavelet `proxy.ts` 鉴权。
---
## 8. 组件复用与替换对照
### 8.1 旧 → Wavelet 组件映射
| 旧组件 | Wavelet 替代 |
|---|---|
| `app-card` | `Card` |
| `app-modal` | `Dialog` |
| `drawer` | `Sheet` |
| `input` | `Input` |
| `textarea` | `Textarea` |
| `switch` | `Switch` |
| `status-badge` | `Badge` |
| `theme-toggle` | 内置 ThemeProvider |
| `sonner` | `sonner`(已有) |
| `empty-state` | `components/common/empty.tsx` |
| `loading-state` | `Skeleton` + `loading.tsx` |
| `error-state` | `error.tsx` |
| `resource-primitives` | `Form` + `Field` + shadcn 表单模式 |
| `trend-chart` / `rank-chart` | Recharts 或 ECharts 封装 |
### 8.2 布局改造
| 项 | 旧实现 | 新实现 |
|---|---|---|
| 侧栏 | `dashboard-sidebar.tsx` | `components/layout/app-sidebar.tsx` 扩展 |
| 顶栏 | `dashboard-topbar.tsx` | `components/layout/header.tsx` 扩展 |
| 导航配置 | `lib/constants/navigation.ts` | `lib/navigation/openflare-nav.ts` |
| 鉴权守卫 | `DashboardAuthGuard` | Wavelet `proxy.ts` + `use-auth-redirect` |
**新侧栏导航结构**:
```
OpenFlare
├── 总览 /openflare
├── 节点 /openflare/nodes
├── 代理规则 /openflare/proxy-routes
├── 配置发布 /openflare/config-versions
├── WAF /openflare/waf
├── 网站 /openflare/websites
├── Pages /openflare/pages
├── 源站 /openflare/origins
├── 访问日志 /openflare/access-logs
├── 性能调优 /openflare/performance
---
平台(Wavelet 原生)
├── 用户管理 /admin/users
├── 系统设置 /admin/settings
├── 任务调度 /admin/tasks
├── 日志分析 /admin/logs
├── ...
```
---
## 9. 分阶段实施计划
### 阶段 0:基建(1 周)
| 任务 ID | 任务 | 产出 |
|---|---|---|
| F0-1 | 创建 `lib/services/openflare/` 骨架 | types + base |
| F0-2 | 创建 `lib/navigation/openflare-nav.ts` | 导航配置 |
| F0-3 | 扩展 `app-sidebar.tsx` | OpenFlare 导航组 |
| F0-4 | 确认 embed 构建方案 | `Makefile` / `next.config.ts` |
| F0-5 | 移除旧前端入口引用准备 | 文档记录 |
### 阶段 1:认证与布局(1 周)
| 任务 ID | 任务 |
|---|---|
| F1-1 | 确认 Wavelet 登录/register 可用 |
| F1-2 | OAuth 回调路径配置 |
| F1-3 | 侧栏 + 顶栏 OpenFlare 品牌 |
| F1-4 | `/home` 重定向至 `/openflare` |
| F1-5 | 用户管理入口暴露至 `/admin/users` |
**验收**:Wavelet 登录后可看到 OpenFlare 空导航骨架。
### 阶段 2:核心链路 UI(2–3 周)
| 任务 ID | 页面 | 依赖 API |
|---|---|---|
| F2-1 | 节点列表 + 详情(edge) | 后端 B2-5 |
| F2-2 | 代理规则列表 + 详情 | 后端 B2-3 |
| F2-3 | 配置发布 | 后端 B2-4 |
| F2-4 | 应用日志 | 后端 B2-7 |
| F2-5 | relay/tunnel 详情页 | 后端 B4-2 |
**验收**:UI 完成节点→规则→发布闭环操作。
### 阶段 3:安全与流量(2 周)
| 任务 ID | 页面 |
|---|---|
| F3-1 | WAF 规则组 |
| F3-2 | WAF IP 组 |
| F3-3 | 网站/域名 |
| F3-4 | TLS 证书 + ACME |
| F3-5 | DNS 账号 |
### 阶段 4:扩展(2 周)
| 任务 ID | 页面 |
|---|---|
| F4-1 | Pages 托管 |
| F4-2 | 源站 |
| F4-3 | 访问日志 |
| F4-4 | 总览仪表盘 |
| F4-5 | 性能调优 |
### 阶段 5:设置合并与收尾(1–2 周)
| 任务 ID | 任务 |
|---|---|
| F5-1 | OpenFlare 运维/系统设置并入 Admin |
| F5-2 | 服务升级 UI 对接 `admin/updater` |
| F5-3 | 废弃 `openflare-server/web` 引用 |
| F5-4 | Playwright E2E 核心路径 |
| F5-5 | 视觉走查与响应式适配 |
| F5-6 | Handover 文档 |
---
## 10. 旧前端源文件 → 新文件完整映射
| 旧文件 | 新文件 | 动作 |
|---|---|---|
| `features/dashboard/components/dashboard-page.tsx` | `openflare/page.tsx` | 重写 |
| `features/nodes/components/nodes-page.tsx` | `openflare/nodes/page.tsx` | 重写 |
| `features/nodes/components/node-detail-page.tsx` | `openflare/nodes/detail/components/edge-node-detail.tsx` | 拆分重写 |
| `features/nodes/components/relay-detail-page.tsx` | `openflare/nodes/detail/components/relay-node-detail.tsx` | 拆分重写 |
| `features/nodes/components/tunnel-detail-page.tsx` | `openflare/nodes/detail/components/tunnel-node-detail.tsx` | 拆分重写 |
| `features/nodes/components/node-editor-modal.tsx` | `openflare/nodes/components/node-form-dialog.tsx` | 重写 |
| `features/proxy-routes/components/proxy-routes-page.tsx` | `openflare/proxy-routes/page.tsx` | 重写 |
| `features/proxy-routes/components/proxy-route-config-page.tsx` | `openflare/proxy-routes/detail/page.tsx` + 6 section | 拆分重写 |
| `features/proxy-routes/components/proxy-route-create-drawer.tsx` | `openflare/proxy-routes/components/create-sheet.tsx` | 重写 |
| `features/config-versions/components/config-versions-page.tsx` | `openflare/config-versions/page.tsx` | 重写 |
| `features/waf/components/waf-page.tsx` | `openflare/waf/page.tsx` | 重写 |
| `features/waf/components/ip-groups-page.tsx` | `openflare/waf/ip-groups/page.tsx` | 重写 |
| `features/waf/components/rule-entry-modal.tsx` | `openflare/waf/components/rule-entry-dialog.tsx` | 重写 |
| `features/websites/components/websites-page.tsx` | `openflare/websites/page.tsx` | 重写 |
| `features/websites/components/website-detail-page.tsx` | `openflare/websites/detail/page.tsx` | 重写 |
| `features/tls-certificates/components/*.tsx` | `openflare/websites/certificates/components/*.tsx` | 重写 |
| `features/pages/components/pages-page.tsx` | `openflare/pages/page.tsx` | 重写 |
| `features/pages/components/pages-detail-page.tsx` | `openflare/pages/detail/page.tsx` | 重写 |
| `features/origins/components/origins-page.tsx` | `openflare/origins/page.tsx` | 重写 |
| `features/access-logs/components/access-logs-page.tsx` | `openflare/access-logs/page.tsx` | 重写 |
| `features/apply-logs/components/apply-logs-page.tsx` | `openflare/apply-logs/page.tsx` | 重写 |
| `features/performance/components/performance-page.tsx` | `openflare/performance/page.tsx` | 重写 |
| `features/settings/components/settings-page.tsx` | 拆入 `admin/settings` + `settings/*` | 拆分废弃 |
| `features/update/components/version-upgrade-modal.tsx` | 并入 `header` + `admin/updater` | 适配 |
| `features/auth/components/*.tsx` | — | **删除**,用 Wavelet |
| `features/users/components/*.tsx` | — | **删除**,用 `/admin/users` |
| `components/layout/dashboard-shell.tsx` | `components/layout/` Wavelet 布局 | 废弃 |
| `components/ui/*.tsx` | `components/ui/*.tsx` Wavelet | 废弃 |
| `lib/api/client.ts` | `lib/services/core/base.service.ts` | 废弃 |
| `store/app-shell.ts` | Wavelet 侧栏内置状态 | 废弃 |
---
## 11. 页面-API 完整依赖表(迁移后)
> 认证类 API 在阶段二切换至 `/api/v1/*`;业务 API 保持 `/api/*`。
| 新页面 | 依赖 API 端点 |
|---|---|
| `/openflare` | `GET /api/dashboard/overview` |
| `/openflare/nodes` | `GET/POST /api/nodes/`, `GET /api/nodes/bootstrap-token` |
| `/openflare/nodes/detail` | `GET/POST /api/nodes/:id/*`, `GET /api/nodes/:id/observability`, `GET /api/nodes/:id/agent-release` |
| `/openflare/proxy-routes` | `GET/POST /api/proxy-routes/*` |
| `/openflare/proxy-routes/detail` | 同上 + `GET /api/managed-domains/`, `GET /api/pages/`, `GET /api/tls-certificates/`, `GET/POST /api/waf/sites/:id/rule-groups`, `GET /api/config-versions/diff`, `POST /api/config-versions/publish` |
| `/openflare/config-versions` | `GET/POST /api/config-versions/*` |
| `/openflare/waf` | `GET/POST /api/waf/rule-groups/*`, `GET /api/proxy-routes/` |
| `/openflare/waf/ip-groups` | `GET/POST /api/waf/ip-groups/*` |
| `/openflare/websites` | `GET/POST /api/managed-domains/*` |
| `/openflare/websites/detail` | 同上 + `GET /api/proxy-routes/`, WAF 绑定 API |
| `/openflare/websites/certificates` | `GET/POST /api/tls-certificates/*`, `GET /api/acme-accounts/default` |
| `/openflare/websites/dns-accounts` | `GET/POST /api/dns-accounts/*` |
| `/openflare/pages` | `GET/POST /api/pages/*` |
| `/openflare/pages/detail` | 部署相关 `/api/pages/:id/deployments/*` |
| `/openflare/origins` | `GET/POST /api/origins/*` |
| `/openflare/access-logs` | `GET/POST /api/access-logs/*` |
| `/openflare/apply-logs` | `GET/POST /api/apply-logs/*` |
| `/openflare/performance` | `GET/POST /api/option/*`, `GET /api/config-versions/preview` |
| `/login` | `POST /api/v1/user/login`, Cap API |
| `/admin/users` | `/api/v1/admin/users/*` |
| `/settings/*` | `/api/v1/user/*` |
| `/admin/settings` | `/api/v1/admin/*` + `/api/option/*`(OpenFlare 扩展) |
| 顶栏升级 | `/api/update/*` 或 `/api/v1/admin/updater/*` |
---
## 12. 验证计划
### 12.1 开发验证
```bash
cd Wavelet/frontend
pnpm lint
pnpm build
pnpm dev # 联调 Wavelet api 进程
```
### 12.2 功能走查清单
| 场景 | 步骤 | 预期 |
|---|---|---|
| 登录 | Wavelet 登录页 | Session 建立,跳转 /openflare |
| 创建节点 | nodes → 创建 → 复制安装命令 | 节点上线 |
| 创建规则 | proxy-routes → 6 section 配置 | 保存成功 |
| 发布配置 | config-versions → diff → publish → activate | Agent 收到配置 |
| WAF 拦截 | waf → 创建规则组 → 绑定站点 | 规则生效 |
| 证书申请 | certificates → ACME | 证书签发 |
| Pages 部署 | pages → 上传 zip → 激活 | 部署成功 |
| 访问日志 | access-logs → 筛选/折叠 | 数据展示 |
| 用户管理 | admin/users | CRUD 正常 |
| 升级 | 顶栏检查更新 | WS 日志 + 升级成功 |
### 12.3 E2E 测试规划
| 测试文件 | 覆盖路径 |
|---|---|
| `e2e/openflare-auth.spec.ts` | 登录/登出 |
| `e2e/openflare-node.spec.ts` | 节点 CRUD |
| `e2e/openflare-proxy-route.spec.ts` | 规则 + 发布 |
| `e2e/openflare-waf.spec.ts` | WAF 规则组 |
---
## 13. 风险与缓解
| 风险 | 缓解 |
|---|---|
| 大文件拆分工作量大 | 按 section/tab 并行;参考 admin/database |
| ECharts → Recharts 世界地图 | 保留 ECharts 作为可选依赖 |
| 静态导出 vs SSR | 优先确认 `build:embed`;保留 `?id=` 查询参数路由 |
| 设置页 2400 行拆分遗漏 | 逐项对照 5 Tab 功能清单 |
| `/user` 无入口历史问题 | 统一纳入 `/admin/users` 侧栏 |
| 微信/OAuth 特殊流程 | 与后端 legacy 层同步验证 |
| 上传进度 | Pages 部署保留 XHR 进度;复用 Wavelet upload 基建 |
---
## 14. 里程碑
| 里程碑 | 时间 | 标志 |
|---|---|---|
| M1 布局就绪 | 第 1 周 | 导航 + 登录 + 空页面 |
| M2 核心 UI | 第 4 周 | 节点/规则/发布可用 |
| M3 安全流量 | 第 6 周 | WAF/证书/网站 |
| M4 全页面 | 第 8 周 | 全部 FC 页面完成 |
| M5 上线切换 | 第 10 周 | 废弃旧 web,embed 新前端 |
---
## 15. 与后端计划协同时间表
```mermaid
gantt
title OpenFlare 迁移协同
dateFormat YYYY-MM-DD
section 后端
基建与认证 :b0, 2026-06-18, 3w
核心链路 :b2, after b0, 3w
安全证书 :b3, after b2, 2w
扩展运维 :b4, after b3, 3w
section 前端
基建布局 :f0, 2026-07-02, 2w
核心UI :f2, after f0, 3w
安全流量UI :f3, after f2, 2w
扩展收尾 :f4, after f3, 3w
```
| 后端里程碑 | 前端可启动项 |
|---|---|
| M2 认证联调 | F1 认证与布局 |
| M3 核心链路 | F2 节点/规则/发布 |
| M4 安全证书 | F3 WAF/网站/证书 |
| M5 全量功能 | F4 仪表盘/日志/Pages |
---
## 16. 参考文档
- [`Wavelet/AGENTS.md`](../../Wavelet/AGENTS.md) — **开发前必读**
- [`docs/plan/20260618-openflare-wavelet-backend-migration.md`](./20260618-openflare-wavelet-backend-migration.md)
- Wavelet 标杆页面:`Wavelet/frontend/app/(main)/admin/database/`、`admin/demo/`
- 旧前端源码:`openflare-server/web/features/`
+7
View File
@@ -9,6 +9,13 @@
1. **[实现计划模板](./implementation-plan-template.md)**:用于新功能开发或重大重构前的技术方案规划。
2. **[AI 接手计划模板](./handover-plan-template.md)**:用于在上下文截断、压缩或更换 AI 代理时,记录当前任务状态、已完成内容与下一步执行计划。
## 正在进行的计划
| 计划 | 说明 |
| --- | --- |
| [OpenFlare → Wavelet 后端迁移计划](./20260618-openflare-wavelet-backend-migration.md) | 将 `openflare-server` 后端迁移至 Wavelet 框架,保留 `/api/*` 路径,复用用户/认证等平台能力 |
| [OpenFlare → Wavelet 前端迁移计划](./20260618-openflare-wavelet-frontend-migration.md) | 将 `openflare-server/web` 业务 UI 按 Wavelet 设计风格重写,复用框架组件与 Admin 基建 |
## 使用建议
* **命名规范**:正在进行的开发计划建议命名为 `docs/plan/YYYYMMDD-[feature-name].md`,接手计划建议命名为 `docs/plan/handover-[task-name].md`。