1210 lines
24 KiB
Markdown
1210 lines
24 KiB
Markdown
# 通用中后台底座平台建设规划
|
||
|
||
## 1. 系统定位
|
||
|
||
本系统定位为一个通用中后台基础框架。
|
||
|
||
本框架只提供中后台常用基础能力,不绑定任何具体业务。它的职责是提供稳定、轻量、现代的管理端基础设施,便于后续在同一工程内按需扩展页面、接口和基础模块。
|
||
|
||
本次设计只包含:
|
||
|
||
- 前端通用框架
|
||
- 后端通用框架
|
||
- 用户、组织、角色、菜单、权限、字典、日志等基础模块
|
||
|
||
本次不包含:
|
||
|
||
- 任何具体业务模块
|
||
- 旧 Vue 页面兼容
|
||
- 接口文档平台
|
||
- 多语言
|
||
- 微前端
|
||
|
||
## 2. 建设目标
|
||
|
||
核心目标:
|
||
|
||
- UI 现代、极简、高级。
|
||
- 前端轻便快速,交互顺滑,首屏和页面切换速度快。
|
||
- 后端结构清晰,接口稳定,权限和日志能力完善。
|
||
- 项目可以快速获得稳定的中后台基础能力。
|
||
- 新页面开发路径固定、清晰、可复制。
|
||
- 代码可读性优先,避免过度封装和框架魔法。
|
||
|
||
设计原则:
|
||
|
||
- 只做底座,不预设业务。
|
||
- 组件库负责基础 UI,不自研复杂 UI 框架。
|
||
- 权限、菜单、字典、日志做成通用能力。
|
||
- 数据查询、缓存、分页、错误处理形成统一模式。
|
||
- 前后端边界清晰,前端不承载安全规则,后端必须做权限校验。
|
||
|
||
## 3. 技术栈
|
||
|
||
### 3.1 前端技术栈
|
||
|
||
推荐技术栈:
|
||
|
||
- Vue 3
|
||
- TypeScript
|
||
- Vite
|
||
- Vue Router
|
||
- Pinia
|
||
- TanStack Query
|
||
- Naive UI
|
||
- Tailwind CSS
|
||
- lucide-vue-next
|
||
- Axios
|
||
- VueUse
|
||
- Vitest
|
||
- Playwright
|
||
- ESLint
|
||
- Prettier
|
||
|
||
说明:
|
||
|
||
- Vue 3 使用 `<script setup lang="ts">` 和 Composition API。
|
||
- Pinia 只负责全局状态,不承载页面列表数据。
|
||
- TanStack Query 负责服务端状态、缓存、刷新、分页、错误重试。
|
||
- Naive UI 负责基础组件,不额外建设复杂主题系统。
|
||
- Tailwind CSS 负责布局、间距、响应式和少量自定义样式。
|
||
- lucide-vue-next 统一图标风格。
|
||
- 系统只使用中文,不做多语言。
|
||
|
||
### 3.2 后端技术栈
|
||
|
||
推荐技术栈:
|
||
|
||
- Kotlin
|
||
- Ktor
|
||
- kotlinx.serialization
|
||
- Exposed
|
||
- HikariCP
|
||
- JWT
|
||
- Logback
|
||
- PostgreSQL
|
||
- Redis
|
||
- Docker Compose
|
||
|
||
说明:
|
||
|
||
- Ktor 负责 HTTP 服务、认证、路由、异常处理。
|
||
- kotlinx.serialization 作为 JSON 序列化方案。
|
||
- Exposed 作为数据库访问层。
|
||
- HikariCP 作为数据库连接池。
|
||
- JWT 作为前后端认证令牌。
|
||
- Logback 输出系统运行日志。
|
||
- PostgreSQL 作为默认关系型数据库。
|
||
- Redis 作为缓存、验证码、临时会话、限流等基础设施。
|
||
- PostgreSQL、Redis 等配套组件统一用根目录 `docker-compose.yml` 管理。
|
||
|
||
## 4. 总体架构
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Web["Vue3 管理端"]
|
||
Api["Ktor API Server"]
|
||
DB["PostgreSQL"]
|
||
Cache["Redis"]
|
||
|
||
Web -->|"HTTP API / JWT"| Api
|
||
Api -->|"Exposed / HikariCP"| DB
|
||
Api -->|"Redisson"| Cache
|
||
```
|
||
|
||
本框架分为两部分:
|
||
|
||
- `web`:前端管理端。
|
||
- `server`:后端 API 服务。
|
||
|
||
前端负责:
|
||
|
||
- 登录页
|
||
- 主布局
|
||
- 动态菜单
|
||
- 路由守卫
|
||
- 页面渲染
|
||
- 表格、表单、弹窗等交互
|
||
- 查询缓存和请求状态管理
|
||
- 按钮级权限展示控制
|
||
|
||
后端负责:
|
||
|
||
- 登录认证
|
||
- JWT 签发与校验
|
||
- 用户管理
|
||
- 组织管理
|
||
- 角色管理
|
||
- 菜单管理
|
||
- 权限校验
|
||
- 字典管理
|
||
- 操作日志
|
||
- 开放接口调用日志
|
||
- 系统异常日志
|
||
- PostgreSQL 连接池
|
||
- Redis 客户端
|
||
|
||
## 5. 工程结构
|
||
|
||
建议采用前后端同仓库:
|
||
|
||
```text
|
||
platform-a/
|
||
docker-compose.yml
|
||
web/
|
||
server/
|
||
```
|
||
|
||
不建议一期引入复杂 monorepo。底座平台先保持清晰、直接、容易部署。
|
||
|
||
配套组件统一放在项目根目录 `docker-compose.yml`:
|
||
|
||
```text
|
||
docker-compose.yml
|
||
postgres: PostgreSQL 18.3
|
||
redis: Redis 8
|
||
```
|
||
|
||
本地开发默认连接:
|
||
|
||
```text
|
||
PostgreSQL:
|
||
host: localhost
|
||
port: 5432
|
||
database: platform_a
|
||
user: platform_a
|
||
password: platform_a_password
|
||
|
||
Redis:
|
||
host: localhost
|
||
port: 6379
|
||
password: platform_a_redis_password
|
||
```
|
||
|
||
启动配套组件:
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
停止配套组件:
|
||
|
||
```bash
|
||
docker compose down
|
||
```
|
||
|
||
如果需要清空本地数据,再执行:
|
||
|
||
```bash
|
||
docker compose down -v
|
||
```
|
||
|
||
## 6. 前端架构设计
|
||
|
||
### 6.1 前端组织原则
|
||
|
||
前端按功能组织页面,不在文档中写死完整目录结构。目录和文件根据实际复杂度创建,避免为了满足规范而产生空目录、空文件。
|
||
|
||
基础原则:
|
||
|
||
- 页面按功能组织。
|
||
- 共享组件放在全局 `components` 目录。
|
||
- 页面私有组件、组合逻辑、类型定义放在页面目录内。
|
||
- 路由、状态、请求、布局、样式等基础能力保持清晰边界。
|
||
- 简单页面可以只保留一个页面文件,复杂页面再拆分私有组件和逻辑。
|
||
|
||
### 6.2 页面组织规则
|
||
|
||
页面组织以可读性为准,不强制固定文件数量。
|
||
|
||
建议规则:
|
||
|
||
- 页面入口负责结构和主要交互。
|
||
- 页面私有逻辑只服务当前页面时,放在页面目录内。
|
||
- 多页面复用的组件、工具、类型再上提到共享目录。
|
||
- 表格列、搜索条件、弹窗状态等页面强相关内容优先靠近页面。
|
||
|
||
### 6.3 路由设计
|
||
|
||
路由分为静态路由和动态路由。
|
||
|
||
静态路由:
|
||
|
||
- `/login`
|
||
- `/403`
|
||
- `/404`
|
||
- `/`
|
||
|
||
动态路由:
|
||
|
||
- 登录后从后端获取菜单。
|
||
- 前端根据菜单里的 `component` 字段加载页面。
|
||
- 菜单变化后,用户重新登录或刷新权限即可生效。
|
||
|
||
后端菜单返回示例:
|
||
|
||
```json
|
||
{
|
||
"id": "1001",
|
||
"parentId": null,
|
||
"type": "MENU",
|
||
"path": "/system/users",
|
||
"name": "SystemUsers",
|
||
"component": "system/users/index",
|
||
"title": "用户管理",
|
||
"icon": "Users",
|
||
"permission": "system:user:view",
|
||
"sort": 10,
|
||
"visible": true,
|
||
"keepAlive": true
|
||
}
|
||
```
|
||
|
||
前端页面加载:
|
||
|
||
```ts
|
||
const viewModules = import.meta.glob('../features/**/index.vue')
|
||
```
|
||
|
||
组件路径规则:
|
||
|
||
```text
|
||
system/users/index -> src/features/system/users/index.vue
|
||
```
|
||
|
||
SPA 页面需要支持页签栏和页面缓存:
|
||
|
||
- 后台主体使用单页应用模式,页面切换不整页刷新。
|
||
- 已打开页面进入页签栏,支持切换、关闭、刷新当前页签。
|
||
- 菜单配置中的 `keepAlive` 控制页面是否缓存。
|
||
- 页面缓存需要和动态路由、权限刷新配合,用户权限变化后应清理不可访问页面。
|
||
- 列表查询数据仍由 TanStack Query 管理,页签缓存主要保留页面组件状态和表单状态。
|
||
|
||
### 6.4 Pinia 状态边界
|
||
|
||
Pinia 只保存全局状态:
|
||
|
||
- 当前 token
|
||
- 当前用户
|
||
- 用户权限码
|
||
- 用户菜单树
|
||
- 当前布局状态
|
||
- 字典缓存
|
||
|
||
不建议放入 Pinia:
|
||
|
||
- 表格列表数据
|
||
- 分页数据
|
||
- 搜索条件
|
||
- 表单弹窗状态
|
||
- 详情数据
|
||
|
||
这些服务端状态统一交给 TanStack Query 管理。
|
||
|
||
### 6.5 TanStack Query 使用规则
|
||
|
||
TanStack Query 用于:
|
||
|
||
- 列表查询
|
||
- 详情查询
|
||
- 字典查询
|
||
- 新增、修改、删除后的缓存刷新
|
||
- 后台刷新
|
||
- 请求错误状态
|
||
- 加载状态
|
||
|
||
建议封装统一 query key:
|
||
|
||
```ts
|
||
export const userKeys = {
|
||
all: ['system', 'users'] as const,
|
||
list: (params: UserQuery) => [...userKeys.all, 'list', params] as const,
|
||
detail: (id: string) => [...userKeys.all, 'detail', id] as const,
|
||
}
|
||
```
|
||
|
||
Mutation 成功后按模块刷新:
|
||
|
||
```ts
|
||
queryClient.invalidateQueries({ queryKey: userKeys.all })
|
||
```
|
||
|
||
### 6.6 HTTP 请求封装
|
||
|
||
统一响应格式:
|
||
|
||
```ts
|
||
export interface ApiResult<T> {
|
||
code: string
|
||
message: string
|
||
data: T
|
||
traceId?: string
|
||
}
|
||
```
|
||
|
||
分页格式:
|
||
|
||
```ts
|
||
export interface PageResult<T> {
|
||
items: T[]
|
||
page: number
|
||
pageSize: number
|
||
total: number
|
||
}
|
||
```
|
||
|
||
HTTP 层职责:
|
||
|
||
- 自动附加 JWT。
|
||
- 处理 401 并跳转登录页。
|
||
- 处理 403 并提示无权限。
|
||
- 统一处理业务错误。
|
||
- 记录 `traceId`。
|
||
|
||
### 6.7 权限控制
|
||
|
||
前端提供三种权限控制:
|
||
|
||
1. 路由权限:无菜单权限不能进入页面。
|
||
2. 按钮权限:无操作权限不显示按钮。
|
||
3. 组件权限:复杂页面局部区域可按权限隐藏。
|
||
|
||
按钮示例:
|
||
|
||
```vue
|
||
<PermissionButton permission="system:user:create">
|
||
新增用户
|
||
</PermissionButton>
|
||
```
|
||
|
||
前端权限只负责体验,后端接口必须再次校验权限。
|
||
|
||
### 6.8 UI 风格
|
||
|
||
整体风格:
|
||
|
||
- 现代
|
||
- 极简
|
||
- 高级
|
||
- 工作台
|
||
- 信息密度适中
|
||
- 视觉安静
|
||
|
||
布局建议:
|
||
|
||
- 左侧导航栏
|
||
- 顶部操作栏
|
||
- 面包屑
|
||
- 页签栏
|
||
- 内容区使用浅灰背景
|
||
- 页面主体使用白色内容面板
|
||
|
||
视觉规范:
|
||
|
||
- 不做花哨渐变背景。
|
||
- 不做厚重阴影。
|
||
- 不做复杂主题编辑器。
|
||
- 卡片只用于真正需要分组的信息。
|
||
- 表格页筛选区要轻,不做大面积表单堆叠。
|
||
- 图标统一使用 lucide-vue-next。
|
||
- 中文字体默认使用系统字体。
|
||
|
||
推荐 Tailwind 基础风格:
|
||
|
||
```css
|
||
body {
|
||
@apply bg-slate-50 text-slate-950 antialiased;
|
||
}
|
||
```
|
||
|
||
推荐主题变量:
|
||
|
||
```css
|
||
:root {
|
||
--app-bg: #f8fafc;
|
||
--app-surface: #ffffff;
|
||
--app-border: #e2e8f0;
|
||
--app-text: #0f172a;
|
||
--app-muted: #64748b;
|
||
--app-primary: #2563eb;
|
||
--app-success: #16a34a;
|
||
--app-warning: #d97706;
|
||
--app-danger: #dc2626;
|
||
}
|
||
```
|
||
|
||
### 6.9 Naive UI 主题
|
||
|
||
Naive UI 通过 `NConfigProvider` 统一配置:
|
||
|
||
- primary color
|
||
- border radius
|
||
- font family
|
||
- component size
|
||
- message provider
|
||
- dialog provider
|
||
- notification provider
|
||
|
||
建议默认尺寸:
|
||
|
||
- 表格:`small`
|
||
- 表单:`medium`
|
||
- 按钮:`medium`
|
||
- 弹窗:保持紧凑
|
||
|
||
### 6.10 前端基础页面
|
||
|
||
一期前端页面:
|
||
|
||
- 登录
|
||
- 工作台首页
|
||
- 用户管理
|
||
- 组织管理
|
||
- 角色管理
|
||
- 菜单管理
|
||
- 字典管理
|
||
- 操作日志
|
||
- 开放接口调用日志
|
||
|
||
## 7. 后端架构设计
|
||
|
||
### 7.1 后端目录结构
|
||
|
||
当前 `server` 已经按基础框架骨架整理为:
|
||
|
||
```text
|
||
server/
|
||
src/main/kotlin/com/bbit/platform/
|
||
Application.kt
|
||
common/
|
||
ApiResult.kt
|
||
BizException.kt
|
||
config/
|
||
AppConfig.kt
|
||
database/
|
||
system/
|
||
SysUserTable.kt
|
||
SysOrgTable.kt
|
||
SysRoleTable.kt
|
||
SysMenuTable.kt
|
||
SysUserRoleTable.kt
|
||
SysRoleMenuTable.kt
|
||
SysDictTypeTable.kt
|
||
SysDictItemTable.kt
|
||
SysOperationLogTable.kt
|
||
SysApiAccessLogTable.kt
|
||
business/
|
||
plugins/
|
||
CorsPlugin.kt
|
||
DatabasePlugin.kt
|
||
LoggingPlugin.kt
|
||
RedisPlugin.kt
|
||
SecurityPlugin.kt
|
||
SerializationPlugin.kt
|
||
StatusPagesPlugin.kt
|
||
```
|
||
|
||
当前结构说明:
|
||
|
||
- `Application.kt` 负责应用启动和插件装配。
|
||
- `common` 放统一响应、业务异常等公共模型。
|
||
- `config` 放应用配置读取。
|
||
- `plugins` 放 Ktor 插件和基础设施配置,数据库连接与 `dbQuery` 当前也放在 `DatabasePlugin.kt`。
|
||
- `database/system` 放系统基础表定义。
|
||
- `database/business` 预留给后续具体功能表,不在底座阶段预设业务表。
|
||
|
||
后续只补必要目录,保持结构直接、清晰:
|
||
|
||
```text
|
||
server/
|
||
src/main/kotlin/com/bbit/platform/
|
||
common/
|
||
PageResult.kt
|
||
PageQuery.kt
|
||
ErrorCode.kt
|
||
TraceContext.kt
|
||
security/
|
||
JwtService.kt
|
||
PasswordService.kt
|
||
PermissionService.kt
|
||
SecurityPrincipal.kt
|
||
RequirePermission.kt
|
||
bootstrap/
|
||
DatabaseInitializer.kt
|
||
SeedData.kt
|
||
modules/
|
||
auth/
|
||
system/
|
||
user/
|
||
org/
|
||
role/
|
||
menu/
|
||
dict/
|
||
logs/
|
||
operation/
|
||
apiaccess/
|
||
```
|
||
|
||
模块目录内部按需拆分 `Routes`、`Service`、`Dtos`,不提前创建空文件。
|
||
|
||
### 7.2 当前默认配置
|
||
|
||
当前 `server/src/main/resources/application.yaml` 只保留底座需要的配置:
|
||
|
||
```yaml
|
||
ktor:
|
||
application:
|
||
modules:
|
||
- com.bbit.platform.ApplicationKt.module
|
||
deployment:
|
||
port: 8080
|
||
|
||
app:
|
||
name: "Platform A"
|
||
env: "local"
|
||
|
||
database:
|
||
url: "jdbc:postgresql://localhost:5432/platform_a"
|
||
user: "platform_a"
|
||
password: "platform_a_password"
|
||
maximumPoolSize: 16
|
||
minimumIdle: 4
|
||
|
||
redis:
|
||
url: "redis://127.0.0.1:6379"
|
||
password: "platform_a_redis_password"
|
||
|
||
security:
|
||
jwt:
|
||
issuer: "platform-a"
|
||
audience: "platform-a-admin"
|
||
realm: "Platform A"
|
||
secret: "change-me-to-a-strong-secret"
|
||
accessTokenTtlMinutes: 120
|
||
|
||
cors:
|
||
allowedHosts: "localhost:5173,127.0.0.1:5173"
|
||
```
|
||
|
||
已经移除的非底座配置:
|
||
|
||
- 邮件 SMTP
|
||
- 阿里云 SDK
|
||
- LLM API Key
|
||
- 具体业务配置
|
||
- 旧项目命名配置
|
||
|
||
### 7.3 后端分层规则
|
||
|
||
每个模块保持简单分层:
|
||
|
||
- `Routes`:HTTP 路由,处理参数绑定和响应。
|
||
- `Service`:可供路由复用的服务,承载业务逻辑、权限逻辑、事务边界和必要的数据访问。
|
||
- `Dtos`:请求和响应对象。
|
||
|
||
规则:
|
||
|
||
- Route 不写复杂业务逻辑。
|
||
- Service 是事务、业务规则和可复用能力的主要承载层。
|
||
- DTO 和数据库实体不要混用。
|
||
|
||
### 7.4 统一响应
|
||
|
||
```kotlin
|
||
@Serializable
|
||
data class ApiResult<T>(
|
||
val code: String,
|
||
val message: String,
|
||
val data: T? = null,
|
||
val traceId: String? = null
|
||
)
|
||
```
|
||
|
||
成功:
|
||
|
||
```json
|
||
{
|
||
"code": "0",
|
||
"message": "成功",
|
||
"data": {}
|
||
}
|
||
```
|
||
|
||
失败:
|
||
|
||
```json
|
||
{
|
||
"code": "SYSTEM.USER_NOT_FOUND",
|
||
"message": "用户不存在",
|
||
"traceId": "..."
|
||
}
|
||
```
|
||
|
||
### 7.5 认证设计
|
||
|
||
登录流程:
|
||
|
||
1. 用户提交账号和密码。
|
||
2. 后端校验用户状态。
|
||
3. 后端校验密码。
|
||
4. 后端签发 JWT。
|
||
5. 前端保存 token。
|
||
6. 前端调用 `/api/auth/me` 获取用户、菜单、权限。
|
||
|
||
JWT 内容建议:
|
||
|
||
```json
|
||
{
|
||
"sub": "userId",
|
||
"username": "admin",
|
||
"orgId": "1",
|
||
"roles": ["admin"],
|
||
"tokenVersion": 1
|
||
}
|
||
```
|
||
|
||
后端需要支持:
|
||
|
||
- token 过期。
|
||
- 用户禁用后拒绝访问。
|
||
- 修改密码后通过 `tokenVersion` 使旧 token 失效。
|
||
|
||
### 7.6 权限模型
|
||
|
||
采用 RBAC:
|
||
|
||
```text
|
||
sys_user
|
||
sys_role
|
||
sys_menu
|
||
sys_user_role
|
||
sys_role_menu
|
||
```
|
||
|
||
菜单类型:
|
||
|
||
- `CATALOG`:目录
|
||
- `MENU`:页面
|
||
- `BUTTON`:按钮或接口权限
|
||
|
||
权限码格式:
|
||
|
||
```text
|
||
system:user:view
|
||
system:user:create
|
||
system:user:update
|
||
system:user:delete
|
||
system:role:assign
|
||
system:menu:update
|
||
system:dict:view
|
||
log:operation:view
|
||
log:api-access:view
|
||
```
|
||
|
||
接口权限校验示例:
|
||
|
||
```kotlin
|
||
post("/api/system/users") {
|
||
requirePermission("system:user:create")
|
||
}
|
||
```
|
||
|
||
### 7.7 组织模型
|
||
|
||
组织使用树结构:
|
||
|
||
```text
|
||
id
|
||
parent_id
|
||
name
|
||
code
|
||
sort
|
||
status
|
||
```
|
||
|
||
组织用于:
|
||
|
||
- 用户归属
|
||
- 数据范围预留
|
||
- 后续数据范围控制的基础
|
||
|
||
一期建议先完成组织树和用户归属,数据范围可以预留字段,不做复杂实现。
|
||
|
||
### 7.8 字典模型
|
||
|
||
字典分为:
|
||
|
||
- 字典类型
|
||
- 字典项
|
||
|
||
字典类型示例:
|
||
|
||
```text
|
||
user_status
|
||
org_status
|
||
menu_type
|
||
log_status
|
||
```
|
||
|
||
前端登录后可加载常用字典,也可以按需查询。字典适合放入 Pinia 缓存。
|
||
|
||
字典和代码枚举需要区分:
|
||
|
||
- 代码枚举用于系统逻辑强依赖的固定值,例如菜单类型、用户状态、角色状态、日志状态。
|
||
- 业务字典用于展示、筛选、颜色标识和可配置选项。
|
||
- 后端逻辑不能依赖后台随意维护的字典项来决定安全规则。
|
||
- 字典项可以影响前端展示,但不能绕过后端权限、状态和数据校验。
|
||
|
||
### 7.9 初始化数据
|
||
|
||
初始化数据放在后端工程内维护,由服务端负责创建和升级基础数据。初始化逻辑应支持重复执行,避免多次启动或多次部署后产生重复数据。
|
||
|
||
建议初始化内容:
|
||
|
||
- 默认组织:总部或默认组织。
|
||
- 默认管理员用户:admin。
|
||
- 默认角色:超级管理员。
|
||
- 默认菜单:工作台、系统管理、用户管理、组织管理、角色管理、菜单管理、字典管理、日志管理。
|
||
- 默认权限码:页面权限和关键按钮权限。
|
||
- 默认字典:用户状态、组织状态、角色状态、菜单类型、日志状态。
|
||
|
||
实现规则:
|
||
|
||
- 初始化数据按稳定编码执行 upsert,例如 `username`、`role.code`、`menu.permission`、`dict_type.code`。
|
||
- 管理员账号固定为 `admin`,初始化密码固定写入后端种子数据,首次登录后可在系统内修改。
|
||
- 初始化逻辑不写在路由里,建议放在 `bootstrap/SeedData.kt`。
|
||
- 数据库表初始化和种子数据初始化分开,方便后续迁移到正式迁移工具。
|
||
- 初始化失败应让服务启动失败,避免系统处于半初始化状态。
|
||
|
||
## 8. 日志设计
|
||
|
||
日志分三类:
|
||
|
||
1. 系统运行日志
|
||
2. 操作日志
|
||
3. 开放接口调用日志
|
||
|
||
### 8.1 系统运行日志
|
||
|
||
系统运行日志通过 Logback 输出。
|
||
|
||
记录内容:
|
||
|
||
- 应用启动
|
||
- 数据库连接
|
||
- 接口异常
|
||
- 未捕获异常
|
||
- 慢请求
|
||
- 关键配置加载结果
|
||
|
||
建议输出:
|
||
|
||
- 控制台日志
|
||
- 文件日志
|
||
- 按日期滚动
|
||
- 错误日志单独文件
|
||
|
||
### 8.2 操作日志
|
||
|
||
操作日志记录后台用户在系统内的关键操作。
|
||
|
||
典型场景:
|
||
|
||
- 登录成功
|
||
- 登录失败
|
||
- 新增用户
|
||
- 修改用户
|
||
- 禁用用户
|
||
- 删除用户
|
||
- 分配角色
|
||
- 修改菜单
|
||
- 修改字典
|
||
- 重置密码
|
||
|
||
操作日志字段:
|
||
|
||
```text
|
||
id
|
||
trace_id
|
||
user_id
|
||
username
|
||
org_id
|
||
operation_type
|
||
operation_name
|
||
http_method
|
||
request_path
|
||
request_params
|
||
ip
|
||
user_agent
|
||
status
|
||
error_message
|
||
cost_ms
|
||
created_at
|
||
```
|
||
|
||
敏感字段处理:
|
||
|
||
- 密码不记录。
|
||
- token 不记录。
|
||
- 身份证、手机号等可按规则脱敏。
|
||
|
||
实现方式:
|
||
|
||
- 提供 `OperationLog` 注解或路由扩展。
|
||
- 对关键接口显式声明操作名称。
|
||
- 在请求结束后统一落库。
|
||
|
||
示例:
|
||
|
||
```kotlin
|
||
post("/api/system/users") {
|
||
withOperationLog("新增用户") {
|
||
requirePermission("system:user:create")
|
||
userService.create(call.receive())
|
||
}
|
||
}
|
||
```
|
||
|
||
### 8.3 开放接口调用日志
|
||
|
||
开放接口调用日志用于记录平台对外提供的 API 被调用情况。
|
||
|
||
适用场景:
|
||
|
||
- 第三方系统调用平台接口。
|
||
- 内部其他系统调用平台接口。
|
||
- 后续开放 API 网关接入。
|
||
|
||
字段:
|
||
|
||
```text
|
||
id
|
||
trace_id
|
||
app_key
|
||
app_name
|
||
http_method
|
||
request_path
|
||
request_headers
|
||
request_body
|
||
response_code
|
||
response_body
|
||
ip
|
||
status
|
||
error_message
|
||
cost_ms
|
||
created_at
|
||
```
|
||
|
||
敏感字段处理:
|
||
|
||
- Authorization 不记录原文。
|
||
- 签名密钥不记录。
|
||
- 请求体和响应体限制长度。
|
||
- 大请求体不记录 body。
|
||
|
||
一期可以先设计数据表和查询页面,开放接口鉴权可后续完善。
|
||
|
||
## 9. 数据库设计
|
||
|
||
### 9.1 基础表
|
||
|
||
```text
|
||
sys_user
|
||
sys_org
|
||
sys_role
|
||
sys_menu
|
||
sys_user_role
|
||
sys_role_menu
|
||
sys_dict_type
|
||
sys_dict_item
|
||
sys_operation_log
|
||
sys_api_access_log
|
||
```
|
||
|
||
### 9.2 通用字段
|
||
|
||
建议所有业务表保留:
|
||
|
||
```text
|
||
id
|
||
created_at
|
||
created_by
|
||
updated_at
|
||
updated_by
|
||
deleted_at
|
||
deleted_by
|
||
version
|
||
```
|
||
|
||
说明:
|
||
|
||
- `id` 建议使用雪花 ID 或 UUID。
|
||
- `created_at`、`updated_at` 使用数据库时间或服务端统一时间。
|
||
- 默认使用软删除,删除时设置 `deleted_at` 和 `deleted_by`。
|
||
- 查询默认过滤 `deleted_at is null`。
|
||
- 唯一约束需要考虑软删除数据,避免已删除数据长期占用唯一值。
|
||
- `version` 用于乐观锁。
|
||
- 操作日志、开放接口调用日志等纯追加日志表不做软删除,也不需要 `updated_at`、`deleted_at`。
|
||
|
||
软删除规则:
|
||
|
||
- 普通删除接口默认执行软删除,不直接物理删除数据。
|
||
- 删除前需要校验引用关系,例如角色被用户使用、组织下存在用户、菜单被角色引用。
|
||
- 系统内置数据可以禁止删除,只允许禁用。
|
||
- 物理删除只作为维护操作,不暴露为普通管理端能力。
|
||
- 恢复已删除数据不是一期能力,但表结构保留恢复可能性。
|
||
|
||
### 9.3 用户表
|
||
|
||
```text
|
||
sys_user
|
||
id
|
||
username
|
||
password_hash
|
||
nickname
|
||
real_name
|
||
phone
|
||
email
|
||
avatar
|
||
org_id
|
||
status
|
||
token_version
|
||
last_login_at
|
||
last_login_ip
|
||
created_at
|
||
created_by
|
||
updated_at
|
||
updated_by
|
||
deleted_at
|
||
deleted_by
|
||
version
|
||
```
|
||
|
||
### 9.4 组织表
|
||
|
||
```text
|
||
sys_org
|
||
id
|
||
parent_id
|
||
name
|
||
code
|
||
sort
|
||
status
|
||
created_at
|
||
created_by
|
||
updated_at
|
||
updated_by
|
||
deleted_at
|
||
deleted_by
|
||
version
|
||
```
|
||
|
||
### 9.5 角色表
|
||
|
||
```text
|
||
sys_role
|
||
id
|
||
name
|
||
code
|
||
description
|
||
status
|
||
data_scope
|
||
created_at
|
||
created_by
|
||
updated_at
|
||
updated_by
|
||
deleted_at
|
||
deleted_by
|
||
version
|
||
```
|
||
|
||
### 9.6 菜单表
|
||
|
||
```text
|
||
sys_menu
|
||
id
|
||
parent_id
|
||
type
|
||
title
|
||
name
|
||
path
|
||
component
|
||
icon
|
||
permission
|
||
sort
|
||
visible
|
||
keep_alive
|
||
status
|
||
created_at
|
||
created_by
|
||
updated_at
|
||
updated_by
|
||
deleted_at
|
||
deleted_by
|
||
version
|
||
```
|
||
|
||
### 9.7 字典表
|
||
|
||
```text
|
||
sys_dict_type
|
||
id
|
||
code
|
||
name
|
||
status
|
||
remark
|
||
created_at
|
||
created_by
|
||
updated_at
|
||
updated_by
|
||
deleted_at
|
||
deleted_by
|
||
version
|
||
|
||
sys_dict_item
|
||
id
|
||
type_id
|
||
label
|
||
value
|
||
color
|
||
sort
|
||
status
|
||
remark
|
||
created_at
|
||
created_by
|
||
updated_at
|
||
updated_by
|
||
deleted_at
|
||
deleted_by
|
||
version
|
||
```
|
||
|
||
## 10. 后端接口范围
|
||
|
||
一期接口范围:
|
||
|
||
```http
|
||
POST /api/auth/login
|
||
POST /api/auth/logout
|
||
GET /api/auth/me
|
||
|
||
GET /api/system/users
|
||
POST /api/system/users
|
||
GET /api/system/users/{id}
|
||
PUT /api/system/users/{id}
|
||
DELETE /api/system/users/{id}
|
||
PUT /api/system/users/{id}/status
|
||
PUT /api/system/users/{id}/password
|
||
PUT /api/system/users/{id}/roles
|
||
|
||
GET /api/system/orgs
|
||
POST /api/system/orgs
|
||
PUT /api/system/orgs/{id}
|
||
DELETE /api/system/orgs/{id}
|
||
|
||
GET /api/system/roles
|
||
POST /api/system/roles
|
||
GET /api/system/roles/{id}
|
||
PUT /api/system/roles/{id}
|
||
DELETE /api/system/roles/{id}
|
||
PUT /api/system/roles/{id}/menus
|
||
|
||
GET /api/system/menus
|
||
POST /api/system/menus
|
||
PUT /api/system/menus/{id}
|
||
DELETE /api/system/menus/{id}
|
||
|
||
GET /api/system/dict-types
|
||
POST /api/system/dict-types
|
||
PUT /api/system/dict-types/{id}
|
||
DELETE /api/system/dict-types/{id}
|
||
|
||
GET /api/system/dict-items
|
||
POST /api/system/dict-items
|
||
PUT /api/system/dict-items/{id}
|
||
DELETE /api/system/dict-items/{id}
|
||
|
||
GET /api/logs/operation
|
||
GET /api/logs/api-access
|
||
```
|
||
|
||
接口路径不带版本号,系统规模不大,默认使用稳定路径。为了避免后续频繁破坏前端和已有调用方,需要遵守接口兼容规则:
|
||
|
||
- 已发布接口路径尽量不改名、不删除。
|
||
- 响应字段只增不减,不修改已有字段含义。
|
||
- 请求字段新增时必须有默认行为,不能让旧前端请求失败。
|
||
- 枚举值可以新增,但前端必须对未知枚举有兜底展示。
|
||
- 废弃字段先保留一段时间,代码中标记 deprecated,再择机清理。
|
||
- 错误码保持稳定,前端不要依赖错误文案做逻辑判断。
|
||
- 破坏性调整优先新增接口,再逐步迁移旧接口。
|
||
|
||
## 11. 前端页面范围
|
||
|
||
一期页面范围:
|
||
|
||
```text
|
||
登录页
|
||
工作台首页
|
||
用户管理
|
||
组织管理
|
||
角色管理
|
||
菜单管理
|
||
字典类型管理
|
||
字典项管理
|
||
操作日志
|
||
开放接口调用日志
|
||
403
|
||
404
|
||
```
|
||
|
||
页面标准能力:
|
||
|
||
- 查询
|
||
- 分页
|
||
- 新增
|
||
- 编辑
|
||
- 删除
|
||
- 启用/禁用
|
||
- 权限控制
|
||
- 操作反馈
|
||
|
||
## 12. 开发规范
|
||
|
||
### 12.1 前端规范
|
||
|
||
- 统一使用 TypeScript。
|
||
- 统一使用 `<script setup>`。
|
||
- 请求统一走 `api/http.ts`。
|
||
- 服务端状态统一使用 TanStack Query。
|
||
- 全局状态才进入 Pinia。
|
||
- 页面文件夹按功能组织。
|
||
- 组件命名使用 PascalCase。
|
||
- API 文件按模块拆分。
|
||
- 表格列配置尽量靠近页面,不抽成难读的全局配置。
|
||
|
||
### 12.2 后端规范
|
||
|
||
- 统一使用 kotlinx.serialization DTO。
|
||
- Route 不写复杂业务逻辑。
|
||
- Service 负责事务、业务规则和必要的数据访问。
|
||
- 所有接口返回 `ApiResult`。
|
||
- 所有异常进入统一异常处理。
|
||
- 所有需要权限的接口必须显式声明权限码。
|
||
- 关键操作必须记录操作日志。
|
||
- 新增和修改统一维护审计字段。
|
||
- 删除默认软删除,普通查询默认排除已删除数据。
|
||
- 初始化数据由后端 `bootstrap` 模块负责,必须可重复执行。
|
||
- 字典和代码枚举边界清晰,安全规则不能依赖可配置字典。
|
||
- 数据库结构先用 Exposed Table 定义表达清楚,正式生产前再补迁移脚本管理机制。
|
||
|
||
## 13. 建设顺序
|
||
|
||
详细建设顺序单独维护在 [建设顺序.md](./建设顺序.md)。
|
||
|
||
整体分为四期:
|
||
|
||
1. 一期:基础后端。
|
||
2. 二期:完整后端。
|
||
3. 三期:基础前端。
|
||
4. 四期:完整前端。
|