交付出件箱

← 返回出件箱

Phase 83.13 数据层 · 完工证据(10 维)

2026-09-24 · 分支 feature/subseat-login-v2 · 提交 82b7229d(本地,未推送)
环境:东京云机本地库 · 云机环境·非验收证据(完整验收去 test)

一句话

给批次五搭好了「地基」:机构能存前缀、每个机构有自己的家长号计数器、席位多了一个「是否改用手机号登录」开关。
老数据一行没动:4.4 万个老账号开关全是「关」,4 万个机构前缀全是空,上线后老用户零感知。

这次加了什么

加在哪 是什么 规矩
机构表 subseat_prefix 家长号前缀(如 ZY) 1-6 位大写字母;两个机构不能撞;可以不填
新表 org_parent_seat_counter 每个机构一行,记家长号用到第几号 从 100000 起,最大 999999;机构删了它跟着删
席位表 phone_login_enabled 这个号是不是「只认手机号登录」 必填,默认「关」;老号永远关,新号在 83.14 开号时才打开

10 维证据(全部主会话亲跑)

前-1 现状:改前代码里这三个新名字确实不存在

改前提交 7cc6b8b7 上 git grep:

subseat_prefix: 0 处
org_parent_seat_counter: 0 处
phone_login_enabled: 0 处
seat_seq_counter: 10 处      ← 对照组,证明查法有效

前-2 复用:旧的按月计数器没动,也没被复用

旧表 seat_seq_counter 是按月计数(批次一的门店号),批次五要按机构计数,口径不同所以另起新表(tech §3)。
git diff 7cc6b8b7 HEAD -- app/models/seat_seq_counter.py migrations/versions/phase83_001* = 空(一行没改)。

前-3 影响面:迁移链与部署

前-4 边界:16 条测试逐个卡住

边界 结果
前缀 ZY 能存 ✅
前缀小写 / 带数字 / 空串 被 CHECK 拒
前缀 7 位 被列长拒(value too long)
两个机构用同一前缀 被唯一索引拒
多个机构都不填前缀 允许
计数 100000 / 999999 能存
计数 99999 / 1000000 被 CHECK 拒
计数不填 默认 100000
删机构 计数行跟着删
新建席位不填开关 默认 false

后-1 diff 范围:只动了 6 个文件

app/models/org_parent_seat_counter.py        (新 · 50 行)
app/models/organization.py                   (+前缀列 + 唯一索引 + CHECK)
app/models/user.py                           (+phone_login_enabled 一列)
migrations/versions/phase83_002_...py        (新 · 120 行)
tests/integration/test_phase83_batch5_login.py (新 · 343 行 · 16 条)
docs/.../impl/phase83-subseat-brandcode-batch1.md (83.13 五个 Step 打勾 + 进度行 ✅)
6 files changed, 543 insertions(+), 7 deletions(-)

后-2 红线:老字段一个没删

后-3 真跑:先退回旧结构看它失败,再升回来看它通过

== downgrade → phase83_001 ==
Running downgrade phase83_002 -> phase83_001
phase83_001
== RED(无新表列) ==
16 failed in 7.40s
== upgrade → phase83_002 ==
Running upgrade phase83_001 -> phase83_002
phase83_002 (head)
== GREEN ==
16 passed in 0.87s

后-4 产物物理确认

2004  app/models/org_parent_seat_counter.py
4793  migrations/versions/phase83_002_subseat_prefix_and_phone_login.py
13344 tests/integration/test_phase83_batch5_login.py

后-5 数据完整性 SQL(本地库 · 升级后)

users(total,true,NULL)          => (44685, 0, 0)      老号全部 false,没有空值
organizations(total,prefix_set) => (40651, 0)         没有机构被自动填前缀
counter rows                    => 0                  计数表空,等 83.14 开号才写
constraints => ck_org_parent_seat_counter_range(c) / ck_organizations_subseat_prefix_format(c)
               org_parent_seat_counter_org_id_fkey(f) / org_parent_seat_counter_pkey(p)
index       => uq_organizations_subseat_prefix  UNIQUE btree (subseat_prefix)
col default => phone_login_enabled NOT NULL default false · last_seq NOT NULL default 100000
对照组 users.must_change_password 存在 => 1

后-6 回归:登录相关老测试

60 passed / 3 failed。3 个失败改之前就有,原因原文:

AssertionError: {"detail":"家长账号请先完成微信授权后登录"}
assert 403 == 200

即 phase74 的老测试里家长登录没带微信身份,被现有规则拦下,与本次加列无关。
原文已存为基线 ~/reports/phase83-b5-baseline-phase74-3fail-20260924.txt,83.14 改登录时拿它对比。

过程中踩的坑(如实记录)

  1. 本地库里 seat_seq_counter 表早被测试夹具建过,但迁移版本号没记,alembic upgrade 报表已存在。
    核对表结构与 phase83_001 一致后,用 alembic stamp phase83_001 补记版本,再升 phase83_002。未删任何表。
  2. 执行层写的测试有 2 处小错(约束类型取出来是 bytes;7 位前缀报的是列长错不是 CHECK 错),已修,16/16 绿。

下一步

83.14 取号 + 开号守门(新号从 100001 起、前缀未设不许开号、超 999999 报 409、新号开关置 true)。