feat: multi-cluster management with pool-based load balancing

- Add ClusterPool entity for grouping clusters into named pools
- Support 3 deployment modes: manual cluster, pool load-balanced, default fallback
- Pool strategies: least-apps (fewest deployed apps) and round-robin
- Add pool CRUD API endpoints (admin) and public pool listing
- Frontend deploy page: 3-mode cluster selector (Default/Manual/Pool)
- Frontend app detail: shows assigned cluster and pool info
- Admin pools management page with cluster selection and strategy picker
- Application entity extended with poolId field
This commit is contained in:
keyhan
2026-04-05 17:37:05 +03:30
parent 1b1ccfc18f
commit 2621dc0cc6
14 changed files with 976 additions and 14 deletions
@@ -0,0 +1,50 @@
import { IsString, IsOptional, IsBoolean, IsArray, IsIn } from 'class-validator';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class CreateClusterPoolDto {
@ApiProperty({ example: 'production-pool' })
@IsString()
name: string;
@ApiPropertyOptional({ example: 'Load-balanced pool for production workloads' })
@IsOptional()
@IsString()
description?: string;
@ApiProperty({ example: 'least-apps', enum: ['least-apps', 'round-robin'] })
@IsIn(['least-apps', 'round-robin'])
strategy: 'least-apps' | 'round-robin';
@ApiProperty({ example: ['uuid-1', 'uuid-2'], description: 'Array of cluster IDs in this pool' })
@IsArray()
@IsString({ each: true })
clusterIds: string[];
}
export class UpdateClusterPoolDto {
@ApiPropertyOptional({ example: 'production-pool-v2' })
@IsOptional()
@IsString()
name?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
description?: string;
@ApiPropertyOptional({ enum: ['least-apps', 'round-robin'] })
@IsOptional()
@IsIn(['least-apps', 'round-robin'])
strategy?: 'least-apps' | 'round-robin';
@ApiPropertyOptional({ description: 'Array of cluster IDs in this pool' })
@IsOptional()
@IsArray()
@IsString({ each: true })
clusterIds?: string[];
@ApiPropertyOptional()
@IsOptional()
@IsBoolean()
isActive?: boolean;
}