# 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 关系概览 ``` usr_user(用户主表) └─< usr_user_permission(用户权限关联,多对多中间表)>─ usr_permission_group(权限分类表) 跨模块引用(当前阶段记录,对应表由后续模块设计): usr_user.sEmployeeId → 职员表.sId(跨模块,可空,ON DELETE SET NULL) ``` ## 表清单 - `usr_user` — 用户账户主表,存储登录信息、类型、语言偏好及安全控制字段 - `tStaff` — 职员维度(员工名 / 部门 / 编号) - `usr_permission_group` — 权限分类/权限组定义表,每行对应一个可分配给用户的权限项 - `usr_user_permission` — 用户与权限组的多对多关联表 - `brand` — 公司/品牌主表,登录账号前缀来源 --- ## `usr_user` — 用户账户主表,存储登录信息、类型、语言偏好及安全控制字段 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | | `sUserCode` | varchar(50) | 否 | — | 用户号(业务编号,人类可读唯一标识) | | `sUsername` | varchar(100) | 否 | — | 用户名(登录标识,全局唯一,不可修改) | | `sPasswordHash` | varchar(255) | 否 | — | BCrypt 哈希密码,禁止存储明文 | | `sUserType` | varchar(20) | 否 | `普通用户` | 用户类型:`普通用户` / `超级管理员` | | `sLanguage` | varchar(20) | 否 | `中文` | 界面语言:`中文` / `英文` / `繁体` | | `bCanEditDoc` | tinyint(1) | 否 | `0` | 单据修改权限:0=否,1=是 | | `bIsDisabled` | tinyint(1) | 否 | `0` | 是否作废/禁用:0=正常,1=禁用 | | `sEmployeeId` | varchar(100) | 是 | NULL | 关联职员 ID(跨模块引用,职员未关联时为 NULL) | | `sCreatorUsername` | varchar(100) | 是 | NULL | 制单人用户名(冗余字段,便于列表展示) | | `tLastLoginDate` | datetime | 是 | NULL | 最后登录时间 | | `iLoginFailCount` | int | 否 | `0` | 连续登录失败次数,用于防暴力破解 | | `tLockUntil` | datetime | 是 | NULL | 账号锁定截止时间,NULL 表示未锁定 | ### 索引 - `uk_usr_user_username_tenant` (UNIQUE): `(sUsername, sBrandsId)` — 用户名在同一 brand 内唯一(V2 迁移:原全局唯一改为多租户复合唯一) - `uk_usr_user_usercode` (UNIQUE): `sUserCode` — 用户号唯一约束 - `idx_usr_user_tenant` (INDEX): `sBrandsId, sSubsidiaryId` — 多租户隔离查询 - `idx_usr_user_type` (INDEX): `sUserType` — 按用户类型过滤 - `idx_usr_user_disabled` (INDEX): `bIsDisabled` — 按状态过滤 ### 外键 - 无(`sEmployeeId` 为跨模块引用,职员表由其他模块管理,当前阶段不建强约束) ### 业务注记 用户登录标识为 `sUsername`(全局唯一),`sUserCode` 为业务编号(可为工号等人类可读标识)。密码以 BCrypt 哈希存储于 `sPasswordHash`,禁止回显。`iLoginFailCount` 达到阈值(默认 5 次)时写入 `tLockUntil`(当前时间 +30 分钟),解锁后计数归零。`sEmployeeId` 软关联职员表,职员表由后续模块设计;`sCreatorUsername` 为冗余字段,记录新建时的操作人用户名。 --- ## `tStaff` — 职员维度(员工名 / 部门 / 编号) ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | | `sStaffNo` | varchar(50) | 是 | — | 职员编号;系统内唯一 | | `sStaffName` | varchar(50) | 否 | — | 职员姓名 | | `sDepartment` | varchar(100) | 是 | NULL | 所属部门(本期暂用字符串,未来如需独立 `tDepartment` 字典表再另行重构) | | `sCreatedBy` | varchar(50) | 是 | — | 制单人 | | `bDeleted` | bit(1) | 否 | 0 | 软删除标记 | | `tDeletedDate` | datetime | 是 | NULL | 软删除时间 | | `sDeletedBy` | varchar(50) | 是 | NULL | 软删除操作人 | ### 索引 - `uk_staff_no` (UNIQUE): (`sStaffNo`) - `idx_staff_name` (NORMAL): (`sStaffName`) - `idx_department` (NORMAL): (`sDepartment`) ### 外键 (无) ### 业务注记 - USR 模块通过 `tUser.iStaffId` 引用本表;REQ-USR-003 列表的「员工名 / 部门」均来自本表。 - 部门当前以字符串保存,便于本期快速落地;后续若需独立部门字典表(如审批流引用部门),改为 `iDepartmentId` 外键。 --- ## `usr_permission_group` — 权限分类/权限组定义表,每行对应一个可分配给用户的权限项 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | | `sGroupCode` | varchar(100) | 否 | — | 权限代码(如 `usr:create`、`usr:edit`),全局唯一 | | `sGroupName` | varchar(200) | 否 | — | 权限显示名称(如"新增用户"、"修改用户") | | `sCategory` | varchar(100) | 是 | NULL | 权限分类标签,用于前端权限分组展示 | ### 索引 - `uk_usr_perm_group_code` (UNIQUE): `sGroupCode` — 权限代码唯一约束 - `idx_usr_perm_group_tenant` (INDEX): `sBrandsId, sSubsidiaryId` — 多租户隔离查询 ### 外键 - 无 ### 业务注记 权限分类表存储系统内所有可分配权限项的定义,`sGroupCode` 即前端 `PermButton` 校验的权限码字符串。`sCategory` 用于将权限归组(如"用户管理"分类下含 `usr:create`、`usr:edit`、`usr:query` 等),对应前端 REQ-USR-001/002 权限组表格的"权限分类"列。 --- ## `usr_user_permission` — 用户与权限组的多对多关联表 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | | `sUserId` | varchar(100) | 否 | — | 关联 `usr_user.sId` | | `sPermGroupId` | varchar(100) | 否 | — | 关联 `usr_permission_group.sId` | ### 索引 - `uk_usr_user_perm` (UNIQUE): `sUserId, sPermGroupId` — 防止重复授权 - `idx_usr_user_perm_user` (INDEX): `sUserId` — 按用户查询其所有权限 - `idx_usr_user_perm_group` (INDEX): `sPermGroupId` — 按权限组查询持有该权限的用户 ### 外键 - `fk_usr_user_perm_user`: `sUserId` → `usr_user.sId` (ON DELETE CASCADE ON UPDATE CASCADE) - `fk_usr_user_perm_group`: `sPermGroupId` → `usr_permission_group.sId` (ON DELETE CASCADE ON UPDATE CASCADE) ### 业务注记 多对多中间表,记录每个用户持有的权限组。新增用户时(REQ-USR-001)保存权限组复选框选中项,修改用户时(REQ-USR-002)先删除该用户旧记录再批量插入新记录(replace 策略)。用户被删除或权限组被删除时,对应关联记录级联删除。 --- ## `brand` — 公司表 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | | `sName` | varchar(100) | 是 | — | 公司名称 | | `sShortName` | varchar(100) | 是 | — | 公司简称 | | `sNo` | varchar(100) | 是 | — | 单位编号(登录账号根据单位编号作为前缀) | ### 索引 - `uk_brand_no` (UNIQUE): `sNo` — 单位编号唯一约束(登录账号前缀来源,必须唯一) - `idx_brand_name` (INDEX): `sName` — 按公司名称查询 ### 外键 - 无 ### 业务注记 公司/品牌主表,记录系统内每个租户的基础信息。`sNo` 为单位编号,登录用户的账号以该编号为前缀生成(参见 `usr_user.sUsername` 的命名规则);因此 `sNo` 必须全局唯一。`sShortName` 为公司简称,用于前端列表 / 抬头等空间受限位置展示。本表为多租户体系的根表,其他业务表的 `sBrandsId` 软关联到本表 `sId`,当前阶段不建强外键约束。