First version for working parallel
Some checks are pending
CI Pipeline / changes (push) Waiting to run
CI Pipeline / core (push) Blocked by required conditions
CI Pipeline / trading-backend (push) Blocked by required conditions
CI Pipeline / trading-data-service (push) Blocked by required conditions
CI Pipeline / trading-frontend (push) Blocked by required conditions
CI Pipeline / erp-core (push) Blocked by required conditions
CI Pipeline / erp-mecanicas (push) Blocked by required conditions
CI Pipeline / gamilit-backend (push) Blocked by required conditions
CI Pipeline / gamilit-frontend (push) Blocked by required conditions

This commit is contained in:
rckrdmrd 2025-12-12 06:36:15 -06:00
parent 789d1ab46b
commit 48e7235e79
221 changed files with 533 additions and 523 deletions

View File

@ -152,7 +152,7 @@ export class AdminAlertsController {
@ApiResponse({ status: 403, description: 'Forbidden - Admin role required' }) @ApiResponse({ status: 403, description: 'Forbidden - Admin role required' })
async createAlert( async createAlert(
@Body() createDto: CreateAlertDto, @Body() createDto: CreateAlertDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<AlertResponseDto> { ): Promise<AlertResponseDto> {
const userId = req.user?.id || req.user?.sub; const userId = req.user?.id || req.user?.sub;
return this.alertsService.createAlert(createDto, userId); return this.alertsService.createAlert(createDto, userId);
@ -184,7 +184,7 @@ export class AdminAlertsController {
async acknowledgeAlert( async acknowledgeAlert(
@Param('id') id: string, @Param('id') id: string,
@Body() dto: AcknowledgeAlertDto, @Body() dto: AcknowledgeAlertDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<AlertResponseDto> { ): Promise<AlertResponseDto> {
const userId = req.user?.id || req.user?.sub; const userId = req.user?.id || req.user?.sub;
return this.alertsService.acknowledgeAlert(id, dto.acknowledgment_note, userId); return this.alertsService.acknowledgeAlert(id, dto.acknowledgment_note, userId);
@ -216,7 +216,7 @@ export class AdminAlertsController {
async resolveAlert( async resolveAlert(
@Param('id') id: string, @Param('id') id: string,
@Body() dto: ResolveAlertDto, @Body() dto: ResolveAlertDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<AlertResponseDto> { ): Promise<AlertResponseDto> {
const userId = req.user?.id || req.user?.sub; const userId = req.user?.id || req.user?.sub;
return this.alertsService.resolveAlert(id, dto.resolution_note, userId); return this.alertsService.resolveAlert(id, dto.resolution_note, userId);

View File

@ -60,7 +60,7 @@ export class AdminBulkOperationsController {
@ApiResponse({ status: 403, description: 'Forbidden - Admin access required' }) @ApiResponse({ status: 403, description: 'Forbidden - Admin access required' })
async bulkSuspendUsers( async bulkSuspendUsers(
@Body() dto: BulkSuspendUsersDto, @Body() dto: BulkSuspendUsersDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> { ): Promise<BulkOperationStatusDto> {
const adminId = req.user.sub; // JWT payload contiene sub = user.id const adminId = req.user.sub; // JWT payload contiene sub = user.id
return this.bulkOpsService.bulkSuspendUsers(dto, adminId); return this.bulkOpsService.bulkSuspendUsers(dto, adminId);
@ -82,7 +82,7 @@ export class AdminBulkOperationsController {
}) })
async bulkActivateUsers( async bulkActivateUsers(
@Body() dto: BulkActivateUsersDto, @Body() dto: BulkActivateUsersDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> { ): Promise<BulkOperationStatusDto> {
const adminId = req.user.sub; const adminId = req.user.sub;
return this.bulkOpsService.bulkActivateUsers(dto, adminId); return this.bulkOpsService.bulkActivateUsers(dto, adminId);
@ -104,7 +104,7 @@ export class AdminBulkOperationsController {
}) })
async bulkUpdateRole( async bulkUpdateRole(
@Body() dto: BulkUpdateRoleDto, @Body() dto: BulkUpdateRoleDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> { ): Promise<BulkOperationStatusDto> {
const adminId = req.user.sub; const adminId = req.user.sub;
return this.bulkOpsService.bulkUpdateRole(dto, adminId); return this.bulkOpsService.bulkUpdateRole(dto, adminId);
@ -126,7 +126,7 @@ export class AdminBulkOperationsController {
}) })
async bulkDeleteUsers( async bulkDeleteUsers(
@Body() dto: BulkDeleteUsersDto, @Body() dto: BulkDeleteUsersDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> { ): Promise<BulkOperationStatusDto> {
const adminId = req.user.sub; const adminId = req.user.sub;
return this.bulkOpsService.bulkDeleteUsers(dto, adminId); return this.bulkOpsService.bulkDeleteUsers(dto, adminId);

View File

@ -69,7 +69,7 @@ export class AdminContentController {
async approveContent( async approveContent(
@Param('id') id: string, @Param('id') id: string,
@Body() approvalDto: ApproveContentDto, @Body() approvalDto: ApproveContentDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<ContentDto> { ): Promise<ContentDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.approveContent( return this.adminContentService.approveContent(
@ -87,7 +87,7 @@ export class AdminContentController {
async approveExercise( async approveExercise(
@Param('id') id: string, @Param('id') id: string,
@Body() approvalDto: ApproveContentDto, @Body() approvalDto: ApproveContentDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<ContentDto> { ): Promise<ContentDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.approveContent( return this.adminContentService.approveContent(
@ -106,7 +106,7 @@ export class AdminContentController {
async rejectContent( async rejectContent(
@Param('id') id: string, @Param('id') id: string,
@Body() rejectionDto: RejectContentDto, @Body() rejectionDto: RejectContentDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<ContentDto> { ): Promise<ContentDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.rejectContent( return this.adminContentService.rejectContent(
@ -124,7 +124,7 @@ export class AdminContentController {
async rejectExercise( async rejectExercise(
@Param('id') id: string, @Param('id') id: string,
@Body() rejectionDto: RejectContentDto, @Body() rejectionDto: RejectContentDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<ContentDto> { ): Promise<ContentDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.rejectContent( return this.adminContentService.rejectContent(
@ -157,7 +157,7 @@ export class AdminContentController {
}) })
async createVersion( async createVersion(
@Body() dto: CreateVersionDto, @Body() dto: CreateVersionDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<VersionResponseDto> { ): Promise<VersionResponseDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.adminContentService.createVersion(dto, adminId); return this.adminContentService.createVersion(dto, adminId);

View File

@ -175,7 +175,7 @@ export class AdminGamificationConfigController {
}) })
async updateGamificationSettings( async updateGamificationSettings(
@Body() dto: UpdateGamificationSettingsDto, @Body() dto: UpdateGamificationSettingsDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<GamificationSettingsResponseDto> { ): Promise<GamificationSettingsResponseDto> {
const adminId = req.user.sub; const adminId = req.user.sub;
return this.gamificationConfigService.updateGamificationSettings( return this.gamificationConfigService.updateGamificationSettings(
@ -282,7 +282,7 @@ export class AdminGamificationConfigController {
description: 'Forbidden - User is not an admin', description: 'Forbidden - User is not an admin',
}) })
async restoreDefaults( async restoreDefaults(
@Request() req: any, @Request() req: AuthRequest,
): Promise<RestoreDefaultsResultDto> { ): Promise<RestoreDefaultsResultDto> {
const adminId = req.user.sub; const adminId = req.user.sub;
return this.gamificationConfigService.restoreDefaults(adminId); return this.gamificationConfigService.restoreDefaults(adminId);
@ -323,7 +323,7 @@ export class AdminGamificationConfigController {
description: 'Forbidden - User is not an admin', description: 'Forbidden - User is not an admin',
}) })
async restoreDefaultsAlternative( async restoreDefaultsAlternative(
@Request() req: any, @Request() req: AuthRequest,
): Promise<RestoreDefaultsResultDto> { ): Promise<RestoreDefaultsResultDto> {
const adminId = req.user.sub; const adminId = req.user.sub;
return this.gamificationConfigService.restoreDefaults(adminId); return this.gamificationConfigService.restoreDefaults(adminId);
@ -503,7 +503,7 @@ export class AdminGamificationConfigController {
async updateParameterById( async updateParameterById(
@Param('id') id: string, @Param('id') id: string,
@Body() dto: UpdateParameterDto, @Body() dto: UpdateParameterDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<UpdateParameterResponseDto> { ): Promise<UpdateParameterResponseDto> {
const adminId = req.user.sub; const adminId = req.user.sub;
return this.gamificationConfigService.updateParameterById( return this.gamificationConfigService.updateParameterById(
@ -635,7 +635,7 @@ export class AdminGamificationConfigController {
async updateMayaRank( async updateMayaRank(
@Param('rankName') rankName: string, @Param('rankName') rankName: string,
@Body() dto: UpdateMayaRankDto, @Body() dto: UpdateMayaRankDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<UpdateMayaRankResponseDto> { ): Promise<UpdateMayaRankResponseDto> {
const adminId = req.user.sub; const adminId = req.user.sub;
return this.gamificationConfigService.updateMayaRank( return this.gamificationConfigService.updateMayaRank(

View File

@ -163,7 +163,7 @@ export class AdminInterventionsController {
async acknowledgeIntervention( async acknowledgeIntervention(
@Param('id') id: string, @Param('id') id: string,
@Body() dto: AcknowledgeInterventionDto, @Body() dto: AcknowledgeInterventionDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<InterventionAlertDto> { ): Promise<InterventionAlertDto> {
const userId = req.user?.id || req.user?.sub; const userId = req.user?.id || req.user?.sub;
return this.interventionsService.acknowledgeIntervention(id, dto.acknowledgment_note, userId); return this.interventionsService.acknowledgeIntervention(id, dto.acknowledgment_note, userId);
@ -211,7 +211,7 @@ export class AdminInterventionsController {
async resolveIntervention( async resolveIntervention(
@Param('id') id: string, @Param('id') id: string,
@Body() dto: ResolveInterventionDto, @Body() dto: ResolveInterventionDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<InterventionAlertDto> { ): Promise<InterventionAlertDto> {
const userId = req.user?.id || req.user?.sub; const userId = req.user?.id || req.user?.sub;
return this.interventionsService.resolveIntervention(id, dto.resolution_notes, userId); return this.interventionsService.resolveIntervention(id, dto.resolution_notes, userId);

View File

@ -37,7 +37,7 @@ export class AdminReportsController {
}) })
async generateReport( async generateReport(
@Body() generateDto: GenerateReportDto, @Body() generateDto: GenerateReportDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<ReportDto> { ): Promise<ReportDto> {
const userId = req.user?.id || req.user?.sub; const userId = req.user?.id || req.user?.sub;
return this.adminReportsService.generateReport(generateDto, userId); return this.adminReportsService.generateReport(generateDto, userId);

View File

@ -71,7 +71,7 @@ export class AdminSystemController {
}) })
async updateSystemConfig( async updateSystemConfig(
@Body() configDto: UpdateSystemConfigDto, @Body() configDto: UpdateSystemConfigDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<SystemConfigDto> { ): Promise<SystemConfigDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.adminSystemService.updateSystemConfig(configDto, adminId); return this.adminSystemService.updateSystemConfig(configDto, adminId);
@ -94,7 +94,7 @@ export class AdminSystemController {
}) })
async getConfigByCategory( async getConfigByCategory(
@Param('category') category: string, @Param('category') category: string,
): Promise<Record<string, any>> { ): Promise<Record<string, unknown>> {
return this.adminSystemService.getConfigByCategory(category); return this.adminSystemService.getConfigByCategory(category);
} }
@ -106,9 +106,9 @@ export class AdminSystemController {
}) })
async updateConfigByCategory( async updateConfigByCategory(
@Param('category') category: string, @Param('category') category: string,
@Body() configDto: Record<string, any>, @Body() configDto: Record<string, unknown>,
@Request() req: any, @Request() req: AuthRequest,
): Promise<Record<string, any>> { ): Promise<Record<string, unknown>> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.adminSystemService.updateConfigByCategory( return this.adminSystemService.updateConfigByCategory(
category, category,
@ -125,7 +125,7 @@ export class AdminSystemController {
}) })
async toggleMaintenance( async toggleMaintenance(
@Body() toggleDto: ToggleMaintenanceDto, @Body() toggleDto: ToggleMaintenanceDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<MaintenanceStatusDto> { ): Promise<MaintenanceStatusDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.adminSystemService.toggleMaintenance( return this.adminSystemService.toggleMaintenance(

View File

@ -137,7 +137,7 @@ export class AdminUsersController {
}) })
async bulkSuspend( async bulkSuspend(
@Body() dto: BulkSuspendUsersDto, @Body() dto: BulkSuspendUsersDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> { ): Promise<BulkOperationStatusDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.bulkOpsService.bulkSuspendUsers(dto, adminId); return this.bulkOpsService.bulkSuspendUsers(dto, adminId);
@ -151,7 +151,7 @@ export class AdminUsersController {
}) })
async bulkDelete( async bulkDelete(
@Body() dto: BulkDeleteUsersDto, @Body() dto: BulkDeleteUsersDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> { ): Promise<BulkOperationStatusDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.bulkOpsService.bulkDeleteUsers(dto, adminId); return this.bulkOpsService.bulkDeleteUsers(dto, adminId);
@ -165,7 +165,7 @@ export class AdminUsersController {
}) })
async bulkUpdateRole( async bulkUpdateRole(
@Body() dto: BulkUpdateRoleDto, @Body() dto: BulkUpdateRoleDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<BulkOperationStatusDto> { ): Promise<BulkOperationStatusDto> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.bulkOpsService.bulkUpdateRole(dto, adminId); return this.bulkOpsService.bulkUpdateRole(dto, adminId);

View File

@ -114,7 +114,7 @@ export class FeatureFlagsController {
}) })
async create( async create(
@Body() dto: CreateFeatureFlagDto, @Body() dto: CreateFeatureFlagDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<FeatureFlag> { ): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.create(dto, adminId); return this.featureFlagsService.create(dto, adminId);
@ -140,7 +140,7 @@ export class FeatureFlagsController {
async update( async update(
@Param('key') key: string, @Param('key') key: string,
@Body() dto: UpdateFeatureFlagDto, @Body() dto: UpdateFeatureFlagDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<FeatureFlag> { ): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.update(key, dto, adminId); return this.featureFlagsService.update(key, dto, adminId);
@ -161,7 +161,7 @@ export class FeatureFlagsController {
}) })
async enable( async enable(
@Param('key') key: string, @Param('key') key: string,
@Request() req: any, @Request() req: AuthRequest,
): Promise<FeatureFlag> { ): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.enable(key, adminId); return this.featureFlagsService.enable(key, adminId);
@ -182,7 +182,7 @@ export class FeatureFlagsController {
}) })
async disable( async disable(
@Param('key') key: string, @Param('key') key: string,
@Request() req: any, @Request() req: AuthRequest,
): Promise<FeatureFlag> { ): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.disable(key, adminId); return this.featureFlagsService.disable(key, adminId);
@ -204,7 +204,7 @@ export class FeatureFlagsController {
async updateRollout( async updateRollout(
@Param('key') key: string, @Param('key') key: string,
@Body('percentage') percentage: number, @Body('percentage') percentage: number,
@Request() req: any, @Request() req: AuthRequest,
): Promise<FeatureFlag> { ): Promise<FeatureFlag> {
const adminId = req.user?.id || req.user?.sub; const adminId = req.user?.id || req.user?.sub;
return this.featureFlagsService.updateRollout(key, percentage, adminId); return this.featureFlagsService.updateRollout(key, percentage, adminId);

View File

@ -75,10 +75,10 @@ export class AlertResponseDto {
suppress_similar!: boolean; suppress_similar!: boolean;
@ApiPropertyOptional({ description: 'Additional context data' }) @ApiPropertyOptional({ description: 'Additional context data' })
context_data?: Record<string, any>; context_data?: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Metrics data' }) @ApiPropertyOptional({ description: 'Metrics data' })
metrics?: Record<string, any>; metrics?: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Related alert IDs', type: [String] }) @ApiPropertyOptional({ description: 'Related alert IDs', type: [String] })
related_alerts?: string[]; related_alerts?: string[];

View File

@ -45,10 +45,10 @@ export class CreateAlertDto {
@ApiPropertyOptional({ description: 'Additional context data (JSON)' }) @ApiPropertyOptional({ description: 'Additional context data (JSON)' })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
context_data?: Record<string, any>; context_data?: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Metrics data (JSON)' }) @ApiPropertyOptional({ description: 'Metrics data (JSON)' })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metrics?: Record<string, any>; metrics?: Record<string, unknown>;
} }

View File

@ -61,5 +61,5 @@ export class ContentDto {
@ApiPropertyOptional({ description: 'Additional metadata' }) @ApiPropertyOptional({ description: 'Additional metadata' })
@Expose() @Expose()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -65,5 +65,5 @@ export class VersionResponseDto {
is_published: true, is_published: true,
}, },
}) })
snapshot!: Record<string, any>; snapshot!: Record<string, unknown>;
} }

View File

@ -48,7 +48,7 @@ export class AdminActionDto {
@ApiPropertyOptional({ @ApiPropertyOptional({
description: 'Additional metadata in JSON format', description: 'Additional metadata in JSON format',
}) })
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
description: 'Timestamp when the action occurred', description: 'Timestamp when the action occurred',

View File

@ -88,7 +88,7 @@ export class CreateFeatureFlagDto {
}) })
@IsObject() @IsObject()
@IsOptional() @IsOptional()
targetConditions?: Record<string, any>; targetConditions?: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
description: 'Categoría de la feature flag', description: 'Categoría de la feature flag',
@ -106,5 +106,5 @@ export class CreateFeatureFlagDto {
}) })
@IsObject() @IsObject()
@IsOptional() @IsOptional()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -15,7 +15,7 @@ export class GamificationSettingsResponseDto {
perfect_score_bonus: 2.0, perfect_score_bonus: 2.0,
}, },
}) })
xp!: Record<string, any>; xp!: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
description: 'Rank thresholds', description: 'Rank thresholds',
@ -27,7 +27,7 @@ export class GamificationSettingsResponseDto {
expert: 5000, expert: 5000,
}, },
}) })
ranks!: Record<string, any>; ranks!: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
description: 'ML Coins rewards', description: 'ML Coins rewards',
@ -37,13 +37,13 @@ export class GamificationSettingsResponseDto {
exercise_completion_reward: 100, exercise_completion_reward: 100,
}, },
}) })
coins!: Record<string, any>; coins!: Record<string, unknown>;
@ApiPropertyOptional({ @ApiPropertyOptional({
description: 'Achievement criteria', description: 'Achievement criteria',
example: { criteria: [] }, example: { criteria: [] },
}) })
achievements?: Record<string, any>; achievements?: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
description: 'Default values from system', description: 'Default values from system',
@ -52,7 +52,7 @@ export class GamificationSettingsResponseDto {
'gamification.xp.completion_multiplier': 1.5, 'gamification.xp.completion_multiplier': 1.5,
}, },
}) })
defaults!: Record<string, any>; defaults!: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
description: 'Timestamp of last update', description: 'Timestamp of last update',

View File

@ -109,13 +109,13 @@ export class ParameterResponseDto {
description: 'Validation rules in JSON format', description: 'Validation rules in JSON format',
example: { regex: '^[0-9]+$' }, example: { regex: '^[0-9]+$' },
}) })
validation_rules?: Record<string, any>; validation_rules?: Record<string, unknown>;
@ApiPropertyOptional({ @ApiPropertyOptional({
description: 'Additional metadata', description: 'Additional metadata',
example: { unit: 'points', category_order: 1 }, example: { unit: 'points', category_order: 1 },
}) })
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
description: 'Timestamp when parameter was created', description: 'Timestamp when parameter was created',

View File

@ -182,5 +182,5 @@ export class UpdateGamificationSettingsDto {
}) })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
achievements?: Record<string, any>; achievements?: Record<string, unknown>;
} }

View File

@ -80,7 +80,7 @@ export class InterventionAlertDto {
description: 'Additional metrics and context data', description: 'Additional metrics and context data',
example: { average_score: 45, exercises_failed: 3 }, example: { average_score: 45, exercises_failed: 3 },
}) })
metrics?: Record<string, any>; metrics?: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
enum: InterventionStatus, enum: InterventionStatus,

View File

@ -58,7 +58,7 @@ export class RecentErrorDto {
nullable: true, nullable: true,
example: { stack: '...', code: 'ECONNREFUSED' }, example: { stack: '...', code: 'ECONNREFUSED' },
}) })
context!: Record<string, any> | null; context!: Record<string, unknown> | null;
@ApiProperty({ @ApiProperty({
description: 'Source of the error', description: 'Source of the error',

View File

@ -91,7 +91,7 @@ export class CreateOrganizationDto {
}) })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
settings?: Record<string, any>; settings?: Record<string, unknown>;
@ApiPropertyOptional({ @ApiPropertyOptional({
description: 'Organization metadata (JSONB)', description: 'Organization metadata (JSONB)',
@ -99,5 +99,5 @@ export class CreateOrganizationDto {
}) })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -49,11 +49,11 @@ export class OrganizationDto {
@ApiProperty({ description: 'Organization settings', example: { theme: 'detective' } }) @ApiProperty({ description: 'Organization settings', example: { theme: 'detective' } })
@Expose() @Expose()
settings!: Record<string, any>; settings!: Record<string, unknown>;
@ApiProperty({ description: 'Organization metadata', example: { notes: '...' } }) @ApiProperty({ description: 'Organization metadata', example: { notes: '...' } })
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
@ApiProperty({ description: 'Creation date', example: '2025-01-15T10:00:00Z' }) @ApiProperty({ description: 'Creation date', example: '2025-01-15T10:00:00Z' })
@Expose() @Expose()

View File

@ -83,7 +83,7 @@ export class UpdateOrganizationDto {
}) })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
settings?: Record<string, any>; settings?: Record<string, unknown>;
@ApiPropertyOptional({ @ApiPropertyOptional({
description: 'Organization metadata (JSONB)', description: 'Organization metadata (JSONB)',
@ -91,5 +91,5 @@ export class UpdateOrganizationDto {
}) })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -48,7 +48,7 @@ export class ReportDto {
@ApiPropertyOptional({ @ApiPropertyOptional({
description: 'Report metadata', description: 'Report metadata',
}) })
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
description: 'Report creation timestamp', description: 'Report creation timestamp',

View File

@ -60,7 +60,7 @@ export class MaintenanceOperationResultDto {
description: 'Additional metadata about the operation', description: 'Additional metadata about the operation',
example: { execution_time_ms: 1523 }, example: { execution_time_ms: 1523 },
}) })
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }
/** /**

View File

@ -20,7 +20,7 @@ export class SystemConfigDto {
session_timeout_minutes!: number; session_timeout_minutes!: number;
@ApiPropertyOptional({ description: 'Custom settings' }) @ApiPropertyOptional({ description: 'Custom settings' })
custom_settings?: Record<string, any>; custom_settings?: Record<string, unknown>;
@ApiProperty({ description: 'Last updated timestamp', example: '2025-11-02T18:00:00Z' }) @ApiProperty({ description: 'Last updated timestamp', example: '2025-11-02T18:00:00Z' })
updated_at!: string; updated_at!: string;

View File

@ -61,5 +61,5 @@ export class UpdateSystemConfigDto {
}) })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
custom_settings?: Record<string, any>; custom_settings?: Record<string, unknown>;
} }

View File

@ -24,5 +24,5 @@ export class UpdateUserDto {
@IsOptional() @IsOptional()
@IsObject() @IsObject()
raw_user_meta_data?: Record<string, any>; raw_user_meta_data?: Record<string, unknown>;
} }

View File

@ -39,7 +39,7 @@ export class UserDetailsDto {
last_sign_in_at?: Date; last_sign_in_at?: Date;
@Expose() @Expose()
raw_user_meta_data!: Record<string, any>; raw_user_meta_data!: Record<string, unknown>;
@Expose() @Expose()
created_at!: Date; created_at!: Date;

View File

@ -88,7 +88,7 @@ export class AdminReport {
* Formato: { startDate: '2025-01-01', endDate: '2025-12-31', classroomId: 'abc', ... } * Formato: { startDate: '2025-01-01', endDate: '2025-12-31', classroomId: 'abc', ... }
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* Mensaje de error si la generación falla * Mensaje de error si la generación falla

View File

@ -101,7 +101,7 @@ export class FeatureFlag {
* @example { "min_level": 5, "schools": ["uuid1", "uuid2"] } * @example { "min_level": 5, "schools": ["uuid1", "uuid2"] }
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
target_conditions!: Record<string, any>; target_conditions!: Record<string, unknown>;
/** /**
* Fecha y hora de inicio de la feature * Fecha y hora de inicio de la feature
@ -122,7 +122,7 @@ export class FeatureFlag {
* @example { "ab_test_group": "A", "tracking_id": "GA-123" } * @example { "ab_test_group": "A", "tracking_id": "GA-123" }
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* ID del usuario que creó la feature flag * ID del usuario que creó la feature flag

View File

@ -121,20 +121,20 @@ export class NotificationSettings {
* @example { "max_retries": 3, "backoff": "exponential" } * @example { "max_retries": 3, "backoff": "exponential" }
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
retry_policy!: Record<string, any>; retry_policy!: Record<string, unknown>;
/** /**
* Configuraciones específicas del canal de entrega * Configuraciones específicas del canal de entrega
* @example { "email_format": "html", "reply_to": "support@example.com" } * @example { "email_format": "html", "reply_to": "support@example.com" }
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
delivery_settings!: Record<string, any>; delivery_settings!: Record<string, unknown>;
/** /**
* Metadatos adicionales * Metadatos adicionales
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* ID del usuario que creó el setting * ID del usuario que creó el setting

View File

@ -176,14 +176,14 @@ export class SystemAlert {
* @example { "endpoint": "/api/users", "statusCode": 500, "requestId": "abc123" } * @example { "endpoint": "/api/users", "statusCode": 500, "requestId": "abc123" }
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
context_data!: Record<string, any>; context_data!: Record<string, unknown>;
/** /**
* Métricas asociadas en formato JSONB * Métricas asociadas en formato JSONB
* @example { "responseTime": 5000, "errorRate": 0.15, "cpuUsage": 0.95 } * @example { "responseTime": 5000, "errorRate": 0.15, "cpuUsage": 0.95 }
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metrics!: Record<string, any>; metrics!: Record<string, unknown>;
/** /**
* Array de IDs de alertas relacionadas * Array de IDs de alertas relacionadas

View File

@ -133,7 +133,7 @@ export class SystemSetting {
* @example { "regex": "^[a-z]+$", "minLength": 3 } * @example { "regex": "^[a-z]+$", "minLength": 3 }
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
validation_rules!: Record<string, any>; validation_rules!: Record<string, unknown>;
/** /**
* Valores permitidos para el setting (array de strings) * Valores permitidos para el setting (array de strings)
@ -158,7 +158,7 @@ export class SystemSetting {
* Metadatos adicionales en formato JSONB * Metadatos adicionales en formato JSONB
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* ID del usuario que creó el setting * ID del usuario que creó el setting

View File

@ -194,7 +194,7 @@ export class AdminAlertsService {
* @param userId - ID del usuario que crea la alerta (para auditoría) * @param userId - ID del usuario que crea la alerta (para auditoría)
* @returns Alerta creada * @returns Alerta creada
*/ */
async createAlert(createDto: CreateAlertDto: string): Promise<AlertResponseDto> { async createAlert(createDto: CreateAlertDto, _userId: string): Promise<AlertResponseDto> {
const alert = this.alertRepo.create({ const alert = this.alertRepo.create({
alert_type: createDto.alert_type, alert_type: createDto.alert_type,
severity: createDto.severity, severity: createDto.severity,

View File

@ -577,7 +577,7 @@ export class AdminContentService {
private createSnapshot( private createSnapshot(
content: any, content: any,
content_type: string, content_type: string,
): Record<string, any> { ): Record<string, unknown> {
switch (content_type) { switch (content_type) {
case 'module': case 'module':
return { return {
@ -804,7 +804,7 @@ export class AdminContentService {
}); });
content_title = template?.name; content_title = template?.name;
} }
} catch (_error) { } catch {
// Content might have been deleted, just leave title as undefined // Content might have been deleted, just leave title as undefined
content_title = undefined; content_title = undefined;
} }

View File

@ -279,7 +279,7 @@ export class AdminSystemService {
adminId: string, adminId: string,
): Promise<SystemConfigDto> { ): Promise<SystemConfigDto> {
// Update settings in database // Update settings in database
const settingsToUpdate: Record<string, any> = { const settingsToUpdate: Record<string, unknown> = {
maintenance_mode: updateDto.maintenance_mode, maintenance_mode: updateDto.maintenance_mode,
maintenance_message: updateDto.maintenance_message, maintenance_message: updateDto.maintenance_message,
allow_registrations: updateDto.allow_registrations, allow_registrations: updateDto.allow_registrations,
@ -360,7 +360,7 @@ export class AdminSystemService {
/** /**
* Get system configuration by category * Get system configuration by category
*/ */
async getConfigByCategory(category: string): Promise<Record<string, any>> { async getConfigByCategory(category: string): Promise<Record<string, unknown>> {
// Validate category // Validate category
const validCategories = ['general', 'email', 'notifications', 'security', 'maintenance']; const validCategories = ['general', 'email', 'notifications', 'security', 'maintenance'];
if (!validCategories.includes(category)) { if (!validCategories.includes(category)) {
@ -387,7 +387,7 @@ export class AdminSystemService {
}); });
// Build config object for this category // Build config object for this category
const config: Record<string, any> = {}; const config: Record<string, unknown> = {};
settings.forEach((setting) => { settings.forEach((setting) => {
config[setting.setting_key] = this.parseValue(setting); config[setting.setting_key] = this.parseValue(setting);
}); });
@ -400,9 +400,9 @@ export class AdminSystemService {
*/ */
async updateConfigByCategory( async updateConfigByCategory(
category: string, category: string,
configDto: Record<string, any>, configDto: Record<string, unknown>,
adminId: string, adminId: string,
): Promise<Record<string, any>> { ): Promise<Record<string, unknown>> {
// Validate category // Validate category
const validCategories = ['general', 'email', 'notifications', 'security', 'maintenance']; const validCategories = ['general', 'email', 'notifications', 'security', 'maintenance'];
if (!validCategories.includes(category)) { if (!validCategories.includes(category)) {
@ -744,7 +744,8 @@ export class AdminSystemService {
pool_size: poolSize, pool_size: poolSize,
active_connections: activeConnections, active_connections: activeConnections,
}; };
} catch () { // eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (_error) {
return { return {
status: 'down', status: 'down',
response_time_ms: -1, response_time_ms: -1,

View File

@ -425,8 +425,8 @@ export class GamificationConfigService {
* Parse settings array into structured config * Parse settings array into structured config
* @private * @private
*/ */
private parseSettings(settings: SystemSetting[]): Record<string, any> { private parseSettings(settings: SystemSetting[]): Record<string, unknown> {
const config: Record<string, any> = { const config: Record<string, unknown> = {
xp: {}, xp: {},
ranks: {}, ranks: {},
coins: {}, coins: {},
@ -446,7 +446,7 @@ export class GamificationConfigService {
} else if (setting.value_type === 'json') { } else if (setting.value_type === 'json') {
try { try {
value = JSON.parse(value); value = JSON.parse(value);
} catch (_error) { } catch {
this.logger.warn(`Failed to parse JSON for ${setting.setting_key}`); this.logger.warn(`Failed to parse JSON for ${setting.setting_key}`);
value = {}; value = {};
} }
@ -471,8 +471,8 @@ export class GamificationConfigService {
* Parse default values from settings * Parse default values from settings
* @private * @private
*/ */
private parseDefaults(settings: SystemSetting[]): Record<string, any> { private parseDefaults(settings: SystemSetting[]): Record<string, unknown> {
const defaults: Record<string, any> = {}; const defaults: Record<string, unknown> = {};
for (const setting of settings) { for (const setting of settings) {
if (setting.default_value) { if (setting.default_value) {
@ -484,7 +484,7 @@ export class GamificationConfigService {
} else if (setting.value_type === 'json') { } else if (setting.value_type === 'json') {
try { try {
value = JSON.parse(value); value = JSON.parse(value);
} catch (_error) { } catch {
this.logger.warn( this.logger.warn(
`Failed to parse default JSON for ${setting.setting_key}`, `Failed to parse default JSON for ${setting.setting_key}`,
); );
@ -542,7 +542,7 @@ export class GamificationConfigService {
* @private * @private
*/ */
private async updateXpSettings( private async updateXpSettings(
xp: Record<string, any>, xp: Record<string, unknown>,
adminId: string, adminId: string,
): Promise<void> { ): Promise<void> {
for (const [key, value] of Object.entries(xp)) { for (const [key, value] of Object.entries(xp)) {
@ -556,7 +556,7 @@ export class GamificationConfigService {
* @private * @private
*/ */
private async updateRankSettings( private async updateRankSettings(
ranks: Record<string, any>, ranks: Record<string, unknown>,
adminId: string, adminId: string,
): Promise<void> { ): Promise<void> {
const settingKey = 'gamification.ranks.thresholds'; const settingKey = 'gamification.ranks.thresholds';
@ -568,7 +568,7 @@ export class GamificationConfigService {
* @private * @private
*/ */
private async updateCoinsSettings( private async updateCoinsSettings(
coins: Record<string, any>, coins: Record<string, unknown>,
adminId: string, adminId: string,
): Promise<void> { ): Promise<void> {
for (const [key, value] of Object.entries(coins)) { for (const [key, value] of Object.entries(coins)) {
@ -582,7 +582,7 @@ export class GamificationConfigService {
* @private * @private
*/ */
private async updateAchievementSettings( private async updateAchievementSettings(
achievements: Record<string, any>, achievements: Record<string, unknown>,
adminId: string, adminId: string,
): Promise<void> { ): Promise<void> {
const settingKey = 'gamification.achievements.criteria'; const settingKey = 'gamification.achievements.criteria';
@ -992,7 +992,7 @@ export class GamificationConfigService {
if (parameter.value_type === 'json') { if (parameter.value_type === 'json') {
try { try {
JSON.parse(value); JSON.parse(value);
} catch (_error) { } catch {
throw new BadRequestException( throw new BadRequestException(
`Invalid JSON value for ${parameter.setting_key}`, `Invalid JSON value for ${parameter.setting_key}`,
); );

View File

@ -69,7 +69,7 @@ export class AssignmentsController {
}, },
}) })
@ApiResponse({ status: 400, description: 'Datos inválidos' }) @ApiResponse({ status: 400, description: 'Datos inválidos' })
async create(@Body() createDto: CreateAssignmentDto, @Request() req: any) { async create(@Body() createDto: CreateAssignmentDto, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.create(createDto, teacherId); return this.assignmentsService.create(createDto, teacherId);
} }
@ -116,7 +116,7 @@ export class AssignmentsController {
}], }],
}, },
}) })
async findAll(@Query() query: any, @Request() req: any) { async findAll(@Query() query: any, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.findAll(teacherId, { return this.assignmentsService.findAll(teacherId, {
isPublished: query.isPublished !== undefined ? query.isPublished === 'true' : undefined, isPublished: query.isPublished !== undefined ? query.isPublished === 'true' : undefined,
@ -164,7 +164,7 @@ export class AssignmentsController {
status: 404, status: 404,
description: 'Asignación no encontrada o acceso denegado', description: 'Asignación no encontrada o acceso denegado',
}) })
async findOne(@Param('id') id: string, @Request() req: any) { async findOne(@Param('id') id: string, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.findOne(id, teacherId); return this.assignmentsService.findOne(id, teacherId);
} }
@ -199,7 +199,7 @@ export class AssignmentsController {
async update( async update(
@Param('id') id: string, @Param('id') id: string,
@Body() updateDto: UpdateAssignmentDto, @Body() updateDto: UpdateAssignmentDto,
@Request() req: any, @Request() req: AuthRequest,
) { ) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.update(id, updateDto, teacherId); return this.assignmentsService.update(id, updateDto, teacherId);
@ -228,7 +228,7 @@ export class AssignmentsController {
status: 404, status: 404,
description: 'Asignación no encontrada o acceso denegado', description: 'Asignación no encontrada o acceso denegado',
}) })
async remove(@Param('id') id: string, @Request() req: any) { async remove(@Param('id') id: string, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
await this.assignmentsService.remove(id, teacherId); await this.assignmentsService.remove(id, teacherId);
} }
@ -266,7 +266,7 @@ export class AssignmentsController {
async assignToClassrooms( async assignToClassrooms(
@Param('id') id: string, @Param('id') id: string,
@Body() dto: AssignToClassroomsDto, @Body() dto: AssignToClassroomsDto,
@Request() req: any, @Request() req: AuthRequest,
) { ) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.assignToClassrooms(id, dto, teacherId); return this.assignmentsService.assignToClassrooms(id, dto, teacherId);
@ -320,7 +320,7 @@ export class AssignmentsController {
async getSubmissions( async getSubmissions(
@Param('id') id: string, @Param('id') id: string,
@Query() query: any, @Query() query: any,
@Request() req: any, @Request() req: AuthRequest,
) { ) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.getSubmissions(id, teacherId, { return this.assignmentsService.getSubmissions(id, teacherId, {
@ -373,7 +373,7 @@ export class AssignmentsController {
async gradeSubmission( async gradeSubmission(
@Param('submissionId') submissionId: string, @Param('submissionId') submissionId: string,
@Body() dto: AssignmentGradeDto, @Body() dto: AssignmentGradeDto,
@Request() req: any, @Request() req: AuthRequest,
) { ) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.gradeSubmission(submissionId, dto, teacherId); return this.assignmentsService.gradeSubmission(submissionId, dto, teacherId);
@ -407,7 +407,7 @@ export class AssignmentsController {
async patch( async patch(
@Param('id') id: string, @Param('id') id: string,
@Body() patchDto: PatchAssignmentDto, @Body() patchDto: PatchAssignmentDto,
@Request() req: any, @Request() req: AuthRequest,
) { ) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.patchAssignment(id, patchDto, teacherId); return this.assignmentsService.patchAssignment(id, patchDto, teacherId);
@ -441,7 +441,7 @@ export class AssignmentsController {
async distribute( async distribute(
@Param('id') id: string, @Param('id') id: string,
@Body() distributeDto: DistributeAssignmentDto, @Body() distributeDto: DistributeAssignmentDto,
@Request() req: any, @Request() req: AuthRequest,
) { ) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.distributeAssignment(id, distributeDto, teacherId); return this.assignmentsService.distributeAssignment(id, distributeDto, teacherId);
@ -472,7 +472,7 @@ export class AssignmentsController {
async duplicate( async duplicate(
@Param('id') id: string, @Param('id') id: string,
@Body() duplicateDto: DuplicateAssignmentDto, @Body() duplicateDto: DuplicateAssignmentDto,
@Request() req: any, @Request() req: AuthRequest,
) { ) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.duplicateAssignment(id, duplicateDto, teacherId); return this.assignmentsService.duplicateAssignment(id, duplicateDto, teacherId);
@ -528,7 +528,7 @@ export class AssignmentsController {
async publish( async publish(
@Param('id') id: string, @Param('id') id: string,
@Body('notifyStudents') notifyStudents: boolean = false, @Body('notifyStudents') notifyStudents: boolean = false,
@Request() req: any, @Request() req: AuthRequest,
) { ) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.publishAssignment(id, teacherId, notifyStudents); return this.assignmentsService.publishAssignment(id, teacherId, notifyStudents);
@ -569,7 +569,7 @@ export class AssignmentsController {
status: 404, status: 404,
description: 'Assignment not found or access denied', description: 'Assignment not found or access denied',
}) })
async close(@Param('id') id: string, @Request() req: any) { async close(@Param('id') id: string, @Request() req: AuthRequest) {
const teacherId = req.user?.userId || req.user?.sub; const teacherId = req.user?.userId || req.user?.sub;
return this.assignmentsService.closeAssignment(id, teacherId); return this.assignmentsService.closeAssignment(id, teacherId);
} }

View File

@ -73,7 +73,7 @@ export class StudentAssignmentsController {
}], }],
}, },
}) })
async getMyAssignments(@Query() query: any, @Request() req: any) { async getMyAssignments(@Query() query: any, @Request() req: AuthRequest) {
const studentId = req.user?.userId || req.user?.sub; const studentId = req.user?.userId || req.user?.sub;
return this.assignmentsService.findStudentAssignments(studentId, { return this.assignmentsService.findStudentAssignments(studentId, {
status: query.status, status: query.status,
@ -104,7 +104,7 @@ export class StudentAssignmentsController {
status: 404, status: 404,
description: 'Tarea no encontrada o no asignada a este estudiante', description: 'Tarea no encontrada o no asignada a este estudiante',
}) })
async getAssignmentDetails(@Param('id') id: string, @Request() req: any) { async getAssignmentDetails(@Param('id') id: string, @Request() req: AuthRequest) {
const studentId = req.user?.userId || req.user?.sub; const studentId = req.user?.userId || req.user?.sub;
return this.assignmentsService.findStudentAssignmentById(id, studentId); return this.assignmentsService.findStudentAssignmentById(id, studentId);
} }
@ -137,7 +137,7 @@ export class StudentAssignmentsController {
}, },
}, },
}) })
async getGradesSummary(@Request() req: any) { async getGradesSummary(@Request() req: AuthRequest) {
const studentId = req.user?.userId || req.user?.sub; const studentId = req.user?.userId || req.user?.sub;
return this.assignmentsService.getStudentGradesSummary(studentId); return this.assignmentsService.getStudentGradesSummary(studentId);
} }

View File

@ -859,7 +859,7 @@ export class AssignmentsService {
*/ */
async findStudentAssignments( async findStudentAssignments(
studentId: string, studentId: string,
filters?: { status?: string; classroomId?: string }, _filters?: { status?: string; classroomId?: string },
): Promise<any[]> { ): Promise<any[]> {
// Get direct student assignments (without relation join - relations commented out) // Get direct student assignments (without relation join - relations commented out)
const studentAssignments = await this.assignmentStudentRepository.find({ const studentAssignments = await this.assignmentStudentRepository.find({

View File

@ -25,7 +25,7 @@ export class AuditInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> { intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const request = context.switchToHttp().getRequest<Request>(); const request = context.switchToHttp().getRequest<Request>();
const { method, url, _body, _user} = request; const { method, url, body: _body, user: _user} = request;
// Skip audit logging for certain endpoints // Skip audit logging for certain endpoints
if (this.shouldSkipAudit(url)) { if (this.shouldSkipAudit(url)) {

View File

@ -45,7 +45,7 @@ export class AuthService {
* 4. Generate JWT tokens * 4. Generate JWT tokens
* 5. Return sanitized user + tokens * 5. Return sanitized user + tokens
*/ */
async register(dto: any): Promise<AuthResponse> { async register(_dto: any): Promise<AuthResponse> {
throw new Error('Register method not implemented - UsersService required'); throw new Error('Register method not implemented - UsersService required');
} }
@ -59,7 +59,7 @@ export class AuthService {
* 4. Generate JWT tokens * 4. Generate JWT tokens
* 5. Return sanitized user + tokens * 5. Return sanitized user + tokens
*/ */
async login(dto: LoginDto): Promise<AuthResponse> { async login(_dto: LoginDto): Promise<AuthResponse> {
throw new Error('Login method not implemented - UsersService required'); throw new Error('Login method not implemented - UsersService required');
} }
@ -76,14 +76,14 @@ export class AuthService {
* 3. Validate user is active * 3. Validate user is active
* 4. Generate new access + refresh tokens * 4. Generate new access + refresh tokens
*/ */
async refreshToken(dto: RefreshTokenDto): Promise<TokenResponse> { async refreshToken(_dto: RefreshTokenDto): Promise<TokenResponse> {
throw new Error('RefreshToken method not implemented - UsersService required'); throw new Error('RefreshToken method not implemented - UsersService required');
} }
/** /**
* Logout - Invalida tokens (client-side) * Logout - Invalida tokens (client-side)
*/ */
async logout(userId: string): Promise<{ message: string }> { async logout(_userId: string): Promise<{ message: string }> {
// TODO: Implementar blacklist de tokens en Redis (opcional) // TODO: Implementar blacklist de tokens en Redis (opcional)
// Por ahora, el logout es client-side (eliminar tokens de localStorage) // Por ahora, el logout es client-side (eliminar tokens de localStorage)
@ -99,7 +99,7 @@ export class AuthService {
* 2. Check if user exists and is active * 2. Check if user exists and is active
* 3. Return sanitized user (without password) * 3. Return sanitized user (without password)
*/ */
async validateUser(userId: string) { async validateUser(_userId: string) {
throw new Error('ValidateUser method not implemented - UsersService required'); throw new Error('ValidateUser method not implemented - UsersService required');
} }

View File

@ -72,7 +72,7 @@ export class AuthController {
@ApiBody({ type: RegisterUserDto }) @ApiBody({ type: RegisterUserDto })
async register( async register(
@Body() dto: RegisterUserDto, @Body() dto: RegisterUserDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<{ user: UserResponseDto; accessToken: string; refreshToken: string }> { ): Promise<{ user: UserResponseDto; accessToken: string; refreshToken: string }> {
const ip = req.ip; const ip = req.ip;
const userAgent = req.headers['user-agent']; const userAgent = req.headers['user-agent'];
@ -104,7 +104,7 @@ export class AuthController {
@ApiBody({ type: LoginDto }) @ApiBody({ type: LoginDto })
async login( async login(
@Body() dto: LoginDto, @Body() dto: LoginDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<{ user: UserResponseDto; accessToken: string; refreshToken: string }> { ): Promise<{ user: UserResponseDto; accessToken: string; refreshToken: string }> {
const ip = req.ip; const ip = req.ip;
const userAgent = req.headers['user-agent']; const userAgent = req.headers['user-agent'];
@ -129,7 +129,7 @@ export class AuthController {
@ApiOperation({ summary: 'Cerrar sesión de usuario' }) @ApiOperation({ summary: 'Cerrar sesión de usuario' })
@ApiResponse({ status: 200, description: 'Sesión cerrada exitosamente' }) @ApiResponse({ status: 200, description: 'Sesión cerrada exitosamente' })
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
async logout(@Request() req: any): Promise<{ message: string }> { async logout(@Request() req: AuthRequest): Promise<{ message: string }> {
// Extraer userId y sessionId del token JWT // Extraer userId y sessionId del token JWT
const userId = req.user?.id; const userId = req.user?.id;
const sessionId = req.user?.sessionId || 'current-session'; const sessionId = req.user?.sessionId || 'current-session';
@ -175,7 +175,7 @@ export class AuthController {
type: UserResponseDto, type: UserResponseDto,
}) })
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
async getProfile(@Request() req: any): Promise<UserResponseDto> { async getProfile(@Request() req: AuthRequest): Promise<UserResponseDto> {
// Extraer userId del token JWT // Extraer userId del token JWT
const userId = req.user?.id; const userId = req.user?.id;
const user = await this.authService.validateUser(userId); const user = await this.authService.validateUser(userId);
@ -185,7 +185,7 @@ export class AuthController {
} }
// Convertir a UserResponseDto (sin password) // Convertir a UserResponseDto (sin password)
const { _encrypted_password, ...userResponse } = user; const { encrypted_password: _encrypted_password, ...userResponse } = user;
return userResponse as UserResponseDto; return userResponse as UserResponseDto;
} }
@ -206,7 +206,7 @@ export class AuthController {
@ApiResponse({ status: 400, description: 'Datos inválidos' }) @ApiResponse({ status: 400, description: 'Datos inválidos' })
@ApiBody({ type: UpdateProfileDto }) @ApiBody({ type: UpdateProfileDto })
async updateProfile( async updateProfile(
@Request() req: any, @Request() req: AuthRequest,
@Body() dto: UpdateProfileDto, @Body() dto: UpdateProfileDto,
): Promise<UserResponseDto> { ): Promise<UserResponseDto> {
// Extraer userId del token JWT // Extraer userId del token JWT
@ -220,7 +220,7 @@ export class AuthController {
} }
// Convertir a UserResponseDto (sin password) // Convertir a UserResponseDto (sin password)
const { _encrypted_password, ...userResponse } = updatedUser; const { encrypted_password: _encrypted_password, ...userResponse } = updatedUser;
return userResponse as UserResponseDto; return userResponse as UserResponseDto;
} }
@ -247,7 +247,7 @@ export class AuthController {
}, },
}, },
}) })
async verifyEmail(@Body('token') token: string): Promise<{ message: string }> { async verifyEmail(@Body('token') _token: string): Promise<{ message: string }> {
// TODO: Implementar lógica de verificación de email // TODO: Implementar lógica de verificación de email
// Por ahora retornamos éxito // Por ahora retornamos éxito
return { message: 'Email verificado exitosamente' }; return { message: 'Email verificado exitosamente' };
@ -275,7 +275,7 @@ export class AuthController {
}, },
}, },
}) })
async forgotPassword(@Body('email') email: string): Promise<{ message: string }> { async forgotPassword(@Body('email') _email: string): Promise<{ message: string }> {
// TODO: Implementar lógica de forgot password // TODO: Implementar lógica de forgot password
return { message: 'Si el email existe, recibirás instrucciones para resetear tu contraseña' }; return { message: 'Si el email existe, recibirás instrucciones para resetear tu contraseña' };
} }
@ -305,8 +305,8 @@ export class AuthController {
}, },
}) })
async resetPassword( async resetPassword(
@Body('token') token: string, @Body('token') _token: string,
@Body('newPassword') newPassword: string, @Body('newPassword') _newPassword: string,
): Promise<{ message: string }> { ): Promise<{ message: string }> {
// TODO: Implementar lógica de reset password // TODO: Implementar lógica de reset password
return { message: 'Contraseña reseteada exitosamente' }; return { message: 'Contraseña reseteada exitosamente' };
@ -340,9 +340,9 @@ export class AuthController {
}, },
}) })
async changePassword( async changePassword(
@Request() req: any, @Request() req: AuthRequest,
@Body('currentPassword') currentPassword: string, @Body('currentPassword') _currentPassword: string,
@Body('newPassword') newPassword: string, @Body('newPassword') _newPassword: string,
): Promise<{ message: string }> { ): Promise<{ message: string }> {
const _userId = req.user?.id; const _userId = req.user?.id;
// TODO: Implementar lógica de cambio de contraseña // TODO: Implementar lógica de cambio de contraseña
@ -363,7 +363,7 @@ export class AuthController {
isArray: true, isArray: true,
}) })
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
async getSessions(@Request() req: any): Promise<UserSessionResponseDto[]> { async getSessions(@Request() req: AuthRequest): Promise<UserSessionResponseDto[]> {
const userId = req.user?.id; const userId = req.user?.id;
return this.sessionService.getSessions(userId); return this.sessionService.getSessions(userId);
} }
@ -391,7 +391,7 @@ export class AuthController {
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
@ApiResponse({ status: 404, description: 'Sesión no encontrada o no pertenece al usuario' }) @ApiResponse({ status: 404, description: 'Sesión no encontrada o no pertenece al usuario' })
async revokeSession( async revokeSession(
@Request() req: any, @Request() req: AuthRequest,
@Param('sessionId') sessionId: string, @Param('sessionId') sessionId: string,
): Promise<{ message: string }> { ): Promise<{ message: string }> {
const userId = req.user?.id; const userId = req.user?.id;
@ -420,7 +420,7 @@ export class AuthController {
}, },
}) })
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
async revokeAllSessions(@Request() req: any): Promise<{ message: string; count: number }> { async revokeAllSessions(@Request() req: AuthRequest): Promise<{ message: string; count: number }> {
const userId = req.user?.id; const userId = req.user?.id;
const currentSessionId = req.user?.sessionId || 'unknown'; const currentSessionId = req.user?.sessionId || 'unknown';
return this.sessionService.revokeAllSessions(userId, currentSessionId); return this.sessionService.revokeAllSessions(userId, currentSessionId);

View File

@ -140,7 +140,7 @@ export class PasswordController {
@ApiResponse({ status: 404, description: 'Usuario no encontrado' }) @ApiResponse({ status: 404, description: 'Usuario no encontrado' })
@ApiBody({ type: ChangePasswordDto }) @ApiBody({ type: ChangePasswordDto })
async changePassword( async changePassword(
@Request() req: any, @Request() req: AuthRequest,
@Body() dto: ChangePasswordDto, @Body() dto: ChangePasswordDto,
): Promise<{ message: string }> { ): Promise<{ message: string }> {
// Extraer userId del token JWT // Extraer userId del token JWT
@ -201,7 +201,7 @@ export class PasswordController {
}) })
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
@ApiResponse({ status: 409, description: 'Email ya verificado' }) @ApiResponse({ status: 409, description: 'Email ya verificado' })
async resendVerification(@Request() req: any): Promise<{ message: string }> { async resendVerification(@Request() req: AuthRequest): Promise<{ message: string }> {
// Extraer userId del token JWT // Extraer userId del token JWT
const userId = req.user?.id; const userId = req.user?.id;
return this.emailVerificationService.resendVerification(userId); return this.emailVerificationService.resendVerification(userId);
@ -226,7 +226,7 @@ export class PasswordController {
}, },
}) })
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
async checkVerificationStatus(@Request() req: any): Promise<{ verified: boolean }> { async checkVerificationStatus(@Request() req: AuthRequest): Promise<{ verified: boolean }> {
// Extraer userId del token JWT // Extraer userId del token JWT
const userId = req.user?.id; const userId = req.user?.id;
return this.emailVerificationService.checkVerificationStatus(userId); return this.emailVerificationService.checkVerificationStatus(userId);

View File

@ -59,7 +59,7 @@ export class UsersController {
type: UserResponseDto, type: UserResponseDto,
}) })
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
async getProfile(@Request() req: any): Promise<UserResponseDto> { async getProfile(@Request() req: AuthRequest): Promise<UserResponseDto> {
const userId = req.user?.id; const userId = req.user?.id;
const user = await this.authService.validateUser(userId); const user = await this.authService.validateUser(userId);
@ -67,7 +67,7 @@ export class UsersController {
throw new UnauthorizedException('Usuario no encontrado'); throw new UnauthorizedException('Usuario no encontrado');
} }
const { _encrypted_password, ...userResponse } = user; const { encrypted_password: _encrypted_password, ...userResponse } = user;
return userResponse as UserResponseDto; return userResponse as UserResponseDto;
} }
@ -88,7 +88,7 @@ export class UsersController {
@ApiResponse({ status: 400, description: 'Datos inválidos' }) @ApiResponse({ status: 400, description: 'Datos inválidos' })
@ApiBody({ type: UpdateProfileDto }) @ApiBody({ type: UpdateProfileDto })
async updateProfile( async updateProfile(
@Request() req: any, @Request() req: AuthRequest,
@Body() dto: UpdateProfileDto, @Body() dto: UpdateProfileDto,
): Promise<UserResponseDto> { ): Promise<UserResponseDto> {
const userId = req.user?.id; const userId = req.user?.id;
@ -98,7 +98,7 @@ export class UsersController {
throw new UnauthorizedException('Usuario no encontrado'); throw new UnauthorizedException('Usuario no encontrado');
} }
const { _encrypted_password, ...userResponse } = updatedUser; const { encrypted_password: _encrypted_password, ...userResponse } = updatedUser;
return userResponse as UserResponseDto; return userResponse as UserResponseDto;
} }
@ -119,7 +119,7 @@ export class UsersController {
}, },
}) })
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
async getPreferences(@Request() req: any): Promise<{ preferences: any }> { async getPreferences(@Request() req: AuthRequest): Promise<{ preferences: any }> {
const userId = req.user?.id; const userId = req.user?.id;
const preferences = await this.authService.getUserPreferences(userId); const preferences = await this.authService.getUserPreferences(userId);
return { preferences }; return { preferences };
@ -151,7 +151,7 @@ export class UsersController {
}, },
}) })
async updatePreferences( async updatePreferences(
@Request() req: any, @Request() req: AuthRequest,
@Body('preferences') preferences: any, @Body('preferences') preferences: any,
): Promise<{ preferences: any }> { ): Promise<{ preferences: any }> {
const userId = req.user?.id; const userId = req.user?.id;
@ -194,7 +194,7 @@ export class UsersController {
}, },
}) })
async uploadAvatar( async uploadAvatar(
@Request() req: any, @Request() req: AuthRequest,
@UploadedFile() file: any, @UploadedFile() file: any,
): Promise<{ avatar_url: string }> { ): Promise<{ avatar_url: string }> {
const userId = req.user?.id; const userId = req.user?.id;
@ -230,7 +230,7 @@ export class UsersController {
}, },
}) })
@ApiResponse({ status: 401, description: 'No autenticado' }) @ApiResponse({ status: 401, description: 'No autenticado' })
async getStatistics(@Request() req: any): Promise<any> { async getStatistics(@Request() req: AuthRequest): Promise<any> {
const userId = req.user?.id; const userId = req.user?.id;
const statistics = await this.authService.getUserStatistics(userId); const statistics = await this.authService.getUserStatistics(userId);
return statistics; return statistics;

View File

@ -52,7 +52,7 @@ export class AssignRoleDto {
*/ */
@IsObject({ message: 'permissions debe ser un objeto JSON válido' }) @IsObject({ message: 'permissions debe ser un objeto JSON válido' })
@IsOptional() @IsOptional()
permissions?: Record<string, any>; permissions?: Record<string, unknown>;
/** /**
* Fecha y hora de expiración del rol (opcional) * Fecha y hora de expiración del rol (opcional)
@ -81,5 +81,5 @@ export class AssignRoleDto {
*/ */
@IsObject({ message: 'metadata debe ser un objeto JSON válido' }) @IsObject({ message: 'metadata debe ser un objeto JSON válido' })
@IsOptional() @IsOptional()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -205,7 +205,7 @@ export class CreateProfileDto {
*/ */
@IsObject() @IsObject()
@IsOptional() @IsOptional()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
/** /**
* ID del usuario en auth.users * ID del usuario en auth.users

View File

@ -126,7 +126,7 @@ export class CreateTenantDto {
*/ */
@IsObject({ message: 'Las configuraciones deben ser un objeto JSON válido' }) @IsObject({ message: 'Las configuraciones deben ser un objeto JSON válido' })
@IsOptional() @IsOptional()
settings?: Record<string, any>; settings?: Record<string, unknown>;
/** /**
* Metadata adicional del tenant (JSONB) * Metadata adicional del tenant (JSONB)
@ -135,5 +135,5 @@ export class CreateTenantDto {
*/ */
@IsObject({ message: 'La metadata debe ser un objeto JSON válido' }) @IsObject({ message: 'La metadata debe ser un objeto JSON válido' })
@IsOptional() @IsOptional()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -141,5 +141,5 @@ export class CreateUserPreferencesDto {
}) })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
preferences?: Record<string, any>; preferences?: Record<string, unknown>;
} }

View File

@ -55,5 +55,5 @@ export class CreateUserDto {
*/ */
@IsObject({ message: 'Los metadatos deben ser un objeto JSON' }) @IsObject({ message: 'Los metadatos deben ser un objeto JSON' })
@IsOptional() @IsOptional()
raw_user_meta_data?: Record<string, any>; raw_user_meta_data?: Record<string, unknown>;
} }

View File

@ -87,7 +87,7 @@ export class ProfileResponseDto {
last_activity_at!: Date | null; last_activity_at!: Date | null;
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
@Expose() @Expose()
created_at!: Date; created_at!: Date;

View File

@ -39,7 +39,7 @@ export class RegisterUserDto {
*/ */
@IsObject({ message: 'Los metadatos deben ser un objeto JSON' }) @IsObject({ message: 'Los metadatos deben ser un objeto JSON' })
@IsOptional() @IsOptional()
raw_user_meta_data?: Record<string, any>; raw_user_meta_data?: Record<string, unknown>;
// Campos opcionales adicionales para registro: // Campos opcionales adicionales para registro:
// Nota: Estos campos se podrían mapear al Profile (auth_management.profiles) // Nota: Estos campos se podrían mapear al Profile (auth_management.profiles)

View File

@ -75,13 +75,13 @@ export class TenantResponseDto {
* Configuraciones del tenant (JSONB) * Configuraciones del tenant (JSONB)
*/ */
@Expose() @Expose()
settings!: Record<string, any>; settings!: Record<string, unknown>;
/** /**
* Metadata adicional del tenant (JSONB) * Metadata adicional del tenant (JSONB)
*/ */
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* Fecha de creación del tenant * Fecha de creación del tenant

View File

@ -20,7 +20,7 @@ export class UpdateUserDto extends PartialType(
) { ) {
// Hereda de CreateUserDto excepto password y email: // Hereda de CreateUserDto excepto password y email:
// - role?: GamilityRoleEnum // - role?: GamilityRoleEnum
// - raw_user_meta_data?: Record<string, any> // - raw_user_meta_data?: Record<string, unknown>
// Campos opcionales adicionales para actualización: // Campos opcionales adicionales para actualización:
// (actualmente solo role y raw_user_meta_data son editables) // (actualmente solo role y raw_user_meta_data son editables)

View File

@ -99,7 +99,7 @@ export class UserPreferencesResponseDto {
dashboard_layout: 'grid', dashboard_layout: 'grid',
}, },
}) })
preferences!: Record<string, any>; preferences!: Record<string, unknown>;
/** /**
* Fecha de creación * Fecha de creación

View File

@ -99,7 +99,7 @@ export class UserResponseDto {
* NOTA: Filtrar campos sensibles si existen * NOTA: Filtrar campos sensibles si existen
*/ */
@Expose() @Expose()
raw_user_meta_data!: Record<string, any>; raw_user_meta_data!: Record<string, unknown>;
/** /**
* Fecha y hora de creación del registro * Fecha y hora de creación del registro

View File

@ -38,7 +38,7 @@ export class UserRoleResponseDto {
* Permisos específicos asociados a este rol * Permisos específicos asociados a este rol
*/ */
@Expose() @Expose()
permissions!: Record<string, any>; permissions!: Record<string, unknown>;
/** /**
* ID del usuario (Profile) que asignó este rol (nullable) * ID del usuario (Profile) que asignó este rol (nullable)
@ -80,7 +80,7 @@ export class UserRoleResponseDto {
* Metadata adicional del user_role * Metadata adicional del user_role
*/ */
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* Fecha de creación del registro * Fecha de creación del registro

View File

@ -43,7 +43,7 @@ export class AuthAttempt {
attempted_at!: Date; attempted_at!: Date;
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
// NOTA: La tabla auth_attempts NO tiene user_id // NOTA: La tabla auth_attempts NO tiene user_id
// Es una tabla de auditoría independiente que solo registra el email // Es una tabla de auditoría independiente que solo registra el email

View File

@ -125,7 +125,7 @@ export class Profile {
last_activity_at!: Date | null; last_activity_at!: Date | null;
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
@CreateDateColumn({ type: 'timestamp with time zone' }) @CreateDateColumn({ type: 'timestamp with time zone' })
created_at!: Date; created_at!: Date;

View File

@ -84,7 +84,7 @@ export class SecurityEvent {
* @example { "failed_attempts": 3, "reason": "invalid_password" } * @example { "failed_attempts": 3, "reason": "invalid_password" }
*/ */
@Column({ type: 'jsonb', nullable: true }) @Column({ type: 'jsonb', nullable: true })
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
/** /**
* Fecha y hora de creación del evento * Fecha y hora de creación del evento

View File

@ -113,14 +113,14 @@ export class Tenant {
timezone: 'America/Mexico_City', timezone: 'America/Mexico_City',
}, },
}) })
settings!: Record<string, any>; settings!: Record<string, unknown>;
/** /**
* Metadata adicional del tenant (JSONB) * Metadata adicional del tenant (JSONB)
* @example { billing_contact: "admin@example.com", notes: "..." } * @example { billing_contact: "admin@example.com", notes: "..." }
*/ */
@Column({ type: 'jsonb', nullable: false, default: {} }) @Column({ type: 'jsonb', nullable: false, default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* Fecha de creación del tenant * Fecha de creación del tenant

View File

@ -117,7 +117,7 @@ export class UserPreferences {
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
@Index('idx_user_preferences_preferences', { synchronize: false }) // GIN index creado en DDL @Index('idx_user_preferences_preferences', { synchronize: false }) // GIN index creado en DDL
preferences!: Record<string, any>; preferences!: Record<string, unknown>;
/** /**
* Fecha de creación * Fecha de creación

View File

@ -92,7 +92,7 @@ export class UserRole {
nullable: false, nullable: false,
default: { read: true, write: false, admin: false, analytics: false }, default: { read: true, write: false, admin: false, analytics: false },
}) })
permissions!: Record<string, any>; permissions!: Record<string, unknown>;
/** /**
* ID del usuario (Profile) que asignó este rol (nullable) * ID del usuario (Profile) que asignó este rol (nullable)
@ -143,7 +143,7 @@ export class UserRole {
* @example { notes: "Rol temporal para proyecto X", reason: "..." } * @example { notes: "Rol temporal para proyecto X", reason: "..." }
*/ */
@Column({ type: 'jsonb', nullable: false, default: {} }) @Column({ type: 'jsonb', nullable: false, default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* Fecha de creación del registro * Fecha de creación del registro

View File

@ -77,7 +77,7 @@ export class UserSession {
revoked_at!: Date | null; revoked_at!: Date | null;
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
// Relaciones // Relaciones
@ManyToOne(() => User, { onDelete: 'CASCADE' }) @ManyToOne(() => User, { onDelete: 'CASCADE' })

View File

@ -137,7 +137,7 @@ export class User {
* Metadatos adicionales del usuario en formato JSON * Metadatos adicionales del usuario en formato JSON
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
raw_user_meta_data!: Record<string, any>; raw_user_meta_data!: Record<string, unknown>;
/** /**
* Fecha y hora de eliminación lógica (soft delete) * Fecha y hora de eliminación lógica (soft delete)

View File

@ -658,7 +658,7 @@ export class AuthService {
* @returns UserResponseDto con campos derivados calculados * @returns UserResponseDto con campos derivados calculados
*/ */
public toUserResponse(user: User): UserResponseDto { public toUserResponse(user: User): UserResponseDto {
const { _encrypted_password, ...userWithoutPassword } = user; const { encrypted_password: _encrypted_password, ...userWithoutPassword } = user;
// Calcular campos derivados para coherencia Frontend-Backend // Calcular campos derivados para coherencia Frontend-Backend
const emailVerified = !!user.email_confirmed_at; const emailVerified = !!user.email_confirmed_at;

View File

@ -42,9 +42,9 @@ export class ContentTemplatesController {
@ApiResponse({ status: 200, description: 'Lista de plantillas obtenida exitosamente', type: [ContentTemplateResponseDto] }) @ApiResponse({ status: 200, description: 'Lista de plantillas obtenida exitosamente', type: [ContentTemplateResponseDto] })
async findAll( async findAll(
@Query('type') type?: string, @Query('type') type?: string,
@Query('category') category?: string, @Query('category') _category?: string,
) { ) {
return this.templatesService.findAll(type, category); return this.templatesService.findAll(type);
} }
/** /**

View File

@ -38,11 +38,11 @@ export class ContentTemplateResponseDto {
@ApiProperty({ description: 'Estructura JSON de la plantilla' }) @ApiProperty({ description: 'Estructura JSON de la plantilla' })
@Expose() @Expose()
template_structure!: Record<string, any>; template_structure!: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Valores predeterminados' }) @ApiPropertyOptional({ description: 'Valores predeterminados' })
@Expose() @Expose()
default_values?: Record<string, any>; default_values?: Record<string, unknown>;
@ApiPropertyOptional({ description: 'Campos requeridos' }) @ApiPropertyOptional({ description: 'Campos requeridos' })
@Expose() @Expose()
@ -82,7 +82,7 @@ export class ContentTemplateResponseDto {
@ApiProperty({ description: 'Metadatos adicionales' }) @ApiProperty({ description: 'Metadatos adicionales' })
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
@ApiPropertyOptional({ description: 'ID del usuario creador' }) @ApiPropertyOptional({ description: 'ID del usuario creador' })
@Expose() @Expose()

View File

@ -62,7 +62,7 @@ export class CreateContentTemplateDto {
*/ */
@ApiProperty({ description: 'Estructura JSON de la plantilla', example: { sections: [], fields: [] } }) @ApiProperty({ description: 'Estructura JSON de la plantilla', example: { sections: [], fields: [] } })
@IsObject() @IsObject()
template_structure!: Record<string, any>; template_structure!: Record<string, unknown>;
/** /**
* Valores predeterminados JSON * Valores predeterminados JSON
@ -70,7 +70,7 @@ export class CreateContentTemplateDto {
@ApiPropertyOptional({ description: 'Valores predeterminados', example: { difficulty: 'medium', duration: 30 } }) @ApiPropertyOptional({ description: 'Valores predeterminados', example: { difficulty: 'medium', duration: 30 } })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
default_values?: Record<string, any>; default_values?: Record<string, unknown>;
/** /**
* Campos requeridos * Campos requeridos
@ -141,7 +141,7 @@ export class CreateContentTemplateDto {
@ApiPropertyOptional({ description: 'Metadatos adicionales', example: {} }) @ApiPropertyOptional({ description: 'Metadatos adicionales', example: {} })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
/** /**
* ID del creador * ID del creador

View File

@ -72,7 +72,7 @@ export class CreateMarieCurieContentDto {
*/ */
@ApiProperty({ description: 'Contenido estructurado JSON', example: { introduction: 'Texto introductorio...', main_content: 'Contenido principal...', key_points: [], timeline: [], quotes: [] } }) @ApiProperty({ description: 'Contenido estructurado JSON', example: { introduction: 'Texto introductorio...', main_content: 'Contenido principal...', key_points: [], timeline: [], quotes: [] } })
@IsObject() @IsObject()
content!: Record<string, any>; content!: Record<string, unknown>;
// ===================================================== // =====================================================
// EDUCATIONAL METADATA // EDUCATIONAL METADATA
@ -196,7 +196,7 @@ export class CreateMarieCurieContentDto {
@ApiPropertyOptional({ description: 'Contexto cultural JSON', example: {} }) @ApiPropertyOptional({ description: 'Contexto cultural JSON', example: {} })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
cultural_context?: Record<string, any>; cultural_context?: Record<string, unknown>;
// ===================================================== // =====================================================
// PUBLICATION STATUS // PUBLICATION STATUS
@ -286,5 +286,5 @@ export class CreateMarieCurieContentDto {
@ApiPropertyOptional({ description: 'Metadatos adicionales', example: {} }) @ApiPropertyOptional({ description: 'Metadatos adicionales', example: {} })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -260,7 +260,7 @@ export class CreateMediaFileDto {
@ApiPropertyOptional({ description: 'Información de procesamiento JSON', example: {} }) @ApiPropertyOptional({ description: 'Información de procesamiento JSON', example: {} })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
processing_info?: Record<string, any>; processing_info?: Record<string, unknown>;
// ===================================================== // =====================================================
// SEARCH & ORGANIZATION // SEARCH & ORGANIZATION
@ -381,7 +381,7 @@ export class CreateMediaFileDto {
@ApiPropertyOptional({ description: 'Datos EXIF JSON', example: {} }) @ApiPropertyOptional({ description: 'Datos EXIF JSON', example: {} })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
exif_data?: Record<string, any>; exif_data?: Record<string, unknown>;
/** /**
* Metadatos adicionales * Metadatos adicionales
@ -389,5 +389,5 @@ export class CreateMediaFileDto {
@ApiPropertyOptional({ description: 'Metadatos adicionales', example: {} }) @ApiPropertyOptional({ description: 'Metadatos adicionales', example: {} })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -45,7 +45,7 @@ export class MarieCurieContentResponseDto {
@ApiProperty({ description: 'Contenido estructurado JSON' }) @ApiProperty({ description: 'Contenido estructurado JSON' })
@Expose() @Expose()
content!: Record<string, any>; content!: Record<string, unknown>;
// ===================================================== // =====================================================
// EDUCATIONAL METADATA // EDUCATIONAL METADATA
@ -109,7 +109,7 @@ export class MarieCurieContentResponseDto {
@ApiProperty({ description: 'Contexto cultural JSON' }) @ApiProperty({ description: 'Contexto cultural JSON' })
@Expose() @Expose()
cultural_context!: Record<string, any>; cultural_context!: Record<string, unknown>;
// ===================================================== // =====================================================
// PUBLICATION STATUS // PUBLICATION STATUS
@ -161,7 +161,7 @@ export class MarieCurieContentResponseDto {
@ApiProperty({ description: 'Metadatos adicionales' }) @ApiProperty({ description: 'Metadatos adicionales' })
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
@ApiProperty({ description: 'Fecha de creación' }) @ApiProperty({ description: 'Fecha de creación' })
@Expose() @Expose()

View File

@ -145,7 +145,7 @@ export class MediaFileResponseDto {
@ApiProperty({ description: 'Información de procesamiento' }) @ApiProperty({ description: 'Información de procesamiento' })
@Expose() @Expose()
processing_info!: Record<string, any>; processing_info!: Record<string, unknown>;
// ===================================================== // =====================================================
// SEARCH & ORGANIZATION // SEARCH & ORGANIZATION
@ -213,11 +213,11 @@ export class MediaFileResponseDto {
@ApiProperty({ description: 'Datos EXIF' }) @ApiProperty({ description: 'Datos EXIF' })
@Expose() @Expose()
exif_data!: Record<string, any>; exif_data!: Record<string, unknown>;
@ApiProperty({ description: 'Metadatos adicionales' }) @ApiProperty({ description: 'Metadatos adicionales' })
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
// ===================================================== // =====================================================
// AUDIT TIMESTAMPS // AUDIT TIMESTAMPS

View File

@ -75,14 +75,14 @@ export class ContentTemplate {
* Define cómo se estructura el contenido * Define cómo se estructura el contenido
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
template_structure!: Record<string, any>; template_structure!: Record<string, unknown>;
/** /**
* Valores predeterminados JSON * Valores predeterminados JSON
* Valores iniciales al crear contenido desde esta plantilla * Valores iniciales al crear contenido desde esta plantilla
*/ */
@Column({ type: 'jsonb', nullable: true }) @Column({ type: 'jsonb', nullable: true })
default_values?: Record<string, any>; default_values?: Record<string, unknown>;
/** /**
* Campos requeridos en el contenido * Campos requeridos en el contenido
@ -146,7 +146,7 @@ export class ContentTemplate {
* Metadatos adicionales en formato JSON * Metadatos adicionales en formato JSON
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* Fecha y hora de creación del registro * Fecha y hora de creación del registro

View File

@ -96,7 +96,7 @@ export class MarieCurieContent {
main_content: '', main_content: '',
}, },
}) })
content!: Record<string, any>; content!: Record<string, unknown>;
// ===================================================== // =====================================================
// EDUCATIONAL METADATA // EDUCATIONAL METADATA
@ -190,7 +190,7 @@ export class MarieCurieContent {
* Contexto cultural en formato JSON * Contexto cultural en formato JSON
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
cultural_context!: Record<string, any>; cultural_context!: Record<string, unknown>;
// ===================================================== // =====================================================
// PUBLICATION STATUS // PUBLICATION STATUS
@ -265,7 +265,7 @@ export class MarieCurieContent {
* Metadatos adicionales en formato JSON * Metadatos adicionales en formato JSON
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* Fecha y hora de creación del registro * Fecha y hora de creación del registro

View File

@ -234,7 +234,7 @@ export class MediaFile {
* Información de procesamiento en formato JSON * Información de procesamiento en formato JSON
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
processing_info!: Record<string, any>; processing_info!: Record<string, unknown>;
// ===================================================== // =====================================================
// SEARCH & ORGANIZATION // SEARCH & ORGANIZATION
@ -326,13 +326,13 @@ export class MediaFile {
* Datos EXIF del archivo (imágenes) * Datos EXIF del archivo (imágenes)
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
exif_data!: Record<string, any>; exif_data!: Record<string, unknown>;
/** /**
* Metadatos adicionales en formato JSON * Metadatos adicionales en formato JSON
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
// ===================================================== // =====================================================
// AUDIT TIMESTAMPS // AUDIT TIMESTAMPS

View File

@ -38,7 +38,7 @@ export class ContentTemplatesService {
* @param category - Categoría (opcional, no usado en DDL pero útil para filtros futuros) * @param category - Categoría (opcional, no usado en DDL pero útil para filtros futuros)
* @returns Lista de plantillas * @returns Lista de plantillas
*/ */
async findAll(type?: string?: string): Promise<ContentTemplate[]> { async findAll(type?: string): Promise<ContentTemplate[]> {
const query = this.templateRepo.createQueryBuilder('t'); const query = this.templateRepo.createQueryBuilder('t');
if (type) { if (type) {
@ -140,7 +140,7 @@ export class ContentTemplatesService {
* @param category - Categoría de plantilla * @param category - Categoría de plantilla
* @returns Lista de plantillas de la categoría * @returns Lista de plantillas de la categoría
*/ */
async findByCategory(category: string): Promise<ContentTemplate[]> { async findByCategory(_category: string): Promise<ContentTemplate[]> {
// Actualmente retorna todas ya que no existe el campo category en DDL // Actualmente retorna todas ya que no existe el campo category en DDL
// Se puede extender con metadata o agregando el campo en una migración futura // Se puede extender con metadata o agregando el campo en una migración futura
return this.templateRepo.find({ return this.templateRepo.find({

View File

@ -90,7 +90,7 @@ export class ExercisesController {
*/ */
private normalizeSubmitData(dto: SubmitExerciseDto, req: any): { private normalizeSubmitData(dto: SubmitExerciseDto, req: any): {
userId: string; userId: string;
answers: Record<string, any>; answers: Record<string, unknown>;
timeSpentSeconds?: number; timeSpentSeconds?: number;
hintsUsed: number; hintsUsed: number;
powerupsUsed: string[]; powerupsUsed: string[];
@ -105,7 +105,7 @@ export class ExercisesController {
} }
// 2. Extraer respuestas (nuevo formato tiene prioridad) // 2. Extraer respuestas (nuevo formato tiene prioridad)
let answers: Record<string, any>; let answers: Record<string, unknown>;
if (dto.answers) { if (dto.answers) {
// Formato nuevo (estándar) // Formato nuevo (estándar)
@ -220,7 +220,7 @@ export class ExercisesController {
status: 500, status: 500,
description: 'Error interno del servidor', description: 'Error interno del servidor',
}) })
async findAll(@Request() req: any) { async findAll(@Request() req: AuthRequest) {
const userId = req.user.id; const userId = req.user.id;
const userRole = req.user.role; const userRole = req.user.role;
@ -372,7 +372,7 @@ export class ExercisesController {
}, },
}, },
}) })
async findOne(@Param('id') id: string, @Request() req: any) { async findOne(@Param('id') id: string, @Request() req: AuthRequest) {
const userId = req.user.id; const userId = req.user.id;
// Obtener ejercicio // Obtener ejercicio
@ -671,7 +671,7 @@ export class ExercisesController {
status: 404, status: 404,
description: 'Módulo no encontrado', description: 'Módulo no encontrado',
}) })
async findByModule(@Param('moduleId') moduleId: string, @Request() req: any) { async findByModule(@Param('moduleId') moduleId: string, @Request() req: AuthRequest) {
// Obtener ejercicios del módulo // Obtener ejercicios del módulo
const exercises = await this.exercisesService.findByModuleId(moduleId); const exercises = await this.exercisesService.findByModuleId(moduleId);
@ -818,7 +818,7 @@ export class ExercisesController {
}, },
}) })
async validateContentByExerciseType( async validateContentByExerciseType(
@Body() body: { exercise_type: ExerciseTypeEnum; content: Record<string, any> }, @Body() body: { exercise_type: ExerciseTypeEnum; content: Record<string, unknown> },
) { ) {
this.exercisesService.validateContentByExerciseType(body.exercise_type, body.content); this.exercisesService.validateContentByExerciseType(body.exercise_type, body.content);
return { return {
@ -943,7 +943,7 @@ export class ExercisesController {
async submitExercise( async submitExercise(
@Param('id') exerciseId: string, @Param('id') exerciseId: string,
@Body() dto: SubmitExerciseDto, @Body() dto: SubmitExerciseDto,
@Request() req: any, @Request() req: AuthRequest,
): Promise<SubmitExerciseResponseDto> { ): Promise<SubmitExerciseResponseDto> {
// ======================================== // ========================================
// 1. NORMALIZACIÓN // 1. NORMALIZACIÓN

View File

@ -80,7 +80,7 @@ export class MediaUploadController {
}) })
@ApiResponse({ status: 400, description: 'Archivo inválido o excede límite de tamaño' }) @ApiResponse({ status: 400, description: 'Archivo inválido o excede límite de tamaño' })
async uploadFile( async uploadFile(
@Request() req: any, @Request() req: AuthRequest,
@UploadedFile() file: any, @UploadedFile() file: any,
@Body() dto: UploadMediaDto, @Body() dto: UploadMediaDto,
): Promise<MediaAttachment> { ): Promise<MediaAttachment> {

View File

@ -349,7 +349,7 @@ export class MediaController {
}) })
async updateProcessingStatus( async updateProcessingStatus(
@Param('id') id: string, @Param('id') id: string,
@Body() body: { status: ProcessingStatusEnum; metadata?: Record<string, any> }, @Body() body: { status: ProcessingStatusEnum; metadata?: Record<string, unknown> },
) { ) {
return this.mediaService.updateProcessingStatus(id, body.status, body.metadata); return this.mediaService.updateProcessingStatus(id, body.status, body.metadata);
} }

View File

@ -110,7 +110,7 @@ export class ModulesController {
status: 500, status: 500,
description: 'Error interno del servidor', description: 'Error interno del servidor',
}) })
async findAll(@Request() req: any, @Query() query: GetModulesQueryDto) { async findAll(@Request() req: AuthRequest, @Query() query: GetModulesQueryDto) {
const userId = req.user.id; const userId = req.user.id;
// Reutilizar getUserModules que ya tiene la lógica correcta para ambas tablas // Reutilizar getUserModules que ya tiene la lógica correcta para ambas tablas
// Ahora acepta classroomId opcional para filtrar // Ahora acepta classroomId opcional para filtrar

View File

@ -84,7 +84,7 @@ export class CreateExerciseDto {
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
config?: Record<string, any>; config?: Record<string, unknown>;
/** /**
* Contenido del ejercicio (JSONB) (REQUERIDO) * Contenido del ejercicio (JSONB) (REQUERIDO)
@ -92,21 +92,21 @@ export class CreateExerciseDto {
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
content?: Record<string, any>; content?: Record<string, unknown>;
/** /**
* Solución del ejercicio (JSONB) * Solución del ejercicio (JSONB)
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
solution?: Record<string, any>; solution?: Record<string, unknown>;
/** /**
* Rúbrica de evaluación (JSONB) * Rúbrica de evaluación (JSONB)
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
rubric?: Record<string, any>; rubric?: Record<string, unknown>;
// ===================================================== // =====================================================
// GRADING & SCORING // GRADING & SCORING
@ -233,7 +233,7 @@ export class CreateExerciseDto {
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
comodines_config?: Record<string, any>; comodines_config?: Record<string, unknown>;
// ===================================================== // =====================================================
// GAMIFICATION & REWARDS // GAMIFICATION & REWARDS
@ -345,5 +345,5 @@ export class CreateExerciseDto {
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -61,16 +61,16 @@ export class ExerciseResponseDto {
exercise_type!: ExerciseTypeEnum; exercise_type!: ExerciseTypeEnum;
@Expose() @Expose()
config!: Record<string, any>; config!: Record<string, unknown>;
@Expose() @Expose()
content!: Record<string, any>; content!: Record<string, unknown>;
@Expose() @Expose()
solution?: Record<string, any>; solution?: Record<string, unknown>;
@Expose() @Expose()
rubric?: Record<string, any>; rubric?: Record<string, unknown>;
// ===================================================== // =====================================================
// GRADING & SCORING // GRADING & SCORING
@ -132,7 +132,7 @@ export class ExerciseResponseDto {
comodines_allowed!: ComodinTypeEnum[]; comodines_allowed!: ComodinTypeEnum[];
@Expose() @Expose()
comodines_config!: Record<string, any>; comodines_config!: Record<string, unknown>;
// ===================================================== // =====================================================
// GAMIFICATION & REWARDS // GAMIFICATION & REWARDS
@ -187,7 +187,7 @@ export class ExerciseResponseDto {
prerequisites?: string[]; prerequisites?: string[];
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
// ===================================================== // =====================================================
// AUDIT FIELDS // AUDIT FIELDS

View File

@ -60,7 +60,7 @@ export class SubmitExerciseDto {
@IsOptional() @IsOptional()
@IsObject({ message: 'answers must be an object' }) @IsObject({ message: 'answers must be an object' })
@IsNotEmpty({ message: 'answers cannot be empty' }) @IsNotEmpty({ message: 'answers cannot be empty' })
answers?: Record<string, any>; answers?: Record<string, unknown>;
/** /**
* Timestamp de inicio del ejercicio (milisegundos desde epoch) * Timestamp de inicio del ejercicio (milisegundos desde epoch)
@ -133,7 +133,7 @@ export class SubmitExerciseDto {
}) })
@IsOptional() @IsOptional()
@IsObject() @IsObject()
submitted_answers?: Record<string, any>; submitted_answers?: Record<string, unknown>;
/** /**
* @deprecated Usar 'startedAt' para calcular tiempo * @deprecated Usar 'startedAt' para calcular tiempo

View File

@ -211,7 +211,7 @@ export class MediaResponseDto {
* Metadatos adicionales * Metadatos adicionales
*/ */
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* Fecha de creación * Fecha de creación

View File

@ -246,5 +246,5 @@ export class UploadMediaDto {
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
} }

View File

@ -46,7 +46,7 @@ export class InfografiaInteractivaAnswerDto {
}, },
}) })
@IsObject({ message: 'answers must be an object' }) @IsObject({ message: 'answers must be an object' })
answers: Record<string, any>; answers: Record<string, unknown>;
@ApiProperty({ @ApiProperty({
description: description:

View File

@ -59,5 +59,5 @@ export class NavegacionHipertextualAnswerDto {
}, },
}) })
@IsObject({ message: 'information_found must be an object' }) @IsObject({ message: 'information_found must be an object' })
information_found: Record<string, any>; information_found: Record<string, unknown>;
} }

View File

@ -66,7 +66,7 @@ export class CreateModuleDto {
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
content?: Record<string, any>; content?: Record<string, unknown>;
/** /**
* Índice de orden para la secuencia de módulos (REQUERIDO) * Índice de orden para la secuencia de módulos (REQUERIDO)
@ -345,14 +345,14 @@ export class CreateModuleDto {
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
settings?: Record<string, any>; settings?: Record<string, unknown>;
/** /**
* Metadatos adicionales (JSONB) * Metadatos adicionales (JSONB)
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
/** /**
* Total de ejercicios en el módulo * Total de ejercicios en el módulo

View File

@ -34,7 +34,7 @@ export class ModuleResponseDto {
summary?: string; summary?: string;
@Expose() @Expose()
content!: Record<string, any>; content!: Record<string, unknown>;
@Expose() @Expose()
order_index!: number; order_index!: number;
@ -165,10 +165,10 @@ export class ModuleResponseDto {
cover_image_url?: string; cover_image_url?: string;
@Expose() @Expose()
settings!: Record<string, any>; settings!: Record<string, unknown>;
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
// ===================================================== // =====================================================
// AUDIT FIELDS // AUDIT FIELDS

View File

@ -65,7 +65,7 @@ export class CreateRubricDto {
* Estructura: {"criteria_1": {"name": string, "levels": {}, "weight": number}} * Estructura: {"criteria_1": {"name": string, "levels": {}, "weight": number}}
*/ */
@IsObject() @IsObject()
criteria!: Record<string, any>; criteria!: Record<string, unknown>;
/** /**
* Escala de puntuación en formato JSONB * Escala de puntuación en formato JSONB
@ -73,7 +73,7 @@ export class CreateRubricDto {
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
scoring_scale?: Record<string, any>; scoring_scale?: Record<string, unknown>;
/** /**
* Peso porcentual de esta rúbrica (1-100%) * Peso porcentual de esta rúbrica (1-100%)
@ -125,7 +125,7 @@ export class CreateRubricDto {
*/ */
@IsOptional() @IsOptional()
@IsObject() @IsObject()
metadata?: Record<string, any>; metadata?: Record<string, unknown>;
/** /**
* ID del usuario que crea la rúbrica * ID del usuario que crea la rúbrica

View File

@ -55,13 +55,13 @@ export class RubricResponseDto {
* Criterios de evaluación en formato JSONB * Criterios de evaluación en formato JSONB
*/ */
@Expose() @Expose()
criteria!: Record<string, any>; criteria!: Record<string, unknown>;
/** /**
* Escala de puntuación * Escala de puntuación
*/ */
@Expose() @Expose()
scoring_scale!: Record<string, any>; scoring_scale!: Record<string, unknown>;
/** /**
* Peso porcentual de la rúbrica * Peso porcentual de la rúbrica
@ -105,7 +105,7 @@ export class RubricResponseDto {
* Metadatos adicionales * Metadatos adicionales
*/ */
@Expose() @Expose()
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* ID del usuario que creó la rúbrica * ID del usuario que creó la rúbrica

View File

@ -76,14 +76,14 @@ export class AssessmentRubric {
* Incluye niveles de logro con puntos y descripciones * Incluye niveles de logro con puntos y descripciones
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
criteria: Record<string, any> = {}; criteria: Record<string, unknown> = {};
/** /**
* Escala de puntuación en formato JSONB * Escala de puntuación en formato JSONB
* Estructura: {"min": number, "max": number, "passing": number} * Estructura: {"min": number, "max": number, "passing": number}
*/ */
@Column({ type: 'jsonb', default: { min: 0, max: 100, passing: 70 } }) @Column({ type: 'jsonb', default: { min: 0, max: 100, passing: 70 } })
scoring_scale!: Record<string, any>; scoring_scale!: Record<string, unknown>;
/** /**
* Peso porcentual de esta rúbrica en la evaluación total (1-100%) * Peso porcentual de esta rúbrica en la evaluación total (1-100%)
@ -120,7 +120,7 @@ export class AssessmentRubric {
* Puede incluir configuraciones específicas de evaluación * Puede incluir configuraciones específicas de evaluación
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* ID del usuario que creó la rúbrica * ID del usuario que creó la rúbrica

View File

@ -150,7 +150,7 @@ export class Exercise {
* - etc. * - etc.
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
config!: Record<string, any>; config!: Record<string, unknown>;
/** /**
* Contenido del ejercicio (JSONB) * Contenido del ejercicio (JSONB)
@ -165,20 +165,20 @@ export class Exercise {
correct_answers: [], correct_answers: [],
}, },
}) })
content!: Record<string, any>; content!: Record<string, unknown>;
/** /**
* Solución del ejercicio (JSONB) * Solución del ejercicio (JSONB)
* Información privada no visible para estudiantes durante la resolución * Información privada no visible para estudiantes durante la resolución
*/ */
@Column({ type: 'jsonb', nullable: true }) @Column({ type: 'jsonb', nullable: true })
solution?: Record<string, any>; solution?: Record<string, unknown>;
/** /**
* Rúbrica de evaluación (JSONB) * Rúbrica de evaluación (JSONB)
*/ */
@Column({ type: 'jsonb', nullable: true }) @Column({ type: 'jsonb', nullable: true })
rubric?: Record<string, any>; rubric?: Record<string, unknown>;
// ===================================================== // =====================================================
// GRADING & SCORING // GRADING & SCORING
@ -328,7 +328,7 @@ export class Exercise {
segunda_oportunidad: { cost: 40, enabled: true }, segunda_oportunidad: { cost: 40, enabled: true },
}, },
}) })
comodines_config!: Record<string, any>; comodines_config!: Record<string, unknown>;
// ===================================================== // =====================================================
// GAMIFICATION & REWARDS // GAMIFICATION & REWARDS
@ -423,7 +423,7 @@ export class Exercise {
* Metadatos adicionales (JSONB) * Metadatos adicionales (JSONB)
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
// ===================================================== // =====================================================
// AUDIT FIELDS // AUDIT FIELDS

View File

@ -241,7 +241,7 @@ export class MediaResource {
* Puede incluir información técnica, codec, bitrate, etc. * Puede incluir información técnica, codec, bitrate, etc.
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
/** /**
* Fecha y hora de creación del registro * Fecha y hora de creación del registro

View File

@ -94,7 +94,7 @@ export class Module {
multimedia_resources: [], multimedia_resources: [],
}, },
}) })
content!: Record<string, any>; content!: Record<string, unknown>;
/** /**
* Índice de orden para la secuencia de módulos * Índice de orden para la secuencia de módulos
@ -350,13 +350,13 @@ export class Module {
* Configuraciones del módulo (JSONB) * Configuraciones del módulo (JSONB)
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
settings!: Record<string, any>; settings!: Record<string, unknown>;
/** /**
* Metadatos adicionales (JSONB) * Metadatos adicionales (JSONB)
*/ */
@Column({ type: 'jsonb', default: {} }) @Column({ type: 'jsonb', default: {} })
metadata!: Record<string, any>; metadata!: Record<string, unknown>;
// ===================================================== // =====================================================
// AUDIT FIELDS // AUDIT FIELDS

View File

@ -195,8 +195,8 @@ export class ExercisesService {
*/ */
validateContentByExerciseType( validateContentByExerciseType(
exerciseType: ExerciseTypeEnum, exerciseType: ExerciseTypeEnum,
content: Record<string, any>, content: Record<string, unknown>,
config?: Record<string, any>, config?: Record<string, unknown>,
): void { ): void {
if (!content) { if (!content) {
throw new BadRequestException('Content is required'); throw new BadRequestException('Content is required');
@ -474,10 +474,10 @@ export class ExercisesService {
* @returns Sanitized content without correct answers * @returns Sanitized content without correct answers
*/ */
private sanitizeContent( private sanitizeContent(
content: Record<string, any>, content: Record<string, unknown>,
config: Record<string, any>, config: Record<string, unknown>,
exerciseType: ExerciseTypeEnum, exerciseType: ExerciseTypeEnum,
): Record<string, any> { ): Record<string, unknown> {
if (!content) { if (!content) {
return content; return content;
} }

View File

@ -85,7 +85,7 @@ export class MediaService {
async updateProcessingStatus( async updateProcessingStatus(
id: string, id: string,
status: ProcessingStatusEnum, status: ProcessingStatusEnum,
metadata?: Record<string, any>, metadata?: Record<string, unknown>,
): Promise<MediaResource> { ): Promise<MediaResource> {
const media = await this.findById(id); const media = await this.findById(id);
if (!media) { if (!media) {

View File

@ -141,7 +141,7 @@ export class ClassroomMissionsController {
async assignMissionToClassroom( async assignMissionToClassroom(
@Param('classroomId') classroomId: string, @Param('classroomId') classroomId: string,
@Body() dto: AssignClassroomMissionDto, @Body() dto: AssignClassroomMissionDto,
@Request() req: any, @Request() req: AuthRequest,
) { ) {
const teacherId = req.user.id; const teacherId = req.user.id;
return this.classroomMissionsService.assignMissionToClassroom(classroomId, teacherId, dto); return this.classroomMissionsService.assignMissionToClassroom(classroomId, teacherId, dto);

Some files were not shown because too many files have changed in this diff Show More