交付出件箱

← 返回出件箱

家长子席位账号「机构自定义前缀」改造 · verify 报告

2026-09-24 · 云机环境只读核查 · 非验收证据
代码基线:feature/subseat-login-v2 @ 0dfa67fd(落后 origin/test 498b8252 7 个 commit,但本次涉及的 seat_service.py / seat_auth.py / brand_code_service.py / user.py 四个文件 git diff --stat HEAD..origin/test 0 差异,基线可信)
数据:test 库经 seatops 通道实查(db-query test 查 users/organizations 受 RLS 假 0,已用 pg_stat_user_tables.n_live_tup=388 交叉证实并绕过)

一、长官提的新规则

二、核查结果(13 维 · 每条附证据)

# 维度 结论 证据(file:line)
1 现在家长号怎么生成 全平台按月共用一个计数器,格式「6 位序号 + YYMM」= 10 位纯数字;批量取号后一次查重剔除,最多 5 轮 app/services/seat_service.py:186 _alloc_seq_batch · :213 _alloc_parent_usernames · :239 f"{seq:06d}{period}"
2 开号入口 全仓只有一个生成函数 generate_seats,所有开号都走它:PC 后台门店席位、PC 后台家长子席位、门店端开家长子席位、品牌码扫码自动开号、结算开通 ×3 admin_seats.py:126 · admin_parent_seats.py:134 · store_subseat.py:79 · brand_code_service.py:94 · internal_settlement.py:577/698/1643
3 账号唯一约束 users.username 全表唯一(跨所有角色),数据库层没有格式约束 app/models/user.py:33 String(64), unique=True · migrations/versions/phase29_001_create_auth_tables.py:35
4 其他角色的账号长什么样 管理员 / 平台员工:手填自由文本(admin、xz_admin…);渠道:CH + 年月 + 3 位(如 CH202608019,11 位) test 库实查:admin 4 / channel 78 / platform_staff 3
5 机构表有没有现成字段 有 org_code(唯一、可空),但它是登录时校验机构一致性用的;test 88 个机构只有 3 个有值,且都是脏数据(uat-181257 / TONGBAN_TEST / uatpwexp09040941)→ 不建议复用,新开专用列 app/models/organization.py:17 · app/api/seat_auth.py:95/162 · internal_settlement.py:549 注释「旧兼容字段,全仓无生成规则」
6 计数表能不能直接用 SeatSeqCounter 主键是 (period, seat_kind),也就是全平台按月,装不下「按机构计数」→ 要新的计数结构 app/models/seat_seq_counter.py:10-25
7 后端哪里写死了格式 只有门店序号池一处(已按 seat_type 过滤,家长号进不去,不受影响);席位登录没有大小写处理(批次五决策 2 本来就要加) seat_service.py:154-158 · seat_auth.py:169/231
8 前端登录框能不能输字母 手机端、平板账号框都没有 inputMode / maxLength / 过滤,BF100001 能直接输;登录按钮只判断非空 web/app/h5/chat/components/seat-login-sheet.tsx:291-305, 110 · web/app/h5/tablet/components/seat-login.tsx:263-277, 95
9 前端写死的文案 「席位账号不是手机号,请输入提供给您的10位数字账号」门店、家长两端共用,家长换格式后说错了,要改 web/app/h5/chat/lib/seat-login-hints.ts:14;断言该文案的测试:seat-login-hints.spec.ts:198、seat-login-sheet-phone-hint.spec.tsx:41
10 后台维护入口放哪 机构编辑是列表页弹窗(里面有「家长子席位开通」开关);品牌码是独立子页面 + 独立接口(require_role("admin"))→ 前缀维护可以照品牌码的做法单独做 web/app/(dashboard)/admin/orgs/page.tsx:249/315 · app/api/admin_brand_code.py:34/41 · admin/orgs/[id]/brand-code/
11 「重复不让保存」有没有现成做法 有:后端返回错误 detail → 前端红字原样显示 admin/orgs/page.tsx:320-324, 714 · admin/orgs/[id]/seats/page.tsx:271-287(席位电话查重同款)
12 开号弹窗 PC 后台「开通子席位」弹窗没有「机构没设前缀」的提示位置,要新增 web/app/(dashboard)/admin/parent-seats/page.tsx:1127-1216
13 现有数据 / 测试 test 家长号 65 个,全是 10 位纯数字;家长号格式断言只在 tests/unit/test_phase83_seat_seq_counter.py(:110-120 等),要重写;门店相关用例保留当回归 test 库实查 · 测试文件 grep

