💡 清理本次改动注释中的票据引用与设计叙述

注释只写从代码看不出来的事实:删除票号引用、设计权衡与取证经过,
保留业务约束(id_card_no 为 NULL 表示未采集、唯一索引覆盖软删除行、
driving_vehicle 为 ALWAYS 策略等)。
This commit is contained in:
2026-10-23 16:34:25 +08:00
parent b04f68e168
commit 77144f4e68
6 changed files with 21 additions and 23 deletions
+2 -2
View File
@@ -83,12 +83,12 @@
<groupId>org.springblade</groupId>
<artifactId>blade-resource-api</artifactId>
</dependency>
<!-- 登录编排需要在认证侧直接调司机档案的 ensureProfile -->
<!-- 登录编排调用司机档案的 ensureProfile -->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-transport-api</artifactId>
</dependency>
<!-- 登录编排的失败语义(建档/绑 openid 失败必须放行)只能靠 mock feign 返回值守住 -->
<!-- 登录编排测试:mock feign 返回值 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
@@ -34,9 +34,9 @@ import static org.springblade.core.oauth2.constant.OAuth2TokenConstant.USER_PHON
/**
* 发码端点的端分流测试。
* <p>
* 守住票 13 的口径:小程序端(User-Type: mp)对未注册手机号也要发码,
* 否则新号走不到「验证码校验通过后自动建号」;Web 端保持拒绝。
* 同时守住「发码不建号」:mp 分支根本不查账号。
* 保住发码端点的分流口径:小程序端(User-Type: mp)对未注册手机号也发码,
* Web 端仍拒绝。
* 同时保住「发码不建号」:mp 分支根本不查账号。
*/
class Oauth2SmsEndpointTest {
@@ -349,9 +349,8 @@ public class CertAuditServiceImpl implements ICertAuditService {
if (Func.isEmpty(snapshot.getIdCardNo()) && Func.isEmpty(snapshot.getDriverFileNo())) {
return;
}
// 身份证号要落到档案上,先确认它没有落在别人名下:该列在基线建表脚本与本地库上
// 有唯一索引 uk_transport_driver_id_card,但迁移历史里没有任何一次添加它的记录,
// 生产库是否已建未核实;应用层查重不能省,否则重复证件号会静默落库
// 身份证号要落到档案上,先确认它没有落在别人名下:重复证件号一旦落库,
// 建档查重与按证件号识别同一人都会失效
requireIdCardNotTaken(snapshot.getIdCardNo(), driver.getId());
driver.setDriverName(snapshot.getRealName());
driver.setIdCardNo(snapshot.getIdCardNo());
@@ -384,10 +383,9 @@ public class CertAuditServiceImpl implements ICertAuditService {
* 身份证号不得落在另一名司机名下
* <p>
* 司机申报的实名内容会写回档案,其中身份证号是管理端建档时的查重判据。
* 该列在基线建表脚本与本地库上有唯一索引 {@code uk_transport_driver_id_card},
* 但迁移历史里没有任何一次添加它的记录,生产库是否已建未核实;
* 应用层查重仍不能省:重复证件号一旦落库,后续建档查重、
* 按证件号识别同一人都将失效。此处阻断审核并整体回滚,交由管理端先处理档案归属。
* {@code blade_transport_driver.id_card_no} 上有唯一索引
* {@code uk_transport_driver_id_card};证件号已属于另一条档案时,
* 此处阻断审核并整体回滚,交由管理端先处理档案归属。
* <p>
* 证件号与当前档案相同(绝大多数情况)、或库里尚无该号时不阻断;
* 快照没带证件号时无从判断,同样不阻断(历史快照就是这种)。
@@ -122,8 +122,8 @@ public class DriverServiceImpl extends BaseServiceImpl<DriverMapper, Driver> imp
if (resolvedTenantId == null) {
resolvedTenantId = trimToNull(AuthUtil.getTenantId());
}
// 租户是档案归属与手机号查重的范围,宁可让本次建档失败(登录层只记 WARN),
// 也不能写出 tenant_id 为空的档案——那会让下一条同号档案无法被查到
// 租户是档案归属与手机号查重的范围,tenant_id 为空的档案不能被后续同号查询命中,
// 故此处拒绝写库(登录层只记 WARN)
if (resolvedTenantId == null) {
throw new ServiceException("租户信息为空,无法创建司机档案");
}
@@ -134,8 +134,8 @@ public class DriverServiceImpl extends BaseServiceImpl<DriverMapper, Driver> imp
if (mobile == null) {
throw new ServiceException("手机号不能为空");
}
// 查找顺序固定为 user_id → phone:user_id 是稳定标识;
// phone 会被运营商二次放号,拿它优先会把别人档案绑给新持卡人
// 查找顺序固定为 user_id → phone:user_id 是账号的稳定标识,
// phone 会被运营商二次放号
Driver bound = findDriverByUserId(mpUserId);
if (bound != null) {
return ensureResult(bound.getId(), false, false, null);
@@ -169,10 +169,10 @@ public class DriverServiceImpl extends BaseServiceImpl<DriverMapper, Driver> imp
}
/**
* 新建占位档案(票 01 定值)
* 新建占位档案
* <p>
* 不走 {@link #submit}:那条路径要求 15 项必填,自动建档必然被拦。这里只满足表约束——
* id_card_no 留 NULL(唯一索引对 NULL 不去重,且 NULL 是「未采集」的判据),
* 不走 {@link #submit}:那条路径要求 15 项必填。这里只满足表约束——
* id_card_no 留 NULL(唯一索引对 NULL 不去重,NULL 同时是「未采集」的判据),
* 其余 NOT NULL 列写空串或可读占位。
*/
private DriverEnsureProfileVO createPlaceholderProfile(String tenantId, Long mpUserId, String mobile) {
@@ -76,7 +76,7 @@ class DriverEnsureProfileTest {
// ------------------------------------------------------------ 新建占位档案
@Test
@DisplayName("无账号档案、无同号档案:按票 01 的占位值新建,created=true")
@DisplayName("无账号档案、无同号档案:按占位值新建,created=true")
void createsPlaceholderProfile() {
// 第一次按 user_id 查、第二次按手机号查,都没有
when(driverMapper.selectList(any())).thenReturn(Collections.emptyList(), Collections.emptyList());
@@ -1,7 +1,7 @@
-- ----------------------------
-- 司机档案与登录账号打通(2026-10-23)
-- ----------------------------
-- 三处结构变更,均在单据「07 数据模型迁移」内:
-- 三处结构变更:
-- ① user_id 加唯一索引 uk_transport_driver_user —— 一个账号只能对应一条司机档案。
-- ② id_card_no 放宽为可空 —— NULL 表示「身份证号尚未采集」,是判断档案是否完善的口径。
-- uk_transport_driver_id_card 保留:MySQL 唯一索引对多行 NULL 不去重,
@@ -11,7 +11,7 @@
-- NULL 表示改造前存量(来源未知,不臆造);account_bound_time 是档案与账号建立关联的时点。
--
-- 只做结构变更,不回填数据:存量档案的 profile_source / account_bound_time 一律保持 NULL。
-- 判定「档案是否采集」用 id_card_no IS NULL,不另加标记列(见票 01)。
-- 判定「档案是否采集」用 id_card_no IS NULL,不另加标记列。
--
-- 幂等:每段先查 information_schema,条件已满足即跳过,重复执行不报错;
-- 全部用 PREPARE 动态语句而非存储过程,因此不需要 DELIMITER——按分号逐句切分的客户端
@@ -20,7 +20,7 @@
-- 前置检查(user_id 有重复时,第 1 节会以
-- Duplicate entry '<值>' for key 'blade_transport_driver.uk_transport_driver_user'
-- 失败并终止;此时本脚本对表零修改,先修数据再重跑):
-- 唯一索引统计**全表**行,含 is_deleted = 1 的软删除档案。票面给的 is_deleted = 0 口径
-- 唯一索引统计**全表**行,含 is_deleted = 1 的软删除档案:只按 is_deleted = 0
-- 只能发现活跃重复,软删除行之间的重复同样会让第 1 节失败:
-- SELECT user_id, COUNT(*) AS dup_count FROM `blade_transport_driver`
-- WHERE user_id IS NOT NULL