Skip to content

[Enhancement]: 允许删除 setup 创建的首个存储策略和策略组 #565

Description

@AptS-1547

Problem

AsterDrive 现在已经是平台化产品,首次 setup 也已经明确拆成 needs_admin -> needs_storage -> ready 三步状态机。存储策略和策略组是管理员管理的普通拓扑对象,不应因为“这是初始化时创建的第一个对象”而永久不可删除。

当前实现仍保留了早期单机 bootstrap 假设:

  • src/services/storage_policy/policy/policies.rs 用固定的 SYSTEM_STORAGE_POLICY_ID = 1 永久拒绝删除内置系统存储策略;
  • 删除唯一默认策略时直接拒绝;
  • 删除唯一默认策略组时直接拒绝;
  • lock_default_group_assignment 还把策略 ID 1 当作默认策略/策略组变更的数据库锁行;
  • 前端和文档把默认策略/策略组描述成必须长期保留的对象。

这会把“完成一次 setup”误读成“永久保留第一条策略”。对 Kubernetes 用户尤其不合适:常见部署会先通过 setup 创建一条临时或占位策略,随后切换到共享 PVC、S3 兼容对象存储或远程 follower。当前限制会留下清理路径被永久阻断的死配置,并让管理员误以为首条策略是系统内建资源,而不是可替换的部署拓扑。

相关背景:#444 正在重做策略组路由模型,本 issue 先把策略/策略组生命周期边界定清,避免新模型继续携带固定首条记录假设。

Desired behavior

  1. 首次 setup 创建的存储策略和策略组在 setup 完成后按普通资源处理,不按创建顺序或固定 ID 特判。
  2. 管理员可以删除首条策略;如果它仍是唯一默认策略,删除成功后系统应回到 needs_storage,而不是返回“删除唯一默认策略被拒绝”。重新创建并设为默认策略、完成默认策略组配置后,再回到 ready
  3. 管理员可以删除首个/唯一默认策略组,前提是没有用户或团队绑定。删除后系统应回到 needs_storage,并在 setup 状态接口、管理端和 readiness 语义中保持一致。
  4. 当存在其他策略或策略组时,删除默认对象仍需先完成默认对象切换,或在同一 writer 事务中原子选择明确的替代默认对象;不得短暂产生两个默认项或让跨 Primary 快照看到半成品拓扑。
  5. 删除策略组的现有绑定保护继续有效:仍被用户或团队引用时必须先迁移绑定,不得因为“首个对象可删”而级联清空业务绑定。
  6. 删除策略的现有数据保护继续有效:blob、策略组项、未完成上传 session 和 force 清理语义保持不变。只有在这些引用按现有流程解除后才允许删除。
  7. 删除最后一个可用策略/策略组后,UI 必须明确提示上传和依赖默认策略组的流程会暂停,指导管理员重新完成 storage setup;不再展示“系统内建策略不可删除”这类误导文案。

Implementation requirements

  • 移除基于 SYSTEM_STORAGE_POLICY_ID 的永久删除保护;如果 ID 1 仍被迁移或兼容逻辑使用,必须与“是否可删除”解耦。
  • 重做默认策略/策略组变更的锁定锚点。不得继续锁定可能已被管理员删除的策略行;使用稳定存在的 setup/拓扑锁资源或数据库原生 advisory lock,并覆盖策略 1 已删除后重新创建默认策略的并发场景。
  • 删除、默认切换、setup 状态计算、策略快照 reload、跨实例 topology reload event 必须在 writer 事务和提交后刷新边界内保持一致。
  • 审查并更新 Rust service/repository、REST 错误映射、前端删除按钮/确认文案、中文和英文 i18n、管理 API 文档与部署/首次 setup 文档。不要只隐藏前端按钮,服务端必须先执行权限和生命周期判断。
  • 不引入“按 ID 大小判断首条”“按 created_at 猜 bootstrap”的新特判;生命周期应由当前默认状态、真实引用和 setup 状态决定。

Acceptance criteria

  • 新数据库完成首次 setup 后,首条策略和首个策略组可以通过管理 API/UI 删除;删除顺序和必要的迁移提示清晰可执行。
  • 只有一个默认策略或策略组、且没有数据/绑定引用时,删除返回成功,/auth/check、setup state、readiness 和管理 UI 均反映 needs_storage
  • 删除后重新创建并设为默认策略/策略组,setup 可再次完成并回到 ready;不依赖 ID 1 重新出现。
  • 策略 1 已删除后,并发创建/切换默认策略仍使用稳定锁正确串行化;SQLite、PostgreSQL、MySQL 的事务语义分别得到验证。
  • blob、策略组项、上传 session、用户绑定、团队绑定等引用保护及 force=true 的现有行为回归测试保持通过。
  • 多 Primary/Kubernetes 共享数据库场景验证删除、setup 状态和 topology reload 不产生过期策略快照或错误默认项。
  • Rust service/integration tests、前端 focused tests、OpenAPI/生成类型(若契约变化)和文档检查均通过;补齐删除唯一默认对象、重新 setup、并发锁定的回归覆盖。

Non-goals

  • 不因本 issue 自动迁移已有 blob,也不绕过现有 storage migration 流程。
  • 仍有 blob、活动上传或用户/团队绑定的对象,删除请求继续返回引用保护错误。
  • 不要求策略组可以保存零条规则;“首个策略组可删除”和“启用中的策略组必须有可路由规则”是两个独立约束。

Category

Admin features

Contribution

  • I am willing to help implement this feature
  • I can help test and provide feedback

Checklist

  • I have searched existing issues for duplicates
  • I have checked the current setup, policy, and policy-group contracts
  • I have removed secrets and private credentials from this report

Metadata

Metadata

Assignees

No one assigned

    Labels

    EnhancementNew feature or requestPriority: HighHigh priority issueRustPull requests that update Rust codeScope: Admin UIAdministrator-facing frontend workflows and management interfacesScope: RuntimeRuntime lifecycle, async execution, tasks, and process-level performanceScope: StorageStorage policies, connectors, drivers, provider capabilities, and storage backendsTypeScriptPull requests that update JavaScript code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions