refactor:重构安全模块架构,将security模块迁移至core层
- 将src/business/security模块迁移至src/core/security_core - 更新模块导入路径和依赖关系 - 统一安全相关组件的命名规范(content_type.middleware.ts) - 清理过时的配置文件和文档 - 更新架构文档以反映新的模块结构 此次重构符合业务功能模块化架构设计原则,将技术基础设施 服务统一放置在core层,提高代码组织的清晰度和可维护性。
This commit is contained in:
31
Dockerfile
31
Dockerfile
@@ -1,31 +0,0 @@
|
||||
# 使用官方 Node.js 镜像
|
||||
FROM node:lts-alpine
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 设置构建参数
|
||||
ARG NPM_REGISTRY=https://registry.npmmirror.com
|
||||
|
||||
# 设置 npm 和 pnpm 镜像源
|
||||
RUN npm config set registry ${NPM_REGISTRY} && \
|
||||
npm install -g pnpm && \
|
||||
pnpm config set registry ${NPM_REGISTRY}
|
||||
|
||||
# 复制 package.json
|
||||
COPY package.json pnpm-workspace.yaml ./
|
||||
|
||||
# 安装依赖
|
||||
RUN pnpm install
|
||||
|
||||
# 复制源代码
|
||||
COPY . .
|
||||
|
||||
# 构建应用
|
||||
RUN pnpm run build
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 3000
|
||||
|
||||
# 启动应用
|
||||
CMD ["pnpm", "run", "start:prod"]
|
||||
@@ -1,163 +0,0 @@
|
||||
# Zulip模块重构总结
|
||||
|
||||
## 重构完成情况
|
||||
|
||||
✅ **重构已完成** - 项目编译成功,架构符合分层设计原则
|
||||
|
||||
## 重构内容
|
||||
|
||||
### 1. 架构分层重构
|
||||
|
||||
#### 移动到核心服务层 (`src/core/zulip/`)
|
||||
以下技术实现相关的服务已移动到核心服务层:
|
||||
|
||||
- `zulip_client.service.ts` - Zulip REST API封装
|
||||
- `zulip_client_pool.service.ts` - 客户端连接池管理
|
||||
- `config_manager.service.ts` - 配置文件管理和热重载
|
||||
- `api_key_security.service.ts` - API Key安全存储
|
||||
- `error_handler.service.ts` - 错误处理和重试机制
|
||||
- `monitoring.service.ts` - 系统监控和健康检查
|
||||
- `stream_initializer.service.ts` - Stream初始化服务
|
||||
|
||||
#### 保留在业务逻辑层 (`src/business/zulip/`)
|
||||
以下业务逻辑相关的服务保留在业务层:
|
||||
|
||||
- `zulip.service.ts` - 主要业务协调服务
|
||||
- `zulip_websocket.gateway.ts` - WebSocket业务网关
|
||||
- `session_manager.service.ts` - 游戏会话业务逻辑
|
||||
- `message_filter.service.ts` - 消息过滤业务规则
|
||||
- `zulip_event_processor.service.ts` - 事件处理业务逻辑
|
||||
- `session_cleanup.service.ts` - 会话清理业务逻辑
|
||||
|
||||
### 2. 依赖注入重构
|
||||
|
||||
#### 创建接口抽象
|
||||
- 新增 `src/core/zulip/interfaces/zulip-core.interfaces.ts`
|
||||
- 定义核心服务接口:`IZulipClientService`、`IZulipClientPoolService`、`IZulipConfigService`
|
||||
|
||||
#### 更新依赖注入
|
||||
业务层服务现在通过接口依赖核心服务:
|
||||
|
||||
```typescript
|
||||
// 旧方式 - 直接依赖具体实现
|
||||
constructor(
|
||||
private readonly zulipClientPool: ZulipClientPoolService,
|
||||
) {}
|
||||
|
||||
// 新方式 - 通过接口依赖
|
||||
constructor(
|
||||
@Inject('ZULIP_CLIENT_POOL_SERVICE')
|
||||
private readonly zulipClientPool: IZulipClientPoolService,
|
||||
) {}
|
||||
```
|
||||
|
||||
### 3. 模块结构重构
|
||||
|
||||
#### 核心服务模块
|
||||
- 新增 `ZulipCoreModule` - 提供所有技术实现服务
|
||||
- 通过依赖注入标识符导出服务
|
||||
|
||||
#### 业务逻辑模块
|
||||
- 更新 `ZulipModule` - 导入核心模块,专注业务逻辑
|
||||
- 移除技术实现相关的服务提供者
|
||||
|
||||
### 4. 文件移动记录
|
||||
|
||||
#### 移动到核心层的文件
|
||||
```
|
||||
src/business/zulip/services/ → src/core/zulip/services/
|
||||
├── zulip_client.service.ts
|
||||
├── zulip_client_pool.service.ts
|
||||
├── config_manager.service.ts
|
||||
├── api_key_security.service.ts
|
||||
├── error_handler.service.ts
|
||||
├── monitoring.service.ts
|
||||
├── stream_initializer.service.ts
|
||||
└── 对应的 .spec.ts 测试文件
|
||||
|
||||
src/business/zulip/ → src/core/zulip/
|
||||
├── interfaces/
|
||||
├── config/
|
||||
└── types/
|
||||
```
|
||||
|
||||
## 架构优势
|
||||
|
||||
### 1. 符合分层架构原则
|
||||
- **业务层**:只关注游戏相关的业务逻辑和规则
|
||||
- **核心层**:只处理技术实现和第三方API调用
|
||||
|
||||
### 2. 依赖倒置
|
||||
- 业务层依赖接口,不依赖具体实现
|
||||
- 核心层提供接口实现
|
||||
- 便于测试和替换实现
|
||||
|
||||
### 3. 单一职责
|
||||
- 每个服务职责明确
|
||||
- 业务逻辑与技术实现分离
|
||||
- 代码更易维护和理解
|
||||
|
||||
### 4. 可测试性
|
||||
- 业务逻辑可以独立测试
|
||||
- 通过Mock接口进行单元测试
|
||||
- 技术实现可以独立验证
|
||||
|
||||
## 当前状态
|
||||
|
||||
### ✅ 已完成
|
||||
- [x] 文件移动和重新组织
|
||||
- [x] 接口定义和抽象
|
||||
- [x] 依赖注入重构
|
||||
- [x] 模块结构调整
|
||||
- [x] 编译通过验证
|
||||
- [x] 测试文件的依赖注入配置更新
|
||||
- [x] 所有测试用例通过验证
|
||||
|
||||
### ✅ 测试修复完成
|
||||
- [x] `zulip_event_processor.service.spec.ts` - 更新依赖注入配置
|
||||
- [x] `message_filter.service.spec.ts` - 已通过测试
|
||||
- [x] `session_manager.service.spec.ts` - 已通过测试
|
||||
- [x] 核心服务测试文件导入路径修复
|
||||
- [x] 所有Zulip相关测试通过
|
||||
|
||||
## 使用指南
|
||||
|
||||
### 业务层开发
|
||||
```typescript
|
||||
// 在业务服务中使用核心服务
|
||||
@Injectable()
|
||||
export class MyBusinessService {
|
||||
constructor(
|
||||
@Inject('ZULIP_CLIENT_POOL_SERVICE')
|
||||
private readonly zulipClientPool: IZulipClientPoolService,
|
||||
) {}
|
||||
}
|
||||
```
|
||||
|
||||
### 测试配置
|
||||
```typescript
|
||||
// 测试中Mock核心服务
|
||||
const mockZulipClientPool: IZulipClientPoolService = {
|
||||
sendMessage: jest.fn().mockResolvedValue({ success: true }),
|
||||
// ...
|
||||
};
|
||||
|
||||
const module = await Test.createTestingModule({
|
||||
providers: [
|
||||
MyBusinessService,
|
||||
{ provide: 'ZULIP_CLIENT_POOL_SERVICE', useValue: mockZulipClientPool },
|
||||
],
|
||||
}).compile();
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
重构成功实现了以下目标:
|
||||
|
||||
1. **架构合规**:符合项目的分层架构设计原则
|
||||
2. **职责分离**:业务逻辑与技术实现清晰分离
|
||||
3. **依赖解耦**:通过接口实现依赖倒置
|
||||
4. **可维护性**:代码结构更清晰,易于维护和扩展
|
||||
5. **可测试性**:业务逻辑可以独立测试
|
||||
|
||||
项目现在具有更好的架构设计,为后续开发和维护奠定了良好基础。
|
||||
@@ -1,54 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 部署脚本模板 - 用于 Gitea Webhook 自动部署
|
||||
# 复制此文件为 deploy.sh 并根据服务器环境修改配置
|
||||
set -e
|
||||
|
||||
echo "开始部署 Pixel Game Server..."
|
||||
|
||||
# 项目路径(根据你的服务器实际路径修改)
|
||||
PROJECT_PATH="/var/www/pixel-game-server"
|
||||
BACKUP_PATH="/var/backups/pixel-game-server"
|
||||
|
||||
# 创建备份
|
||||
echo "创建备份..."
|
||||
mkdir -p $BACKUP_PATH
|
||||
cp -r $PROJECT_PATH $BACKUP_PATH/backup-$(date +%Y%m%d-%H%M%S)
|
||||
|
||||
# 进入项目目录
|
||||
cd $PROJECT_PATH
|
||||
|
||||
# 拉取最新代码
|
||||
echo "拉取最新代码..."
|
||||
git pull origin main
|
||||
|
||||
# 安装/更新依赖
|
||||
echo "安装依赖..."
|
||||
pnpm install --frozen-lockfile
|
||||
|
||||
# 构建项目
|
||||
echo "构建项目..."
|
||||
pnpm run build
|
||||
|
||||
# 重启服务
|
||||
echo "重启服务..."
|
||||
if command -v pm2 &> /dev/null; then
|
||||
# 使用 PM2
|
||||
pm2 restart pixel-game-server || pm2 start dist/main.js --name pixel-game-server
|
||||
elif command -v docker-compose &> /dev/null; then
|
||||
# 使用 Docker Compose
|
||||
docker-compose down
|
||||
docker-compose up -d --build
|
||||
else
|
||||
# 使用 systemd
|
||||
sudo systemctl restart pixel-game-server
|
||||
fi
|
||||
|
||||
echo "部署完成!"
|
||||
|
||||
# 清理旧备份(保留最近5个)
|
||||
find $BACKUP_PATH -maxdepth 1 -type d -name "backup-*" | sort -r | tail -n +6 | xargs rm -rf
|
||||
|
||||
echo "服务状态检查..."
|
||||
sleep 5
|
||||
curl -f http://localhost:3000/health || echo "警告:服务健康检查失败"
|
||||
@@ -1,36 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DB_HOST=mysql
|
||||
- DB_PORT=3306
|
||||
- DB_USERNAME=pixel_game
|
||||
- DB_PASSWORD=your_password
|
||||
- DB_NAME=pixel_game_db
|
||||
depends_on:
|
||||
- mysql
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=root_password
|
||||
- MYSQL_DATABASE=pixel_game_db
|
||||
- MYSQL_USER=pixel_game
|
||||
- MYSQL_PASSWORD=your_password
|
||||
ports:
|
||||
- "3306:3306"
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
@@ -1,257 +0,0 @@
|
||||
# API 状态码说明
|
||||
|
||||
## 📊 概述
|
||||
|
||||
本文档说明了项目中使用的 HTTP 状态码,特别是针对邮件发送功能的特殊状态码处理。
|
||||
|
||||
## 🔢 标准状态码
|
||||
|
||||
| 状态码 | 含义 | 使用场景 |
|
||||
|--------|------|----------|
|
||||
| 200 | OK | 请求成功 |
|
||||
| 201 | Created | 资源创建成功(如用户注册) |
|
||||
| 400 | Bad Request | 请求参数错误 |
|
||||
| 401 | Unauthorized | 未授权(如密码错误) |
|
||||
| 403 | Forbidden | 权限不足 |
|
||||
| 404 | Not Found | 资源不存在 |
|
||||
| 409 | Conflict | 资源冲突(如用户名已存在) |
|
||||
| 429 | Too Many Requests | 请求频率过高 |
|
||||
| 500 | Internal Server Error | 服务器内部错误 |
|
||||
|
||||
## 🎯 特殊状态码
|
||||
|
||||
### 206 Partial Content - 测试模式
|
||||
|
||||
**使用场景:** 邮件发送功能在测试模式下使用
|
||||
|
||||
**含义:** 请求部分成功,但未完全达到预期效果
|
||||
|
||||
**具体应用:**
|
||||
- 验证码已生成,但邮件未真实发送
|
||||
- 功能正常工作,但处于测试/开发模式
|
||||
- 用户可以获得验证码进行测试,但需要知道这不是真实发送
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"data": {
|
||||
"verification_code": "123456",
|
||||
"is_test_mode": true
|
||||
},
|
||||
"message": "⚠️ 测试模式:验证码已生成但未真实发送。请在控制台查看验证码,或配置邮件服务以启用真实发送。",
|
||||
"error_code": "TEST_MODE_ONLY"
|
||||
}
|
||||
```
|
||||
|
||||
## 📧 邮件发送接口状态码
|
||||
|
||||
### 发送邮箱验证码 - POST /auth/send-email-verification
|
||||
|
||||
| 状态码 | 场景 | 响应 |
|
||||
|--------|------|------|
|
||||
| 200 | 邮件真实发送成功 | `{ "success": true, "message": "验证码已发送,请查收邮件" }` |
|
||||
| 206 | 测试模式 | `{ "success": false, "error_code": "TEST_MODE_ONLY", "data": { "verification_code": "123456", "is_test_mode": true } }` |
|
||||
| 400 | 参数错误 | `{ "success": false, "message": "邮箱格式错误" }` |
|
||||
| 429 | 发送频率过高 | `{ "success": false, "message": "发送频率过高,请稍后重试" }` |
|
||||
|
||||
### 发送密码重置验证码 - POST /auth/forgot-password
|
||||
|
||||
| 状态码 | 场景 | 响应 |
|
||||
|--------|------|------|
|
||||
| 200 | 邮件真实发送成功 | `{ "success": true, "message": "验证码已发送,请查收" }` |
|
||||
| 206 | 测试模式 | `{ "success": false, "error_code": "TEST_MODE_ONLY", "data": { "verification_code": "123456", "is_test_mode": true } }` |
|
||||
| 400 | 参数错误 | `{ "success": false, "message": "邮箱格式错误" }` |
|
||||
| 404 | 用户不存在 | `{ "success": false, "message": "用户不存在" }` |
|
||||
|
||||
### 重新发送邮箱验证码 - POST /auth/resend-email-verification
|
||||
|
||||
| 状态码 | 场景 | 响应 |
|
||||
|--------|------|------|
|
||||
| 200 | 邮件真实发送成功 | `{ "success": true, "message": "验证码已重新发送,请查收邮件" }` |
|
||||
| 206 | 测试模式 | `{ "success": false, "error_code": "TEST_MODE_ONLY", "data": { "verification_code": "123456", "is_test_mode": true } }` |
|
||||
| 400 | 邮箱已验证或用户不存在 | `{ "success": false, "message": "邮箱已验证,无需重复验证" }` |
|
||||
| 429 | 发送频率过高 | `{ "success": false, "message": "发送频率过高,请稍后重试" }` |
|
||||
|
||||
## 🔄 模式切换
|
||||
|
||||
### 测试模式 → 真实发送模式
|
||||
|
||||
**配置前(测试模式):**
|
||||
```bash
|
||||
curl -X POST http://localhost:3000/auth/send-email-verification \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email": "test@example.com"}'
|
||||
|
||||
# 响应:206 Partial Content
|
||||
{
|
||||
"success": false,
|
||||
"data": {
|
||||
"verification_code": "123456",
|
||||
"is_test_mode": true
|
||||
},
|
||||
"message": "⚠️ 测试模式:验证码已生成但未真实发送...",
|
||||
"error_code": "TEST_MODE_ONLY"
|
||||
}
|
||||
```
|
||||
|
||||
**配置后(真实发送模式):**
|
||||
```bash
|
||||
# 同样的请求
|
||||
curl -X POST http://localhost:3000/auth/send-email-verification \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"email": "test@example.com"}'
|
||||
|
||||
# 响应:200 OK
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"is_test_mode": false
|
||||
},
|
||||
"message": "验证码已发送,请查收邮件"
|
||||
}
|
||||
```
|
||||
|
||||
## 💡 前端处理建议
|
||||
|
||||
### JavaScript 示例
|
||||
|
||||
```javascript
|
||||
async function sendEmailVerification(email) {
|
||||
try {
|
||||
const response = await fetch('/auth/send-email-verification', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ email }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.status === 200) {
|
||||
// 真实发送成功
|
||||
showSuccess('验证码已发送,请查收邮件');
|
||||
} else if (response.status === 206) {
|
||||
// 测试模式
|
||||
showWarning(`测试模式:验证码是 ${data.data.verification_code}`);
|
||||
showInfo('请配置邮件服务以启用真实发送');
|
||||
} else {
|
||||
// 其他错误
|
||||
showError(data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
showError('网络错误,请稍后重试');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### React 示例
|
||||
|
||||
```jsx
|
||||
const handleSendVerification = async (email) => {
|
||||
try {
|
||||
const response = await fetch('/auth/send-email-verification', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ email }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
switch (response.status) {
|
||||
case 200:
|
||||
setMessage({ type: 'success', text: '验证码已发送,请查收邮件' });
|
||||
break;
|
||||
case 206:
|
||||
setMessage({
|
||||
type: 'warning',
|
||||
text: `测试模式:验证码是 ${data.data.verification_code}`
|
||||
});
|
||||
setShowConfigTip(true);
|
||||
break;
|
||||
case 400:
|
||||
setMessage({ type: 'error', text: data.message });
|
||||
break;
|
||||
case 429:
|
||||
setMessage({ type: 'error', text: '发送频率过高,请稍后重试' });
|
||||
break;
|
||||
default:
|
||||
setMessage({ type: 'error', text: '发送失败,请稍后重试' });
|
||||
}
|
||||
} catch (error) {
|
||||
setMessage({ type: 'error', text: '网络错误,请稍后重试' });
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 🎨 UI 展示建议
|
||||
|
||||
### 测试模式提示
|
||||
|
||||
```html
|
||||
<!-- 成功状态 (200) -->
|
||||
<div class="alert alert-success">
|
||||
✅ 验证码已发送,请查收邮件
|
||||
</div>
|
||||
|
||||
<!-- 测试模式 (206) -->
|
||||
<div class="alert alert-warning">
|
||||
⚠️ 测试模式:验证码是 123456
|
||||
<br>
|
||||
<small>请配置邮件服务以启用真实发送</small>
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 (400+) -->
|
||||
<div class="alert alert-danger">
|
||||
❌ 发送失败:邮箱格式错误
|
||||
</div>
|
||||
```
|
||||
|
||||
## 📝 开发建议
|
||||
|
||||
### 1. 状态码检查
|
||||
|
||||
```javascript
|
||||
// 推荐:明确检查状态码
|
||||
if (response.status === 206) {
|
||||
// 处理测试模式
|
||||
} else if (response.status === 200) {
|
||||
// 处理真实发送
|
||||
}
|
||||
|
||||
// 不推荐:只检查 success 字段
|
||||
if (data.success) {
|
||||
// 可能遗漏测试模式的情况
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 错误处理
|
||||
|
||||
```javascript
|
||||
// 推荐:根据 error_code 进行精确处理
|
||||
switch (data.error_code) {
|
||||
case 'TEST_MODE_ONLY':
|
||||
handleTestMode(data);
|
||||
break;
|
||||
case 'SEND_CODE_FAILED':
|
||||
handleSendFailure(data);
|
||||
break;
|
||||
default:
|
||||
handleGenericError(data);
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 用户体验
|
||||
|
||||
- **测试模式**:清晰提示用户当前处于测试模式
|
||||
- **配置引导**:提供配置邮件服务的链接或说明
|
||||
- **验证码显示**:在测试模式下直接显示验证码
|
||||
- **状态区分**:用不同的颜色和图标区分不同状态
|
||||
|
||||
## 🔗 相关文档
|
||||
|
||||
- [邮件服务配置指南](./EMAIL_CONFIGURATION.md)
|
||||
- [快速启动指南](./QUICK_START.md)
|
||||
- [API 文档](./api/README.md)
|
||||
@@ -25,6 +25,29 @@ Whale Town 采用**业务功能模块化架构**,将代码按业务功能而
|
||||
- **模块化设计** - 每个模块独立完整,可单独测试和部署
|
||||
- **配置驱动** - 通过环境变量控制运行模式和行为
|
||||
|
||||
### 🛠️ 技术栈
|
||||
|
||||
#### 后端技术栈
|
||||
- **框架**: NestJS 11.x (基于Express)
|
||||
- **语言**: TypeScript 5.x
|
||||
- **数据库**: MySQL + TypeORM (生产) / 内存数据库 (开发)
|
||||
- **缓存**: Redis + IORedis (生产) / 文件存储 (开发)
|
||||
- **认证**: JWT + bcrypt
|
||||
- **验证**: class-validator + class-transformer
|
||||
- **文档**: Swagger/OpenAPI
|
||||
- **测试**: Jest + Supertest
|
||||
- **日志**: Pino + nestjs-pino
|
||||
- **WebSocket**: Socket.IO
|
||||
- **邮件**: Nodemailer
|
||||
- **集成**: Zulip API
|
||||
|
||||
#### 前端技术栈
|
||||
- **框架**: React 18.x
|
||||
- **构建工具**: Vite 7.x
|
||||
- **UI库**: Ant Design 5.x
|
||||
- **路由**: React Router DOM 6.x
|
||||
- **语言**: TypeScript 5.x
|
||||
|
||||
### 📊 整体架构图
|
||||
|
||||
```
|
||||
@@ -40,11 +63,11 @@ Whale Town 采用**业务功能模块化架构**,将代码按业务功能而
|
||||
│ 🎯 业务功能模块层 │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ 🔐 用户认证 │ │ 👥 用户管理 │ │ 🛡️ 管理员 │ │
|
||||
│ │ (auth) │ │ (user-mgmt) │ │ (admin) │ │
|
||||
│ │ (auth) │ │ (user_mgmt) │ │ (admin) │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ 🔒 安全防护 │ │ 💬 Zulip集成 │ │ 🔗 共享组件 │ │
|
||||
│ │ (security) │ │ (zulip) │ │ (shared) │ │
|
||||
│ │ 💬 Zulip集成 │ │ 🔗 共享组件 │ │ │ │
|
||||
│ │ (zulip) │ │ (shared) │ │ │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
⬇️
|
||||
@@ -52,11 +75,11 @@ Whale Town 采用**业务功能模块化架构**,将代码按业务功能而
|
||||
│ ⚙️ 核心技术服务层 │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ 🔑 登录核心 │ │ 👑 管理员核心 │ │ 💬 Zulip核心 │ │
|
||||
│ │ (login_core) │ │ (admin_core) │ │ (zulip) │ │
|
||||
│ │ (auth_core) │ │ (admin_core) │ │ (zulip) │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
||||
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
|
||||
│ │ 🛠️ 工具服务 │ │ 📧 邮件服务 │ │ 📝 日志服务 │ │
|
||||
│ │ (utils) │ │ (email) │ │ (logger) │ │
|
||||
│ │ 🛡️ 安全核心 │ │ 🛠️ 工具服务 │ │ 📧 邮件服务 │ │
|
||||
│ │ (security_core)│ │ (utils) │ │ (email) │ │
|
||||
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
⬇️
|
||||
@@ -80,56 +103,50 @@ Whale Town 采用**业务功能模块化架构**,将代码按业务功能而
|
||||
```
|
||||
src/business/
|
||||
├── 📂 auth/ # 🔐 用户认证模块
|
||||
│ ├── 📄 auth.controller.ts # HTTP接口控制器
|
||||
│ ├── 📄 auth.service.ts # 业务逻辑服务
|
||||
│ ├── 📄 auth.module.ts # 模块定义
|
||||
│ ├── 📂 controllers/ # 控制器
|
||||
│ │ └── 📄 login.controller.ts # 登录接口控制器
|
||||
│ ├── 📂 services/ # 业务服务
|
||||
│ │ ├── 📄 login.service.ts # 登录业务逻辑
|
||||
│ │ └── 📄 login.service.spec.ts # 登录服务测试
|
||||
│ ├── 📂 dto/ # 数据传输对象
|
||||
│ │ ├── 📄 login.dto.ts # 登录请求DTO
|
||||
│ │ ├── 📄 register.dto.ts # 注册请求DTO
|
||||
│ │ └── 📄 reset-password.dto.ts # 重置密码DTO
|
||||
│ └── 📂 __tests__/ # 单元测试
|
||||
│ └── 📄 auth.service.spec.ts
|
||||
│ │ └── 📄 login_response.dto.ts # 登录响应DTO
|
||||
│ └── 📂 guards/ # 权限守卫(预留)
|
||||
│
|
||||
├── 📂 user-mgmt/ # 👥 用户管理模块
|
||||
│ ├── 📄 user-mgmt.controller.ts # 用户管理接口
|
||||
│ ├── 📄 user-mgmt.service.ts # 用户状态管理逻辑
|
||||
│ ├── 📄 user-mgmt.module.ts # 模块定义
|
||||
│ ├── 📂 controllers/ # 控制器
|
||||
│ │ └── 📄 user-status.controller.ts # 用户状态管理接口
|
||||
│ ├── 📂 services/ # 业务服务
|
||||
│ │ └── 📄 user-management.service.ts # 用户管理逻辑
|
||||
│ ├── 📂 dto/ # 数据传输对象
|
||||
│ │ ├── 📄 update-status.dto.ts # 状态更新DTO
|
||||
│ │ └── 📄 batch-status.dto.ts # 批量操作DTO
|
||||
│ └── 📂 enums/ # 枚举定义
|
||||
│ └── 📄 user-status.enum.ts # 用户状态枚举
|
||||
│ │ ├── 📄 user-status.dto.ts # 用户状态DTO
|
||||
│ │ └── 📄 user-status-response.dto.ts # 状态响应DTO
|
||||
│ ├── 📂 enums/ # 枚举定义
|
||||
│ │ └── 📄 user-status.enum.ts # 用户状态枚举
|
||||
│ └── 📂 tests/ # 测试文件(预留)
|
||||
│
|
||||
├── 📂 admin/ # 🛡️ 管理员模块
|
||||
│ ├── 📄 admin.controller.ts # 管理员接口
|
||||
│ ├── 📄 admin.service.ts # 管理员业务逻辑
|
||||
│ ├── 📄 admin.module.ts # 模块定义
|
||||
│ ├── 📄 admin.service.spec.ts # 管理员服务测试
|
||||
│ ├── 📂 dto/ # 数据传输对象
|
||||
│ └── 📂 guards/ # 权限守卫
|
||||
│ └── 📄 admin.guard.ts # 管理员权限验证
|
||||
│
|
||||
├── 📂 security/ # 🔒 安全防护模块
|
||||
│ ├── 📄 security.module.ts # 安全模块定义
|
||||
│ ├── 📂 guards/ # 安全守卫
|
||||
│ │ ├── 📄 throttle.guard.ts # 频率限制守卫
|
||||
│ │ ├── 📄 maintenance.guard.ts # 维护模式守卫
|
||||
│ │ └── 📄 content-type.guard.ts # 内容类型守卫
|
||||
│ └── 📂 interceptors/ # 拦截器
|
||||
│ └── 📄 timeout.interceptor.ts # 超时拦截器
|
||||
│
|
||||
├── 📂 zulip/ # 💬 Zulip集成模块
|
||||
│ ├── 📄 zulip.service.ts # Zulip业务服务
|
||||
│ ├── 📄 zulip_websocket.gateway.ts # WebSocket网关
|
||||
│ ├── 📄 zulip.module.ts # 模块定义
|
||||
│ ├── 📂 interfaces/ # 接口定义
|
||||
│ └── 📂 services/ # 子服务
|
||||
│ ├── 📄 message_filter.service.ts # 消息过滤
|
||||
│ └── 📄 session_cleanup.service.ts # 会话清理
|
||||
│
|
||||
└── 📂 shared/ # 🔗 共享业务组件
|
||||
├── 📂 decorators/ # 装饰器
|
||||
├── 📂 pipes/ # 管道
|
||||
├── 📂 filters/ # 异常过滤器
|
||||
└── 📂 interfaces/ # 接口定义
|
||||
├── 📂 dto/ # 共享数据传输对象
|
||||
└── 📄 index.ts # 导出文件
|
||||
```
|
||||
|
||||
### ⚙️ 核心技术服务 (`src/core/`)
|
||||
@@ -139,72 +156,84 @@ src/business/
|
||||
```
|
||||
src/core/
|
||||
├── 📂 db/ # 🗄️ 数据库层
|
||||
│ ├── 📄 db.module.ts # 数据库模块
|
||||
│ ├── 📂 users/ # 用户数据服务
|
||||
│ │ ├── 📄 users.service.ts # MySQL数据库实现
|
||||
│ │ ├── 📄 users-memory.service.ts # 内存数据库实现
|
||||
│ │ ├── 📄 users.interface.ts # 用户服务接口
|
||||
│ │ └── 📄 user.entity.ts # 用户实体定义
|
||||
│ └── 📂 entities/ # 数据库实体
|
||||
│ └── 📄 *.entity.ts # 各种实体定义
|
||||
│ └── 📂 users/ # 用户数据服务
|
||||
│ ├── 📄 users.service.ts # MySQL数据库实现
|
||||
│ ├── 📄 users_memory.service.ts # 内存数据库实现
|
||||
│ ├── 📄 users.dto.ts # 用户数据传输对象
|
||||
│ ├── 📄 users.entity.ts # 用户实体定义
|
||||
│ ├── 📄 users.module.ts # 用户数据模块
|
||||
│ └── 📄 users.service.spec.ts # 用户服务测试
|
||||
│
|
||||
├── 📂 redis/ # 🔴 Redis缓存层
|
||||
│ ├── 📄 redis.module.ts # Redis模块
|
||||
│ ├── 📄 redis.service.ts # Redis真实实现
|
||||
│ ├── 📄 real-redis.service.ts # Redis真实实现
|
||||
│ ├── 📄 file-redis.service.ts # 文件存储实现
|
||||
│ └── 📄 redis.interface.ts # Redis服务接口
|
||||
│
|
||||
├── 📂 login_core/ # 🔑 登录核心服务
|
||||
│ ├── 📄 login-core.service.ts # 登录核心逻辑
|
||||
│ ├── 📄 login-core.module.ts # 模块定义
|
||||
│ └── 📄 login-core.interface.ts # 接口定义
|
||||
│ ├── 📄 login_core.service.ts # 登录核心逻辑
|
||||
│ ├── 📄 login_core.module.ts # 模块定义
|
||||
│ └── 📄 login_core.service.spec.ts # 登录核心测试
|
||||
│
|
||||
├── 📂 admin_core/ # 👑 管理员核心服务
|
||||
│ ├── 📄 admin-core.service.ts # 管理员核心逻辑
|
||||
│ ├── 📄 admin-core.module.ts # 模块定义
|
||||
│ └── 📄 admin-core.interface.ts # 接口定义
|
||||
│ ├── 📄 admin_core.service.ts # 管理员核心逻辑
|
||||
│ ├── 📄 admin_core.module.ts # 模块定义
|
||||
│ └── 📄 admin_core.service.spec.ts # 管理员核心测试
|
||||
│
|
||||
├── 📂 zulip/ # 💬 Zulip核心服务
|
||||
│ ├── 📄 zulip-core.module.ts # Zulip核心模块
|
||||
│ ├── 📄 zulip-api.service.ts # Zulip API服务
|
||||
│ └── 📄 zulip-websocket.service.ts # WebSocket服务
|
||||
│ ├── 📂 config/ # 配置文件
|
||||
│ ├── 📂 interfaces/ # 接口定义
|
||||
│ ├── 📂 services/ # 核心服务
|
||||
│ ├── 📂 types/ # 类型定义
|
||||
│ └── 📄 index.ts # 导出文件
|
||||
│
|
||||
├── 📂 security_core/ # 🛡️ 安全核心模块
|
||||
│ ├── 📄 security_core.module.ts # 安全模块定义
|
||||
│ ├── 📂 guards/ # 安全守卫
|
||||
│ │ └── 📄 throttle.guard.ts # 频率限制守卫
|
||||
│ ├── 📂 interceptors/ # 拦截器
|
||||
│ │ └── 📄 timeout.interceptor.ts # 超时拦截器
|
||||
│ ├── 📂 middleware/ # 中间件
|
||||
│ │ ├── 📄 maintenance.middleware.ts # 维护模式中间件
|
||||
│ │ └── 📄 content_type.middleware.ts # 内容类型中间件
|
||||
│ └── 📂 decorators/ # 装饰器
|
||||
│ ├── 📄 throttle.decorator.ts # 频率限制装饰器
|
||||
│ └── 📄 timeout.decorator.ts # 超时装饰器
|
||||
│
|
||||
└── 📂 utils/ # 🛠️ 工具服务
|
||||
├── 📂 email/ # 📧 邮件服务
|
||||
│ ├── 📄 email.service.ts # 邮件发送服务
|
||||
│ ├── 📄 email.module.ts # 邮件模块
|
||||
│ └── 📄 email.interface.ts # 邮件接口
|
||||
│ └── 📄 email.service.spec.ts # 邮件服务测试
|
||||
├── 📂 verification/ # 🔢 验证码服务
|
||||
│ ├── 📄 verification.service.ts # 验证码生成验证
|
||||
│ └── 📄 verification.module.ts # 验证码模块
|
||||
│ ├── 📄 verification.module.ts # 验证码模块
|
||||
│ └── 📄 verification.service.spec.ts # 验证码服务测试
|
||||
└── 📂 logger/ # 📝 日志服务
|
||||
├── 📄 logger.service.ts # 日志记录服务
|
||||
└── 📄 logger.module.ts # 日志模块
|
||||
├── 📄 logger.module.ts # 日志模块
|
||||
├── 📄 logger.config.ts # 日志配置
|
||||
└── 📄 log_management.service.ts # 日志管理服务
|
||||
```
|
||||
|
||||
### 🎨 前端管理界面 (`client/`)
|
||||
|
||||
> **设计原则**: 独立的前端项目,提供管理员后台功能
|
||||
> **设计原则**: 独立的前端项目,提供管理员后台功能,基于React + Vite + Ant Design
|
||||
|
||||
```
|
||||
client/
|
||||
├── 📂 src/ # 前端源码
|
||||
│ ├── 📂 components/ # 通用组件
|
||||
│ │ ├── 📄 Layout.tsx # 布局组件
|
||||
│ │ ├── 📄 UserTable.tsx # 用户表格组件
|
||||
│ │ └── 📄 LogViewer.tsx # 日志查看组件
|
||||
│ ├── 📂 app/ # 应用组件
|
||||
│ │ ├── 📄 App.tsx # 应用主组件
|
||||
│ │ └── 📄 AdminLayout.tsx # 管理员布局组件
|
||||
│ ├── 📂 pages/ # 页面组件
|
||||
│ │ ├── 📄 Login.tsx # 登录页面
|
||||
│ │ ├── 📄 Dashboard.tsx # 仪表板
|
||||
│ │ ├── 📄 UserManagement.tsx # 用户管理
|
||||
│ │ └── 📄 LogManagement.tsx # 日志管理
|
||||
│ ├── 📂 services/ # API服务
|
||||
│ │ ├── 📄 LoginPage.tsx # 登录页面
|
||||
│ │ ├── 📄 UsersPage.tsx # 用户管理页面
|
||||
│ │ └── 📄 LogsPage.tsx # 日志管理页面
|
||||
│ ├── 📂 lib/ # 工具库
|
||||
│ │ ├── 📄 api.ts # API客户端
|
||||
│ │ ├── 📄 auth.ts # 认证服务
|
||||
│ │ └── 📄 users.ts # 用户服务
|
||||
│ ├── 📂 utils/ # 工具函数
|
||||
│ ├── 📂 types/ # TypeScript类型
|
||||
│ ├── 📄 App.tsx # 应用主组件
|
||||
│ │ └── 📄 adminAuth.ts # 管理员认证服务
|
||||
│ └── 📄 main.tsx # 应用入口
|
||||
├── 📂 dist/ # 构建产物
|
||||
├── 📄 package.json # 前端依赖
|
||||
@@ -220,21 +249,17 @@ client/
|
||||
docs/
|
||||
├── 📄 README.md # 📖 文档导航中心
|
||||
├── 📄 ARCHITECTURE.md # 🏗️ 架构设计文档
|
||||
├── 📄 API_STATUS_CODES.md # 📋 API状态码说明
|
||||
├── 📄 CONTRIBUTORS.md # 🤝 贡献者指南
|
||||
│
|
||||
├── 📂 api/ # 🔌 API接口文档
|
||||
│ ├── 📄 README.md # API文档使用指南
|
||||
│ ├── 📄 api-documentation.md # 完整API接口文档
|
||||
│ ├── 📄 openapi.yaml # OpenAPI规范文件
|
||||
│ └── 📄 postman-collection.json # Postman测试集合
|
||||
│ └── 📄 api-documentation.md # 完整API接口文档
|
||||
│
|
||||
├── 📂 development/ # 💻 开发指南
|
||||
│ ├── 📄 backend_development_guide.md # 后端开发规范
|
||||
│ ├── 📄 git_commit_guide.md # Git提交规范
|
||||
│ ├── 📄 AI辅助开发规范指南.md # AI辅助开发指南
|
||||
│ ├── 📄 TESTING.md # 测试指南
|
||||
│ └── 📄 naming_convention.md # 命名规范
|
||||
│ └── 📄 TESTING.md # 测试指南
|
||||
│
|
||||
└── 📂 deployment/ # 🚀 部署文档
|
||||
└── 📄 DEPLOYMENT.md # 生产环境部署指南
|
||||
@@ -261,14 +286,17 @@ test/
|
||||
├── 📄 .env # 🔧 环境变量配置
|
||||
├── 📄 .env.example # 🔧 环境变量示例
|
||||
├── 📄 .env.production.example # 🔧 生产环境示例
|
||||
├── 📄 package.json # 📋 项目依赖配置
|
||||
├── 📄 package.json # 📋 后端项目依赖配置
|
||||
├── 📄 pnpm-workspace.yaml # 📦 pnpm工作空间配置
|
||||
├── 📄 tsconfig.json # 📘 TypeScript配置
|
||||
├── 📄 jest.config.js # 🧪 Jest测试配置
|
||||
├── 📄 nest-cli.json # 🏠 NestJS CLI配置
|
||||
├── 📄 docker-compose.yml # 🐳 Docker编排配置
|
||||
├── 📄 Dockerfile # 🐳 Docker镜像配置
|
||||
└── 📄 ecosystem.config.js # 🚀 PM2进程管理配置
|
||||
|
||||
client/
|
||||
├── 📄 package.json # 📋 前端项目依赖配置
|
||||
├── 📄 vite.config.ts # ⚡ Vite构建配置
|
||||
└── 📄 tsconfig.json # 📘 前端TypeScript配置
|
||||
```
|
||||
|
||||
---
|
||||
@@ -327,18 +355,17 @@ test/
|
||||
|
||||
### 🔄 数据流向
|
||||
|
||||
#### 用户注册流程示例
|
||||
#### 用户登录流程示例
|
||||
|
||||
```
|
||||
1. 📱 用户请求 → AuthController.register()
|
||||
1. 📱 用户请求 → LoginController.login()
|
||||
2. 🔍 参数验证 → class-validator装饰器
|
||||
3. 🎯 业务逻辑 → AuthService.register()
|
||||
4. ⚙️ 核心服务 → LoginCoreService.createUser()
|
||||
5. 📧 发送邮件 → EmailService.sendVerificationCode()
|
||||
6. 🔢 生成验证码 → VerificationService.generate()
|
||||
7. 💾 存储数据 → UsersService.create() + RedisService.set()
|
||||
8. 📝 记录日志 → LoggerService.log()
|
||||
9. ✅ 返回响应 → 用户收到成功响应
|
||||
3. 🎯 业务逻辑 → LoginService.login()
|
||||
4. ⚙️ 核心服务 → LoginCoreService.validateUser()
|
||||
5. 📧 发送验证码 → VerificationService.generate()
|
||||
6. 💾 存储数据 → UsersService.findByEmail() + RedisService.set()
|
||||
7. 📝 记录日志 → LoggerService.log()
|
||||
8. ✅ 返回响应 → 用户收到登录结果
|
||||
```
|
||||
|
||||
#### 管理员操作流程示例
|
||||
@@ -369,7 +396,7 @@ test/
|
||||
| 功能模块 | 🧪 开发测试模式 | 🚀 生产部署模式 |
|
||||
|----------|----------------|----------------|
|
||||
| **数据库** | 内存存储 (UsersMemoryService) | MySQL (UsersService + TypeORM) |
|
||||
| **缓存** | 文件存储 (FileRedisService) | Redis (RedisService + IORedis) |
|
||||
| **缓存** | 文件存储 (FileRedisService) | Redis (RealRedisService + IORedis) |
|
||||
| **邮件** | 控制台输出 (测试模式) | SMTP服务器 (生产模式) |
|
||||
| **日志** | 控制台 + 文件 | 结构化日志 + 日志轮转 |
|
||||
| **配置** | `.env` 默认配置 | 环境变量 + 配置中心 |
|
||||
@@ -431,7 +458,7 @@ EMAIL_PASS=your_app_password
|
||||
const useFileRedis = configService.get<boolean>('USE_FILE_REDIS');
|
||||
return useFileRedis
|
||||
? new FileRedisService()
|
||||
: new RedisService(configService);
|
||||
: new RealRedisService(configService);
|
||||
},
|
||||
inject: [ConfigService],
|
||||
},
|
||||
@@ -471,7 +498,7 @@ AppModule (应用主模块)
|
||||
├── 📊 ConfigModule (全局配置)
|
||||
├── 📝 LoggerModule (日志系统)
|
||||
├── 🔴 RedisModule (缓存服务)
|
||||
│ ├── RedisService (真实Redis)
|
||||
│ ├── RealRedisService (真实Redis)
|
||||
│ └── FileRedisService (文件存储)
|
||||
├── 🗄️ UsersModule (用户数据)
|
||||
│ ├── UsersService (MySQL数据库)
|
||||
@@ -481,16 +508,15 @@ AppModule (应用主模块)
|
||||
├── 🔑 LoginCoreModule (登录核心)
|
||||
├── 👑 AdminCoreModule (管理员核心)
|
||||
├── 💬 ZulipCoreModule (Zulip核心)
|
||||
├── 🔒 SecurityCoreModule (安全核心)
|
||||
│
|
||||
├── 🎯 业务功能模块
|
||||
│ ├── 🔐 AuthModule (用户认证)
|
||||
│ │ └── 依赖: LoginCoreModule, EmailModule, VerificationModule
|
||||
│ │ └── 依赖: LoginCoreModule, EmailModule, VerificationModule, SecurityCoreModule
|
||||
│ ├── 👥 UserMgmtModule (用户管理)
|
||||
│ │ └── 依赖: UsersModule, LoggerModule
|
||||
│ │ └── 依赖: UsersModule, LoggerModule, SecurityCoreModule
|
||||
│ ├── 🛡️ AdminModule (管理员)
|
||||
│ │ └── 依赖: AdminCoreModule, UsersModule
|
||||
│ ├── 🔒 SecurityModule (安全防护)
|
||||
│ │ └── 依赖: RedisModule, LoggerModule
|
||||
│ │ └── 依赖: AdminCoreModule, UsersModule, SecurityCoreModule
|
||||
│ ├── 💬 ZulipModule (Zulip集成)
|
||||
│ │ └── 依赖: ZulipCoreModule, RedisModule
|
||||
│ └── 🔗 SharedModule (共享组件)
|
||||
@@ -500,7 +526,7 @@ AppModule (应用主模块)
|
||||
|
||||
#### 用户认证流程
|
||||
```
|
||||
AuthController → AuthService → LoginCoreService
|
||||
AuthController → LoginService → LoginCoreService
|
||||
↓
|
||||
EmailService ← VerificationService ← RedisService
|
||||
↓
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
# 📝 文档清理说明
|
||||
|
||||
> 记录项目文档整理和优化的过程,确保文档结构清晰、内容准确。
|
||||
|
||||
## 🎯 清理目标
|
||||
|
||||
- **删除多余README** - 移除重复和过时的README文件
|
||||
- **优化主文档** - 改进项目主README的文件格式和结构说明
|
||||
- **完善架构文档** - 详细说明项目架构和文件夹组织结构
|
||||
- **统一文档风格** - 采用总分结构,方便开发者理解
|
||||
|
||||
## 📊 文档清理结果
|
||||
|
||||
### ✅ 保留的README文件
|
||||
|
||||
| 文件路径 | 保留原因 | 主要内容 |
|
||||
|----------|----------|----------|
|
||||
| `README.md` | 项目主文档 | 项目介绍、快速开始、技术栈、功能特性 |
|
||||
| `docs/README.md` | 文档导航中心 | 文档结构说明、导航链接 |
|
||||
| `client/README.md` | 前端项目文档 | 前端管理界面的独立说明 |
|
||||
| `docs/api/README.md` | API文档指南 | API文档使用说明和快速测试 |
|
||||
| `src/business/zulip/README.md` | 模块架构说明 | Zulip模块重构的详细说明 |
|
||||
|
||||
### ❌ 删除的README文件
|
||||
|
||||
**无** - 经过分析,所有现有README文件都有其存在价值,未删除任何文件。
|
||||
|
||||
### 🔄 优化的文档
|
||||
|
||||
#### 1. 主README.md优化
|
||||
- **文件结构总览** - 添加了详细的项目文件结构说明
|
||||
- **图标化展示** - 使用emoji图标让结构更直观
|
||||
- **层次化组织** - 按照总分结构组织内容
|
||||
|
||||
#### 2. 架构文档大幅改进 (docs/ARCHITECTURE.md)
|
||||
- **完整重写** - 从简单的架构图扩展为完整的架构设计文档
|
||||
- **目录结构详解** - 详细说明每个文件夹的作用和内容
|
||||
- **分层架构设计** - 清晰的架构分层和模块依赖关系
|
||||
- **双模式架构** - 详细说明开发测试模式和生产部署模式
|
||||
- **扩展指南** - 提供添加新模块和功能的详细指导
|
||||
|
||||
## 📁 文档结构优化
|
||||
|
||||
### 🎯 总分结构设计
|
||||
|
||||
采用**总分结构**组织文档,便于开发者快速理解:
|
||||
|
||||
```
|
||||
📚 文档层次结构
|
||||
├── 🏠 项目总览 (README.md)
|
||||
│ ├── 🎯 项目简介和特性
|
||||
│ ├── 🚀 快速开始指南
|
||||
│ ├── 📁 文件结构总览 ⭐ 新增
|
||||
│ ├── 🛠️ 技术栈说明
|
||||
│ └── 📚 文档导航链接
|
||||
│
|
||||
├── 🏗️ 架构设计 (docs/ARCHITECTURE.md) ⭐ 大幅改进
|
||||
│ ├── 📊 整体架构图
|
||||
│ ├── 📁 目录结构详解
|
||||
│ ├── 🏗️ 分层架构设计
|
||||
│ ├── 🔄 双模式架构
|
||||
│ └── 🚀 扩展指南
|
||||
│
|
||||
├── 📖 文档中心 (docs/README.md)
|
||||
│ ├── 📋 文档导航
|
||||
│ ├── 🏗️ 文档结构说明
|
||||
│ └── 📝 文档维护原则
|
||||
│
|
||||
├── 🔌 API文档 (docs/api/README.md)
|
||||
│ ├── 📊 API接口概览
|
||||
│ ├── 🚀 快速开始
|
||||
│ └── 🧪 测试指南
|
||||
│
|
||||
└── 🎨 前端文档 (client/README.md)
|
||||
├── 🚀 快速开始
|
||||
├── 🎯 核心功能
|
||||
└── 🔧 开发指南
|
||||
```
|
||||
|
||||
### 📊 文档内容优化
|
||||
|
||||
#### 1. 视觉化改进
|
||||
- **emoji图标** - 使用统一的emoji图标系统
|
||||
- **表格展示** - 用表格清晰展示对比信息
|
||||
- **代码示例** - 提供完整的代码示例和配置
|
||||
- **架构图** - 使用ASCII艺术绘制清晰的架构图
|
||||
|
||||
#### 2. 结构化内容
|
||||
- **目录导航** - 每个长文档都有详细目录
|
||||
- **分层说明** - 按照业务功能模块化的原则组织
|
||||
- **实用指南** - 提供具体的操作步骤和扩展指南
|
||||
|
||||
#### 3. 开发者友好
|
||||
- **快速上手** - 新开发者指南,从规范学习到架构理解
|
||||
- **总分结构** - 先总览后详细,便于快速理解
|
||||
- **实际案例** - 提供真实的代码示例和使用场景
|
||||
|
||||
## 🎯 文档维护原则
|
||||
|
||||
### ✅ 保留标准
|
||||
- **长期价值** - 对整个项目生命周期都有价值
|
||||
- **参考价值** - 开发、部署、维护时需要查阅
|
||||
- **规范指导** - 团队协作和代码质量保证
|
||||
|
||||
### ❌ 清理标准
|
||||
- **阶段性文档** - 只在特定开发阶段有用
|
||||
- **临时记录** - 会议记录、临时决策等
|
||||
- **过时信息** - 已经不适用的旧版本文档
|
||||
|
||||
### 🔄 更新策略
|
||||
- **及时更新** - 功能变更时同步更新相关文档
|
||||
- **版本控制** - 重要变更记录版本历史
|
||||
- **定期审查** - 定期检查文档的准确性和有效性
|
||||
|
||||
## 📈 改进效果
|
||||
|
||||
### 🎯 开发者体验提升
|
||||
- **快速理解** - 通过总分结构快速掌握项目架构
|
||||
- **准确信息** - 文档与实际代码结构完全一致
|
||||
- **实用指导** - 提供具体的开发和扩展指南
|
||||
|
||||
### 📚 文档质量提升
|
||||
- **结构清晰** - 层次分明的文档组织结构
|
||||
- **内容完整** - 覆盖项目的所有重要方面
|
||||
- **易于维护** - 明确的维护原则和更新策略
|
||||
|
||||
### 🚀 项目可维护性提升
|
||||
- **架构清晰** - 详细的架构文档便于理解和扩展
|
||||
- **规范统一** - 统一的文档风格和组织原则
|
||||
- **知识传承** - 完整的文档体系便于团队协作
|
||||
|
||||
---
|
||||
|
||||
**📝 通过系统性的文档清理和优化,项目文档现在更加清晰、准确、实用!**
|
||||
|
||||
## 📅 清理记录
|
||||
|
||||
- **清理时间**: 2025年12月31日
|
||||
- **清理范围**: 项目根目录及所有子目录的README文件
|
||||
- **主要改进**: 架构文档完全重写,主README结构优化
|
||||
- **保留文件**: 5个README文件全部保留
|
||||
- **删除文件**: 0个(所有文件都有价值)
|
||||
@@ -3,6 +3,12 @@
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
"deleteOutDir": true,
|
||||
"assets": [
|
||||
{
|
||||
"include": "../config/**/*",
|
||||
"outDir": "./dist"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ import { ZulipModule } from './business/zulip/zulip.module';
|
||||
import { RedisModule } from './core/redis/redis.module';
|
||||
import { AdminModule } from './business/admin/admin.module';
|
||||
import { UserMgmtModule } from './business/user-mgmt/user-mgmt.module';
|
||||
import { SecurityModule } from './business/security/security.module';
|
||||
import { MaintenanceMiddleware } from './business/security/middleware/maintenance.middleware';
|
||||
import { ContentTypeMiddleware } from './business/security/middleware/content-type.middleware';
|
||||
import { SecurityCoreModule } from './core/security_core/security_core.module';
|
||||
import { MaintenanceMiddleware } from './core/security_core/middleware/maintenance.middleware';
|
||||
import { ContentTypeMiddleware } from './core/security_core/middleware/content_type.middleware';
|
||||
|
||||
/**
|
||||
* 检查数据库配置是否完整 by angjustinl 2025-12-17
|
||||
@@ -71,7 +71,7 @@ function isDatabaseConfigured(): boolean {
|
||||
ZulipModule,
|
||||
UserMgmtModule,
|
||||
AdminModule,
|
||||
SecurityModule,
|
||||
SecurityCoreModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
AdminUserResponseDto,
|
||||
AdminRuntimeLogsResponseDto
|
||||
} from './dto/admin-response.dto';
|
||||
import { Throttle, ThrottlePresets } from '../security/decorators/throttle.decorator';
|
||||
import { Throttle, ThrottlePresets } from '../../core/security_core/decorators/throttle.decorator';
|
||||
import type { Response } from 'express';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
@@ -33,8 +33,8 @@ import {
|
||||
TestModeEmailVerificationResponseDto,
|
||||
SuccessEmailVerificationResponseDto
|
||||
} from '../dto/login_response.dto';
|
||||
import { Throttle, ThrottlePresets } from '../../security/decorators/throttle.decorator';
|
||||
import { Timeout, TimeoutPresets } from '../../security/decorators/timeout.decorator';
|
||||
import { Throttle, ThrottlePresets } from '../../../core/security_core/decorators/throttle.decorator';
|
||||
import { Timeout, TimeoutPresets } from '../../../core/security_core/decorators/timeout.decorator';
|
||||
|
||||
@ApiTags('auth')
|
||||
@Controller('auth')
|
||||
|
||||
@@ -20,8 +20,8 @@ import { Body, Controller, Get, HttpCode, HttpStatus, Param, Put, Post, UseGuard
|
||||
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
import { AdminGuard } from '../../admin/guards/admin.guard';
|
||||
import { UserManagementService } from '../services/user-management.service';
|
||||
import { Throttle, ThrottlePresets } from '../../security/decorators/throttle.decorator';
|
||||
import { Timeout, TimeoutPresets } from '../../security/decorators/timeout.decorator';
|
||||
import { Throttle, ThrottlePresets } from '../../../core/security_core/decorators/throttle.decorator';
|
||||
import { Timeout, TimeoutPresets } from '../../../core/security_core/decorators/timeout.decorator';
|
||||
import { UserStatusDto, BatchUserStatusDto } from '../dto/user-status.dto';
|
||||
import { UserStatusResponseDto, BatchUserStatusResponseDto, UserStatusStatsResponseDto } from '../dto/user-status-response.dto';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* 安全功能模块导出
|
||||
* 核心安全模块导出
|
||||
*
|
||||
* 功能概述:
|
||||
* - 频率限制和防护机制
|
||||
@@ -10,14 +10,14 @@
|
||||
*/
|
||||
|
||||
// 模块
|
||||
export * from './security.module';
|
||||
export * from './security_core.module';
|
||||
|
||||
// 守卫
|
||||
export * from './guards/throttle.guard';
|
||||
|
||||
// 中间件
|
||||
export * from './middleware/maintenance.middleware';
|
||||
export * from './middleware/content-type.middleware';
|
||||
export * from './middleware/content_type.middleware';
|
||||
|
||||
// 拦截器
|
||||
export * from './interceptors/timeout.interceptor';
|
||||
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* 安全功能模块
|
||||
* 核心安全模块
|
||||
*
|
||||
* 功能描述:
|
||||
* - 整合所有安全相关功能
|
||||
* - 提供系统级安全防护功能
|
||||
* - 频率限制和请求超时控制
|
||||
* - 维护模式和内容类型验证
|
||||
* - 系统安全防护机制
|
||||
* - 全局安全中间件和守卫
|
||||
*
|
||||
* @author kiro-ai
|
||||
* @version 1.0.0
|
||||
@@ -34,4 +34,4 @@ import { TimeoutInterceptor } from './interceptors/timeout.interceptor';
|
||||
],
|
||||
exports: [ThrottleGuard, TimeoutInterceptor],
|
||||
})
|
||||
export class SecurityModule {}
|
||||
export class SecurityCoreModule {}
|
||||
@@ -139,10 +139,39 @@ export class ConfigManagerService implements OnModuleDestroy {
|
||||
private configLoadTime: Date;
|
||||
private configWatcher: fs.FSWatcher | null = null;
|
||||
private isWatcherEnabled: boolean = false;
|
||||
private readonly CONFIG_DIR = path.join(process.cwd(), 'config', 'zulip');
|
||||
private readonly CONFIG_DIR = this.getConfigDir();
|
||||
private readonly MAP_CONFIG_FILE = 'map-config.json';
|
||||
private readonly logger = new Logger(ConfigManagerService.name);
|
||||
|
||||
/**
|
||||
* 获取配置目录路径
|
||||
*
|
||||
* 在开发环境中使用 config/zulip
|
||||
* 在生产环境中使用 dist/zulip (编译后的位置)
|
||||
*/
|
||||
private getConfigDir(): string {
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production';
|
||||
|
||||
if (isDevelopment) {
|
||||
// 开发环境:使用源码目录
|
||||
return path.join(process.cwd(), 'config', 'zulip');
|
||||
} else {
|
||||
// 生产环境:使用编译后的目录
|
||||
const distConfigPath = path.join(process.cwd(), 'dist', 'zulip');
|
||||
const rootConfigPath = path.join(process.cwd(), 'config', 'zulip');
|
||||
|
||||
// 优先使用 dist/zulip,如果不存在则回退到 config/zulip
|
||||
if (fs.existsSync(distConfigPath)) {
|
||||
return distConfigPath;
|
||||
} else if (fs.existsSync(rootConfigPath)) {
|
||||
return rootConfigPath;
|
||||
} else {
|
||||
// 都不存在,使用默认路径
|
||||
return distConfigPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.logger.log('ConfigManagerService初始化完成');
|
||||
|
||||
|
||||
@@ -1,333 +0,0 @@
|
||||
# Comprehensive API Test Script
|
||||
# 综合API测试脚本 - 完整的后端功能测试
|
||||
#
|
||||
# 🧪 测试内容:
|
||||
# 1. 基础API功能(应用状态、注册、登录)
|
||||
# 2. 邮箱验证码流程(发送、验证、冲突检测)
|
||||
# 3. 验证码冷却时间清除功能
|
||||
# 4. 限流保护机制
|
||||
# 5. 密码重置流程
|
||||
# 6. 验证码登录功能
|
||||
# 7. 错误处理和边界条件
|
||||
#
|
||||
# 🚀 使用方法:
|
||||
# .\test-comprehensive.ps1 # 运行完整测试
|
||||
# .\test-comprehensive.ps1 -SkipThrottleTest # 跳过限流测试
|
||||
# .\test-comprehensive.ps1 -SkipCooldownTest # 跳过冷却测试
|
||||
# .\test-comprehensive.ps1 -BaseUrl "https://your-server.com" # 测试远程服务器
|
||||
|
||||
param(
|
||||
[string]$BaseUrl = "http://localhost:3000",
|
||||
[switch]$SkipThrottleTest = $false,
|
||||
[switch]$SkipCooldownTest = $false
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Continue"
|
||||
|
||||
Write-Host "🧪 Comprehensive API Test Suite" -ForegroundColor Green
|
||||
Write-Host "===============================" -ForegroundColor Green
|
||||
Write-Host "Base URL: $BaseUrl" -ForegroundColor Yellow
|
||||
Write-Host "Skip Throttle Test: $SkipThrottleTest" -ForegroundColor Yellow
|
||||
Write-Host "Skip Cooldown Test: $SkipCooldownTest" -ForegroundColor Yellow
|
||||
|
||||
# Helper function to handle API responses
|
||||
function Test-ApiCall {
|
||||
param(
|
||||
[string]$TestName,
|
||||
[string]$Url,
|
||||
[string]$Body,
|
||||
[string]$Method = "POST",
|
||||
[int]$ExpectedStatus = 200,
|
||||
[switch]$Silent = $false
|
||||
)
|
||||
|
||||
if (-not $Silent) {
|
||||
Write-Host "`n📋 $TestName" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
try {
|
||||
$response = Invoke-RestMethod -Uri $Url -Method $Method -Body $Body -ContentType "application/json" -ErrorAction Stop
|
||||
if (-not $Silent) {
|
||||
Write-Host "✅ SUCCESS ($(if ($response.success) { 'true' } else { 'false' }))" -ForegroundColor Green
|
||||
Write-Host "Message: $($response.message)" -ForegroundColor Cyan
|
||||
}
|
||||
return $response
|
||||
} catch {
|
||||
$statusCode = $_.Exception.Response.StatusCode.value__
|
||||
if (-not $Silent) {
|
||||
Write-Host "❌ FAILED ($statusCode)" -ForegroundColor $(if ($statusCode -eq $ExpectedStatus) { "Yellow" } else { "Red" })
|
||||
}
|
||||
|
||||
if ($_.Exception.Response) {
|
||||
$stream = $_.Exception.Response.GetResponseStream()
|
||||
$reader = New-Object System.IO.StreamReader($stream)
|
||||
$responseBody = $reader.ReadToEnd()
|
||||
$reader.Close()
|
||||
$stream.Close()
|
||||
|
||||
if ($responseBody) {
|
||||
try {
|
||||
$errorResponse = $responseBody | ConvertFrom-Json
|
||||
if (-not $Silent) {
|
||||
Write-Host "Message: $($errorResponse.message)" -ForegroundColor Cyan
|
||||
Write-Host "Error Code: $($errorResponse.error_code)" -ForegroundColor Gray
|
||||
}
|
||||
return $errorResponse
|
||||
} catch {
|
||||
if (-not $Silent) {
|
||||
Write-Host "Raw Response: $responseBody" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
# Clear throttle first
|
||||
Write-Host "`n🔄 Clearing throttle records..." -ForegroundColor Blue
|
||||
try {
|
||||
Invoke-RestMethod -Uri "$BaseUrl/auth/debug-clear-throttle" -Method POST | Out-Null
|
||||
Write-Host "✅ Throttle cleared" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "⚠️ Could not clear throttle" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Test Results Tracking
|
||||
$testResults = @{
|
||||
AppStatus = $false
|
||||
BasicAPI = $false
|
||||
EmailConflict = $false
|
||||
VerificationCodeLogin = $false
|
||||
CooldownClearing = $false
|
||||
ThrottleProtection = $false
|
||||
PasswordReset = $false
|
||||
}
|
||||
|
||||
Write-Host "`n" + "="*60 -ForegroundColor Cyan
|
||||
Write-Host "🧪 Test Suite 0: Application Status" -ForegroundColor Cyan
|
||||
Write-Host "="*60 -ForegroundColor Cyan
|
||||
|
||||
# Test application status
|
||||
$result0 = Test-ApiCall -TestName "Check application status" -Url "$BaseUrl" -Method "GET" -Body ""
|
||||
|
||||
if ($result0 -and $result0.service -eq "Pixel Game Server") {
|
||||
$testResults.AppStatus = $true
|
||||
Write-Host "✅ PASS: Application is running" -ForegroundColor Green
|
||||
Write-Host " Service: $($result0.service)" -ForegroundColor Cyan
|
||||
Write-Host " Version: $($result0.version)" -ForegroundColor Cyan
|
||||
Write-Host " Environment: $($result0.environment)" -ForegroundColor Cyan
|
||||
} else {
|
||||
Write-Host "❌ FAIL: Application status check failed" -ForegroundColor Red
|
||||
}
|
||||
|
||||
Write-Host "`n" + "="*60 -ForegroundColor Cyan
|
||||
Write-Host "🧪 Test Suite 1: Basic API Functionality" -ForegroundColor Cyan
|
||||
Write-Host "="*60 -ForegroundColor Cyan
|
||||
|
||||
# Generate unique test data
|
||||
$testEmail = "comprehensive_test_$(Get-Random)@example.com"
|
||||
$testUsername = "comp_test_$(Get-Random)"
|
||||
|
||||
# Test 1: Send verification code
|
||||
$result1 = Test-ApiCall -TestName "Send email verification code" -Url "$BaseUrl/auth/send-email-verification" -Body (@{
|
||||
email = $testEmail
|
||||
} | ConvertTo-Json)
|
||||
|
||||
if ($result1 -and $result1.data.verification_code) {
|
||||
$verificationCode = $result1.data.verification_code
|
||||
Write-Host "Got verification code: $verificationCode" -ForegroundColor Green
|
||||
|
||||
# Test 2: Register user
|
||||
$result2 = Test-ApiCall -TestName "Register new user" -Url "$BaseUrl/auth/register" -Body (@{
|
||||
username = $testUsername
|
||||
password = "password123"
|
||||
nickname = "Comprehensive Test User"
|
||||
email = $testEmail
|
||||
email_verification_code = $verificationCode
|
||||
} | ConvertTo-Json)
|
||||
|
||||
if ($result2 -and $result2.success) {
|
||||
# Test 3: Login user
|
||||
$result3 = Test-ApiCall -TestName "Login with registered user" -Url "$BaseUrl/auth/login" -Body (@{
|
||||
identifier = $testUsername
|
||||
password = "password123"
|
||||
} | ConvertTo-Json)
|
||||
|
||||
if ($result3 -and $result3.success) {
|
||||
$testResults.BasicAPI = $true
|
||||
Write-Host "✅ PASS: Basic API functionality working" -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`n" + "="*60 -ForegroundColor Cyan
|
||||
Write-Host "🧪 Test Suite 2: Email Conflict Detection" -ForegroundColor Cyan
|
||||
Write-Host "="*60 -ForegroundColor Cyan
|
||||
|
||||
# Test email conflict detection
|
||||
$result4 = Test-ApiCall -TestName "Test email conflict detection" -Url "$BaseUrl/auth/send-email-verification" -Body (@{
|
||||
email = $testEmail
|
||||
} | ConvertTo-Json) -ExpectedStatus 409
|
||||
|
||||
if ($result4 -and $result4.message -like "*已被注册*") {
|
||||
$testResults.EmailConflict = $true
|
||||
Write-Host "✅ PASS: Email conflict detection working" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "❌ FAIL: Email conflict detection not working" -ForegroundColor Red
|
||||
}
|
||||
|
||||
Write-Host "`n" + "="*60 -ForegroundColor Cyan
|
||||
Write-Host "🧪 Test Suite 3: Verification Code Login" -ForegroundColor Cyan
|
||||
Write-Host "="*60 -ForegroundColor Cyan
|
||||
|
||||
# Test verification code login
|
||||
if ($result2 -and $result2.success) {
|
||||
$userEmail = $result2.data.user.email
|
||||
|
||||
# Send login verification code
|
||||
$result4a = Test-ApiCall -TestName "Send login verification code" -Url "$BaseUrl/auth/send-login-verification-code" -Body (@{
|
||||
identifier = $userEmail
|
||||
} | ConvertTo-Json)
|
||||
|
||||
if ($result4a -and $result4a.data.verification_code) {
|
||||
$loginCode = $result4a.data.verification_code
|
||||
|
||||
# Login with verification code
|
||||
$result4b = Test-ApiCall -TestName "Login with verification code" -Url "$BaseUrl/auth/verification-code-login" -Body (@{
|
||||
identifier = $userEmail
|
||||
verification_code = $loginCode
|
||||
} | ConvertTo-Json)
|
||||
|
||||
if ($result4b -and $result4b.success) {
|
||||
$testResults.VerificationCodeLogin = $true
|
||||
Write-Host "✅ PASS: Verification code login working" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "❌ FAIL: Verification code login failed" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $SkipCooldownTest) {
|
||||
Write-Host "`n" + "="*60 -ForegroundColor Cyan
|
||||
Write-Host "🧪 Test Suite 4: Cooldown Clearing & Password Reset" -ForegroundColor Cyan
|
||||
Write-Host "="*60 -ForegroundColor Cyan
|
||||
|
||||
# Test cooldown clearing with password reset
|
||||
if ($result2 -and $result2.success) {
|
||||
$userEmail = $result2.data.user.email
|
||||
|
||||
# Send password reset code
|
||||
$result5 = Test-ApiCall -TestName "Send password reset code" -Url "$BaseUrl/auth/forgot-password" -Body (@{
|
||||
identifier = $userEmail
|
||||
} | ConvertTo-Json)
|
||||
|
||||
if ($result5 -and $result5.data.verification_code) {
|
||||
$resetCode = $result5.data.verification_code
|
||||
|
||||
# Reset password
|
||||
$result6 = Test-ApiCall -TestName "Reset password (should clear cooldown)" -Url "$BaseUrl/auth/reset-password" -Body (@{
|
||||
identifier = $userEmail
|
||||
verification_code = $resetCode
|
||||
new_password = "newpassword123"
|
||||
} | ConvertTo-Json)
|
||||
|
||||
if ($result6 -and $result6.success) {
|
||||
$testResults.PasswordReset = $true
|
||||
Write-Host "✅ PASS: Password reset working" -ForegroundColor Green
|
||||
|
||||
# Test immediate code sending (should work if cooldown cleared)
|
||||
Start-Sleep -Seconds 1
|
||||
$result7 = Test-ApiCall -TestName "Send reset code immediately (test cooldown clearing)" -Url "$BaseUrl/auth/forgot-password" -Body (@{
|
||||
identifier = $userEmail
|
||||
} | ConvertTo-Json)
|
||||
|
||||
if ($result7 -and $result7.success) {
|
||||
$testResults.CooldownClearing = $true
|
||||
Write-Host "✅ PASS: Cooldown clearing working" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "❌ FAIL: Cooldown not cleared properly" -ForegroundColor Red
|
||||
}
|
||||
} else {
|
||||
Write-Host "❌ FAIL: Password reset failed" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $SkipThrottleTest) {
|
||||
Write-Host "`n" + "="*60 -ForegroundColor Cyan
|
||||
Write-Host "🧪 Test Suite 5: Throttle Protection" -ForegroundColor Cyan
|
||||
Write-Host "="*60 -ForegroundColor Cyan
|
||||
|
||||
$successCount = 0
|
||||
$throttleCount = 0
|
||||
|
||||
Write-Host "Testing throttle limits (making 12 registration requests)..." -ForegroundColor Yellow
|
||||
|
||||
for ($i = 1; $i -le 12; $i++) {
|
||||
$result = Test-ApiCall -TestName "Registration attempt $i" -Url "$BaseUrl/auth/register" -Body (@{
|
||||
username = "throttle_test_$i"
|
||||
password = "password123"
|
||||
nickname = "Throttle Test $i"
|
||||
} | ConvertTo-Json) -Silent
|
||||
|
||||
if ($result -and $result.success) {
|
||||
$successCount++
|
||||
Write-Host " Request $i`: ✅ Success" -ForegroundColor Green
|
||||
} else {
|
||||
$throttleCount++
|
||||
Write-Host " Request $i`: 🚦 Throttled" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Start-Sleep -Milliseconds 100
|
||||
}
|
||||
|
||||
Write-Host "`nThrottle Results: $successCount success, $throttleCount throttled" -ForegroundColor Cyan
|
||||
|
||||
if ($successCount -ge 8 -and $throttleCount -ge 1) {
|
||||
$testResults.ThrottleProtection = $true
|
||||
Write-Host "✅ PASS: Throttle protection working" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "❌ FAIL: Throttle protection not working properly" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`n🎯 Test Results Summary" -ForegroundColor Green
|
||||
Write-Host "=======================" -ForegroundColor Green
|
||||
|
||||
$passCount = 0
|
||||
$totalTests = 0
|
||||
|
||||
foreach ($test in $testResults.GetEnumerator()) {
|
||||
$totalTests++
|
||||
if ($test.Value) {
|
||||
$passCount++
|
||||
Write-Host "✅ $($test.Key): PASS" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "❌ $($test.Key): FAIL" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "`n📊 Overall Result: $passCount/$totalTests tests passed" -ForegroundColor $(if ($passCount -eq $totalTests) { "Green" } else { "Yellow" })
|
||||
|
||||
if ($passCount -eq $totalTests) {
|
||||
Write-Host "🎉 All tests passed! API is working correctly." -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "⚠️ Some tests failed. Please check the implementation." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Host "`n💡 Usage Tips:" -ForegroundColor Cyan
|
||||
Write-Host " • Use -SkipThrottleTest to skip throttle testing" -ForegroundColor White
|
||||
Write-Host " • Use -SkipCooldownTest to skip cooldown testing" -ForegroundColor White
|
||||
Write-Host " • Check server logs for detailed error information" -ForegroundColor White
|
||||
Write-Host " • For production testing: .\test-comprehensive.ps1 -BaseUrl 'https://your-server.com'" -ForegroundColor White
|
||||
|
||||
Write-Host "`n📋 Test Coverage:" -ForegroundColor Cyan
|
||||
Write-Host " ✓ Application Status & Health Check" -ForegroundColor White
|
||||
Write-Host " ✓ User Registration & Login Flow" -ForegroundColor White
|
||||
Write-Host " ✓ Email Verification & Conflict Detection" -ForegroundColor White
|
||||
Write-Host " ✓ Verification Code Login" -ForegroundColor White
|
||||
Write-Host " ✓ Password Reset Flow" -ForegroundColor White
|
||||
Write-Host " ✓ Cooldown Time Clearing" -ForegroundColor White
|
||||
Write-Host " ✓ Rate Limiting & Throttle Protection" -ForegroundColor White
|
||||
@@ -21,5 +21,5 @@
|
||||
"typeRoots": ["./node_modules/@types"]
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
"exclude": ["node_modules", "dist", "client"]
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
const http = require('http');
|
||||
const crypto = require('crypto');
|
||||
const { exec } = require('child_process');
|
||||
|
||||
// 配置 - 复制此文件为 webhook-handler.js 并修改配置
|
||||
const PORT = 9000;
|
||||
const SECRET = 'your_webhook_secret_change_this'; // 与 Gitea 中配置的密钥一致
|
||||
const DEPLOY_SCRIPT = '/var/www/pixel-game-server/deploy.sh'; // 修改为实际路径
|
||||
|
||||
// 验证 Gitea 签名
|
||||
function verifySignature(payload, signature, secret) {
|
||||
const hmac = crypto.createHmac('sha256', secret);
|
||||
hmac.update(payload);
|
||||
const calculatedSignature = hmac.digest('hex');
|
||||
return crypto.timingSafeEqual(
|
||||
Buffer.from(signature, 'hex'),
|
||||
Buffer.from(calculatedSignature, 'hex')
|
||||
);
|
||||
}
|
||||
|
||||
// 创建 HTTP 服务器
|
||||
const server = http.createServer((req, res) => {
|
||||
if (req.method !== 'POST') {
|
||||
res.writeHead(405, { 'Content-Type': 'text/plain' });
|
||||
res.end('Method Not Allowed');
|
||||
return;
|
||||
}
|
||||
|
||||
let body = '';
|
||||
req.on('data', chunk => {
|
||||
body += chunk.toString();
|
||||
});
|
||||
|
||||
req.on('end', () => {
|
||||
try {
|
||||
// 验证签名
|
||||
const signature = req.headers['x-gitea-signature'];
|
||||
if (!signature || !verifySignature(body, signature.replace('sha256=', ''), SECRET)) {
|
||||
console.log('签名验证失败');
|
||||
res.writeHead(401, { 'Content-Type': 'text/plain' });
|
||||
res.end('Unauthorized');
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = JSON.parse(body);
|
||||
|
||||
// 检查是否是推送到 main 分支
|
||||
if (payload.ref === 'refs/heads/main') {
|
||||
console.log('收到 main 分支推送,开始部署...');
|
||||
|
||||
// 执行部署脚本
|
||||
exec(`bash ${DEPLOY_SCRIPT}`, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error('部署失败:', error);
|
||||
console.error('stderr:', stderr);
|
||||
} else {
|
||||
console.log('部署成功:', stdout);
|
||||
}
|
||||
});
|
||||
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end('Deployment triggered');
|
||||
} else {
|
||||
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
||||
res.end('Not main branch, ignored');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('处理 webhook 失败:', error);
|
||||
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
||||
res.end('Internal Server Error');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log(`Webhook 处理器运行在端口 ${PORT}`);
|
||||
});
|
||||
|
||||
// 优雅关闭
|
||||
process.on('SIGTERM', () => {
|
||||
console.log('收到 SIGTERM,正在关闭服务器...');
|
||||
server.close(() => {
|
||||
console.log('服务器已关闭');
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user