import { Controller, Get, Post, Put, Delete, Body, Param, Query, NotFoundException, HttpException, HttpStatus } from '@nestjs/common'; import { ServerRepository } from '../../../infrastructure/repositories/server.repository'; import { Server } from '../../../domain/entities/server.entity'; import { TenantContextService } from '@it0/common'; import * as crypto from 'crypto'; @Controller('api/v1/inventory/servers') export class ServerController { constructor(private readonly serverRepository: ServerRepository) {} private serializeServer(server: Server) { return { ...server, hostname: server.name, sshPort: server.port, }; } @Get() async listServers(@Query('environment') env?: string) { const servers = env ? await this.serverRepository.findByEnvironment(env) : await this.serverRepository.findAll(); return servers.map((s) => this.serializeServer(s)); } @Post() async createServer(@Body() body: any) { // Quota enforcement const tenant = TenantContextService.getTenant(); if (tenant && tenant.maxServers !== -1) { const existing = await this.serverRepository.findAll(); if (existing.length >= tenant.maxServers) { throw new HttpException( { message: `Server quota exceeded (${existing.length}/${tenant.maxServers}). Upgrade your plan to add more servers.`, code: 'QUOTA_EXCEEDED' }, HttpStatus.TOO_MANY_REQUESTS, ); } } const server = new Server(); server.id = crypto.randomUUID(); server.tenantId = body.tenantId; server.name = body.hostname ?? body.name; server.host = body.host; server.port = body.sshPort ?? body.port ?? 22; server.environment = body.environment; server.role = body.role; server.clusterId = body.clusterId; server.sshUser = body.sshUser; server.credentialId = body.credentialId; server.networkType = body.networkType ?? 'private'; server.jumpServerId = body.jumpServerId; server.sshOptions = body.sshOptions ?? {}; server.tags = body.tags ?? {}; server.status = 'active'; server.description = body.description; server.createdAt = new Date(); server.updatedAt = new Date(); return this.serializeServer(await this.serverRepository.save(server)); } @Get(':id') async getServer(@Param('id') id: string) { const server = await this.serverRepository.findById(id); if (!server) { throw new NotFoundException(`Server ${id} not found`); } return this.serializeServer(server); } @Put(':id') async updateServer(@Param('id') id: string, @Body() body: any) { const server = await this.serverRepository.findById(id); if (!server) { throw new NotFoundException(`Server ${id} not found`); } const { hostname, sshPort, ...rest } = body; if (hostname !== undefined) rest.name = hostname; if (sshPort !== undefined) rest.port = sshPort; Object.assign(server, rest); server.updatedAt = new Date(); return this.serializeServer(await this.serverRepository.save(server)); } @Delete(':id') async deleteServer(@Param('id') id: string) { const server = await this.serverRepository.findById(id); if (!server) { throw new NotFoundException(`Server ${id} not found`); } await this.serverRepository.remove(server); return { message: 'Server deleted', id }; } }