diff --git a/docs/changelog/index.md b/docs/changelog/index.md index 33a6b53a..f33dea25 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -19,6 +19,7 @@ sidebar: false ### 移除 - 移除 Wavelet 中从旧系统迁移但未实装的全局 API / Web / 敏感接口限流选项(`GlobalApiRateLimit*`、`GlobalWebRateLimit*`、`CriticalRateLimit*`)及相关校验与数据库种子。 +- 移除 `internal/apps/openflare/legacy/` 控制台兼容层、`compat/auth.go`(`OpenFlare-Token` JWT 桥接)及前端 `legacy-base.service.ts`;`openflare-server/web` 不再能对接当前 Wavelet 后端管理 API。 ### 新增 @@ -31,7 +32,7 @@ sidebar: false - Wavelet WAF / 代理规则认证实装完整 PoW 配置面板:支持难度、算法、TTL 与路径/IP/UA 黑白名单编辑。 - Wavelet WAF 新建/编辑规则组改用右侧 Sheet 抽屉,替代居中弹窗,与站点绑定等操作保持一致的 shadcn 侧栏交互。 -- 将 `openflare-server` 后端业务域迁移至 `Wavelet/internal/apps/openflare/`,通过 `/api/*` legacy 兼容层保持旧前端 API 路径不变。 +- 将 `openflare-server` 后端业务域迁移至 `Wavelet/internal/apps/openflare/`;管理控制台 API 挂载于 `/api/v1/d/*`,节点协议挂载于 `/api/v1/agent|relay|tunnel/*`。 - 新增 OpenFlare 业务表 goose 迁移(`of_options`、`of_origins`、`of_proxy_routes`、`of_nodes`、`of_waf_*`、`of_tls_*`、`of_config_versions`、`of_pages_*`、`of_apply_logs` 等)。 - 重叠职能复用 Wavelet 内置用户/OAuth/Cap/认证源能力;新增 `integration` 包覆盖认证、核心链路、安全、Agent 协议集成测试。 - 修复 Wavelet 引入 `openflare` 模块后 `gomodule/redigo v2.0.0+incompatible` 导致 `redistore` 编译失败的问题。 @@ -40,19 +41,19 @@ sidebar: false - Agent heartbeat 恢复可观测性数据持久化(系统画像、指标快照、流量报表、健康事件等)。 - Wavelet 默认数据库名由 `wavelet` 调整为 `openflare`(PostgreSQL、ClickHouse、SQLite 后备路径同步更新)。 - Wavelet 默认 PostgreSQL `application_name` 由 `wavelet-server` 调整为 `openflare-server`,Redis 键前缀由 `wavelet:` 调整为 `openflare:`。 -- 实装 Agent WAF IP 组同步(heartbeat `waf_ip_groups` 增量下发与 `/api/agent/waf/ip-groups/sync`)。 -- 实装 Pages Agent 部署包下载(`/api/agent/pages/deployments/:deployment_id/package` 二进制响应)。 -- 全局 `OpenFlare-Token` 桥接至 legacy `/api/*` 管理端路由。 +- 实装 Agent WAF IP 组同步(heartbeat `waf_ip_groups` 增量下发与 `/api/v1/agent/waf/ip-groups/sync`)。 +- 实装 Pages Agent 部署包下载(`/api/v1/agent/pages/deployments/:deployment_id/package` 二进制响应)。 + - 实装访问日志单表查询层(列表、折叠、IP 汇总/趋势、地域统计)及 `(node_id, logged_at)` 复合索引。 -- 扩展 Relay/Flared heartbeat 载荷与可观测性持久化(frps 观测、健康事件);新增 `of_node_obs_frpc` 单表。 +- 扩展 Relay/Tunnel heartbeat 载荷与可观测性持久化(frps 观测、健康事件);新增 `of_node_obs_frpc` 单表。 - Agent heartbeat 恢复 Geo 自动更新、访问日志地域解析与 90 天保留清理;对齐 config `support_files` 过滤规则。 -- 补全 OAuth 快捷路由(`/api/oauth/github`、`/api/oauth/wechat`、`/api/oauth/wechat/bind`、`/api/oauth/email/bind`)。 +- OAuth 登录/绑定统一由 Wavelet `/api/v1/oauth/:source/*` 提供;旧 `/api/oauth/*` 快捷路径未保留。 - 新增 `internal/apps/openflare/tasks/` 集中承载 OpenFlare 定时/后台任务业务逻辑;调度已迁入 Wavelet Asynq 异步任务框架(`async_tasks.go` + `w_schedules` 种子迁移),含数据库可观测性自动清理、WAF IP 组周期同步、UptimeKuma 同步、ACME 证书自动续期。 - Pages 部署包上传改为通过 Wavelet `upload.Ingest` 写入本地文件存储框架,部署记录关联 `upload_id`;Agent 下载改为从存储后端流式读取。 - 实装数据库可观测性手动/自动清理、WAF IP 组订阅/自动同步与测试接口、UptimeKuma 监控同步、TLS ACME 申请/续期(lego DNS-01)。 - 修复 Wavelet Agent WebSocket 未处理 `status` 消息导致 WS 模式下 `last_seen_at` 停止更新、节点超时显示离线的问题;列表「最近心跳」恢复显示「WS 已连接」。 - 修复节点「强制同步」仍为 stub 导致始终返回「节点不在线或通过 WebSocket 发送同步指令失败」的问题。 -- 将 OpenFlare 管理控制台从 `openflare-server/web` 迁移至 `Wavelet/frontend/app/(main)/openflare/`,复用 Wavelet shadcn 组件与 Session 鉴权;新增 `LegacyOpenFlareBaseService` 对接 `/api/*` 业务 API。 +- 将 OpenFlare 管理控制台从 `openflare-server/web` 迁移至 `Wavelet/frontend/`,复用 Wavelet shadcn 组件与 Session 鉴权;Service 层对接 `/api/v1/d/*`(`OpenFlareBaseService`)。 - 实装节点、代理规则(6 Section)、配置发布、WAF、网站/证书/DNS、Pages、源站、访问/应用日志、仪表盘、性能调优等业务页面;Admin 设置新增 OpenFlare 运维扩展 Tab。 - 修复静态导出构建中 `useSearchParams` 未包裹 Suspense 的问题;`pnpm build:embed` 全量 46 页通过。 - 补全前端迁移收尾:新增 `/openflare/about` 关于页与 `AboutService`;补全 `UpdateService` 升级流程(在线升级、手动上传、WebSocket 日志流)及顶栏版本升级入口。 @@ -79,11 +80,12 @@ sidebar: false - OpenFlare 路由注册统一收敛至 `internal/router/v1/openflare/`(`register_*.go` + `RegisterV1Routes`);`internal/apps/openflare/*/routers.go` 仅保留 Handler 与业务逻辑。 - 将 OpenFlare 路由注册包从 `internal/router/openflare/` 迁移至 `internal/router/v1/openflare/`,与 v1 路由分层目录结构对齐。 - OpenFlare 管理端路由注册从 `RegisterCustomRoutes` 移至 `v1.RegisterV1Routes`,API 前缀由 `/api/v1/custom/openflare` 调整为 `/api/v1/openflare`。 -- OpenFlare 管理控制台 API 统一迁移至 `/api/v1/openflare/*`,响应格式对齐 Wavelet `{error_msg, data}` + `response.Abort*`。 -- `/api/*` 仅保留 Agent/Relay/Flared 节点协议路由(legacy `{success, message, data}` 信封);控制台鉴权改为 `apiutil.AdminRequired()`。 -- 前端 OpenFlare Service 层由 `LegacyOpenFlareBaseService` 切换为 `OpenFlareBaseService`(`BaseService` + v1 路径)。 -- 为 OpenFlare v1 管理端 API 补充 Swagger 注解(`/api/v1/openflare/*`,约 99 个端点)。 -- 移除已无引用的 `internal/apps/openflare/auth/`、`compat/auth.go`、`compat/routes.go` 及前端 `legacy-base.service.ts`。 +- OpenFlare 管理控制台 API 统一迁移至 `/api/v1/d/*`,响应格式对齐 Wavelet `{error_msg, data}` + `response.Abort*`。 +- 节点协议路由迁移至 `/api/v1/agent|relay|tunnel/*`(`flared` 更名为 `tunnel`);协议层保留 legacy `{success, message, data}` 信封。 +- 控制台鉴权改为 `apiutil.AdminRequired()`(Session / Access Token)。 +- 前端 OpenFlare Service 层切换为 `OpenFlareBaseService`(`BaseService` + `/api/v1/d/*`)。 +- 为 OpenFlare 管理端 API 补充 Swagger 注解(约 99 个端点)。 +- 移除已无引用的 `internal/apps/openflare/auth/`、`compat/routes.go`。 ## [v2.3.4] - 2026-06-17 diff --git a/docs/plan/20260618-openflare-wavelet-backend-migration.md b/docs/plan/20260618-openflare-wavelet-backend-migration.md index f53f776e..70c0eeac 100644 --- a/docs/plan/20260618-openflare-wavelet-backend-migration.md +++ b/docs/plan/20260618-openflare-wavelet-backend-migration.md @@ -2,7 +2,7 @@ > **文档类型**:实现计划(Implementation Plan) > **创建日期**:2026-06-18 -> **状态**:实施中(阶段一旧前端联调,核心 API 与后台任务已落地) +> **状态**:实施中(阶段 5 收尾;控制台 `/api/v1/d/*` + 新前端已落地,legacy 兼容层已撤销) > **前置阅读**:[`Wavelet/AGENTS.md`](../../Wavelet/AGENTS.md)、[`docs/guideline/Constraints.md`](../guideline/Constraints.md)、[`docs/design/architecture.md`](../design/architecture.md) --- @@ -635,153 +635,178 @@ curl http://127.0.0.1:3000/api/agent/config-versions/active \ --- -## 12. API 端点完整对照表(旧 → 新实现位置) +## 12. API 端点完整对照表(openflare-server → Wavelet 当前实现) -> 路径阶段一保持不变;实现位置为 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) | 响应格式 | |---|---|---|---| -| 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 | +| 管理控制台 | `/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 | --- diff --git a/docs/plan/handover-openflare-backend-migration.md b/docs/plan/handover-openflare-backend-migration.md index 1d6c6321..0b3dd917 100644 --- a/docs/plan/handover-openflare-backend-migration.md +++ b/docs/plan/handover-openflare-backend-migration.md @@ -1,7 +1,7 @@ # OpenFlare 后端迁移 — AI 接手文档 > **状态**:进行中(阶段 5 收尾) -> **主线**:`openflare-server` 业务域已迁入 `Wavelet/internal/apps/openflare/`,阶段一通过 `/api/*` legacy 层联调旧前端 +> **主线**:`openflare-server` 业务域已迁入 `Wavelet/internal/apps/openflare/`;管理控制台走 `/api/v1/d/*` + `Wavelet/frontend`;节点协议走 `/api/v1/agent|relay|tunnel/*` > **关联计划**:[实现计划](./20260618-openflare-wavelet-backend-migration.md) --- @@ -10,34 +10,36 @@ ### 主线任务 -将 OpenFlare 控制面后端从 `openflare-server` 迁移至 Wavelet 框架,保留旧前端 API 路径,复用 Wavelet 用户/OAuth/Cap 等平台能力,并完成 Agent/Relay/Flared 协议兼容。 +将 OpenFlare 控制面后端从 `openflare-server` 迁移至 Wavelet 框架,复用 Wavelet 用户/OAuth/Cap 等平台能力,并完成 Agent/Relay/Tunnel 协议兼容。 + +**架构现状(2026-06-19)**:原计划「阶段一 `/api/*` legacy 层 + 旧前端联调」已在 v1 路径切换时撤销。`internal/apps/openflare/legacy/`、`compat/auth.go` 已删除;`openflare-server/web` 不再能对接当前 Wavelet 后端。 ### 开发分支 -- 分支:`dev`(相对 `origin/dev` 领先若干提交) -- 工作区:迁移计划文档 `docs/plan/20260618-openflare-wavelet-backend-migration.md` 可能仍有未提交修改 +- 分支:`dev` +- 参考对照:旧后端 `openflare-server/`(待 ETL 验证后归档) ### 已完成(✅) -- [x] **Batch 0 基建**:`compat/`、`legacy/register*.go`、`router.go` 挂载 `/api/*` -- [x] **T-AUTH ~ T-MISC** 全部 14 个业务任务队列项(见下表) -- [x] **goose 迁移** `202606190001` ~ `202606190012`(PostgreSQL + SQLite 双份) -- [x] **可观测性 v1 单表**:无 `_00`~`_09` 分片;heartbeat 持久化、访问日志查询、Relay/Flared 观测 -- [x] **定时任务包** `internal/apps/openflare/tasks/`(主进程 cron,非 Asynq) +- [x] **业务模块 T-OPTION ~ T-MISC**:14 个 OpenFlare 业务包 + `internal/router/v1/openflare/register_*.go` +- [x] **goose 迁移** `202606190001` ~ `202606190014`(PostgreSQL + SQLite 双份) +- [x] **可观测性 v1 单表**:无 `_00`~`_09` 分片;heartbeat 持久化、访问日志查询、Relay/Tunnel 观测 +- [x] **后台任务**:已迁入 Wavelet Asynq(`async_tasks.go` + `202606190013` 种子) - [x] **TLS ACME** 申请/续期(lego DNS-01) - [x] **集成测试** 4 个场景包全部通过(23 用例) - [x] **配置默认值**:DB 名 `openflare`、监听 `:3000`、`application_name=openflare-server`、Redis 前缀 `openflare:` +- [x] **API 路径统一**:控制台 `/api/v1/d/*`;协议 `/api/v1/agent|relay|tunnel/*`;Swagger 约 99 端点 ### 进行中(阶段 5) - [/] **B5-3** 旧环境数据迁移脚本 `support-files/migration/`(用户 + 业务表 ETL,含 10 分片观测数据合并) - [/] **B5-4** `make swagger` + `make code-check` 全绿 -- [/] **B5-5** 全量 API 回归(120+ 端点对照表) +- [/] **B5-5** 全量 API 回归(对照实现计划 §12 端点表) ### 待处理 - [ ] 生产环境:创建并**激活** config version,消除节点列表「异常」(`openresty_status=unhealthy` + `当前没有激活版本`) -- [ ] 旧前端静态托管与 Wavelet 嵌入前端的联调路径文档化(阶段二切 `Wavelet/frontend`) +- [ ] 归档 `openflare-server/` 整包(ETL 与回归通过后) --- @@ -45,29 +47,30 @@ | ID | 板块 | 状态 | 负责目录 | |---|---|---|---| -| T-AUTH | 认证/用户/OAuth/Cap | ✅ | `legacy/register_auth.go`, `openflare/auth/`, `compat/auth.go` | -| T-OPTION | 状态/公告/Option | ✅ | `legacy/register_option.go`, `openflare/option/` | -| T-ORIGIN | 源站 | ✅ | `legacy/register_origin.go`, `openflare/origin/` | -| T-APPLYLOG | 应用日志 | ✅ | `legacy/register_apply_log.go`, `openflare/apply_log/` | -| T-PROXY | 代理规则 | ✅ | `legacy/register_proxy_route.go`, `openflare/proxy_route/` | -| T-NODE | 节点管理 | ✅ | `legacy/register_node.go`, `openflare/node/` | -| T-WAF | WAF | ✅ | `legacy/register_waf.go`, `openflare/waf/` | -| T-TLS | TLS/证书/域名/DNS | ✅ | `legacy/register_tls.go`, `openflare/tls/` | -| T-CFGVER | 配置版本 | ✅ | `legacy/register_config_version.go`, `openflare/config_version/` | -| T-AGENT | Agent API + WS | ✅ | `legacy/register_agent.go`, `openflare/agent/`, `openflare/websocket/` | -| T-PAGES | Pages 托管 | ✅ | `legacy/register_pages.go`, `openflare/pages/` | -| T-RELAY | Relay + Flared | ✅ | `legacy/register_relay_flared.go`, `openflare/relay/`, `openflare/flared/` | -| T-OBS | 仪表盘 + 可观测 | ✅ | `legacy/register_dashboard_obs.go`, `openflare/dashboard/`, `openflare/observability/` | -| T-MISC | 升级/GeoIP/UptimeKuma | ✅ | `legacy/register_misc.go`, `openflare/update/`, `openflare/geoip/`, `openflare/uptimekuma/` | +| T-AUTH | 认证/用户/OAuth/Cap | ✅ | Wavelet `apps/user`、`apps/oauth`、`apps/cap`、`apps/admin`(无独立 legacy 包) | +| T-OPTION | 状态/公告/Option | ✅ | `openflare/option/`,`register_option.go` | +| T-ORIGIN | 源站 | ✅ | `openflare/origin/`,`register_origin.go` | +| T-APPLYLOG | 应用日志 | ✅ | `openflare/apply_log/`,`register_apply_log.go` | +| T-PROXY | 代理规则 | ✅ | `openflare/proxy_route/`,`register_proxy_route.go` | +| T-NODE | 节点管理 | ✅ | `openflare/node/`,`register_node.go` | +| T-WAF | WAF | ✅ | `openflare/waf/`,`register_waf.go` | +| T-TLS | TLS/证书/域名/DNS | ✅ | `openflare/tls/`,`register_tls.go` | +| T-CFGVER | 配置版本 | ✅ | `openflare/config_version/`,`register_config_version.go` | +| T-AGENT | Agent API + WS | ✅ | `openflare/agent/`,`register_agent.go` | +| T-PAGES | Pages 托管 | ✅ | `openflare/pages/`,`register_pages.go` | +| T-RELAY | Relay + Tunnel | ✅ | `openflare/relay/`、`openflare/flared/`,`register_relay_flared.go` | +| T-OBS | 仪表盘 + 可观测 | ✅ | `openflare/dashboard/`、`openflare/observability/`,`register_dashboard.go`、`register_observability.go` | +| T-MISC | 升级/GeoIP/UptimeKuma | ✅ | `openflare/update/`、`openflare/geoip/`、`openflare/uptimekuma/`,`register_update.go`、`register_option.go` | ### 任务隔离规则 | 规则 | 说明 | |---|---| -| 文件所有权 | 每个任务 **仅修改** 自己的 `internal/apps/openflare//`、对应 `legacy/register_.go`、`internal/model/openflare_.go`、goose SQL | +| 文件所有权 | 每个任务 **仅修改** 自己的 `internal/apps/openflare//`、对应 `router/v1/openflare/register_.go`、`internal/model/openflare_.go`、goose SQL | | 禁止修改 | `v1/user.go`、`v1/admin.go`、`model/users.go`、其他任务的 `register_*.go` | -| 响应格式 | 旧前端兼容 API 使用 `compat.OK/Fail/Unauthorized`(`{success,message,data}`) | -| 鉴权 | 管理端 `compat.AdminAuth()` / `compat.RootAuth()`;用户 `compat.UserAuth()`;全局 `OpenFlare-Token` 桥接见 `legacy/register.go` | +| 控制台响应格式 | `{error_msg, data}` + `response.Abort*`(Wavelet 标准) | +| 协议响应格式 | `compat.OK/Fail`(`{success, message, data}`),供 Agent/Relay/Tunnel 二进制使用 | +| 控制台鉴权 | `apiutil.AdminRequired()`(Session / `X-Access-Token`,`user.IsAdmin` + `token_admin`) | | Logic 层 | `logics.go` 使用 `context.Context`,不依赖 `*gin.Context` | | 数据源 | `db.DB(ctx)` 获取 GORM | | 质量门禁 | 完成后 `go build ./...` 并通过本模块测试 | @@ -76,27 +79,29 @@ ## 3. 核心文件与上下文 -### 路由与兼容层 +### 路由注册 | 路径 | 职责 | |---|---| -| `Wavelet/internal/router/router.go` | 在 `apiGroup` 下调用 `oflegacy.RegisterRoutes` | -| `Wavelet/internal/apps/openflare/legacy/register.go` | 汇总各 `register_*.go`;`OpenFlare-Token` 全局桥接 | -| `Wavelet/internal/apps/openflare/compat/auth.go` | JWT ↔ Session/AccessToken、角色 `of_role` 解析 | -| `Wavelet/internal/apps/openflare/compat/response.go` | Wavelet 信封 → 旧 `{success,message,data}` | +| `Wavelet/internal/router/router.go` | `apiGroup` → `v1.RegisterV1Routes` | +| `Wavelet/internal/router/v1/v1.go` | 汇总 User/Admin/OpenFlare 路由 | +| `Wavelet/internal/router/v1/openflare/v1.go` | `RegisterV1Routes` → `/api/v1/d/*` 控制台 | +| `Wavelet/internal/router/v1/openflare/openflare.go` | `RegisterRoutes` → `/api/v1/agent|relay|tunnel/*` 协议 | +| `Wavelet/internal/router/v1/openflare/register_*.go` | 各资源路由挂载 | +| `Wavelet/internal/apps/openflare/*/routers.go` | Handler + Swagger 注解 | +| `Wavelet/internal/apps/openflare/compat/response.go` | 协议层 legacy 信封(**仅** Agent/Relay/Tunnel) | +| `Wavelet/internal/apps/openflare/apiutil/` | 控制台 BindJSON、AdminRequired、RegisterCollection | -### 定时任务(OpenFlare cron) +### 后台任务(Asynq) -| 文件 | Job 名 | Cron | 说明 | -|---|---|---|---| -| `tasks/database_cleanup.go` | `database_auto_cleanup` | `0 3 * * *` | 可观测数据自动清理(受 Option 开关控制) | -| `tasks/waf_ip_group_sync.go` | `waf_ip_group_sync` | `@every 5m` | WAF IP 组周期同步 | -| `tasks/uptimekuma_sync.go` | `uptime_kuma_sync` | `* * * * *` | 按 Option 间隔触发 UptimeKuma 同步 | -| `tasks/ssl_renew.go` | `ssl_renew` | `0 0 * * *` | ACME 证书自动续期 | -| `waf/register_tasks.go` | — | — | 通过 `RegisterCronJob` 注册,避免 import cycle | +| 任务名 | 说明 | +|---|---| +| `openflare:database_auto_cleanup` | 可观测数据自动清理(受 Option 开关控制) | +| `openflare:waf_ip_group_sync` | WAF IP 组周期同步 | +| `openflare:uptime_kuma_sync` | UptimeKuma 同步 | +| `openflare:ssl_renew` | ACME 证书自动续期 | -**启动链路**:`wavelet api` / `wavelet all` → `bootstrap.RegisterAPI()` → `bootstrap.Init(ctx, {API:true})` → `oftasks.Start(ctx)`。 -**注意**:OpenFlare cron **仅在 API 进程**运行;`wavelet worker` / `wavelet scheduler` 负责 Wavelet 框架 Asynq 任务,与 OpenFlare cron 解耦。 +**启动链路**:`wavelet api` / `wavelet all` → `bootstrap.Init` → Asynq worker/scheduler 执行;任务定义见 `async_tasks.go`,调度种子见 `202606190013`。 ### 数据库迁移 @@ -111,23 +116,24 @@ | `202606190007` | `of_tls_*` | | `202606190008` | `of_config_versions` | | `202606190009` | `of_pages_*` | -| `202606190010` | 可观测性单表(profiles/metrics/reports/health/openresty/frps/access_logs) | -| `202606190011` | `of_node_access_logs` 复合索引 `(node_id, logged_at)` | +| `202606190010` | 可观测性单表 | +| `202606190011` | `of_node_access_logs` 复合索引 | | `202606190012` | `of_node_obs_frpc` | +| `202606190013` | OpenFlare Asynq 调度种子 | +| `202606190014` | Pages `upload_id` 字段 | 路径:`Wavelet/internal/db/migrator/goose/postgres/` 与 `sqlite/` 各一份。 ### 近期修复要点(2026-06-19) -| 问题 | 根因 | 修复位置 | +| 问题 | 根因 | 修复/处理 | |---|---|---| -| Agent 已连接但节点显示「异常」 | 无激活 config version → `openresty_status=unhealthy` | 运维:发布并激活配置版本 | +| Agent 已连接但节点显示「异常」 | 无激活 config version | 运维:发布并激活配置版本 | | 节点详情无错误日志 | 可观测性表未迁移 | `202606190010` + `agent/observability.go` | | WAF IP 组未下发 | Agent sync 未实装 | `agent/waf_ip_group.go`、`waf/ip_group_sync.go` | | Pages 包下载 404 | Agent 路由缺失 | `pages/logics.go`、`agent/routers.go` | -| 旧前端 Token 部分路由 401 | 未全局桥接 | `legacy/register.go` | | 访问日志查询空 | 单表查询层缺失 | `model/openflare_access_log.go`、`202606190011` | -| Relay/Flared 观测缺失 | heartbeat 未持久化 | `relay/observability.go`、`flared/observability.go`、`202606190012` | +| Relay/Tunnel 观测缺失 | heartbeat 未持久化 | `relay/observability.go`、`flared/observability.go`、`202606190012` | ### 依赖修复 @@ -139,10 +145,10 @@ | 测试包 | 场景 | 结果 | |---|---|---| -| `integration/auth_option_test.go` | 登录/self/option 权限/热重载 | ✅ 5/5 | +| `integration/auth_option_test.go` | Access Token 鉴权、option 权限、热重载 | ✅ 5/5 | | `integration/core_chain_test.go` | 源站→规则→发布→节点→apply-log | ✅ 6/6 | | `integration/security_test.go` | WAF/TLS/域名/DNS | ✅ 7/7 | -| `integration/agent_protocol_test.go` | Agent/Relay/Flared 协议 | ✅ 5/5 | +| `integration/agent_protocol_test.go` | Agent/Relay/Tunnel 协议 | ✅ 5/5 | ```bash cd Wavelet @@ -170,26 +176,21 @@ redis: key_prefix: "openflare:" ``` -或使用 `.env` / 环境变量:`DB_ENABLED=true`、`DB_NAME=openflare`、`POSTGRES_DB=openflare`。 - ### 启动命令 ```bash cd Wavelet -# 开发:API + Worker + Scheduler 合一 -go run . all - -# 生产:分进程(OpenFlare cron 仅需 api 进程) -go run . api +go run . all # 开发:API + Worker + Scheduler +go run . api # 生产:API 进程 go run . worker go run . scheduler ``` -### 阶段一旧前端联调 +### 当前联调方式 -- **API**:指向 Wavelet `:3000` 的 `/api/*`(legacy 兼容层) -- **静态页面**:阶段一仍使用 `openflare-server/web/build`(由旧 Server 托管或独立静态服务);Wavelet 默认嵌入的是 `Wavelet/frontend`,非旧 OpenFlare UI -- **鉴权**:旧前端使用 `OpenFlare-Token` Header;登录 `POST /api/user/login` 由 legacy 层签发 JWT +- **管理控制台**:`Wavelet/frontend`(`pnpm dev` 或 embed 构建产物),Session 鉴权,API 前缀 `/api/v1/d/*` +- **节点二进制**:连接 `/api/v1/agent/*`、`/api/v1/relay/*`、`/api/v1/tunnel/*`(legacy `{success,message,data}` 信封) +- **旧前端 `openflare-server/web`**:已无法对接当前后端(无 `/api/*` 控制台路由、无 `OpenFlare-Token` 桥接) --- @@ -198,8 +199,8 @@ go run . scheduler | 项 | 说明 | 当前处理 | |---|---|---| | 观测数据 10 分片 → 单表 | 旧生产环境有 `node_*_XX` 分片表 | v1 单表;B5-3 ETL 脚本待建 | -| 微信登录 | Wavelet 无内置 | legacy 快捷路由已补;长期评估废弃或独立维护 | -| OpenFlare cron vs Asynq | 两套任务体系并存 | 阶段一 cron 在 API 进程;后续可迁入统一框架 | +| 微信登录 | Wavelet 无内置 | 旧 `/api/oauth/wechat*` 未保留;评估废弃或补 v1 适配 | +| 三级角色 Root(100) | 旧 `RootAuth` | 简化为 `is_admin` + Access Token `token_admin` | | 节点「异常」展示 | 连接正常但无激活版本 | 属预期行为;需运维发布配置 | | `make code-check` | 全仓库静态检查 | 阶段 5 待跑通 | @@ -207,13 +208,11 @@ go run . scheduler ## 7. 下一步行动指南 -新接手 AI 建议按以下顺序执行: - 1. **确认环境**:`cd Wavelet && go build ./... && go test ./internal/apps/openflare/... -count=1` -2. **跑质量门禁**:`make code-check`(修复 swagger/静态检查问题) -3. **实现 B5-3**:在 `Wavelet/support-files/migration/` 编写 `users` → `w_users` 与业务表 ETL(含分片观测合并) -4. **API 回归**:对照实现计划 §12 端点表,用 curl/集成测试逐项验证 -5. **联调验证**:旧前端登录 → 创建规则 → 发布并**激活** config version → Agent 心跳 → 检查节点状态与 apply-log +2. **跑质量门禁**:`make code-check` +3. **实现 B5-3**:`Wavelet/support-files/migration/` ETL 脚本 +4. **API 回归**:对照实现计划 §12 端点表逐项验证 +5. **联调验证**:`Wavelet/frontend` 登录 → 创建规则 → 发布并**激活** config version → Agent 心跳 → 检查节点状态 --- @@ -221,9 +220,9 @@ go run . scheduler | 文档 | 用途 | |---|---| -| [实现计划](./20260618-openflare-wavelet-backend-migration.md) | 完整模块清单、端点对照、分阶段验收 | -| [前端迁移计划](./20260618-openflare-wavelet-frontend-migration.md) | 阶段二 UI 迁移 | -| [`Wavelet/AGENTS.md`](../../Wavelet/AGENTS.md) | 框架 Guardrails 与 Skills | +| [实现计划](./20260618-openflare-wavelet-backend-migration.md) | 模块清单、§12 端点对照 | +| [前端迁移计划](./20260618-openflare-wavelet-frontend-migration.md) | UI 迁移与验收 | +| [`Wavelet/AGENTS.md`](../../Wavelet/AGENTS.md) | 框架 Guardrails | | [`docs/guideline/Constraints.md`](../guideline/Constraints.md) | 开发约束 | -| 旧后端源码 | `openflare-server/internal/controller/`、`service/`、`model/` | +| 旧后端源码(对照用) | `openflare-server/internal/` | | Changelog | [`docs/changelog/index.md`](../changelog/index.md) `[Unreleased]` | \ No newline at end of file