chore: 清理旧文件和更新项目配置

- 删除旧的DTO文件(已迁移到对应业务模块)
- 删除旧的测试目录结构
- 删除过时的API目录
- 更新package.json配置
- 移除不再使用的文件
This commit is contained in:
moyin
2025-12-24 18:05:07 +08:00
parent e6d8c28806
commit 612755de63
13 changed files with 1 additions and 1757 deletions

View File

@@ -1,106 +0,0 @@
# 贡献者名单
感谢所有为 Whale Town 项目做出贡献的开发者们!🎉
## 核心贡献者
### 🏆 主要维护者
**moyin** - 主要维护者
- Gitea: [@moyin](https://gitea.xinghangee.icu/moyin)
- Email: xinghang_a@proton.me
- 提交数: **66 commits**
- 主要贡献:
- 🚀 项目架构设计与初始化
- 🔐 完整用户认证系统实现
- 📧 邮箱验证系统设计与开发
- 🗄️ Redis缓存服务文件存储+真实Redis双模式
- 📝 完整的API文档系统Swagger UI + OpenAPI
- 🧪 测试框架搭建与114个测试用例编写
- 📊 高性能日志系统集成Pino
- 🔧 项目配置优化与部署方案
- 🐛 验证码TTL重置关键问题修复
- 📚 完整的项目文档体系建设
### 🌟 核心开发者
**angjustinl** - 核心开发者
- Gitea: [@ANGJustinl](https://gitea.xinghangee.icu/ANGJustinl)
- GitHub: [@ANGJustinl](https://github.com/ANGJustinl)
- Email: 96008766+ANGJustinl@users.noreply.github.com
- 提交数: **2 commits**
- 主要贡献:
- 🔄 邮箱验证流程重构与优化
- 💾 基于内存的用户服务实现
- 🛠️ API响应处理改进
- 🧪 测试用例完善与错误修复
- 📚 系统架构优化
**jianuo** - 核心开发者
- Gitea: [@jianuo](https://gitea.xinghangee.icu/jianuo)
- Email: 32106500027@e.gzhu.edu.cn
- 提交数: **6 commits**
- 主要贡献:
- 🎛️ **管理员后台系统** - 完整的前后端管理界面开发
- 📊 **日志管理功能** - 运行时日志查看与下载系统
- 🔐 **管理员认证系统** - 独立Token认证与权限控制
- 🧪 **单元测试完善** - 管理员功能测试用例编写
- ⚙️ **TypeScript配置优化** - Node16模块解析配置
- 🐳 **Docker部署优化** - 容器化部署问题修复
- 📖 **技术栈文档更新** - 项目技术栈说明完善
## 贡献统计
| 贡献者 | 提交数 | 主要领域 | 贡献占比 |
|--------|--------|----------|----------|
| moyin | 66 | 架构设计、核心功能、文档、测试 | 88% |
| jianuo | 6 | 管理员后台、日志系统、部署优化 | 8% |
| angjustinl | 2 | 功能优化、测试、重构 | 3% |
## 项目里程碑
### 2025年12月
- **12月17日**: 项目初始化,完成基础架构搭建
- **12月17日**: 实现完整的用户认证系统
- **12月17日**: 完成API文档系统集成
- **12月17日**: 实现邮箱验证系统
- **12月17日**: 修复验证码TTL重置关键问题
- **12月18日**: angjustinl重构邮箱验证流程引入内存用户服务
- **12月18日**: jianuo修复Docker部署问题
- **12月18日**: 完成测试用例修复和优化
- **12月19日**: jianuo开发管理员后台系统
- **12月20日**: jianuo完善日志管理功能
- **12月21日**: jianuo添加管理员后台单元测试
- **12月22日**: 管理员后台功能合并到主分支
## 如何成为贡献者
我们欢迎所有形式的贡献!无论是:
- 🐛 **Bug修复** - 发现并修复问题
-**新功能** - 添加有价值的功能
- 📚 **文档改进** - 完善项目文档
- 🧪 **测试用例** - 提高代码覆盖率
- 🎨 **代码优化** - 改进代码质量
- 💡 **建议反馈** - 提出改进建议
### 贡献流程
1. Fork 项目到你的Gitea账户
2. 创建功能分支:`git checkout -b feature/your-feature`
3. 提交你的更改:`git commit -m "feat添加新功能"`
4. 推送到分支:`git push origin feature/your-feature`
5. 创建Pull Request
### 贡献规范
请在贡献前阅读:
- [AI辅助开发规范指南](./docs/AI辅助开发规范指南.md)
- [后端开发规范](./docs/backend_development_guide.md)
- [Git提交规范](./docs/git_commit_guide.md)
---
**再次感谢所有贡献者的辛勤付出!** 🙏
*如果你的名字没有出现在列表中请联系我们或提交PR更新此文件。*

View File

@@ -1,418 +0,0 @@
# 🚀 Whale Town 部署指南
本文档详细说明如何部署 Whale Town 像素游戏后端服务到生产环境。
## 📋 前置要求
### 基础环境
- **Node.js** 18+ (推荐 20.x LTS)
- **pnpm** 包管理器
- **MySQL** 8.0+
- **Redis** 6.0+ (可选,支持文件存储模式)
- **PM2** 进程管理器(推荐)
- **Nginx** 反向代理(推荐)
### 新增要求 (管理员后台)
- **Web服务器** (Nginx/Apache) - 用于前端管理界面
- **SSL证书** (推荐) - 保护管理后台安全
## 部署步骤
### 1. 服务器环境准备
```bash
# 安装 Node.js (使用 NodeSource 仓库)
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
sudo apt-get install -y nodejs
# 安装 pnpm
curl -fsSL https://get.pnpm.io/install.sh | sh
source ~/.bashrc
# 安装 PM2
npm install -g pm2
# 安装 MySQL
sudo apt update
sudo apt install mysql-server
sudo mysql_secure_installation
```
### 2. 克隆项目
```bash
# 创建项目目录
sudo mkdir -p /var/www
cd /var/www
# 克隆项目(替换为你的实际仓库地址)
git clone https://gitea.xinghangee.icu/datawhale/whale-town-end.git
cd whale-town-end
```
### 3. 配置环境
```bash
# 复制环境配置文件
cp .env.production.example .env.production
# 编辑环境配置(填入实际的数据库信息)
nano .env.production
# 复制部署脚本
cp deploy.sh.example deploy.sh
chmod +x deploy.sh
# 编辑部署脚本(修改路径配置)
nano deploy.sh
# 复制 webhook 处理器
cp webhook-handler.js.example webhook-handler.js
# 编辑 webhook 处理器(修改密钥和路径)
nano webhook-handler.js
```
### 4. 数据库设置
```bash
# 登录 MySQL
sudo mysql -u root -p
# 创建数据库和用户
CREATE DATABASE pixel_game_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'pixel_game'@'localhost' IDENTIFIED BY 'your_secure_password';
GRANT ALL PRIVILEGES ON pixel_game_db.* TO 'pixel_game'@'localhost';
FLUSH PRIVILEGES;
EXIT;
```
### 5. 安装依赖和构建
```bash
# 安装后端依赖
pnpm install --frozen-lockfile
# 安装前端依赖 (新增)
cd client
pnpm install --frozen-lockfile
cd ..
# 构建后端
pnpm run build
# 构建前端管理界面 (新增)
cd client
pnpm run build
cd ..
```
### 6. 启动服务
```bash
# 使用 PM2 启动应用
pm2 start ecosystem.config.js --env production
# 保存 PM2 配置
pm2 save
# 设置开机自启
pm2 startup
# 按照提示执行显示的命令
```
### 7. 配置 Nginx
#### 方案一: 分离部署 (推荐)
创建后端API配置
```bash
sudo nano /etc/nginx/sites-available/whale-town-api
```
```nginx
server {
listen 80;
server_name api.whaletown.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
```
创建前端管理界面配置:
```bash
sudo nano /etc/nginx/sites-available/whale-town-admin
```
```nginx
server {
listen 80;
server_name admin.whaletown.com;
root /var/www/whale-town-end/client/dist;
index index.html;
# SPA路由支持
location / {
try_files $uri $uri/ /index.html;
}
# API代理
location /api/ {
proxy_pass http://api.whaletown.com/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
```
#### 方案二: 单域名部署
创建统一配置:
```bash
sudo nano /etc/nginx/sites-available/whale-town-unified
```
```nginx
server {
listen 80;
server_name whaletown.com;
# API接口
location /api/ {
proxy_pass http://localhost:3000/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
# 管理后台
location /admin/ {
alias /var/www/whale-town-end/client/dist/;
try_files $uri $uri/ /admin/index.html;
}
# 主站点 (可选)
location / {
proxy_pass http://localhost:3000;
}
}
```
启用配置:
```bash
# 启用站点
sudo ln -s /etc/nginx/sites-available/whale-town-* /etc/nginx/sites-enabled/
# 测试配置
sudo nginx -t
# 重载配置
sudo systemctl reload nginx
```
## 🔒 SSL证书配置 (推荐)
### 使用 Let's Encrypt
```bash
# 安装 Certbot
sudo apt install certbot python3-certbot-nginx
# 为API域名申请证书
sudo certbot --nginx -d api.whaletown.com
# 为管理后台申请证书
sudo certbot --nginx -d admin.whaletown.com
# 设置自动续期
sudo crontab -e
# 添加: 0 12 * * * /usr/bin/certbot renew --quiet
```
## 🎛️ 管理员后台配置
### 环境变量配置
`.env.production` 中添加:
```bash
# 管理员Token配置 (必须)
ADMIN_TOKEN_SECRET=your_super_strong_random_secret_at_least_32_chars
ADMIN_TOKEN_TTL_SECONDS=28800
# 首次部署启用管理员引导
ADMIN_BOOTSTRAP_ENABLED=true
ADMIN_USERNAME=admin
ADMIN_PASSWORD=YourStrongPassword123!
ADMIN_NICKNAME=系统管理员
# CORS配置 (如果前后端分离)
CORS_ORIGIN=https://admin.whaletown.com
```
### 访问管理后台
- **地址**: https://admin.whaletown.com
- **默认账号**: admin / YourStrongPassword123!
**⚠️ 重要**: 首次登录后立即修改密码并关闭引导功能 (`ADMIN_BOOTSTRAP_ENABLED=false`)
## 📡 Gitea Webhook 配置
1. 在 Gitea 仓库中进入 **Settings****Webhooks**
3. 配置:
- **Target URL**: `http://your-server.com:9000/webhook``http://your-domain.com/webhook`
- **HTTP Method**: `POST`
- **POST Content Type**: `application/json`
- **Secret**: 与 `webhook-handler.js` 中的 `SECRET` 一致
- **Trigger On**: 选择 `Push events`
- **Branch filter**: `main`
## ✅ 验证部署
### 基础服务检查
```bash
# 检查PM2服务状态
pm2 status
# 检查后端API
curl http://localhost:3000/
curl http://localhost:3000/api-docs
# 检查前端管理界面
curl -I https://admin.whaletown.com
```
### 管理员后台测试
```bash
# 测试管理员登录API
curl -X POST https://api.whaletown.com/admin/auth/login \
-H "Content-Type: application/json" \
-d '{"identifier":"admin","password":"YourStrongPassword123!"}'
# 访问管理界面
# 浏览器打开: https://admin.whaletown.com
```
### 功能验证清单
- [ ] 后端API服务正常响应
- [ ] API文档可访问
- [ ] 前端管理界面加载正常
- [ ] 管理员登录功能正常
- [ ] 用户管理功能正常
- [ ] 日志查看功能正常
- [ ] SSL证书配置正确
## 🔧 常用命令
### 服务管理
```bash
# 重启后端服务
pm2 restart whale-town-end
# 重启前端服务 (如果使用PM2托管)
pm2 restart whale-town-admin
# 查看服务日志
pm2 logs whale-town-end --lines 100
pm2 logs whale-town-admin --lines 100
# 手动部署
bash deploy.sh
```
### 更新部署
```bash
# 更新后端
git pull origin main
pnpm install
pnpm run build
pm2 reload whale-town-end
# 更新前端管理界面
cd client
git pull origin main
pnpm install
pnpm run build
sudo systemctl reload nginx
cd ..
```
### 日志管理
```bash
# 查看应用日志
tail -f logs/app.log
# 查看管理员操作日志
tail -f logs/admin.log
# 查看Nginx日志
sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log
```
## 🚨 故障排除
### 后端服务问题
**服务无法启动**
- 检查环境变量配置 (`cat .env.production`)
- 检查数据库连接 (`mysql -u pixel_game -p`)
- 查看PM2日志 (`pm2 logs whale-town-end`)
- 检查端口占用 (`netstat -tlnp | grep 3000`)
**管理员登录失败**
- 验证 `ADMIN_TOKEN_SECRET` 配置
- 检查管理员账号是否创建
- 查看后端错误日志
- 确认密码复杂度要求
### 前端管理界面问题
**界面无法访问**
- 检查前端构建是否成功 (`ls -la client/dist/`)
- 验证Nginx配置 (`sudo nginx -t`)
- 检查域名解析
- 查看Nginx错误日志
**API请求失败**
- 检查CORS配置
- 验证API代理设置
- 确认后端服务状态
- 检查防火墙规则
### 数据库连接问题
**连接失败**
- 检查MySQL服务状态 (`sudo systemctl status mysql`)
- 验证数据库用户权限
- 检查网络连接
- 确认数据库配置
### SSL证书问题
**证书验证失败**
- 检查证书有效期 (`sudo certbot certificates`)
- 验证域名解析
- 重新申请证书 (`sudo certbot --nginx -d your-domain.com`)
### 性能问题
**响应缓慢**
- 检查系统资源使用 (`htop`, `df -h`)
- 优化数据库查询
- 配置Redis缓存
- 启用Nginx压缩
### 日志文件过大
**磁盘空间不足**
- 配置日志轮转 (`sudo nano /etc/logrotate.d/whale-town`)
- 清理旧日志文件
- 监控磁盘使用情况

View File

@@ -1,138 +0,0 @@
# 测试指南
本项目支持**无数据库和无邮件服务器**的测试模式,让你可以快速验证所有功能!
## 🚀 快速开始
### 1. 环境配置
```bash
# 复制环境配置文件
cp .env.example .env
```
默认配置已经设置为测试模式,无需修改即可使用。
### 2. 启动服务
```bash
# 安装依赖
npm install
# 启动开发服务器
npm run dev
```
### 3. 运行测试
**Windows (PowerShell):**
```powershell
.\test-api.ps1
```
**Linux/macOS:**
```bash
./test-api.sh
```
**自定义参数:**
```bash
# Windows
.\test-api.ps1 -BaseUrl "http://localhost:3000" -TestEmail "custom@example.com"
# Linux/macOS
./test-api.sh "http://localhost:3000" "custom@example.com"
```
## 🧪 测试功能
测试脚本会验证以下功能:
-**邮箱验证码发送** - 生成6位数验证码
-**邮箱验证码验证** - 验证码校验和清理
-**用户注册** - 完整的用户注册流程
-**用户登录** - 用户名/邮箱/手机号登录
## 🔧 测试模式特性
- 🗄️ **Redis 文件存储** - 使用 `redis-data/redis.json` 存储验证码
- 📧 **邮件测试模式** - 邮件内容输出到控制台无需真实SMTP
- 💾 **内存用户存储** - 无需数据库,用户数据存储在内存中
- 🔄 **自动切换** - 根据配置自动选择存储模式
## 📊 单元测试
```bash
# 运行所有单元测试
npm test
# 监听模式
npm run test:watch
# 生成覆盖率报告
npm run test:cov
```
## 🌐 生产环境配置
要切换到生产环境,编辑 `.env` 文件:
```bash
# 启用数据库(取消注释并填入真实数据)
DB_HOST=your_mysql_host
DB_PORT=3306
DB_USERNAME=your_db_username
DB_PASSWORD=your_db_password
DB_NAME=your_db_name
# 启用真实Redis取消注释并设置
USE_FILE_REDIS=false
REDIS_HOST=your_redis_host
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
# 启用邮件服务(取消注释并填入真实数据)
EMAIL_HOST=smtp.gmail.com
EMAIL_PORT=587
EMAIL_USER=your_email@gmail.com
EMAIL_PASS=your_app_password
EMAIL_FROM="Whale Town Game" <noreply@whaletown.com>
# 生产环境设置
NODE_ENV=production
LOG_LEVEL=info
```
## 🔍 故障排除
### 服务启动失败
- 检查端口3000是否被占用
- 确认Node.js版本 >= 18.0.0
- 运行 `npm install` 重新安装依赖
### 测试脚本执行失败
- 确认服务器正在运行
- 检查防火墙设置
- 在Linux/macOS上确保脚本有执行权限`chmod +x test-api.sh`
### Redis文件存储问题
- 检查 `redis-data` 目录权限
- 确认 `USE_FILE_REDIS=true` 设置正确
### 邮件测试模式问题
- 确认邮件配置为注释状态
- 检查服务器控制台日志输出
## 📝 测试数据
测试完成后,你可以查看:
- `redis-data/redis.json` - 验证码存储数据
- 服务器控制台 - 邮件内容输出
- 测试脚本输出 - API响应结果
## 🎯 下一步
- 查看 [API 文档](http://localhost:3000/api-docs) 了解更多接口
- 阅读 [开发规范](./docs/backend_development_guide.md) 开始开发
- 使用 [AI 辅助指南](./docs/AI辅助开发规范指南.md) 提高开发效率

View File

@@ -29,6 +29,7 @@
"@nestjs/platform-socket.io": "^10.4.20", "@nestjs/platform-socket.io": "^10.4.20",
"@nestjs/schedule": "^4.1.2", "@nestjs/schedule": "^4.1.2",
"@nestjs/swagger": "^11.2.3", "@nestjs/swagger": "^11.2.3",
"@nestjs/throttler": "^6.5.0",
"@nestjs/typeorm": "^11.0.0", "@nestjs/typeorm": "^11.0.0",
"@nestjs/websockets": "^10.4.20", "@nestjs/websockets": "^10.4.20",
"@types/archiver": "^7.0.0", "@types/archiver": "^7.0.0",

View File

View File

@@ -1,34 +0,0 @@
/**
* 管理员相关 DTO
*
* 功能描述:
* - 定义管理员登录与用户密码重置的请求结构
* - 使用 class-validator 进行参数校验
*
* @author jianuo
* @version 1.0.0
* @since 2025-12-19
*/
import { ApiProperty } from '@nestjs/swagger';
import { IsNotEmpty, IsString, MinLength } from 'class-validator';
export class AdminLoginDto {
@ApiProperty({ description: '登录标识符(用户名/邮箱/手机号)', example: 'admin' })
@IsString()
@IsNotEmpty()
identifier: string;
@ApiProperty({ description: '密码', example: 'Admin123456' })
@IsString()
@IsNotEmpty()
password: string;
}
export class AdminResetPasswordDto {
@ApiProperty({ description: '新密码至少8位包含字母和数字', example: 'NewPass1234' })
@IsString()
@IsNotEmpty()
@MinLength(8)
new_password: string;
}

View File

@@ -1,164 +0,0 @@
/**
* 管理员相关响应 DTO
*
* 功能描述:
* - 为 Swagger 提供明确的响应结构定义
* - 与 AdminService 返回结构保持一致
*
* @author jianuo
* @version 1.0.0
* @since 2025-12-19
*/
import { ApiProperty } from '@nestjs/swagger';
class AdminInfoDto {
@ApiProperty({ example: '1' })
id: string;
@ApiProperty({ example: 'admin' })
username: string;
@ApiProperty({ example: '管理员' })
nickname: string;
@ApiProperty({ example: 9 })
role: number;
}
class AdminLoginDataDto {
@ApiProperty({ type: AdminInfoDto })
admin: AdminInfoDto;
@ApiProperty({ description: '管理员访问Token用于Authorization Bearer' })
access_token: string;
@ApiProperty({ description: '过期时间戳(毫秒)', example: 1766102400000 })
expires_at: number;
}
export class AdminLoginResponseDto {
@ApiProperty({ example: true })
success: boolean;
@ApiProperty({ type: AdminLoginDataDto, required: false })
data?: AdminLoginDataDto;
@ApiProperty({ example: '管理员登录成功' })
message: string;
@ApiProperty({ required: false, example: 'ADMIN_LOGIN_FAILED' })
error_code?: string;
}
class AdminUserDto {
@ApiProperty({ example: '1' })
id: string;
@ApiProperty({ example: 'user1' })
username: string;
@ApiProperty({ example: '小明' })
nickname: string;
@ApiProperty({ required: false, example: 'user1@example.com', nullable: true })
email?: string;
@ApiProperty({ example: false })
email_verified: boolean;
@ApiProperty({ required: false, example: '+8613800138000', nullable: true })
phone?: string;
@ApiProperty({ required: false, example: 'https://example.com/avatar.png', nullable: true })
avatar_url?: string;
@ApiProperty({ example: 1 })
role: number;
@ApiProperty({ example: '2025-12-19T00:00:00.000Z' })
created_at: Date;
@ApiProperty({ example: '2025-12-19T00:00:00.000Z' })
updated_at: Date;
}
class AdminUsersDataDto {
@ApiProperty({ type: [AdminUserDto] })
users: AdminUserDto[];
@ApiProperty({ example: 100 })
limit: number;
@ApiProperty({ example: 0 })
offset: number;
}
export class AdminUsersResponseDto {
@ApiProperty({ example: true })
success: boolean;
@ApiProperty({ type: AdminUsersDataDto, required: false })
data?: AdminUsersDataDto;
@ApiProperty({ example: '用户列表获取成功' })
message: string;
@ApiProperty({ required: false, example: 'ADMIN_USERS_FAILED' })
error_code?: string;
}
class AdminUserDataDto {
@ApiProperty({ type: AdminUserDto })
user: AdminUserDto;
}
export class AdminUserResponseDto {
@ApiProperty({ example: true })
success: boolean;
@ApiProperty({ type: AdminUserDataDto, required: false })
data?: AdminUserDataDto;
@ApiProperty({ example: '用户信息获取成功' })
message: string;
}
export class AdminCommonResponseDto {
@ApiProperty({ example: true })
success: boolean;
@ApiProperty({ required: false })
data?: any;
@ApiProperty({ example: '密码重置成功' })
message: string;
@ApiProperty({ required: false, example: 'ADMIN_OPERATION_FAILED' })
error_code?: string;
}
class AdminRuntimeLogsDataDto {
@ApiProperty({ example: 'dev.log' })
file: string;
@ApiProperty({ description: '日志文件最后更新时间ISO', example: '2025-12-19T19:10:15.000Z' })
updated_at: string;
@ApiProperty({ type: [String], description: '日志行(按时间顺序,越靠后越新)' })
lines: string[];
}
export class AdminRuntimeLogsResponseDto {
@ApiProperty({ example: true })
success: boolean;
@ApiProperty({ type: AdminRuntimeLogsDataDto, required: false })
data?: AdminRuntimeLogsDataDto;
@ApiProperty({ example: '运行日志获取成功' })
message: string;
@ApiProperty({ required: false, example: 'ADMIN_OPERATION_FAILED' })
error_code?: string;
}

View File

@@ -1,72 +0,0 @@
/**
* 应用状态响应 DTO
*
* 功能描述:
* - 定义应用状态接口的响应格式
* - 提供 Swagger 文档生成支持
*
* @author angjustinl
* @version 1.0.0
* @since 2025-12-17
*/
import { ApiProperty } from '@nestjs/swagger';
/**
* 应用状态响应 DTO
*/
export class AppStatusResponseDto {
@ApiProperty({
description: '服务名称',
example: 'Pixel Game Server',
type: String
})
service: string;
@ApiProperty({
description: '服务版本',
example: '1.0.0',
type: String
})
version: string;
@ApiProperty({
description: '运行状态',
example: 'running',
enum: ['running', 'starting', 'stopping', 'error'],
type: String
})
status: string;
@ApiProperty({
description: '当前时间戳',
example: '2025-12-17T15:00:00.000Z',
type: String,
format: 'date-time'
})
timestamp: string;
@ApiProperty({
description: '运行时间(秒)',
example: 3600,
type: Number,
minimum: 0
})
uptime: number;
@ApiProperty({
description: '运行环境',
example: 'development',
enum: ['development', 'production', 'test'],
type: String
})
environment: string;
@ApiProperty({
description: '存储模式',
example: 'memory',
enum: ['database', 'memory'],
type: String
})
storage_mode: 'database' | 'memory';
}

View File

@@ -1,56 +0,0 @@
/**
* 通用错误响应 DTO
*
* 功能描述:
* - 定义统一的错误响应格式
* - 提供 Swagger 文档生成支持
*
* @author angjustinl
* @version 1.0.0
* @since 2025-12-17
*/
import { ApiProperty } from '@nestjs/swagger';
/**
* 通用错误响应 DTO
*/
export class ErrorResponseDto {
@ApiProperty({
description: 'HTTP 状态码',
example: 500,
type: Number
})
statusCode: number;
@ApiProperty({
description: '错误消息',
example: 'Internal server error',
type: String
})
message: string;
@ApiProperty({
description: '错误发生时间',
example: '2025-12-17T15:00:00.000Z',
type: String,
format: 'date-time'
})
timestamp: string;
@ApiProperty({
description: '请求路径',
example: '/api/status',
type: String,
required: false
})
path?: string;
@ApiProperty({
description: '错误代码',
example: 'INTERNAL_ERROR',
type: String,
required: false
})
error?: string;
}

View File

@@ -1,374 +0,0 @@
/**
* 登录业务数据传输对象
*
* 功能描述:
* - 定义登录相关API的请求数据结构
* - 提供数据验证规则和错误提示
* - 确保API接口的数据格式一致性
*
* @author moyin
* @version 1.0.0
* @since 2025-12-17
*/
import {
IsString,
IsEmail,
IsPhoneNumber,
IsNotEmpty,
Length,
IsOptional,
Matches,
IsNumberString
} from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
/**
* 登录请求DTO
*/
export class LoginDto {
/**
* 登录标识符
* 支持用户名、邮箱或手机号登录
*/
@ApiProperty({
description: '登录标识符,支持用户名、邮箱或手机号',
example: 'testuser',
minLength: 1,
maxLength: 100
})
@IsString({ message: '登录标识符必须是字符串' })
@IsNotEmpty({ message: '登录标识符不能为空' })
@Length(1, 100, { message: '登录标识符长度需在1-100字符之间' })
identifier: string;
/**
* 密码
*/
@ApiProperty({
description: '用户密码',
example: 'password123',
minLength: 1,
maxLength: 128
})
@IsString({ message: '密码必须是字符串' })
@IsNotEmpty({ message: '密码不能为空' })
@Length(1, 128, { message: '密码长度需在1-128字符之间' })
password: string;
}
/**
* 注册请求DTO
*/
export class RegisterDto {
/**
* 用户名
*/
@ApiProperty({
description: '用户名,只能包含字母、数字和下划线',
example: 'testuser',
minLength: 1,
maxLength: 50,
pattern: '^[a-zA-Z0-9_]+$'
})
@IsString({ message: '用户名必须是字符串' })
@IsNotEmpty({ message: '用户名不能为空' })
@Length(1, 50, { message: '用户名长度需在1-50字符之间' })
@Matches(/^[a-zA-Z0-9_]+$/, { message: '用户名只能包含字母、数字和下划线' })
username: string;
/**
* 密码
*/
@ApiProperty({
description: '密码必须包含字母和数字长度8-128字符',
example: 'password123',
minLength: 8,
maxLength: 128
})
@IsString({ message: '密码必须是字符串' })
@IsNotEmpty({ message: '密码不能为空' })
@Length(8, 128, { message: '密码长度需在8-128字符之间' })
@Matches(/^(?=.*[a-zA-Z])(?=.*\d)/, { message: '密码必须包含字母和数字' })
password: string;
/**
* 昵称
*/
@ApiProperty({
description: '用户昵称',
example: '测试用户',
minLength: 1,
maxLength: 50
})
@IsString({ message: '昵称必须是字符串' })
@IsNotEmpty({ message: '昵称不能为空' })
@Length(1, 50, { message: '昵称长度需在1-50字符之间' })
nickname: string;
/**
* 邮箱(可选)
*/
@ApiProperty({
description: '邮箱地址(可选)',
example: 'test@example.com',
required: false
})
@IsOptional()
@IsEmail({}, { message: '邮箱格式不正确' })
email?: string;
/**
* 手机号(可选)
*/
@ApiProperty({
description: '手机号码(可选)',
example: '+8613800138000',
required: false
})
@IsOptional()
@IsPhoneNumber(null, { message: '手机号格式不正确' })
phone?: string;
/**
* 邮箱验证码(当提供邮箱时必填)
*/
@ApiProperty({
description: '邮箱验证码,当提供邮箱时必填',
example: '123456',
pattern: '^\\d{6}$',
required: false
})
@IsOptional()
@IsString({ message: '验证码必须是字符串' })
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
email_verification_code?: string;
}
/**
* GitHub OAuth登录请求DTO
*/
export class GitHubOAuthDto {
/**
* GitHub用户ID
*/
@ApiProperty({
description: 'GitHub用户ID',
example: '12345678',
minLength: 1,
maxLength: 100
})
@IsString({ message: 'GitHub ID必须是字符串' })
@IsNotEmpty({ message: 'GitHub ID不能为空' })
@Length(1, 100, { message: 'GitHub ID长度需在1-100字符之间' })
github_id: string;
/**
* 用户名
*/
@ApiProperty({
description: 'GitHub用户名',
example: 'octocat',
minLength: 1,
maxLength: 50
})
@IsString({ message: '用户名必须是字符串' })
@IsNotEmpty({ message: '用户名不能为空' })
@Length(1, 50, { message: '用户名长度需在1-50字符之间' })
username: string;
/**
* 昵称
*/
@ApiProperty({
description: 'GitHub显示名称',
example: 'The Octocat',
minLength: 1,
maxLength: 50
})
@IsString({ message: '昵称必须是字符串' })
@IsNotEmpty({ message: '昵称不能为空' })
@Length(1, 50, { message: '昵称长度需在1-50字符之间' })
nickname: string;
/**
* 邮箱(可选)
*/
@ApiProperty({
description: 'GitHub邮箱地址可选',
example: 'octocat@github.com',
required: false
})
@IsOptional()
@IsEmail({}, { message: '邮箱格式不正确' })
email?: string;
/**
* 头像URL可选
*/
@ApiProperty({
description: 'GitHub头像URL可选',
example: 'https://github.com/images/error/octocat_happy.gif',
required: false
})
@IsOptional()
@IsString({ message: '头像URL必须是字符串' })
avatar_url?: string;
}
/**
* 忘记密码请求DTO
*/
export class ForgotPasswordDto {
/**
* 邮箱或手机号
*/
@ApiProperty({
description: '邮箱或手机号',
example: 'test@example.com',
minLength: 1,
maxLength: 100
})
@IsString({ message: '标识符必须是字符串' })
@IsNotEmpty({ message: '邮箱或手机号不能为空' })
@Length(1, 100, { message: '标识符长度需在1-100字符之间' })
identifier: string;
}
/**
* 重置密码请求DTO
*/
export class ResetPasswordDto {
/**
* 邮箱或手机号
*/
@ApiProperty({
description: '邮箱或手机号',
example: 'test@example.com',
minLength: 1,
maxLength: 100
})
@IsString({ message: '标识符必须是字符串' })
@IsNotEmpty({ message: '邮箱或手机号不能为空' })
@Length(1, 100, { message: '标识符长度需在1-100字符之间' })
identifier: string;
/**
* 验证码
*/
@ApiProperty({
description: '6位数字验证码',
example: '123456',
pattern: '^\\d{6}$'
})
@IsString({ message: '验证码必须是字符串' })
@IsNotEmpty({ message: '验证码不能为空' })
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
verification_code: string;
/**
* 新密码
*/
@ApiProperty({
description: '新密码必须包含字母和数字长度8-128字符',
example: 'newpassword123',
minLength: 8,
maxLength: 128
})
@IsString({ message: '新密码必须是字符串' })
@IsNotEmpty({ message: '新密码不能为空' })
@Length(8, 128, { message: '新密码长度需在8-128字符之间' })
@Matches(/^(?=.*[a-zA-Z])(?=.*\d)/, { message: '新密码必须包含字母和数字' })
new_password: string;
}
/**
* 修改密码请求DTO
*/
export class ChangePasswordDto {
/**
* 用户ID
* 实际应用中应从JWT令牌中获取这里为了演示放在请求体中
*/
@ApiProperty({
description: '用户ID实际应用中应从JWT令牌中获取',
example: '1'
})
@IsNumberString({}, { message: '用户ID必须是数字字符串' })
@IsNotEmpty({ message: '用户ID不能为空' })
user_id: string;
/**
* 旧密码
*/
@ApiProperty({
description: '当前密码',
example: 'oldpassword123',
minLength: 1,
maxLength: 128
})
@IsString({ message: '旧密码必须是字符串' })
@IsNotEmpty({ message: '旧密码不能为空' })
@Length(1, 128, { message: '旧密码长度需在1-128字符之间' })
old_password: string;
/**
* 新密码
*/
@ApiProperty({
description: '新密码必须包含字母和数字长度8-128字符',
example: 'newpassword123',
minLength: 8,
maxLength: 128
})
@IsString({ message: '新密码必须是字符串' })
@IsNotEmpty({ message: '新密码不能为空' })
@Length(8, 128, { message: '新密码长度需在8-128字符之间' })
@Matches(/^(?=.*[a-zA-Z])(?=.*\d)/, { message: '新密码必须包含字母和数字' })
new_password: string;
}
/**
* 邮箱验证请求DTO
*/
export class EmailVerificationDto {
/**
* 邮箱地址
*/
@ApiProperty({
description: '邮箱地址',
example: 'test@example.com'
})
@IsEmail({}, { message: '邮箱格式不正确' })
@IsNotEmpty({ message: '邮箱不能为空' })
email: string;
/**
* 验证码
*/
@ApiProperty({
description: '6位数字验证码',
example: '123456',
pattern: '^\\d{6}$'
})
@IsString({ message: '验证码必须是字符串' })
@IsNotEmpty({ message: '验证码不能为空' })
@Matches(/^\d{6}$/, { message: '验证码必须是6位数字' })
verification_code: string;
}
/**
* 发送邮箱验证码请求DTO
*/
export class SendEmailVerificationDto {
/**
* 邮箱地址
*/
@ApiProperty({
description: '邮箱地址',
example: 'test@example.com'
})
@IsEmail({}, { message: '邮箱格式不正确' })
@IsNotEmpty({ message: '邮箱不能为空' })
email: string;
}

View File

@@ -1,395 +0,0 @@
/**
* 登录业务响应数据传输对象
*
* 功能描述:
* - 定义登录相关API的响应数据结构
* - 提供Swagger文档生成支持
* - 确保API响应的数据格式一致性
*
* @author moyin
* @version 1.0.0
* @since 2025-12-17
*/
import { ApiProperty } from '@nestjs/swagger';
/**
* 用户信息响应DTO
*/
export class UserInfoDto {
@ApiProperty({
description: '用户ID',
example: '1'
})
id: string;
@ApiProperty({
description: '用户名',
example: 'testuser'
})
username: string;
@ApiProperty({
description: '用户昵称',
example: '测试用户'
})
nickname: string;
@ApiProperty({
description: '邮箱地址',
example: 'test@example.com',
required: false
})
email?: string;
@ApiProperty({
description: '手机号码',
example: '+8613800138000',
required: false
})
phone?: string;
@ApiProperty({
description: '头像URL',
example: 'https://example.com/avatar.jpg',
required: false
})
avatar_url?: string;
@ApiProperty({
description: '用户角色',
example: 1
})
role: number;
@ApiProperty({
description: '创建时间',
example: '2025-12-17T10:00:00.000Z'
})
created_at: Date;
}
/**
* 登录响应数据DTO
*/
export class LoginResponseDataDto {
@ApiProperty({
description: '用户信息',
type: UserInfoDto
})
user: UserInfoDto;
@ApiProperty({
description: '访问令牌',
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
})
access_token: string;
@ApiProperty({
description: '刷新令牌',
example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
required: false
})
refresh_token?: string;
@ApiProperty({
description: '是否为新用户',
example: false,
required: false
})
is_new_user?: boolean;
@ApiProperty({
description: '响应消息',
example: '登录成功'
})
message: string;
}
/**
* 登录响应DTO
*/
export class LoginResponseDto {
@ApiProperty({
description: '请求是否成功',
example: true
})
success: boolean;
@ApiProperty({
description: '响应数据',
type: LoginResponseDataDto,
required: false
})
data?: LoginResponseDataDto;
@ApiProperty({
description: '响应消息',
example: '登录成功'
})
message: string;
@ApiProperty({
description: '错误代码',
example: 'LOGIN_FAILED',
required: false
})
error_code?: string;
}
/**
* 注册响应DTO
*/
export class RegisterResponseDto {
@ApiProperty({
description: '请求是否成功',
example: true
})
success: boolean;
@ApiProperty({
description: '响应数据',
type: LoginResponseDataDto,
required: false
})
data?: LoginResponseDataDto;
@ApiProperty({
description: '响应消息',
example: '注册成功'
})
message: string;
@ApiProperty({
description: '错误代码',
example: 'REGISTER_FAILED',
required: false
})
error_code?: string;
}
/**
* GitHub OAuth响应DTO
*/
export class GitHubOAuthResponseDto {
@ApiProperty({
description: '请求是否成功',
example: true
})
success: boolean;
@ApiProperty({
description: '响应数据',
type: LoginResponseDataDto,
required: false
})
data?: LoginResponseDataDto;
@ApiProperty({
description: '响应消息',
example: 'GitHub登录成功'
})
message: string;
@ApiProperty({
description: '错误代码',
example: 'GITHUB_OAUTH_FAILED',
required: false
})
error_code?: string;
}
/**
* 忘记密码响应数据DTO
*/
export class ForgotPasswordResponseDataDto {
@ApiProperty({
description: '验证码(仅用于演示,实际应用中不应返回)',
example: '123456',
required: false
})
verification_code?: string;
@ApiProperty({
description: '是否为测试模式',
example: true,
required: false
})
is_test_mode?: boolean;
}
/**
* 忘记密码响应DTO
*/
export class ForgotPasswordResponseDto {
@ApiProperty({
description: '请求是否成功',
example: false,
examples: {
success: {
summary: '真实发送成功',
value: true
},
testMode: {
summary: '测试模式',
value: false
}
}
})
success: boolean;
@ApiProperty({
description: '响应数据',
type: ForgotPasswordResponseDataDto,
required: false,
examples: {
success: {
summary: '真实发送成功',
value: {
verification_code: '123456',
is_test_mode: false
}
},
testMode: {
summary: '测试模式',
value: {
verification_code: '059174',
is_test_mode: true
}
}
}
})
data?: ForgotPasswordResponseDataDto;
@ApiProperty({
description: '响应消息',
example: '⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。',
examples: {
success: {
summary: '真实发送成功',
value: '验证码已发送,请查收'
},
testMode: {
summary: '测试模式',
value: '⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。'
}
}
})
message: string;
@ApiProperty({
description: '错误代码',
example: 'TEST_MODE_ONLY',
examples: {
success: {
summary: '真实发送成功',
value: null
},
testMode: {
summary: '测试模式',
value: 'TEST_MODE_ONLY'
},
failed: {
summary: '发送失败',
value: 'SEND_CODE_FAILED'
}
},
required: false
})
error_code?: string;
}
/**
* 通用响应DTO用于重置密码、修改密码等
*/
export class CommonResponseDto {
@ApiProperty({
description: '请求是否成功',
example: true
})
success: boolean;
@ApiProperty({
description: '响应消息',
example: '操作成功'
})
message: string;
@ApiProperty({
description: '错误代码',
example: 'OPERATION_FAILED',
required: false
})
error_code?: string;
}
/**
* 测试模式邮件验证码响应DTO by angjustinl 2025-12-17
*/
export class TestModeEmailVerificationResponseDto {
@ApiProperty({
description: '请求是否成功测试模式下为false',
example: false
})
success: boolean;
@ApiProperty({
description: '响应数据',
example: {
verification_code: '059174',
is_test_mode: true
}
})
data: {
verification_code: string;
is_test_mode: boolean;
};
@ApiProperty({
description: '响应消息',
example: '⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。'
})
message: string;
@ApiProperty({
description: '错误代码',
example: 'TEST_MODE_ONLY'
})
error_code: string;
}
/**
* 成功发送邮件验证码响应DTO
*/
export class SuccessEmailVerificationResponseDto {
@ApiProperty({
description: '请求是否成功',
example: true
})
success: boolean;
@ApiProperty({
description: '响应数据',
example: {
verification_code: '123456',
is_test_mode: false
}
})
data: {
verification_code: string;
is_test_mode: boolean;
};
@ApiProperty({
description: '响应消息',
example: '验证码已发送,请查收'
})
message: string;
@ApiProperty({
description: '错误代码',
example: null,
required: false
})
error_code?: string;
}

View File

View File