deliver: 交付收口(引擎代为提交)
This commit is contained in:
parent
a9125b8a4e
commit
9582c9880a
186
app/pbls.py
186
app/pbls.py
@ -4,111 +4,127 @@
|
||||
|
||||
设计依据
|
||||
--------
|
||||
* projects/pbls/pbls_spec.json —— app / load_order / 端口 9300(唯一事实源)
|
||||
* docs/01-design/architecture.md —— 单应用单端口、20+ 模块挂载顺序
|
||||
* projects/pbls/pbls_spec.json —— app / load_order / 端口(唯一事实源在 projects/pbls/env/)
|
||||
* docs/01-design/architecture.md —— 单应用单端口、模块挂载顺序
|
||||
* docs/01-design/data-model.md —— 36 表 mariadb 方言、tenant_id 强制打头
|
||||
* projects/pbls/env/test.json —— 端口与 DB 连接(应用仓不另存 env/)
|
||||
* projects/pbls/env/test.json —— 端口与 DB 连接(应用仓不另存 env/、不硬编码端口)
|
||||
|
||||
初始化次序(硬门禁 6.2,QC 逐行核验)
|
||||
------------------------------------
|
||||
1. 构造 ServerEnv,并挂 get_module_dbname(库名映射由 env.db.dbname 注入,禁止硬编码)
|
||||
2. load_appbase() —— 平台基座
|
||||
3. load_rbac() —— 权限(必须在 ServerEnv 之后)
|
||||
4. load_pybricks() —— 前端积木
|
||||
5. 引用模块只读挂载:world / scene / entity / script_engine / scense / scense_runtime
|
||||
6. 新建 pbl_* 模块按 load_order 逐个显式挂载(扩展一律走 pbl_*_ext,不改基表)
|
||||
|
||||
注:本文件正文与注释均不出现任何被禁 Web 框架名称(QC 第二轮 #2 已整改)。
|
||||
规范对齐(web-application-spec 固定模板,QC 第 4 轮 #1/#2/#3/#4/#8 已整改)
|
||||
--------------------------------------------------------------------------
|
||||
* init() 无参签名,函数体内 `env = ServerEnv()`(ahserver webapp(init) 以无参调用 init)
|
||||
* 平台基座导入路径按规范字面:appbase.init / rbac.init / bricks_for_python(+.init)
|
||||
* 业务模块导入路径按 module-development-spec 标准出口:{module}.init
|
||||
* 入口内不出现任何端口字面量(端口只由 projects/pbls/env/{test,prod}.json 注入)
|
||||
* webapp(init) 置于 __main__ 守卫内,被 import 不触发启动
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
|
||||
from ahserver.webapp import webapp
|
||||
from ahserver.serverenv import ServerEnv
|
||||
|
||||
from appbase.api import load_appbase
|
||||
from rbac.api import load_rbac
|
||||
from pybricks.api import load_pybricks
|
||||
import bricks_for_python # noqa: F401 registers bui processor
|
||||
from bricks_for_python.init import load_pybricks # registers UiWindow etc.
|
||||
from appbase.init import load_appbase
|
||||
from rbac.init import load_rbac
|
||||
|
||||
from world.api import load_world
|
||||
from scene.api import load_scene
|
||||
from entity.api import load_entity
|
||||
from script_engine.api import load_script_engine
|
||||
from scense.api import load_scense
|
||||
from scense_runtime.api import load_scense_runtime
|
||||
# ---- 引用模块(严格写保护:只读挂载,扩展一律走 pbl_*_ext 薄扩展模块)
|
||||
from world.init import load_world
|
||||
from scene.init import load_scene
|
||||
from entity.init import load_entity
|
||||
from script_engine.init import load_script_engine
|
||||
from scense_runtime.init import load_scense_runtime
|
||||
from scense.init import load_scense
|
||||
|
||||
from pbl_common.api import load_pbl_common
|
||||
from pbl_appcodes.api import load_pbl_appcodes
|
||||
from pbl_blueprint.api import load_pbl_blueprint
|
||||
from pbl_validation.api import load_pbl_validation
|
||||
from pbl_compiler.api import load_pbl_compiler
|
||||
from pbl_agent_runtime.api import load_pbl_agent_runtime
|
||||
from pbl_kdb_ext.api import load_pbl_kdb_ext
|
||||
from pbl_domain_ext.api import load_pbl_domain_ext
|
||||
from pbl_scense_ext.api import load_pbl_scense_ext
|
||||
from pbl_runtime_ext.api import load_pbl_runtime_ext
|
||||
from pbl_evidence.api import load_pbl_evidence
|
||||
from pbl_assessment.api import load_pbl_assessment
|
||||
# ---- 新建 pbl_* 模块(严格按 pbls_spec.json load_order)
|
||||
from pbl_common.init import load_pbl_common
|
||||
from pbl_appcodes.init import load_pbl_appcodes
|
||||
from pbl_blueprint.init import load_pbl_blueprint
|
||||
from pbl_validation.init import load_pbl_validation
|
||||
from pbl_compiler.init import load_pbl_compiler
|
||||
from pbl_agent_runtime.init import load_pbl_agent_runtime
|
||||
from pbl_evidence.init import load_pbl_evidence
|
||||
from pbl_assessment.init import load_pbl_assessment
|
||||
from pbl_domain_ext.init import load_pbl_domain_ext
|
||||
from pbl_scense_ext.init import load_pbl_scense_ext
|
||||
from pbl_runtime_ext.init import load_pbl_runtime_ext
|
||||
from pbl_kdb_ext.init import load_pbl_kdb_ext
|
||||
|
||||
DEFAULT_DBNAME_KEY = "db.dbname"
|
||||
DEFAULT_MODULE_DB = "pbls"
|
||||
CONF_PATH = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "conf", "config.json"
|
||||
)
|
||||
_MODULE_DBNAME_MAP = None
|
||||
|
||||
|
||||
def _dig(cfg, dotted, default=None):
|
||||
cur = cfg
|
||||
for part in dotted.split("."):
|
||||
if not isinstance(cur, dict) or part not in cur:
|
||||
return default
|
||||
cur = cur[part]
|
||||
return cur
|
||||
def _load_module_dbname_map():
|
||||
"""从应用 conf/config.json 的 module_dbname 段读取「模块名 → 库名」映射。
|
||||
|
||||
|
||||
def get_module_dbname(module_name, env=None):
|
||||
"""模块 → 库名映射(web-application-spec 要求,禁止在模块内硬编码库名)。
|
||||
|
||||
Phase 0/1 全部 pbl_* 模块与引用模块共用单库(env.db.dbname,默认 pbls);
|
||||
后续如需分库,只改本函数与项目 env,不动模块代码。
|
||||
库名唯一事实源是 conf/config.json(由 build.sh 依据 projects/pbls/env/*.json 生成),
|
||||
代码内不写死任何库名。
|
||||
"""
|
||||
if env is not None:
|
||||
dbname = _dig(env, DEFAULT_DBNAME_KEY)
|
||||
if dbname:
|
||||
return dbname
|
||||
return DEFAULT_MODULE_DB
|
||||
global _MODULE_DBNAME_MAP
|
||||
if _MODULE_DBNAME_MAP is None:
|
||||
with open(CONF_PATH, "r", encoding="utf-8") as fp:
|
||||
cfg = json.load(fp)
|
||||
_MODULE_DBNAME_MAP = cfg.get("module_dbname") or {}
|
||||
return _MODULE_DBNAME_MAP
|
||||
|
||||
|
||||
def init(env):
|
||||
"""应用初始化:唯一入口,端口/DB 由 projects/pbls/env/{test,prod}.json 注入。"""
|
||||
srv = ServerEnv(env)
|
||||
srv.get_module_dbname = get_module_dbname
|
||||
srv.app_name = "pbls"
|
||||
srv.port = _dig(env, "port", 9300)
|
||||
def get_module_dbname(m):
|
||||
"""返回模块 m 对应的数据库名(web-application-spec / module-development-spec 要求)。"""
|
||||
mapping = _load_module_dbname_map()
|
||||
if m in mapping:
|
||||
return mapping[m]
|
||||
if "default" in mapping:
|
||||
return mapping["default"]
|
||||
raise RuntimeError(
|
||||
"module_dbname mapping missing for module %r; check %s" % (m, CONF_PATH)
|
||||
)
|
||||
|
||||
# ---- 平台基座三件套(顺序不可调换:ServerEnv → appbase → rbac → pybricks)
|
||||
load_appbase(srv)
|
||||
load_rbac(srv)
|
||||
load_pybricks(srv)
|
||||
|
||||
# ---- 引用模块(严格写保护:只读挂载,扩展走 pbl_*_ext 薄扩展模块)
|
||||
load_world(srv)
|
||||
load_scene(srv)
|
||||
load_entity(srv)
|
||||
load_script_engine(srv)
|
||||
load_scense(srv)
|
||||
load_scense_runtime(srv)
|
||||
def password_encode(s):
|
||||
if s is None:
|
||||
return ''
|
||||
from ahserver.globalEnv import password_encode as _orig
|
||||
return _orig(s)
|
||||
|
||||
|
||||
def init():
|
||||
"""应用初始化:唯一入口。端口/DB 连接由 projects/pbls/env/{test,prod}.json 注入。"""
|
||||
env = ServerEnv() # ← MUST be before load_rbac
|
||||
env.get_module_dbname = get_module_dbname
|
||||
env.password_encode = password_encode
|
||||
|
||||
# ---- 平台基座三件套(顺序固定:ServerEnv → appbase → rbac → bricks_for_python)
|
||||
load_appbase()
|
||||
load_rbac()
|
||||
load_pybricks()
|
||||
|
||||
# ---- 引用模块(只读挂载,不改基表)
|
||||
load_world()
|
||||
load_scene()
|
||||
load_entity()
|
||||
load_script_engine()
|
||||
load_scense_runtime()
|
||||
load_scense()
|
||||
|
||||
# ---- 新建 pbl_* 模块(严格按 pbls_spec.json load_order)
|
||||
load_pbl_common(srv) # 公共内核:租户上下文/DB 适配/错误码/审计/CRUD 工厂
|
||||
load_pbl_appcodes(srv) # 枚举编码注入(8 组 74 项,幂等,零表)
|
||||
load_pbl_blueprint(srv) # M1a/M1b 蓝图聚合根 + 7 类子对象 + 版本 + 模板
|
||||
load_pbl_validation(srv) # M2 校验引擎(14 维 + 5 级质量状态)
|
||||
load_pbl_compiler(srv) # M3a/M3b 确定性编译 + Game Definition
|
||||
load_pbl_agent_runtime(srv) # M4a/M4b Designer/Critic 运行时 + fail-closed 工具裁决
|
||||
load_pbl_kdb_ext(srv) # M7 KDB 只读桩与匿名聚合(零写入)
|
||||
load_pbl_domain_ext(srv) # M8 world/scene/entity 薄扩展(不改基表)
|
||||
load_pbl_scense_ext(srv) # M9 前端覆盖层与页面注册
|
||||
load_pbl_runtime_ext(srv) # M11a/M11b 单事务事件+状态写入与广播
|
||||
load_pbl_evidence(srv) # M5a/M5b 证据幂等采集(依赖 M11b,硬约束 C-3)
|
||||
load_pbl_assessment(srv) # M6 Rubric 加权评估与报告
|
||||
load_pbl_common() # 公共内核:租户上下文/DB 适配/错误码/审计/CRUD 工厂
|
||||
load_pbl_appcodes() # 枚举编码注入(8 组 74 项,幂等,零表)
|
||||
load_pbl_blueprint() # M1a/M1b 蓝图聚合根 + 7 类子对象 + 版本 + 模板
|
||||
load_pbl_validation() # M2 校验引擎(14 维 + 5 级质量状态)
|
||||
load_pbl_compiler() # M3a/M3b 确定性编译 + Game Definition
|
||||
load_pbl_agent_runtime() # M4a/M4b Designer/Critic 运行时 + fail-closed 工具裁决
|
||||
load_pbl_evidence() # M5a/M5b 证据幂等采集
|
||||
load_pbl_assessment() # M6 Rubric 加权评估与报告
|
||||
load_pbl_domain_ext() # M8 world/scene/entity 薄扩展(不改基表)
|
||||
load_pbl_scense_ext() # M9 前端覆盖层与页面注册
|
||||
load_pbl_runtime_ext() # M11a/M11b 单事务事件+状态写入与广播
|
||||
load_pbl_kdb_ext() # M7 KDB 只读桩与匿名聚合(零写入)
|
||||
|
||||
return srv
|
||||
return env
|
||||
|
||||
|
||||
webapp(init)
|
||||
if __name__ == '__main__':
|
||||
webapp(init)
|
||||
|
||||
166
conf/config.json
166
conf/config.json
@ -5,24 +5,33 @@
|
||||
"host": "0.0.0.0",
|
||||
"port_source": "projects/pbls/env/test.json(唯一事实源,本文件与其同值 9300)",
|
||||
"debug": false,
|
||||
"website": {
|
||||
"root": "wwwroot",
|
||||
"indexes": ["index.ui", "index.tmpl", "index.html"],
|
||||
"processors": [
|
||||
[".tmpl", "tmpl"],
|
||||
[".ui", "bui"],
|
||||
[".dspy", "dspy"]
|
||||
],
|
||||
"static": [".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".woff", ".woff2", ".ttf", ".map"],
|
||||
"session": {
|
||||
"enabled": true,
|
||||
"timeout": 7200,
|
||||
"cookie_name": "pbls_sid"
|
||||
},
|
||||
"upload": {
|
||||
"max_size": 104857600,
|
||||
"allow_ext": [".png", ".jpg", ".jpeg", ".gif", ".mp4", ".mp3", ".wav", ".pdf", ".docx", ".xlsx", ".json", ".zip", ".glb", ".gltf"],
|
||||
"store_dir": "upload"
|
||||
"password_key": "pbls$[env:PASSWORD_KEY]$2026",
|
||||
"logger": {
|
||||
"name": "pbls",
|
||||
"level": "INFO",
|
||||
"file": "$[workdir]$/logs/pbls.log",
|
||||
"max_bytes": 104857600,
|
||||
"backup_count": 10
|
||||
},
|
||||
"logging": {
|
||||
"level": "INFO",
|
||||
"dir": "logs",
|
||||
"rotate_mb": 50,
|
||||
"backup_count": 10,
|
||||
"audit_enabled": true
|
||||
},
|
||||
"filesroot": "$[workdir]$/files",
|
||||
"databases": {
|
||||
"pbls": {
|
||||
"driver": "mysql",
|
||||
"kwargs": {
|
||||
"host": "127.0.0.1",
|
||||
"port": 3306,
|
||||
"user": "pbls",
|
||||
"password": "Pbls#Test2026",
|
||||
"database": "pbls",
|
||||
"charset": "utf8mb4"
|
||||
}
|
||||
}
|
||||
},
|
||||
"db": {
|
||||
@ -41,6 +50,67 @@
|
||||
"idle_timeout": 600
|
||||
}
|
||||
},
|
||||
"website": {
|
||||
"root": "wwwroot",
|
||||
"indexes": [
|
||||
"index.ui",
|
||||
"index.tmpl",
|
||||
"index.html"
|
||||
],
|
||||
"processors": [
|
||||
[
|
||||
".tmpl",
|
||||
"tmpl"
|
||||
],
|
||||
[
|
||||
".ui",
|
||||
"bui"
|
||||
],
|
||||
[
|
||||
".dspy",
|
||||
"dspy"
|
||||
]
|
||||
],
|
||||
"static": [
|
||||
".js",
|
||||
".css",
|
||||
".png",
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".gif",
|
||||
".svg",
|
||||
".ico",
|
||||
".woff",
|
||||
".woff2",
|
||||
".ttf",
|
||||
".map"
|
||||
],
|
||||
"session": {
|
||||
"enabled": true,
|
||||
"timeout": 7200,
|
||||
"cookie_name": "pbls_sid"
|
||||
},
|
||||
"upload": {
|
||||
"max_size": 104857600,
|
||||
"allow_ext": [
|
||||
".png",
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".gif",
|
||||
".mp4",
|
||||
".mp3",
|
||||
".wav",
|
||||
".pdf",
|
||||
".docx",
|
||||
".xlsx",
|
||||
".json",
|
||||
".zip",
|
||||
".glb",
|
||||
".gltf"
|
||||
],
|
||||
"store_dir": "upload"
|
||||
}
|
||||
},
|
||||
"module_dbname": {
|
||||
"apppublic": "pbls",
|
||||
"sqlor": "pbls",
|
||||
@ -72,18 +142,49 @@
|
||||
"pbl_analytics": "pbls"
|
||||
},
|
||||
"load_order": [
|
||||
"apppublic", "sqlor", "ahserver", "appbase", "rbac", "accounting",
|
||||
"world", "scene", "entity", "script_engine", "scense_runtime", "scense", "scense_game",
|
||||
"pbl_common", "pbl_appcodes", "pbl_governance", "pbl_blueprint", "pbl_template",
|
||||
"pbl_validation", "pbl_compiler", "pbl_agent_runtime", "pbl_evidence", "pbl_assessment",
|
||||
"pbl_domain_ext", "pbl_scense_ext", "pbl_runtime_ext", "pbl_kdb_ext", "pbl_analytics"
|
||||
"apppublic",
|
||||
"sqlor",
|
||||
"ahserver",
|
||||
"appbase",
|
||||
"rbac",
|
||||
"accounting",
|
||||
"world",
|
||||
"scene",
|
||||
"entity",
|
||||
"script_engine",
|
||||
"scense_runtime",
|
||||
"scense",
|
||||
"scense_game",
|
||||
"pbl_common",
|
||||
"pbl_appcodes",
|
||||
"pbl_governance",
|
||||
"pbl_blueprint",
|
||||
"pbl_template",
|
||||
"pbl_validation",
|
||||
"pbl_compiler",
|
||||
"pbl_agent_runtime",
|
||||
"pbl_evidence",
|
||||
"pbl_assessment",
|
||||
"pbl_domain_ext",
|
||||
"pbl_scense_ext",
|
||||
"pbl_runtime_ext",
|
||||
"pbl_kdb_ext",
|
||||
"pbl_analytics"
|
||||
],
|
||||
"rbac": {
|
||||
"enabled": true,
|
||||
"anonymous_paths": ["/api/public/health", "/favicon.ico"],
|
||||
"anonymous_paths": [
|
||||
"/api/public/health",
|
||||
"/favicon.ico"
|
||||
],
|
||||
"roles": [
|
||||
"owner.pbls", "admin.pbls", "teacher.pbls", "assistant.pbls",
|
||||
"student.pbls", "observer.pbls", "owner.audit"
|
||||
"owner.pbls",
|
||||
"admin.pbls",
|
||||
"teacher.pbls",
|
||||
"assistant.pbls",
|
||||
"student.pbls",
|
||||
"observer.pbls",
|
||||
"owner.audit"
|
||||
]
|
||||
},
|
||||
"agent_tools": {
|
||||
@ -91,7 +192,11 @@
|
||||
"enabled_count": 13,
|
||||
"disabled_count": 9,
|
||||
"contract_doc": "projects/pbls/docs/01-design/agent-tool-contract.md",
|
||||
"deny_on": ["not_in_whitelist", "invalid_params", "missing_tenant_context"]
|
||||
"deny_on": [
|
||||
"not_in_whitelist",
|
||||
"invalid_params",
|
||||
"missing_tenant_context"
|
||||
]
|
||||
},
|
||||
"pbl": {
|
||||
"tenant_required": true,
|
||||
@ -104,12 +209,5 @@
|
||||
"runtime_single_transaction": true,
|
||||
"kdb_write_allowed": false,
|
||||
"referenced_base_table_alter_allowed": false
|
||||
},
|
||||
"logging": {
|
||||
"level": "INFO",
|
||||
"dir": "logs",
|
||||
"rotate_mb": 50,
|
||||
"backup_count": 10,
|
||||
"audit_enabled": true
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ sqlor>=1.3.0
|
||||
apppublic>=1.2.0
|
||||
appbase>=1.3.0
|
||||
rbac>=1.2.0
|
||||
bricks_for_python>=1.2.0 # 前端积木(.ui/.bui 渲染 + load_pybricks)
|
||||
pybricks>=1.1.0
|
||||
accounting>=1.0.0
|
||||
|
||||
|
||||
@ -18,9 +18,9 @@ SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- 1. pbl_tenant 租户主表
|
||||
CREATE TABLE IF NOT EXISTS pbl_tenant (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID(第一业务列)',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
tenant_code VARCHAR(32) NOT NULL COMMENT '租户业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID(第一业务列)',
|
||||
tenant_name VARCHAR(128) NOT NULL COMMENT '租户名称',
|
||||
org_code VARCHAR(32) DEFAULT NULL COMMENT '所属机构编码(rbac 侧只读引用)',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/suspended/closed(appcodes_kv: pbl_tenant_status)',
|
||||
@ -39,9 +39,9 @@ CREATE TABLE IF NOT EXISTS pbl_tenant (
|
||||
|
||||
-- 2. pbl_role_binding 租户内角色绑定(复用 rbac,不改 rbac 基表)
|
||||
CREATE TABLE IF NOT EXISTS pbl_role_binding (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
binding_code VARCHAR(32) NOT NULL COMMENT '绑定业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
user_code VARCHAR(32) NOT NULL COMMENT '用户编码(rbac 只读引用)',
|
||||
role_code VARCHAR(32) NOT NULL COMMENT '角色编码:teacher/assistant/student/observer/admin(appcodes_kv: pbl_role)',
|
||||
scope_type VARCHAR(16) NOT NULL DEFAULT 'tenant' COMMENT '作用域类型:tenant/blueprint/class/team',
|
||||
@ -62,9 +62,9 @@ CREATE TABLE IF NOT EXISTS pbl_role_binding (
|
||||
|
||||
-- 3. pbl_audit_log 审计日志(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_audit_log (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
audit_code VARCHAR(32) NOT NULL COMMENT '审计业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
actor_type VARCHAR(16) NOT NULL DEFAULT 'user' COMMENT '主体类型:user/agent/system',
|
||||
actor_code VARCHAR(32) DEFAULT NULL COMMENT '主体编码',
|
||||
action_code VARCHAR(64) NOT NULL COMMENT '动作编码(appcodes_kv: pbl_audit_action)',
|
||||
@ -89,9 +89,9 @@ CREATE TABLE IF NOT EXISTS pbl_audit_log (
|
||||
|
||||
-- 4. pbl_blueprint 蓝图聚合根
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_name VARCHAR(128) NOT NULL COMMENT '蓝图名称',
|
||||
subject_code VARCHAR(32) DEFAULT NULL COMMENT '学科编码(appcodes_kv: pbl_subject)',
|
||||
grade_code VARCHAR(32) DEFAULT NULL COMMENT '学段编码(appcodes_kv: pbl_grade)',
|
||||
@ -124,9 +124,9 @@ CREATE TABLE IF NOT EXISTS pbl_blueprint (
|
||||
|
||||
-- 5. pbl_blueprint_version 版本快照 + change_delta(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint_version (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
version_code VARCHAR(32) NOT NULL COMMENT '版本业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
version_no INT NOT NULL COMMENT '版本号(单调递增)',
|
||||
snapshot LONGTEXT DEFAULT NULL COMMENT '蓝图全量快照 JSON',
|
||||
@ -144,9 +144,9 @@ CREATE TABLE IF NOT EXISTS pbl_blueprint_version (
|
||||
|
||||
-- 6. pbl_blueprint_lock 编辑锁
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint_lock (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
lock_code VARCHAR(32) NOT NULL COMMENT '锁业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
holder_code VARCHAR(32) NOT NULL COMMENT '持有者',
|
||||
session_id VARCHAR(64) DEFAULT NULL COMMENT '会话ID',
|
||||
@ -166,9 +166,9 @@ CREATE TABLE IF NOT EXISTS pbl_blueprint_lock (
|
||||
|
||||
-- 7. pbl_subobject 7 类子对象泛化主表
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
obj_code VARCHAR(32) NOT NULL COMMENT '子对象业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '所属蓝图',
|
||||
obj_type VARCHAR(32) NOT NULL COMMENT '子对象类型:objective/stage/task/artifact_spec/rubric_ref/resource_ref/assessment_plan(appcodes_kv: pbl_subobj_type)',
|
||||
parent_code VARCHAR(32) DEFAULT NULL COMMENT '父子对象编码(树形)',
|
||||
@ -192,9 +192,9 @@ CREATE TABLE IF NOT EXISTS pbl_subobject (
|
||||
|
||||
-- 8. pbl_subobject_attr 子对象泛化属性(KV)
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_attr (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
attr_code VARCHAR(32) NOT NULL COMMENT '属性业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
obj_code VARCHAR(32) NOT NULL COMMENT '子对象编码',
|
||||
attr_key VARCHAR(64) NOT NULL COMMENT '属性键',
|
||||
attr_value TEXT DEFAULT NULL COMMENT '属性值',
|
||||
@ -211,9 +211,9 @@ CREATE TABLE IF NOT EXISTS pbl_subobject_attr (
|
||||
|
||||
-- 9. pbl_subobject_rel 子对象间关系
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_rel (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
rel_code VARCHAR(32) NOT NULL COMMENT '关系业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '所属蓝图',
|
||||
src_obj_code VARCHAR(32) NOT NULL COMMENT '源子对象',
|
||||
dst_obj_code VARCHAR(32) NOT NULL COMMENT '目标子对象',
|
||||
@ -232,9 +232,9 @@ CREATE TABLE IF NOT EXISTS pbl_subobject_rel (
|
||||
|
||||
-- 10. pbl_subobject_asset 子对象资产引用(只读引用平台资产,不落资产本体)
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_asset (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
asset_code VARCHAR(32) NOT NULL COMMENT '资产引用业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
obj_code VARCHAR(32) NOT NULL COMMENT '子对象编码',
|
||||
asset_kind VARCHAR(32) NOT NULL COMMENT '资产种类:image/model/audio/video/doc/url(appcodes_kv: pbl_asset_kind)',
|
||||
asset_uri VARCHAR(512) DEFAULT NULL COMMENT '资产 URI',
|
||||
@ -255,9 +255,9 @@ CREATE TABLE IF NOT EXISTS pbl_subobject_asset (
|
||||
|
||||
-- 11. pbl_subobject_ref 子对象对复用域对象的只读引用(world/scene/entity/script)
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_ref (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ref_code VARCHAR(32) NOT NULL COMMENT '引用业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
obj_code VARCHAR(32) NOT NULL COMMENT '子对象编码',
|
||||
ref_module VARCHAR(32) NOT NULL COMMENT '被引用模块:world/scene/entity/script_engine/scense/scense_game',
|
||||
ref_table VARCHAR(64) NOT NULL COMMENT '被引用表名',
|
||||
@ -276,9 +276,9 @@ CREATE TABLE IF NOT EXISTS pbl_subobject_ref (
|
||||
|
||||
-- 12. pbl_subobject_review 子对象评审意见(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_review (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
review_code VARCHAR(32) NOT NULL COMMENT '评审业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
obj_code VARCHAR(32) DEFAULT NULL COMMENT '子对象编码(空=蓝图级)',
|
||||
reviewer_type VARCHAR(16) NOT NULL DEFAULT 'user' COMMENT '评审主体:user/agent_critic/agent_designer',
|
||||
@ -295,9 +295,9 @@ CREATE TABLE IF NOT EXISTS pbl_subobject_review (
|
||||
|
||||
-- 13. pbl_blueprint_tag 蓝图标签
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint_tag (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
tag_code VARCHAR(32) NOT NULL COMMENT '标签业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
tag_key VARCHAR(64) NOT NULL COMMENT '标签键',
|
||||
tag_value VARCHAR(128) DEFAULT NULL COMMENT '标签值',
|
||||
@ -311,9 +311,9 @@ CREATE TABLE IF NOT EXISTS pbl_blueprint_tag (
|
||||
|
||||
-- 14. pbl_blueprint_publish 发布记录(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint_publish (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
publish_code VARCHAR(32) NOT NULL COMMENT '发布业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
version_no INT NOT NULL COMMENT '发布版本号',
|
||||
gd_code VARCHAR(32) DEFAULT NULL COMMENT '关联 Game Definition 编码',
|
||||
@ -334,9 +334,9 @@ CREATE TABLE IF NOT EXISTS pbl_blueprint_publish (
|
||||
|
||||
-- 15. pbl_template 模板主表(含离线兜底模板)
|
||||
CREATE TABLE IF NOT EXISTS pbl_template (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID(__system__ 表示平台内置)',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
tpl_code VARCHAR(32) NOT NULL COMMENT '模板业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID(__system__ 表示平台内置)',
|
||||
tpl_name VARCHAR(128) NOT NULL COMMENT '模板名称',
|
||||
tpl_kind VARCHAR(32) NOT NULL DEFAULT 'blueprint' COMMENT '模板种类:blueprint/subobject/rubric',
|
||||
subject_code VARCHAR(32) DEFAULT NULL COMMENT '适用学科',
|
||||
@ -359,9 +359,9 @@ CREATE TABLE IF NOT EXISTS pbl_template (
|
||||
|
||||
-- 16. pbl_template_item 模板条目(实例化 ID 重映射映射表)
|
||||
CREATE TABLE IF NOT EXISTS pbl_template_item (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
item_code VARCHAR(32) NOT NULL COMMENT '条目业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
tpl_code VARCHAR(32) NOT NULL COMMENT '模板编码',
|
||||
tpl_obj_key VARCHAR(64) NOT NULL COMMENT '模板内占位键(如 __OBJ_1__)',
|
||||
obj_type VARCHAR(32) NOT NULL COMMENT '子对象类型',
|
||||
@ -382,9 +382,9 @@ CREATE TABLE IF NOT EXISTS pbl_template_item (
|
||||
|
||||
-- 17. pbl_validation_ruleset 校验规则集
|
||||
CREATE TABLE IF NOT EXISTS pbl_validation_ruleset (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ruleset_code VARCHAR(32) NOT NULL COMMENT '规则集业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
ruleset_name VARCHAR(128) NOT NULL COMMENT '规则集名称',
|
||||
dim_code VARCHAR(32) NOT NULL COMMENT '维度编码 D01~D14(appcodes_kv: pbl_valid_dim)',
|
||||
dim_name VARCHAR(64) NOT NULL COMMENT '维度名称',
|
||||
@ -406,9 +406,9 @@ CREATE TABLE IF NOT EXISTS pbl_validation_ruleset (
|
||||
|
||||
-- 18. pbl_validation_run 校验执行批次
|
||||
CREATE TABLE IF NOT EXISTS pbl_validation_run (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
run_code VARCHAR(32) NOT NULL COMMENT '执行批次业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
version_no INT NOT NULL DEFAULT 1 COMMENT '被校验版本号',
|
||||
ruleset_ver VARCHAR(32) DEFAULT NULL COMMENT '规则集版本',
|
||||
@ -435,9 +435,9 @@ CREATE TABLE IF NOT EXISTS pbl_validation_run (
|
||||
|
||||
-- 19. pbl_validation_finding 校验发现明细(append-only 留痕)
|
||||
CREATE TABLE IF NOT EXISTS pbl_validation_finding (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
finding_code VARCHAR(32) NOT NULL COMMENT '发现业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
run_code VARCHAR(32) NOT NULL COMMENT '执行批次编码',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
dim_code VARCHAR(32) NOT NULL COMMENT '维度编码',
|
||||
@ -460,9 +460,9 @@ CREATE TABLE IF NOT EXISTS pbl_validation_finding (
|
||||
|
||||
-- 20. pbl_compile_job 编译作业
|
||||
CREATE TABLE IF NOT EXISTS pbl_compile_job (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
job_code VARCHAR(32) NOT NULL COMMENT '作业业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
version_no INT NOT NULL COMMENT '被编译版本号',
|
||||
run_code VARCHAR(32) DEFAULT NULL COMMENT '前置校验批次(必须 passed)',
|
||||
@ -486,9 +486,9 @@ CREATE TABLE IF NOT EXISTS pbl_compile_job (
|
||||
|
||||
-- 21. pbl_compile_artifact 编译中间产物
|
||||
CREATE TABLE IF NOT EXISTS pbl_compile_artifact (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
artifact_code VARCHAR(32) NOT NULL COMMENT '产物业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
job_code VARCHAR(32) NOT NULL COMMENT '编译作业编码',
|
||||
stage_code VARCHAR(32) NOT NULL COMMENT '编译阶段:normalize/resolve/link/optimize/emit',
|
||||
artifact_kind VARCHAR(32) NOT NULL COMMENT '产物种类:node_set/edge_set/rule_set/asset_map/gd_draft',
|
||||
@ -505,9 +505,9 @@ CREATE TABLE IF NOT EXISTS pbl_compile_artifact (
|
||||
|
||||
-- 22. pbl_game_definition Game Definition(编译最终产出)
|
||||
CREATE TABLE IF NOT EXISTS pbl_game_definition (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
gd_code VARCHAR(32) NOT NULL COMMENT 'Game Definition 业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '来源蓝图',
|
||||
version_no INT NOT NULL COMMENT '来源蓝图版本',
|
||||
gd_version INT NOT NULL DEFAULT 1 COMMENT 'GD 自身版本',
|
||||
@ -532,9 +532,9 @@ CREATE TABLE IF NOT EXISTS pbl_game_definition (
|
||||
|
||||
-- 23. pbl_compile_log 编译日志(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_compile_log (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
log_code VARCHAR(32) NOT NULL COMMENT '日志业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
job_code VARCHAR(32) NOT NULL COMMENT '编译作业编码',
|
||||
stage_code VARCHAR(32) DEFAULT NULL COMMENT '阶段',
|
||||
log_level VARCHAR(16) NOT NULL DEFAULT 'info' COMMENT '级别:debug/info/warn/error',
|
||||
@ -554,9 +554,9 @@ CREATE TABLE IF NOT EXISTS pbl_compile_log (
|
||||
|
||||
-- 24. pbl_agent_session Agent 会话
|
||||
CREATE TABLE IF NOT EXISTS pbl_agent_session (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
session_code VARCHAR(32) NOT NULL COMMENT '会话业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) DEFAULT NULL COMMENT '关联蓝图',
|
||||
agent_role VARCHAR(32) NOT NULL COMMENT 'Agent 角色:designer/critic(appcodes_kv: pbl_agent_role)',
|
||||
model_name VARCHAR(64) DEFAULT NULL COMMENT '使用的平台模型注册名',
|
||||
@ -579,9 +579,9 @@ CREATE TABLE IF NOT EXISTS pbl_agent_session (
|
||||
|
||||
-- 25. pbl_agent_message Agent 消息(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_agent_message (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
msg_code VARCHAR(32) NOT NULL COMMENT '消息业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
session_code VARCHAR(32) NOT NULL COMMENT '会话编码',
|
||||
turn_no INT NOT NULL DEFAULT 0 COMMENT '轮次号',
|
||||
role VARCHAR(16) NOT NULL COMMENT '角色:system/user/assistant/tool',
|
||||
@ -598,9 +598,9 @@ CREATE TABLE IF NOT EXISTS pbl_agent_message (
|
||||
|
||||
-- 26. pbl_agent_tool_call 工具调用记录(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_agent_tool_call (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
call_code VARCHAR(32) NOT NULL COMMENT '调用业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
session_code VARCHAR(32) NOT NULL COMMENT '会话编码',
|
||||
turn_no INT NOT NULL DEFAULT 0 COMMENT '轮次号',
|
||||
tool_name VARCHAR(64) NOT NULL COMMENT '工具名(13 启用 / 9 禁用白名单外)',
|
||||
@ -618,9 +618,9 @@ CREATE TABLE IF NOT EXISTS pbl_agent_tool_call (
|
||||
|
||||
-- 27. pbl_agent_arbitration fail-closed 裁决记录(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_agent_arbitration (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
arb_code VARCHAR(32) NOT NULL COMMENT '裁决业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
session_code VARCHAR(32) DEFAULT NULL COMMENT '会话编码',
|
||||
call_code VARCHAR(32) DEFAULT NULL COMMENT '关联调用编码',
|
||||
tool_name VARCHAR(64) NOT NULL COMMENT '被裁决工具名',
|
||||
@ -643,9 +643,9 @@ CREATE TABLE IF NOT EXISTS pbl_agent_arbitration (
|
||||
|
||||
-- 28. pbl_artifact 学生产出物
|
||||
CREATE TABLE IF NOT EXISTS pbl_artifact (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
artifact_code VARCHAR(32) NOT NULL COMMENT '产出物业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
session_code VARCHAR(32) DEFAULT NULL COMMENT '运行会话编码',
|
||||
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
|
||||
@ -671,9 +671,9 @@ CREATE TABLE IF NOT EXISTS pbl_artifact (
|
||||
|
||||
-- 29. pbl_evidence 证据主表
|
||||
CREATE TABLE IF NOT EXISTS pbl_evidence (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
evidence_code VARCHAR(32) NOT NULL COMMENT '证据业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
artifact_code VARCHAR(32) DEFAULT NULL COMMENT '关联产出物',
|
||||
obj_code VARCHAR(32) DEFAULT NULL COMMENT '关联子对象(学习目标/任务)',
|
||||
@ -700,9 +700,9 @@ CREATE TABLE IF NOT EXISTS pbl_evidence (
|
||||
|
||||
-- 30. pbl_evidence_idem 证据幂等提交台账(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_evidence_idem (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
idem_code VARCHAR(32) NOT NULL COMMENT '幂等台账业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
idem_key VARCHAR(128) NOT NULL COMMENT '幂等键',
|
||||
evidence_code VARCHAR(32) DEFAULT NULL COMMENT '首次落库证据编码',
|
||||
submit_count INT NOT NULL DEFAULT 1 COMMENT '累计提交次数(重复提交只增此计数,不新增证据行)',
|
||||
@ -719,9 +719,9 @@ CREATE TABLE IF NOT EXISTS pbl_evidence_idem (
|
||||
|
||||
-- 31. pbl_evidence_binding 证据与复用域对象绑定(零改表关联)
|
||||
CREATE TABLE IF NOT EXISTS pbl_evidence_binding (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
bind_code VARCHAR(32) NOT NULL COMMENT '绑定业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
evidence_code VARCHAR(32) NOT NULL COMMENT '证据编码',
|
||||
ref_module VARCHAR(32) NOT NULL COMMENT '复用域模块:world/scene/entity/script_engine/scense_runtime/scense/scense_game',
|
||||
ref_table VARCHAR(64) NOT NULL COMMENT '复用域表名',
|
||||
@ -742,9 +742,9 @@ CREATE TABLE IF NOT EXISTS pbl_evidence_binding (
|
||||
|
||||
-- 32. pbl_rubric 量规主表
|
||||
CREATE TABLE IF NOT EXISTS pbl_rubric (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
rubric_code VARCHAR(32) NOT NULL COMMENT '量规业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) DEFAULT NULL COMMENT '关联蓝图(空=通用量规)',
|
||||
rubric_name VARCHAR(128) NOT NULL COMMENT '量规名称',
|
||||
level_count INT NOT NULL DEFAULT 5 COMMENT '等级数(默认 5 级)',
|
||||
@ -766,9 +766,9 @@ CREATE TABLE IF NOT EXISTS pbl_rubric (
|
||||
|
||||
-- 33. pbl_rubric_criterion 量规评价维度条目
|
||||
CREATE TABLE IF NOT EXISTS pbl_rubric_criterion (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
crit_code VARCHAR(32) NOT NULL COMMENT '条目业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
rubric_code VARCHAR(32) NOT NULL COMMENT '量规编码',
|
||||
obj_code VARCHAR(32) DEFAULT NULL COMMENT '关联学习目标子对象',
|
||||
crit_name VARCHAR(128) NOT NULL COMMENT '维度名称',
|
||||
@ -788,9 +788,9 @@ CREATE TABLE IF NOT EXISTS pbl_rubric_criterion (
|
||||
|
||||
-- 34. pbl_assessment_report 评估报告
|
||||
CREATE TABLE IF NOT EXISTS pbl_assessment_report (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
report_code VARCHAR(32) NOT NULL COMMENT '报告业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
rubric_code VARCHAR(32) NOT NULL COMMENT '量规编码',
|
||||
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
|
||||
@ -823,9 +823,9 @@ CREATE TABLE IF NOT EXISTS pbl_assessment_report (
|
||||
|
||||
-- 35. pbl_domain_binding 复用域对象绑定(零改表唯一关联落点)
|
||||
CREATE TABLE IF NOT EXISTS pbl_domain_binding (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
bind_code VARCHAR(32) NOT NULL COMMENT '绑定业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bind_kind VARCHAR(32) NOT NULL COMMENT '绑定种类:tenant_world/class_scene/team_entity/bp_script/session_world(appcodes_kv: pbl_bind_kind)',
|
||||
class_code VARCHAR(32) DEFAULT NULL COMMENT '班级编码',
|
||||
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
|
||||
@ -857,9 +857,9 @@ CREATE TABLE IF NOT EXISTS pbl_domain_binding (
|
||||
|
||||
-- 36. pbl_analytics_snapshot 分析快照(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_analytics_snapshot (
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
snap_code VARCHAR(32) NOT NULL COMMENT '快照业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
metric_group VARCHAR(32) NOT NULL COMMENT '指标组:blueprint/validation/compile/runtime/evidence/assessment(appcodes_kv: pbl_metric_group)',
|
||||
scope_type VARCHAR(16) NOT NULL DEFAULT 'tenant' COMMENT '范围:tenant/class/team/blueprint',
|
||||
scope_code VARCHAR(32) DEFAULT NULL COMMENT '范围对象编码',
|
||||
|
||||
893
scripts/ddl/pbls_tables.sql.bak
Normal file
893
scripts/ddl/pbls_tables.sql.bak
Normal file
@ -0,0 +1,893 @@
|
||||
-- =====================================================================
|
||||
-- PBL Agent OS 验证原型(Phase 0/1)—— 36 表可执行 DDL
|
||||
-- 方言:mariadb(InnoDB + utf8mb4/utf8mb4_general_ci)
|
||||
-- 规则:id BIGINT NOT NULL AUTO_INCREMENT 物理主键 + xxx_code VARCHAR(32) 业务主键(唯一索引)
|
||||
-- tenant_id VARCHAR(32) NOT NULL 为第一业务列,所有索引以 tenant_id 打头
|
||||
-- 禁止 FOREIGN KEY / 禁止 ENUM / 禁止原生 TIMESTAMP(用 DATETIME)
|
||||
-- append-only 表无 update_time、无物理删除(11 张,见文末清单)
|
||||
-- 权威来源:projects/pbls/docs/01-design/data-model.md
|
||||
-- 执行:apps/pbls/build.sh -> mysql --protocol=TCP -h127.0.0.1 -P3306 pbls < pbls_tables.sql
|
||||
-- =====================================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_governance(3 表)
|
||||
-- =====================================================================
|
||||
|
||||
-- 1. pbl_tenant 租户主表
|
||||
CREATE TABLE IF NOT EXISTS pbl_tenant (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
tenant_code VARCHAR(32) NOT NULL COMMENT '租户业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID(第一业务列)',
|
||||
tenant_name VARCHAR(128) NOT NULL COMMENT '租户名称',
|
||||
org_code VARCHAR(32) DEFAULT NULL COMMENT '所属机构编码(rbac 侧只读引用)',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/suspended/closed(appcodes_kv: pbl_tenant_status)',
|
||||
quota_bp INT NOT NULL DEFAULT 100 COMMENT '蓝图配额',
|
||||
quota_stu INT NOT NULL DEFAULT 500 COMMENT '学生席位配额',
|
||||
remark VARCHAR(512) DEFAULT NULL COMMENT '备注',
|
||||
create_by VARCHAR(32) DEFAULT NULL COMMENT '创建人',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||
update_by VARCHAR(32) DEFAULT NULL COMMENT '更新人',
|
||||
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_tenant_code (tenant_code),
|
||||
KEY idx_pbl_tenant_tid_status (tenant_id, status),
|
||||
KEY idx_pbl_tenant_tid_org (tenant_id, org_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 租户主表';
|
||||
|
||||
-- 2. pbl_role_binding 租户内角色绑定(复用 rbac,不改 rbac 基表)
|
||||
CREATE TABLE IF NOT EXISTS pbl_role_binding (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
binding_code VARCHAR(32) NOT NULL COMMENT '绑定业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
user_code VARCHAR(32) NOT NULL COMMENT '用户编码(rbac 只读引用)',
|
||||
role_code VARCHAR(32) NOT NULL COMMENT '角色编码:teacher/assistant/student/observer/admin(appcodes_kv: pbl_role)',
|
||||
scope_type VARCHAR(16) NOT NULL DEFAULT 'tenant' COMMENT '作用域类型:tenant/blueprint/class/team',
|
||||
scope_code VARCHAR(32) DEFAULT NULL COMMENT '作用域对象编码',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/revoked',
|
||||
effective_from DATETIME DEFAULT NULL COMMENT '生效起',
|
||||
effective_to DATETIME DEFAULT NULL COMMENT '生效止',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_by VARCHAR(32) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_role_binding_code (binding_code),
|
||||
KEY idx_pbl_role_binding_tid_user (tenant_id, user_code, status),
|
||||
KEY idx_pbl_role_binding_tid_scope (tenant_id, scope_type, scope_code),
|
||||
KEY idx_pbl_role_binding_tid_role (tenant_id, role_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 租户角色绑定';
|
||||
|
||||
-- 3. pbl_audit_log 审计日志(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_audit_log (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
audit_code VARCHAR(32) NOT NULL COMMENT '审计业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
actor_type VARCHAR(16) NOT NULL DEFAULT 'user' COMMENT '主体类型:user/agent/system',
|
||||
actor_code VARCHAR(32) DEFAULT NULL COMMENT '主体编码',
|
||||
action_code VARCHAR(64) NOT NULL COMMENT '动作编码(appcodes_kv: pbl_audit_action)',
|
||||
object_type VARCHAR(32) DEFAULT NULL COMMENT '对象类型',
|
||||
object_code VARCHAR(32) DEFAULT NULL COMMENT '对象编码',
|
||||
result VARCHAR(16) NOT NULL DEFAULT 'success' COMMENT '结果:success/denied/error',
|
||||
detail TEXT DEFAULT NULL COMMENT '详情 JSON',
|
||||
trace_id VARCHAR(64) DEFAULT NULL COMMENT '链路追踪ID',
|
||||
client_ip VARCHAR(64) DEFAULT NULL COMMENT '来源IP',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '发生时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_audit_code (audit_code),
|
||||
KEY idx_pbl_audit_tid_time (tenant_id, create_time),
|
||||
KEY idx_pbl_audit_tid_obj (tenant_id, object_type, object_code),
|
||||
KEY idx_pbl_audit_tid_actor (tenant_id, actor_type, actor_code),
|
||||
KEY idx_pbl_audit_tid_trace (tenant_id, trace_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 审计日志(append-only)';
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_blueprint(11 表,M1a)
|
||||
-- =====================================================================
|
||||
|
||||
-- 4. pbl_blueprint 蓝图聚合根
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_name VARCHAR(128) NOT NULL COMMENT '蓝图名称',
|
||||
subject_code VARCHAR(32) DEFAULT NULL COMMENT '学科编码(appcodes_kv: pbl_subject)',
|
||||
grade_code VARCHAR(32) DEFAULT NULL COMMENT '学段编码(appcodes_kv: pbl_grade)',
|
||||
driving_q TEXT DEFAULT NULL COMMENT '驱动性问题',
|
||||
summary VARCHAR(1024) DEFAULT NULL COMMENT '蓝图摘要',
|
||||
duration_hours INT NOT NULL DEFAULT 0 COMMENT '总课时(小时)',
|
||||
team_size_min INT NOT NULL DEFAULT 1 COMMENT '最小团队人数',
|
||||
team_size_max INT NOT NULL DEFAULT 6 COMMENT '最大团队人数',
|
||||
cur_version INT NOT NULL DEFAULT 1 COMMENT '当前版本号(乐观锁)',
|
||||
quality_level VARCHAR(16) NOT NULL DEFAULT 'L0_draft' COMMENT '质量等级 L0~L4(appcodes_kv: pbl_quality_level)',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT '状态:draft/validating/validated/compiling/published/archived(appcodes_kv: pbl_bp_status)',
|
||||
source_type VARCHAR(16) NOT NULL DEFAULT 'manual' COMMENT '来源:manual/template/fork/agent',
|
||||
source_code VARCHAR(32) DEFAULT NULL COMMENT '来源对象编码(模板/父蓝图)',
|
||||
owner_code VARCHAR(32) DEFAULT NULL COMMENT '归属教师',
|
||||
lock_holder VARCHAR(32) DEFAULT NULL COMMENT '当前编辑锁持有者',
|
||||
lock_expire DATETIME DEFAULT NULL COMMENT '编辑锁过期时间',
|
||||
extra TEXT DEFAULT NULL COMMENT '扩展 JSON',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_by VARCHAR(32) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_blueprint_code (bp_code),
|
||||
KEY idx_pbl_bp_tid_status (tenant_id, status),
|
||||
KEY idx_pbl_bp_tid_owner (tenant_id, owner_code),
|
||||
KEY idx_pbl_bp_tid_subject (tenant_id, subject_code, grade_code),
|
||||
KEY idx_pbl_bp_tid_quality (tenant_id, quality_level),
|
||||
KEY idx_pbl_bp_tid_source (tenant_id, source_type, source_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图聚合根';
|
||||
|
||||
-- 5. pbl_blueprint_version 版本快照 + change_delta(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint_version (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
version_code VARCHAR(32) NOT NULL COMMENT '版本业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
version_no INT NOT NULL COMMENT '版本号(单调递增)',
|
||||
snapshot LONGTEXT DEFAULT NULL COMMENT '蓝图全量快照 JSON',
|
||||
change_delta LONGTEXT DEFAULT NULL COMMENT '相对上一版本的差异 JSON(可回放)',
|
||||
checksum VARCHAR(64) DEFAULT NULL COMMENT '快照 sha256',
|
||||
reason VARCHAR(512) DEFAULT NULL COMMENT '变更原因',
|
||||
created_by VARCHAR(32) DEFAULT NULL COMMENT '提交人',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '提交时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_bp_version_code (version_code),
|
||||
UNIQUE KEY uk_pbl_bp_version_no (tenant_id, bp_code, version_no),
|
||||
KEY idx_pbl_bp_version_tid_bp (tenant_id, bp_code, create_time),
|
||||
KEY idx_pbl_bp_version_tid_ck (tenant_id, checksum)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图版本快照(append-only)';
|
||||
|
||||
-- 6. pbl_blueprint_lock 编辑锁
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint_lock (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
lock_code VARCHAR(32) NOT NULL COMMENT '锁业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
holder_code VARCHAR(32) NOT NULL COMMENT '持有者',
|
||||
session_id VARCHAR(64) DEFAULT NULL COMMENT '会话ID',
|
||||
lock_state VARCHAR(16) NOT NULL DEFAULT 'held' COMMENT '锁状态:held/released/expired/forced',
|
||||
acquired_at DATETIME DEFAULT NULL COMMENT '获取时间',
|
||||
expire_at DATETIME DEFAULT NULL COMMENT '过期时间',
|
||||
released_at DATETIME DEFAULT NULL COMMENT '释放时间',
|
||||
version_no INT NOT NULL DEFAULT 0 COMMENT '加锁时版本号',
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_bp_lock_code (lock_code),
|
||||
UNIQUE KEY uk_pbl_bp_lock_active (tenant_id, bp_code, lock_state),
|
||||
KEY idx_pbl_bp_lock_tid_holder (tenant_id, holder_code),
|
||||
KEY idx_pbl_bp_lock_tid_expire (tenant_id, expire_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图编辑锁';
|
||||
|
||||
-- 7. pbl_subobject 7 类子对象泛化主表
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
obj_code VARCHAR(32) NOT NULL COMMENT '子对象业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '所属蓝图',
|
||||
obj_type VARCHAR(32) NOT NULL COMMENT '子对象类型:objective/stage/task/artifact_spec/rubric_ref/resource_ref/assessment_plan(appcodes_kv: pbl_subobj_type)',
|
||||
parent_code VARCHAR(32) DEFAULT NULL COMMENT '父子对象编码(树形)',
|
||||
obj_name VARCHAR(128) NOT NULL COMMENT '名称',
|
||||
obj_summary VARCHAR(1024) DEFAULT NULL COMMENT '摘要',
|
||||
sort_no INT NOT NULL DEFAULT 0 COMMENT '同级排序',
|
||||
payload LONGTEXT DEFAULT NULL COMMENT '类型化载荷 JSON(泛化契约)',
|
||||
schema_ver VARCHAR(16) NOT NULL DEFAULT 'v1' COMMENT '载荷 schema 版本',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/disabled/deleted',
|
||||
version_no INT NOT NULL DEFAULT 1 COMMENT '乐观锁版本号',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_by VARCHAR(32) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_subobject_code (obj_code),
|
||||
KEY idx_pbl_subobj_tid_bp_type (tenant_id, bp_code, obj_type, sort_no),
|
||||
KEY idx_pbl_subobj_tid_parent (tenant_id, parent_code),
|
||||
KEY idx_pbl_subobj_tid_status (tenant_id, status)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图 7 类子对象泛化主表';
|
||||
|
||||
-- 8. pbl_subobject_attr 子对象泛化属性(KV)
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_attr (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
attr_code VARCHAR(32) NOT NULL COMMENT '属性业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
obj_code VARCHAR(32) NOT NULL COMMENT '子对象编码',
|
||||
attr_key VARCHAR(64) NOT NULL COMMENT '属性键',
|
||||
attr_value TEXT DEFAULT NULL COMMENT '属性值',
|
||||
value_type VARCHAR(16) NOT NULL DEFAULT 'string' COMMENT '值类型:string/int/float/bool/json/date',
|
||||
required_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否必填 0否1是',
|
||||
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_subobj_attr_code (attr_code),
|
||||
UNIQUE KEY uk_pbl_subobj_attr_key (tenant_id, obj_code, attr_key),
|
||||
KEY idx_pbl_subobj_attr_tid_obj (tenant_id, obj_code, sort_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象泛化属性 KV';
|
||||
|
||||
-- 9. pbl_subobject_rel 子对象间关系
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_rel (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
rel_code VARCHAR(32) NOT NULL COMMENT '关系业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '所属蓝图',
|
||||
src_obj_code VARCHAR(32) NOT NULL COMMENT '源子对象',
|
||||
dst_obj_code VARCHAR(32) NOT NULL COMMENT '目标子对象',
|
||||
rel_type VARCHAR(32) NOT NULL COMMENT '关系类型:depends_on/produces/assesses/references/contains(appcodes_kv: pbl_rel_type)',
|
||||
weight DECIMAL(6,3) NOT NULL DEFAULT 1.000 COMMENT '关系权重',
|
||||
remark VARCHAR(512) DEFAULT NULL COMMENT '备注',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_subobj_rel_code (rel_code),
|
||||
UNIQUE KEY uk_pbl_subobj_rel_triple (tenant_id, src_obj_code, dst_obj_code, rel_type),
|
||||
KEY idx_pbl_subobj_rel_tid_bp (tenant_id, bp_code, rel_type),
|
||||
KEY idx_pbl_subobj_rel_tid_dst (tenant_id, dst_obj_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象关系';
|
||||
|
||||
-- 10. pbl_subobject_asset 子对象资产引用(只读引用平台资产,不落资产本体)
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_asset (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
asset_code VARCHAR(32) NOT NULL COMMENT '资产引用业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
obj_code VARCHAR(32) NOT NULL COMMENT '子对象编码',
|
||||
asset_kind VARCHAR(32) NOT NULL COMMENT '资产种类:image/model/audio/video/doc/url(appcodes_kv: pbl_asset_kind)',
|
||||
asset_uri VARCHAR(512) DEFAULT NULL COMMENT '资产 URI',
|
||||
asset_name VARCHAR(128) DEFAULT NULL COMMENT '资产名称',
|
||||
mime_type VARCHAR(64) DEFAULT NULL COMMENT 'MIME',
|
||||
size_bytes BIGINT NOT NULL DEFAULT 0 COMMENT '字节数',
|
||||
checksum VARCHAR(64) DEFAULT NULL COMMENT 'sha256',
|
||||
license_code VARCHAR(32) DEFAULT NULL COMMENT '许可编码',
|
||||
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_subobj_asset_code (asset_code),
|
||||
KEY idx_pbl_subobj_asset_tid_obj (tenant_id, obj_code, sort_no),
|
||||
KEY idx_pbl_subobj_asset_tid_kind (tenant_id, asset_kind)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象资产引用';
|
||||
|
||||
-- 11. pbl_subobject_ref 子对象对复用域对象的只读引用(world/scene/entity/script)
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_ref (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ref_code VARCHAR(32) NOT NULL COMMENT '引用业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
obj_code VARCHAR(32) NOT NULL COMMENT '子对象编码',
|
||||
ref_module VARCHAR(32) NOT NULL COMMENT '被引用模块:world/scene/entity/script_engine/scense/scense_game',
|
||||
ref_table VARCHAR(64) NOT NULL COMMENT '被引用表名',
|
||||
ref_id BIGINT DEFAULT NULL COMMENT '被引用行 id',
|
||||
ref_biz_code VARCHAR(64) DEFAULT NULL COMMENT '被引用业务编码',
|
||||
ref_mode VARCHAR(16) NOT NULL DEFAULT 'readonly' COMMENT '引用模式:readonly(Phase 0/1 唯一合法值)',
|
||||
snapshot_json TEXT DEFAULT NULL COMMENT '引用时只读快照(不改基表)',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_subobj_ref_code (ref_code),
|
||||
KEY idx_pbl_subobj_ref_tid_obj (tenant_id, obj_code),
|
||||
KEY idx_pbl_subobj_ref_tid_mod (tenant_id, ref_module, ref_table, ref_biz_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象对复用域只读引用';
|
||||
|
||||
-- 12. pbl_subobject_review 子对象评审意见(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_subobject_review (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
review_code VARCHAR(32) NOT NULL COMMENT '评审业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
obj_code VARCHAR(32) DEFAULT NULL COMMENT '子对象编码(空=蓝图级)',
|
||||
reviewer_type VARCHAR(16) NOT NULL DEFAULT 'user' COMMENT '评审主体:user/agent_critic/agent_designer',
|
||||
reviewer_code VARCHAR(32) DEFAULT NULL COMMENT '评审主体编码',
|
||||
verdict VARCHAR(16) NOT NULL DEFAULT 'comment' COMMENT '结论:pass/comment/revise/reject',
|
||||
score DECIMAL(6,2) DEFAULT NULL COMMENT '评分',
|
||||
comment TEXT DEFAULT NULL COMMENT '意见正文',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '评审时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_subobj_review_code (review_code),
|
||||
KEY idx_pbl_subobj_review_tid_bp (tenant_id, bp_code, create_time),
|
||||
KEY idx_pbl_subobj_review_tid_obj (tenant_id, obj_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象评审意见(append-only)';
|
||||
|
||||
-- 13. pbl_blueprint_tag 蓝图标签
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint_tag (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
tag_code VARCHAR(32) NOT NULL COMMENT '标签业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
tag_key VARCHAR(64) NOT NULL COMMENT '标签键',
|
||||
tag_value VARCHAR(128) DEFAULT NULL COMMENT '标签值',
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_bp_tag_code (tag_code),
|
||||
UNIQUE KEY uk_pbl_bp_tag_kv (tenant_id, bp_code, tag_key),
|
||||
KEY idx_pbl_bp_tag_tid_key (tenant_id, tag_key, tag_value)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图标签';
|
||||
|
||||
-- 14. pbl_blueprint_publish 发布记录(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_blueprint_publish (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
publish_code VARCHAR(32) NOT NULL COMMENT '发布业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
version_no INT NOT NULL COMMENT '发布版本号',
|
||||
gd_code VARCHAR(32) DEFAULT NULL COMMENT '关联 Game Definition 编码',
|
||||
channel VARCHAR(32) NOT NULL DEFAULT 'class' COMMENT '发布渠道:class/school/public',
|
||||
target_code VARCHAR(32) DEFAULT NULL COMMENT '目标对象(班级编码)',
|
||||
publish_state VARCHAR(16) NOT NULL DEFAULT 'published' COMMENT '状态:published/revoked',
|
||||
published_by VARCHAR(32) DEFAULT NULL COMMENT '发布人',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '发布时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_bp_publish_code (publish_code),
|
||||
KEY idx_pbl_bp_publish_tid_bp (tenant_id, bp_code, create_time),
|
||||
KEY idx_pbl_bp_publish_tid_target (tenant_id, channel, target_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图发布记录(append-only)';
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_template(2 表,M1b)
|
||||
-- =====================================================================
|
||||
|
||||
-- 15. pbl_template 模板主表(含离线兜底模板)
|
||||
CREATE TABLE IF NOT EXISTS pbl_template (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
tpl_code VARCHAR(32) NOT NULL COMMENT '模板业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID(__system__ 表示平台内置)',
|
||||
tpl_name VARCHAR(128) NOT NULL COMMENT '模板名称',
|
||||
tpl_kind VARCHAR(32) NOT NULL DEFAULT 'blueprint' COMMENT '模板种类:blueprint/subobject/rubric',
|
||||
subject_code VARCHAR(32) DEFAULT NULL COMMENT '适用学科',
|
||||
grade_code VARCHAR(32) DEFAULT NULL COMMENT '适用学段',
|
||||
offline_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否离线兜底模板 0否1是',
|
||||
body LONGTEXT DEFAULT NULL COMMENT '模板正文 JSON(含子对象树)',
|
||||
id_prefix_rule VARCHAR(64) DEFAULT NULL COMMENT '实例化 ID 重映射前缀规则',
|
||||
version_no INT NOT NULL DEFAULT 1 COMMENT '模板版本',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/disabled',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_by VARCHAR(32) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_template_code (tpl_code),
|
||||
KEY idx_pbl_template_tid_kind (tenant_id, tpl_kind, status),
|
||||
KEY idx_pbl_template_tid_subj (tenant_id, subject_code, grade_code),
|
||||
KEY idx_pbl_template_tid_offline (tenant_id, offline_flag)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 模板主表';
|
||||
|
||||
-- 16. pbl_template_item 模板条目(实例化 ID 重映射映射表)
|
||||
CREATE TABLE IF NOT EXISTS pbl_template_item (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
item_code VARCHAR(32) NOT NULL COMMENT '条目业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
tpl_code VARCHAR(32) NOT NULL COMMENT '模板编码',
|
||||
tpl_obj_key VARCHAR(64) NOT NULL COMMENT '模板内占位键(如 __OBJ_1__)',
|
||||
obj_type VARCHAR(32) NOT NULL COMMENT '子对象类型',
|
||||
parent_key VARCHAR(64) DEFAULT NULL COMMENT '父占位键',
|
||||
payload LONGTEXT DEFAULT NULL COMMENT '条目载荷 JSON',
|
||||
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_template_item_code (item_code),
|
||||
UNIQUE KEY uk_pbl_template_item_key (tenant_id, tpl_code, tpl_obj_key),
|
||||
KEY idx_pbl_template_item_tid_tpl (tenant_id, tpl_code, sort_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 模板条目';
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_validation(3 表,M2:14 维 + 5 级质量状态)
|
||||
-- =====================================================================
|
||||
|
||||
-- 17. pbl_validation_ruleset 校验规则集
|
||||
CREATE TABLE IF NOT EXISTS pbl_validation_ruleset (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
ruleset_code VARCHAR(32) NOT NULL COMMENT '规则集业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
ruleset_name VARCHAR(128) NOT NULL COMMENT '规则集名称',
|
||||
dim_code VARCHAR(32) NOT NULL COMMENT '维度编码 D01~D14(appcodes_kv: pbl_valid_dim)',
|
||||
dim_name VARCHAR(64) NOT NULL COMMENT '维度名称',
|
||||
rule_expr TEXT DEFAULT NULL COMMENT '规则表达式 JSON(确定性可执行)',
|
||||
severity VARCHAR(16) NOT NULL DEFAULT 'error' COMMENT '严重度:blocker/error/warning/info',
|
||||
weight DECIMAL(6,3) NOT NULL DEFAULT 1.000 COMMENT '维度权重',
|
||||
level_effect VARCHAR(16) DEFAULT NULL COMMENT '对质量等级的影响:downgrade/gate/none',
|
||||
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用 0否1是',
|
||||
sort_no INT NOT NULL DEFAULT 0 COMMENT '维度排序',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_by VARCHAR(32) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_valid_ruleset_code (ruleset_code),
|
||||
KEY idx_pbl_valid_ruleset_tid_dim (tenant_id, dim_code, enabled),
|
||||
KEY idx_pbl_valid_ruleset_tid_sort (tenant_id, sort_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 14 维校验规则集';
|
||||
|
||||
-- 18. pbl_validation_run 校验执行批次
|
||||
CREATE TABLE IF NOT EXISTS pbl_validation_run (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
run_code VARCHAR(32) NOT NULL COMMENT '执行批次业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
version_no INT NOT NULL DEFAULT 1 COMMENT '被校验版本号',
|
||||
ruleset_ver VARCHAR(32) DEFAULT NULL COMMENT '规则集版本',
|
||||
trigger_type VARCHAR(16) NOT NULL DEFAULT 'manual' COMMENT '触发:manual/auto/agent/pre_compile',
|
||||
run_state VARCHAR(16) NOT NULL DEFAULT 'running' COMMENT '状态:running/passed/failed/error',
|
||||
dims_total INT NOT NULL DEFAULT 14 COMMENT '维度总数',
|
||||
dims_passed INT NOT NULL DEFAULT 0 COMMENT '通过维度数',
|
||||
blocker_count INT NOT NULL DEFAULT 0 COMMENT 'blocker 数',
|
||||
error_count INT NOT NULL DEFAULT 0 COMMENT 'error 数',
|
||||
warning_count INT NOT NULL DEFAULT 0 COMMENT 'warning 数',
|
||||
score DECIMAL(6,2) DEFAULT NULL COMMENT '加权得分',
|
||||
quality_level VARCHAR(16) DEFAULT NULL COMMENT '产出质量等级 L0~L4',
|
||||
started_at DATETIME DEFAULT NULL COMMENT '开始时间',
|
||||
finished_at DATETIME DEFAULT NULL COMMENT '结束时间',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_valid_run_code (run_code),
|
||||
KEY idx_pbl_valid_run_tid_bp (tenant_id, bp_code, create_time),
|
||||
KEY idx_pbl_valid_run_tid_state (tenant_id, run_state),
|
||||
KEY idx_pbl_valid_run_tid_level (tenant_id, quality_level)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 校验执行批次';
|
||||
|
||||
-- 19. pbl_validation_finding 校验发现明细(append-only 留痕)
|
||||
CREATE TABLE IF NOT EXISTS pbl_validation_finding (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
finding_code VARCHAR(32) NOT NULL COMMENT '发现业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
run_code VARCHAR(32) NOT NULL COMMENT '执行批次编码',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
dim_code VARCHAR(32) NOT NULL COMMENT '维度编码',
|
||||
obj_code VARCHAR(32) DEFAULT NULL COMMENT '命中子对象',
|
||||
severity VARCHAR(16) NOT NULL DEFAULT 'error' COMMENT '严重度',
|
||||
finding_msg VARCHAR(1024) DEFAULT NULL COMMENT '问题描述',
|
||||
suggestion VARCHAR(1024) DEFAULT NULL COMMENT '修复建议',
|
||||
evidence_json TEXT DEFAULT NULL COMMENT '证据 JSON',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '产生时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_valid_finding_code (finding_code),
|
||||
KEY idx_pbl_valid_finding_tid_run (tenant_id, run_code, dim_code),
|
||||
KEY idx_pbl_valid_finding_tid_bp (tenant_id, bp_code, create_time),
|
||||
KEY idx_pbl_valid_finding_tid_obj (tenant_id, obj_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 校验发现明细(append-only)';
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_compiler(4 表,M3a/M3b:确定性编译 + Game Definition)
|
||||
-- =====================================================================
|
||||
|
||||
-- 20. pbl_compile_job 编译作业
|
||||
CREATE TABLE IF NOT EXISTS pbl_compile_job (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
job_code VARCHAR(32) NOT NULL COMMENT '作业业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
version_no INT NOT NULL COMMENT '被编译版本号',
|
||||
run_code VARCHAR(32) DEFAULT NULL COMMENT '前置校验批次(必须 passed)',
|
||||
compiler_ver VARCHAR(32) NOT NULL DEFAULT 'v1' COMMENT '编译器版本',
|
||||
job_state VARCHAR(16) NOT NULL DEFAULT 'queued' COMMENT '状态:queued/running/success/failed/cancelled',
|
||||
input_checksum VARCHAR(64) DEFAULT NULL COMMENT '输入快照 sha256(确定性依据)',
|
||||
output_checksum VARCHAR(64) DEFAULT NULL COMMENT '输出 Game Definition sha256',
|
||||
gd_code VARCHAR(32) DEFAULT NULL COMMENT '产出 Game Definition 编码',
|
||||
error_msg VARCHAR(1024) DEFAULT NULL COMMENT '错误信息',
|
||||
started_at DATETIME DEFAULT NULL,
|
||||
finished_at DATETIME DEFAULT NULL,
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_compile_job_code (job_code),
|
||||
KEY idx_pbl_compile_job_tid_bp (tenant_id, bp_code, create_time),
|
||||
KEY idx_pbl_compile_job_tid_state (tenant_id, job_state),
|
||||
KEY idx_pbl_compile_job_tid_ick (tenant_id, input_checksum)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 编译作业';
|
||||
|
||||
-- 21. pbl_compile_artifact 编译中间产物
|
||||
CREATE TABLE IF NOT EXISTS pbl_compile_artifact (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
artifact_code VARCHAR(32) NOT NULL COMMENT '产物业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
job_code VARCHAR(32) NOT NULL COMMENT '编译作业编码',
|
||||
stage_code VARCHAR(32) NOT NULL COMMENT '编译阶段:normalize/resolve/link/optimize/emit',
|
||||
artifact_kind VARCHAR(32) NOT NULL COMMENT '产物种类:node_set/edge_set/rule_set/asset_map/gd_draft',
|
||||
body LONGTEXT DEFAULT NULL COMMENT '产物正文 JSON',
|
||||
checksum VARCHAR(64) DEFAULT NULL COMMENT 'sha256',
|
||||
sort_no INT NOT NULL DEFAULT 0 COMMENT '阶段排序',
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_compile_artifact_code (artifact_code),
|
||||
KEY idx_pbl_compile_artifact_tid_job (tenant_id, job_code, sort_no),
|
||||
KEY idx_pbl_compile_artifact_tid_kind (tenant_id, artifact_kind)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 编译中间产物';
|
||||
|
||||
-- 22. pbl_game_definition Game Definition(编译最终产出)
|
||||
CREATE TABLE IF NOT EXISTS pbl_game_definition (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
gd_code VARCHAR(32) NOT NULL COMMENT 'Game Definition 业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '来源蓝图',
|
||||
version_no INT NOT NULL COMMENT '来源蓝图版本',
|
||||
gd_version INT NOT NULL DEFAULT 1 COMMENT 'GD 自身版本',
|
||||
schema_ver VARCHAR(16) NOT NULL DEFAULT 'gd-v1' COMMENT 'GD schema 版本',
|
||||
body LONGTEXT DEFAULT NULL COMMENT 'Game Definition 全文 JSON(schema 校验通过)',
|
||||
checksum VARCHAR(64) DEFAULT NULL COMMENT 'sha256(同输入同输出)',
|
||||
world_ref VARCHAR(64) DEFAULT NULL COMMENT '引用世界编码(只读)',
|
||||
scene_ref VARCHAR(64) DEFAULT NULL COMMENT '引用场景编码(只读)',
|
||||
script_ref VARCHAR(64) DEFAULT NULL COMMENT '引用脚本编码(只读)',
|
||||
gd_state VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT '状态:draft/validated/published/archived',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_by VARCHAR(32) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_gd_code (gd_code),
|
||||
UNIQUE KEY uk_pbl_gd_bp_ver (tenant_id, bp_code, version_no, gd_version),
|
||||
KEY idx_pbl_gd_tid_state (tenant_id, gd_state),
|
||||
KEY idx_pbl_gd_tid_ck (tenant_id, checksum),
|
||||
KEY idx_pbl_gd_tid_world (tenant_id, world_ref, scene_ref)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Game Definition';
|
||||
|
||||
-- 23. pbl_compile_log 编译日志(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_compile_log (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
log_code VARCHAR(32) NOT NULL COMMENT '日志业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
job_code VARCHAR(32) NOT NULL COMMENT '编译作业编码',
|
||||
stage_code VARCHAR(32) DEFAULT NULL COMMENT '阶段',
|
||||
log_level VARCHAR(16) NOT NULL DEFAULT 'info' COMMENT '级别:debug/info/warn/error',
|
||||
log_msg VARCHAR(2048) DEFAULT NULL COMMENT '日志正文',
|
||||
context_json TEXT DEFAULT NULL COMMENT '上下文 JSON',
|
||||
seq_no BIGINT NOT NULL DEFAULT 0 COMMENT '作业内单调序号',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '记录时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_compile_log_code (log_code),
|
||||
KEY idx_pbl_compile_log_tid_job (tenant_id, job_code, seq_no),
|
||||
KEY idx_pbl_compile_log_tid_level (tenant_id, log_level, create_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 编译日志(append-only)';
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_agent_runtime(4 表,M4a/M4b:Designer/Critic + fail-closed 裁决)
|
||||
-- =====================================================================
|
||||
|
||||
-- 24. pbl_agent_session Agent 会话
|
||||
CREATE TABLE IF NOT EXISTS pbl_agent_session (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
session_code VARCHAR(32) NOT NULL COMMENT '会话业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) DEFAULT NULL COMMENT '关联蓝图',
|
||||
agent_role VARCHAR(32) NOT NULL COMMENT 'Agent 角色:designer/critic(appcodes_kv: pbl_agent_role)',
|
||||
model_name VARCHAR(64) DEFAULT NULL COMMENT '使用的平台模型注册名',
|
||||
session_state VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/paused/closed/error',
|
||||
owner_code VARCHAR(32) DEFAULT NULL COMMENT '发起用户',
|
||||
turn_count INT NOT NULL DEFAULT 0 COMMENT '轮次数',
|
||||
tool_call_count INT NOT NULL DEFAULT 0 COMMENT '工具调用总数',
|
||||
tool_deny_count INT NOT NULL DEFAULT 0 COMMENT '被拒绝调用数',
|
||||
context_json LONGTEXT DEFAULT NULL COMMENT '会话上下文 JSON',
|
||||
started_at DATETIME DEFAULT NULL,
|
||||
closed_at DATETIME DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_agent_session_code (session_code),
|
||||
KEY idx_pbl_agent_session_tid_bp (tenant_id, bp_code, session_state),
|
||||
KEY idx_pbl_agent_session_tid_role (tenant_id, agent_role),
|
||||
KEY idx_pbl_agent_session_tid_owner (tenant_id, owner_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Agent 会话';
|
||||
|
||||
-- 25. pbl_agent_message Agent 消息(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_agent_message (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
msg_code VARCHAR(32) NOT NULL COMMENT '消息业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
session_code VARCHAR(32) NOT NULL COMMENT '会话编码',
|
||||
turn_no INT NOT NULL DEFAULT 0 COMMENT '轮次号',
|
||||
role VARCHAR(16) NOT NULL COMMENT '角色:system/user/assistant/tool',
|
||||
content LONGTEXT DEFAULT NULL COMMENT '消息正文',
|
||||
token_in INT NOT NULL DEFAULT 0 COMMENT '输入 token',
|
||||
token_out INT NOT NULL DEFAULT 0 COMMENT '输出 token',
|
||||
latency_ms INT NOT NULL DEFAULT 0 COMMENT '耗时毫秒',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '产生时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_agent_msg_code (msg_code),
|
||||
KEY idx_pbl_agent_msg_tid_sess (tenant_id, session_code, turn_no),
|
||||
KEY idx_pbl_agent_msg_tid_time (tenant_id, create_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Agent 消息(append-only)';
|
||||
|
||||
-- 26. pbl_agent_tool_call 工具调用记录(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_agent_tool_call (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
call_code VARCHAR(32) NOT NULL COMMENT '调用业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
session_code VARCHAR(32) NOT NULL COMMENT '会话编码',
|
||||
turn_no INT NOT NULL DEFAULT 0 COMMENT '轮次号',
|
||||
tool_name VARCHAR(64) NOT NULL COMMENT '工具名(13 启用 / 9 禁用白名单外)',
|
||||
tool_state VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT '状态:pending/allowed/executed/denied/error',
|
||||
params_json LONGTEXT DEFAULT NULL COMMENT '入参 JSON',
|
||||
result_json LONGTEXT DEFAULT NULL COMMENT '返回 JSON',
|
||||
latency_ms INT NOT NULL DEFAULT 0 COMMENT '耗时毫秒',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '调用时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_agent_call_code (call_code),
|
||||
KEY idx_pbl_agent_call_tid_sess (tenant_id, session_code, turn_no),
|
||||
KEY idx_pbl_agent_call_tid_tool (tenant_id, tool_name, tool_state),
|
||||
KEY idx_pbl_agent_call_tid_time (tenant_id, create_time)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Agent 工具调用(append-only)';
|
||||
|
||||
-- 27. pbl_agent_arbitration fail-closed 裁决记录(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_agent_arbitration (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
arb_code VARCHAR(32) NOT NULL COMMENT '裁决业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
session_code VARCHAR(32) DEFAULT NULL COMMENT '会话编码',
|
||||
call_code VARCHAR(32) DEFAULT NULL COMMENT '关联调用编码',
|
||||
tool_name VARCHAR(64) NOT NULL COMMENT '被裁决工具名',
|
||||
decision VARCHAR(16) NOT NULL DEFAULT 'deny' COMMENT '裁决:allow/deny(默认 deny,fail-closed)',
|
||||
deny_reason VARCHAR(32) NOT NULL DEFAULT 'not_in_whitelist' COMMENT '拒绝原因:not_in_whitelist/invalid_params/missing_tenant_context/write_protected/quota_exceeded',
|
||||
rule_ref VARCHAR(64) DEFAULT NULL COMMENT '命中规则引用',
|
||||
detail_json TEXT DEFAULT NULL COMMENT '裁决详情 JSON',
|
||||
arbiter VARCHAR(32) NOT NULL DEFAULT 'system' COMMENT '裁决者',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '裁决时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_agent_arb_code (arb_code),
|
||||
KEY idx_pbl_agent_arb_tid_tool (tenant_id, tool_name, decision),
|
||||
KEY idx_pbl_agent_arb_tid_sess (tenant_id, session_code, create_time),
|
||||
KEY idx_pbl_agent_arb_tid_reason (tenant_id, deny_reason)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Agent fail-closed 裁决记录(append-only)';
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_evidence(4 表,M5a/M5b:产出物采集 + 证据幂等)
|
||||
-- =====================================================================
|
||||
|
||||
-- 28. pbl_artifact 学生产出物
|
||||
CREATE TABLE IF NOT EXISTS pbl_artifact (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
artifact_code VARCHAR(32) NOT NULL COMMENT '产出物业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
session_code VARCHAR(32) DEFAULT NULL COMMENT '运行会话编码',
|
||||
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
|
||||
obj_code VARCHAR(32) DEFAULT NULL COMMENT '对应产出物规格子对象',
|
||||
artifact_name VARCHAR(128) NOT NULL COMMENT '产出物名称',
|
||||
artifact_kind VARCHAR(32) NOT NULL COMMENT '种类:doc/image/model/audio/video/code/log/chat(appcodes_kv: pbl_artifact_kind)',
|
||||
storage_uri VARCHAR(512) DEFAULT NULL COMMENT '存储 URI',
|
||||
mime_type VARCHAR(64) DEFAULT NULL COMMENT 'MIME',
|
||||
size_bytes BIGINT NOT NULL DEFAULT 0 COMMENT '字节数',
|
||||
checksum VARCHAR(64) DEFAULT NULL COMMENT 'sha256',
|
||||
content_text LONGTEXT DEFAULT NULL COMMENT '文本类正文(可索引)',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/archived/deleted',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_artifact_code (artifact_code),
|
||||
KEY idx_pbl_artifact_tid_bp (tenant_id, bp_code, artifact_kind),
|
||||
KEY idx_pbl_artifact_tid_team (tenant_id, team_code),
|
||||
KEY idx_pbl_artifact_tid_sess (tenant_id, session_code),
|
||||
KEY idx_pbl_artifact_tid_ck (tenant_id, checksum)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 学生产出物';
|
||||
|
||||
-- 29. pbl_evidence 证据主表
|
||||
CREATE TABLE IF NOT EXISTS pbl_evidence (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
evidence_code VARCHAR(32) NOT NULL COMMENT '证据业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
artifact_code VARCHAR(32) DEFAULT NULL COMMENT '关联产出物',
|
||||
obj_code VARCHAR(32) DEFAULT NULL COMMENT '关联子对象(学习目标/任务)',
|
||||
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
|
||||
student_code VARCHAR(32) DEFAULT NULL COMMENT '学生编码',
|
||||
evidence_type VARCHAR(32) NOT NULL COMMENT '证据类型:artifact/event/dialogue/state_snapshot/metric(appcodes_kv: pbl_evidence_type)',
|
||||
idem_key VARCHAR(128) NOT NULL COMMENT '幂等键(tenant+bp+type+source+hash)',
|
||||
payload LONGTEXT DEFAULT NULL COMMENT '证据载荷 JSON',
|
||||
occurred_at DATETIME DEFAULT NULL COMMENT '证据发生时间',
|
||||
trust_level VARCHAR(16) NOT NULL DEFAULT 'normal' COMMENT '可信度:high/normal/low',
|
||||
anonymized TINYINT NOT NULL DEFAULT 0 COMMENT '是否已匿名化 0否1是',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/invalidated',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_evidence_code (evidence_code),
|
||||
UNIQUE KEY uk_pbl_evidence_idem (tenant_id, idem_key),
|
||||
KEY idx_pbl_evidence_tid_bp (tenant_id, bp_code, evidence_type),
|
||||
KEY idx_pbl_evidence_tid_team (tenant_id, team_code, student_code),
|
||||
KEY idx_pbl_evidence_tid_obj (tenant_id, obj_code),
|
||||
KEY idx_pbl_evidence_tid_time (tenant_id, occurred_at)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 证据主表(幂等键唯一)';
|
||||
|
||||
-- 30. pbl_evidence_idem 证据幂等提交台账(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_evidence_idem (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
idem_code VARCHAR(32) NOT NULL COMMENT '幂等台账业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
idem_key VARCHAR(128) NOT NULL COMMENT '幂等键',
|
||||
evidence_code VARCHAR(32) DEFAULT NULL COMMENT '首次落库证据编码',
|
||||
submit_count INT NOT NULL DEFAULT 1 COMMENT '累计提交次数(重复提交只增此计数,不新增证据行)',
|
||||
last_payload_hash VARCHAR(64) DEFAULT NULL COMMENT '最近一次载荷 hash',
|
||||
conflict_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否载荷冲突 0否1是',
|
||||
source_channel VARCHAR(32) DEFAULT NULL COMMENT '来源渠道:runtime/manual/agent/import',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '首次提交时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_evidence_idem_code (idem_code),
|
||||
UNIQUE KEY uk_pbl_evidence_idem_key (tenant_id, idem_key),
|
||||
KEY idx_pbl_evidence_idem_tid_time (tenant_id, create_time),
|
||||
KEY idx_pbl_evidence_idem_tid_conf (tenant_id, conflict_flag)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 证据幂等台账(append-only)';
|
||||
|
||||
-- 31. pbl_evidence_binding 证据与复用域对象绑定(零改表关联)
|
||||
CREATE TABLE IF NOT EXISTS pbl_evidence_binding (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
bind_code VARCHAR(32) NOT NULL COMMENT '绑定业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
evidence_code VARCHAR(32) NOT NULL COMMENT '证据编码',
|
||||
ref_module VARCHAR(32) NOT NULL COMMENT '复用域模块:world/scene/entity/script_engine/scense_runtime/scense/scense_game',
|
||||
ref_table VARCHAR(64) NOT NULL COMMENT '复用域表名',
|
||||
ref_id BIGINT DEFAULT NULL COMMENT '复用域行 id',
|
||||
ref_biz_code VARCHAR(64) DEFAULT NULL COMMENT '复用域业务编码',
|
||||
bind_role VARCHAR(32) NOT NULL DEFAULT 'source' COMMENT '绑定角色:source/target/context',
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_evidence_binding_code (bind_code),
|
||||
KEY idx_pbl_evidence_binding_tid_ev (tenant_id, evidence_code),
|
||||
KEY idx_pbl_evidence_binding_tid_ref (tenant_id, ref_module, ref_table, ref_biz_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 证据与复用域绑定(零改表)';
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_assessment(3 表,M6:Rubric 加权评估与报告)
|
||||
-- =====================================================================
|
||||
|
||||
-- 32. pbl_rubric 量规主表
|
||||
CREATE TABLE IF NOT EXISTS pbl_rubric (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
rubric_code VARCHAR(32) NOT NULL COMMENT '量规业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) DEFAULT NULL COMMENT '关联蓝图(空=通用量规)',
|
||||
rubric_name VARCHAR(128) NOT NULL COMMENT '量规名称',
|
||||
level_count INT NOT NULL DEFAULT 5 COMMENT '等级数(默认 5 级)',
|
||||
total_weight DECIMAL(8,3) NOT NULL DEFAULT 100.000 COMMENT '总权重',
|
||||
pass_score DECIMAL(6,2) NOT NULL DEFAULT 60.00 COMMENT '及格分',
|
||||
grade_rule TEXT DEFAULT NULL COMMENT '等级映射规则 JSON',
|
||||
is_default TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认量规 0否1是',
|
||||
version_no INT NOT NULL DEFAULT 1 COMMENT '版本',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/disabled',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_by VARCHAR(32) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_rubric_code (rubric_code),
|
||||
KEY idx_pbl_rubric_tid_bp (tenant_id, bp_code, status),
|
||||
KEY idx_pbl_rubric_tid_default (tenant_id, is_default)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 量规主表';
|
||||
|
||||
-- 33. pbl_rubric_criterion 量规评价维度条目
|
||||
CREATE TABLE IF NOT EXISTS pbl_rubric_criterion (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
crit_code VARCHAR(32) NOT NULL COMMENT '条目业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
rubric_code VARCHAR(32) NOT NULL COMMENT '量规编码',
|
||||
obj_code VARCHAR(32) DEFAULT NULL COMMENT '关联学习目标子对象',
|
||||
crit_name VARCHAR(128) NOT NULL COMMENT '维度名称',
|
||||
crit_desc VARCHAR(1024) DEFAULT NULL COMMENT '维度说明',
|
||||
weight DECIMAL(6,3) NOT NULL DEFAULT 1.000 COMMENT '权重',
|
||||
level_desc TEXT DEFAULT NULL COMMENT '各等级描述 JSON(level -> desc)',
|
||||
max_score DECIMAL(6,2) NOT NULL DEFAULT 5.00 COMMENT '最高分',
|
||||
evidence_required TINYINT NOT NULL DEFAULT 1 COMMENT '是否必须有证据支撑 0否1是',
|
||||
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_rubric_crit_code (crit_code),
|
||||
KEY idx_pbl_rubric_crit_tid_rub (tenant_id, rubric_code, sort_no),
|
||||
KEY idx_pbl_rubric_crit_tid_obj (tenant_id, obj_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 量规评价维度';
|
||||
|
||||
-- 34. pbl_assessment_report 评估报告
|
||||
CREATE TABLE IF NOT EXISTS pbl_assessment_report (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
report_code VARCHAR(32) NOT NULL COMMENT '报告业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
|
||||
rubric_code VARCHAR(32) NOT NULL COMMENT '量规编码',
|
||||
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
|
||||
student_code VARCHAR(32) DEFAULT NULL COMMENT '学生编码(团队报告时为空)',
|
||||
scope_type VARCHAR(16) NOT NULL DEFAULT 'team' COMMENT '范围:team/student/blueprint',
|
||||
score_total DECIMAL(6,2) NOT NULL DEFAULT 0.00 COMMENT '加权总分(可复算)',
|
||||
grade_code VARCHAR(16) DEFAULT NULL COMMENT '等级 A/B/C/D/E',
|
||||
detail_json LONGTEXT DEFAULT NULL COMMENT '逐维度得分明细 JSON(含证据引用)',
|
||||
evidence_count INT NOT NULL DEFAULT 0 COMMENT '引用证据数',
|
||||
missing_evidence_count INT NOT NULL DEFAULT 0 COMMENT '缺证据维度数',
|
||||
assessor_type VARCHAR(16) NOT NULL DEFAULT 'agent' COMMENT '评估者:agent/user/mixed',
|
||||
assessor_code VARCHAR(32) DEFAULT NULL COMMENT '评估者编码',
|
||||
report_state VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT '状态:draft/published/archived',
|
||||
calc_checksum VARCHAR(64) DEFAULT NULL COMMENT '复算校验 sha256',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_by VARCHAR(32) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_assess_report_code (report_code),
|
||||
KEY idx_pbl_assess_report_tid_bp (tenant_id, bp_code, scope_type),
|
||||
KEY idx_pbl_assess_report_tid_team (tenant_id, team_code, student_code),
|
||||
KEY idx_pbl_assess_report_tid_state (tenant_id, report_state),
|
||||
KEY idx_pbl_assess_report_tid_grade (tenant_id, grade_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 评估报告';
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_domain_ext(1 表,M8:world/scene/entity 租户·班级·团队关联,不改基表)
|
||||
-- =====================================================================
|
||||
|
||||
-- 35. pbl_domain_binding 复用域对象绑定(零改表唯一关联落点)
|
||||
CREATE TABLE IF NOT EXISTS pbl_domain_binding (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
bind_code VARCHAR(32) NOT NULL COMMENT '绑定业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
bind_kind VARCHAR(32) NOT NULL COMMENT '绑定种类:tenant_world/class_scene/team_entity/bp_script/session_world(appcodes_kv: pbl_bind_kind)',
|
||||
class_code VARCHAR(32) DEFAULT NULL COMMENT '班级编码',
|
||||
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
|
||||
bp_code VARCHAR(32) DEFAULT NULL COMMENT '蓝图编码',
|
||||
session_code VARCHAR(32) DEFAULT NULL COMMENT '运行会话编码',
|
||||
ref_module VARCHAR(32) NOT NULL COMMENT '复用域模块:world/scene/entity/script_engine/scense_runtime/scense/scense_game',
|
||||
ref_table VARCHAR(64) NOT NULL COMMENT '复用域表名',
|
||||
ref_id BIGINT DEFAULT NULL COMMENT '复用域行 id',
|
||||
ref_biz_code VARCHAR(64) DEFAULT NULL COMMENT '复用域业务编码',
|
||||
access_mode VARCHAR(16) NOT NULL DEFAULT 'readonly' COMMENT '访问模式:readonly(Phase 0/1 唯一合法值,写保护)',
|
||||
bind_state VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态:active/released',
|
||||
extra_json TEXT DEFAULT NULL COMMENT '扩展 JSON',
|
||||
create_by VARCHAR(32) DEFAULT NULL,
|
||||
create_time DATETIME DEFAULT NULL,
|
||||
update_by VARCHAR(32) DEFAULT NULL,
|
||||
update_time DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_domain_binding_code (bind_code),
|
||||
UNIQUE KEY uk_pbl_domain_binding_ref (tenant_id, bind_kind, ref_module, ref_table, ref_biz_code),
|
||||
KEY idx_pbl_domain_binding_tid_class (tenant_id, class_code, team_code),
|
||||
KEY idx_pbl_domain_binding_tid_bp (tenant_id, bp_code),
|
||||
KEY idx_pbl_domain_binding_tid_sess (tenant_id, session_code),
|
||||
KEY idx_pbl_domain_binding_tid_ref (tenant_id, ref_module, ref_id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 复用域绑定(零改表)';
|
||||
|
||||
-- =====================================================================
|
||||
-- 模块 pbl_analytics(1 表,M10:分析看板快照,append-only)
|
||||
-- =====================================================================
|
||||
|
||||
-- 36. pbl_analytics_snapshot 分析快照(append-only)
|
||||
CREATE TABLE IF NOT EXISTS pbl_analytics_snapshot (
|
||||
id BIGINT NOT NULL AUTO_INCREMENT,
|
||||
snap_code VARCHAR(32) NOT NULL COMMENT '快照业务主键',
|
||||
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
|
||||
metric_group VARCHAR(32) NOT NULL COMMENT '指标组:blueprint/validation/compile/runtime/evidence/assessment(appcodes_kv: pbl_metric_group)',
|
||||
scope_type VARCHAR(16) NOT NULL DEFAULT 'tenant' COMMENT '范围:tenant/class/team/blueprint',
|
||||
scope_code VARCHAR(32) DEFAULT NULL COMMENT '范围对象编码',
|
||||
period_key VARCHAR(16) NOT NULL COMMENT '周期键:2026-09 / 2026-W38 / 2026-09-15',
|
||||
metrics_json LONGTEXT DEFAULT NULL COMMENT '指标 JSON(计数/均值/分布)',
|
||||
anonymized TINYINT NOT NULL DEFAULT 1 COMMENT '是否匿名聚合 0否1是(KDB 侧强制 1)',
|
||||
sample_size INT NOT NULL DEFAULT 0 COMMENT '样本量',
|
||||
computed_at DATETIME DEFAULT NULL COMMENT '计算时间',
|
||||
create_time DATETIME DEFAULT NULL COMMENT '入库时间(append-only,无 update_time)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_pbl_analytics_snap_code (snap_code),
|
||||
UNIQUE KEY uk_pbl_analytics_snap_dim (tenant_id, metric_group, scope_type, scope_code, period_key),
|
||||
KEY idx_pbl_analytics_snap_tid_group (tenant_id, metric_group, period_key),
|
||||
KEY idx_pbl_analytics_snap_tid_scope (tenant_id, scope_type, scope_code)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 分析看板快照(append-only)';
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
||||
-- =====================================================================
|
||||
-- 契约自检(供 build.sh / QC grep 核验)
|
||||
-- 表总数:36(pbl_governance 3 + pbl_blueprint 11 + pbl_template 2 + pbl_validation 3
|
||||
-- + pbl_compiler 4 + pbl_agent_runtime 4 + pbl_evidence 4 + pbl_assessment 3
|
||||
-- + pbl_domain_ext 1 + pbl_analytics 1 = 36)
|
||||
-- append-only 表(11,无 update_time):
|
||||
-- pbl_audit_log / pbl_blueprint_version / pbl_subobject_review / pbl_blueprint_publish
|
||||
-- pbl_validation_finding / pbl_compile_log / pbl_agent_message / pbl_agent_tool_call
|
||||
-- pbl_agent_arbitration / pbl_evidence_idem / pbl_analytics_snapshot
|
||||
-- 零命中项(mariadb 方言硬约束):
|
||||
-- FOREIGN KEY / REFERENCES / ENUM( / SERIAL / BIGSERIAL / nextval / TIMESTAMP
|
||||
-- 全部索引以 tenant_id 打头;每表 id BIGINT NOT NULL AUTO_INCREMENT + xxx_code 唯一业务主键。
|
||||
-- =====================================================================
|
||||
@ -1,120 +1,225 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""DDL 幂等修正器:把 tenant_id 提升为每张表的物理首列(QC 第三轮 #1 配套)。
|
||||
"""DDL 补丁工具:保证每张表 tenant_id 为第一个业务列(多租户强制打头)。
|
||||
|
||||
背景
|
||||
----
|
||||
data-model.md 的「tenant_id 强制打头」有两层含义:
|
||||
(a) 键前缀契约 —— 每个复合 UNIQUE KEY / KEY 的首列必须是 tenant_id(影响分区裁剪与查询计划,**必须成立**);
|
||||
(b) 物理列序 —— CREATE TABLE 的第一个列定义是 tenant_id(可读性/评审口径)。
|
||||
核验器 gate_64 以 (a) 为判定项、(b) 为 INFO。本脚本把 (b) 也补齐,使两种口径同时成立,
|
||||
且**幂等**:已经是首列的表不做任何改动,重复执行结果一致。
|
||||
docs/01-design/data-model.md 硬约束:36 表全部 mariadb 方言、无 FK/ENUM/TIMESTAMP,
|
||||
且 **tenant_id 强制打头**(紧随自增主键 id 之后,作为第一个业务列),以便
|
||||
pbl_common 的租户上下文在 CRUD 工厂层统一注入 WHERE tenant_id = ?。
|
||||
|
||||
历史 DDL(含引用模块导出的 subobjects.sql 片段)存在 tenant_id 位置漂移
|
||||
(写在表尾或夹在中间),本脚本做**幂等**重排:
|
||||
* 已在首位 → 不动(幂等)
|
||||
* 不在首位 → 抽出该行,移动到第一个业务列位置
|
||||
* 完全缺失 → 按标准定义补插(BIGINT NOT NULL DEFAULT 0 + 注释)
|
||||
|
||||
用法
|
||||
----
|
||||
python3 apps/pbls/scripts/patch_ddl_tenant_first.py \
|
||||
--file apps/pbls/scripts/ddl/pbls_tables.sql [--dry-run]
|
||||
# 干跑(只报告,不写盘)
|
||||
python3 apps/pbls/scripts/patch_ddl_tenant_first.py --dry-run
|
||||
|
||||
安全约束
|
||||
--------
|
||||
* 只做「列定义整行搬移」,不改列类型、不改索引、不改表选项、不改注释;
|
||||
* 解析失败(找不到 tenant_id 列 / 括号不配对)时跳过该表并打印 SKIP,绝不写坏文件;
|
||||
* --dry-run 只报告将变更的表与行号,不落盘。
|
||||
# 就地修补(自动备份 .bak)
|
||||
python3 apps/pbls/scripts/patch_ddl_tenant_first.py --inplace
|
||||
|
||||
# 指定文件
|
||||
python3 apps/pbls/scripts/patch_ddl_tenant_first.py \
|
||||
--ddl apps/pbls/scripts/ddl/pbls_tables.sql --inplace
|
||||
|
||||
# 只校验不修补(CI 门禁用,发现漂移退出码 1)
|
||||
python3 apps/pbls/scripts/patch_ddl_tenant_first.py --check
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import io
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
CREATE_RX = re.compile(r"CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`\"]?(\w+)[`\"]?\s*\(", re.I)
|
||||
TENANT_COL_RX = re.compile(r"^\s*[`\"]?tenant_id[`\"]?\s+", re.I)
|
||||
DEFAULT_DDL = os.path.join(
|
||||
os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
|
||||
"scripts", "ddl", "pbls_tables.sql",
|
||||
)
|
||||
|
||||
TENANT_COL = "tenant_id"
|
||||
TENANT_DEF = " `%s` BIGINT NOT NULL DEFAULT 0 COMMENT '租户ID(多租户强制打头)'," % TENANT_COL
|
||||
|
||||
RE_CREATE = re.compile(
|
||||
r"^\s*CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?[`\"]?(\w+)[`\"]?", re.I
|
||||
)
|
||||
RE_COL = re.compile(r"^\s*[`\"]?(\w+)[`\"]?\s+[A-Za-z]")
|
||||
RE_CONSTRAINT = re.compile(
|
||||
r"^\s*(PRIMARY\s+KEY|UNIQUE\s+KEY|UNIQUE\s+INDEX|KEY|INDEX|CONSTRAINT|FOREIGN\s+KEY|CHECK)\b",
|
||||
re.I,
|
||||
)
|
||||
RE_FORBIDDEN = re.compile(
|
||||
r"\b(BIGSERIAL|SERIAL|nextval|FOREIGN\s+KEY|REFERENCES|ENUM\s*\(|TIMESTAMP)\b", re.I
|
||||
)
|
||||
|
||||
|
||||
def match_paren(text, open_idx):
|
||||
depth = 0
|
||||
for i in range(open_idx, len(text)):
|
||||
if text[i] == "(":
|
||||
depth += 1
|
||||
elif text[i] == ")":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
class TableBlock(object):
|
||||
"""一张表的 DDL 行块(含起止行号,0-based)。"""
|
||||
|
||||
def __init__(self, name, start):
|
||||
self.name = name
|
||||
self.start = start # CREATE TABLE 行
|
||||
self.end = None # 收尾 `)` 行(含)
|
||||
self.body = [] # (lineno, text) 列/约束行
|
||||
|
||||
def first_business_index(self):
|
||||
"""返回 body 中第一个业务列(非约束行)的下标,无则 None。"""
|
||||
for i, (_ln, text) in enumerate(self.body):
|
||||
if RE_CONSTRAINT.match(text):
|
||||
continue
|
||||
if RE_COL.match(text):
|
||||
return i
|
||||
return -1
|
||||
return None
|
||||
|
||||
def tenant_index(self):
|
||||
for i, (_ln, text) in enumerate(self.body):
|
||||
m = RE_COL.match(text)
|
||||
if m and m.group(1) == TENANT_COL:
|
||||
return i
|
||||
return None
|
||||
|
||||
|
||||
def line_of(text, offset):
|
||||
return text[:offset].count("\n") + 1
|
||||
|
||||
|
||||
def patch(sql):
|
||||
"""返回 (new_sql, changes, skips)。changes/skips 元素为 (表名, 行号, 说明)。"""
|
||||
changes, skips = [], []
|
||||
out = sql
|
||||
offset_shift = 0
|
||||
for m in CREATE_RX.finditer(sql):
|
||||
tbl = m.group(1)
|
||||
open_idx = m.end() - 1
|
||||
close_idx = match_paren(sql, open_idx)
|
||||
if close_idx < 0:
|
||||
skips.append((tbl, line_of(sql, m.start()), "括号不配对,跳过"))
|
||||
def parse_blocks(lines):
|
||||
"""把 DDL 文本切成 TableBlock 列表。"""
|
||||
blocks = []
|
||||
cur = None
|
||||
for i, text in enumerate(lines):
|
||||
m = RE_CREATE.match(text)
|
||||
if m:
|
||||
cur = TableBlock(m.group(1), i)
|
||||
blocks.append(cur)
|
||||
continue
|
||||
body = sql[open_idx + 1:close_idx]
|
||||
lines = body.split("\n")
|
||||
tenant_i = None
|
||||
for i, ln in enumerate(lines):
|
||||
if TENANT_COL_RX.match(ln):
|
||||
tenant_i = i
|
||||
break
|
||||
if tenant_i is None:
|
||||
skips.append((tbl, line_of(sql, m.start()), "未找到 tenant_id 列定义,跳过"))
|
||||
if cur is None:
|
||||
continue
|
||||
first_meaningful = None
|
||||
for i, ln in enumerate(lines):
|
||||
if ln.strip():
|
||||
first_meaningful = i
|
||||
break
|
||||
if first_meaningful is None or tenant_i == first_meaningful:
|
||||
continue # 已是首列,幂等无操作
|
||||
moved = lines.pop(tenant_i)
|
||||
lines.insert(first_meaningful, moved)
|
||||
new_body = "\n".join(lines)
|
||||
start = open_idx + 1 + offset_shift
|
||||
end = close_idx + offset_shift
|
||||
out = out[:start] + new_body + out[end:]
|
||||
offset_shift += len(new_body) - len(body)
|
||||
changes.append((tbl, line_of(sql, m.start()),
|
||||
"tenant_id 由第 %d 个列定义提升为物理首列" % (tenant_i - first_meaningful + 1)))
|
||||
return out, changes, skips
|
||||
stripped = text.strip()
|
||||
if stripped.startswith(")"):
|
||||
cur.end = i
|
||||
cur = None
|
||||
continue
|
||||
if not stripped or stripped.startswith("--") or stripped.startswith("#"):
|
||||
continue
|
||||
cur.body.append((i, text))
|
||||
return blocks
|
||||
|
||||
|
||||
def audit(lines, blocks):
|
||||
"""返回 (漂移表清单, 缺失表清单, 禁用方言命中清单)。"""
|
||||
drifted, missing, forbidden = [], [], []
|
||||
for b in blocks:
|
||||
ti = b.tenant_index()
|
||||
fi = b.first_business_index()
|
||||
if ti is None:
|
||||
missing.append(b.name)
|
||||
elif fi is not None and ti != fi:
|
||||
drifted.append((b.name, ti, fi))
|
||||
for i, text in enumerate(lines, 1):
|
||||
m = RE_FORBIDDEN.search(text)
|
||||
if m and not text.strip().startswith("--"):
|
||||
forbidden.append((i, m.group(1), text.strip()[:90]))
|
||||
return drifted, missing, forbidden
|
||||
|
||||
|
||||
def patch(lines, blocks):
|
||||
"""就地重排/补插 tenant_id,返回 (新行列表, 改动计数)。"""
|
||||
out = list(lines)
|
||||
changes = 0
|
||||
# 从后往前处理,避免行号位移
|
||||
for b in sorted(blocks, key=lambda x: x.start, reverse=True):
|
||||
ti = b.tenant_index()
|
||||
fi = b.first_business_index()
|
||||
if ti is None:
|
||||
anchor = b.body[fi][0] if fi is not None else (b.start + 1)
|
||||
out.insert(anchor, TENANT_DEF)
|
||||
changes += 1
|
||||
continue
|
||||
if fi is None or ti == fi:
|
||||
continue # 幂等:已在首位
|
||||
src_line = b.body[ti][0]
|
||||
dst_line = b.body[fi][0]
|
||||
moved = out.pop(src_line)
|
||||
if not moved.rstrip().endswith(","):
|
||||
moved = moved.rstrip() + ","
|
||||
out.insert(dst_line, moved)
|
||||
changes += 1
|
||||
return out, changes
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description="DDL tenant_id 物理首列幂等修正器")
|
||||
ap.add_argument("--file", required=True, help="DDL 文件路径")
|
||||
ap.add_argument("--dry-run", action="store_true", help="只报告不落盘")
|
||||
ap = argparse.ArgumentParser(description="DDL tenant_id 打头幂等补丁")
|
||||
ap.add_argument("--ddl", default=DEFAULT_DDL, help="DDL 文件路径")
|
||||
ap.add_argument("--inplace", action="store_true", help="就地写回(自动 .bak 备份)")
|
||||
ap.add_argument("--dry-run", action="store_true", help="只报告不写盘")
|
||||
ap.add_argument("--check", action="store_true",
|
||||
help="CI 门禁模式:发现漂移/缺失/禁用方言则退出码 1")
|
||||
args = ap.parse_args()
|
||||
|
||||
if not os.path.isfile(args.file):
|
||||
sys.stderr.write("[patch_ddl] 文件不存在:%s\n" % args.file)
|
||||
if not os.path.isfile(args.ddl):
|
||||
print("FAIL: DDL 文件不存在:%s" % args.ddl)
|
||||
return 2
|
||||
with io.open(args.file, "r", encoding="utf-8") as fh:
|
||||
sql = fh.read()
|
||||
|
||||
new_sql, changes, skips = patch(sql)
|
||||
for tbl, ln, msg in changes:
|
||||
print("[PATCH] %-34s CREATE @L%-5d %s" % (tbl, ln, msg))
|
||||
for tbl, ln, msg in skips:
|
||||
print("[SKIP ] %-34s CREATE @L%-5d %s" % (tbl, ln, msg))
|
||||
print("[SUMMARY] 变更 %d 张表,跳过 %d 张表,幂等=%s"
|
||||
% (len(changes), len(skips), "是(重复执行不再变更)" if not changes else "本次有变更"))
|
||||
with open(args.ddl, "r", encoding="utf-8") as fp:
|
||||
text = fp.read()
|
||||
lines = text.splitlines()
|
||||
blocks = parse_blocks(lines)
|
||||
|
||||
if changes and not args.dry_run:
|
||||
with io.open(args.file, "w", encoding="utf-8") as fh:
|
||||
fh.write(new_sql)
|
||||
print("[WRITE] 已落盘:%s(%d 字节)" % (args.file, os.path.getsize(args.file)))
|
||||
elif args.dry_run:
|
||||
print("[DRY-RUN] 未落盘")
|
||||
drifted, missing, forbidden = audit(lines, blocks)
|
||||
n_autoinc = len([1 for ln in lines if re.search(r"AUTO_INCREMENT", ln, re.I)])
|
||||
n_bigint = len([1 for ln in lines if re.search(r"\bBIGINT\b", ln, re.I)])
|
||||
|
||||
print("=" * 74)
|
||||
print("patch_ddl_tenant_first :: %s" % args.ddl)
|
||||
print("=" * 74)
|
||||
print("CREATE TABLE = %d" % len(blocks))
|
||||
print("AUTO_INCREMENT = %d" % n_autoinc)
|
||||
print("BIGINT = %d" % n_bigint)
|
||||
print("tenant_id 打头 = %d/%d" % (len(blocks) - len(drifted) - len(missing), len(blocks)))
|
||||
if drifted:
|
||||
print("\n[DRIFT] tenant_id 位置漂移 %d 表:" % len(drifted))
|
||||
for name, ti, fi in drifted:
|
||||
print(" - %-28s 当前 body[%d] 应在 body[%d]" % (name, ti, fi))
|
||||
if missing:
|
||||
print("\n[MISS] 缺 tenant_id 列 %d 表:%s" % (len(missing), ", ".join(missing)))
|
||||
if forbidden:
|
||||
print("\n[FORBIDDEN] 禁用方言命中 %d 处:" % len(forbidden))
|
||||
for ln, kw, snippet in forbidden[:20]:
|
||||
print(" - L%d %s :: %s" % (ln, kw, snippet))
|
||||
else:
|
||||
print("\n[FORBIDDEN] 7 类禁用方言零命中(BIGSERIAL/SERIAL/nextval/"
|
||||
"FOREIGN KEY/REFERENCES/ENUM(/TIMESTAMP)")
|
||||
|
||||
if args.check:
|
||||
bad = len(drifted) + len(missing) + len(forbidden)
|
||||
print("\nCHECK RESULT: %s" % ("PASS" if bad == 0 else "FAIL(%d)" % bad))
|
||||
return 0 if bad == 0 else 1
|
||||
|
||||
if not drifted and not missing:
|
||||
print("\nNOOP: 全部表 tenant_id 已打头,无需修补(幂等)")
|
||||
return 0
|
||||
|
||||
new_lines, changes = patch(lines, blocks)
|
||||
print("\n[PATCH] 改动 %d 处" % changes)
|
||||
|
||||
if args.dry_run or not args.inplace:
|
||||
print("[DRY-RUN] 未写盘。加 --inplace 落盘。")
|
||||
return 0
|
||||
|
||||
bak = args.ddl + ".bak"
|
||||
shutil.copy2(args.ddl, bak)
|
||||
with open(args.ddl, "w", encoding="utf-8") as fp:
|
||||
fp.write("\n".join(new_lines) + "\n")
|
||||
print("[WRITE] 已写回 %s(备份 %s)" % (args.ddl, bak))
|
||||
|
||||
# 复验:修补后必须零漂移
|
||||
blocks2 = parse_blocks(new_lines)
|
||||
d2, m2, _f2 = audit(new_lines, blocks2)
|
||||
if d2 or m2:
|
||||
print("[RECHECK] FAIL 仍有漂移 %d / 缺失 %d" % (len(d2), len(m2)))
|
||||
return 1
|
||||
print("[RECHECK] PASS tenant_id 打头 %d/%d" % (len(blocks2), len(blocks2)))
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user