Admin:档口入库码删除改为物理删除 #318

Open
opened 2026-08-28 10:49:35 +08:00 by ila · 2 comments
Owner

基本信息

  • 类型:需求
  • 父级大工单:#14
  • 所属 MVP / 版本:#224 Admin 档口入库码回写
  • 阶段:阶段 14:删除语义简化
  • 原始需求来源:用户于 2026-08-28 要求“档口入库码的删除改成物理删除”,并确认“正在回写禁止删除,其他状态物理删除”
  • 前置工单:#238(本工单替代其后续删除行为,保留已有 schema 与历史数据兼容)
  • 是否允许并行:否。删除逻辑与后台回写共享同一业务表,需要独立验证事务竞争。
  • 状态:待验收

要解决什么

当前页面删除只写入 deleted_at/deleted_by_user_id,重复导入时恢复旧记录。内部业务已经确认不再需要新删除记录的软删除恢复,需要把页面删除改成不可恢复的物理删除,同时不能让正在发送顺运宝请求的 applying 记录失去本地收尾依据。

做什么 / 不做什么

做:

  • 当前页面可见记录中,除 applying 外的所有状态允许物理删除。
  • 在同一事务中锁定并核对全部选中记录;任一记录不存在、状态已变化或处于 applying 时整批回滚。
  • queued 记录若尚未被后台领取可以删除;若已被领取并变为 applying,删除整批拒绝。
  • 删除确认和成功反馈明确“永久删除、不可恢复、不会撤销顺运宝远端快递单号”。
  • 物理删除后重复导入相同业务键创建新记录。
  • 更新 Admin 数据模型和界面规范 Wiki,并同步本地只读镜像。

不做:

  • 不删除或迁移现有 deleted_at/deleted_by_user_id 字段。
  • 不清理生产库既有软删除记录;旧记录仍由现有兼容导入逻辑处理。
  • 不允许删除 applying 记录,不取消已经开始的顺运宝远端请求。
  • 不撤销顺运宝已经写入的快递单号,不部署生产,不执行生产数据删除。

已确认的实现方案

  • Repository 新增事务化物理删除:按稳定 ID 排序 SELECT ... FOR UPDATE,核对数量和状态,再执行参数化 DELETE;任何冲突回滚整批。
  • Service 保留 ID 去重和当前页批量上限,改调物理删除;不再保存删除账号和时间。
  • Handler 与模板沿用现有 POST、CSRF 和二次确认,只改不可恢复语义及错误反馈。
  • 不新增 schema 版本;保留 v24 字段是历史兼容,不再作为新删除入口使用。
  • 设计证据:复用现有列表、勾选和确认框,仅替换已确认的数据行为与提示语,不新增页面或主要交互;用户于 2026-08-28 确认上述边界。

预计修改:

  • admin/repository/inner_code.go
  • admin/repository/inner_code_test.go
  • admin/service/inner_code_delete.go
  • admin/handler/web/inner_code.go
  • admin/templates/inner_code/list.html
  • admin/inner_code_template_test.go
  • 必要的 Admin 删除链路测试
  • Wiki:Admin-Data-Model、Admin-UI-Specification 及对应 docs/admin/ 镜像

验收标准

  • pending/ready/queued/updated/already_filled/skipped/failed/needs_check 可物理删除,数据库行不再存在。
  • 选中集合包含 applying 时整批拒绝,其他记录不被部分删除。
  • ID 不存在或并发状态变化时整批回滚。
  • queued 与后台领取竞争时,只能出现“删除成功且未领取”或“已领取并拒绝删除”,不能删除已经领取的记录。
  • 删除确认写明数量、不可恢复和不撤销远端值;成功提示不再宣称可恢复。
  • 新删除记录重新导入时按新增处理;既有软删除历史兼容不被迁移或清理。
  • 固定 Go 1.23.0 build/test/vet 通过,受影响模板和 repository/service 测试通过。
  • Wiki 在线更新、回读 revision、镜像同步检查通过。

验证方式

在 admin/ 执行:

$env:GOTOOLCHAIN="go1.23.0"
go test ./... -count=1
go build ./...
go vet ./...
Remove-Item Env:GOTOOLCHAIN

并执行受影响 repository/service/template 单测;MySQL _test 环境可用时验证 SELECT ... FOR UPDATE 与后台领取竞争。

风险和回退

  • 物理删除不可恢复;确认框必须明确说明。
  • 删除已完成或需核对记录会丢失本地匹配/回写信息,但用户已接受内部系统的简化语义;远端值不撤销。
  • applying 记录若被删除会导致远端结果无法收尾,因此固定禁止。
  • 回退代码可恢复未来使用软删除,但不能恢复已经物理删除的数据。

Gitea 操作说明

