Files
makemd/docs/用户层级架构差异分析.md

384 lines
15 KiB
Markdown
Raw Normal View History

# 用户层级架构文档与实际代码差异分析
> **分析日期**: 2026-03-29
> **文档版本**: 用户层级架构说明.md v1.1
> **代码版本**: server/src
---
## 1. 表名差异
| 文档中的表名 | 实际代码中的表名 | 说明 |
|-------------|----------------|------|
| `cf_users` | `cf_user` | 复数/单数差异 |
| `cf_tenants` | `cf_tenant` | 复数/单数差异 |
| `cf_departments` | `cf_department` | 复数/单数差异 |
| `cf_role_permissions` | `cf_role_permission` | 复数/单数差异 |
| `cf_shop_auth` | **不存在** | 文档中提到但代码中未实现 |
---
## 2. 用户表 (`cf_user`) 差异
### 文档中的字段
```sql
id VARCHAR(36) PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(20) DEFAULT 'OPERATOR',
tenant_id VARCHAR(36) NOT NULL,
dept_id VARCHAR(36),
status ENUM('active', 'inactive', 'suspended') DEFAULT 'active',
last_login_at TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
```
### 实际代码中的字段
```sql
id VARCHAR(36) PRIMARY KEY,
tenant_id VARCHAR(36) NOT NULL,
username VARCHAR(64) NOT NULL UNIQUE,
email VARCHAR(128) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
full_name VARCHAR(128) NOT NULL,
phone VARCHAR(32),
status ENUM('ACTIVE', 'INACTIVE', 'LOCKED') DEFAULT 'ACTIVE'),
role ENUM('ADMIN', 'MANAGER', 'OPERATOR', 'FINANCE', 'SOURCING', 'LOGISTICS', 'ANALYST') NOT NULL,
is_superadmin BOOLEAN DEFAULT FALSE,
last_login_by VARCHAR(36),
last_login_at TIMESTAMP,
created_by VARCHAR(36) NOT NULL,
updated_by VARCHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
```
### 差异点
| 字段 | 文档 | 实际代码 | 差异说明 |
|------|------|---------|---------|
| `username` | VARCHAR(50) | VARCHAR(64) | 长度不同 |
| `email` | VARCHAR(100) | VARCHAR(128) | 长度不同 |
| `dept_id` | ✅ 存在 | ❌ 不存在 | 实际代码中没有部门ID字段 |
| `full_name` | ❌ 不存在 | ✅ 存在 | 实际代码中有全名字段 |
| `phone` | ❌ 不存在 | ✅ 存在 | 实际代码中有电话字段 |
| `is_superadmin` | ❌ 不存在 | ✅ 存在 | 实际代码中有超级管理员标识 |
| `created_by` | ❌ 不存在 | ✅ 存在 | 实际代码中有创建人字段 |
| `updated_by` | ❌ 不存在 | ✅ 存在 | 实际代码中有更新人字段 |
| `status` | 小写枚举 | 大写枚举 | 命名风格不同 |
| `role` | 字符串 | 枚举类型 | 类型定义不同 |
---
## 3. 租户表 (`cf_tenant`) 差异
### 文档中的字段
```sql
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(100) NOT NULL,
type ENUM('SAAS', 'ENTERPRISE', 'TRIAL') DEFAULT 'SAAS',
status ENUM('ACTIVE', 'SUSPENDED', 'CANCELLED') DEFAULT 'ACTIVE',
plan_id VARCHAR(36),
quota_config JSON,
settings JSON,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
```
### 实际代码中的字段
```sql
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(128) NOT NULL UNIQUE,
domain VARCHAR(128) NOT NULL UNIQUE,
contact_name VARCHAR(64) NOT NULL,
contact_email VARCHAR(128) NOT NULL UNIQUE,
contact_phone VARCHAR(32) NOT NULL,
address VARCHAR(255) NOT NULL,
status ENUM('ACTIVE', 'INACTIVE', 'SUSPENDED') DEFAULT 'ACTIVE'),
quota_limit DECIMAL(10, 2) DEFAULT 10000,
quota_used DECIMAL(10, 2) DEFAULT 0,
created_by VARCHAR(36) NOT NULL,
updated_by VARCHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
```
### 差异点
| 字段 | 文档 | 实际代码 | 差异说明 |
|------|------|---------|---------|
| `name` | VARCHAR(100) | VARCHAR(128) | 长度不同 |
| `type` | ✅ 存在 | ❌ 不存在 | 实际代码中没有租户类型字段 |
| `plan_id` | ✅ 存在 | ❌ 不存在 | 实际代码中没有套餐ID字段 |
| `quota_config` | ✅ 存在 | ❌ 不存在 | 实际代码中没有JSON配置字段 |
| `settings` | ✅ 存在 | ❌ 不存在 | 实际代码中没有JSON设置字段 |
| `domain` | ❌ 不存在 | ✅ 存在 | 实际代码中有域名字段 |
| `contact_name` | ❌ 不存在 | ✅ 存在 | 实际代码中有联系人姓名字段 |
| `contact_email` | ❌ 不存在 | ✅ 存在 | 实际代码中有联系人邮箱字段 |
| `contact_phone` | ❌ 不存在 | ✅ 存在 | 实际代码中有联系人电话字段 |
| `address` | ❌ 不存在 | ✅ 存在 | 实际代码中有地址字段 |
| `quota_limit` | ❌ 不存在 | ✅ 存在 | 实际代码中有配额限制字段 |
| `quota_used` | ❌ 不存在 | ✅ 存在 | 实际代码中有已用配额字段 |
| `created_by` | ❌ 不存在 | ✅ 存在 | 实际代码中有创建人字段 |
| `updated_by` | ❌ 不存在 | ✅ 存在 | 实际代码中有更新人字段 |
---
## 4. 部门表 (`cf_department`) 差异
### 文档中的字段
```sql
id VARCHAR(36) PRIMARY KEY,
tenant_id VARCHAR(36) NOT NULL,
parent_id VARCHAR(36),
name VARCHAR(100) NOT NULL,
manager_id VARCHAR(36),
path VARCHAR(500),
depth INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (tenant_id) REFERENCES cf_tenants(id),
INDEX idx_tenant_path (tenant_id, path)
```
### 实际代码中的字段HierarchyService.ts中定义
```sql
id VARCHAR(36) PRIMARY KEY,
tenant_id VARCHAR(36) NOT NULL,
name VARCHAR(128) NOT NULL,
parent_id VARCHAR(36),
path VARCHAR(500),
depth INT DEFAULT 0,
manager_id VARCHAR(36),
status ENUM('ACTIVE', 'INACTIVE') DEFAULT 'ACTIVE',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
```
### 差异点
| 字段 | 文档 | 实际代码 | 差异说明 |
|------|------|---------|---------|
| `name` | VARCHAR(100) | VARCHAR(128) | 长度不同 |
| `status` | ❌ 不存在 | ✅ 存在 | 实际代码中有状态字段 |
| `updated_at` | ❌ 不存在 | ✅ 存在 | 实际代码中有更新时间字段 |
---
## 5. 角色权限表 (`cf_role_permission`) 差异
### 文档中的字段
```sql
id VARCHAR(36) PRIMARY KEY,
role_key VARCHAR(50) NOT NULL,
permission_key VARCHAR(100) NOT NULL,
tenant_id VARCHAR(36),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_role_perm (role_key, permission_key, tenant_id)
```
### 实际代码中的字段
```sql
id VARCHAR(36) PRIMARY KEY,
role_id VARCHAR(36) NOT NULL,
permission_id VARCHAR(36) NOT NULL,
created_by VARCHAR(36) NOT NULL,
updated_by VARCHAR(36) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uk_role_perm (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES cf_role(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES cf_permission(id) ON DELETE CASCADE
```
### 差异点
| 字段 | 文档 | 实际代码 | 差异说明 |
|------|------|---------|---------|
| `role_key` | ✅ 存在 | ❌ 不存在 | 实际代码中是`role_id` |
| `permission_key` | ✅ 存在 | ❌ 不存在 | 实际代码中是`permission_id` |
| `tenant_id` | ✅ 存在 | ❌ 不存在 | 实际代码中没有租户ID字段 |
| `created_by` | ❌ 不存在 | ✅ 存在 | 实际代码中有创建人字段 |
| `updated_by` | ❌ 不存在 | ✅ 存在 | 实际代码中有更新人字段 |
| `updated_at` | ❌ 不存在 | ✅ 存在 | 实际代码中有更新时间字段 |
---
## 6. 数据范围类型差异
### 文档中的数据范围类型
| 类型 | 说明 | SQL过滤条件 | 适用角色 |
|------|------|------------|---------|
| **SELF** | 只看自己创建的数据 | `WHERE created_by = {userId}` | 普通员工 |
| **TEAM** | 看自己组的数据 | `WHERE team_id IN ({userTeams})` | 组长 |
| **DEPT** | 看自己部门的数据 | `WHERE dept_id IN ({userDepts})` | 部门主管 |
| **ORG** | 看整个公司的数据 | `WHERE tenant_id = {tenantId}` | 高管 |
| **ALL** | 全平台数据(超管) | 无过滤 | 系统管理员 |
### 实际代码中的数据范围类型RBACEngine.ts
```typescript
export interface DataScope {
type: 'ALL' | 'ORG' | 'DEPT' | 'SHOP' | 'OWN';
departmentId?: string;
shopId?: string;
}
```
### 差异点
| 文档类型 | 实际代码类型 | 差异说明 |
|----------|-------------|---------|
| **SELF** | **OWN** | 实际代码中是`OWN`而不是`SELF` |
| **TEAM** | **SHOP** | 实际代码中是`SHOP`而不是`TEAM` |
| **DEPT** | **DEPT** | 一致 |
| **ORG** | **ORG** | 一致 |
| **ALL** | **ALL** | 一致 |
---
## 7. 服务实现差异
### DataScopeService
- **文档中**: 提到`DataScopeService`类,包含`getUserDataScope``applyDataScope`方法
- **实际代码**: 不存在`DataScopeService`
- **实际实现**: 数据隔离功能通过`DataIsolationService`实现
### HierarchyService
- **文档中的方法签名**:
```typescript
static async getUserHierarchyPath(userId: string): Promise<string[]>;
static async getSubDepartments(deptId: string): Promise<Department[]>;
static async getDepartmentUsers(deptId: string): Promise<User[]>;
static async transferUser(userId: string, targetDeptId: string): Promise<void>;
static async getDepartmentStats(deptId: string): Promise<DeptStats>;
```
- **实际代码中的方法**:
```typescript
static async initializeTenantHierarchy(tenantId: string): Promise<void>;
static async createDepartment(tenantId: string, name: string, parentId?: string): Promise<Department>;
static async updateDepartment(deptId: string, updates: Partial<Department>): Promise<void>;
static async deleteDepartment(deptId: string): Promise<void>;
static async getDepartmentTree(tenantId: string): Promise<HierarchyNode[]>;
static async getDepartmentStats(deptId: string): Promise<HierarchyStats>;
static async transferUser(userId: string, targetDeptId: string): Promise<void>;
static async createShop(tenantId: string, deptId: string, shopData: Partial<Shop>): Promise<Shop>;
static async updateShop(shopId: string, updates: Partial<Shop>): Promise<void>;
static async deleteShop(shopId: string): Promise<void>;
static async getShopTree(tenantId: string): Promise<HierarchyNode[]>;
static async assignUserToShop(userId: string, shopId: string): Promise<void>;
static async removeUserFromShop(userId: string): Promise<void>;
```
### AuthService
- **文档中的方法签名**:
```typescript
static async login(credentials: LoginCredentials): Promise<AuthResult>;
static async verifyToken(token: string): Promise<TokenPayload>;
static async refreshToken(refreshToken: string): Promise<AuthResult>;
static async logout(userId: string): Promise<void>;
```
- **实际代码中的方法**:
```typescript
static async login(input: LoginInput): Promise<LoginResult>;
static async register(input: RegisterInput): Promise<RegisterResult>;
static async passwordReset(input: PasswordResetInput): Promise<PasswordResetResult>;
static async checkPermission(input: PermissionCheckInput): Promise<PermissionCheckResult>;
static async getUserPermissions(input: UserPermissionsInput): Promise<UserPermissionsResult>;
static async assignRole(input: AssignRoleInput): Promise<boolean>;
static async removeRole(input: RemoveRoleInput): Promise<boolean>;
```
---
## 8. 权限点设计差异
### 文档中的权限点命名规范
```typescript
const PERMISSIONS = {
'product:read': '查看商品',
'product:create': '创建商品',
'product:update': '更新商品',
'product:delete': '删除商品',
'product:export': '导出商品',
'product:import': '导入商品',
// ... 其他权限
};
```
### 实际代码中的权限点RBACEngine.ts
```typescript
const PERMISSIONS: Permission[] = [
{ id: 'admin:all', name: '超级管理员', description: '拥有所有系统权限', module: 'SYSTEM', action: 'EXECUTE' },
{ id: 'product:read', name: '查看商品', description: '允许查看商品列表与详情', module: 'PRODUCT', action: 'READ' },
{ id: 'product:write', name: '编辑商品', description: '允许创建和修改商品信息', module: 'PRODUCT', action: 'WRITE' },
{ id: 'product:delete', name: '删除商品', description: '允许删除商品', module: 'PRODUCT', action: 'DELETE' },
{ id: 'product:publish', name: '发布商品', description: '允许执行商品刊登任务', module: 'PRODUCT', action: 'EXECUTE' },
{ id: 'product:score', name: '商品评分', description: '允许查看AI选品评分', module: 'PRODUCT', action: 'READ' },
{ id: 'order:read', name: '查看订单', description: '允许查看销售订单', module: 'ORDER', action: 'READ' },
{ id: 'order:write', name: '创建订单', description: '允许创建订单', module: 'ORDER', action: 'WRITE' },
{ id: 'order:cancel', name: '取消订单', description: '允许取消订单', module: 'ORDER', action: 'EXECUTE' },
{ id: 'order:refund', name: '退款处理', description: '允许处理退款', module: 'ORDER', action: 'EXECUTE' },
// ... 更多权限
];
```
### 差异点
| 差异 | 说明 |
|------|------|
| **权限结构** | 实际代码使用`Permission`对象数组包含id、name、description、module、action字段 |
| **模块划分** | 实际代码按模块划分PRODUCT、ORDER、INVENTORY、FINANCE、ADVERTISING、SOURCING、LOGISTICS、AI、COLLECTION、USER、TENANT、AUDIT |
| **操作类型** | 实际代码使用READ、WRITE、DELETE、EXECUTE四种操作类型 |
| **权限数量** | 实际代码中定义了50+个权限点,比文档中更详细 |
---
## 9. 建议修正
### 9.1 表名统一
建议将文档中的表名统一为实际代码中的单数形式:
- `cf_users``cf_user`
- `cf_tenants``cf_tenant`
- `cf_departments``cf_department`
- `cf_role_permissions``cf_role_permission`
### 9.2 字段定义更新
建议更新文档中的字段定义,与实际代码保持一致:
- 添加缺失的字段(如`full_name``phone``is_superadmin`等)
- 删除不存在的字段(如`dept_id``type``plan_id`等)
- 更新字段类型和长度(如`username`从VARCHAR(50)改为VARCHAR(64)
### 9.3 数据范围类型更新
建议将文档中的数据范围类型更新为实际代码中的定义:
- `SELF``OWN`
- `TEAM``SHOP`
- 保持`DEPT``ORG``ALL`不变
### 9.4 服务方法签名更新
建议更新文档中的服务方法签名,与实际代码保持一致:
- `HierarchyService`方法签名更新
- `AuthService`方法签名更新
- 删除不存在的`DataScopeService`引用
### 9.5 权限点设计更新
建议更新文档中的权限点设计与实际代码中的RBACEngine保持一致
- 使用`Permission`对象结构
- 按模块划分权限
- 使用READ、WRITE、DELETE、EXECUTE操作类型
### 9.6 店铺授权表
建议删除文档中关于`cf_shop_auth`表的描述,因为实际代码中不存在此表。
---
## 10. 总结
| 差异类型 | 数量 | 严重程度 |
|----------|------|---------|
| 表名不一致 | 5 | 🟡 中等 |
| 字段缺失 | 15+ | 🔴 严重 |
| 字段类型不一致 | 8 | 🟡 中等 |
| 数据范围类型不一致 | 2 | 🟡 中等 |
| 服务方法签名不一致 | 3 | 🟡 中等 |
| 权限点设计不一致 | 1 | 🟡 中等 |
**总体评估**: 文档与实际代码存在较多差异,建议尽快更新文档以保持一致性。