Admin:按创建人隔离采集采购任务并增加管理员筛选 #127

Closed
opened 2026-08-10 22:51:00 +08:00 by ila · 3 comments
Owner

基本信息

  • 类型:需求 / 权限修复
  • 父级大工单:#14
  • 所属 MVP / 版本:#15 Admin 四模块可用闭环
  • 阶段:采集采购任务归属与数据隔离
  • 依赖:现有管理员/采购员固定角色、Client 当前归属权限、MySQL v5 生产结构

要解决什么

当前“采集采购”模块没有任务创建人字段,所有已登录用户使用同一套列表、统计、详情和删除接口,因此采购员能够查看其他用户创建的采购任务、价格、执行结果,也可能通过提交任务编号删除其他用户的任务。

只增加“创建人”筛选不能形成权限隔离:采购员仍可选择“全部”或直接修改 URL。需要把创建人作为稳定审计字段,并由后端按角色强制限制可见范围。

PDD 商品档案、采集状态和采集结果仍是全局共享数据;本工单隔离的是任务记录,不拆分 PDD 商品数据。

做什么 / 不做什么

做什么

  • 在生产 MySQL 增加可空的 tasks.created_by_user_id:
    • 新创建的采集、重新采集和采购任务必须写入当前登录用户 ID;
    • 历史任务保持 NULL,界面显示“历史任务”,不得猜测归属;
    • 增加用户外键和适合用户范围 + 更新时间分页的索引。
  • 权限策略:
    • 管理员可以查看全部任务;
    • 采购员只能查看 created_by_user_id = 当前用户 ID 的任务;
    • 历史 NULL 任务只允许管理员查看。
  • 管理员工具条增加“创建人”筛选:
    • 默认“全部创建人”;
    • 包含所有现有及已禁用采购员,保证历史记录可追溯;
    • 提供“历史任务”选项;
    • 采购员不显示该筛选控件,也不能通过 URL 扩大范围。
  • 管理员任务列表增加“创建人”列;采购员页面可不重复显示始终为自己的创建人。
  • 任务详情显示创建人;采购员直接访问别人的任务编号返回 404,避免泄露任务是否存在。
  • 批量删除在同一权限范围内执行:
    • 采购员只能删除自己创建的任务;
    • 请求中混入无权限或不存在的任务编号时整批拒绝,不得部分删除;
    • 管理员继续可以删除可见的任意任务。
  • 列表、状态统计、分页、详情和删除必须复用同一可见范围。
  • 所有任务创建入口统一传入当前用户并写创建人,包括:
    • PDD 批量创建采集任务;
    • PDD 单商品重新采集;
    • 后续批量重新采集入口;
    • 蝦皮/PDD ���联采集入口;
    • 顺运宝/PDD 关联采集入口;
    • 顺运宝创建采购任务。
  • 更新稳定需求、数据模型、界面和安全文档,增加角色隔离回归测试。

不做什么

  • 不按用户拆分 PDD 商品、规格、价格或采集状态;这些业务数据继续全局共享。
  • 不让采购员通过筛选查看其他用户任务。
  • 不把 live_confirmed_by 当作通用创建人;它只表示真实采购安全确认审计。
  • 不根据 assigned Client 当前负责人动态推断任务创建人,避免 Client 转交后历史任务归属漂移。
  • 不擅自给历史 NULL 任务回填用户。
  • 不修改 Client 四接口、领取规则、结果提交规则或任务 JSON。
  • 不增加复杂 RBAC、团队共享、代办或任务转交功能。

