# 03-数据库设计文档 - **Schema**: `xlyweberp_vibe_erp_test` - **Migration 清单**: `sql/migrations/V*.sql`(由 Flyway 顺序 apply) - **生成方式**: 由 A3 `db-design-gen` 基于 `docs/01-需求清单//REQ-*.md` REQ 卡片正向设计生成(schema SSoT)。 ## 项目标准列约定 下文每张业务表的字段清单都自动包含以下 5 个标准列(匈牙利前缀 `i` int / `s` varchar / `t` datetime)。渲染时由 `docs-03-table-template.md` 模板内置原样输出。 | 列名 | 类型 | 可空 | 主键 | 说明 | |---|---|---|---|---| | `iIncrement` | int | 否 | 是 | 整数主键 ID(自增方式由实现决定:DB `AUTO_INCREMENT` 或应用 / 触发器分配) | | `sId` | varchar(100) | 是 | — | 业务 ID(对外暴露的字符串标识,如 UUID / 人类可读编号) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离) | | `tCreateDate` | datetime | 否 | — | 记录创建时间 | 字典 / 辅助表如有豁免,在该表业务注记里注明豁免原因。 ## ER 关系概览 ``` tCompany (公司/版本字典) ▲ │ 登录时仅作为下拉来源,无 FK 引用 tEmployee (职员) ▲ │ iEmployeeId(可空) │ tUser ────────────────────────► tUserPermission ◄──── tPermission (用户) N:M (经关联表) (权限分类字典) ``` - `tUser` 通过 `iEmployeeId` 可选关联 `tEmployee`(员工名/部门 等显示属性的来源)。 - `tUser` 与 `tPermission` 经 `tUserPermission` 关联表实现多对多权限分配。 - `tCompany` 在登录场景作为「版本」下拉值的来源,业务上独立,登录时不强约束 FK(避免账号跨公司复用受阻)。 ## 表清单 - `tUser` — 系统用户主表(账号 / 类型 / 语言 / 密码哈希 / 登录态) - `tEmployee` — 职员字典(员工名 / 部门),被用户表可选引用 - `tPermission` — 权限分类字典 - `tUserPermission` — 用户 ↔ 权限 多对多关联表 - `tCompany` — 公司及其版本字典,用于登录页「版本」下拉 --- ## `tUser` — 系统用户主表 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | CURRENT_TIMESTAMP | 创建时间(标准列) | | `sUserCode` | varchar(32) | 否 | — | 用户号,业务唯一编码 | | `sUserName` | varchar(50) | 否 | — | 用户名(登录标识),全局唯一 | | `iEmployeeId` | int | 是 | NULL | 关联 `tEmployee.iIncrement`,可选;选填后页面回显员工名/部门 | | `sUserType` | varchar(20) | 否 | 'NORMAL' | 用户类型:`NORMAL`=普通用户,`ADMIN`=超级管理员 | | `sLanguage` | varchar(16) | 否 | 'zh-CN' | 界面语言:`zh-CN` 中文,`en` 英文,`zh-TW` 繁体 | | `iCanEditDoc` | tinyint(1) | 否 | 0 | 单据修改权限:0=否,1=是 | | `sPasswordHash` | varchar(100) | 否 | — | 密码哈希(BCrypt 或同强度算法),初始值由系统生成;REQ-USR-001 边界要求"以哈希形式存储" | | `iIsDisabled` | tinyint(1) | 否 | 0 | 作废标志:0=有效,1=已作废(被作废后不可登录) | | `tLastLoginDate` | datetime | 是 | NULL | 最近一次登录时间,登录成功时更新 | | `iLoginFailCount` | int | 否 | 0 | 连续登录失败计数,登录成功清零(用于阈值锁定) | | `tLockedUntil` | datetime | 是 | NULL | 临时锁定截止时间;非空且大于当前时刻视为锁定(REQ-USR-004 防暴破) | | `sCreatedBy` | varchar(50) | 是 | NULL | 制单人(创建该用户的操作员用户名) | | `tUpdateDate` | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 修改时间 | ### 索引 - `uk_tUser_sUserName` (UNIQUE): `sUserName` - `uk_tUser_sUserCode` (UNIQUE): `sUserCode` - `idx_tUser_iEmployeeId` (NORMAL): `iEmployeeId` - `idx_tUser_tenant_status` (NORMAL): `sBrandsId, sSubsidiaryId, iIsDisabled` - `idx_tUser_tLastLoginDate` (NORMAL): `tLastLoginDate` - `idx_tUser_sUserType` (NORMAL): `sUserType` ### 外键 - `fk_tUser_iEmployeeId`: `iEmployeeId` → `tEmployee.iIncrement` (ON DELETE SET NULL, ON UPDATE CASCADE) ### 业务注记 - 用户名 `sUserName` 全局唯一,对应 REQ-USR-001 跨字段规则"用户名在系统内全局唯一"。 - `sUserType` 取值受系统配置约束:当前仅 `NORMAL` / `ADMIN` 两类,由应用层枚举校验。 - 密码字段只存哈希,禁止存明文;REQ-USR-001 初始密码 `666666` 由应用层哈希后写入。 - `iLoginFailCount` + `tLockedUntil` 配合实现 REQ-USR-004 的"连续失败临时锁定账号",具体阈值由 `application.yml` 配置(如 5 次失败锁 30 分钟)。 - 作废用 `iIsDisabled` 软删除,禁止物理 DELETE;REQ-USR-002 中"被禁用账号无法登录"由 Service 层在登录时校验本字段。 --- ## `tEmployee` — 职员字典 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | CURRENT_TIMESTAMP | 创建时间(标准列) | | `sEmployeeCode` | varchar(32) | 否 | — | 员工号,业务唯一编码 | | `sEmployeeName` | varchar(50) | 否 | — | 员工姓名 | | `sDepartment` | varchar(100) | 是 | NULL | 所属部门名 | | `iIsDisabled` | tinyint(1) | 否 | 0 | 作废标志:0=有效,1=已作废 | | `tUpdateDate` | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 修改时间 | ### 索引 - `uk_tEmployee_sEmployeeCode` (UNIQUE): `sEmployeeCode` - `idx_tEmployee_sEmployeeName` (NORMAL): `sEmployeeName` - `idx_tEmployee_sDepartment` (NORMAL): `sDepartment` - `idx_tEmployee_tenant` (NORMAL): `sBrandsId, sSubsidiaryId` ### 外键 (无外向引用;本表作为字典被 `tUser.iEmployeeId` 反向引用) ### 业务注记 - 字典表,提供 REQ-USR-001/002 中"员工名"下拉来源以及 REQ-USR-003 列表中"员工名 / 部门"的显示数据。 - 部门字段当前为字符串扁平存储;如后续部门需要层级管理,再拆 `tDepartment` 表并将本字段改为外键。 - 员工被作废(`iIsDisabled=1`)后,引用了该员工的 `tUser` 记录通过 `iEmployeeId` 仍可保留旧值;查询时需 LEFT JOIN 并过滤展示。 --- ## `tPermission` — 权限分类字典 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | CURRENT_TIMESTAMP | 创建时间(标准列) | | `sCategory` | varchar(100) | 否 | — | 权限分类编码(如 `usr:user:create`) | | `sCategoryName` | varchar(100) | 否 | — | 权限分类中文名(用于权限组复选框展示) | | `sDescription` | varchar(255) | 是 | NULL | 权限说明 | | `iIsDisabled` | tinyint(1) | 否 | 0 | 作废标志:0=有效,1=已作废 | | `tUpdateDate` | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 修改时间 | ### 索引 - `uk_tPermission_sCategory` (UNIQUE): `sCategory` - `idx_tPermission_sCategoryName` (NORMAL): `sCategoryName` ### 外键 (无) ### 业务注记 - 提供 REQ-USR-001/002 表 2「权限组」复选框的下拉数据;新增 / 修改用户时配套写入 `tUserPermission`。 - `sCategory` 作为程序内 RBAC 校验的字符串编码,规范见 `docs/04 § 1.6`;新增权限须同步发布到后端枚举与前端 ``。 - 字典表,行数预期 < 1000;不做按租户隔离查询的复合索引。 --- ## `tUserPermission` — 用户 ↔ 权限多对多关联表 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | CURRENT_TIMESTAMP | 创建时间(标准列) | | `iUserId` | int | 否 | — | 用户主键,关联 `tUser.iIncrement` | | `iPermissionId` | int | 否 | — | 权限主键,关联 `tPermission.iIncrement` | | `sGrantedBy` | varchar(50) | 是 | NULL | 授权操作员用户名(审计用) | ### 索引 - `uk_tUserPermission_user_perm` (UNIQUE): `iUserId, iPermissionId` - `idx_tUserPermission_iPermissionId` (NORMAL): `iPermissionId` ### 外键 - `fk_tUserPermission_iUserId`: `iUserId` → `tUser.iIncrement` (ON DELETE CASCADE, ON UPDATE CASCADE) - `fk_tUserPermission_iPermissionId`: `iPermissionId` → `tPermission.iIncrement` (ON DELETE RESTRICT, ON UPDATE CASCADE) ### 业务注记 - 关联表,承载 REQ-USR-001/002 表 2「权限组」的勾选结果。 - 用户被删除时级联清理本表行;权限分类被删除时阻止(需先解除全部用户授权)。 - 唯一索引 `(iUserId, iPermissionId)` 防止重复授权。 - 字典关联表不带 `tUpdateDate` / `iIsDisabled`:授权关系采用"存在即生效,删除即撤销"语义,无需软删。 --- ## `tCompany` — 公司及版本字典 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | CURRENT_TIMESTAMP | 创建时间(标准列) | | `sCompanyName` | varchar(100) | 否 | — | 公司名称 | | `sEdition` | varchar(32) | 否 | '标准版' | 版本:`标准版` / `专业版` / `企业版` 等 | | `iIsDisabled` | tinyint(1) | 否 | 0 | 作废标志 | | `tUpdateDate` | datetime | 否 | CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 修改时间 | ### 索引 - `idx_tCompany_sCompanyName` (NORMAL): `sCompanyName` - `idx_tCompany_sEdition` (NORMAL): `sEdition` ### 外键 (无) ### 业务注记 - 字典表,提供 REQ-USR-004 登录页「版本」下拉数据。 - 不与 `tUser` 建外键:账号可在多公司 / 多版本之间复用;登录时仅用作上下文选择,由应用层校验"用户是否被允许进入该公司版本"。 - 当 `sEdition` 的取值集合稳定后,可改为受控字典并迁移到 `tDictionary` 类公共字典表;当前阶段独立维护。 --- ## 种子数据(V2 migration) 由 `sql/migrations/V2__seed_admin_and_permissions.sql` 写入,REQ-USR-001 配套。 ### `tPermission` | sCategory | sCategoryName | 用途 | |---|---|---| | `usr:user:create` | 新增用户 | REQ-USR-001 接口 `@PreAuthorize` | | `usr:user:update` | 修改用户 | REQ-USR-002 接口 `@PreAuthorize` | | `usr:user:list` | 查询用户 | REQ-USR-003 接口 `@PreAuthorize` | | `usr:user:assign-role` | 分配用户角色 | REQ-USR-002 修改 `userType` 子权限 | ### `tUser` — 超级管理员 | sUserCode | sUserName | sUserType | sLanguage | sBrandsId | sSubsidiaryId | 明文密码 | |---|---|---|---|---|---|---| | ADMIN001 | admin | ADMIN | zh-CN | BR-DEFAULT | SUB-DEFAULT | `admin`(BCrypt $2y$10$ 哈希存入) | ### `tUserPermission` admin × 上述 4 个权限分类,全部授权(`sGrantedBy='system'`)。