# 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 关系概览 本期共 5 张业务表,分布在 USR / MOD 两个模块: - **`tUser`** 是用户账户主表,可选关联 `tStaff`(员工);与 `tPermissionCategory` 通过 `tUserPermission` 形成多对多权限授权关系。登录失败计数走 Redis,不入库。 - **`tStaff`** 是职员维度表,作为 `tUser` 的员工来源(员工名 / 部门下拉)。 - **`tPermissionCategory`** 是权限分类树(自引用 `iParentId`),由 `tUserPermission` 关联到具体用户。 - **`tUserPermission`** 是 `tUser` × `tPermissionCategory` 的关联表(多对多)。 - **`tModule`** 是 ERP 业务模块定义表(自引用 `iParentId` 形成模块树),与本期其他表无外键关系。 软删除统一使用 `bDeleted` / `tDeletedDate` / `sDeletedBy` 三件套;查询接口默认过滤 `bDeleted = 0`。 ## 表清单 - `tUser` — 系统用户账户与登录凭据 - `tStaff` — 职员维度(员工名 / 部门 / 编号) - `tPermissionCategory` — 权限分类树 - `tUserPermission` — 用户与权限分类的关联 - `tModule` — ERP 业务模块元数据树 --- ## `tUser` — 系统用户账户与登录凭据 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | | `sUserNo` | varchar(50) | 否 | — | 用户号;系统内唯一 | | `sUserName` | varchar(50) | 否 | — | 用户名(登录账号);系统内唯一 | | `iStaffId` | int | 是 | NULL | 关联职员 ID(可选,外键 → `tStaff.iIncrement`) | | `sUserType` | varchar(20) | 否 | `普通用户` | 用户类型;枚举:`普通用户` / `超级管理员` | | `sLanguage` | varchar(10) | 否 | `zh` | 语言偏好;枚举:`zh` / `en` / `zh-TW` | | `bCanModifyDocs` | tinyint(1) | 否 | 0 | 单据修改权限;0 否 / 1 是 | | `sPasswordHash` | varchar(255) | 否 | — | 密码哈希值(BCrypt 等强哈希算法),新增默认初始密码 `666666` 的哈希 | | `tLastLoginDate` | datetime | 是 | NULL | 最后登录时间 | | `sCreatedBy` | varchar(50) | 是 | — | 制单人(创建用户的操作员用户号) | | `bDeleted` | tinyint(1) | 否 | 0 | 软删除标记;0 有效 / 1 已作废 | | `tDeletedDate` | datetime | 是 | NULL | 软删除时间 | | `sDeletedBy` | varchar(50) | 是 | NULL | 软删除操作人 | ### 索引 - `uk_user_no` (UNIQUE): (`sUserNo`) - `uk_user_name` (UNIQUE): (`sUserName`) - `idx_staff_id` (NORMAL): (`iStaffId`) - `idx_brand_subsidiary` (NORMAL): (`sBrandsId`, `sSubsidiaryId`) - `idx_deleted_login` (NORMAL): (`bDeleted`, `tLastLoginDate`) ### 外键 - `fk_user_staff`: `iStaffId` → `tStaff.iIncrement` (ON DELETE SET NULL, ON UPDATE CASCADE) ### 业务注记 - 用户名 / 用户号在系统内全局唯一(含已软删除记录是否计入唯一性,需在 service 层用部分唯一索引或代码校验决定,本设计取代码校验,唯一索引仅约束未删除部分由应用层保证)。 - 密码哈希存储;登录失败次数 / 临时锁定不入库,由 Redis 维护。 - REQ-USR-003 查询接口的「作废」字段直接映射 `bDeleted`;「制单日期」即 `tCreateDate`;「制单人」即 `sCreatedBy`。 - 未关联职员的用户允许 `iStaffId = NULL`(如系统管理员账号)。 --- ## `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` | tinyint(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` 外键。 --- ## `tPermissionCategory` — 权限分类树 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | | `sCategoryCode` | varchar(50) | 否 | — | 权限分类编码;系统内唯一 | | `sCategoryName` | varchar(100) | 否 | — | 权限分类名称(界面展示) | | `iParentId` | int | 是 | NULL | 父分类 ID(自引用,根节点为 NULL) | | `iSortOrder` | int | 否 | 0 | 同级排序号 | | `sCreatedBy` | varchar(50) | 是 | — | 制单人 | | `bDeleted` | tinyint(1) | 否 | 0 | 软删除标记 | | `tDeletedDate` | datetime | 是 | NULL | 软删除时间 | | `sDeletedBy` | varchar(50) | 是 | NULL | 软删除操作人 | ### 索引 - `uk_category_code` (UNIQUE): (`sCategoryCode`) - `idx_parent` (NORMAL): (`iParentId`) ### 外键 - `fk_category_parent`: `iParentId` → `tPermissionCategory.iIncrement` (ON DELETE RESTRICT, ON UPDATE CASCADE) ### 业务注记 - REQ-USR-001 / 002 表 2「权限组 - 权限分类」下拉来源即本表(`bDeleted = 0` 过滤)。 - 自引用形成权限分类树;删除前须确保无子分类、无 `tUserPermission` 引用。 --- ## `tUserPermission` — 用户与权限分类关联 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | | `iUserId` | int | 否 | — | 关联用户 ID(外键 → `tUser.iIncrement`) | | `iCategoryId` | int | 否 | — | 关联权限分类 ID(外键 → `tPermissionCategory.iIncrement`) | | `sCreatedBy` | varchar(50) | 是 | — | 授权操作人 | ### 索引 - `uk_user_category` (UNIQUE): (`iUserId`, `iCategoryId`) - `idx_category` (NORMAL): (`iCategoryId`) ### 外键 - `fk_up_user`: `iUserId` → `tUser.iIncrement` (ON DELETE CASCADE, ON UPDATE CASCADE) - `fk_up_category`: `iCategoryId` → `tPermissionCategory.iIncrement` (ON DELETE RESTRICT, ON UPDATE CASCADE) ### 业务注记 - 关联表保留标准列以保持设计一致性,无独立软删除字段——授权撤销直接物理删除关联行(CASCADE 也会随用户删除而清理)。 - REQ-USR-001 / 002 提交时按表 2 选中行重建本表 `iUserId` 下的关联(先删后插或差异同步)。 --- ## `tModule` — ERP 业务模块元数据树 ### 字段 | 字段 | 类型 | Nullable | 默认 | 业务含义 | |---|---|---|---|---| | `iIncrement` | int | 否 | — | 整数主键 ID(标准列) | | `sId` | varchar(100) | 是 | — | 业务 ID(标准列) | | `sBrandsId` | varchar(100) | 是 | — | 品牌 ID(多租户隔离,标准列) | | `sSubsidiaryId` | varchar(100) | 是 | — | 子公司 ID(组织层级隔离,标准列) | | `tCreateDate` | datetime | 否 | — | 创建时间(标准列) | | `sDisplayType` | varchar(20) | 否 | `手机端` | 显示类型;枚举:`手机端` / `前端业务` / `系统配置` / `接口` | | `sProcedureName` | varchar(100) | 否 | — | 存储过程(审核)名称;系统内唯一 | | `sModuleType` | varchar(50) | 否 | — | 模块类型(本期按自由文本处理,VARCHAR(50);如未来收敛到枚举再加 CHECK 约束) | | `sManageDeptEn` | varchar(50) | 否 | — | 管理部门英文标识 | | `bShowPermission` | tinyint(1) | 否 | 0 | 权限是否显示;0 否 / 1 是 | | `sModuleNameZh` | varchar(100) | 否 | — | 界面名称(中文,模糊查询用) | | `iParentId` | int | 是 | NULL | 父模块 ID(自引用,根节点为 NULL) | | `iSortOrder` | int | 否 | 0 | 同级排序号 | | `sCreatedBy` | varchar(50) | 是 | — | 制单人 | | `bDeleted` | tinyint(1) | 否 | 0 | 软删除标记 | | `tDeletedDate` | datetime | 是 | NULL | 软删除时间 | | `sDeletedBy` | varchar(50) | 是 | NULL | 软删除操作人 | ### 索引 - `uk_procedure_name` (UNIQUE): (`sProcedureName`) - `idx_module_name_zh` (NORMAL): (`sModuleNameZh`) - `idx_parent` (NORMAL): (`iParentId`) - `idx_display_type` (NORMAL): (`sDisplayType`) ### 外键 - `fk_module_parent`: `iParentId` → `tModule.iIncrement` (ON DELETE RESTRICT, ON UPDATE CASCADE) ### 业务注记 - REQ-MOD-004 查询按 `sModuleNameZh` 模糊匹配(`LIKE '%关键字%'`,`bDeleted = 0` 过滤),结果按 `iParentId` 拼装树形。 - REQ-MOD-003 删除策略:仅软删除(写入 `bDeleted` / `tDeletedDate` / `sDeletedBy`);service 层先校验「无未删除子模块」「未被外部业务引用」再执行。 - `sProcedureName` 假定系统内唯一,若实际允许同名请在审阅时移除该唯一索引。