Files
form-center-service/sql/t12_access_simplification.sql
chenxing f10b367bbc t13:所有权模型切换——audience 多值门 + ALL/SELF 两档 + 冻结开关,三层模型与身份矩阵出清
- DDL sql/t12_access_simplification.sql(非幂等,先查列):form.audience TINYINT→VARCHAR(64)
  + 存量迁移、form 加 creator_id/frozen/anon_cookie_minutes、answer 加 anon_ip/anon_ua
  + idx_answer_form_utime;实体与 @Index 同步(本地库已备份并手工执行)
- audience 多值(C1/C2/C5):FormEnums.Audience 扩 ANONYMOUS + parse/join/namesOf 单点工具;
  配置通道收数组并加跨字段约束(含 ANONYMOUS 时 fill_limit 必 0,CUSTOM(5));
  FormView/ResolvedFormView/FillableRow/oapi SchemaView 出参一律数组(flow-center 需通告)
- 两档范围(§2.3/D4):DataScopeService 重写为 {all,self} + 平台级表单的租户限定变体(D9),
  身份默认矩阵与回落分支删除;5 实现器收敛为 ALL/SELF 两个,SCHOOL 谓词并入 ALL 变体、
  TEACHING_CLASS 摘除;AnswerScopeQueryBuilder 改吃查询规格(V55 唯一出口不变)
- audience 门替第 0 关(§3.1):AnswerService 的 fillAccess.resolve+requireFillEntry 换成
  人群门,requireSubject 指定权收敛为"该表单 ALL 档";FillAccessService 全类删除;
  代录/导入不过人群门(P116 用户裁决:§3.4 与 §5.1/V73 冲突取"功能可用"一侧)
- fillable 行形状(C2):删 canFill/myTier,入集=身份类型 ∈ audience(与提交同一公式)
- 冻结开关(§4.2/V61):config 通道 + 两条编辑通道同关,文案指路"撤回后重新提交";
  新增 AnswerFrozenIT 钉双通道与修正路径
- 创建人识别(C16):creator_id 建列 + create_by 账号名兜底(兜底取会话线程账号,
  与 create_by 同一事实源,不拿 BoaUser.account 跨系统比串)
- 测试:FillAccessServiceTest 整类删除(V48 作废)、AnswerFillGateIT 按 v2 语义重写(V66)、
  DataScopeServiceTest 按两档重写、AdminScopeIT/AnswerExportIT/ReadFixture 造数改自填路径
2026-10-20 12:54:07 +08:00

