You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

8.9 KiB

Phase A 企业注册与入驻基础闭环实施报告

日期:2026-09-22 范围:企业专用注册、company-register 验证码、事务创建、入驻聚合查询 基线:master / 00153aa5d92d13e66d6cdc42ecd1fe903d6e666

1. 结论与边界

本阶段实现了企业注册和企业入驻状态聚合,不进入 Phase B 已认证企业业务门禁,不进入 Phase C 管理员用户与角色管理,不修改 users.version、user_management_actions、岗位/简历/Offer/面试等业务门禁。

当前未暂存、未提交、未推送;V1–V46 未修改;未新增 V47;没有修改生产数据库的迁移脚本。

2. 权威库存

编码前核对了 AuthController/AuthService、SmsVerificationService/SmsVerificationCodeRepository、PasswordPolicy/PasswordAuthenticationService、AuthSessionService.createSession、注销手机号墓碑、User/UserRepository/user_roles、Company/CompanyRepository/CompanyService、企业认证服务与状态、ErrorCode/ErrorHttpStatusRegistry、SecurityConfig 以及 OpenAPI 基线。

实际短信用途以源码为准,保留 login、password-set、password-reset,新增并白名单化 company-register;任意其他非空用途均拒绝。OpenAPI 基线为 180 paths / 218 operations,本阶段变更为 182 paths / 220 operations。

3. 修改文件

生产代码新增:

  • auth/company/CompanyRegistrationProperties.java
  • auth/company/CompanyRegistrationRequest.java
  • auth/company/CompanyRegistrationResponse.java
  • auth/company/CompanyRegistrationService.java
  • company/CompanyOnboardingResponse.java
  • company/CompanyOnboardingService.java

生产代码修改:AuthController、CompanyController、SecurityConfig、application.yml、SmsVerificationService、SmsVerificationCodeRepository、AuditService、ErrorCode、ErrorHttpStatusRegistry。

测试新增/调整为 Phase A 行为锁定、既有短信/映射/OpenAPI 计数同步;未修改 V1–V46 或 pom.xml。

4. 企业注册契约

新增 POST /auth/company/register,使用强类型请求 DTO 和 Jakarta Validation。客户端只能提交手机号、验证码、密码及企业资料,不能提交 userId、role、verified 或 passwordHash。成功响应包含 userId、companyId、role=COMPANY、onboardingStatus=UNVERIFIED、现有格式的 Access/Refresh Token 和 expiresIn,不回显完整手机号、密码、验证码或密码摘要。

新增 GET /companies/me/onboarding,仅认证用户可访问,响应只包含企业安全摘要、聚合状态、认证申请安全摘要、missingFields 与 allowedActions,不返回 materialsJson、decisionReason、reviewerId、存储路径或其他敏感企业数据。未新增重复的 verifications 接口。

5. 事务边界

CompanyRegistrationService.register 在一个数据库事务中完成:功能开关、短信校验/消费、注销墓碑、手机号占用检查、BCrypt 密码、用户、user_roles、企业资料、登录会话和固定脱敏审计事件。用户保存并 flush 后再创建企业和会话;注册失败不会向客户端返回未提交 Token。数据库唯一约束是并发最终防线,DataIntegrityViolationException 转为统一冲突业务错误。

审计写入使用 AuditService.logRequired 的 PROPAGATION_MANDATORY + saveAndFlush,因此审计失败会使注册事务回滚。Redis 限流键不属于数据库事务,报告和测试没有虚假声称 Redis 自动回滚。

6. 验证码原子消费

SmsVerificationCodeRepository.consumeIfValid 使用条件更新,同时约束 id、used=false、未过期和 attempts < maxAttempts。只有受影响行数恰为 1 才算消费成功,0 行统一按验证码无效处理。错误验证码仍递增尝试次数并保留锁定语义;用途在查询前经过固定白名单校验。企业注册事务回滚时,数据库中的 used 更新随事务回滚。

修复前行为是“查询 → 修改实体 used → save”,受控变异到该实现时,SmsVerificationAtomicConsumptionTest 为 4 run / 2 failures(条件更新未调用、0 行竞争未失败);恢复条件更新后为 4 / 0 / 0 / 0。该变异证明测试不是空转。

7. 入驻状态推导

  • companies.verified=true → VERIFIED;
  • 未认证且无申请 → UNVERIFIED;
  • 最新 PENDING 或 RESUBMITTED → PENDING;
  • 最新 REJECTED → REJECTED;
  • 未认证但最新 APPROVED 或未知状态 → 失败关闭并返回专用一致性错误。