怎么做

  1. 增加 MySQL v6 migration:
    • created_by_user_id VARCHAR(191) NULL;
    • 外键指向 users(user_id);
    • 索引建议 (created_by_user_id, updated_at DESC, task_id DESC);
    • DDL 按项目规则可重放,全部完成并通过 schema 自检后才记录版本;
    • 历史 SQLite migrations 冻结,不改历史结构;SQLite 测试基线按项目既有兼容方式补充。
  2. 在 model.Task、Repository 任务插入与查询结构中增加创建人字段。
  3. 所有 Web 创建入口把 currentUser(c) 传到 Service;Service 校验登录用户为正常状态后,将其 UserID 写入任务。
  4. 引入统一的任务可见范围对象,例如管理员范围为空、采购员范围固定为当前 UserID;Repository 的列表、统计、详情和删除统一使用该范围。
  5. 管理员创建人筛选只能在管理员全量范围内进一步收窄;采购员提交的 created_by 查询参数必须忽略或拒绝,不能扩大范围。
  6. 任务列表查询 LEFT JOIN users 获取创建人用户名;历史 NULL 显示“历史任务”,禁用账号仍显示原用户名。
  7. 删除先在事务中锁定并核对全部去重后的任务编号均在当前范围,再执行删除;任一越权/不存在则整体回滚。
  8. Handler 对越权详情统一返回 404;不在错误消息中暴露创建人或任务内容。
  9. 增加迁移、Repository、Service、Handler 和模板测试;覆盖管理员/采购员、URL 伪造、统计分页、详情、批量删除、历史任务和所有创建入口。

预计修改文件:

  • admin/repository/mysql_db.go 及迁移/自检测试
  • admin/repository/db.go(仅测试/历史兼容基线所需)
  • admin/model/model.go
  • admin/repository/task.go
  • admin/service/task.go
  • PDD、蝦皮、顺运宝任务创建 Service 与 Handler
  • admin/handler/web/others.go
  • admin/templates/task/list.html
  • admin/templates/task/detail_modal.html
  • 相邻测试
  • docs/admin/01-requirements.md
  • docs/admin/03-data-model.md
  • docs/admin/05-ui-specification.md
  • docs/admin/06-quality-security.md
  • 完成后归档 docs/task/<工单号>-admin按创建人隔离采集采购任务.md

验收标准

  • 新建采集、重新采集和采购任务均记录当前登录用户 ID。
  • 管理员看到全部任务,并能按正常、禁用采购员及“历史任务”筛选。
  • 采购员列表只包含自己创建的任务,且没有创建人筛选控件。
  • 采购员伪造创建人查询参数仍无法看到其他用户或历史任务。
  • 列表、底部状态统计和分页使用完全相同的用户范围。
  • 管理员列表和任务详情显示创建人;历史 NULL 显示“历史任务”。
  • 采购员直接访问别人的任务详情返回 404。
  • 采购员删除自己的任务成功;混入别人的任务编号时整批拒绝且一条也不删除。
  • 管理员仍可删除任意可见任务。
  • PDD 商品、规格、价格和采集状态仍对所有正常用户共享。
  • 历史任务不被自动归属给任何采购员,只有管理员可见。
  • MySQL v5 → v6、重复执行迁移和 schema 自检通过;旧代码回���时可忽略新增可空列。
  • Client 四接口、领取与无条件接收结果契约保持不变。
  • Go 1.23.0 build、test、vet 通过;1366×768 下管理员筛选与表格可操作。

怎么验证

从 admin/ 目录执行:

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

使用独立 MySQL 8.4 测试库验证:

  1. 从 v5 schema 升级到 v6,核对字段、外键、索引和 schema version。
  2. 重复启动/迁移,确认 DDL 可重放且自检一致。
  3. 准备管理员、采购员 A、采购员 B、禁用采购员和历史 NULL 任务。
  4. 分别登录验证列表、筛选、统计、分页、详情 URL 伪造和批量删除。
  5. 从 PDD、重新采集、蝦皮、顺运宝和采购任务入口分别创建任务,核对创建人。
  6. 执行 Client 四接口契约回归,确认领取和结果提交不受 Web 可见范围影响。

