import { IsString, IsOptional, IsEnum, IsNumber, IsDate, IsArray, IsObject, Min, ValidateNested, IsBoolean } from 'class-validator'; import { Type } from 'class-transformer'; import { ApiProperty, ApiPropertyOptional, PartialType } from '@nestjs/swagger'; import { GoalType, MetricType, PeriodType, DataSource, GoalStatus, SourceConfig, Milestone } from '../entities/definition.entity'; // ───────────────────────────────────────────── // Milestone DTO // ───────────────────────────────────────────── export class MilestoneDto { @ApiProperty({ example: 50 }) @IsNumber() @Min(0) percentage: number; @ApiProperty({ example: true }) @IsBoolean() notify: boolean; } // ───────────────────────────────────────────── // Source Config DTO // ───────────────────────────────────────────── export class SourceConfigDto { @ApiPropertyOptional({ example: 'sales' }) @IsOptional() @IsString() module?: string; @ApiPropertyOptional({ example: 'opportunities' }) @IsOptional() @IsString() entity?: string; @ApiPropertyOptional({ example: { status: 'won' } }) @IsOptional() @IsObject() filter?: Record; @ApiPropertyOptional({ enum: ['sum', 'count', 'avg'] }) @IsOptional() @IsString() aggregation?: 'sum' | 'count' | 'avg'; @ApiPropertyOptional({ example: 'amount' }) @IsOptional() @IsString() field?: string; } // ───────────────────────────────────────────── // Create Definition DTO // ───────────────────────────────────────────── export class CreateDefinitionDto { @ApiProperty({ example: 'Q1 Sales Target' }) @IsString() name: string; @ApiPropertyOptional({ example: 'Achieve $100,000 in closed deals' }) @IsOptional() @IsString() description?: string; @ApiPropertyOptional({ example: 'sales' }) @IsOptional() @IsString() category?: string; @ApiPropertyOptional({ enum: GoalType, default: GoalType.TARGET }) @IsOptional() @IsEnum(GoalType) type?: GoalType; @ApiPropertyOptional({ enum: MetricType, default: MetricType.NUMBER }) @IsOptional() @IsEnum(MetricType) metric?: MetricType; @ApiProperty({ example: 100000 }) @IsNumber() @Min(0) targetValue: number; @ApiPropertyOptional({ example: 'USD' }) @IsOptional() @IsString() unit?: string; @ApiPropertyOptional({ enum: PeriodType, default: PeriodType.MONTHLY }) @IsOptional() @IsEnum(PeriodType) period?: PeriodType; @ApiProperty({ example: '2026-01-01' }) @Type(() => Date) @IsDate() startsAt: Date; @ApiProperty({ example: '2026-03-31' }) @Type(() => Date) @IsDate() endsAt: Date; @ApiPropertyOptional({ enum: DataSource, default: DataSource.MANUAL }) @IsOptional() @IsEnum(DataSource) source?: DataSource; @ApiPropertyOptional({ type: SourceConfigDto }) @IsOptional() @ValidateNested() @Type(() => SourceConfigDto) sourceConfig?: SourceConfigDto; @ApiPropertyOptional({ type: [MilestoneDto] }) @IsOptional() @IsArray() @ValidateNested({ each: true }) @Type(() => MilestoneDto) milestones?: MilestoneDto[]; @ApiPropertyOptional({ enum: GoalStatus, default: GoalStatus.DRAFT }) @IsOptional() @IsEnum(GoalStatus) status?: GoalStatus; @ApiPropertyOptional({ type: [String], example: ['sales', 'q1'] }) @IsOptional() @IsArray() @IsString({ each: true }) tags?: string[]; } // ───────────────────────────────────────────── // Update Definition DTO // ───────────────────────────────────────────── export class UpdateDefinitionDto extends PartialType(CreateDefinitionDto) {} // ───────────────────────────────────────────── // Update Status DTO // ───────────────────────────────────────────── export class UpdateDefinitionStatusDto { @ApiProperty({ enum: GoalStatus }) @IsEnum(GoalStatus) status: GoalStatus; } // ───────────────────────────────────────────── // Definition Response DTO // ───────────────────────────────────────────── export class DefinitionResponseDto { @ApiProperty() id: string; @ApiProperty() tenantId: string; @ApiProperty() name: string; @ApiPropertyOptional() description: string | null; @ApiPropertyOptional() category: string | null; @ApiProperty({ enum: GoalType }) type: GoalType; @ApiProperty({ enum: MetricType }) metric: MetricType; @ApiProperty() targetValue: number; @ApiPropertyOptional() unit: string | null; @ApiProperty({ enum: PeriodType }) period: PeriodType; @ApiProperty() startsAt: Date; @ApiProperty() endsAt: Date; @ApiProperty({ enum: DataSource }) source: DataSource; @ApiProperty() sourceConfig: SourceConfig; @ApiProperty({ type: [MilestoneDto] }) milestones: Milestone[]; @ApiProperty({ enum: GoalStatus }) status: GoalStatus; @ApiProperty({ type: [String] }) tags: string[]; @ApiProperty() createdAt: Date; @ApiProperty() updatedAt: Date; @ApiPropertyOptional() createdBy: string | null; @ApiPropertyOptional() assignmentCount?: number; } // ───────────────────────────────────────────── // Definition Filters DTO // ───────────────────────────────────────────── export class DefinitionFiltersDto { @ApiPropertyOptional({ enum: GoalStatus }) @IsOptional() @IsEnum(GoalStatus) status?: GoalStatus; @ApiPropertyOptional({ enum: PeriodType }) @IsOptional() @IsEnum(PeriodType) period?: PeriodType; @ApiPropertyOptional() @IsOptional() @IsString() category?: string; @ApiPropertyOptional() @IsOptional() @IsString() search?: string; @ApiPropertyOptional() @IsOptional() @Type(() => Date) @IsDate() activeOn?: Date; @ApiPropertyOptional({ example: 'createdAt' }) @IsOptional() @IsString() sortBy?: string; @ApiPropertyOptional({ enum: ['ASC', 'DESC'], default: 'DESC' }) @IsOptional() @IsString() sortOrder?: 'ASC' | 'DESC'; @ApiPropertyOptional({ default: 1 }) @IsOptional() @Type(() => Number) @IsNumber() page?: number; @ApiPropertyOptional({ default: 20 }) @IsOptional() @Type(() => Number) @IsNumber() limit?: number; }