- 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 造数改自填路径
75 lines
5.2 KiB
SQL
75 lines
5.2 KiB
SQL
-- ============================================================
|
||
-- 表单中心 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
|