# n05-salary-calc 薪资计算器与历史记录 ## Why 路线图将“薪资计算器”列为完全缺失能力,当前后端没有城市社保、公积金政策参数,也没有统一的到手工资计算与历史快照。求职者只能手工套用税率和各地政策,容易出现基数截断、累计预扣、个人缴费比例或大病固定费口径错误,且无法保存和复核自己的估算结果。 本变更新增一个面向已登录 `STUDENT` 的后端闭环:按中国大陆地级行政区和省直辖县级市加载当前政策,允许用户覆盖个人缴费参数,按居民个人综合所得累计预扣法估算到手工资,并把每次成功计算保存为独立的不可变历史快照。 ## What Changes - 新增 `salarycalculator` 后端模块与六个接口: - `GET /salary-calculator/cities` - `GET /salary-calculator/cities/{cityCode}` - `POST /salary-calculator/calculations` - `GET /salary-calculator/calculations` - `GET /salary-calculator/calculations/{id}` - `DELETE /salary-calculator/calculations/{id}` - 新增 `salary_city_policy` 与 `salary_calculation_history` 两张核心表,`V40` 建表,`V41` 写入覆盖全部目标城市的政策种子,并通过 `dataLevel` 区分城市级参数与省级回退参数。 - 城市政策以六位行政区划代码为主键,覆盖大陆全部地级行政区、直辖市和省直辖县级市;同城不拆分到区县。每条记录标记 `CITY` 或 `PROVINCE_FALLBACK`,不得把省级近似值伪装成城市级官方值。 - 计算支持城市默认值、用户覆盖项、社保与公积金基数截断、个人养老/医疗/失业/公积金、大病固定费、专项附加扣除、累计月份和居民个人综合所得累计预扣。 - 历史记录保存输入、城市默认参数、用户覆盖项、最终生效参数、完整结果、城市政策版本、全国税率版本和创建时间;历史不可编辑,支持分页列表、详情和物理删除单条。 - 计算接口支持可选 `idempotencyKey` 和服务端请求指纹去重,并要求 `expectedPolicyVersion` 与当前城市政策版本一致。 - 新增 `9801–9805` 错误码,覆盖城市不存在、参数非法、历史不存在、幂等冲突和政策版本冲突。 - 薪资历史不写入业务审计日志、不进入个人数据导出;账号注销完成时物理删除该用户全部薪资历史。 ## Scope ### In Scope - 中国大陆地级行政区、直辖市和省直辖县级市的城市政策配置、启用状态、`dataLevel` 数据精度、政策版本与生效日期。 - 城市列表、城市详情和当前默认参数查询。 - 税前月薪、累计月份、专项附加扣除和用户覆盖项驱动的到手工资估算。 - 居民个人综合所得累计预扣、个人五险一金、公积金和大病固定费计算。 - 计算历史的快照保存、分页查询、详情、物理删除和账号注销清理。 - `STUDENT` 角色、JWT 身份、用户数据隔离、政策版本冲突和幂等并发处理。 - `V40/V41` Flyway 迁移、H2 集成测试、真实 MySQL/Docker 黑盒验收、OpenAPI 和前端联调文档。 ### Out of Scope - 前端页面、交互设计、客户端状态管理和支付/工资单集成。 - 企业用工成本、单位社保和单位公积金视角。 - 年终奖、13 薪、绩效、提成、股票、期权、副业或多单位收入。 - 入职、离职、请假导致的天级折算,非居民个人计税和年度汇算清缴。 - 个税专项附加扣除的项目级明细、家庭成员和年度限额管理。 - 行业薪资参考、岗位薪资排名、薪资分布和 Offer 综合比较。 - ADMIN 城市政策维护界面、外部实时政策 API 和自动抓取服务。\n- 不承诺未核验城市参数达到城市级官方精确度;此类城市只能使用明确标记的省级回退参数。 - 个人数据导出中的薪资历史章节。 - 港澳台地区和其他不适用内地社保、公积金及税制的地区。 ## Impact - `mydreamjob-server/src/main/resources/db/migration/`:新增 `V40`、`V41`,不修改历史迁移。 - `mydreamjob-server/src/main/java/com/mydreamjob/salarycalculator/`:新增实体、Repository、计算服务、Controller、DTO 和错误处理。 - `mydreamjob-server/src/main/java/com/mydreamjob/common/exception/ErrorCode.java`:新增 `9801–9805`。 - `mydreamjob-server/src/main/java/com/mydreamjob/config/SecurityConfig.java`:明确薪资接口的认证入口。 - `mydreamjob-server/src/main/java/com/mydreamjob/deletion/AccountDeletionCompletionWorker.java`:在注销完成事务中清理该用户薪资历史。 - `mydreamjob-server/src/test/java/com/mydreamjob/salarycalculator/`:新增单元、MockMvc、持久化、权限、幂等、迁移和端到端测试。 - `docs/openapi-rc.json`、`docs/salary-calculator-api.md`、`docs/frontend-integration.md`、`docs/backend-development-roadmap.md`、`README.md`:同步接口、错误码、计算口径和状态。 - 不改变现有 Offer、个人资料、求职偏好、账号注销读接口或既有错误码语义。 ## Proof of Completion - 已登录 `STUDENT` 可通过城市接口加载当前政策,通过计算接口获得包含当月与累计拆解的到手工资估算。 - 用户覆盖项优先于城市默认值;基数截断、比例、上限、大病固定费、专项扣除和累计税款的边界测试全部通过。 - 政策版本不匹配返回 `409/9805` 且不生成历史;相同幂等键重放不产生重复历史,同键不同规范化请求返回 `409/9804`。 - 历史只能由所属用户查询和删除;删除为物理删除,账号注销完成会清理该用户全部薪资历史。 - `V41` 种子测试证明目标城市全覆盖、城市编码唯一、字段合法、生效日期不晚于采集截止日、版本号非空,并明确区分城市级与省级回退记录。 - `mvn -Dtest=SalaryCalculator*Test test`、`mvn clean verify`、`python docs/verify_openapi.py` 和真实 MySQL/Docker 黑盒验收通过。