diff --git a/backend-nest/src/common/filters/http-exception.filter.ts b/backend-nest/src/common/filters/http-exception.filter.ts index 783d476..039f1f2 100644 --- a/backend-nest/src/common/filters/http-exception.filter.ts +++ b/backend-nest/src/common/filters/http-exception.filter.ts @@ -4,14 +4,18 @@ import { ArgumentsHost, HttpException, HttpStatus, + Logger, } from '@nestjs/common'; import { Response } from 'express'; @Catch() export class HttpExceptionFilter implements ExceptionFilter { + private readonly logger = new Logger('ExceptionFilter'); + catch(exception: unknown, host: ArgumentsHost) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); + const request = ctx.getRequest(); let status = HttpStatus.INTERNAL_SERVER_ERROR; let message = 'Internal server error'; @@ -28,6 +32,13 @@ export class HttpExceptionFilter implements ExceptionFilter { message = obj.message[0] as string; } } + } else { + // Log non-HttpException errors with full details + const err = exception instanceof Error ? exception : new Error(String(exception)); + this.logger.error( + `Unhandled exception on ${request.method} ${request.url}: ${err.message}`, + err.stack, + ); } response.status(status).json({ message }); diff --git a/backend-nest/src/modules/chat/chat.controller.ts b/backend-nest/src/modules/chat/chat.controller.ts index 14981bc..fd8ecb9 100644 --- a/backend-nest/src/modules/chat/chat.controller.ts +++ b/backend-nest/src/modules/chat/chat.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Put, Param, Body, Query, ParseIntPipe, UseGuards } from '@nestjs/common'; +import { Controller, Get, Put, Param, Body, Query, UseGuards } from '@nestjs/common'; import { ApiTags, ApiBearerAuth, ApiOperation, ApiQuery } from '@nestjs/swagger'; import { ChatService } from './chat.service'; import { FlagMessageDto } from './dto/flag-message.dto'; @@ -21,9 +21,10 @@ export class ChatController { @ApiQuery({ name: 'limit', required: false, example: 100 }) async getMessages( @CurrentTenant() licenseId: string, - @Query('limit', new ParseIntPipe({ optional: true })) limit?: number, + @Query('limit') limit?: string, ) { - return await this.chatService.getMessages(licenseId, limit || 100); + const limitNum = limit ? parseInt(limit, 10) : 100; + return await this.chatService.getMessages(licenseId, limitNum); } @Put(':id/flag') diff --git a/backend-nest/src/modules/notifications/notifications.controller.ts b/backend-nest/src/modules/notifications/notifications.controller.ts index 5b0bf8d..704fc2b 100644 --- a/backend-nest/src/modules/notifications/notifications.controller.ts +++ b/backend-nest/src/modules/notifications/notifications.controller.ts @@ -27,7 +27,8 @@ export class NotificationsController { description: 'Notification config retrieved successfully', }) async getConfig(@CurrentTenant() licenseId: string) { - return await this.notificationsService.getConfig(licenseId); + const config = await this.notificationsService.getConfig(licenseId); + return { config }; } @Put('config') @@ -43,6 +44,7 @@ export class NotificationsController { @CurrentTenant() licenseId: string, @Body() dto: UpdateConfigDto, ) { - return await this.notificationsService.updateConfig(licenseId, dto); + const config = await this.notificationsService.updateConfig(licenseId, dto); + return { config }; } } diff --git a/backend-nest/src/modules/servers/servers.service.ts b/backend-nest/src/modules/servers/servers.service.ts index d850eda..a5afef4 100644 --- a/backend-nest/src/modules/servers/servers.service.ts +++ b/backend-nest/src/modules/servers/servers.service.ts @@ -17,7 +17,8 @@ export class ServersService { ) {} /** - * Get server connection and config for a license + * Get server connection and config for a license. + * Returns null fields if no server has been set up yet. */ async getServer(licenseId: string) { const connection = await this.connectionRepo.findOne({ @@ -28,11 +29,11 @@ export class ServersService { where: { license_id: licenseId }, }); - if (!connection || !config) { - throw new NotFoundException('Server not found for this license'); - } - - return { connection, config }; + return { + connection: connection || null, + config: config || null, + setup_required: !connection || !config, + }; } /** diff --git a/backend-nest/src/modules/webstore/webstore.controller.ts b/backend-nest/src/modules/webstore/webstore.controller.ts index 2f88a78..a589b6d 100644 --- a/backend-nest/src/modules/webstore/webstore.controller.ts +++ b/backend-nest/src/modules/webstore/webstore.controller.ts @@ -18,7 +18,8 @@ export class WebstoreController { @ApiBearerAuth() @ApiOperation({ summary: 'Get webstore configuration' }) async getConfig(@CurrentTenant() licenseId: string) { - return this.webstoreService.getConfig(licenseId); + const config = await this.webstoreService.getConfig(licenseId); + return { config }; } @Put('webstore/config') @@ -28,7 +29,8 @@ export class WebstoreController { @CurrentTenant() licenseId: string, @Body() dto: UpdateStoreConfigDto, ) { - return this.webstoreService.updateConfig(licenseId, dto); + const config = await this.webstoreService.updateConfig(licenseId, dto); + return { config }; } @Get('webstore/categories') diff --git a/backend-nest/src/modules/wipes/wipes.controller.ts b/backend-nest/src/modules/wipes/wipes.controller.ts index c887fd1..69b51ef 100644 --- a/backend-nest/src/modules/wipes/wipes.controller.ts +++ b/backend-nest/src/modules/wipes/wipes.controller.ts @@ -7,7 +7,6 @@ import { Body, Param, Query, - ParseIntPipe, UseGuards, } from '@nestjs/common'; import { ApiTags, ApiBearerAuth, ApiOperation, ApiQuery } from '@nestjs/swagger'; @@ -81,9 +80,10 @@ export class WipesController { @ApiQuery({ name: 'limit', required: false, example: 50 }) getHistory( @CurrentTenant() licenseId: string, - @Query('limit', new ParseIntPipe({ optional: true })) limit?: number, + @Query('limit') limit?: string, ) { - return this.wipesService.getHistory(licenseId, limit || 50); + const limitNum = limit ? parseInt(limit, 10) : 50; + return this.wipesService.getHistory(licenseId, limitNum); } @Post('trigger')