import { IsArray, IsBoolean, IsEnum, IsIn, IsInt, IsOptional, IsString, Max, Min } from 'class-validator'; // ── LearningProfile ── export class SaveLearningProfileDto { @IsOptional() @IsString() learningGoal?: string; @IsOptional() @IsString() currentLevel?: string; @IsOptional() @IsInt() @Min(1) @Max(480) dailyAvailableMinutes?: number; @IsOptional() @IsString() qualityPreference?: string; @IsOptional() @IsString() ageRange?: string; @IsOptional() @IsString() occupation?: string; @IsOptional() @IsString() examTarget?: string; @IsOptional() @IsString() learningDeadline?: string; @IsOptional() @IsString() learningStyle?: string; @IsOptional() @IsString() aiAcceptanceLevel?: string; @IsOptional() @IsString() digitalSkillLevel?: string; @IsOptional() @IsArray() @IsString({ each: true }) preferredQuestionTypes?: string[]; @IsOptional() @IsString() preferredLanguage?: string; } // ── AiSettings ── export class UpdateAiSettingsDto { @IsOptional() @IsBoolean() allowAiAnalysis?: boolean; @IsOptional() @IsBoolean() allowUseLearningBehavior?: boolean; @IsOptional() @IsBoolean() allowUseUserProfile?: boolean; @IsOptional() @IsBoolean() allowUseDocumentContent?: boolean; @IsOptional() @IsBoolean() allowStoreAiAnalysisHistory?: boolean; @IsOptional() @IsString() apiKeyMode?: string; @IsOptional() @IsString() defaultCredentialId?: string; @IsOptional() @IsBoolean() fallbackToPlatformKey?: boolean; @IsOptional() @IsInt() @Min(0) maxDailyAiJobs?: number; @IsOptional() @IsInt() @Min(0) maxDailyTokenBudget?: number; } // ── ModelCredential ── export class CreateCredentialDto { @IsString() provider!: string; @IsString() apiKey!: string; @IsOptional() @IsString() keyAlias?: string; } export class UpdateCredentialDto { @IsString() apiKey!: string; @IsOptional() @IsString() keyAlias?: string; } export class CredentialResponseDto { id!: string; provider!: string; keyAlias?: string; maskedKey!: string; status!: string; lastTestedAt?: string; lastUsedAt?: string; createdAt!: string; updatedAt!: string; } // ── Analysis Job ── export const VALID_JOB_TYPES = [ 'learning_state_analysis', 'weak_point_analysis', 'next_action_planning', 'quiz_generation', 'flashcard_generation', ] as const; export const VALID_TARGET_TYPES = ['user', 'material', 'knowledge_base'] as const; const VALID_DIFFICULTY_LEVELS = ['easy', 'medium', 'hard'] as const; export class CreateAnalysisJobDto { @IsIn(VALID_JOB_TYPES) jobType!: string; @IsIn(VALID_TARGET_TYPES) targetType!: string; @IsString() targetId!: string; @IsOptional() @IsString() idempotencyKey?: string; @IsOptional() @IsString() apiKeyMode?: string; @IsOptional() @IsString() credentialId?: string; @IsOptional() @IsString() promptVersion?: string; @IsOptional() @IsString() outputSchemaVersion?: string; // Quiz-specific (API-AI-023) @IsOptional() @IsInt() @Min(1) @Max(50) questionCount?: number; @IsOptional() @IsArray() @IsString({ each: true }) questionTypes?: string[]; // Flashcard-specific (API-AI-024) @IsOptional() @IsInt() @Min(1) @Max(100) cardCount?: number; // Shared by quiz & flashcard @IsOptional() @IsIn(VALID_DIFFICULTY_LEVELS) difficultyLevel?: string; @IsOptional() @IsArray() @IsString({ each: true }) knowledgePointIds?: string[]; } export class CreateAnalysisJobResponseDto { jobId!: string; status!: string; createdAt!: string; @IsOptional() @IsString() planId?: string; }