75 lines
5.2 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================================
-- 表单中心 T13(契约 v2 §17.3)· 权限简化与匿名面 DDL(MySQL 5.7 兼容复核版)
-- 范围:《契约v2-权限简化与开放接入.md》§17.3 三笔 =
-- ① form.audience TINYINT→VARCHAR(64) + 存量迁移(1→'STUDENT'、2→'TEACHER',C1)
-- ② form 加 creator_id / frozen / anon_cookie_minutes(C16、§4.2、C7)
-- ③ answer 加 anon_ip / anon_ua + 复合索引 idx_answer_form_utime(C8/C12、§6.1)
-- 批次硬前置:**T13 部署前必须执行**(audience 列型改后新代码按 VARCHAR 码串读写,
-- ddl-auto=update 不会改已存在列的类型——本地/160 都必须手工跑本脚本)。
--
-- ⚠ 本脚本【不是幂等的】(沿 t10 先例:MySQL 5.7 无 ADD COLUMN IF NOT EXISTS / 无 MODIFY 判存在):
-- 执行前逐条先查——
-- SHOW COLUMNS FROM `form` LIKE 'audience'; -- Type 应为 tinyint;已是 varchar(64) 则跳过 ①
-- SHOW COLUMNS FROM `form` LIKE 'creator_id'; -- 有结果则跳过 ② 的第一条
-- SHOW COLUMNS FROM `form` LIKE 'frozen'; -- 有结果则跳过 ② 的第二条
-- SHOW COLUMNS FROM `form` LIKE 'anon_cookie_minutes'; -- 有结果则跳过 ② 的第三条
-- SHOW COLUMNS FROM `answer` LIKE 'anon_ip'; -- 有结果则跳过 ③ 的加列
-- SHOW INDEX FROM `answer` WHERE Key_name='idx_answer_form_utime'; -- 有结果则跳过 ③ 的加索引
-- 备份:`mysqld --single-transaction` 前先 mysqldump 本库(本地 bsch_formcenter / 160 容器网同名库)。
--
-- 5.7 复核要点(沿 t10):①无 CTE/WITH、无函数索引、无生成列、无 CHECK 约束;②utf8mb4 显式 CHARSET/COLLATE;
-- ③InnoDB、无物理外键(creator_id→UserBase 用户主键、form_uuid→form.uuid 都是逻辑外键)。
--
-- 存量与语义:
-- · audience 迁移后**不允许出现逗号串之外的形态**;空串/NULL 视为脏数据,读侧按默认 STUDENT 解释(C1)。
-- · creator_id 存量=NULL:解析期按 `create_by`(账号名)兜底判定创建人(C16),
-- 一次性回填对照 UserBase 由人工/脚本另做(160 现存 form 行个位数);未回填行由兜底覆盖,不阻塞发布。
-- · frozen/anon_cookie_minutes 有默认值(0 / 10),存量行即"未冻结、默认 10 分钟",无需回填。
-- · anon_ip/anon_ua 只由 T15 匿名面写入,列先建不启用=部署即安全(§17.3 注)。
-- ============================================================
-- ① 面向人群改多值码串(C1:逗号分隔枚举码闭集 STUDENT/TEACHER/ANONYMOUS;禁止布尔补丁 D8)
-- 顺序刻意:先改列型(tinyint 值 1/2 转成字符串 '1'/'2'),再把数字串映射成枚举码。
ALTER TABLE `form`
MODIFY COLUMN `audience` VARCHAR(64) NOT NULL DEFAULT 'STUDENT'
COMMENT '面向人群(C1 多选,逗号分隔枚举码:STUDENT/TEACHER/ANONYMOUS;原 TINYINT 1/2 由本脚本迁移)';
UPDATE `form` SET `audience` = 'STUDENT' WHERE `audience` = '1';
UPDATE `form` SET `audience` = 'TEACHER' WHERE `audience` = '2';
-- ②-a 创建人归一列(C16:现网 create_by=账号名字符串,与两表 user_id 标识体系不同,建列归一)
ALTER TABLE `form`
ADD COLUMN `creator_id` BIGINT NULL DEFAULT NULL
COMMENT '创建人 user_id(BoaUser.id,新建时从会话落列;NULL=存量未回填,解析期按 create_by 账号名兜底)'
AFTER `name`;
-- ②-b 冻结开关(§4.2/D11:1=提交后禁编辑,双写通道同关;修正路径=撤回+重交)
ALTER TABLE `form`
ADD COLUMN `frozen` TINYINT NOT NULL DEFAULT 0
COMMENT '提交后禁编辑(1=开启,喂外部业务应用的表单建议开启;§4.2)'
AFTER `answer_no_enabled`;
-- ②-c 匿名防重窗口(C7:cookie 有效期分钟数,表单级可配,默认 10)
ALTER TABLE `form`
ADD COLUMN `anon_cookie_minutes` INT NOT NULL DEFAULT 10
COMMENT '匿名 cookie 防重窗口分钟数(C7,默认 10;仅 audience 含 ANONYMOUS 的表单有意义)'
AFTER `frozen`;
-- ③ 答卷匿名留痕两列 + 非冻结增量拉取索引(§6.1:现状 answer 表无任何 update_time 索引,已核实)
ALTER TABLE `answer`
ADD COLUMN `anon_ip` VARCHAR(64) NULL DEFAULT NULL
COMMENT '匿名提交来源 IP(C8/C12,仅匿名答卷填充,登录答卷恒 NULL)'
AFTER `idempotency_key`,
ADD COLUMN `anon_ua` VARCHAR(512) NULL DEFAULT NULL
COMMENT '匿名提交 User-Agent(C8/C12,只进独立列,不进 values_json)'
AFTER `anon_ip`;
ALTER TABLE `answer`
ADD KEY `idx_answer_form_utime` (`form_uuid`, `update_time`, `id`);
-- 自验(执行后逐条核对,V66/V67/V70 的库侧半边):
-- SHOW CREATE TABLE form\G -- audience varchar(64) NOT NULL DEFAULT 'STUDENT' + creator_id/frozen/anon_cookie_minutes
-- SHOW CREATE TABLE answer\G -- anon_ip/anon_ua + KEY idx_answer_form_utime(form_uuid,update_time,id)
-- SELECT audience, COUNT(*) FROM form GROUP BY audience; -- 只应出现 STUDENT/TEACHER/组合码串,不得再有 '1'/'2'
-- EXPLAIN SELECT id FROM answer WHERE form_uuid='<32位>' ORDER BY update_time, id; -- 应命中 idx_answer_form_utime