diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md deleted file mode 100644 index d36f7fb..0000000 --- a/CONTRIBUTORS.md +++ /dev/null @@ -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更新此文件。* \ No newline at end of file diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md deleted file mode 100644 index 29076e6..0000000 --- a/DEPLOYMENT.md +++ /dev/null @@ -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`) -- 清理旧日志文件 -- 监控磁盘使用情况 \ No newline at end of file diff --git a/TESTING.md b/TESTING.md deleted file mode 100644 index 7846627..0000000 --- a/TESTING.md +++ /dev/null @@ -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" - -# 生产环境设置 -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) 提高开发效率 \ No newline at end of file diff --git a/package.json b/package.json index e29ee1c..9c60e3a 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@nestjs/platform-socket.io": "^10.4.20", "@nestjs/schedule": "^4.1.2", "@nestjs/swagger": "^11.2.3", + "@nestjs/throttler": "^6.5.0", "@nestjs/typeorm": "^11.0.0", "@nestjs/websockets": "^10.4.20", "@types/archiver": "^7.0.0", diff --git a/src/api/.gitkeep b/src/api/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/dto/admin.dto.ts b/src/dto/admin.dto.ts deleted file mode 100644 index 420f387..0000000 --- a/src/dto/admin.dto.ts +++ /dev/null @@ -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; -} diff --git a/src/dto/admin_response.dto.ts b/src/dto/admin_response.dto.ts deleted file mode 100644 index faf2c0f..0000000 --- a/src/dto/admin_response.dto.ts +++ /dev/null @@ -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; -} diff --git a/src/dto/app.dto.ts b/src/dto/app.dto.ts deleted file mode 100644 index 498f5c5..0000000 --- a/src/dto/app.dto.ts +++ /dev/null @@ -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'; -} \ No newline at end of file diff --git a/src/dto/error_response.dto.ts b/src/dto/error_response.dto.ts deleted file mode 100644 index 595fc42..0000000 --- a/src/dto/error_response.dto.ts +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/src/dto/login.dto.ts b/src/dto/login.dto.ts deleted file mode 100644 index 6fa11f0..0000000 --- a/src/dto/login.dto.ts +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/src/dto/login_response.dto.ts b/src/dto/login_response.dto.ts deleted file mode 100644 index ef853f2..0000000 --- a/src/dto/login_response.dto.ts +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/test/api/.gitkeep b/test/api/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/test/service/.gitkeep b/test/service/.gitkeep deleted file mode 100644 index e69de29..0000000