风险和回退

  • 风险:只过滤列表但详情/删除仍越权。列表、统计、详情和删除必须复用统一服务端范围,并覆盖 URL/表单伪造测试。
  • 风险:���史任务错误归属导致数据泄露。历史记录保持 NULL,只对管理员显示。
  • 风险:Client 转交后任务归属漂移。创建人是不可变审计字段,不根据 Client 当前负责人重算。
  • 风险:遗漏���个任务创建入口导致新任务为 NULL。所有 Web 创建路径必须有测试,Service 对缺少有效 actor 的新任务创建请求直接拒绝。
  • 风险:生产迁移失败。v6 DDL 分步可重放,自检通过后才记版本;迁移前备份 schema。代码回退不删除新增可空列,旧版本可继续运行。
  • 回退:回退应用代码并保留 v6 可空字段、外键和索引,不修改或删除已写入的创建人审计数据。
## 基本信息 - 类型:需求 / 权限修复 - 父级大工单:#14 - 所属 MVP / 版本:#15 Admin 四模块可用闭环 - 阶段:采集采购任务归属与数据隔离 - 依赖:现有管理员/采购员固定角色、Client 当前归属权限、MySQL v5 生产结构 ## 要解决什么 当前“采集采购”模块没有任务创建人字段,所有已登录用户使用同一套列表、统计、详情和删除接口,因此采购员能够查看其他用户创建的采购任务、价格、执行结果,也可能通过提交任务编号删除其他用户的任务。 只增加“创建人”筛选不能形成权限隔离:采购员仍可选择“全部”或直接修改 URL。需要把创建人作为稳定审计字段,并由后端按角色强制限制可见范围。 PDD 商品档案、采集状态和采集结果仍是全局共享数据;本工单隔离的是任务记录,不拆分 PDD 商品数据。 ## 做什么 / 不做什么 ### 做什么 - 在生产 MySQL 增加可空的 `tasks.created_by_user_id`: - 新创建的采集、重新采集和采购任务必须写入当前登录用户 ID; - 历史任务保持 NULL,界面显示“历史任务”,不得猜测归属; - 增加用户外键和适合用户范围 + 更新时间分页的索引。 - 权限策略: - 管理员可以查看全部任务; - 采购员只能查看 `created_by_user_id = 当前用户 ID` 的任务; - 历史 NULL 任务只允许管理员查看。 - 管理员工具条增加“创建人”筛选: - 默认“全部创建人”; - 包含所有现有及已禁用采购员,保证历史记录可追溯; - 提供“历史任务”选项; - 采购员不显示该筛选控件,也不能通过 URL 扩大范围。 - 管理员任务列表增加“创建人”列;采购员页面可不重复显示始终为自己的创建人。 - 任务详情显示创建人;采购员直接访问别人的任务编号返回 404,避免泄露任务是否存在。 - 批量删除在同一权限范围内执行: - 采购员只能删除自己创建的任务; - 请求中混入无权限或不存在的任务编号时整批拒绝,不得部分删除; - 管理员继续可以删除可见的任意任务。 - 列表、状态统计、分页、详情和删除必须复用同一可见范围。 - 所有任务创建入口统一传入当前用户并写创建人,包括: - PDD 批量创建采集任务; - PDD 单商品重新采集; - 后续批量重新采集入口; - 蝦皮/PDD ���联采集入口; - 顺运宝/PDD 关联采集入口; - 顺运宝创建采购任务。 - 更新稳定需求、数据模型、界面和安全文档,增加角色隔离回归测试。 ### 不做什么 - 不按用户拆分 PDD 商品、规格、价格或采集状态;这些业务数据继续全局共享。 - 不让采购员通过筛选查看其他用户任务。 - 不把 `live_confirmed_by` 当作通用创建人;它只表示真实采购安全确认审计。 - 不根据 assigned Client 当前负责人动态推断任务创建人,避免 Client 转交后历史任务归属漂移。 - 不擅自给历史 NULL 任务回填用户。 - 不修改 Client 四接口、领取规则、结果提交规则或任务 JSON。 - 不增加复杂 RBAC、团队共享、代办或任务转交功能。 ## 怎么做 1. 增加 MySQL v6 migration: - `created_by_user_id VARCHAR(191) NULL`; - 外键指向 `users(user_id)`; - 索引建议 `(created_by_user_id, updated_at DESC, task_id DESC)`; - DDL 按项目规则可重放,全部完成并通过 schema 自检后才记录版本; - 历史 SQLite migrations 冻结,不改历史结构;SQLite 测试基线按项目既有兼容方式补充。 2. 在 `model.Task`、Repository 任务插入与查询结构中增加创建人字段。 3. 所有 Web 创建入口把 `currentUser(c)` 传到 Service;Service 校验登录用户为正常状态后,将其 UserID 写入任务。 4. 引入统一的任务可见范围对象,例如管理员范围为空、采购员范围固定为当前 UserID;Repository 的列表、统计、详情和删除统一使用该范围。 5. 管理员创建人筛选只能在管理员全量范围内进一步收窄;采购员提交的 `created_by` 查询参数必须忽略或拒绝,不能扩大范围。 6. 任务列表查询 LEFT JOIN `users` 获取创建人用户名;历史 NULL 显示“历史任务”,禁用账号仍显示原用户名。 7. 删除先在事务中锁定并核对全部去重后的任务编号均在当前范围,再执行删除;任一越权/不存在则整体回滚。 8. Handler 对越权详情统一返回 404;不在错误消息中暴露创建人或任务内容。 9. 增加迁移、Repository、Service、Handler 和模板测试;覆盖管理员/采购员、URL 伪造、统计分页、详情、批量删除、历史任务和所有创建入口。 预计修改文件: - `admin/repository/mysql_db.go` 及迁移/自检测试 - `admin/repository/db.go`(仅测试/历史兼容基线所需) - `admin/model/model.go` - `admin/repository/task.go` - `admin/service/task.go` - PDD、蝦皮、顺运宝任务创建 Service 与 Handler - `admin/handler/web/others.go` - `admin/templates/task/list.html` - `admin/templates/task/detail_modal.html` - 相邻测试 - `docs/admin/01-requirements.md` - `docs/admin/03-data-model.md` - `docs/admin/05-ui-specification.md` - `docs/admin/06-quality-security.md` - 完成后归档 `docs/task/<工单号>-admin按创建人隔离采集采购任务.md` ## 验收标准 - [x] 新建采集、重新采集和采购任务均记录当前登录用户 ID。 - [x] 管理员看到全部任务,并能按正常、禁用采购员及“历史任务”筛选。 - [x] 采购员列表只包含自己创建的任务,且没有创建人筛选控件。 - [x] 采购员伪造创建人查询参数仍无法看到其他用户或历史任务。 - [x] 列表、底部状态统计和分页使用完全相同的用户范围。 - [x] 管理员列表和任务详情显示创建人;历史 NULL 显示“历史任务”。 - [x] 采购员直接访问别人的任务详情返回 404。 - [x] 采购员删除自己的任务成功;混入别人的任务编号时整批拒绝且一条也不删除。 - [x] 管理员仍可删除任意可见任务。 - [x] PDD 商品、规格、价格和采集状态仍对所有正常用户共享。 - [x] 历史任务不被自动归属给任何采购员,只有管理员可见。 - [x] MySQL v5 → v6、重复执行迁移和 schema 自检通过;旧代码回���时可忽略新增可空列。 - [x] Client 四接口、领取与无条件接收结果契约保持不变。 - [x] Go 1.23.0 build、test、vet 通过;1366×768 下管理员筛选与表格可操作。 ## 怎么验证 从 `admin/` 目录执行: ```powershell $env:GOTOOLCHAIN='go1.23.0' gofmt -l . go build ./... go test ./... -count=1 go vet ./... Remove-Item Env:GOTOOLCHAIN ``` 使用独立 MySQL 8.4 测试库验证: 1. 从 v5 schema 升级到 v6,核对字段、外键、索引和 schema version。 2. 重复启动/迁移,确认 DDL 可重放且自检一致。 3. 准备管理员、采购员 A、采购员 B、禁用采购员和历史 NULL 任务。 4. 分别登录验证列表、筛选、统计、分页、详情 URL 伪造和批量删除。 5. 从 PDD、重新采集、蝦皮、顺运宝和采购任务入口分别创建任务,核对创建人。 6. 执行 Client 四接口契约回归,确认领取和结果提交不受 Web 可见范围影响。 ## 风险和回退 - 风险:只过滤列表但详情/删除仍越权。列表、统计、详情和删除必须复用统一服务端范围,并覆盖 URL/表单伪造测试。 - 风险:���史任务错误归属导致数据泄露。历史记录保持 NULL,只对管理员显示。 - 风险:Client 转交后任务归属漂移。创建人是不可变审计字段,不根据 Client 当前负责人重算。 - 风险:遗漏���个任务创建入口导致新任务为 NULL。所有 Web 创建路径必须有测试,Service 对缺少有效 actor 的新任务创建请求直接拒绝。 - 风险:生产迁移失败。v6 DDL 分步可重放,自检通过后才记版本;迁移前备份 schema。代码回退不删除新增可空列,旧版本可继续运行。 - 回退:回退应用代码并保留 v6 可空字段、外键和索引,不修改或删除已写入的创建人审计数据。
Author
Owner

