fix: allow deleting system default sync channel with immediate heal
Remove hard ban that returned 400 with no UI feedback; delete then Ensure+rebinding, and show confirm/toast on SyncPage. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -121,21 +121,23 @@ func syncDeleteHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
authx.WriteError(w, http.StatusNotFound, err.Error())
|
||||
return
|
||||
}
|
||||
// Z12h-1:公司默认同步通道禁止删除(账号落点依赖它)
|
||||
if ch.IsSystemDefault {
|
||||
authx.WriteError(w, http.StatusBadRequest, "公司默认同步通道不可删除;账号绑定落点依赖此通道。若异常请刷新页面自动修复")
|
||||
return
|
||||
}
|
||||
wasDefault := ch.IsSystemDefault
|
||||
svcCtx.DBSync.StopChannel(id)
|
||||
if err := svcCtx.DBSync.Store().DeleteChannel(id); err != nil {
|
||||
authx.WriteError(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
// 若误删后仍有 Binding 挂死,heal 会挂回默认通道
|
||||
if _, hErr := applogic.HealTenantSyncBind(r.Context(), svcCtx, tid); hErr != nil {
|
||||
_ = hErr
|
||||
// Z12h-1:默认同步可删;删后 Ensure+heal,账号落点自动挂回新默认通道
|
||||
out := map[string]any{"ok": true, "deleted_id": id, "was_system_default": wasDefault}
|
||||
if healed, hErr := applogic.HealTenantSyncBind(r.Context(), svcCtx, tid); hErr != nil {
|
||||
out["heal_error"] = hErr.Error()
|
||||
} else if healed != nil {
|
||||
out["channel_id"] = healed.ChannelID
|
||||
out["recreated_default"] = wasDefault || healed.ChannelCreated
|
||||
out["bindings_fixed"] = healed.BindingsFixed
|
||||
out["agents_fixed"] = healed.AgentsFixed
|
||||
}
|
||||
httpx.OkJson(w, map[string]any{"ok": true})
|
||||
httpx.OkJson(w, out)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -586,9 +586,35 @@ export function SyncPage(props: {
|
||||
<Button
|
||||
size="small"
|
||||
danger
|
||||
onClick={async () => {
|
||||
await deleteSyncChannel(session, r.id);
|
||||
await refresh();
|
||||
onClick={() => {
|
||||
Modal.confirm({
|
||||
title: `删除通道「${r.name || r.id}」?`,
|
||||
content: r.is_system_default
|
||||
? "这是公司默认同步通道。删除后将自动重建并重挂库绑定,账号落点不会丢失。"
|
||||
: "删除后,仍挂在此通道上的绑定会自动改挂公司默认同步通道。",
|
||||
okText: "确认删除",
|
||||
okType: "danger",
|
||||
cancelText: "取消",
|
||||
onOk: async () => {
|
||||
setBusy(true);
|
||||
try {
|
||||
const res = await deleteSyncChannel(session, r.id);
|
||||
if (res.heal_error) {
|
||||
message.warning(`通道已删,自愈未完成:${res.heal_error}`);
|
||||
} else if (res.recreated_default) {
|
||||
message.success("已删除;公司默认同步通道已自动重建并重挂绑定");
|
||||
} else {
|
||||
message.success("已删除");
|
||||
}
|
||||
await refresh();
|
||||
} catch (e: any) {
|
||||
message.error(e.message || String(e));
|
||||
throw e;
|
||||
} finally {
|
||||
setBusy(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
删除
|
||||
|
||||
@@ -869,6 +869,8 @@ export type SyncChannel = {
|
||||
pk_columns: Record<string, string>;
|
||||
/** 绑定智能体:模块/库归属对照 */
|
||||
agent_id?: number;
|
||||
/** 公司默认同步通道(Z12) */
|
||||
is_system_default?: boolean;
|
||||
/** 绑定已发布模块 slug */
|
||||
app_slug?: string;
|
||||
last_error?: string;
|
||||
@@ -966,6 +968,16 @@ export async function deleteSyncChannel(session: Session, id: string) {
|
||||
});
|
||||
const data = await readJson(res);
|
||||
throwIfBad(res, data, "delete sync channel failed");
|
||||
return data as {
|
||||
ok?: boolean;
|
||||
deleted_id?: string;
|
||||
was_system_default?: boolean;
|
||||
recreated_default?: boolean;
|
||||
channel_id?: string;
|
||||
bindings_fixed?: number;
|
||||
agents_fixed?: number;
|
||||
heal_error?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export async function testSyncEndpoints(
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
| 默认同步通道默认启动 | 创建即 enabled;重启自动 Start |
|
||||
| **Z14c** ACL | 智能体 JWT 放行挂载 `online_db_id`(`agentOwnsOnlineDB`) |
|
||||
| Podman DNS / 脚本可执行位 | compose aliases;`restart.sh` 100755 |
|
||||
| **Z12h / Z12h-1 / Z12h-2** | `HealTenantSyncBind`:Ensure 默认通道 + 重挂 Agent/Binding;`is_system_default` 禁删;列表/换票/`agents/me`/ensure Binding 触发;见 §5.9 |
|
||||
| **Z12h / Z12h-1 / Z12h-2** | `HealTenantSyncBind`:Ensure 默认通道 + 重挂 Agent/Binding;默认同步**可删**,删后立即 Ensure+heal;列表/换票/`agents/me`/ensure Binding 触发;见 §5.9 |
|
||||
|
||||
> 产品一句:**账号已绑定 ⇒ 落点信息固定;通道没了平台自动补,终端无需手填 channel_id。**
|
||||
|
||||
@@ -552,13 +552,13 @@ POST .../schema
|
||||
| **Z12f** | **P1** | **开通 UX** | 启用智能体即可;DSN 用公司级默认 | **智建已落实** |
|
||||
| **Z12g** | **P1** | **默认同步通道默认启动** | 创建 `Enabled=true`;重启对 `IsSystemDefault` 自动 Start;控制台保存后自动启动 | **智建已落实**(`cb76824`) |
|
||||
| **Z12h** | **P0** | **通道误删自愈** | `HealTenantSyncBind`:Ensure 默认通道 + 重挂挂死 Agent/Binding(保留 `online_db_id`);触发:`ensureAgentSyncBind` / `agents/me` / 换票 / 通道·Binding 列表 / 删非默认通道后 | **智建已落实** |
|
||||
| **Z12h-1** | **P1** | **禁删或删后重建默认同步** | `is_system_default` **禁止删除**;删其它通道后 heal | **智建已落实** |
|
||||
| **Z12h-1** | **P1** | **禁删或删后重建默认同步** | `is_system_default` **可删**;删后立即 Ensure+heal 重建并重挂 | **智建已落实** |
|
||||
| **Z12h-2** | **P1** | **orphan Binding heal** | 列表 / Ensure Binding 时通道缺失 → 静默改挂默认通道 | **智建已落实** |
|
||||
|
||||
**缺口说明(2026-08-06 · 已关闭)**
|
||||
|
||||
- 原:SyncPage「通道已删除」、`ensureAgentSyncBind` 见非空 `channel_id` 即跳过。
|
||||
- 现:列表/换票等路径先 heal;默认通道不可删。生产须 **pull** 后验收第 4 条。
|
||||
- 现:列表/换票等路径先 heal;默认通道可删并立即重建。生产须 **pull** 后验收第 4 条。
|
||||
|
||||
**宇恒已做(2026-08-05)**
|
||||
|
||||
@@ -571,7 +571,7 @@ POST .../schema
|
||||
1. 新公司:只「启用智能体」,**不**点新建通道,换票已带 `channel_id`,宇恒可 drain。
|
||||
2. 账号 A 的本机库 push 不会出现在账号 B 的线上库;共享库仅在显式共享时可见。
|
||||
3. 用户全程无需 F12、无需手填 `YXD_SYNC_CHANNEL_ID`。
|
||||
4. **(Z12h)** 默认同步通道 API **不可删**;若 Binding/Agent 仍挂历史死 `channel_id`(或误删非默认通道)→ `agents/me` / 换票 / 打开 SyncPage → Ensure 默认通道并重挂,「通道已删除」红字消失;宇恒无需手填新 ID。
|
||||
4. **(Z12h)** 删除默认同步通道 → 立即重建并重挂;Binding/Agent 挂死 ID 时打开 SyncPage / 换票 / `agents/me` 亦会自愈,「通道已删除」红字消失;宇恒无需手填新 ID。
|
||||
|
||||
### 5.10 【双方代码已接 Z13】绑定流程简化:绑定码 / 手机号(2026-08-05)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user