Files
form-center-service/sql/form_consumer_access_v3.sql
chenxing d7473112b0
build / build-push (push) Successful in 1m26s
t1~t3落地+10-22精修: 消费授权v3(owner/grant/订阅/目录)+答卷投递v2(可信提交上下文/快照/幂等关联)+答卷对账v1(清单/派发/租约/结果)
含10-22精修六类修复: 续租renewRunning/结果INCOMPLETE_RESULT门/终态TASK_TERMINAL/liveGrant复用ACL/hosted幂等重放绑定/错误明细整条重序列化。
合规审计与证据: 工作区docs/tasks/REFINEMENT_AUDIT.md + evidence/refinement-20261022/(patch+指纹)。SQL未执行、测试未运行(仅-skipTests编译)。
2026-10-22 10:02:57 +08:00

65 lines
5.4 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.
-- ============================================================
-- 表单中心 v3 · 消费应用授权 DDL(MySQL 5.7 兼容复核版,TASK_1)
-- 范围:《consumer-access-v3.md》§2/§3 = 建两张表 form_ownership / form_consumer_grant
-- 依据:VERIFICATION V03/V04/V07;owner 绑定与 grant 分权(读/订阅)、默认拒绝、撤销留痕
-- 用途:生产 ddl-auto=none 时的升级脚本;开发期(本机 bsch_formcenter,ddl-auto=update)由 Hibernate
-- 自动追加,本脚本同时是"实表应当长什么样"的评审权威(沿 t2/t3/t10/t16 先例)。
-- 5.7 复核要点:①无 CTE/WITH、无函数索引、无生成列、无 CHECK 约束;②utf8mb4 显式写 CHARSET/COLLATE;
-- ③<b>不建物理外键</b>——form_uuid 对 form 是逻辑引用(同 t16 对 app_code 的处理:
-- 表单软删是唯一切除形态且无物理删除,绑定/授权行必须能在表单软删后继续存在以支撑溯源,
-- 建 FK 等于把"级联删"写进库侧规则);④无可空业务列(判权路径不写"未知=怎样"的分支)。
-- 身份口径:owner_app_key / consumer_app_key 存的是<b>平台 appKey</b>(UserBase 应用注册分配,
-- 验签三件套里那个 X-App-Key),<b>不是</b> form.app_code 那种人读 slug。
-- app_registry 仍是快应用目录,本批一行不加(v3 §1 红线:不把业务授权塞回注册表)。
-- 租户口径:consumer_school_id 既是授权生效域,也是读答卷时的行集限定域;0 不是合法消费域
-- (平台级是资源域,不是一个能答卷的租户),服务侧直接拒。
-- 默认拒绝:两把 *_allowed 开关默认 0,enabled 默认 1(建行即生效,但建之前服务侧必须显式给开关);
-- 撤销是 enabled=0 + grant_version 进位,<b>不删行</b>(判权 SQL 必须带 enabled 条件)。
-- 非幂等:MySQL 5.7 无 ADD/CREATE IF NOT EXISTS 的评审友好写法(写了反而掩盖"表已存在但列不对"的漂移)。
-- 执行前先 `SHOW TABLES LIKE 'form_ownership'` / `'form_consumer_grant'` 确认不存在;
-- 存量:系统未上线,两张表零存量、无需回填(与 t16 同一论证)。
-- ============================================================
CREATE TABLE `form_ownership` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`form_uuid` VARCHAR(32) NOT NULL COMMENT '资源坐标:表单全局 uuid(契约 §1,不可枚举、跨版本不变)',
`form_school_id` BIGINT NOT NULL COMMENT '绑定时表单自己的 sch_id;0=平台级表单',
`owner_app_key` VARCHAR(64) NOT NULL COMMENT '资源拥有者应用的平台 appKey(写入前已核验 UserBase 注册身份)',
`create_by` VARCHAR(255) DEFAULT NULL,
`create_time` DATETIME DEFAULT NULL,
`update_by` VARCHAR(255) DEFAULT NULL,
`update_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_ownership_form` (`form_uuid`),
KEY `idx_ownership_owner` (`owner_app_key`, `form_school_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
COMMENT='表单资源拥有者绑定(v3 §2:一张表一个 owner,只能由管理面写;form_uuid 为逻辑引用不建 FK)';
CREATE TABLE `form_consumer_grant` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`form_uuid` VARCHAR(32) NOT NULL COMMENT '被授权的表单 uuid',
`consumer_school_id` BIGINT NOT NULL COMMENT '消费租户(授权生效域 = 读答卷的行集限定域,≥1)',
`consumer_app_key` VARCHAR(64) NOT NULL COMMENT '消费应用的平台 appKey',
`read_allowed` TINYINT NOT NULL DEFAULT 0 COMMENT '读授权:目录/schema/answer/answers;默认拒绝',
`subscribe_allowed` TINYINT NOT NULL DEFAULT 0 COMMENT '订阅授权:答卷变更事件投递(owner 不天然持有)',
`enabled` TINYINT NOT NULL DEFAULT 1 COMMENT '生效开关;0=已撤销(保留行供审计与 grant_version 判新旧)',
`grant_version` INT NOT NULL DEFAULT 1 COMMENT '授权版本号:撤销与重申都进位,投递侧必须带它下发',
`create_by` VARCHAR(255) DEFAULT NULL,
`create_time` DATETIME DEFAULT NULL,
`update_by` VARCHAR(255) DEFAULT NULL,
`update_time` DATETIME DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_grant` (`form_uuid`, `consumer_school_id`, `consumer_app_key`),
KEY `idx_grant_consumer` (`consumer_app_key`, `consumer_school_id`, `enabled`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
COMMENT='消费应用对某张表单的显式授权(v3 §2:三元唯一、读与订阅分权、默认拒绝、撤销不删行)';
-- 自验(执行后逐条核对):
-- SHOW CREATE TABLE form_ownership\G -- 应含 UNIQUE KEY `uk_ownership_form` (`form_uuid`)
-- SHOW CREATE TABLE form_consumer_grant\G -- 应含 UNIQUE KEY `uk_grant` (三元键) 与 idx_grant_consumer
-- SELECT COUNT(*) FROM information_schema.columns
-- WHERE table_schema=DATABASE() AND table_name IN ('form_ownership','form_consumer_grant')
-- AND column_name REGEXP 'secret|app_code|role|perm'; -- 必须 0 行(密钥与 app_code 都不进授权表)
-- SELECT COUNT(*) FROM information_schema.referential_constraints
-- WHERE table_name IN ('form_ownership','form_consumer_grant'); -- 必须 0 行(无物理外键)