xpeditis2.0/apps/backend/src/application/controllers/ports.controller.ts
2025-12-03 21:39:50 +01:00

99 lines
2.8 KiB
TypeScript

import {
Controller,
Get,
Query,
HttpCode,
HttpStatus,
Logger,
UsePipes,
ValidationPipe,
UseGuards,
} from '@nestjs/common';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiBadRequestResponse,
ApiInternalServerErrorResponse,
ApiBearerAuth,
} from '@nestjs/swagger';
import { PortSearchRequestDto, PortSearchResponseDto } from '../dto/port.dto';
import { PortMapper } from '../mappers/port.mapper';
import { PortSearchService } from '@domain/services/port-search.service';
import { JwtAuthGuard } from '../guards/jwt-auth.guard';
import { CurrentUser, UserPayload } from '../decorators/current-user.decorator';
@ApiTags('Ports')
@Controller('ports')
@ApiBearerAuth()
export class PortsController {
private readonly logger = new Logger(PortsController.name);
constructor(private readonly portSearchService: PortSearchService) {}
@Get('search')
@UseGuards(JwtAuthGuard)
@HttpCode(HttpStatus.OK)
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
@ApiOperation({
summary: 'Search ports (autocomplete)',
description:
'Search for maritime ports by name, city, or UN/LOCODE code. Returns up to 50 results ordered by relevance. Requires authentication.',
})
@ApiResponse({
status: HttpStatus.OK,
description: 'Port search completed successfully',
type: PortSearchResponseDto,
})
@ApiResponse({
status: 401,
description: 'Unauthorized - missing or invalid token',
})
@ApiBadRequestResponse({
description: 'Invalid request parameters',
schema: {
example: {
statusCode: 400,
message: ['query must be a string'],
error: 'Bad Request',
},
},
})
@ApiInternalServerErrorResponse({
description: 'Internal server error',
})
async searchPorts(
@Query() dto: PortSearchRequestDto,
@CurrentUser() user: UserPayload
): Promise<PortSearchResponseDto> {
const startTime = Date.now();
this.logger.log(
`[User: ${user.email}] Searching ports: query="${dto.query}", limit=${dto.limit || 10}, country=${dto.countryFilter || 'all'}`
);
try {
// Call domain service
const result = await this.portSearchService.search({
query: dto.query,
limit: dto.limit,
countryFilter: dto.countryFilter,
});
const duration = Date.now() - startTime;
this.logger.log(
`[User: ${user.email}] Port search completed: ${result.totalMatches} results in ${duration}ms`
);
// Map to response DTO
return PortMapper.toSearchResponseDto(result.ports, result.totalMatches);
} catch (error: any) {
const duration = Date.now() - startTime;
this.logger.error(
`[User: ${user.email}] Port search failed after ${duration}ms: ${error?.message || 'Unknown error'}`,
error?.stack
);
throw error;
}
}
}