实施进度:已完成 #127 主体实现。增加 MySQL v6 的 created_by_user_id、外键和索引;所有 Web 任务创建入口写当前用户;采购员列表、统计、分页、详情、删除固定为本人范围;管理员可筛选创建人和历史任务;混合越权删除整体回滚。已补迁移、入口、权限、模板测试与 Admin 文档。Go 1.23.0 的 test、vet、build 已通过。当前环境未启用独立 _test MySQL,真实 MySQL 8.4 迁移用例已写入但尚未实跑,不会用生产库代替测试库。实现细节:删除采用事务内带权限范围的 DELETE,并以受影响行数核对完整性;任一编号不存在或越权即回滚,与工单要求的全有或全无结果一致。

实施进度:已完成 #127 主体实现。增加 MySQL v6 的 created_by_user_id、外键和索引;所有 Web 任务创建入口写当前用户;采购员列表、统计、分页、详情、删除固定为本人范围;管理员可筛选创建人和历史任务;混合越权删除整体回滚。已补迁移、入口、权限、模板测试与 Admin 文档。Go 1.23.0 的 test、vet、build 已通过。当前环境未启用独立 _test MySQL,真实 MySQL 8.4 迁移用例已写入但尚未实跑,不会用生产库代替测试库。实现细节:删除采用事务内带权限范围的 DELETE,并以受影响行数核对完整性;任一编号不存在或越权即回滚,与工单要求的全有或全无结果一致。
Author
Owner

