Files
workspace/code/fms/FMS新系统核心表结构设计.md
T
2026-08-18 22:33:54 +08:00

646 lines
37 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FMS 新系统核心表结构设计
## 1. 说明
本文档给出 FMS 新系统核心平台表的 SQL Server 建表语句,范围包括元数据中心(模块、实体、字段、字段分组、关系、页面菜单、多语言)、Schema Compiler、权限中心、技术日志、登录日志与业务审计。
设计原则:
- 业务实体(订舱、集装箱、发票等)由 Schema Compiler 根据 `s_module_entity` + `s_module_field` 生成真实物理表,本文档只定义平台核心表。
- 实体是数据和字段的所有者,页面只是实体的一种展示方式;字段挂实体(`s_module_entity`),不挂菜单。
- 页面和菜单合并为一条 `s_module_menu` 记录(导航节点 = 页面入口),用 `b_menu_type` 区分节点性质。
- 元数据变更通过服务层校验后立即生效,DDL 同步执行、失败回滚,不做异步迁移任务表,也不建立配置变更集、版本快照或运行时状态表。
约定如下:
- 所有表名以 `s_` 开头,字段名以 `b_` 开头。
- 表名、字段名、索引名和约束名统一使用 `snake_case`。
- 不创建物理外键,关联字段只作为逻辑外键使用。
- 逻辑外键必须创建必要的普通索引或唯一索引。
- 一个租户使用一个独立业务数据库,普通业务表不重复保存 `b_tenant_id` 或 `b_org_id`;集中技术日志和登录日志允许使用 `b_org_id` 标识日志来源。
- 内部主键统一使用 `bigint identity(1, 1)`,跨环境标识使用稳定的 `b_*_key`。
- 同库内的逻辑关联 ID(例如 `b_form_id`)统一使用 `bigint`,不使用 `uniqueidentifier`。
- 时间点统一使用 `datetime2(3)`,应用层按 UTC 写入。
- 稳定业务标识统一使用 `b_*_key`,跨环境导入导出不得依赖内部 `b_id`。
- 扩展内容统一使用 `nvarchar(max)` 普通文本保存,由应用层按业务约定解析和校验,不使用 JSON 字段类型。
- 原布尔语义字段统一使用 `tinyint`,取值约定为 `0`(否)或 `1`(是)。
- 核心业务字段使用真实数据库列,不采用全量 EAV;不设置无业务含义的通用扩展列(如 `b_bz1~n`、`mx_varchar_n`),字段必须有明确的 `b_field_key` 与语义。
- 下面的 `b_*_id`、`b_*_key` 关联均为逻辑外键,由应用服务负责校验一致性。
## 2. 元数据中心
### 2.1 模块
模块是业务能力边界,不是数据库表的别名。模块只保存身份、依赖与启用状态,不承载菜单、路由或数据源职责。
```sql
create table dbo.s_module (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_module_key nvarchar(128) not null, -- 模块稳定业务标识(如 ocean、finance、master-data)
b_name_key nvarchar(256) not null, -- 模块显示名多语言 key
b_description nvarchar(1000) null, -- 模块描述
b_origin nvarchar(32) not null -- 来源:platform 平台内置 / tenant 租户定制
constraint df_s_module_origin default N'platform',
b_enabled tinyint not null -- 是否启用(1启用/0停用)
constraint df_s_module_enabled default 1,
b_sort_no int not null -- 模块排序号
constraint df_s_module_sort_no default 0,
b_icon_key nvarchar(128) null, -- 模块图标 key
b_config_text nvarchar(max) null, -- 模块扩展配置(应用自定义解析)
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_module_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_module primary key (b_id),
constraint ux_s_module_key unique (b_module_key)
);
create index ix_s_module_key
on dbo.s_module (b_module_key, b_enabled);
```
### 2.2 模块依赖
模块依赖必须形成有向无环图,不允许循环依赖。
```sql
create table dbo.s_module_dependency (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_module_key nvarchar(128) not null, -- 依赖方模块 key(如 ocean)
b_depends_on_module_key nvarchar(128) not null, -- 被依赖模块 key(如 master-data)
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_module_dependency_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_module_dependency primary key (b_id),
constraint ux_s_module_dependency_key unique (
b_module_key,
b_depends_on_module_key
)
);
create index ix_s_module_dependency_depends_on
on dbo.s_module_dependency (b_depends_on_module_key);
```
### 2.3 实体
实体是数据和字段的所有者,同时声明"查询数据源"和"保存数据源"。查询源可以是真实表,也可以是带关联/聚合的 SQL 视图(视图只读,用于列表展示);保存目标必须是真实表。
```sql
create table dbo.s_module_entity (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_entity_key nvarchar(192) not null, -- 实体稳定业务标识(如 ocean.booking)
b_module_key nvarchar(128) not null, -- 所属模块 key
b_name_key nvarchar(256) not null, -- 实体显示名多语言 key
b_description nvarchar(1000) null, -- 实体描述
b_view_table sysname not null, -- 查询数据源:真实表或 SQL 视图(如 ocean_booking / v_booking_with_fee)
b_save_table sysname null, -- 保存目标:真实表(查询源为视图时必填,只读实体可为空)
b_key_field sysname null, -- 保存对象主键字段(如 b_id)
b_delete_policy nvarchar(32) not null -- 删除策略(默认 lifecycle)
constraint df_s_module_entity_delete_policy default N'lifecycle',
b_origin nvarchar(32) not null -- 来源:platform / tenant
constraint df_s_module_entity_origin default N'platform',
b_enabled tinyint not null -- 是否启用
constraint df_s_module_entity_enabled default 1,
b_config_text nvarchar(max) null, -- 实体扩展配置
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_module_entity_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_module_entity primary key (b_id),
constraint ux_s_module_entity_key unique (b_entity_key)
);
create index ix_s_module_entity_module_key
on dbo.s_module_entity (b_module_key, b_enabled);
create index ix_s_module_entity_save_table
on dbo.s_module_entity (b_save_table);
```
实体的"查/存"配置方式:
```text
简单实体: b_view_table = b_save_table = 同一张真实表
复杂列表: b_view_table = 带关联/聚合的 SQL 视图(只读), b_save_table = 真实表
纯查询实体: b_view_table = 视图或表, b_save_table = 空(只读,不可保存)
```
删除策略取值(`b_delete_policy`):
```text
restrictWhenReferenced 主数据:有引用时拒绝删除,只能停用或合并
lifecycle 业务单据:草稿且无下游时可删,正式后只能取消/作废
cascadeOwned 主表拥有的从数据:随主表同一事务级联删除
hardDelete 临时记录:校验权限后直接物理删除
```
### 2.4 字段
字段属于实体,同时携带数据库列定义、UI 行为与业务语义(供 UI 和 AI 理解)。
```sql
create table dbo.s_module_field (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_entity_key nvarchar(192) not null, -- 所属实体 key
b_field_key nvarchar(128) not null, -- 字段稳定业务标识(如 carrier_id)
b_name_key nvarchar(256) not null, -- 字段显示名多语言 key
b_label nvarchar(256) not null, -- 字段标签(可随时改,不改数据库)
b_description nvarchar(1000) null, -- 字段描述
b_physical_column_name sysname not null, -- 真实数据库列名(通常与 b_field_key 相同)
b_data_type nvarchar(64) not null, -- 存储数据类型(如 varchar/decimal/datetime)
b_semantic_type nvarchar(128) null, -- 语义类型(如 email/money/phone,供 UI/AI 理解)
b_write_mode nvarchar(32) not null -- 后端写入模式(如 direct/compute/readonly)
constraint df_s_module_field_write_mode default N'direct',
b_required tinyint not null -- 是否必填
constraint df_s_module_field_required default 0,
b_enabled tinyint not null -- 是否启用(停用则隐藏并保留数据)
constraint df_s_module_field_enabled default 1,
b_queryable tinyint not null -- 是否出现在查询条件中
constraint df_s_module_field_queryable default 0,
b_sortable tinyint not null -- 是否可排序
constraint df_s_module_field_sortable default 0,
b_list_visible tinyint not null -- 是否显示在固定列表组件
constraint df_s_module_field_list_visible default 1,
b_edit_visible tinyint not null -- 是否显示在固定编辑组件
constraint df_s_module_field_edit_visible default 1,
b_readonly tinyint not null -- 编辑组件中是否只读
constraint df_s_module_field_readonly default 0,
b_sort_no int not null -- 列表/表单默认排序
constraint df_s_module_field_sort_no default 0,
b_group_key nvarchar(128) null, -- 所属分组 key(逻辑外键,空为未分组)
b_width int null, -- 列表列宽(px)
b_component_type nvarchar(64) null, -- 固定表单组件类型(input/select/date)
b_auditable tinyint not null -- 是否记录字段级审计
constraint df_s_module_field_auditable default 0,
b_audit_visibility nvarchar(32) null, -- 审计可见性(内部/客户可见)
b_sensitive tinyint not null -- 是否敏感字段(涉及脱敏/导出控制)
constraint df_s_module_field_sensitive default 0,
b_max_length int null, -- 字符串最大长度
b_numeric_precision tinyint null, -- 数值精度(总位数)
b_numeric_scale tinyint null, -- 数值小数位
b_temporal_type nvarchar(32) null, -- 时间类型(如 date/datetime)
b_unit_key nvarchar(128) null, -- 计量单位 key
b_default_value_text nvarchar(max) null, -- 默认值(文本表达)
b_aliases_text nvarchar(max) null, -- 字段别名(搜索/AI 理解用)
b_validation_text nvarchar(max) null, -- 校验规则(文本表达)
b_ai_hints_text nvarchar(max) null, -- 给 AI 理解的提示信息
b_origin nvarchar(32) not null -- 来源:platform / tenant
constraint df_s_module_field_origin default N'platform',
b_required_by_code tinyint not null -- 是否被代码强依赖
constraint df_s_module_field_required_by_code default 0,
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_module_field_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_module_field primary key (b_id),
constraint ux_s_module_field_key unique (
b_entity_key,
b_field_key
)
);
create index ix_s_module_field_entity_key
on dbo.s_module_field (b_entity_key, b_enabled, b_sort_no, b_field_key);
create index ix_s_module_field_physical_column_name
on dbo.s_module_field (b_entity_key, b_physical_column_name);
```
写入模式取值(`b_write_mode`):
```text
direct 可通过 saveobjt 普通保存(如备注、ETD、件数)
createOnly 仅创建时允许写入(如来源系统、初始业务类型)
readOnly 前端和普通接口只读(如汇总金额、关联展示值)
computed 由公式或计算服务生成(如毛利、计费重量)
actionOnly 只能通过指定业务动作修改(如审核状态、确认时间)
system 仅平台内部维护(如创建人、版本、流水状态)
```
### 2.5 关系
`b_relation` 描述实体之间的引用与主子关系,通用运行时据此执行外键校验、主子事务、级联删除和子表区域渲染。
```sql
create table dbo.s_module_relation (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_relation_key nvarchar(192) not null, -- 关系稳定业务标识
b_entity_key nvarchar(192) not null, -- 主实体 key
b_relation_type nvarchar(32) not null, -- 关系类型:one-to-one/one-to-many/many-to-one/many-to-many
b_target_entity_key nvarchar(192) not null, -- 目标实体 key
b_ownership nvarchar(32) not null -- 所有权(默认 reference 引用)
constraint df_s_module_relation_ownership default N'reference',
b_required tinyint not null -- 是否必填
constraint df_s_module_relation_required default 0,
b_delete_policy nvarchar(32) null, -- 删除策略:restrict/set-null/cascade/archive
b_save_strategy nvarchar(32) null, -- 保存策略:separate 独立保存 / with-parent 随主实体事务保存
b_order_field nvarchar(256) null, -- 子表排序字段表达式
b_unique_constraint tinyint not null -- 是否唯一约束
constraint df_s_module_relation_unique_constraint default 0,
b_name_key nvarchar(256) not null, -- 关系显示名多语言 key
b_enabled tinyint not null -- 是否启用
constraint df_s_module_relation_enabled default 1,
b_config_text nvarchar(max) null, -- 关系扩展配置
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_module_relation_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_module_relation primary key (b_id),
constraint ux_s_module_relation_key unique (b_relation_key)
);
create index ix_s_module_relation_entity_key
on dbo.s_module_relation (b_entity_key, b_enabled);
create index ix_s_module_relation_target_entity_key
on dbo.s_module_relation (b_target_entity_key);
```
### 2.6 页面菜单入口
每条菜单记录同时代表一个导航节点和一个页面入口。`directory` 仅表示目录节点,`page` 使用固定 Vue 页面组件,`data_category` 表示数据目录,`data` 表示由通用列表与表单组件维护的数据模块,`external` 表示外链。
```sql
create table dbo.s_module_menu (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_menu_key nvarchar(192) not null, -- 菜单/页面稳定业务标识
b_module_key nvarchar(128) null, -- 所属平台模块 key
b_parent_menu_key nvarchar(192) null, -- 父菜单 key(导航树自引用)
b_name_key nvarchar(256) not null, -- 菜单显示名多语言 key
b_menu_type nvarchar(32) not null, -- 菜单类型:directory/page/data_category/data/external
b_route nvarchar(256) null, -- 固定页面或外链路由
b_entity_key nvarchar(192) null, -- data 类型绑定的实体 key
b_permission_key nvarchar(192) null, -- 页面访问权限 key
b_icon_key nvarchar(128) null, -- 菜单图标 key
b_sort_no int not null -- 菜单排序号
constraint df_s_module_menu_sort_no default 0,
b_can_menu tinyint not null -- 是否显示在菜单中
constraint df_s_module_menu_can_menu default 1,
b_enabled tinyint not null -- 是否启用
constraint df_s_module_menu_enabled default 1,
b_config_text nvarchar(max) null, -- 菜单/页面扩展配置
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_module_menu_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_module_menu primary key (b_id),
constraint ux_s_module_menu_key unique (b_menu_key)
);
create index ix_s_module_menu_module_key
on dbo.s_module_menu (b_module_key, b_enabled);
create index ix_s_module_menu_parent_key
on dbo.s_module_menu (b_parent_menu_key, b_sort_no, b_enabled);
create index ix_s_module_menu_route
on dbo.s_module_menu (b_route, b_enabled);
create index ix_s_module_menu_entity_key
on dbo.s_module_menu (b_entity_key, b_enabled);
```
约束由元数据校验器执行:`directory` 节点不能填写业务表或外链路由;`page` 节点必须填写 `b_route`;`data` 节点必须填写 `b_entity_key`(查询走实体 `b_view_table`,保存走实体 `b_save_table`);`external` 节点必须填写 `b_route` 和 `b_permission_key`。固定页面组件负责布局,表中只保存实体引用和导航配置。目录仅在至少存在一个可访问子页面时显示。
### 2.7 字段分组
字段分组是实体级独立定义,用于表单/编辑页面按分组展示字段。分组定义集中在 `s_module_field_group`,字段通过 `s_module_field.b_group_key` 引用分组,避免在每个字段上重复维护分组标题与排序。
```sql
create table dbo.s_module_field_group (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_entity_key nvarchar(192) not null, -- 所属实体 key
b_group_key nvarchar(128) not null, -- 分组稳定标识(如 basic/transport/finance)
b_name_key nvarchar(256) not null, -- 分组标题多语言 key
b_sort_no int not null -- 分组排序号(0,1,2...)
constraint df_s_module_field_group_sort_no default 0,
b_enabled tinyint not null -- 是否启用(停用则整组隐藏)
constraint df_s_module_field_group_enabled default 1,
b_config_text nvarchar(max) null, -- 分组扩展配置
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_module_field_group_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_module_field_group primary key (b_id),
constraint ux_s_module_field_group_key unique (
b_entity_key,
b_group_key
)
);
create index ix_s_module_field_group_entity_key
on dbo.s_module_field_group (b_entity_key, b_enabled, b_sort_no);
```
表单渲染时按 `b_sort_no` 排序分组,组内字段按 `s_module_field.b_sort_no` 排序;`s_module_field.b_group_key` 为空的字段显示在"未分组"区。新增/调整/停用分组只改 `s_module_field_group`,不需要逐个修改字段。
### 2.8 多语言
多语言是元数据运行时的一部分,统一解析模块、菜单、实体、字段、动作和主数据的显示名称。
```sql
create table dbo.s_module_i18n (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_resource_key nvarchar(256) not null, -- 多语言资源 key(如 nameKey)
b_locale nvarchar(32) not null, -- 语言区域(如 zh-CN/en-US)
b_resource_value nvarchar(max) not null, -- 该语言下的显示文本
b_source_type nvarchar(32) not null -- 来源类型(默认 manual 人工 / ai AI 生成)
constraint df_s_module_i18n_source_type default N'manual',
b_resource_status nvarchar(32) not null -- 资源状态(默认 confirmed 已确认)
constraint df_s_module_i18n_resource_status default N'confirmed',
b_model_key nvarchar(128) null, -- 生成翻译的 AI 模型标识(追溯用)
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_module_i18n_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_module_i18n primary key (b_id),
constraint ux_s_module_i18n_key_locale unique (
b_resource_key,
b_locale
)
);
create index ix_s_module_i18n_resource_key
on dbo.s_module_i18n (b_resource_key, b_locale);
```
## 3. Schema Compiler
元数据变更通过服务层校验后立即生效。Schema Compiler 根据 `s_module_entity` 的保存数据源(`b_save_table`)配置和 `s_module_field` 的物理字段配置生成所需的 `CREATE TABLE`、`ALTER TABLE`、索引和约束语句,并由应用服务直接执行;执行成功后提交元数据变更,失败则回滚本次操作并返回错误。查询数据源(`b_view_table`)为 SQL 视图时,由运维或售后在数据库中维护视图定义,Schema Compiler 不生成视图 DDL。
执行机制:
- DDL 同步执行,单租户库内加锁,同一时间只允许一个结构变更任务;其他租户不受影响。
- 每个变更步骤记录开始时间、结束时间、checksum 和执行结果;重启或网络中断后可以从最后一个已确认步骤继续执行。
- DDL、数据转换和结构校验全部成功后,才提交元数据变更;提交失败保持原结构,进入可修复状态。
- 变更审计统一写入现有审计日志;本阶段不建立配置变更集、版本快照或迁移任务表,如果未来需要异步执行、失败重试、断点恢复或版本回滚,再增加专用任务表。
- 破坏性变更(删除字段、缩短长度、改变类型)采用 expand-contract:先新增兼容结构、双写或分批迁移数据、校验新旧数据、停止写入旧结构、经过保留期后归档或删除旧结构。
## 4. 统一权限中心
### 4.1 角色与用户角色关系
```sql
create table dbo.s_auth_role (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_role_key nvarchar(128) not null, -- 角色稳定业务标识
b_role_name nvarchar(256) not null, -- 角色名称
b_description nvarchar(1000) null, -- 角色描述
b_role_type nvarchar(32) not null -- 角色类型(默认 custom 自定义)
constraint df_s_auth_role_role_type default N'custom',
b_enabled tinyint not null -- 是否启用
constraint df_s_auth_role_enabled default 1,
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_auth_role_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
b_updated_at datetime2(3) null, -- 更新时间
b_updated_by nvarchar(128) null, -- 更新人
constraint pk_s_auth_role primary key (b_id),
constraint ux_s_auth_role_key unique (b_role_key)
);
create table dbo.s_auth_user_role (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_user_key nvarchar(128) not null, -- 用户稳定 key
b_role_key nvarchar(128) not null, -- 角色 key
b_enabled tinyint not null -- 是否启用(该用户角色关系)
constraint df_s_auth_user_role_enabled default 1,
b_effective_from datetime2(3) null, -- 生效开始时间(可定时)
b_effective_to datetime2(3) null, -- 生效结束时间(可定时)
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_auth_user_role_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_auth_user_role primary key (b_id),
constraint ux_s_auth_user_role_key unique (b_user_key, b_role_key)
);
create index ix_s_auth_user_role_role_key
on dbo.s_auth_user_role (b_role_key, b_enabled);
```
### 4.2 功能权限
首期只做 RBAC 功能授权(页面、实体、动作、字段)。数据范围策略(`auth_data_policy`)和字段查看/导出/脱敏策略(`auth_field_policy`)作为后续扩展,不在本版本建表。
```sql
create table dbo.s_auth_permission (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_permission_key nvarchar(192) not null, -- 权限稳定业务标识
b_module_key nvarchar(128) null, -- 所属模块 key
b_resource_type nvarchar(32) not null, -- 资源类型(如 menu/entity/field/action)
b_resource_key nvarchar(256) not null, -- 资源稳定 key(被授权的对象)
b_action_type nvarchar(64) null, -- 操作类型(如 view/create/update/delete/confirm)
b_name_key nvarchar(256) not null, -- 权限显示名多语言 key
b_description nvarchar(1000) null, -- 权限描述
b_enabled tinyint not null -- 是否启用
constraint df_s_auth_permission_enabled default 1,
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_auth_permission_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_auth_permission primary key (b_id),
constraint ux_s_auth_permission_key unique (b_permission_key)
);
create table dbo.s_auth_role_permission (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_role_key nvarchar(128) not null, -- 角色 key
b_permission_key nvarchar(192) not null, -- 权限 key
b_permission_effect nvarchar(16) not null -- 权限效果(默认 allow 允许)
constraint df_s_auth_role_permission_effect default N'allow',
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_auth_role_permission_created_at default sysutcdatetime(),
b_created_by nvarchar(128) not null, -- 创建人
constraint pk_s_auth_role_permission primary key (b_id),
constraint ux_s_auth_role_permission_key unique (
b_role_key,
b_permission_key
)
);
create index ix_s_auth_permission_resource_key
on dbo.s_auth_permission (b_resource_type, b_resource_key, b_enabled);
create index ix_s_auth_role_permission_permission_key
on dbo.s_auth_role_permission (b_permission_key, b_permission_effect);
```
菜单显示继承页面访问权限:用户拥有 `s_module_menu.b_permission_key` 对应权限时菜单才显示;目录菜单在无可访问子页面时自动隐藏。前端只控制显示,后端通用数据运行时和动作引擎必须再次检查同一个权限 key。
## 5. 日志与审计
### 5.1 技术日志
技术日志主要用于请求链路、SQL、异常、性能和外部接口排查,推荐写入 Loki、OpenSearch、Elasticsearch 等日志平台。下面的表适合集中日志库或短期数据库兜底,不建议把所有高频技术日志长期写入租户业务库。
```sql
create table dbo.s_log_technical (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_occurred_at datetime2(3) not null -- 发生时间(UTC)
constraint df_s_log_technical_occurred_at default sysutcdatetime(),
b_log_level nvarchar(16) not null, -- 日志级别(如 INFO/WARN/ERROR)
b_log_category nvarchar(64) not null, -- 日志分类(如 sql/exception/performance)
b_operation nvarchar(192) not null, -- 操作名(如 loadData/saveObject)
b_org_id nvarchar(128) null, -- 租户/组织 ID(日志来源标识)
b_user_key nvarchar(128) null, -- 操作用户 key
b_source_type nvarchar(32) null, -- 来源类型(如 web/api)
b_module_key nvarchar(128) null, -- 相关模块 key
b_operation_key nvarchar(192) null, -- 相关操作 key(如 saveObject.submit)
b_request_id nvarchar(128) null, -- 请求 ID
b_trace_id nvarchar(128) null, -- 追踪 ID(串联链路)
b_application_version nvarchar(128) null, -- 应用版本
b_server_node nvarchar(128) null, -- 服务节点标识
b_duration_ms bigint null, -- 耗时(毫秒)
b_result_code nvarchar(128) null, -- 结果码
b_error_code nvarchar(128) null, -- 错误码
b_error_message nvarchar(2000) null, -- 错误信息
b_exception_text nvarchar(max) null, -- 异常堆栈(文本)
b_context_text nvarchar(max) null, -- 上下文信息(文本)
constraint pk_s_log_technical primary key (b_id)
);
create index ix_s_log_technical_trace_id
on dbo.s_log_technical (b_trace_id, b_occurred_at desc);
create index ix_s_log_technical_org_time
on dbo.s_log_technical (b_org_id, b_occurred_at desc);
create index ix_s_log_technical_level_time
on dbo.s_log_technical (b_log_level, b_occurred_at desc);
```
### 5.2 登录日志
登录日志记录登录成功、失败、退出、刷新令牌和账号锁定等安全事件。它可以与技术日志使用相同的 `b_request_id`、`b_trace_id` 关联,但业务职责独立。
```sql
create table dbo.s_log_login (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_org_id nvarchar(128) null, -- 租户/组织 ID
b_user_key nvarchar(128) null, -- 用户 key
b_login_name nvarchar(256) null, -- 登录名
b_login_type nvarchar(32) not null, -- 登录类型(如 password/token)
b_login_status nvarchar(32) not null, -- 登录状态(如 success/failed)
b_auth_method nvarchar(32) null, -- 认证方式(如 ldap/oidc)
b_failure_reason nvarchar(512) null, -- 失败原因
b_ip_address varchar(64) null, -- 登录 IP
b_user_agent nvarchar(1000) null, -- 客户端 UA
b_device_key nvarchar(256) null, -- 设备标识
b_request_id nvarchar(128) null, -- 请求 ID
b_trace_id nvarchar(128) null, -- 追踪 ID
b_occurred_at datetime2(3) not null -- 发生时间(UTC)
constraint df_s_log_login_occurred_at default sysutcdatetime(),
b_created_at datetime2(3) not null -- 创建时间(UTC)
constraint df_s_log_login_created_at default sysutcdatetime(),
constraint pk_s_log_login primary key (b_id)
);
create index ix_s_log_login_user_time
on dbo.s_log_login (b_user_key, b_occurred_at desc);
create index ix_s_log_login_name_time
on dbo.s_log_login (b_login_name, b_occurred_at desc);
create index ix_s_log_login_status_time
on dbo.s_log_login (b_login_status, b_occurred_at desc);
create index ix_s_log_login_trace_id
on dbo.s_log_login (b_trace_id, b_occurred_at desc);
```
### 5.3 业务审计事件与字段变更
```sql
create table dbo.s_log_audit (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_event_key nvarchar(192) not null, -- 业务事件稳定标识
b_module_key nvarchar(128) not null, -- 被审计的数据模块 key
b_entity_id nvarchar(128) not null, -- 被审计的业务数据 ID
b_business_no nvarchar(192) null, -- 业务单号(如订舱号)
b_operation_key nvarchar(192) null, -- 触发的操作 key(如 saveObject.submit)
b_operator_key nvarchar(128) not null, -- 操作人 key
b_operator_name nvarchar(256) null, -- 操作人名称(快照)
b_source_type nvarchar(32) not null, -- 来源类型(如 user/ai/api)
b_visibility nvarchar(32) not null, -- 可见性(内部/客户可见)
b_request_id nvarchar(128) null, -- 请求 ID
b_trace_id nvarchar(128) not null, -- 追踪 ID(关联技术日志)
b_business_event_id bigint null, -- 关联的业务事件 ID
b_payload_text nvarchar(max) null, -- 事件载荷(文本,如前后快照)
b_occurred_at datetime2(3) not null -- 发生时间(UTC)
constraint df_s_log_audit_occurred_at default sysutcdatetime(),
constraint pk_s_log_audit primary key (b_id)
);
create table dbo.s_log_audit_field (
b_id bigint identity(1, 1) not null, -- 内部自增主键
b_event_id bigint not null, -- 所属审计事件 ID
b_module_key nvarchar(128) not null, -- 数据模块 key
b_entity_id nvarchar(128) not null, -- 业务数据 ID
b_field_key nvarchar(128) not null, -- 变更的字段 key
b_field_label_snapshot nvarchar(256) null, -- 字段标签快照
b_before_value_text nvarchar(max) null, -- 变更前原始值
b_after_value_text nvarchar(max) null, -- 变更后原始值
b_before_display_value nvarchar(1000) null, -- 变更前显示值(如引用字段 label)
b_after_display_value nvarchar(1000) null, -- 变更后显示值
b_visibility nvarchar(32) not null, -- 可见性(内部/客户可见)
constraint pk_s_log_audit_field primary key (b_id)
);
create index ix_s_log_audit_module
on dbo.s_log_audit (b_module_key, b_entity_id, b_occurred_at desc);
create index ix_s_log_audit_trace_id
on dbo.s_log_audit (b_trace_id);
create index ix_s_log_audit_field_audit_event_id
on dbo.s_log_audit_field (b_event_id);
```
## 6. 逻辑外键清单
以下关联不创建物理外键,由服务层、变更校验器和 Schema Compiler 负责检查:
| 表 | 字段 | 逻辑目标 |
| --- | --- | --- |
| `s_module_dependency` | `b_module_key` | `s_module.b_module_key` |
| `s_module_dependency` | `b_depends_on_module_key` | `s_module.b_module_key` |
| `s_module_entity` | `b_module_key` | `s_module.b_module_key` |
| `s_module_field` | `b_entity_key` | `s_module_entity.b_entity_key` |
| `s_module_field` | `b_group_key` | 实体范围内的 `s_module_field_group.b_group_key` |
| `s_module_field_group` | `b_entity_key` | `s_module_entity.b_entity_key` |
| `s_module_relation` | `b_entity_key` | `s_module_entity.b_entity_key` |
| `s_module_relation` | `b_target_entity_key` | `s_module_entity.b_entity_key` |
| `s_module_menu` | `b_module_key` | `s_module.b_module_key` |
| `s_module_menu` | `b_parent_menu_key` | `s_module_menu.b_menu_key` |
| `s_module_menu` | `b_entity_key` | `s_module_entity.b_entity_key` |
| `s_module_menu` | `b_permission_key` | `s_auth_permission.b_permission_key` |
| `s_auth_user_role` | `b_role_key` | `s_auth_role.b_role_key` |
| `s_auth_role_permission` | `b_permission_key` | `s_auth_permission.b_permission_key` |
| `s_log_audit_field` | `b_event_id` | `s_log_audit.b_id` |
| `s_log_technical` | `b_user_key` | 当前身份系统的用户 `b_user_key` |
| `s_log_login` | `b_user_key` | 当前身份系统的用户 `b_user_key` |
逻辑外键写入时应执行以下校验:
```text
稳定 key 是否存在
-> 目标资源是否启用
-> 跨模块引用是否合法(依赖图中可达)
-> 字段、实体类型和分组配置是否匹配
-> 删除或停用前是否仍被其他资源引用
```
## 7. 实施建议
建议按以下顺序创建和启用这些表:
```text
元数据基础表(模块/依赖/实体/字段/字段分组/关系)
-> 页面菜单入口表
-> 多语言表
-> 权限表
-> 日志与审计表
```
正式执行前还应补充:
- 根据实际 SQL Server 2022 环境确认过滤索引和 `datetime2` 支持情况。
- 根据现有用户表确定 `b_user_key`、`b_created_by` 和 `b_updated_by` 的实际数据类型。
- 根据最终稳定 key 长度评估唯一索引的键长度。
- 为高数据量审计表制定归档及清理策略。
- 用独立测试数据库执行完整建表脚本,并验证重复安装和 Schema 迁移流程。
- 选择一条真实业务纵向验证(例如"基础资料 + 海运订舱 + 确认动作"),验证售后新增字段、Schema Compiler 加列、生成列表/表单和 DDL 失败回滚的完整链路。