三、主会话抽查(照代理报告逐条复核 · 全部对上)

①username约束   user.py:33  username = Column(String(64), unique=True, nullable=True, index=True)
②org_code      organization.py:17  org_code = Column(String(50), unique=True, nullable=True, comment="机构编码(旧字段,兼容)")
               seat_auth.py:162  4. org_code 一致性:seat.linked_org_id 对应 org.org_code == 请求 org_code → 否则 401
③计数表主键     seat_seq_counter.py:25  """家长席位号码月度序号原子计数器 · 复合 PK (period, seat_kind)"""
④家长号拼装     seat_service.py:239  candidates = [f"{seq:06d}{period}" for seq in seq_range]
⑤开号调用方     brand_code_service.py:94 / store_subseat.py:79 / internal_settlement.py:577,698,1643 / admin_seats.py:126 / admin_parent_seats.py:134
⑥登录错误提示   seat-login-hints.ts:14  "席位账号不是手机号,请输入提供给您的10位数字账号";
⑦后台机构弹窗   admin/orgs/page.tsx:315  enable_parent_subseat: enableParentSubseat, // Phase 74
⑧独立入口先例   admin_brand_code.py:41  router = APIRouter(prefix="/api/admin/orgs", tags=["管理后台-机构-品牌码"])
对照组          seat_service.py 中 "def " 共 17 处(证明查法有效)

四、要长官拍板的点(附建议)

  1. 前缀几位、能用什么字符 —— 建议 2–4 个大写字母(如 BF、ZYZN),不许数字和符号;保存时统一转大写再查重
  2. 开过号以后前缀还能不能改 —— 建议不能改。改了以后旧号还挂着老前缀,别的机构再用这个老前缀就会撞号
  3. 机构没设前缀怎么办 —— 建议不能开子席位,开号时提示「请先设置子席位前缀」。⚠️ 品牌码扫码也会自动开家长号(维度 2),所以开品牌码之前也必须先设好前缀,否则家长扫码会失败。已开「家长子席位」的机构上线前要先补前缀
  4. 已经开出去的老家长号(10 位数字)改不改 —— 建议不改,只管以后新开的(符合「老号一字不变」)
  5. 要不要禁用 CH —— 渠道账号都是 CH 开头,建议不让机构用 CH,免得看起来像渠道号

五、改动范围(不是「改一行」)

层 要做的
数据库 机构表新增「子席位前缀」列(唯一);新的「按机构」计数结构(从 100001 起);迁移挂在 phase83_001 之后
后端 seat_service.py:186-255 取号改成「机构前缀 + 机构计数」;新维护接口(照 admin_brand_code.py,查重不过返回错误);三个开号入口加「没设前缀不许开」;席位登录加大写处理(决策 2)
前端 新的前缀维护页面(照品牌码页);开子席位弹窗加提示;改 seat-login-hints.ts:14 那句「10位数字账号」
测试 重写 test_phase83_seat_seq_counter.py 家长号格式相关用例;改两条文案断言
文档 / 图 方案决策 1 作废改写;图里 T0000012609 全部换成新格式示例

顺带的好处:计数器按机构分开以后,不同机构同时开号不会再互相排队,批次四(一次开 5 万个号)要的提速方向正好一致。