5.9 KiB
薪资历史能力规格
Purpose
保存求职者每次成功薪资估算的可追溯快照,并提供仅限本人访问的分页查询、详情和物理删除能力。
ADDED Requirements
Requirement: 成功计算自动保存历史
The system SHALL 在计算并保存接口成功完成时自动创建一条历史记录,并在响应中返回历史 ID 和创建时间。系统 MUST NOT 要求调用方再调用第二个保存接口。
Scenario: 首次成功计算
- WHEN STUDENT 提交合法且政策版本一致的计算请求
- THEN 系统在同一事务中完成计算并保存历史,返回结果及新历史 ID
Requirement: 历史保存完整且可重建的快照
The system SHALL 在历史记录中保存原始输入、城市编码与名称、城市默认参数、用户覆盖项、最终生效参数、完整结果、monthIndex、城市政策版本、政策生效日期、全国税率版本和创建时间。三类 JSON 快照 MUST 能独立重建当时结果。
Scenario: 城市参数后来变化
- WHEN 历史创建后城市默认参数或政策版本发生变化
- THEN 历史详情仍返回创建时的输入、政策、覆盖项和完整结果,不重新读取当前城市配置
Requirement: 计算保存使用幂等键防重
The system SHALL 支持可选 idempotencyKey,最长 64 字符,空白值按未提供处理。同一用户相同幂等键且规范化业务字段相同 MUST 返回原历史;相同幂等键但规范化字段不同 MUST 返回 409/9804。
Scenario: 相同请求网络重试
- WHEN 客户端使用相同用户、相同幂等键和相同规范化业务字段重试计算
- THEN 系统返回同一条历史和相同计算结果,不新增数据库行
Scenario: 相同幂等键不同请求体
- WHEN 客户端复用幂等键但修改税前月薪或政策版本
- THEN 系统返回 409/9804,且不创建第二条历史
Requirement: 同一幂等键并发只能生成一条历史
The system SHALL 使用事务和数据库唯一约束处理并发。相同用户相同幂等键并发请求 MUST 最多生成一条历史;同键不同请求并发时,一方成功,另一方 MUST 返回 409/9804。
Scenario: 并发相同请求
- WHEN 两个请求同时提交相同用户、幂等键和规范化业务字段
- THEN 数据库中最多存在一条历史,两个成功响应指向同一历史 ID
Requirement: 历史列表和详情仅返回本人数据
The system SHALL 提供按创建时间倒序、ID 倒序的分页列表和详情接口。列表 MUST 只返回摘要;详情 MUST 返回完整快照。查询必须同时按当前登录用户和历史 ID 过滤。
Scenario: 查询本人历史
- WHEN STUDENT 调用历史列表或详情接口
- THEN 系统只返回该 STUDENT 的历史,按最新创建时间排序
Scenario: 猜测他人历史 ID
- WHEN STUDENT 请求不属于自己的历史 ID
- THEN 系统返回 404/9803,不泄露该记录是否存在
Requirement: 历史不可编辑且可以物理删除单条
The system SHALL 不提供历史更新接口。历史创建后不可修改;用户删除本人历史时 MUST 物理删除该行及其幂等键,后续可以为该幂等键创建新历史。
Scenario: 删除本人历史
- WHEN STUDENT 删除自己的历史记录
- THEN 系统物理删除该记录并返回成功响应,后续详情查询返回 404/9803
Scenario: 重复删除历史
- WHEN STUDENT 再次删除已经删除的历史
- THEN 系统返回 404/9803,不返回成功状态
Requirement: 历史列表采用统一分页且不提供额外筛选
The system SHALL 使用 page=0、size=20 的分页默认值,size 最大为 100;首期 MUST NOT 增加城市、日期范围或薪资范围筛选。
Scenario: 超出分页上限
- WHEN 客户端请求
size=101 - THEN 系统返回 400/9802,不返回历史列表
Requirement: 历史数据按用户长期保留
The system SHALL 允许历史记录长期保留直至用户主动删除,不设置自动过期、定时清理或业务数量配额。城市停用、政策更新或历史数量增长 MUST NOT 影响历史详情读取。
Scenario: 城市停用后查看旧历史
- WHEN 历史所属城市后来被停用
- THEN STUDENT 仍可查看该历史详情
Requirement: 历史不进入审计日志或个人数据导出
The system SHALL 不因薪资计算或单条历史删除写入业务审计日志,也不得把税前工资、基数、税额、到手工资或 JSON 快照写入应用日志。薪资历史 MUST NOT 纳入现有个人数据导出 ZIP。
Scenario: 计算成功后的日志检查
- WHEN 系统完成一次薪资计算和历史保存
- THEN 日志仅包含请求 ID、用户 ID、历史 ID、城市编码、状态和耗时,不包含金额或参数快照
Requirement: 账号注销清理薪资历史
The system SHALL 在账号注销完成事务中物理删除该用户全部薪资历史。注销处于 PENDING 时 MUST 禁止计算和删除写入,COMPLETED 时所有薪资接口 MUST 返回 409/9303。
Scenario: 注销完成后清理历史
- WHEN 用户账号注销完成
- THEN 数据库中不存在该用户的
salary_calculation_history行
Scenario: 注销冷静期尝试计算
- WHEN 用户处于
PENDING状态调用计算接口 - THEN 现有注销守卫返回 409/9302,且不创建历史
Requirement: 数据库迁移保证城市政策和历史完整性
The system SHALL 通过 V40 创建 salary_city_policy 与 salary_calculation_history,通过 V41 写入目标城市种子。城市编码 MUST 唯一,历史幂等键 MUST 按用户唯一,历史快照 MUST 保留且不依赖后续城市更新。
Scenario: 迁移初始化
- WHEN 在 MySQL 或 H2 MySQL 模式执行
V40和V41 - THEN 城市政策表、历史表、主外键、唯一键和索引创建成功,目标城市种子导入成功