- JWT 引入 sid,单会话精确强退(sid 黑名单)与按用户踢全部(tokenVersion) - User 新增 lockedAt/lockReason,登录/刷新/守卫统一拒绝锁定 - sessions 模块:活跃会话列表 + 单会话强退;users 新增 lock/unlock/kick-sessions - 资源注册 + syncTenantResources 存量租户补齐脚本 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
267 lines
9.3 KiB
Plaintext
267 lines
9.3 KiB
Plaintext
// 通用系统管理脚手架 (sysmgr) 数据模型
|
||
// 约定:表名 sys_ 前缀;列 snake_case(模型 camelCase + @map);业务键关联(角色/资源/组织/字典/租户用 code,用户用 id)。
|
||
|
||
generator client {
|
||
provider = "prisma-client-js"
|
||
}
|
||
|
||
datasource db {
|
||
provider = "mysql"
|
||
url = env("DATABASE_URL")
|
||
}
|
||
|
||
/// 租户
|
||
model Tenant {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
code String @unique @db.VarChar(64)
|
||
name String @db.VarChar(128)
|
||
status String @default("enabled") @db.VarChar(16)
|
||
remark String? @db.VarChar(255)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
createdBy String? @map("created_by") @db.VarChar(36)
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
|
||
@@map("sys_tenant")
|
||
}
|
||
|
||
/// 用户
|
||
model User {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
username String @db.VarChar(64)
|
||
passwordHash String @map("password_hash") @db.VarChar(255)
|
||
nickname String? @db.VarChar(64)
|
||
email String? @db.VarChar(128)
|
||
phone String? @db.VarChar(32)
|
||
avatar String? @db.VarChar(255)
|
||
status String @default("enabled") @db.VarChar(16)
|
||
tokenVersion Int @default(0) @map("token_version")
|
||
lockedAt DateTime? @map("locked_at")
|
||
lockReason String? @map("lock_reason") @db.VarChar(255)
|
||
orgCode String? @map("org_code") @db.VarChar(64)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
createdBy String? @map("created_by") @db.VarChar(36)
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
@@unique([tenantCode, username])
|
||
@@index([tenantCode])
|
||
@@index([orgCode])
|
||
@@map("sys_user")
|
||
}
|
||
|
||
/// 角色
|
||
model Role {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
code String @db.VarChar(64)
|
||
name String @db.VarChar(64)
|
||
dataScope String @default("all") @map("data_scope") @db.VarChar(16)
|
||
status String @default("enabled") @db.VarChar(16)
|
||
remark String? @db.VarChar(255)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
createdBy String? @map("created_by") @db.VarChar(36)
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
@@unique([tenantCode, code])
|
||
@@index([tenantCode])
|
||
@@map("sys_role")
|
||
}
|
||
|
||
/// 资源(菜单/按钮/接口)
|
||
model Resource {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
parentCode String? @map("parent_code") @db.VarChar(64)
|
||
type String @db.VarChar(16)
|
||
code String @db.VarChar(128)
|
||
name String @db.VarChar(64)
|
||
path String? @db.VarChar(255)
|
||
component String? @db.VarChar(255)
|
||
method String? @db.VarChar(8)
|
||
apiPath String? @map("api_path") @db.VarChar(255)
|
||
icon String? @db.VarChar(64)
|
||
sort Int @default(0)
|
||
status String @default("enabled") @db.VarChar(16)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
createdBy String? @map("created_by") @db.VarChar(36)
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
@@unique([tenantCode, code])
|
||
@@index([tenantCode])
|
||
@@index([parentCode])
|
||
@@map("sys_resource")
|
||
}
|
||
|
||
/// 组织
|
||
model Org {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
parentCode String? @map("parent_code") @db.VarChar(64)
|
||
code String @db.VarChar(64)
|
||
name String @db.VarChar(64)
|
||
leader String? @db.VarChar(64)
|
||
sort Int @default(0)
|
||
status String @default("enabled") @db.VarChar(16)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
createdBy String? @map("created_by") @db.VarChar(36)
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
@@unique([tenantCode, code])
|
||
@@index([tenantCode])
|
||
@@index([parentCode])
|
||
@@map("sys_org")
|
||
}
|
||
|
||
/// 字典类型
|
||
model DictType {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
code String @db.VarChar(64)
|
||
name String @db.VarChar(64)
|
||
status String @default("enabled") @db.VarChar(16)
|
||
builtIn Boolean @default(false) @map("built_in")
|
||
remark String? @db.VarChar(255)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
createdBy String? @map("created_by") @db.VarChar(36)
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
@@unique([tenantCode, code])
|
||
@@index([tenantCode])
|
||
@@map("sys_dict_type")
|
||
}
|
||
|
||
/// 字典项
|
||
model DictItem {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
dictTypeCode String @map("dict_type_code") @db.VarChar(64)
|
||
label String @db.VarChar(64)
|
||
value String @db.VarChar(64)
|
||
sort Int @default(0)
|
||
status String @default("enabled") @db.VarChar(16)
|
||
builtIn Boolean @default(false) @map("built_in")
|
||
colorType String? @map("color_type") @db.VarChar(16)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
createdBy String? @map("created_by") @db.VarChar(36)
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
@@unique([tenantCode, dictTypeCode, value])
|
||
@@index([tenantCode, dictTypeCode])
|
||
@@map("sys_dict_item")
|
||
}
|
||
|
||
/// 参数配置
|
||
model Config {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
key String @db.VarChar(128)
|
||
value String? @db.Text
|
||
remark String? @db.VarChar(255)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
createdBy String? @map("created_by") @db.VarChar(36)
|
||
updatedAt DateTime @updatedAt @map("updated_at")
|
||
deletedAt DateTime? @map("deleted_at")
|
||
|
||
@@unique([tenantCode, key])
|
||
@@map("sys_config")
|
||
}
|
||
|
||
/// 操作日志(只增,硬删)
|
||
model AuditLog {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
userId String? @map("user_id") @db.VarChar(36)
|
||
username String? @db.VarChar(64)
|
||
module String? @db.VarChar(64)
|
||
action String? @db.VarChar(64)
|
||
method String? @db.VarChar(8)
|
||
path String? @db.VarChar(255)
|
||
params String? @db.Text
|
||
result String? @db.Text
|
||
status String? @db.VarChar(16)
|
||
errorMessage String? @map("error_message") @db.Text
|
||
ip String? @db.VarChar(64)
|
||
userAgent String? @map("user_agent") @db.VarChar(255)
|
||
durationMs Int? @map("duration_ms")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([tenantCode, createdAt])
|
||
@@map("sys_audit_log")
|
||
}
|
||
|
||
/// 登录日志(只增,硬删)
|
||
model LoginLog {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
username String? @db.VarChar(64)
|
||
ip String? @db.VarChar(64)
|
||
userAgent String? @map("user_agent") @db.VarChar(255)
|
||
status String @default("success") @db.VarChar(16)
|
||
message String? @db.VarChar(255)
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([tenantCode, createdAt])
|
||
@@map("sys_login_log")
|
||
}
|
||
|
||
/// 刷新令牌(会话载体,硬删)
|
||
model RefreshToken {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
userId String @map("user_id") @db.VarChar(36)
|
||
sid String? @db.VarChar(36)
|
||
jti String @unique @db.VarChar(64)
|
||
tokenHash String @map("token_hash") @db.VarChar(255)
|
||
ip String? @db.VarChar(64)
|
||
userAgent String? @map("user_agent") @db.VarChar(255)
|
||
loginAt DateTime @default(now()) @map("login_at")
|
||
expireAt DateTime @map("expire_at")
|
||
revokedAt DateTime? @map("revoked_at")
|
||
createdAt DateTime @default(now()) @map("created_at")
|
||
|
||
@@index([tenantCode, userId])
|
||
@@index([sid])
|
||
@@map("sys_refresh_token")
|
||
}
|
||
|
||
/// 用户-角色关联
|
||
model UserRole {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
userId String @map("user_id") @db.VarChar(36)
|
||
roleCode String @map("role_code") @db.VarChar(64)
|
||
|
||
@@unique([tenantCode, userId, roleCode])
|
||
@@index([tenantCode, userId])
|
||
@@map("sys_user_role")
|
||
}
|
||
|
||
/// 角色-资源关联
|
||
model RoleResource {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
roleCode String @map("role_code") @db.VarChar(64)
|
||
resourceCode String @map("resource_code") @db.VarChar(128)
|
||
|
||
@@unique([tenantCode, roleCode, resourceCode])
|
||
@@index([tenantCode, roleCode])
|
||
@@map("sys_role_resource")
|
||
}
|
||
|
||
/// 角色-组织关联(数据权限「自定义」)
|
||
model RoleOrg {
|
||
id String @id @default(uuid(7)) @db.VarChar(36)
|
||
tenantCode String @map("tenant_code") @db.VarChar(64)
|
||
roleCode String @map("role_code") @db.VarChar(64)
|
||
orgCode String @map("org_code") @db.VarChar(64)
|
||
|
||
@@unique([tenantCode, roleCode, orgCode])
|
||
@@map("sys_role_org")
|
||
}
|