Files
junhong_cmp_fiber/openspec/specs/iot-card-import-task/spec.md
huang a924e63e68
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m42s
feat: 实现物联网卡独立管理和批量导入功能
新增物联网卡独立管理模块,支持单卡查询、批量导入和状态管理。主要变更包括:

功能特性:
- 新增物联网卡 CRUD 接口(查询、分页列表、删除)
- 支持 CSV/Excel 批量导入物联网卡
- 实现异步导入任务处理和进度跟踪
- 新增 ICCID 号码格式校验器(支持 Luhn 算法)
- 新增 CSV 文件解析工具(支持编码检测和错误处理)

数据库变更:
- 移除 iot_card 和 device 表的 owner_id/owner_type 字段
- 新增 iot_card_import_task 导入任务表
- 为导入任务添加运营商类型字段

测试覆盖:
- 新增 IoT 卡 Store 层单元测试
- 新增 IoT 卡导入任务单元测试
- 新增 IoT 卡集成测试(包含导入流程测试)
- 新增 CSV 工具和 ICCID 校验器测试

文档更新:
- 更新 OpenAPI 文档(新增 7 个 IoT 卡接口)
- 归档 OpenSpec 变更提案
- 更新 API 文档规范和生成器指南

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-24 11:03:43 +08:00

6.3 KiB

iot-card-import-task Specification

Purpose

TBD - created by archiving change iot-card-standalone-management. Update Purpose after archive.

Requirements

Requirement: 导入任务实体定义

系统 SHALL 定义 IoT 卡导入任务(IotCardImportTask)实体,用于跟踪 IoT 卡批量导入的进度和结果。

实体字段:

任务信息:

  • id: 任务 ID(主键,BIGINT)
  • task_no: 任务编号(VARCHAR(50),唯一,格式: IMP-YYYYMMDD-XXXXXX)
  • status: 任务状态(INT,1-待处理 2-处理中 3-已完成 4-失败)

导入参数:

  • carrier_id: 运营商 ID(BIGINT,必填)
  • batch_no: 批次号(VARCHAR(100),可选)
  • file_name: 原始文件名(VARCHAR(255),可选)

进度统计:

  • total_count: 总数(INT,CSV 文件总行数)
  • success_count: 成功数(INT,成功导入的 ICCID 数量)
  • skip_count: 跳过数(INT,因重复等原因跳过的数量)
  • fail_count: 失败数(INT,因格式错误等原因失败的数量)

结果详情:

  • skipped_items: 跳过记录详情(JSONB,结构: [{line, iccid, reason}])
  • failed_items: 失败记录详情(JSONB,结构: [{line, iccid, reason}])

时间和错误:

  • started_at: 开始处理时间(TIMESTAMP,可空)
  • completed_at: 完成时间(TIMESTAMP,可空)
  • error_message: 任务级错误信息(TEXT,可空,如文件解析失败等)

系统字段:

  • shop_id: 店铺 ID(BIGINT,可空,记录发起导入的店铺)
  • created_at: 创建时间(TIMESTAMP,自动填充)
  • updated_at: 更新时间(TIMESTAMP,自动填充)
  • creator: 创建人 ID(BIGINT)
  • updater: 更新人 ID(BIGINT)

Scenario: 创建导入任务

  • WHEN 管理员上传 CSV 文件发起导入
  • THEN 系统创建导入任务记录,status 为 1(待处理),total_count 为 CSV 行数,返回任务 ID

Scenario: 导入任务开始处理

  • WHEN Worker 开始处理导入任务
  • THEN 系统将任务 status 从 1(待处理) 变更为 2(处理中),started_at 记录当前时间

Scenario: 导入任务完成

  • WHEN Worker 完成导入任务处理
  • THEN 系统将任务 status 变更为 3(已完成),completed_at 记录当前时间,更新 success_countskip_countfail_count

Scenario: 导入任务失败

  • WHEN Worker 处理导入任务时发生严重错误(如文件损坏)
  • THEN 系统将任务 status 变更为 4(失败),error_message 记录错误信息

Requirement: 导入任务状态流转

系统 SHALL 管理导入任务的状态流转,确保状态变更符合业务规则。

