# 软删除标准化改造（RPC + RLS）操作文档

## 摘要
本次对管理端涉及的“删除”相关数据库逻辑进行标准化改造：
- 将各模块 RPC 删除行为由物理删除统一切换为软删除（`UPDATE ... SET deleted_at = now(), deleted_by = ...`）；
- 对存在依赖关系的对象补齐级联软删除（如：删除客服话术分类时同步软删其下话术等）；
- 对各模块 RLS 策略补齐 `deleted_at IS NULL` 过滤条件，使业务侧默认不可见已软删数据；
- 提供执行顺序建议，确保先补齐字段/索引，再应用 RLS/RPC 逻辑。

## 动机
- 统一删除语义，避免误操作导致数据不可恢复。
- 支持审计追溯（删除时间、删除人）。
- 通过 RLS 形成“默认过滤”，降低前端/服务层遗漏过滤导致的数据暴露风险。

## 影响范围
- **数据库**：涉及多个域（admin/cms/decoration/delivery/distribution/finance/kefu/user/auth）的 RLS 与 RPC 文件；新增/补齐软删除字段与索引（迁移脚本）。
- **管理端功能**：所有调用相关 `rpc_admin_*_delete*` 的管理页面，其删除行为从“物理删除”变更为“逻辑删除”。
- **数据可见性**：RLS 在 SELECT 场景默认排除 `deleted_at IS NOT NULL` 的记录，前端列表/查询将不再返回已软删数据。

## 变更清单
> 本次变更以 `docs/sql/00_meta/12_soft_delete_standard.md` 作为软删除标准口径。

### 新增文件
- `docs/sql/00_meta/11_roles_and_permissions_strategy.md`
- `docs/sql/00_meta/12_soft_delete_standard.md`
- `docs/sql/10_schema/99_soft_delete_migration_v1.sql`

### 修改文件
#### RLS（补齐 `deleted_at IS NULL`）
- `docs/sql/20_rls/admin/ml_system_configs_rls_v1.sql`
- `docs/sql/20_rls/cms/ml_cms_rls_v1.sql`
- `docs/sql/20_rls/decoration/ml_decoration_rls_v1.sql`
- `docs/sql/20_rls/delivery/ak_delivery_rls_v1.sql`
- `docs/sql/20_rls/distribution/ml_distribution_rls_v1.sql`
- `docs/sql/20_rls/finance/ml_extract_rls_v1.sql`
- `docs/sql/20_rls/finance/ml_invoices_rls_v1.sql`
- `docs/sql/20_rls/finance/ml_user_bill_rls_v1.sql`
- `docs/sql/20_rls/finance/ml_user_recharge_rls_v1.sql`

#### RPC（删除改为软删除 + deleted_by 审计 + 必要时级联）
- `docs/sql/30_rpc/auth/rpc_admin_delete_permission_v1.sql`
- `docs/sql/30_rpc/auth/rpc_admin_delete_role_v1.sql`
- `docs/sql/30_rpc/cms/rpc_admin_article_category_delete_v1.sql`
- `docs/sql/30_rpc/cms/rpc_admin_article_delete_v1.sql`
- `docs/sql/30_rpc/decoration/rpc_admin_delete_diy_page_v1.sql`
- `docs/sql/30_rpc/delivery/rpc_admin_delete_delivery_staff_v1.sql`
- `docs/sql/30_rpc/delivery/rpc_admin_delete_delivery_station_v1.sql`
- `docs/sql/30_rpc/distribution/rpc_admin_delete_agent_v1.sql`
- `docs/sql/30_rpc/distribution/rpc_admin_delete_division_v1.sql`
- `docs/sql/30_rpc/kefu/rpc_admin_kefu_account_delete_v1.sql`
- `docs/sql/30_rpc/kefu/rpc_admin_kefu_auto_reply_delete_v1.sql`
- `docs/sql/30_rpc/kefu/rpc_admin_kefu_word_category_delete_v1.sql`
- `docs/sql/30_rpc/kefu/rpc_admin_kefu_word_delete_v1.sql`
- `docs/sql/30_rpc/product/rpc_admin_category_delete_v1.sql`
- `docs/sql/30_rpc/user/rpc_admin_user_group_delete_v1.sql`
- `docs/sql/30_rpc/user/rpc_admin_user_label_delete_v1.sql`
- `docs/sql/30_rpc/user/rpc_admin_user_level_delete_v1.sql`

#### 前端（与删除相关页面适配/受影响）
- `pages/mall/admin/setting/delivery/station.uvue`
- `pages/mall/admin/setting/interface/storage.uvue`

### 删除文件
- 无

## 兼容性与风险
- **数据不可再“物理删除”释放唯一约束**：软删除后记录仍在表中，若存在唯一索引且未做“partial unique（仅对未删除记录生效）”，可能导致“删除后无法新建同名/同 key”问题，需要按业务决定是否改索引策略。
- **RLS 策略一致性要求更高**：补齐 `deleted_at IS NULL` 后，任何期望访问回收站数据的场景都需要新增专用策略或通过管理端特权 RPC 实现。
- **级联链路需覆盖完整**：部分对象存在多级依赖（分类 -> 子项 -> 关联），若漏掉级联，会出现“父对象不可见但子对象仍可见/仍占用数据”的不一致。

## 回滚方案
- **仅回滚删除语义（不建议长期保持）**：
  - 将相关 `rpc_admin_*_delete*` 还原为物理删除（`DELETE FROM ...`）并移除 `deleted_at/deleted_by` 写入逻辑。
- **回滚 RLS 过滤**：
  - 在对应 `docs/sql/20_rls/**` 中移除 `AND deleted_at IS NULL`（或恢复到改造前版本）。
- **回滚 schema 迁移**：
  - 不建议回滚 `deleted_*` 字段（会丢失审计数据）；如必须回滚，应先评估依赖与历史数据。

## 验证方式
- **字段与索引**：执行 `docs/sql/10_schema/99_soft_delete_migration_v1.sql` 后，确认涉及表存在 `deleted_at/deleted_by` 字段，以及 `idx_<table>_soft_delete` 索引。
- **RLS 过滤生效**：对任一涉及表执行查询（按当前角色权限），确认已软删的数据默认不返回。
- **RPC 删除行为**：调用任一删除 RPC 后：
  - 记录未被物理删除；
  - `deleted_at` 被写入当前时间；
  - `deleted_by` 被写入执行删除的管理员用户 ID；
  - 对需要级联的对象，子表记录同步被标记软删。

## 关联文档
- `docs/project_spec/AGENT_PROJECT_SPEC.md`
- `docs/sql/00_meta/12_soft_delete_standard.md`