当前 Agent 工具集中未提供项目 Gitea MCP,因此按仓库规则回退到 Gitea API 创建和更新本工单;凭据仅从进程环境读取,未写入仓库或工单。

## 基本信息 - 类型:需求 - 父级大工单:#14 - 所属 MVP / 版本:#224 Admin 档口入库码回写 - 阶段:阶段 14:删除语义简化 - 原始需求来源:用户于 2026-08-28 要求“档口入库码的删除改成物理删除”,并确认“正在回写禁止删除,其他状态物理删除” - 前置工单:#238(本工单替代其后续删除行为,保留已有 schema 与历史数据兼容) - 是否允许并行:否。删除逻辑与后台回写共享同一业务表,需要独立验证事务竞争。 - 状态:待验收 ## 要解决什么 当前页面删除只写入 `deleted_at/deleted_by_user_id`,重复导入时恢复旧记录。内部业务已经确认不再需要新删除记录的软删除恢复,需要把页面删除改成不可恢复的物理删除,同时不能让正在发送顺运宝请求的 `applying` 记录失去本地收尾依据。 ## 做什么 / 不做什么 做: - 当前页面可见记录中,除 `applying` 外的所有状态允许物理删除。 - 在同一事务中锁定并核对全部选中记录;任一记录不存在、状态已变化或处于 `applying` 时整批回滚。 - `queued` 记录若尚未被后台领取可以删除;若已被领取并变为 `applying`,删除整批拒绝。 - 删除确认和成功反馈明确“永久删除、不可恢复、不会撤销顺运宝远端快递单号”。 - 物理删除后重复导入相同业务键创建新记录。 - 更新 Admin 数据模型和界面规范 Wiki,并同步本地只读镜像。 不做: - 不删除或迁移现有 `deleted_at/deleted_by_user_id` 字段。 - 不清理生产库既有软删除记录;旧记录仍由现有兼容导入逻辑处理。 - 不允许删除 `applying` 记录,不取消已经开始的顺运宝远端请求。 - 不撤销顺运宝已经写入的快递单号,不部署生产,不执行生产数据删除。 ## 已确认的实现方案 - Repository 新增事务化物理删除:按稳定 ID 排序 `SELECT ... FOR UPDATE`,核对数量和状态,再执行参数化 `DELETE`;任何冲突回滚整批。 - Service 保留 ID 去重和当前页批量上限,改调物理删除;不再保存删除账号和时间。 - Handler 与模板沿用现有 POST、CSRF 和二次确认,只改不可恢复语义及错误反馈。 - 不新增 schema 版本;保留 v24 字段是历史兼容,不再作为新删除入口使用。 - 设计证据:复用现有列表、勾选和确认框,仅替换已确认的数据行为与提示语,不新增页面或主要交互;用户于 2026-08-28 确认上述边界。 预计修改: - `admin/repository/inner_code.go` - `admin/repository/inner_code_test.go` - `admin/service/inner_code_delete.go` - `admin/handler/web/inner_code.go` - `admin/templates/inner_code/list.html` - `admin/inner_code_template_test.go` - 必要的 Admin 删除链路测试 - Wiki:`Admin-Data-Model`、`Admin-UI-Specification` 及对应 `docs/admin/` 镜像 ## 验收标准 - [x] `pending/ready/queued/updated/already_filled/skipped/failed/needs_check` 可物理删除,数据库行不再存在。 - [x] 选中集合包含 `applying` 时整批拒绝,其他记录不被部分删除。 - [x] ID 不存在或并发状态变化时整批回滚。 - [x] `queued` 与后台领取竞争时,只能出现“删除成功且未领取”或“已领取并拒绝删除”,不能删除已经领取的记录。 - [x] 删除确认写明数量、不可恢复和不撤销远端值;成功提示不再宣称可恢复。 - [x] 新删除记录重新导入时按新增处理;既有软删除历史兼容不被迁移或清理。 - [x] 固定 Go 1.23.0 build/test/vet 通过,受影响模板和 repository/service 测试通过。 - [x] Wiki 在线更新、回读 revision、镜像同步检查通过。 ## 验证方式 在 `admin/` 执行: ```powershell $env:GOTOOLCHAIN="go1.23.0" go test ./... -count=1 go build ./... go vet ./... Remove-Item Env:GOTOOLCHAIN ``` 并执行受影响 repository/service/template 单测;MySQL `_test` 环境可用时验证 `SELECT ... FOR UPDATE` 与后台领取竞争。 ## 风险和回退 - 物理删除不可恢复;确认框必须明确说明。 - 删除已完成或需核对记录会丢失本地匹配/回写信息,但用户已接受内部系统的简化语义;远端值不撤销。 - `applying` 记录若被删除会导致远端结果无法收尾,因此固定禁止。 - 回退代码可恢复未来使用软删除,但不能恢复已经物理删除的数据。 ## Gitea 操作说明 当前 Agent 工具集中未提供项目 Gitea MCP,因此按仓库规则回退到 Gitea API 创建和更新本工单;凭据仅从进程环境读取,未写入仓库或工单。
Author
Owner