状态定义:

  • 1-待处理: 任务已创建,等待 Worker 处理
  • 2-处理中: Worker 正在处理导入
  • 3-已完成: 导入处理完成(可能有部分失败)
  • 4-失败: 任务级别错误,导入中断

状态流转规则:

  • 待处理(1) → 处理中(2): Worker 开始处理
  • 处理中(2) → 已完成(3): 处理完成
  • 处理中(2) → 失败(4): 发生严重错误
  • 待处理(1) → 失败(4): 文件验证失败等

Scenario: 正常状态流转

  • WHEN 导入任务经历完整生命周期
  • THEN 状态依次变更: 待处理(1) → 处理中(2) → 已完成(3)

Scenario: 异常状态流转

  • WHEN 导入任务处理过程中发生严重错误
  • THEN 状态变更: 待处理(1) → 处理中(2) → 失败(4)

Requirement: 导入任务列表查询

系统 SHALL 支持查询导入任务列表,用于管理和监控导入任务。

查询条件:

  • 任务状态(status): 可选,1-待处理 2-处理中 3-已完成 4-失败
  • 运营商 ID(carrier_id): 可选
  • 批次号(batch_no): 可选,模糊匹配
  • 创建时间范围: 可选

分页:

  • 默认每页 20 条,最大每页 100 条
  • 默认按创建时间倒序排列

数据权限:

  • 基于 shop_id 自动应用数据权限过滤
  • 代理只能看到自己店铺及下级店铺发起的导入任务

Scenario: 查询所有导入任务

  • WHEN 管理员查询导入任务列表
  • THEN 系统返回导入任务列表,包含任务编号、状态、运营商、总数、成功数、跳过数、失败数、创建时间

Scenario: 按状态筛选导入任务

  • WHEN 管理员查询状态为 2(处理中) 的导入任务
  • THEN 系统返回所有正在处理的导入任务列表

Requirement: 导入任务详情查询

系统 SHALL 支持查询单个导入任务的详细信息,包括跳过/失败记录详情。

详情信息:

  • 任务基本信息: 任务编号、状态、运营商、批次号、文件名
  • 进度统计: 总数、成功数、跳过数、失败数
  • 时间信息: 创建时间、开始时间、完成时间
  • 跳过记录详情: 行号、ICCID、原因
  • 失败记录详情: 行号、ICCID、原因
  • 错误信息: 任务级错误(如有)

Scenario: 查询导入任务详情

  • WHEN 管理员查询导入任务(ID 为 1)的详情
  • THEN 系统返回任务完整信息,包括跳过和失败记录的详细列表

Scenario: 查询导入任务的跳过记录

  • WHEN 管理员查询导入任务(ID 为 1)的跳过记录
  • THEN 系统返回跳过记录列表,每条包含: 行号(line)、ICCID、原因(如"ICCID 已存在")

Scenario: 查询导入任务的失败记录

  • WHEN 管理员查询导入任务(ID 为 1)的失败记录
  • THEN 系统返回失败记录列表,每条包含: 行号(line)、ICCID、原因(如"电信 ICCID 必须为 19 位")

Requirement: 导入任务数据校验

系统 SHALL 对导入任务数据进行校验,确保数据完整性和一致性。

校验规则:

  • 任务编号(task_no): 必填,系统自动生成,格式 IMP-YYYYMMDD-XXXXXX,唯一
  • 任务状态(status): 必填,枚举值 1(待处理) | 2(处理中) | 3(已完成) | 4(失败)
  • 运营商 ID(carrier_id): 必填,必须是有效的运营商 ID
  • 总数(total_count): 必填,≥ 0
  • 成功数(success_count): 必填,≥ 0,≤ total_count
  • 跳过数(skip_count): 必填,≥ 0,≤ total_count
  • 失败数(fail_count): 必填,≥ 0,≤ total_count
  • 数量一致性: success_count + skip_count + fail_count ≤ total_count

Scenario: 创建任务时运营商 ID 无效

  • WHEN 创建导入任务时 carrier_id 不存在
  • THEN 系统拒绝创建,返回错误信息"运营商 ID 无效"

Scenario: 更新任务时数量不一致

  • WHEN 更新导入任务时 success_count + skip_count + fail_count > total_count
  • THEN 系统拒绝更新,返回错误信息"统计数量不一致"