251125:0000 Phase 6 wait start dev Check

This commit is contained in:
2025-11-25 00:28:33 +07:00
parent 553c2d13ad
commit 582ecb5741
22 changed files with 3757 additions and 489 deletions
@@ -0,0 +1,16 @@
import { IsBoolean, IsOptional, IsString } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class SetMaintenanceDto {
@ApiProperty({ description: 'สถานะ Maintenance (true = เปิด, false = ปิด)' })
@IsBoolean()
enabled!: boolean; // ✅ เพิ่ม ! ตรงนี้
@ApiProperty({
description: 'เหตุผลที่ปิดปรับปรุง (แสดงให้ User เห็น)',
required: false,
})
@IsOptional()
@IsString()
reason?: string; // Optional (?) ไม่ต้องใส่ !
}
@@ -0,0 +1,30 @@
import { Controller, Get, Post, Body, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { MonitoringService } from './monitoring.service';
import { SetMaintenanceDto } from './dto/set-maintenance.dto';
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard';
import { RequirePermission } from '../../common/decorators/require-permission.decorator';
import { BypassMaintenance } from '../../common/decorators/bypass-maintenance.decorator';
@ApiTags('System Monitoring')
@Controller('monitoring')
export class MonitoringController {
constructor(private readonly monitoringService: MonitoringService) {}
@Get('maintenance')
@ApiOperation({ summary: 'Check maintenance status (Public)' })
@BypassMaintenance() // API นี้ต้องเรียกได้แม้ระบบปิดอยู่
getMaintenanceStatus() {
return this.monitoringService.getMaintenanceStatus();
}
@Post('maintenance')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@RequirePermission('system.manage_all') // เฉพาะ Superadmin เท่านั้น
@BypassMaintenance() // Admin ต้องยิงเปิด/ปิดได้แม้ระบบจะปิดอยู่
@ApiOperation({ summary: 'Toggle Maintenance Mode (Admin Only)' })
setMaintenanceMode(@Body() dto: SetMaintenanceDto) {
return this.monitoringService.setMaintenanceMode(dto);
}
}
@@ -1,23 +1,34 @@
// File: src/modules/monitoring/monitoring.module.ts
import { Global, Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HttpModule } from '@nestjs/axios';
import { APP_INTERCEPTOR } from '@nestjs/core';
// Existing Components
import { HealthController } from './controllers/health.controller';
import { MetricsService } from './services/metrics.service';
import { PerformanceInterceptor } from '../../common/interceptors/performance.interceptor';
@Global() // ทำให้ Module นี้ใช้งานได้ทั่วทั้ง App โดยไม่ต้อง Import ซ้ำ
// [NEW] Maintenance Mode Components
import { MonitoringController } from './monitoring.controller';
import { MonitoringService } from './monitoring.service';
@Global() // Module นี้เป็น Global (ดีแล้วครับ)
@Module({
imports: [TerminusModule, HttpModule],
controllers: [HealthController],
controllers: [
HealthController, // ✅ ของเดิม: /health
MonitoringController, // ✅ ของใหม่: /monitoring/maintenance
],
providers: [
MetricsService,
MetricsService, // ✅ ของเดิม
MonitoringService, // ✅ ของใหม่ (Logic เปิด/ปิด Maintenance)
{
provide: APP_INTERCEPTOR, // Register Global Interceptor
useClass: PerformanceInterceptor,
provide: APP_INTERCEPTOR,
useClass: PerformanceInterceptor, // ✅ ของเดิม (จับเวลา Response Time)
},
],
exports: [MetricsService],
exports: [MetricsService, MonitoringService],
})
export class MonitoringModule {}
@@ -0,0 +1,44 @@
// File: src/modules/monitoring/monitoring.service.ts
import { Injectable, Logger } from '@nestjs/common';
import { InjectRedis } from '@nestjs-modules/ioredis';
import Redis from 'ioredis';
import { SetMaintenanceDto } from './dto/set-maintenance.dto';
@Injectable()
export class MonitoringService {
private readonly logger = new Logger(MonitoringService.name);
private readonly MAINTENANCE_KEY = 'system:maintenance_mode';
constructor(@InjectRedis() private readonly redis: Redis) {}
/**
* ตรวจสอบสถานะปัจจุบัน
*/
async getMaintenanceStatus() {
const status = await this.redis.get(this.MAINTENANCE_KEY);
return {
isEnabled: status === 'true',
message:
status === 'true' ? 'System is under maintenance' : 'System is normal',
};
}
/**
* ตั้งค่า Maintenance Mode
*/
async setMaintenanceMode(dto: SetMaintenanceDto) {
if (dto.enabled) {
await this.redis.set(this.MAINTENANCE_KEY, 'true');
// เก็บเหตุผลไว้ใน Key อื่นก็ได้ถ้าต้องการ แต่เบื้องต้น Guard เช็คแค่ Key นี้
this.logger.warn(
`⚠️ SYSTEM ENTERED MAINTENANCE MODE: ${dto.reason || 'No reason provided'}`,
);
} else {
await this.redis.del(this.MAINTENANCE_KEY);
this.logger.log('✅ System exited maintenance mode');
}
return this.getMaintenanceStatus();
}
}