实施完成,状态:待用户验收。实现提交 a9f22b9;归档提交 dbe4779;归档 docs/task/127-admin按创建人隔离采集采购任务.md。Go 1.23.0 全包 test/vet/build 通过;真实 MySQL 8.4 隔离库 v5→v6、断点重跑和错误结构拒绝 2 项通过;任务创建入口、采购员范围、管理员筛选、越权详情、原子删除、禁用账号选项 6 项定向集成测试通过。生产 autobuy 数据未用于测试。未验证项仅为 1366×768 和双浏览器 Session 的人工视觉/操作验收。

实施完成,状态:待用户验收。实现提交 a9f22b9;归档提交 dbe4779;归档 docs/task/127-admin按创建人隔离采集采购任务.md。Go 1.23.0 全包 test/vet/build 通过;真实 MySQL 8.4 隔离库 v5→v6、断点重跑和错误结构拒绝 2 项通过;任务创建入口、采购员范围、管理员筛选、越权详情、原子删除、禁用账号选项 6 项定向集成测试通过。生产 autobuy 数据未用于测试。未验证项仅为 1366×768 和双浏览器 Session 的人工视觉/操作验收。
Author
Owner

用户已明确验收通过。验收清单已回填,本工单关闭。

用户已明确验收通过。验收清单已回填,本工单关闭。
ila closed this issue 2026-08-10 23:25:21 +08:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: chengma/cmautobuy#127