Files
IMTIM-Portal/PLAN.md
T

356 lines
9.1 KiB
Markdown
Raw Normal View History

2026-04-17 16:27:18 +08:00
# 门户登录基座应用 - 开发计划
## 项目概述
建立一个门户登录的基座应用,提供基础的用户认证功能,采用前后端分离架构,最终打包为单个Docker镜像部署。
---
## 技术栈
### 后端
- **框架**: Node.js + Koa (ES Modules)
- **ORM**: Prisma v5.22
- **数据库**: SQLite
- **认证**: OAuth 2.0 / OIDC (对接 Casdoor v3.18.0)
- **JWT**: jsonwebtoken v9
### 前端
- **框架**: Next.js 16 (App Router)
- **React**: v19
- **TypeScript**: v5
- **UI组件库**: Radix UI + Lucide Icons + TailwindCSS v4
- **状态管理**: Zustand v5
- **HTTP客户端**: Axios
### 部署
- **容器化**: Docker (多阶段构建)
- **反向代理**: Nginx
- **认证服务**: Casdoor v3.18.0 (本地Docker部署)
---
## 项目结构
```
base-imtim/
├── backend/ # Koa后端服务
│ ├── prisma/ # Prisma ORM配置
│ │ ├── migrations/ # 数据库迁移历史
│ │ └── schema.prisma # 数据模型定义
│ └── src/
│ ├── config/ # 配置文件
│ ├── controllers/ # 控制器
│ ├── middleware/ # 中间件(认证、日志等)
│ ├── routes/ # 路由定义
│ ├── services/ # 业务逻辑
│ └── index.js # 入口文件
├── frontend/ # Next.js前端应用
│ └── src/
│ ├── app/ # App Router页面
│ │ ├── api/ # API代理路由
│ │ ├── dashboard/ # 仪表板(需认证)
│ │ ├── login/ # 登录页
│ │ └── page.tsx # 首页
│ ├── components/ # React组件
│ │ ├── header.tsx # 导航栏
│ │ ├── layout.tsx # 布局组件
│ │ └── protected-route.tsx # 路由守卫
│ └── lib/
│ ├── api.ts # HTTP客户端
│ └── auth-store.ts # 认证状态管理
├── docker/ # Docker配置
│ ├── Dockerfile # 多阶段构建定义
│ ├── nginx.conf # Nginx反向代理配置
│ └── start.sh # 容器启动脚本
├── docs/ # 文档
│ └── casdoor-setup.md # Casdoor配置手册
├── .gitignore # Git忽略规则
├── docker-compose.yml # 开发环境编排
├── PLAN.md # 本文件
└── README.md
```
---
## 功能模块
### 1. 后端 (Koa)
#### 1.1 核心功能
- [x] 项目初始化 (Koa + 中间件)
- [x] 数据库配置 (SQLite + Prisma)
- [x] 用户模型设计
- `id`: UUID
- `username`: 用户名
- `email`: 邮箱
- `avatar`: 头像URL
- `casdoorId`: Casdoor用户ID
- `createdAt`: 创建时间
- `updatedAt`: 更新时间
#### 1.2 认证模块
- [x] Casdoor OAuth 2.0 集成
- `/api/auth/login` - 生成Casdoor登录链接
- `/api/auth/callback` - 处理Casdoor回调
- `/api/auth/logout` - 登出
- `/api/auth/user` - 获取当前用户信息
- [x] JWT Token管理
- [x] 认证中间件
#### 1.3 API路由
```
POST /api/auth/login # 获取登录URL
GET /api/auth/callback # OAuth回调
POST /api/auth/logout # 登出
GET /api/auth/user # 获取用户信息 (需认证)
GET /api/health # 健康检查
```
#### 1.4 中间件
- [x] 认证中间件 (验证JWT)
- [x] 错误处理中间件
- [x] 日志中间件
- [x] CORS中间件
### 2. 前端 (Next.js)
#### 2.1 页面结构
- [x] 首页 (`/`)
- [x] 登录页 (`/login`)
- [x] 仪表板 (`/dashboard`) - 登录后可见
- [x] API代理路由 (`/api/*`)
#### 2.2 核心组件
- [x] Layout (布局组件)
- Header (导航栏 + 用户菜单)
- Footer (页脚)
- [x] LoginButton (登录按钮)
- [x] UserMenu (用户菜单 - Radix Dropdown)
- [x] ProtectedRoute (受保护路由)
#### 2.3 功能实现
- [x] 与后端API对接 (Axios)
- [x] 认证状态管理 (Zustand + localStorage)
- [x] 路由守卫 (未登录跳转)
- [x] 响应式设计 (TailwindCSS v4)
- [x] OAuth回调Token处理
---
## 开发步骤
### Phase 1: 项目初始化 ✅
#### 1.1 后端初始化
```bash
cd backend
npm init -y
npm install koa koa-router koa-bodyparser koa-cors
npm install @prisma/client prisma
npm install jsonwebtoken axios dotenv
```
初始化Prisma:
```bash
npx prisma init
```
#### 1.2 前端初始化
```bash
npx create-next-app@latest frontend --typescript --tailwind --app --src-dir
cd frontend
npm install @radix-ui/react-dialog @radix-ui/react-dropdown-menu
npm install @radix-ui/react-avatar @radix-ui/react-separator
npm install axios zustand lucide-react
```
### Phase 2: 数据库与认证 ✅
#### 2.1 数据库模型
`backend/prisma/schema.prisma`:
```prisma
datasource db {
provider = "sqlite"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model User {
id String @id @default(uuid())
username String @unique
email String? @unique
avatar String?
casdoorId String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
```
运行迁移:
```bash
npx prisma migrate dev
npx prisma generate
```
#### 2.2 Casdoor集成
环境变量配置 (`backend/.env`):
```env
CASDOOR_SERVER_URL=http://localhost:8000
CASDOOR_CLIENT_ID=your-client-id
CASDOOR_CLIENT_SECRET=your-client-secret
CASDOOR_ORG_NAME=imtim
CASDOOR_APP_NAME=base-imtim
CASDOOR_REDIRECT_URI=http://localhost:3000/api/auth/callback
JWT_SECRET=your-jwt-secret-key
APP_PORT=3001
```
### Phase 3: 后端API开发 ✅
#### 3.1 认证流程实现
```
1. 用户访问 /login → 点击登录
2. 前端请求后端获取Casdoor登录URL
3. 用户跳转到Casdoor登录
4. 登录成功后Casdoor回调 /api/auth/callback
5. Next.js API路由重定向到后端处理
6. 后端用code换取token,获取用户信息
7. 创建/更新本地用户记录
8. 生成JWT token
9. 重定向到前端dashboard,携带token
10. 前端存储token到localStorage
```
#### 3.2 核心服务
`backend/src/services/auth.service.js`:
- `getLoginUrl()` - 生成Casdoor授权URL
- `handleCallback(code, redirectUri)` - 处理OAuth回调
- `verifyToken(token)` - 验证JWT
### Phase 4: 前端开发 ✅
#### 4.1 认证状态管理
`frontend/src/lib/auth-store.ts`:
```typescript
import { create } from 'zustand';
interface AuthState {
user: User | null;
token: string | null;
isAuthenticated: boolean;
login: (token: string, user: User) => void;
logout: () => void;
initialize: () => void;
}
```
#### 4.2 API代理路由
`frontend/src/app/api/auth/*/route.ts`:
- `/api/auth/login` - POST - 获取登录URL
- `/api/auth/callback` - GET - OAuth回调重定向
- `/api/auth/user` - GET - 获取用户信息
- `/api/auth/logout` - POST - 登出
#### 4.3 受保护路由
`frontend/src/app/dashboard/page.tsx`:
- 使用 Suspense 包裹 useSearchParams
- Token从URL参数传递到API请求
- 成功后存储到localStorage
### Phase 5: Docker化部署 ✅
#### 5.1 Dockerfile (多阶段构建)
```dockerfile
# 阶段1: 构建前端
FROM node:20-alpine AS frontend-builder
WORKDIR /app/frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
# 阶段2: 构建后端
FROM node:20-alpine AS backend-builder
WORKDIR /app/backend
COPY backend/package*.json ./
RUN npm ci
COPY backend/ ./
RUN npx prisma generate
# 阶段3: 生产环境
FROM node:20-alpine AS production
WORKDIR /app
RUN apk add --no-cache nginx
# 复制后端和前端构建
COPY --from=backend-builder /app/backend ./backend
COPY --from=frontend-builder /app/frontend/.next ./frontend/.next
# 安装生产依赖、配置nginx、启动脚本
# ...
```
#### 5.2 Nginx配置
反向代理配置:
- `/` → Next.js (3002)
- `/api/` → Koa (3001)
---
## 开发状态
| 阶段 | 任务 | 状态 |
|------|------|------|
| Phase 1 | 项目初始化 | ✅ 已完成 |
| Phase 2 | 数据库与认证配置 | ✅ 已完成 |
| Phase 3 | 后端API开发 | ✅ 已完成 |
| Phase 4 | 前端开发 | ✅ 已完成 |
| Phase 5 | Docker化部署 | ✅ 已完成 |
| **总计** | | **✅ 基座功能已完成** |
---
## 注意事项
1. **Casdoor版本**: 确保使用v3.18.0,API可能与其他版本不兼容
2. **回调URL**: Casdoor配置的重定向URL必须为 `http://localhost:3000/api/auth/callback`
3. **Casdoor用户信息端点**: v3.x 使用 `/api/get-account` 而非 `/api/userinfo`
4. **网络配置**: Docker容器间通信需要使用服务名而非localhost
5. **数据持久化**: SQLite数据库文件需要挂载volume以防数据丢失
6. **useSearchParams**: 必须包裹在 Suspense 边界内
---
## 后续扩展
- [ ] 角色权限管理 (RBAC)
- [ ] 多租户支持
- [ ] 第三方登录 (GitHub, Google等)
- [ ] 用户资料编辑
- [ ] 审计日志
- [ ] API限流
- [ ] 监控与告警
- [ ] 国际化 (i18n)
---
## 参考资源
- [Koa文档](https://koajs.com/)
- [Next.js文档](https://nextjs.org/docs)
- [Radix UI文档](https://www.radix-ui.com/)
- [Casdoor文档](https://casdoor.org/docs/overview)
- [Prisma文档](https://www.prisma.io/docs)
- [Docker文档](https://docs.docker.com/)