missingFields 从资料实际内容派生,没有新增重复状态字段;allowedActions 随聚合状态返回。

8. 错误码与安全配置

新增唯一数字码:COMPANY_REGISTRATION_DISABLED=10301、COMPANY_REGISTRATION_CONFLICT=10302、COMPANY_ONBOARDING_INCONSISTENT_STATE=10303、COMPANY_REGISTRATION_DEPENDENCY_UNAVAILABLE=10304。映射统一进入 ErrorHttpStatusRegistry:关闭/依赖不可用为 503,冲突/不一致为 409。

匿名放行仅新增 POST /auth/company/register;GET /companies/me/onboarding 保持认证,学生、管理员和匿名均不获得企业入驻数据。日志、审计和响应不记录密码、摘要、验证码、Token、SQL、手机号或请求 DTO。

9. 测试矩阵

新增了企业注册 service/integration/concurrency、入驻 service/controller、验证码原子消费、用途白名单、事务回滚、敏感数据、功能开关等测试类;并同步了既有短信安全、公司 Controller 和异常映射测试。

  • Phase A 定向测试:全部通过;两项阻断整改后的完整定向集 28/28;
  • 真实 MySQL/Testcontainers 并发:1/1,通过同验证码双线程仅一个成功;
  • mvn test:2865 / Failures 0 / Errors 0 / Skipped 0;
  • mvn clean verify:2865 / Failures 0 / Errors 0 / Skipped 0;
  • OpenAPI:python ..\\docs\\verify_openapi.py → 182 paths / 220 operations,All checks passed。

全量验证期间出现的 Hikari 重连和 MySQL 8.4/Flyway 兼容性 warning 均未导致失败;一次与编译并发运行的错误结果未计入,随后单独顺序运行得到上述完整通过结果。

测试/脚本自身问题:早期黑盒驱动曾把短信发送参数误放在 JSON body(实际接口是 query 参数),且临时 JWT 密钥长度不足 32 字符;两项均在产品代码之外修正。重复运行时还触发了短信限流,随后销毁临时数据库并以全新隔离容器重跑,得到本节所列成功结果。未放宽产品断言。

10. 真实 MySQL/Redis/RabbitMQ 黑盒

使用临时隔离容器(MySQL 8.4、Redis 7.4、RabbitMQ 3.13)和最新 JAR 完成真实 HTTP 验收。三中间件均真实健康,应用 /api/v1/health 为 200/UP。

验证结果:匿名 onboarding 为 401;无有效验证码注册被拒;发送 company-register 后注册 200;密码登录 200;/auth/me 200;带注册 Access Token 的 onboarding 200。数据库逐表核对为:目标手机号 users=1、companies=1、user_roles=1 且角色仅 COMPANY、companies.verified=0、验证码 used=1。密码登录产生第二个合法会话,属于预期行为。临时容器、临时 JAR 进程、临时端口和运行日志均已清理,未触碰既有 backend-infra 卷或历史数据。

11. 敏感信息扫描

扫描新增生产代码、测试代码、OpenAPI、验证脚本相关输出和本报告:未发现真实手机号、明文密码、BCrypt 摘要、JWT/Bearer、Refresh Token、数据库/Redis/RabbitMQ 密码、私钥、AWS key 或连接串。黑盒使用的临时凭据只存在于进程环境和临时容器,测试结束后容器和日志已删除;报告不记录其值。

12. 数据与兼容性

未新增数据库迁移;V1–V46 逐项保持不变。求职者短信登录、现有密码登录/设置/修改/重置、Token 刷新/登出、管理员初始化、既有企业资料和企业认证接口保持原路径与行为。企业注册后经现有 /auth/password/login 成功登录并得到 COMPANY 身份。

13. 未进入的范围

本轮没有实现已认证企业业务门禁、管理员用户/角色管理、users.version、user_management_actions、岗位发布、简历、Offer 或面试门禁改造;没有提交、推送或进入 Phase B/C。

14. 当前结束状态

验证完成后未暂存、未提交、未推送;无 Java/Maven 残留进程;8080/8081 空闲;临时测试账号与业务数据在隔离容器销毁时清理;未删除审计历史。工作区仍保留既有历史未跟踪文件和两个 Windows stat 缓存假阳性文件,未覆盖、删除或暂存。

15. 结论

实施阶段完成后,独立复验发现功能开关的宽松布尔绑定问题;现已整改为字符串配置并严格使用小写字面量 true 判断。事务回滚测试也已补齐 users、user_roles、companies、session、audit 五类独立故障注入,新增回滚覆盖后的完整 Phase A 定向集为 28/28,全量回归为 2865/2865,均无失败、错误或跳过。