mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-28 07:36:38 +08:00
9b98194a0a
- Add backend API for tunnel delete rule resolution (allow, deny, confirm) - Add contract tests for delete resolution endpoint - Add frontend API types and endpoints for delete resolution - Add tunnel delete resolution settings UI with resolution mode selector - Support per-tunnel and global delete resolution configuration
184 lines
7.9 KiB
Markdown
184 lines
7.9 KiB
Markdown
# 044 - 隧道删除时的规则依赖处理设计
|
||
|
||
## Goal
|
||
- 删除隧道前识别关联规则,避免默认级联误删。
|
||
- 在隧道页提供两种处理方式:迁移规则到其他隧道,或连同规则一起删除。
|
||
- 第一阶段只覆盖单条隧道删除,先把核心交互和执行链路做稳。
|
||
|
||
## Checklist
|
||
- [x] 复核当前 `tunnel.tsx` 删除交互与 `DeleteTunnelCascade` 行为。
|
||
- [x] 梳理可复用的规则换隧道能力(`forward/batch-change-tunnel`)。
|
||
- [x] 产出前端交互、接口与执行链路设计。
|
||
- [x] 明确第一阶段范围、异常处理与回滚要求。
|
||
|
||
## Implementation Checklist
|
||
- [x] 新增后端删除预检与带规则处理的删除接口。
|
||
- [x] 在后端补齐规则迁移/失败明细/回滚链路。
|
||
- [x] 接入前端隧道删除预检、替换/删除规则弹窗与结果展示。
|
||
- [x] 运行定向测试并记录结果。
|
||
|
||
## Current State
|
||
- `vite-frontend/src/pages/tunnel.tsx` 的单条删除当前直接调用 `/tunnel/delete`,没有前置依赖检查。
|
||
- `go-backend/internal/store/repo/repository_mutations.go` 里的 `DeleteTunnelCascade` 会直接删除该隧道下的 `forward`、`forward_port`、`user_tunnel`、`chain_tunnel` 等关联数据。
|
||
- `vite-frontend/src/pages/forward.tsx` 已经有“批量换隧道”交互和 `/forward/batch-change-tunnel`,但如果前端直接串联“先换规则、再删隧道”,中间任一步失败都会留下半完成状态,不适合作为删除流程的最终方案。
|
||
|
||
## Proposed UX
|
||
- 点击隧道删除按钮后,前端先请求“删除预检”接口,不直接进入最终确认。
|
||
- 若关联规则数为 `0`,继续沿用当前简单确认弹框。
|
||
- 若关联规则数大于 `0`,改为展示“处理关联规则”弹框:
|
||
- 顶部 `Alert` 提示:`隧道 "A" 正被 12 条规则使用`。
|
||
- 展示前 5 条规则摘要:规则名、所属用户、入口端口;剩余规则用“还有 N 条未展开”提示即可。
|
||
- 提供 `RadioGroup` 两个动作:
|
||
- `替换到其他隧道`(推荐,默认)
|
||
- `删除这些规则`
|
||
- 选择“替换到其他隧道”时显示 `Select`:
|
||
- 数据源直接复用当前页已经加载的 `tunnels`。
|
||
- 仅显示 `status === 1` 且 `id !== 当前隧道` 的选项。
|
||
- 若没有可选隧道,则禁用该选项并自动回退到“删除这些规则”。
|
||
- 确认按钮文案动态变化:
|
||
- `替换规则并删除隧道`
|
||
- `删除规则并删除隧道`
|
||
- 提交时展示 loading 状态;成功后关闭弹框、刷新隧道列表并 toast 成功。
|
||
- 如果后端返回规则级失败明细,前端复用现有 `BatchActionResultModal` 展示失败项,而不是只给一个通用 toast。
|
||
|
||
## API Design
|
||
### 1. 删除预检
|
||
`POST /api/v1/tunnel/delete-preview`
|
||
|
||
Request:
|
||
```json
|
||
{ "id": 12 }
|
||
```
|
||
|
||
Response:
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"msg": "",
|
||
"data": {
|
||
"tunnelId": 12,
|
||
"tunnelName": "HK-Entry",
|
||
"forwardCount": 12,
|
||
"sampleForwards": [
|
||
{
|
||
"id": 101,
|
||
"name": "web-1",
|
||
"userId": 9,
|
||
"userName": "alice",
|
||
"inPort": 443
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
- `sampleForwards` 只需要返回前 5 条,前端用 `forwardCount` 决定是否显示“更多”提示。
|
||
- 预检只描述现状,不负责最终授权或一致性保证;真正提交删除时,后端必须再校验一次。
|
||
|
||
### 2. 带规则处理的删除
|
||
`POST /api/v1/tunnel/delete-with-forwards`
|
||
|
||
Request:
|
||
```json
|
||
{
|
||
"id": 12,
|
||
"action": "replace",
|
||
"targetTunnelId": 18
|
||
}
|
||
```
|
||
|
||
或:
|
||
|
||
```json
|
||
{
|
||
"id": 12,
|
||
"action": "delete_forwards"
|
||
}
|
||
```
|
||
|
||
Success response:
|
||
```json
|
||
{
|
||
"code": 0,
|
||
"msg": "",
|
||
"data": {
|
||
"forwardCount": 12,
|
||
"migratedCount": 12,
|
||
"deletedForwardCount": 0,
|
||
"portAdjustedCount": 2
|
||
}
|
||
}
|
||
```
|
||
|
||
Failure response:
|
||
```json
|
||
{
|
||
"code": -2,
|
||
"msg": "部分规则迁移失败",
|
||
"data": {
|
||
"successCount": 9,
|
||
"failCount": 3,
|
||
"failures": [
|
||
{
|
||
"id": 101,
|
||
"name": "web-1",
|
||
"reason": "目标隧道入口节点端口 443 已占用"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
- 保持现有 `/tunnel/delete` 不动,兼容旧调用和当前批量删除逻辑。
|
||
- `vite-frontend/src/pages/tunnel.tsx` 的单条删除新流程全部走新接口。
|
||
|
||
## Backend Execution Strategy
|
||
- `delete-preview`
|
||
- 校验 tunnel 是否存在。
|
||
- 查询 `forward.tunnel_id = 当前隧道` 的数量和前 5 条摘要。
|
||
- `delete-with-forwards`
|
||
- 再次查询依赖规则,避免 preview 与提交之间状态变化导致误判。
|
||
- `action = delete_forwards`
|
||
- 直接复用当前级联删除逻辑。
|
||
- `action = replace`
|
||
- 校验 `targetTunnelId`:存在、启用、且不等于当前隧道。
|
||
- 先对全部关联规则做一次前置校验:目标隧道入口节点、端口范围、端口冲突、监听 IP 约束。
|
||
- 全部校验通过后,再逐条迁移规则并同步运行时。
|
||
- 任一规则迁移失败时,返回失败明细并中止删除;对已迁移规则做回滚,保证用户感知为“要么都成功,要么都不删”。
|
||
- 规则处理完成后,再删除隧道本身及非 `forward` 关联数据。
|
||
|
||
## Frontend Implementation Notes
|
||
- `vite-frontend/src/pages/tunnel.tsx`
|
||
- 新增删除预检 loading、依赖摘要、处理动作等 state。
|
||
- 复用现有 `Modal`,根据 preview 结果切换普通确认视图和依赖处理视图。
|
||
- 复用 `Select`、`RadioGroup`、`Alert`。
|
||
- 成功后继续沿用当前 `setTunnels`、`setTunnelOrder`、`setSelectedIds` 清理逻辑。
|
||
- `vite-frontend/src/api/index.ts`
|
||
- 新增 `previewTunnelDelete`。
|
||
- 新增 `deleteTunnelWithForwards`。
|
||
- 删除失败且返回批量明细时,复用 `BatchActionResultModal`,避免具体失败规则原因被 toast 吞掉。
|
||
|
||
## Scope Decision
|
||
- 第一阶段只改“隧道页单条删除”。
|
||
- `批量删除隧道` 先保持现有“级联删除规则”行为和提示文案不变。
|
||
- 如果第一阶段确认体验和后端回滚链路都稳定,再补第二阶段:批量删除时按每条隧道分别预检和处理。
|
||
|
||
## Edge Cases
|
||
- 没有可替换隧道:只允许“删除这些规则”。
|
||
- 目标隧道在提交前被禁用或删除:后端返回明确错误,前端保留当前弹框和用户选择。
|
||
- preview 时没有规则、提交时新建了规则:以后端最终校验为准,返回需要重新处理的提示。
|
||
- 迁移时若原入口端口在目标隧道不可用,沿用现有“换隧道”语义:优先保留原端口,不可用时自动分配可用端口,并通过 `portAdjustedCount` 给前端一个非阻塞提示。
|
||
- 第一阶段不自动补发目标隧道的 `user_tunnel` 授权,先与现有“批量换隧道”语义保持一致;如果后续需要让用户也获得目标隧道的新增规则权限,再单独评估自动补授权。
|
||
|
||
## Implementation Notes
|
||
- 后端新增 `/api/v1/tunnel/delete-preview` 和 `/api/v1/tunnel/delete-with-forwards`,单条隧道删除改为先预检再执行。
|
||
- 后端新增 `/api/v1/tunnel/batch-delete-preview` 和 `/api/v1/tunnel/batch-delete-with-forwards`,批量删除支持统一预检并选择“批量替换规则”或“批量删除规则”。
|
||
- 规则替换删除在后端先做端口/节点占用预检,再执行逐条迁移;执行阶段若任一规则失败,会回滚已迁移规则,并把失败明细返回给前端弹窗展示。
|
||
- 前端 `tunnel.tsx` 删除弹窗已支持三种状态:预检中、普通删除确认、有依赖规则时的“替换/删除规则”决策视图。
|
||
- 批量删除弹窗现在会汇总每条选中隧道的依赖规则数量,并在批量替换失败时按“隧道级”返回失败原因,避免整批操作信息丢失。
|
||
|
||
## Verification
|
||
- `cd go-backend && go test ./internal/http/handler/...`
|
||
- `cd go-backend && go test ./tests/contract/... -run 'TestTunnelDeletePreviewIncludesDependentRulesContract|TestTunnelDeleteWithForwardsDeleteActionRemovesTunnelAndRulesContract|TestTunnelDeleteWithForwardsReplaceReturnsFailureDetailsContract'`
|
||
- `cd vite-frontend && npm run build`
|