实施细节补充:为兼容现有 SQLite 单测且保持生产 MySQL 的原子竞争语义,Repository 使用事务内状态预检,随后执行带 deleted_at IS NULL AND status<>'applying' 条件的单条参数化 DELETE,并严格核对影响行数。后台领取先发生时 DELETE 不命中并整批回滚;DELETE 先发生时领取不命中。该方式替代正文中的显式 SELECT ... FOR UPDATE,不改变用户确认的外部行为或安全边界。

实施细节补充:为兼容现有 SQLite 单测且保持生产 MySQL 的原子竞争语义,Repository 使用事务内状态预检,随后执行带 `deleted_at IS NULL AND status<>'applying'` 条件的单条参数化 `DELETE`,并严格核对影响行数。后台领取先发生时 DELETE 不命中并整批回滚;DELETE 先发生时领取不命中。该方式替代正文中的显式 `SELECT ... FOR UPDATE`,不改变用户确认的外部行为或安全边界。
Author
Owner

最终实施与验证证据

  • 最终行为:除 applying 外的可见状态执行物理删除;选中集合包含正在回写、已不存在或并发变化记录时整批回滚。queued 尚未领取时可删,领取后因状态变为 applying 而拒绝。
  • 页面:沿用现有 POST、CSRF、勾选和二次确认;确认文案明确“永久删除、不可恢复、不撤销顺运宝远端值”,成功反馈不再宣称可恢复。
  • 数据兼容:没有新增 schema;v24 字段和既有软删除记录保留,未执行存量清理。新物理删除记录重新导入按新增处理。
  • 实现提交:e784806,已推送到 origin/main。
  • 固定 Go 1.23:go test ./... -count=1、go build ./...、go vet ./... 全部通过。
  • Harness:44 项测试通过,python dev_scripts/harness.py check --strict 通过。
  • Wiki:Admin-Data-Model revision 4b1088936cfa06915528a6bcfa09d1ef88e8dbbe;Admin-UI-Specification revision 9643e885d9ae16a82080552fdf3751e4328afb19。两页已通过 Harness 导出;UI 页 sync --check 通过。全量 34 页在线检查曾因 Gitea TLS/读取超时停止,但本工单两页已单独验证。
  • MySQL:增加真实 MySQL _test 集成测试,覆盖物理删除、重新导入为新增、applying 整批拒绝;当前环境未提供 CMAUTOBUY_MYSQL_TEST=1 和独立 _test 库,因此该测试在全量测试中按现有门禁跳过。未连接或清理生产数据库。
  • 未执行:生产部署、生产数据删除、真实顺运宝写入。
  • 长期文档影响已处理;按当前工作流不创建 docs/task 快照。

状态更新为“待验收”,工单保持打开。

## 最终实施与验证证据 - 最终行为:除 `applying` 外的可见状态执行物理删除;选中集合包含正在回写、已不存在或并发变化记录时整批回滚。`queued` 尚未领取时可删,领取后因状态变为 `applying` 而拒绝。 - 页面:沿用现有 POST、CSRF、勾选和二次确认;确认文案明确“永久删除、不可恢复、不撤销顺运宝远端值”,成功反馈不再宣称可恢复。 - 数据兼容:没有新增 schema;v24 字段和既有软删除记录保留,未执行存量清理。新物理删除记录重新导入按新增处理。 - 实现提交:`e784806`,已推送到 `origin/main`。 - 固定 Go 1.23:`go test ./... -count=1`、`go build ./...`、`go vet ./...` 全部通过。 - Harness:44 项测试通过,`python dev_scripts/harness.py check --strict` 通过。 - Wiki:`Admin-Data-Model` revision `4b1088936cfa06915528a6bcfa09d1ef88e8dbbe`;`Admin-UI-Specification` revision `9643e885d9ae16a82080552fdf3751e4328afb19`。两页已通过 Harness 导出;UI 页 `sync --check` 通过。全量 34 页在线检查曾因 Gitea TLS/读取超时停止,但本工单两页已单独验证。 - MySQL:增加真实 MySQL `_test` 集成测试,覆盖物理删除、重新导入为新增、`applying` 整批拒绝;当前环境未提供 `CMAUTOBUY_MYSQL_TEST=1` 和独立 `_test` 库,因此该测试在全量测试中按现有门禁跳过。未连接或清理生产数据库。 - 未执行:生产部署、生产数据删除、真实顺运宝写入。 - 长期文档影响已处理;按当前工作流不创建 `docs/task` 快照。 状态更新为“待验收”,工单保持打开。
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: OPC/cmautobuy#318