## MODIFIED Requirements

### Requirement: 导出任务异步分片执行

系统 SHALL 使用 Asynq 异步任务执行导出流程，并采用 `dispatch -> shard -> finalize` 三段式处理；大数据量导出 MUST 支持分片并行执行。dispatch 阶段 MUST 通过 `DataSource.Count` 获取总行数后按 `offset/limit` 切分分片，不再使用 Keyset 游标。

#### Scenario: 创建任务后异步执行

- **WHEN** 导出任务创建成功
- **THEN** 系统将主任务入队，任务状态从"待处理"推进到"处理中"

#### Scenario: dispatch 阶段通过 Count 切分分片

- **WHEN** dispatch 阶段调用 DataSource.Count 返回总行数
- **THEN** 系统按 ExportDefaultShardSize 计算分片数，每个分片记录 offset 和 limit，不依赖主表 ID 游标

#### Scenario: 分片任务并行处理

- **WHEN** dispatch 阶段生成多个 offset/limit 分片
- **THEN** 系统并行执行多个 shard 任务并按分片回写进度

#### Scenario: 分片失败触发重试

- **WHEN** 某个 shard 任务因临时错误失败
- **THEN** 系统按 Asynq 重试策略重试该分片，且不影响其他分片状态

#### Scenario: finalize 合并分片文件而非重查数据库

- **WHEN** 所有分片任务完成且均为成功状态
- **THEN** finalize 阶段按 shard_no 升序从 OSS 下载各分片 CSV 文件（不含表头），顺序追加写入本地临时文件，在文件头部写入表头后上传为最终产物，不重新查询数据库

#### Scenario: XLSX 格式 finalize 降级路径

- **WHEN** 导出格式为 xlsx，finalize 阶段合并分片
- **THEN** 各分片在 shard 阶段生成不含表头的 CSV 中间文件（而非 xlsx），finalize 合并 CSV 后用 excelize 流式写出最终 xlsx 文件

---

### Requirement: 导出结果 OSS 交付与详情下载链接

系统 SHALL 将导出产物上传至 OSS，并在任务详情接口返回可直接下载的 `download_url`；该下载链接默认有效期 MUST 为 24 小时。分片产物 MUST 可被 finalize 阶段独立下载拼接（每个分片文件仅含数据行，不含表头）。

#### Scenario: 已完成任务详情返回下载链接

- **WHEN** 任务状态为"已完成"且产物上传成功
- **THEN** 任务详情接口返回 `file_key` 与可直接下载的 `download_url`

#### Scenario: 未完成任务不返回下载链接

- **WHEN** 任务状态为"待处理"或"处理中"
- **THEN** 任务详情接口不返回可用的 `download_url`

#### Scenario: 下载链接过期后可重新获取

- **WHEN** 用户在 URL 过期后再次调用任务详情接口
- **THEN** 系统重新生成新的 24 小时有效下载链接

#### Scenario: 分片文件不含表头

- **WHEN** shard 阶段生成分片文件并上传 OSS
- **THEN** 分片文件仅包含数据行，不包含表头行，使得 finalize 可直接顺序追加而无需跳过首行
