diff --git a/src/ab-testing/ab-testing.controller.ts b/src/ab-testing/ab-testing.controller.ts index f3ff6d87..4682ea78 100644 --- a/src/ab-testing/ab-testing.controller.ts +++ b/src/ab-testing/ab-testing.controller.ts @@ -22,6 +22,9 @@ import { RolesGuard } from '../auth/guards/roles.guard'; import { Roles } from '../auth/decorators/roles.decorator'; import { UserRole } from '../users/entities/user.entity'; +/** + * Exposes AB testing endpoints. + */ @Controller('ab-testing') @UseGuards(JwtAuthGuard, RolesGuard) export class ABTestingController { @@ -35,6 +38,10 @@ export class ABTestingController { private reportsService: ABTestingReportsService, ) {} + /** + * Returns all Experiments. + * @returns The operation result. + */ @Get('experiments') @Roles(UserRole.ADMIN, UserRole.TEACHER) async getAllExperiments(): Promise { @@ -42,12 +49,22 @@ export class ABTestingController { return await this.abTestingService.getAllExperiments(); } + /** + * Returns experiment By Id. + * @param id The identifier. + * @returns The operation result. + */ @Get('experiments/:id') async getExperimentById(@Param('id') id: string): Promise { this.logger.log(`Fetching experiment: ${id}`); return await this.abTestingService.getExperimentById(id); } + /** + * Creates experiment. + * @param createExperimentDto The request payload. + * @returns The operation result. + */ @Post('experiments') @HttpCode(HttpStatus.CREATED) @Roles(UserRole.ADMIN) @@ -56,6 +73,11 @@ export class ABTestingController { return await this.abTestingService.createExperiment(createExperimentDto); } + /** + * Starts experiment. + * @param id The identifier. + * @returns The operation result. + */ @Post('experiments/:id/start') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -64,6 +86,11 @@ export class ABTestingController { return await this.abTestingService.startExperiment(id); } + /** + * Stops experiment. + * @param id The identifier. + * @returns The operation result. + */ @Post('experiments/:id/stop') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -72,6 +99,12 @@ export class ABTestingController { return await this.abTestingService.stopExperiment(id); } + /** + * Updates experiment. + * @param id The identifier. + * @param updateData The data to process. + * @returns The operation result. + */ @Put('experiments/:id') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -80,6 +113,11 @@ export class ABTestingController { return await this.experimentService.updateExperiment(id, updateData); } + /** + * Removes experiment. + * @param id The identifier. + * @returns The operation result. + */ @Delete('experiments/:id') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -89,12 +127,23 @@ export class ABTestingController { return { message: 'Experiment deleted successfully' }; } + /** + * Returns experiment Results. + * @param id The identifier. + * @returns The operation result. + */ @Get('experiments/:id/results') async getExperimentResults(@Param('id') id: string): Promise { this.logger.log(`Fetching results for experiment: ${id}`); return await this.experimentService.getExperimentResults(id); } + /** + * Adds a variant. + * @param experimentId The experiment identifier. + * @param variantData The data to process. + * @returns The operation result. + */ @Post('experiments/:id/variants') @HttpCode(HttpStatus.CREATED) @Roles(UserRole.ADMIN) @@ -103,6 +152,11 @@ export class ABTestingController { return await this.experimentService.addVariant(experimentId, variantData); } + /** + * Removes variant. + * @param variantId The variant identifier. + * @returns The operation result. + */ @Delete('variants/:id') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -112,6 +166,12 @@ export class ABTestingController { return { message: 'Variant removed successfully' }; } + /** + * Updates traffic Allocation. + * @param experimentId The experiment identifier. + * @param allocations The allocations. + * @returns The operation result. + */ @Put('experiments/:id/traffic-allocation') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -124,18 +184,34 @@ export class ABTestingController { return { message: 'Traffic allocation updated successfully' }; } + /** + * Returns statistical Analysis. + * @param id The identifier. + * @returns The operation result. + */ @Get('experiments/:id/statistical-analysis') async getStatisticalAnalysis(@Param('id') id: string): Promise { this.logger.log(`Performing statistical analysis for experiment: ${id}`); return await this.statisticalAnalysisService.calculateStatisticalSignificance(id); } + /** + * Returns effect Size. + * @param id The identifier. + * @returns The operation result. + */ @Get('experiments/:id/effect-size') async getEffectSize(@Param('id') id: string): Promise { this.logger.log(`Calculating effect size for experiment: ${id}`); return await this.statisticalAnalysisService.calculateEffectSize(id); } + /** + * Automatically selects a winner. + * @param id The identifier. + * @param criteria The criteria. + * @returns The operation result. + */ @Post('experiments/:id/auto-select-winner') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -144,12 +220,22 @@ export class ABTestingController { return await this.automatedDecisionService.autoSelectWinner(id, criteria); } + /** + * Returns decision Recommendations. + * @param id The identifier. + * @returns The operation result. + */ @Get('experiments/:id/decision-recommendations') async getDecisionRecommendations(@Param('id') id: string): Promise { this.logger.log(`Getting decision recommendations for experiment: ${id}`); return await this.automatedDecisionService.getDecisionRecommendations(id); } + /** + * Automatically allocates traffic. + * @param id The identifier. + * @returns The operation result. + */ @Post('experiments/:id/auto-allocate-traffic') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -159,6 +245,11 @@ export class ABTestingController { return { message: 'Traffic auto-allocated successfully' }; } + /** + * Returns dashboard Summary. + * @param filters The filter criteria. + * @returns The operation result. + */ @Get('reports/dashboard') @Roles(UserRole.ADMIN, UserRole.TEACHER) async getDashboardSummary(@Query() filters?: any): Promise { @@ -166,24 +257,42 @@ export class ABTestingController { return await this.reportsService.getDashboardSummary(filters); } + /** + * Generates experiment Report. + * @param id The identifier. + * @returns The operation result. + */ @Get('reports/experiment/:id') async generateExperimentReport(@Param('id') id: string): Promise { this.logger.log(`Generating report for experiment: ${id}`); return await this.reportsService.generateExperimentReport(id); } + /** + * Returns performance Comparison Report. + * @returns The operation result. + */ @Get('reports/performance-comparison') async getPerformanceComparisonReport(): Promise { this.logger.log('Generating performance comparison report'); return await this.reportsService.generatePerformanceComparisonReport(); } + /** + * Returns experiment Timeline. + * @returns The operation result. + */ @Get('reports/timeline') async getExperimentTimeline(): Promise { this.logger.log('Generating experiment timeline'); return await this.reportsService.getExperimentTimeline(); } + /** + * Exports experiment Data. + * @param id The identifier. + * @returns The operation result. + */ @Get('reports/experiment/:id/export') async exportExperimentData(@Param('id') id: string): Promise { this.logger.log(`Exporting data for experiment: ${id}`); @@ -194,6 +303,11 @@ export class ABTestingController { }; } + /** + * Pauses experiment. + * @param id The identifier. + * @returns The operation result. + */ @Post('experiments/:id/pause') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -202,6 +316,11 @@ export class ABTestingController { return await this.experimentService.pauseExperiment(id); } + /** + * Resumes experiment. + * @param id The identifier. + * @returns The operation result. + */ @Post('experiments/:id/resume') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -210,6 +329,11 @@ export class ABTestingController { return await this.experimentService.resumeExperiment(id); } + /** + * Archives experiment. + * @param id The identifier. + * @returns The operation result. + */ @Post('experiments/:id/archive') @HttpCode(HttpStatus.OK) @Roles(UserRole.ADMIN) @@ -218,6 +342,12 @@ export class ABTestingController { return await this.experimentService.archiveExperiment(id); } + /** + * Assigns user To Variant. + * @param experimentId The experiment identifier. + * @param userId The user identifier. + * @returns The operation result. + */ @Get('experiments/:id/assign-user/:userId') @Roles(UserRole.ADMIN) async assignUserToVariant( diff --git a/src/ab-testing/ab-testing.module.ts b/src/ab-testing/ab-testing.module.ts index fd2ea095..8713de22 100644 --- a/src/ab-testing/ab-testing.module.ts +++ b/src/ab-testing/ab-testing.module.ts @@ -11,6 +11,9 @@ import { AutomatedDecisionService } from './automation/automated-decision.servic import { ABTestingReportsService } from './reporting/ab-testing-reports.service'; import { ABTestingController } from './ab-testing.controller'; +/** + * Registers the aBTesting module. + */ @Module({ imports: [ TypeOrmModule.forFeature([Experiment, IExperimentVariant, ExperimentMetric, VariantMetric]), diff --git a/src/ab-testing/ab-testing.service.ts b/src/ab-testing/ab-testing.service.ts index b3ea915d..2d3ab9f4 100644 --- a/src/ab-testing/ab-testing.service.ts +++ b/src/ab-testing/ab-testing.service.ts @@ -36,6 +36,9 @@ export interface ICreateMetricDto { configuration?: any; } +/** + * Provides aBTesting operations. + */ @Injectable() export class ABTestingService { private readonly logger = new Logger(ABTestingService.name); diff --git a/src/ab-testing/analysis/statistical-analysis.service.ts b/src/ab-testing/analysis/statistical-analysis.service.ts index 1756db9b..bf1ec8f9 100644 --- a/src/ab-testing/analysis/statistical-analysis.service.ts +++ b/src/ab-testing/analysis/statistical-analysis.service.ts @@ -5,6 +5,9 @@ import { Experiment } from '../entities/experiment.entity'; import { IExperimentVariant } from '../entities/experiment-variant.entity'; import { VariantMetric } from '../entities/variant-metric.entity'; +/** + * Provides statistical Analysis operations. + */ @Injectable() export class StatisticalAnalysisService { private readonly logger = new Logger(StatisticalAnalysisService.name); diff --git a/src/ab-testing/automation/automated-decision.service.ts b/src/ab-testing/automation/automated-decision.service.ts index 7a400666..f9065a7a 100644 --- a/src/ab-testing/automation/automated-decision.service.ts +++ b/src/ab-testing/automation/automated-decision.service.ts @@ -13,6 +13,9 @@ export interface IWinnerSelectionCriteria { durationThreshold: number; // in days } +/** + * Provides automated Decision operations. + */ @Injectable() export class AutomatedDecisionService { private readonly logger = new Logger(AutomatedDecisionService.name); diff --git a/src/ab-testing/entities/experiment-metric.entity.ts b/src/ab-testing/entities/experiment-metric.entity.ts index 2df85eac..b015af22 100644 --- a/src/ab-testing/entities/experiment-metric.entity.ts +++ b/src/ab-testing/entities/experiment-metric.entity.ts @@ -17,6 +17,9 @@ export enum MetricType { CUSTOM = 'custom', } +/** + * Represents the experiment Metric entity. + */ @Entity({ name: 'experiment_metrics' }) export class ExperimentMetric { @PrimaryGeneratedColumn('uuid') diff --git a/src/ab-testing/entities/experiment-variant.entity.ts b/src/ab-testing/entities/experiment-variant.entity.ts index 7f9e0023..00c68e36 100644 --- a/src/ab-testing/entities/experiment-variant.entity.ts +++ b/src/ab-testing/entities/experiment-variant.entity.ts @@ -12,6 +12,9 @@ import { import { Experiment } from './experiment.entity'; import { VariantMetric } from './variant-metric.entity'; +/** + * Represents the experiment Variant entity. + */ @Entity({ name: 'experiment_variants' }) export class IExperimentVariant { @PrimaryGeneratedColumn('uuid') diff --git a/src/ab-testing/entities/experiment.entity.ts b/src/ab-testing/entities/experiment.entity.ts index 512c44bb..e92a41df 100644 --- a/src/ab-testing/entities/experiment.entity.ts +++ b/src/ab-testing/entities/experiment.entity.ts @@ -24,6 +24,9 @@ export enum ExperimentType { MULTI_ARMED_BANDIT = 'multi_armed_bandit', } +/** + * Represents the experiment entity. + */ @Entity({ name: 'experiments' }) export class Experiment { @PrimaryGeneratedColumn('uuid') diff --git a/src/ab-testing/entities/variant-metric.entity.ts b/src/ab-testing/entities/variant-metric.entity.ts index 6af50c21..4355ddce 100644 --- a/src/ab-testing/entities/variant-metric.entity.ts +++ b/src/ab-testing/entities/variant-metric.entity.ts @@ -9,6 +9,9 @@ import { } from 'typeorm'; import { IExperimentVariant } from './experiment-variant.entity'; +/** + * Represents the variant Metric entity. + */ @Entity({ name: 'variant_metrics' }) export class VariantMetric { @PrimaryGeneratedColumn('uuid') diff --git a/src/ab-testing/experiments/experiment.service.ts b/src/ab-testing/experiments/experiment.service.ts index b338177e..c6026a29 100644 --- a/src/ab-testing/experiments/experiment.service.ts +++ b/src/ab-testing/experiments/experiment.service.ts @@ -6,6 +6,9 @@ import { IExperimentVariant } from '../entities/experiment-variant.entity'; import { ExperimentMetric } from '../entities/experiment-metric.entity'; import { VariantMetric } from '../entities/variant-metric.entity'; +/** + * Provides experiment operations. + */ @Injectable() export class ExperimentService { private readonly logger = new Logger(ExperimentService.name); diff --git a/src/ab-testing/reporting/ab-testing-reports.service.ts b/src/ab-testing/reporting/ab-testing-reports.service.ts index 9dd76efb..ab8a3c53 100644 --- a/src/ab-testing/reporting/ab-testing-reports.service.ts +++ b/src/ab-testing/reporting/ab-testing-reports.service.ts @@ -14,6 +14,9 @@ export interface IReportFilters { includeArchived?: boolean; } +/** + * Provides aBTesting Reports operations. + */ @Injectable() export class ABTestingReportsService { private readonly logger = new Logger(ABTestingReportsService.name); diff --git a/src/app.controller.ts b/src/app.controller.ts index 1888bb9b..95614359 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -4,6 +4,9 @@ import { ApiTags, ApiResponse } from '@nestjs/swagger'; import { AppService } from './app.service'; import { AnalyticsService } from './analytics/analytics.service'; +/** + * Exposes app endpoints. + */ @ApiTags('app') @Controller() export class AppController { @@ -12,6 +15,10 @@ export class AppController { private readonly analyticsService: AnalyticsService, ) {} + /** + * Returns hello. + * @returns The resulting string value. + */ @Get() @ApiResponse({ status: HttpStatus.OK, description: 'Root endpoint response' }) getHello(): string { diff --git a/src/app.module.ts b/src/app.module.ts index d08efbbe..a87256b6 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -65,6 +65,10 @@ import { LoggingInterceptor } from './common/interceptors/logging.interceptor'; @Global() @Module({}) export class AppModule { + /** + * Creates the root application module. + * @returns The resulting dynamic module. + */ static async forRoot(): Promise { const flags = loadFeatureFlags(); const startupLogger = new StartupLogger(); diff --git a/src/app.service.ts b/src/app.service.ts index 927d7cca..6dccefba 100644 --- a/src/app.service.ts +++ b/src/app.service.ts @@ -1,7 +1,14 @@ import { Injectable } from '@nestjs/common'; +/** + * Provides app operations. + */ @Injectable() export class AppService { + /** + * Retrieves hello. + * @returns The resulting string value. + */ getHello(): string { return 'Hello World!'; } diff --git a/src/assessment/assessment.controller.ts b/src/assessment/assessment.controller.ts index 7af50f2b..5c4b4ee3 100644 --- a/src/assessment/assessment.controller.ts +++ b/src/assessment/assessment.controller.ts @@ -2,10 +2,19 @@ import { Body, Controller, Get, Param, Post, UseGuards, Request } from '@nestjs/ import { AssessmentsService } from './assessments.service'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; +/** + * Exposes assessments endpoints. + */ @Controller('assessments') export class AssessmentsController { constructor(private readonly service: AssessmentsService) {} + /** + * Starts start. + * @param req The req. + * @param id The identifier. + * @returns The operation result. + */ @Post(':id/start') @UseGuards(JwtAuthGuard) start(@Request() req: any, @Param('id') id: string): any { @@ -16,12 +25,25 @@ export class AssessmentsController { return this.service.startAssessment(studentId, id); } + /** + * Submits submit. + * @param req The req. + * @param id The identifier. + * @param answers The answers. + * @returns The operation result. + */ @Post('attempts/:id/submit') @UseGuards(JwtAuthGuard) submit(@Request() req: any, @Param('id') id: string, @Body('answers') answers: any[]): any { return this.service.submitAssessment(id, answers); } + /** + * Executes results. + * @param req The req. + * @param id The identifier. + * @returns The operation result. + */ @Get('attempts/:id') @UseGuards(JwtAuthGuard) results(@Request() req: any, @Param('id') id: string): any { diff --git a/src/assessment/assessment.module.ts b/src/assessment/assessment.module.ts index 50a1df71..502d4336 100644 --- a/src/assessment/assessment.module.ts +++ b/src/assessment/assessment.module.ts @@ -10,6 +10,9 @@ import { QuestionBankService } from './questions/question-bank.service'; import { ScoreCalculationService } from './scoring/score-calculation.service'; import { Module } from '@nestjs/common'; +/** + * Registers the assessments module. + */ @Module({ imports: [TypeOrmModule.forFeature([Assessment, Question, AssessmentAttempt, Answer])], controllers: [AssessmentsController], diff --git a/src/assessment/assessments.service.ts b/src/assessment/assessments.service.ts index 1f2f9487..3f4b2de7 100644 --- a/src/assessment/assessments.service.ts +++ b/src/assessment/assessments.service.ts @@ -9,6 +9,9 @@ import { Answer } from './entities/answer.entity'; import { ScoreCalculationService } from './scoring/score-calculation.service'; import { Question } from './entities/question.entity'; +/** + * Provides assessment operations. + */ @Injectable() export class AssessmentsService { constructor( @@ -22,6 +25,12 @@ export class AssessmentsService { private readonly feedbackService: FeedbackGenerationService, ) {} + /** + * Starts assessment. + * @param studentId The student identifier. + * @param assessmentId The assessment identifier. + * @returns The operation result. + */ async startAssessment(studentId: string, assessmentId: string) { const assessment = await this.assessmentRepo.findOne({ where: { id: assessmentId }, @@ -36,12 +45,21 @@ export class AssessmentsService { }); } + /** + * Retrieves all matching results. + * @returns The matching results. + */ async findAll(): Promise { return await this.assessmentRepo.find({ relations: ['questions'], }); } + /** + * Retrieves the requested record. + * @param id The identifier. + * @returns The resulting assessment. + */ async findOne(id: string): Promise { return await this.assessmentRepo.findOne({ where: { id }, @@ -49,22 +67,42 @@ export class AssessmentsService { }); } + /** + * Retrieves records by their identifiers. + * @param ids The identifiers. + * @returns The matching results. + */ async findByIds(ids: string[]): Promise { if (ids.length === 0) return []; return await this.assessmentRepo.findByIds(ids); } + /** + * Creates a new record. + * @param data The data to process. + * @returns The resulting assessment. + */ async create(data: any): Promise { const assessment = this.assessmentRepo.create(data); const saved = await this.assessmentRepo.save(assessment); return Array.isArray(saved) ? saved[0] : saved; } + /** + * Updates the requested record. + * @param id The identifier. + * @param data The data to process. + * @returns The resulting assessment. + */ async update(id: string, data: any): Promise { await this.assessmentRepo.update(id, data); return this.findOne(id); } + /** + * Removes the requested record. + * @param id The identifier. + */ async remove(id: string): Promise { const assessment = await this.findOne(id); if (!assessment) { @@ -82,6 +120,12 @@ export class AssessmentsService { }); } + /** + * Submits assessment. + * @param attemptId The attempt identifier. + * @param answers The answers. + * @returns The operation result. + */ async submitAssessment(attemptId: string, answers: any[]) { const attempt = await this.attemptRepo.findOne({ where: { id: attemptId }, @@ -126,6 +170,11 @@ export class AssessmentsService { }; } + /** + * Retrieves results. + * @param attemptId The attempt identifier. + * @returns The operation result. + */ getResults(attemptId: string) { return this.attemptRepo.findOne({ where: { id: attemptId }, diff --git a/src/assessment/dto/create-assessment.dto.ts b/src/assessment/dto/create-assessment.dto.ts index 8188cab5..791cf385 100644 --- a/src/assessment/dto/create-assessment.dto.ts +++ b/src/assessment/dto/create-assessment.dto.ts @@ -24,6 +24,9 @@ export enum AssessmentStatus { ARCHIVED = 'archived', } +/** + * Defines the create Assessment payload. + */ export class CreateAssessmentDto { @ApiProperty({ description: 'Assessment title', diff --git a/src/assessment/dto/update-assessment.dto.ts b/src/assessment/dto/update-assessment.dto.ts index 8034569e..0b45176e 100644 --- a/src/assessment/dto/update-assessment.dto.ts +++ b/src/assessment/dto/update-assessment.dto.ts @@ -1,4 +1,7 @@ import { PartialType } from '@nestjs/swagger'; import { CreateAssessmentDto } from './create-assessment.dto'; +/** + * Defines the update Assessment payload. + */ export class UpdateAssessmentDto extends PartialType(CreateAssessmentDto) {} diff --git a/src/assessment/entities/answer.entity.ts b/src/assessment/entities/answer.entity.ts index fdf04582..a67a51ef 100644 --- a/src/assessment/entities/answer.entity.ts +++ b/src/assessment/entities/answer.entity.ts @@ -1,6 +1,9 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, VersionColumn } from 'typeorm'; import { AssessmentAttempt } from './assessment-attempt.entity'; import { Question } from './question.entity'; +/** + * Represents the answer entity. + */ @Entity() export class Answer { @PrimaryGeneratedColumn('uuid') diff --git a/src/assessment/entities/assessment-attempt.entity.ts b/src/assessment/entities/assessment-attempt.entity.ts index 460fbcd1..e271ce46 100644 --- a/src/assessment/entities/assessment-attempt.entity.ts +++ b/src/assessment/entities/assessment-attempt.entity.ts @@ -10,6 +10,9 @@ import { AssessmentStatus } from '../enums/assessment-status.enum'; import { Answer } from './answer.entity'; import { Assessment } from './assessment.entity'; +/** + * Represents the assessment Attempt entity. + */ @Entity() export class AssessmentAttempt { @PrimaryGeneratedColumn('uuid') diff --git a/src/assessment/entities/assessment.entity.ts b/src/assessment/entities/assessment.entity.ts index 95c447c6..a72d4c72 100644 --- a/src/assessment/entities/assessment.entity.ts +++ b/src/assessment/entities/assessment.entity.ts @@ -10,6 +10,9 @@ import { } from 'typeorm'; import { Question } from './question.entity'; +/** + * Represents the assessment entity. + */ @Entity() export class Assessment { @PrimaryGeneratedColumn('uuid') diff --git a/src/assessment/entities/question.entity.ts b/src/assessment/entities/question.entity.ts index 5353d0c9..b5e1cdd2 100644 --- a/src/assessment/entities/question.entity.ts +++ b/src/assessment/entities/question.entity.ts @@ -10,6 +10,9 @@ import { import { QuestionType } from '../enums/question-type.enum'; import { Assessment } from './assessment.entity'; +/** + * Represents the question entity. + */ @Entity() export class Question { @PrimaryGeneratedColumn('uuid') diff --git a/src/assessment/feedback/feedback-generation.service.ts b/src/assessment/feedback/feedback-generation.service.ts index e977d130..4638bd23 100644 --- a/src/assessment/feedback/feedback-generation.service.ts +++ b/src/assessment/feedback/feedback-generation.service.ts @@ -1,5 +1,8 @@ import { Injectable } from '@nestjs/common'; +/** + * Provides feedback Generation operations. + */ @Injectable() export class FeedbackGenerationService { generate(score: number, maxScore: number): string { diff --git a/src/assessment/questions/question-bank.service.ts b/src/assessment/questions/question-bank.service.ts index 58c2fa7d..4caf19b9 100644 --- a/src/assessment/questions/question-bank.service.ts +++ b/src/assessment/questions/question-bank.service.ts @@ -3,6 +3,9 @@ import { Repository } from 'typeorm'; import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; +/** + * Provides question Bank operations. + */ @Injectable() export class QuestionBankService { constructor( diff --git a/src/assessment/scoring/score-calculation.service.ts b/src/assessment/scoring/score-calculation.service.ts index 060be7be..2de06ebb 100644 --- a/src/assessment/scoring/score-calculation.service.ts +++ b/src/assessment/scoring/score-calculation.service.ts @@ -2,8 +2,17 @@ import { Injectable } from '@nestjs/common'; import { Question } from '../entities/question.entity'; import { QuestionType } from '../enums/question-type.enum'; +/** + * Provides score Calculation operations. + */ @Injectable() export class ScoreCalculationService { + /** + * Calculates calculate. + * @param question The question. + * @param response The response. + * @returns The calculated numeric value. + */ calculate(question: Question, response: any): number { switch (question.type) { case QuestionType.MULTIPLE_CHOICE: diff --git a/src/audit-log/audit-log.controller.ts b/src/audit-log/audit-log.controller.ts index 4c90427e..158eed79 100644 --- a/src/audit-log/audit-log.controller.ts +++ b/src/audit-log/audit-log.controller.ts @@ -27,6 +27,9 @@ import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { AuditAction, AuditCategory, AuditSeverity } from './enums/audit-action.enum'; import { SensitiveOperationsService } from './services/sensitive-operations.service'; +/** + * Exposes audit Log endpoints. + */ @ApiTags('Audit Logs') @ApiBearerAuth() @UseGuards(JwtAuthGuard) @@ -39,6 +42,27 @@ export class AuditLogController { private readonly sensitiveOpsService: SensitiveOperationsService, ) {} + /** + * Returns search. + * @param userId The user identifier. + * @param userEmail The email address. + * @param actions The actions. + * @param categories The categories. + * @param severities The severities. + * @param entityType The entity type. + * @param entityId The entity identifier. + * @param ipAddress The ip address. + * @param sessionId The session identifier. + * @param tenantId The tenant identifier. + * @param apiEndpoint The api endpoint. + * @param httpMethod The http method. + * @param statusCode The status value. + * @param startDate The start date. + * @param endDate The end date. + * @param page The page number. + * @param limit The maximum number of results. + * @returns The operation result. + */ @Get() @ApiOperation({ summary: 'Search audit logs with filters' }) @ApiQuery({ name: 'userId', required: false, description: 'Filter by user ID' }) @@ -111,6 +135,11 @@ export class AuditLogController { return this.auditLogService.search(filters, page, limit); } + /** + * Returns recent. + * @param limit The maximum number of results. + * @returns The matching results. + */ @Get('recent') @ApiOperation({ summary: 'Get recent audit logs' }) @ApiQuery({ @@ -126,6 +155,12 @@ export class AuditLogController { return this.auditLogService.findAll(limit); } + /** + * Returns by User. + * @param userId The user identifier. + * @param limit The maximum number of results. + * @returns The matching results. + */ @Get('user/:userId') @ApiOperation({ summary: 'Get audit logs for a specific user' }) @ApiParam({ name: 'userId', description: 'User ID' }) @@ -143,6 +178,13 @@ export class AuditLogController { return this.auditLogService.findByUser(userId, limit); } + /** + * Returns by Entity. + * @param entityType The entity type. + * @param entityId The entity identifier. + * @param limit The maximum number of results. + * @returns The matching results. + */ @Get('entity/:entityType/:entityId') @ApiOperation({ summary: 'Get audit logs for a specific entity' }) @ApiParam({ name: 'entityType', description: 'Entity type (e.g., user, course)' }) @@ -162,6 +204,12 @@ export class AuditLogController { return this.auditLogService.findByEntity(entityType, entityId, limit); } + /** + * Returns by Ip Address. + * @param ipAddress The ip address. + * @param limit The maximum number of results. + * @returns The matching results. + */ @Get('ip/:ipAddress') @ApiOperation({ summary: 'Get audit logs by IP address' }) @ApiParam({ name: 'ipAddress', description: 'IP address' }) @@ -179,6 +227,10 @@ export class AuditLogController { return this.auditLogService.findByIpAddress(ipAddress, limit); } + /** + * Returns statistics. + * @returns The operation result. + */ @Get('statistics') @ApiOperation({ summary: 'Get audit log statistics' }) @ApiResponse({ status: 200, description: 'Statistics' }) @@ -186,6 +238,12 @@ export class AuditLogController { return this.auditLogService.getStatistics(); } + /** + * Generates report. + * @param startDate The start date. + * @param endDate The end date. + * @returns The operation result. + */ @Get('report') @ApiOperation({ summary: 'Generate audit report' }) @ApiQuery({ name: 'startDate', required: true, description: 'Start date (ISO 8601)' }) @@ -199,6 +257,15 @@ export class AuditLogController { return this.auditLogService.generateReport(new Date(startDate), new Date(endDate)); } + /** + * Exports to Json. + * @param res The res. + * @param userId The user identifier. + * @param actions The actions. + * @param startDate The start date. + * @param endDate The end date. + * @returns The operation result. + */ @Post('export/json') @ApiOperation({ summary: 'Export audit logs to JSON' }) @ApiQuery({ name: 'userId', required: false }) @@ -225,6 +292,15 @@ export class AuditLogController { res.send(json); } + /** + * Exports to Csv. + * @param res The res. + * @param userId The user identifier. + * @param actions The actions. + * @param startDate The start date. + * @param endDate The end date. + * @returns The operation result. + */ @Post('export/csv') @ApiOperation({ summary: 'Export audit logs to CSV' }) @ApiQuery({ name: 'userId', required: false }) @@ -251,6 +327,10 @@ export class AuditLogController { res.send(csv); } + /** + * Applies retention Policy. + * @returns The operation result. + */ @Post('retention/apply') @ApiOperation({ summary: 'Apply retention policy (delete old logs)' }) @ApiResponse({ status: 200, description: 'Retention policy applied' }) diff --git a/src/audit-log/audit-log.entity.ts b/src/audit-log/audit-log.entity.ts index d0ad2cb7..b9e890db 100644 --- a/src/audit-log/audit-log.entity.ts +++ b/src/audit-log/audit-log.entity.ts @@ -8,6 +8,9 @@ import { } from 'typeorm'; import { AuditAction, AuditSeverity, AuditCategory } from './enums/audit-action.enum'; +/** + * Represents the audit Log entity. + */ @Entity('audit_logs') @Index(['userId', 'timestamp']) @Index(['action', 'timestamp']) diff --git a/src/audit-log/audit-log.module.ts b/src/audit-log/audit-log.module.ts index 3e2b1220..f0c10170 100644 --- a/src/audit-log/audit-log.module.ts +++ b/src/audit-log/audit-log.module.ts @@ -9,6 +9,9 @@ import { AuditLogInterceptor } from './interceptors/audit-log.interceptor'; import { AuditRetentionTask } from './tasks/audit-retention.task'; import { SensitiveOperationsService } from './services/sensitive-operations.service'; +/** + * Registers the audit Log module. + */ @Module({ imports: [TypeOrmModule.forFeature([AuditLog]), ConfigModule, ScheduleModule.forRoot()], controllers: [AuditLogController], diff --git a/src/audit-log/audit-log.service.ts b/src/audit-log/audit-log.service.ts index 691c8bb4..bb21bb79 100644 --- a/src/audit-log/audit-log.service.ts +++ b/src/audit-log/audit-log.service.ts @@ -71,6 +71,9 @@ export interface IAuditReport { failedActions: Array<{ action: string; count: number }>; } +/** + * Provides audit Log operations. + */ @Injectable() export class AuditLogService { private readonly logger = new Logger(AuditLogService.name); diff --git a/src/audit-log/interceptors/audit-log.interceptor.ts b/src/audit-log/interceptors/audit-log.interceptor.ts index c947de81..baf804e1 100644 --- a/src/audit-log/interceptors/audit-log.interceptor.ts +++ b/src/audit-log/interceptors/audit-log.interceptor.ts @@ -14,12 +14,21 @@ interface IRequestWithUser extends Request { requestId?: string; } +/** + * Intercepts audit Log request handling. + */ @Injectable() export class AuditLogInterceptor implements NestInterceptor { private readonly logger = new Logger(AuditLogInterceptor.name); constructor(private readonly auditLogService: AuditLogService) {} + /** + * Executes intercept. + * @param context The context. + * @param next The next. + * @returns The resulting observable. + */ intercept(context: ExecutionContext, next: CallHandler): Observable { const request = context.switchToHttp().getRequest(); const response = context.switchToHttp().getResponse(); diff --git a/src/audit-log/tasks/audit-retention.task.ts b/src/audit-log/tasks/audit-retention.task.ts index 5b73e583..6e0cca88 100644 --- a/src/audit-log/tasks/audit-retention.task.ts +++ b/src/audit-log/tasks/audit-retention.task.ts @@ -2,6 +2,9 @@ import { Injectable, Logger } from '@nestjs/common'; import { Cron, CronExpression } from '@nestjs/schedule'; import { AuditLogService } from '../audit-log.service'; +/** + * Provides audit Retention Task behavior. + */ @Injectable() export class AuditRetentionTask { private readonly logger = new Logger(AuditRetentionTask.name); diff --git a/src/auth/auth.controller.ts b/src/auth/auth.controller.ts index 12e24827..8c86ec4d 100644 --- a/src/auth/auth.controller.ts +++ b/src/auth/auth.controller.ts @@ -16,11 +16,20 @@ import { import { JwtAuthGuard } from './guards/jwt-auth.guard'; import { CurrentUser } from './decorators/current-user.decorator'; +/** + * Exposes auth endpoints. + */ @ApiTags('auth') @Controller('auth') export class AuthController { constructor(private readonly authService: AuthService) {} + /** + * Registers register. + * @param registerDto The request payload. + * @param req The req. + * @returns The operation result. + */ @Post('register') @Throttle({ default: THROTTLE.STRICT }) @ApiOperation({ summary: 'Register a new user' }) @@ -30,6 +39,12 @@ export class AuthController { return this.authService.register(registerDto, ipAddress, userAgent); } + /** + * Executes login. + * @param loginDto The request payload. + * @param req The req. + * @returns The operation result. + */ @Post('login') @Throttle({ default: THROTTLE.AUTH_LOGIN }) @ApiOperation({ summary: 'Login user and get tokens' }) @@ -39,6 +54,11 @@ export class AuthController { return this.authService.login(loginDto, ipAddress, userAgent); } + /** + * Refreshes refresh. + * @param refreshTokenDto The request payload. + * @returns The operation result. + */ @Post('refresh') @Throttle({ default: THROTTLE.REFRESH }) @ApiOperation({ summary: 'Refresh access token using refresh token' }) @@ -46,6 +66,12 @@ export class AuthController { return this.authService.refreshToken(refreshTokenDto.refreshToken); } + /** + * Executes logout. + * @param user The user. + * @param req The req. + * @returns The operation result. + */ @Post('logout') @UseGuards(JwtAuthGuard) @ApiBearerAuth() @@ -56,6 +82,11 @@ export class AuthController { return this.authService.logout(user.userId, user.sessionId, ipAddress, userAgent); } + /** + * Executes forgot Password. + * @param forgotPasswordDto The request payload. + * @returns The operation result. + */ @Post('forgot-password') @Throttle({ default: THROTTLE.AUTH_DEFAULT }) @ApiOperation({ summary: 'Request a password reset link' }) @@ -63,6 +94,11 @@ export class AuthController { return this.authService.forgotPassword(forgotPasswordDto.email); } + /** + * Resets password. + * @param resetPasswordDto The request payload. + * @returns The operation result. + */ @Post('reset-password') @Throttle({ default: THROTTLE.AUTH_DEFAULT }) @ApiOperation({ summary: 'Reset password using token' }) @@ -70,6 +106,13 @@ export class AuthController { return this.authService.resetPassword(resetPasswordDto); } + /** + * Executes change Password. + * @param user The user. + * @param changePasswordDto The request payload. + * @param req The req. + * @returns The operation result. + */ @Post('change-password') @UseGuards(JwtAuthGuard) @ApiBearerAuth() @@ -84,6 +127,11 @@ export class AuthController { return this.authService.changePassword(user.userId, changePasswordDto, ipAddress, userAgent); } + /** + * Validates email. + * @param verifyEmailDto The request payload. + * @returns The operation result. + */ @Post('verify-email') @Throttle({ default: THROTTLE.MODERATE }) @ApiOperation({ summary: 'Verify email using token' }) diff --git a/src/auth/auth.service.ts b/src/auth/auth.service.ts index 3c4e016b..91ebfa17 100644 --- a/src/auth/auth.service.ts +++ b/src/auth/auth.service.ts @@ -58,6 +58,9 @@ interface ITokenUser { role: UserRole; } +/** + * Provides auth operations. + */ @Injectable() export class AuthService { private readonly logger = new Logger(AuthService.name); @@ -73,6 +76,13 @@ export class AuthService { private readonly passwordPolicyService: PasswordPolicyService, ) {} + /** + * Registers register. + * @param registerDto The request payload. + * @param ipAddress The ip address. + * @param userAgent The user agent. + * @returns The resulting register response. + */ async register( registerDto: RegisterDto, ipAddress?: string, @@ -262,6 +272,14 @@ export class AuthService { } } + /** + * Executes logout. + * @param userId The user identifier. + * @param sessionId The session identifier. + * @param ipAddress The ip address. + * @param userAgent The user agent. + * @returns The operation result. + */ async logout( userId: string, sessionId?: string, @@ -290,6 +308,11 @@ export class AuthService { return { message: 'Logout successful' }; } + /** + * Executes forgot Password. + * @param email The email address. + * @returns The operation result. + */ async forgotPassword(email: string): Promise<{ message: string }> { const user = await this.usersService.findByEmail(email); if (!user) { @@ -309,6 +332,11 @@ export class AuthService { return { message: 'If the email exists, a password reset link has been sent.' }; } + /** + * Resets password. + * @param resetPasswordDto The request payload. + * @returns The operation result. + */ async resetPassword(resetPasswordDto: ResetPasswordDto): Promise<{ message: string }> { await this.passwordPolicyService.enforce(resetPasswordDto.newPassword); @@ -330,6 +358,14 @@ export class AuthService { return { message: 'Password has been reset successfully' }; } + /** + * Executes change Password. + * @param userId The user identifier. + * @param changePasswordDto The request payload. + * @param ipAddress The ip address. + * @param userAgent The user agent. + * @returns The operation result. + */ async changePassword( userId: string, changePasswordDto: ChangePasswordDto, @@ -371,6 +407,11 @@ export class AuthService { return { message: 'Password changed successfully' }; } + /** + * Validates email. + * @param token The token value. + * @returns The operation result. + */ async verifyEmail(token: string): Promise<{ message: string }> { // Find user by verification token const userOrNull = await this.usersService.findByEmailVerificationToken(token); diff --git a/src/auth/dto/auth.dto.ts b/src/auth/dto/auth.dto.ts index 0db261a6..491da0ef 100644 --- a/src/auth/dto/auth.dto.ts +++ b/src/auth/dto/auth.dto.ts @@ -3,6 +3,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { UserRole } from '../../users/entities/user.entity'; import { IsStrongPassword } from '../../common/validators/password.validator'; +/** + * Defines the register payload. + */ export class RegisterDto { @ApiProperty({ example: 'john.doe@example.com' }) @IsEmail({}, { message: 'Must be a valid email address' }) @@ -30,6 +33,9 @@ export class RegisterDto { role?: UserRole; } +/** + * Defines the login payload. + */ export class LoginDto { @ApiProperty({ example: 'john.doe@example.com' }) @IsEmail({}, { message: 'Must be a valid email address' }) @@ -42,6 +48,9 @@ export class LoginDto { password: string; } +/** + * Defines the refresh Token payload. + */ export class RefreshTokenDto { @ApiProperty() @IsString() @@ -49,6 +58,9 @@ export class RefreshTokenDto { refreshToken: string; } +/** + * Defines the forgot Password payload. + */ export class ForgotPasswordDto { @ApiProperty({ example: 'john.doe@example.com' }) @IsEmail({}, { message: 'Must be a valid email address' }) @@ -56,6 +68,9 @@ export class ForgotPasswordDto { email: string; } +/** + * Defines the reset Password payload. + */ export class ResetPasswordDto { @ApiProperty() @IsString() @@ -68,6 +83,9 @@ export class ResetPasswordDto { newPassword: string; } +/** + * Defines the change Password payload. + */ export class ChangePasswordDto { @ApiProperty({ example: 'OldPass123!' }) @IsString() @@ -80,6 +98,9 @@ export class ChangePasswordDto { newPassword: string; } +/** + * Defines the verify Email payload. + */ export class VerifyEmailDto { @ApiProperty() @IsString() diff --git a/src/auth/guards/jwt-auth.guard.ts b/src/auth/guards/jwt-auth.guard.ts index 91447a67..7eddb37d 100644 --- a/src/auth/guards/jwt-auth.guard.ts +++ b/src/auth/guards/jwt-auth.guard.ts @@ -2,5 +2,8 @@ import { Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { AUTH_STRATEGY } from '../../common/constants/auth.constants'; +/** + * Protects jwt Auth execution paths. + */ @Injectable() export class JwtAuthGuard extends AuthGuard(AUTH_STRATEGY.JWT) {} diff --git a/src/auth/guards/roles.guard.ts b/src/auth/guards/roles.guard.ts index bf7aeac7..713f2f49 100644 --- a/src/auth/guards/roles.guard.ts +++ b/src/auth/guards/roles.guard.ts @@ -3,10 +3,18 @@ import { Reflector } from '@nestjs/core'; import { ROLES_KEY } from '../decorators/roles.decorator'; import { UserRole } from '../../users/entities/user.entity'; +/** + * Protects roles execution paths. + */ @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} + /** + * Executes can Activate. + * @param context The context. + * @returns Whether the operation succeeded. + */ canActivate(context: ExecutionContext): boolean { const requiredRoles = this.reflector.getAllAndOverride(ROLES_KEY, [ context.getHandler(), diff --git a/src/auth/guards/ws-jwt-auth.guard.ts b/src/auth/guards/ws-jwt-auth.guard.ts index 67c7920a..14f13154 100644 --- a/src/auth/guards/ws-jwt-auth.guard.ts +++ b/src/auth/guards/ws-jwt-auth.guard.ts @@ -4,6 +4,9 @@ import { ConfigService } from '@nestjs/config'; import { Socket } from 'socket.io'; import * as jwt from 'jsonwebtoken'; +/** + * Protects ws Jwt Auth execution paths. + */ @Injectable() export class WsJwtAuthGuard implements CanActivate { constructor( @@ -11,6 +14,11 @@ export class WsJwtAuthGuard implements CanActivate { private readonly configService: ConfigService, ) {} + /** + * Executes can Activate. + * @param context The context. + * @returns Whether the operation succeeded. + */ async canActivate(context: ExecutionContext): Promise { const client: Socket = context.switchToWs().getClient(); const token = diff --git a/src/auth/jwt.strategy.ts b/src/auth/jwt.strategy.ts index 5695a93a..4bc0a528 100644 --- a/src/auth/jwt.strategy.ts +++ b/src/auth/jwt.strategy.ts @@ -21,6 +21,9 @@ interface IValidatedUser { sid: string; } +/** + * Implements the jwt strategy. + */ @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor( diff --git a/src/auth/strategies/jwt.strategy.ts b/src/auth/strategies/jwt.strategy.ts index fa7e52cb..dffc1e0a 100644 --- a/src/auth/strategies/jwt.strategy.ts +++ b/src/auth/strategies/jwt.strategy.ts @@ -14,6 +14,9 @@ export interface IJwtPayload { sid?: string; } +/** + * Implements the jwt strategy. + */ @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor( diff --git a/src/backup/backup.controller.ts b/src/backup/backup.controller.ts index 31be6689..073ee851 100644 --- a/src/backup/backup.controller.ts +++ b/src/backup/backup.controller.ts @@ -18,6 +18,9 @@ import { RestoreBackupDto } from './dto/restore-backup.dto'; import { TriggerRecoveryTestDto } from './dto/trigger-recovery-test.dto'; import { RecoveryTestResponseDto } from './dto/recovery-test-response.dto'; +/** + * Exposes backup endpoints. + */ @ApiTags('backup') @ApiBearerAuth() @UseGuards(JwtAuthGuard) @@ -29,6 +32,11 @@ export class BackupController { private readonly backupMonitoringService: BackupMonitoringService, ) {} + /** + * Executes restore Backup. + * @param dto The dto. + * @returns The operation result. + */ @Post('restore') @ApiOperation({ summary: 'Restore from backup' }) @ApiResponse({ status: HttpStatus.ACCEPTED, description: 'Restore initiated' }) @@ -38,6 +46,11 @@ export class BackupController { return { message: 'Restore initiated' }; } + /** + * Executes trigger Recovery Test. + * @param dto The dto. + * @returns The resulting recovery test response dto. + */ @Post('test') @ApiOperation({ summary: 'Trigger recovery test' }) @ApiResponse({ status: HttpStatus.OK, description: 'Recovery test triggered' }) @@ -45,6 +58,11 @@ export class BackupController { return this.recoveryTestingService.createRecoveryTest(dto.backupRecordId); } + /** + * Returns recovery Test. + * @param testId The test identifier. + * @returns The resulting recovery test response dto. + */ @Get('test/:testId') @ApiOperation({ summary: 'Get recovery test results' }) @ApiResponse({ @@ -58,6 +76,10 @@ export class BackupController { return this.recoveryTestingService.getTestResults(testId); } + /** + * Returns backup Health. + * @returns The operation result. + */ @Get('health') @ApiOperation({ summary: 'Get backup system health' }) @ApiResponse({ status: HttpStatus.OK, description: 'Backup health status' }) diff --git a/src/backup/backup.module.ts b/src/backup/backup.module.ts index 0d8ee817..515ba664 100644 --- a/src/backup/backup.module.ts +++ b/src/backup/backup.module.ts @@ -26,6 +26,9 @@ import { BackupQueueProcessor } from './processing/backup-queue.processor'; import { MediaModule } from '../media/media.module'; import { MonitoringModule } from '../monitoring/monitoring.module'; +/** + * Registers the backup module. + */ @Module({ imports: [ ConfigModule, diff --git a/src/backup/backup.service.ts b/src/backup/backup.service.ts index 67342b1a..dc88ab30 100644 --- a/src/backup/backup.service.ts +++ b/src/backup/backup.service.ts @@ -20,6 +20,9 @@ import { } from '../monitoring/scheduled-task-monitoring.service'; import { TIME } from '../common/constants/time.constants'; +/** + * Provides backup operations. + */ @Injectable() export class BackupService { private readonly logger = new Logger(BackupService.name); @@ -230,6 +233,11 @@ export class BackupService { await new Promise((resolve) => setTimeout(resolve, ms)); } + /** + * Retrieves latest Backup. + * @param region The region. + * @returns The operation result. + */ async getLatestBackup(region?: Region): Promise { const where: any = { status: BackupStatus.COMPLETED, @@ -245,6 +253,12 @@ export class BackupService { }); } + /** + * Updates backup Status. + * @param backupId The backup identifier. + * @param status The status value. + * @param updates The updates. + */ async updateBackupStatus( backupId: string, status: BackupStatus, @@ -271,6 +285,11 @@ export class BackupService { } } + /** + * Executes to Response Dto. + * @param backup The backup. + * @returns The resulting backup response dto. + */ toResponseDto(backup: BackupRecord): BackupResponseDto { return { id: backup.id, diff --git a/src/backup/disaster-recovery/disaster-recovery.service.ts b/src/backup/disaster-recovery/disaster-recovery.service.ts index e9a76013..2b509fe4 100644 --- a/src/backup/disaster-recovery/disaster-recovery.service.ts +++ b/src/backup/disaster-recovery/disaster-recovery.service.ts @@ -11,6 +11,9 @@ import * as fs from 'fs'; const execAsync = promisify(exec); const RTO_THRESHOLD_SECONDS = 900; // 15 minutes +/** + * Provides disaster Recovery operations. + */ @Injectable() export class DisasterRecoveryService { private readonly logger = new Logger(DisasterRecoveryService.name); @@ -26,6 +29,10 @@ export class DisasterRecoveryService { this.kmsClient = new KMSClient({ region: awsRegion }); } + /** + * Executes execute Restore. + * @param backupId The backup identifier. + */ async executeRestore(backupId: string): Promise { this.logger.log(`Starting disaster recovery restore for backup: ${backupId}`); diff --git a/src/backup/dto/backup-response.dto.ts b/src/backup/dto/backup-response.dto.ts index bee58496..8d28928d 100644 --- a/src/backup/dto/backup-response.dto.ts +++ b/src/backup/dto/backup-response.dto.ts @@ -12,6 +12,9 @@ import { IsDate, } from 'class-validator'; +/** + * Defines the backup Response payload. + */ export class BackupResponseDto { @ApiProperty() @IsNotEmpty() diff --git a/src/backup/dto/recovery-test-response.dto.ts b/src/backup/dto/recovery-test-response.dto.ts index 15c20604..d51409b7 100644 --- a/src/backup/dto/recovery-test-response.dto.ts +++ b/src/backup/dto/recovery-test-response.dto.ts @@ -2,6 +2,9 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { RecoveryTestStatus } from '../enums/recovery-test-status.enum'; import { IsNotEmpty, IsUUID, IsString, IsOptional, IsNumber, IsDate } from 'class-validator'; +/** + * Defines the recovery Test Response payload. + */ export class RecoveryTestResponseDto { @ApiProperty() @IsNotEmpty() diff --git a/src/backup/dto/restore-backup.dto.ts b/src/backup/dto/restore-backup.dto.ts index 989c087b..77578772 100644 --- a/src/backup/dto/restore-backup.dto.ts +++ b/src/backup/dto/restore-backup.dto.ts @@ -1,6 +1,9 @@ import { IsUUID, IsNotEmpty, IsString } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +/** + * Defines the restore Backup payload. + */ export class RestoreBackupDto { @ApiProperty({ description: 'Backup record ID to restore from' }) @IsUUID() diff --git a/src/backup/dto/trigger-recovery-test.dto.ts b/src/backup/dto/trigger-recovery-test.dto.ts index 050000f1..c3480c81 100644 --- a/src/backup/dto/trigger-recovery-test.dto.ts +++ b/src/backup/dto/trigger-recovery-test.dto.ts @@ -1,6 +1,9 @@ import { IsUUID, IsNotEmpty, IsString } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +/** + * Defines the trigger Recovery Test payload. + */ export class TriggerRecoveryTestDto { @ApiProperty({ description: 'Backup record ID to test' }) @IsUUID() diff --git a/src/backup/entities/backup-record.entity.ts b/src/backup/entities/backup-record.entity.ts index 6a327026..da62f12e 100644 --- a/src/backup/entities/backup-record.entity.ts +++ b/src/backup/entities/backup-record.entity.ts @@ -12,6 +12,9 @@ import { BackupStatus } from '../enums/backup-status.enum'; import { BackupType } from '../enums/backup-type.enum'; import { Region } from '../enums/region.enum'; +/** + * Represents the backup Record entity. + */ @Entity('backup_records') @Index(['status', 'createdAt']) @Index(['region']) diff --git a/src/backup/entities/recovery-test.entity.ts b/src/backup/entities/recovery-test.entity.ts index 980579d0..5b981f17 100644 --- a/src/backup/entities/recovery-test.entity.ts +++ b/src/backup/entities/recovery-test.entity.ts @@ -12,6 +12,9 @@ import { import { RecoveryTestStatus } from '../enums/recovery-test-status.enum'; import { BackupRecord } from './backup-record.entity'; +/** + * Represents the recovery Test entity. + */ @Entity('recovery_tests') @Index(['status', 'createdAt']) @Index(['backupRecordId']) diff --git a/src/backup/integrity/data-integrity.service.ts b/src/backup/integrity/data-integrity.service.ts index d45df828..39ba9b03 100644 --- a/src/backup/integrity/data-integrity.service.ts +++ b/src/backup/integrity/data-integrity.service.ts @@ -6,6 +6,9 @@ import { FileStorageService } from '../../media/storage/file-storage.service'; import * as crypto from 'crypto'; import * as fs from 'fs'; +/** + * Provides data Integrity operations. + */ @Injectable() export class DataIntegrityService { private readonly logger = new Logger(DataIntegrityService.name); @@ -16,6 +19,11 @@ export class DataIntegrityService { private readonly fileStorageService: FileStorageService, ) {} + /** + * Validates backup Integrity. + * @param backupId The backup identifier. + * @returns Whether the operation succeeded. + */ async verifyBackupIntegrity(backupId: string): Promise { this.logger.log(`Verifying backup integrity for: ${backupId}`); @@ -65,6 +73,11 @@ export class DataIntegrityService { } } + /** + * Calculates checksums. + * @param filePath The file to process. + * @returns The operation result. + */ async calculateChecksums(filePath: string): Promise<{ md5: string; sha256: string }> { const fileBuffer = await fs.promises.readFile(filePath); diff --git a/src/backup/monitoring/backup-monitoring.service.ts b/src/backup/monitoring/backup-monitoring.service.ts index c2359cf2..7afb0335 100644 --- a/src/backup/monitoring/backup-monitoring.service.ts +++ b/src/backup/monitoring/backup-monitoring.service.ts @@ -9,6 +9,9 @@ import { MetricsCollectionService } from '../../monitoring/metrics/metrics-colle import { AlertingService } from '../../monitoring/alerting/alerting.service'; import { Histogram, Counter } from 'prom-client'; +/** + * Provides backup Monitoring operations. + */ @Injectable() export class BackupMonitoringService { private readonly logger = new Logger(BackupMonitoringService.name); @@ -45,6 +48,10 @@ export class BackupMonitoringService { }); } + /** + * Validates backup Health. + * @returns The operation result. + */ async checkBackupHealth(): Promise<{ healthy: boolean; issues: string[] }> { const issues: string[] = []; @@ -91,6 +98,11 @@ export class BackupMonitoringService { }; } + /** + * Records backup Metrics. + * @param backupId The backup identifier. + * @param duration The duration. + */ async recordBackupMetrics(backupId: string, duration: number): Promise { const backup = await this.backupRepository.findOne({ where: { id: backupId }, diff --git a/src/backup/testing/recovery-testing.service.ts b/src/backup/testing/recovery-testing.service.ts index 31526c5b..1c3a7c17 100644 --- a/src/backup/testing/recovery-testing.service.ts +++ b/src/backup/testing/recovery-testing.service.ts @@ -20,6 +20,9 @@ import * as fs from 'fs'; const execAsync = promisify(exec); +/** + * Provides recovery Testing operations. + */ @Injectable() export class RecoveryTestingService { private readonly logger = new Logger(RecoveryTestingService.name); @@ -39,6 +42,11 @@ export class RecoveryTestingService { this.kmsClient = new KMSClient({ region: awsRegion }); } + /** + * Creates recovery Test. + * @param backupId The backup identifier. + * @returns The resulting recovery test response dto. + */ async createRecoveryTest(backupId: string): Promise { const backup = await this.backupService.getLatestBackup(); if (!backup) { @@ -75,6 +83,10 @@ export class RecoveryTestingService { return this.toResponseDto(recoveryTest); } + /** + * Executes execute Recovery Test. + * @param testId The test identifier. + */ async executeRecoveryTest(testId: string): Promise { const test = await this.recoveryTestRepository.findOne({ where: { id: testId }, @@ -164,6 +176,11 @@ export class RecoveryTestingService { } } + /** + * Retrieves test Results. + * @param testId The test identifier. + * @returns The resulting recovery test response dto. + */ async getTestResults(testId: string): Promise { const test = await this.recoveryTestRepository.findOne({ where: { id: testId }, diff --git a/src/caching/analytics/cache-analytics.service.ts b/src/caching/analytics/cache-analytics.service.ts index 488a6cd3..6848154b 100644 --- a/src/caching/analytics/cache-analytics.service.ts +++ b/src/caching/analytics/cache-analytics.service.ts @@ -22,6 +22,9 @@ export interface ICacheAnalyticsSummary { patternStats: Map; } +/** + * Provides cache Analytics operations. + */ @Injectable() export class CacheAnalyticsService implements OnModuleInit, OnModuleDestroy { private readonly logger = new Logger(CacheAnalyticsService.name); @@ -31,12 +34,18 @@ export class CacheAnalyticsService implements OnModuleInit, OnModuleDestroy { constructor(private readonly cachingService: CachingService) {} + /** + * Executes on Module Init. + */ onModuleInit(): void { // Start periodic metrics aggregation this.startMetricsFlush(); this.logger.log('Cache analytics service initialized'); } + /** + * Executes on Module Destroy. + */ onModuleDestroy(): void { if (this.flushInterval) { clearInterval(this.flushInterval); diff --git a/src/caching/cache-management.controller.ts b/src/caching/cache-management.controller.ts index 5331f8c2..3aaf6cb2 100644 --- a/src/caching/cache-management.controller.ts +++ b/src/caching/cache-management.controller.ts @@ -18,6 +18,9 @@ import { CacheStrategiesService } from './strategies/cache-strategies.service'; import { RolesGuard } from '../common/guards/roles.guard'; import { Roles, Role } from '../common/decorators/roles.decorator'; +/** + * Exposes cache Management endpoints. + */ @ApiTags('Cache Management') @ApiBearerAuth() @Controller('cache') @@ -32,6 +35,10 @@ export class CacheManagementController { private readonly strategiesService: CacheStrategiesService, ) {} + /** + * Returns stats. + * @returns The operation result. + */ @Get('stats') @ApiOperation({ summary: 'Get cache statistics' }) @ApiResponse({ @@ -62,6 +69,10 @@ export class CacheManagementController { }; } + /** + * Returns analytics. + * @returns The operation result. + */ @Get('analytics') @ApiOperation({ summary: 'Get detailed cache analytics' }) @ApiResponse({ @@ -84,6 +95,10 @@ export class CacheManagementController { }; } + /** + * Returns prometheus Metrics. + * @returns The operation result. + */ @Get('metrics/prometheus') @ApiOperation({ summary: 'Get Prometheus-compatible metrics' }) @ApiResponse({ @@ -94,6 +109,10 @@ export class CacheManagementController { return this.analyticsService.getPrometheusMetrics(); } + /** + * Returns strategies. + * @returns The operation result. + */ @Get('strategies') @ApiOperation({ summary: 'Get all cache strategies' }) @ApiResponse({ @@ -107,6 +126,10 @@ export class CacheManagementController { }; } + /** + * Returns warmed Keys. + * @returns The operation result. + */ @Get('warmed') @ApiOperation({ summary: 'Get warmed cache keys' }) @ApiResponse({ @@ -120,6 +143,11 @@ export class CacheManagementController { }; } + /** + * Returns key. + * @param key The key. + * @returns The operation result. + */ @Get('key/:key') @ApiOperation({ summary: 'Get a cached value by key' }) @ApiParam({ name: 'key', description: 'Cache key to retrieve' }) @@ -143,6 +171,10 @@ export class CacheManagementController { }; } + /** + * Clears all. + * @returns The operation result. + */ @Delete('clear') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Clear all cache' }) @@ -154,6 +186,11 @@ export class CacheManagementController { await this.cachingService.clearAll(); } + /** + * Clears by Pattern. + * @param pattern The pattern. + * @returns The operation result. + */ @Delete('clear/:pattern') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Clear cache by pattern' }) @@ -168,6 +205,11 @@ export class CacheManagementController { await this.cachingService.delPattern(`cache:${decodedPattern}`); } + /** + * Invalidates course. + * @param courseId The course identifier. + * @returns The operation result. + */ @Delete('invalidate/course/:courseId') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Invalidate all cache for a specific course' }) @@ -180,6 +222,11 @@ export class CacheManagementController { await this.invalidationService.invalidateCourse(courseId); } + /** + * Invalidates user. + * @param userId The user identifier. + * @returns The operation result. + */ @Delete('invalidate/user/:userId') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Invalidate all cache for a specific user' }) @@ -192,6 +239,10 @@ export class CacheManagementController { await this.invalidationService.invalidateUser(userId); } + /** + * Invalidates search. + * @returns The operation result. + */ @Delete('invalidate/search') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Invalidate all search cache' }) @@ -203,6 +254,10 @@ export class CacheManagementController { await this.invalidationService.invalidateSearch(); } + /** + * Warms cache. + * @returns The operation result. + */ @Post('warm') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Manually trigger cache warming' }) @@ -218,6 +273,11 @@ export class CacheManagementController { }; } + /** + * Resets analytics. + * @param pattern The pattern. + * @returns The operation result. + */ @Post('analytics/reset') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Reset analytics metrics' }) diff --git a/src/caching/caching.module.ts b/src/caching/caching.module.ts index 1fedd1b8..84ce200e 100644 --- a/src/caching/caching.module.ts +++ b/src/caching/caching.module.ts @@ -10,6 +10,9 @@ import { CacheAnalyticsService } from './analytics/cache-analytics.service'; import { CacheManagementController } from './cache-management.controller'; import { getSharedRedisClient } from '../config/cache.config'; +/** + * Registers the caching module. + */ @Global() @Module({ imports: [ConfigModule, EventEmitterModule], diff --git a/src/caching/caching.service.ts b/src/caching/caching.service.ts index ef295eca..87b17f78 100644 --- a/src/caching/caching.service.ts +++ b/src/caching/caching.service.ts @@ -8,6 +8,9 @@ export interface ICacheOptions { prefix?: string; } +/** + * Provides caching operations. + */ @Injectable() export class CachingService implements OnModuleDestroy { private readonly logger = new Logger(CachingService.name); @@ -20,6 +23,9 @@ export class CachingService implements OnModuleDestroy { this.defaultTtl = parseInt(this.configService.get('REDIS_TTL') || '300', 10); } + /** + * Executes on Module Destroy. + */ async onModuleDestroy(): Promise { if (this.redis.status !== 'end') { await this.redis.quit(); diff --git a/src/caching/interceptors/cache.interceptor.ts b/src/caching/interceptors/cache.interceptor.ts index 9a8b658f..39a1b468 100644 --- a/src/caching/interceptors/cache.interceptor.ts +++ b/src/caching/interceptors/cache.interceptor.ts @@ -43,6 +43,9 @@ export interface ICacheInterceptorOptions { trackAnalytics?: boolean; } +/** + * Intercepts cache request handling. + */ @Injectable() export class CacheInterceptor implements NestInterceptor { private readonly defaultTtl: number; @@ -62,6 +65,12 @@ export class CacheInterceptor implements NestInterceptor { this.trackAnalytics = options?.trackAnalytics ?? true; } + /** + * Executes intercept. + * @param context The context. + * @param next The next. + * @returns The resulting observable. + */ intercept(context: ExecutionContext, next: CallHandler): Observable { const request = context.switchToHttp().getRequest(); diff --git a/src/caching/invalidation/invalidation.service.ts b/src/caching/invalidation/invalidation.service.ts index 6dc8b828..a35e7616 100644 --- a/src/caching/invalidation/invalidation.service.ts +++ b/src/caching/invalidation/invalidation.service.ts @@ -9,6 +9,9 @@ export interface InvalidationResult { keysDeleted: number; } +/** + * Provides cache Invalidation operations. + */ @Injectable() export class CacheInvalidationService implements OnModuleInit, OnModuleDestroy { private readonly logger = new Logger(CacheInvalidationService.name); @@ -20,10 +23,18 @@ export class CacheInvalidationService implements OnModuleInit, OnModuleDestroy { private readonly eventEmitter: EventEmitter2, ) {} + /** + * Executes on Module Init. + * @returns The operation result. + */ onModuleInit() { this.logger.log('Cache invalidation service initialized'); } + /** + * Executes on Module Destroy. + * @returns The operation result. + */ onModuleDestroy() { this.tagIndex.clear(); } @@ -170,6 +181,10 @@ export class CacheInvalidationService implements OnModuleInit, OnModuleDestroy { // Event handlers for automatic invalidation + /** + * Handles course Updated Event. + * @param payload The payload to process. + */ @OnEvent(CACHE_EVENTS.COURSE_UPDATED) async handleCourseUpdatedEvent(payload: { courseId: string }): Promise { this.logger.debug(`Handling course updated event for: ${payload.courseId}`); @@ -177,6 +192,10 @@ export class CacheInvalidationService implements OnModuleInit, OnModuleDestroy { await this.invalidateByPatterns(patterns); } + /** + * Handles course Deleted Event. + * @param payload The payload to process. + */ @OnEvent(CACHE_EVENTS.COURSE_DELETED) async handleCourseDeletedEvent(payload: { courseId: string }): Promise { this.logger.debug(`Handling course deleted event for: ${payload.courseId}`); @@ -184,6 +203,10 @@ export class CacheInvalidationService implements OnModuleInit, OnModuleDestroy { await this.invalidateByPatterns(patterns); } + /** + * Handles user Updated Event. + * @param payload The payload to process. + */ @OnEvent(CACHE_EVENTS.USER_UPDATED) async handleUserUpdatedEvent(payload: { userId: string }): Promise { this.logger.debug(`Handling user updated event for: ${payload.userId}`); @@ -191,6 +214,10 @@ export class CacheInvalidationService implements OnModuleInit, OnModuleDestroy { await this.invalidateByPatterns(patterns); } + /** + * Handles user Deleted Event. + * @param payload The payload to process. + */ @OnEvent(CACHE_EVENTS.USER_DELETED) async handleUserDeletedEvent(payload: { userId: string }): Promise { this.logger.debug(`Handling user deleted event for: ${payload.userId}`); @@ -198,6 +225,10 @@ export class CacheInvalidationService implements OnModuleInit, OnModuleDestroy { await this.invalidateByPatterns(patterns); } + /** + * Handles enrollment Created Event. + * @param payload The payload to process. + */ @OnEvent(CACHE_EVENTS.ENROLLMENT_CREATED) async handleEnrollmentCreatedEvent(payload: { enrollmentId: string; @@ -208,6 +239,10 @@ export class CacheInvalidationService implements OnModuleInit, OnModuleDestroy { await this.invalidateByPatterns(patterns); } + /** + * Handles enrollment Updated Event. + * @param payload The payload to process. + */ @OnEvent(CACHE_EVENTS.ENROLLMENT_UPDATED) async handleEnrollmentUpdatedEvent(payload: { enrollmentId: string; @@ -218,6 +253,9 @@ export class CacheInvalidationService implements OnModuleInit, OnModuleDestroy { await this.invalidateByPatterns(patterns); } + /** + * Handles search Index Updated Event. + */ @OnEvent(CACHE_EVENTS.SEARCH_INDEX_UPDATED) async handleSearchIndexUpdatedEvent(): Promise { this.logger.debug('Handling search index updated event'); diff --git a/src/caching/strategies/cache-strategies.service.ts b/src/caching/strategies/cache-strategies.service.ts index b4282eb2..6a50f09a 100644 --- a/src/caching/strategies/cache-strategies.service.ts +++ b/src/caching/strategies/cache-strategies.service.ts @@ -15,6 +15,9 @@ export interface ICacheStrategyConfig { relatedPatterns: string[]; } +/** + * Provides cache Strategies operations. + */ @Injectable() export class CacheStrategiesService { private readonly strategies: Map = new Map(); diff --git a/src/caching/warming/cache-warming.service.ts b/src/caching/warming/cache-warming.service.ts index 285fadd0..734862cd 100644 --- a/src/caching/warming/cache-warming.service.ts +++ b/src/caching/warming/cache-warming.service.ts @@ -59,6 +59,9 @@ export interface ICacheWarmableProvider { getWarmableData(): Promise>; } +/** + * Provides cache Warming operations. + */ @Injectable() export class CacheWarmingService implements OnModuleInit, OnModuleDestroy { private readonly logger = new Logger(CacheWarmingService.name); @@ -94,6 +97,9 @@ export class CacheWarmingService implements OnModuleInit, OnModuleDestroy { this.dataProviders.push(provider); } + /** + * Executes on Module Init. + */ async onModuleInit(): Promise { if (!this.config.enabled) { this.logger.log('Cache warming is disabled'); @@ -111,6 +117,9 @@ export class CacheWarmingService implements OnModuleInit, OnModuleDestroy { this.schedulePeriodicWarmup(); } + /** + * Executes on Module Destroy. + */ onModuleDestroy(): void { if (this.warmupInterval) { clearInterval(this.warmupInterval); diff --git a/src/cdn/caching/edge-caching.service.ts b/src/cdn/caching/edge-caching.service.ts index b03f413f..e1d398f0 100644 --- a/src/cdn/caching/edge-caching.service.ts +++ b/src/cdn/caching/edge-caching.service.ts @@ -15,12 +15,21 @@ export interface IPurgeResult { provider: string; } +/** + * Provides edge Caching operations. + */ @Injectable() export class EdgeCachingService { private readonly logger = new Logger(EdgeCachingService.name); constructor(private cloudflareService: CloudflareService) {} + /** + * Retrieves edge Url. + * @param originalUrl The original url. + * @param location The location. + * @returns The resulting string value. + */ async getEdgeUrl(originalUrl: string, location?: string): Promise { // In a real implementation, this would return the CDN URL for the optimal edge location // For now, just return the original URL with CDN prefix @@ -94,6 +103,10 @@ export class EdgeCachingService { return this.purgeUrls(urls); } + /** + * Warms cache. + * @param urls The urls. + */ async warmCache(urls: string[]): Promise { this.logger.log(`Warming cache for ${urls.length} URLs`); @@ -107,6 +120,16 @@ export class EdgeCachingService { } } + /** + * Retrieves cache Status. + * @param _url The url. + * @returns The resulting promise<{ + cached: boolean; + age?: number; + expires?: date; + last modified?: date; + }>. + */ async getCacheStatus(_url: string): Promise<{ cached: boolean; age?: number; diff --git a/src/cdn/cdn.controller.ts b/src/cdn/cdn.controller.ts index 294d57f8..8d8ffa26 100644 --- a/src/cdn/cdn.controller.ts +++ b/src/cdn/cdn.controller.ts @@ -38,6 +38,9 @@ import { FILE_SIZE_LIMITS, } from '../media/validation/file-validation.constants'; +/** + * Exposes cdn endpoints. + */ @ApiTags('CDN') @Controller('cdn') export class CdnController { @@ -50,6 +53,12 @@ export class CdnController { private readonly imageProcessing: ImageProcessingService, ) {} + /** + * Uploads content. + * @param file The file to process. + * @param options The options. + * @returns The resulting content metadata. + */ @Post('upload') @UseInterceptors(FileInterceptor('file')) @ApiOperation({ summary: 'Upload content to CDN with full validation' }) @@ -129,6 +138,11 @@ export class CdnController { } } + /** + * Validates file. + * @param file The file to process. + * @returns The resulting file validation result. + */ @Post('validate') @UseInterceptors(FileInterceptor('file')) @ApiOperation({ summary: 'Validate file without uploading' }) @@ -168,6 +182,11 @@ export class CdnController { return this.fileValidation.validateFile(file); } + /** + * Executes scan File. + * @param file The file to process. + * @returns The operation result. + */ @Post('scan') @UseInterceptors(FileInterceptor('file')) @ApiOperation({ summary: 'Scan file for malware without uploading' }) @@ -204,6 +223,10 @@ export class CdnController { return this.malwareScanning.scanFile(file); } + /** + * Returns allowed Types. + * @returns The operation result. + */ @Get('allowed-types') @ApiOperation({ summary: 'Get allowed file types and size limits' }) @ApiResponse({ @@ -239,6 +262,11 @@ export class CdnController { }; } + /** + * Executes compress Preview. + * @param file The file to process. + * @returns The operation result. + */ @Post('compress-preview') @UseInterceptors(FileInterceptor('file')) @ApiOperation({ summary: 'Preview image compression without saving' }) @@ -284,6 +312,18 @@ export class CdnController { } } + /** + * Returns content Url. + * @param contentId The content identifier. + * @param optimize The optimize. + * @param width The width. + * @param height The height. + * @param quality The quality. + * @param format The format. + * @param userLocation The user location. + * @param bandwidth The bandwidth. + * @returns The operation result. + */ @Get('content/:contentId') @ApiOperation({ summary: 'Get optimized content URL' }) @ApiParam({ name: 'contentId', description: 'Content identifier' }) @@ -329,6 +369,11 @@ export class CdnController { } } + /** + * Invalidates content. + * @param contentId The content identifier. + * @returns The operation result. + */ @Delete('content/:contentId') @ApiOperation({ summary: 'Invalidate content cache' }) @ApiParam({ name: 'contentId', description: 'Content identifier' }) @@ -345,6 +390,14 @@ export class CdnController { } } + /** + * Returns health. + * @returns The resulting promise<{ + status: string; + providers: record; + timestamp: string; + }>. + */ @Get('health') @ApiOperation({ summary: 'Check CDN health status' }) @ApiResponse({ status: 200, description: 'CDN health status' }) @@ -371,6 +424,12 @@ export class CdnController { } } + /** + * Returns analytics. + * @param startDate The start date. + * @param endDate The end date. + * @returns The operation result. + */ @Get('analytics') @ApiOperation({ summary: 'Get CDN analytics' }) @ApiQuery({ name: 'startDate', required: false }) diff --git a/src/cdn/cdn.module.ts b/src/cdn/cdn.module.ts index ff205694..f3533104 100644 --- a/src/cdn/cdn.module.ts +++ b/src/cdn/cdn.module.ts @@ -16,6 +16,9 @@ import { FileValidationService } from '../media/validation/file-validation.servi import { MalwareScanningService } from '../media/validation/malware-scanning.service'; import { ImageProcessingService } from '../media/processing/image-processing.service'; +/** + * Registers the cdn module. + */ @Module({ imports: [ ConfigModule, diff --git a/src/cdn/cdn.service.ts b/src/cdn/cdn.service.ts index 3cdb105f..662deef0 100644 --- a/src/cdn/cdn.service.ts +++ b/src/cdn/cdn.service.ts @@ -23,6 +23,9 @@ export interface IContentDeliveryOptions { responsive?: boolean; } +/** + * Provides cdn operations. + */ @Injectable() export class CdnService { private readonly logger = new Logger(CdnService.name); @@ -80,6 +83,10 @@ export class CdnService { return edgeUrl; } + /** + * Invalidates content. + * @param contentId The content identifier. + */ async invalidateContent(contentId: string): Promise { // Purge from edge caches await this.edgeCachingService.purgeContent(contentId); @@ -90,6 +97,12 @@ export class CdnService { this.logger.warn(`Cache invalidation for ${contentId} - manual cleanup may be required`); } + /** + * Uploads content. + * @param file The file to process. + * @param options The options. + * @returns The resulting content metadata. + */ async uploadContent( file: IUploadedFile, options: IContentDeliveryOptions = {}, diff --git a/src/cdn/dto/upload-content.dto.ts b/src/cdn/dto/upload-content.dto.ts index 459932f9..c98f5b08 100644 --- a/src/cdn/dto/upload-content.dto.ts +++ b/src/cdn/dto/upload-content.dto.ts @@ -1,6 +1,9 @@ import { IsOptional, IsString, IsNumber, IsBoolean, Min, Max } from 'class-validator'; import { ApiPropertyOptional } from '@nestjs/swagger'; +/** + * Defines the upload Content payload. + */ export class UploadContentDto { @ApiPropertyOptional({ description: 'Whether to optimize the content automatically', diff --git a/src/cdn/entities/content-metadata.entity.ts b/src/cdn/entities/content-metadata.entity.ts index 5efb11ee..e75fd234 100644 --- a/src/cdn/entities/content-metadata.entity.ts +++ b/src/cdn/entities/content-metadata.entity.ts @@ -23,6 +23,9 @@ export enum ContentStatus { FAILED = 'failed', } +/** + * Represents the content Metadata entity. + */ @Entity('content_metadata') @Index(['contentId'], { unique: true }) @Index(['status']) diff --git a/src/cdn/geo/geo-location.service.ts b/src/cdn/geo/geo-location.service.ts index 4762706b..4c801c52 100644 --- a/src/cdn/geo/geo-location.service.ts +++ b/src/cdn/geo/geo-location.service.ts @@ -22,6 +22,9 @@ export interface IEdgeLocation { priority: number; } +/** + * Provides geo Location operations. + */ @Injectable() export class GeoLocationService { private readonly logger = new Logger(GeoLocationService.name); @@ -95,6 +98,11 @@ export class GeoLocationService { } } + /** + * Retrieves optimal Location. + * @param userLocation The user location. + * @returns The resulting string value. + */ async getOptimalLocation(userLocation?: string): Promise { if (!userLocation) { // Default to primary edge location @@ -152,6 +160,12 @@ export class GeoLocationService { return sortedLocations.slice(0, limit); } + /** + * Optimizes route For Connection. + * @param userLocation The user location. + * @param connectionType The connection type. + * @returns The resulting string value. + */ async optimizeRouteForConnection(userLocation: string, connectionType: string): Promise { const locations = await this.getNearestEdgeLocations(userLocation, 5); @@ -170,6 +184,11 @@ export class GeoLocationService { } } + /** + * Retrieves latency Estimates. + * @param userLocation The user location. + * @returns The resulting record. + */ async getLatencyEstimates(userLocation: string): Promise> { const userCoords = await this.getCoordinates(userLocation); const estimates: Record = {}; @@ -239,6 +258,14 @@ export class GeoLocationService { }; } + /** + * Retrieves geo Stats. + * @returns The resulting promise<{ + total requests: number; + top countries: array<{ country: string; count: number }>; + average latency: number; + }>. + */ async getGeoStats(): Promise<{ totalRequests: number; topCountries: Array<{ country: string; count: number }>; diff --git a/src/cdn/optimization/asset-optimization.service.ts b/src/cdn/optimization/asset-optimization.service.ts index dd43694f..24681f63 100644 --- a/src/cdn/optimization/asset-optimization.service.ts +++ b/src/cdn/optimization/asset-optimization.service.ts @@ -9,8 +9,17 @@ export interface IOptimizationResult { format: string; } +/** + * Provides asset Optimization operations. + */ @Injectable() export class AssetOptimizationService { + /** + * Optimizes image. + * @param contentId The content identifier. + * @param _options The options. + * @returns The resulting string value. + */ async optimizeImage(contentId: string, _options: any): Promise { try { // Download image (in real implementation, you'd fetch from storage) @@ -58,6 +67,12 @@ export class AssetOptimizationService { } } + /** + * Optimizes video. + * @param contentId The content identifier. + * @param _options The options. + * @returns The resulting string value. + */ async optimizeVideo(contentId: string, _options: any): Promise { // Implementation for video optimization using ffmpeg // For now, return original @@ -123,6 +138,16 @@ export class AssetOptimizationService { return parts.join('_'); } + /** + * Retrieves optimization Stats. + * @param _contentId The content identifier. + * @returns The resulting promise<{ + original size: number; + optimized size: number; + savings percentage: number; + formats: string[]; + }>. + */ async getOptimizationStats(_contentId: string): Promise<{ originalSize: number; optimizedSize: number; diff --git a/src/cdn/providers/aws-cloudfront.service.ts b/src/cdn/providers/aws-cloudfront.service.ts index 0aaa5dbb..2f535632 100644 --- a/src/cdn/providers/aws-cloudfront.service.ts +++ b/src/cdn/providers/aws-cloudfront.service.ts @@ -36,6 +36,9 @@ export interface IPurgeResult { invalidationId?: string; } +/** + * Provides aWSCloud Front operations. + */ @Injectable() export class AWSCloudFrontService { private readonly logger = new Logger(AWSCloudFrontService.name); @@ -191,6 +194,12 @@ export class AWSCloudFrontService { } } + /** + * Retrieves usage Statistics. + * @param _startDate The start date. + * @param _endDate The end date. + * @returns The operation result. + */ async getUsageStatistics(_startDate: Date, _endDate: Date): Promise { // AWS CloudFront doesn't have direct metrics API in SDK // Would need to use CloudWatch or external monitoring @@ -206,6 +215,10 @@ export class AWSCloudFrontService { }; } + /** + * Updates distribution Settings. + * @param _settings The settings. + */ async updateDistributionSettings(_settings: any): Promise { try { // Get current distribution config @@ -217,6 +230,10 @@ export class AWSCloudFrontService { } } + /** + * Creates origin Access Identity. + * @returns The resulting string value. + */ async createOriginAccessIdentity(): Promise { // Implementation would create CloudFront Origin Access Identity // for secure S3 access @@ -254,6 +271,11 @@ export class AWSCloudFrontService { throw new Error(`Invalidation ${invalidationId} did not complete within timeout`); } + /** + * Removes file. + * @param key The key. + * @returns Whether the operation succeeded. + */ async deleteFile(key: string): Promise { try { if (!this.config.bucketName) { @@ -277,6 +299,11 @@ export class AWSCloudFrontService { } } + /** + * Retrieves file Metadata. + * @param _key The key. + * @returns The operation result. + */ async getFileMetadata(_key: string): Promise { // Implementation would get object metadata from S3 return { diff --git a/src/cdn/providers/cloudflare.service.ts b/src/cdn/providers/cloudflare.service.ts index 8d09c099..2ca486d0 100644 --- a/src/cdn/providers/cloudflare.service.ts +++ b/src/cdn/providers/cloudflare.service.ts @@ -23,6 +23,9 @@ export interface IPurgeResult { failedUrls: string[]; } +/** + * Provides cloudflare operations. + */ @Injectable() export class CloudflareService { private readonly logger = new Logger(CloudflareService.name); @@ -95,6 +98,10 @@ export class CloudflareService { } } + /** + * Executes purge Everything. + * @returns Whether the operation succeeded. + */ async purgeEverything(): Promise { try { const response = await this.httpClient.post(`/zones/${this.config.zoneId}/purge_cache`, { @@ -108,6 +115,12 @@ export class CloudflareService { } } + /** + * Retrieves analytics. + * @param startDate The start date. + * @param endDate The end date. + * @returns The operation result. + */ async getAnalytics(startDate: Date, endDate: Date): Promise { try { const response = await this.httpClient.get( @@ -127,6 +140,11 @@ export class CloudflareService { } } + /** + * Creates custom Domain. + * @param domain The domain. + * @returns Whether the operation succeeded. + */ async createCustomDomain(domain: string): Promise { try { const response = await this.httpClient.post( @@ -145,6 +163,10 @@ export class CloudflareService { } } + /** + * Retrieves zone Settings. + * @returns The operation result. + */ async getZoneSettings(): Promise { try { const response = await this.httpClient.get(`/zones/${this.config.zoneId}/settings`); @@ -156,6 +178,11 @@ export class CloudflareService { } } + /** + * Updates cache Settings. + * @param settings The settings. + * @returns Whether the operation succeeded. + */ async updateCacheSettings(settings: any): Promise { try { const response = await this.httpClient.patch( @@ -198,6 +225,11 @@ export class CloudflareService { }; } + /** + * Retrieves image Variants. + * @param imageId The image identifier. + * @returns The matching results. + */ async getImageVariants(imageId: string): Promise { try { const response = await this.httpClient.get( @@ -211,6 +243,11 @@ export class CloudflareService { } } + /** + * Removes image. + * @param imageId The image identifier. + * @returns Whether the operation succeeded. + */ async deleteImage(imageId: string): Promise { try { const response = await this.httpClient.delete( diff --git a/src/collaboration/collaboration.controller.ts b/src/collaboration/collaboration.controller.ts index 9a03b6ae..fc58a8d8 100644 --- a/src/collaboration/collaboration.controller.ts +++ b/src/collaboration/collaboration.controller.ts @@ -22,6 +22,9 @@ import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { RolesGuard } from '../auth/guards/roles.guard'; // import { IsString, IsNotEmpty } from 'class-validator'; +/** + * Exposes collaboration endpoints. + */ @Controller('collaboration') @UseGuards(JwtAuthGuard, RolesGuard) export class CollaborationController { diff --git a/src/collaboration/collaboration.module.ts b/src/collaboration/collaboration.module.ts index 48915c73..3d544c39 100644 --- a/src/collaboration/collaboration.module.ts +++ b/src/collaboration/collaboration.module.ts @@ -7,6 +7,9 @@ import { CollaborationService } from './collaboration.service'; import { CollaborationGateway } from './gateway/collaboration.gateway'; import { CollaborationController } from './collaboration.controller'; +/** + * Registers the collaboration module. + */ @Module({ imports: [], controllers: [CollaborationController], diff --git a/src/collaboration/collaboration.service.ts b/src/collaboration/collaboration.service.ts index 2c7c5acd..91aaaade 100644 --- a/src/collaboration/collaboration.service.ts +++ b/src/collaboration/collaboration.service.ts @@ -4,6 +4,9 @@ import { WhiteboardService } from './whiteboard/whiteboard.service'; import { VersionControlService } from './versioning/version-control.service'; import { CollaborationPermissionsService } from './permissions/collaboration-permissions.service'; +/** + * Provides collaboration operations. + */ @Injectable() export class CollaborationService { constructor( diff --git a/src/collaboration/documents/shared-document.service.ts b/src/collaboration/documents/shared-document.service.ts index 32ddc72f..afcaf3a6 100644 --- a/src/collaboration/documents/shared-document.service.ts +++ b/src/collaboration/documents/shared-document.service.ts @@ -20,6 +20,9 @@ export interface ICollaborativeDocument { updatedAt: Date; } +/** + * Provides shared Document operations. + */ @Injectable() export class SharedDocumentService { private readonly logger = Logger; diff --git a/src/collaboration/permissions/collaboration-permissions.service.ts b/src/collaboration/permissions/collaboration-permissions.service.ts index de03d716..c3259203 100644 --- a/src/collaboration/permissions/collaboration-permissions.service.ts +++ b/src/collaboration/permissions/collaboration-permissions.service.ts @@ -24,6 +24,9 @@ export interface ICollaborativeResource { updatedAt: Date; } +/** + * Provides collaboration Permissions operations. + */ @Injectable() export class CollaborationPermissionsService { private readonly logger = Logger; diff --git a/src/collaboration/versioning/version-control.service.ts b/src/collaboration/versioning/version-control.service.ts index 15c9adbe..b06b81fa 100644 --- a/src/collaboration/versioning/version-control.service.ts +++ b/src/collaboration/versioning/version-control.service.ts @@ -21,6 +21,9 @@ export interface IVersionHistory { updatedAt: Date; } +/** + * Provides version Control operations. + */ @Injectable() export class VersionControlService { private readonly logger = Logger; diff --git a/src/collaboration/whiteboard/whiteboard.service.ts b/src/collaboration/whiteboard/whiteboard.service.ts index 98ea9a77..b3825b25 100644 --- a/src/collaboration/whiteboard/whiteboard.service.ts +++ b/src/collaboration/whiteboard/whiteboard.service.ts @@ -34,6 +34,9 @@ export interface ICollaborativeWhiteboard { updatedAt: Date; } +/** + * Provides whiteboard operations. + */ @Injectable() export class WhiteboardService { private readonly logger = Logger; diff --git a/src/common/common.module.ts b/src/common/common.module.ts index 5da4cc99..a61e7539 100644 --- a/src/common/common.module.ts +++ b/src/common/common.module.ts @@ -3,6 +3,9 @@ import { ConfigModule } from '@nestjs/config'; import { TransactionHelperService } from './database/transaction-helper.service'; import { LogShipperService } from './services/log-shipper.service'; +/** + * Registers the common module. + */ @Module({ imports: [ConfigModule], providers: [TransactionHelperService, LogShipperService], diff --git a/src/common/csrf/csrf.controller.ts b/src/common/csrf/csrf.controller.ts index 97ffab44..c7b4b3af 100644 --- a/src/common/csrf/csrf.controller.ts +++ b/src/common/csrf/csrf.controller.ts @@ -4,11 +4,19 @@ import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger'; import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard'; import { CsrfService } from './csrf.service'; +/** + * Exposes csrf endpoints. + */ @ApiTags('CSRF') @Controller('csrf') export class CsrfController { constructor(private readonly csrfService: CsrfService) {} + /** + * Returns csrf Token. + * @param req The req. + * @param res The res. + */ @Get('token') @UseGuards(JwtAuthGuard) @ApiOperation({ summary: 'Get CSRF token' }) @@ -21,6 +29,11 @@ export class CsrfController { res.json({ csrfToken: token }); } + /** + * Validates csrf Token. + * @param req The req. + * @returns The operation result. + */ @Post('validate') @UseGuards(JwtAuthGuard) @HttpCode(HttpStatus.OK) @@ -35,6 +48,11 @@ export class CsrfController { return { valid: isValid }; } + /** + * Invalidates csrf Token. + * @param req The req. + * @returns The operation result. + */ @Post('invalidate') @UseGuards(JwtAuthGuard) @HttpCode(HttpStatus.OK) diff --git a/src/common/csrf/csrf.module.ts b/src/common/csrf/csrf.module.ts index 2535efe1..89c460b0 100644 --- a/src/common/csrf/csrf.module.ts +++ b/src/common/csrf/csrf.module.ts @@ -3,12 +3,20 @@ import { CsrfMiddleware } from '../middleware/csrf.middleware'; import { CsrfService } from './csrf.service'; import { CsrfController } from './csrf.controller'; +/** + * Registers the csrf module. + */ @Module({ providers: [CsrfService], controllers: [CsrfController], exports: [CsrfService], }) export class CsrfModule { + /** + * Executes configure. + * @param consumer The consumer. + * @returns The operation result. + */ configure(consumer: MiddlewareConsumer) { consumer.apply(CsrfMiddleware).forRoutes({ path: '*', method: RequestMethod.ALL }); } diff --git a/src/common/csrf/csrf.service.ts b/src/common/csrf/csrf.service.ts index 2f2ef0b4..64f27f0c 100644 --- a/src/common/csrf/csrf.service.ts +++ b/src/common/csrf/csrf.service.ts @@ -2,6 +2,9 @@ import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { v4 as uuidv4 } from 'uuid'; +/** + * Provides csrf operations. + */ @Injectable() export class CsrfService { private readonly csrfTokens = new Map(); @@ -11,6 +14,11 @@ export class CsrfService { this.tokenExpiryTime = this.configService.get('CSRF_TOKEN_EXPIRY', 3600000); // 1 hour default } + /** + * Generates token. + * @param sessionId The session identifier. + * @returns The resulting string value. + */ generateToken(sessionId: string): string { const token = uuidv4(); const expires = Date.now() + this.tokenExpiryTime; @@ -19,6 +27,12 @@ export class CsrfService { return token; } + /** + * Validates token. + * @param sessionId The session identifier. + * @param token The token value. + * @returns Whether the operation succeeded. + */ validateToken(sessionId: string, token: string): boolean { const storedToken = this.csrfTokens.get(sessionId); @@ -29,10 +43,19 @@ export class CsrfService { return storedToken.token === token; } + /** + * Invalidates token. + * @param sessionId The session identifier. + */ invalidateToken(sessionId: string): void { this.csrfTokens.delete(sessionId); } + /** + * Retrieves token. + * @param sessionId The session identifier. + * @returns The operation result. + */ getToken(sessionId: string): string | null { const storedToken = this.csrfTokens.get(sessionId); @@ -43,6 +66,9 @@ export class CsrfService { return storedToken.token; } + /** + * Executes cleanup Expired Tokens. + */ cleanupExpiredTokens(): void { const now = Date.now(); for (const [sessionId, tokenData] of this.csrfTokens.entries()) { diff --git a/src/common/database/transactional.interceptor.ts b/src/common/database/transactional.interceptor.ts index fd461fbe..bf08b32b 100644 --- a/src/common/database/transactional.interceptor.ts +++ b/src/common/database/transactional.interceptor.ts @@ -16,6 +16,12 @@ export class TransactionalInterceptor implements NestInterceptor { private readonly transactionService: TransactionService, ) {} + /** + * Executes intercept. + * @param context The context. + * @param next The next. + * @returns The resulting observable. + */ async intercept(context: ExecutionContext, next: CallHandler): Promise> { const options = this.reflector.get( TRANSACTIONAL_KEY, diff --git a/src/common/dto/pagination.dto.ts b/src/common/dto/pagination.dto.ts index dec54571..ae3c2c8a 100644 --- a/src/common/dto/pagination.dto.ts +++ b/src/common/dto/pagination.dto.ts @@ -14,6 +14,9 @@ export enum CursorDirection { BACKWARD = 'backward', } +/** + * Defines the pagination Query payload. + */ export class PaginationQueryDto { @IsOptional() @Type(() => Number) @@ -43,6 +46,9 @@ export class PaginationQueryDto { search?: string; } +/** + * Defines the cursor Pagination Query payload. + */ export class CursorPaginationQueryDto { @IsOptional() @IsString() diff --git a/src/common/examples/timeout-example.controller.ts b/src/common/examples/timeout-example.controller.ts index 7e552b2e..47d0476b 100644 --- a/src/common/examples/timeout-example.controller.ts +++ b/src/common/examples/timeout-example.controller.ts @@ -2,9 +2,16 @@ import { Controller, Get, Post, Body } from '@nestjs/common'; import { ApiTags, ApiOperation } from '@nestjs/swagger'; import { Timeout } from '../interceptors/timeout.interceptor'; +/** + * Exposes timeout Example endpoints. + */ @ApiTags('Timeout Examples') @Controller('examples') export class TimeoutExampleController { + /** + * Returns quick Response. + * @returns The operation result. + */ @Get('quick') @ApiOperation({ summary: 'Quick endpoint with custom timeout' }) @Timeout(5000) // 5 seconds timeout @@ -13,6 +20,10 @@ export class TimeoutExampleController { return { message: 'Quick response' }; } + /** + * Returns slow Response. + * @returns The operation result. + */ @Get('slow') @ApiOperation({ summary: 'Slow endpoint with longer timeout' }) @Timeout(120000) // 2 minutes timeout @@ -22,6 +33,11 @@ export class TimeoutExampleController { return { message: 'Slow response completed' }; } + /** + * Processes data. + * @param data The data to process. + * @returns The operation result. + */ @Post('process') @ApiOperation({ summary: 'Processing endpoint with custom timeout' }) @Timeout(60000) // 1 minute timeout @@ -31,6 +47,10 @@ export class TimeoutExampleController { return { result: 'Data processed successfully' }; } + /** + * Returns default Timeout. + * @returns The operation result. + */ @Get('default') @ApiOperation({ summary: 'Endpoint using default timeout' }) getDefaultTimeout(): { message: string; timeout: string } { diff --git a/src/common/export/export.service.ts b/src/common/export/export.service.ts index 314584cd..92a5f2ec 100644 --- a/src/common/export/export.service.ts +++ b/src/common/export/export.service.ts @@ -24,6 +24,9 @@ export enum UserExportStatus { FAILED = 'failed', } +/** + * Provides user Export History operations. + */ @Entity('user_export_history') @Index(['userId', 'createdAt']) export class UserExportHistory { @@ -107,6 +110,9 @@ interface IPreparedExportData { }; } +/** + * Provides export operations. + */ @Injectable() export class ExportService { private readonly logger = new Logger(ExportService.name); @@ -124,6 +130,12 @@ export class ExportService { private readonly exportQueue: Queue, ) {} + /** + * Executes request User Data Export. + * @param userId The user identifier. + * @param format The format. + * @returns The operation result. + */ async requestUserDataExport(userId: string, format: ExportFormat = 'json') { this.ensureValidFormat(format); @@ -168,6 +180,11 @@ export class ExportService { }; } + /** + * Retrieves user Export History. + * @param userId The user identifier. + * @returns The operation result. + */ async getUserExportHistory(userId: string) { const history = await this.exportHistoryRepository.find({ where: { userId }, @@ -188,6 +205,16 @@ export class ExportService { })); } + /** + * Retrieves completed Export File. + * @param userId The user identifier. + * @param exportId The export identifier. + * @returns The resulting promise<{ + file name: string; + mime type: string; + content: buffer; + }>. + */ async getCompletedExportFile( userId: string, exportId: string, @@ -506,12 +533,19 @@ export class ExportService { } } +/** + * Provides user Data Export operations. + */ @Processor('user-data-export') export class UserDataExportProcessor { private readonly logger = new Logger(UserDataExportProcessor.name); constructor(private readonly exportService: ExportService) {} + /** + * Handles generate User Data Export. + * @param job The job. + */ @Process('generate-user-data-export') async handleGenerateUserDataExport(job: Job): Promise { this.logger.log(`Processing user export job: ${job.id}`); diff --git a/src/common/guards/roles.guard.ts b/src/common/guards/roles.guard.ts index 89880b51..43d7b8d8 100644 --- a/src/common/guards/roles.guard.ts +++ b/src/common/guards/roles.guard.ts @@ -2,10 +2,18 @@ import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { ROLES_KEY } from '../decorators/roles.decorator'; +/** + * Protects roles execution paths. + */ @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} + /** + * Executes can Activate. + * @param context The context. + * @returns Whether the operation succeeded. + */ canActivate(context: ExecutionContext): boolean { const requiredRoles = this.reflector.getAllAndOverride(ROLES_KEY, [ context.getHandler(), diff --git a/src/common/guards/ws-throttler.guard.ts b/src/common/guards/ws-throttler.guard.ts index b74d6c63..fcc1f0f3 100644 --- a/src/common/guards/ws-throttler.guard.ts +++ b/src/common/guards/ws-throttler.guard.ts @@ -2,6 +2,9 @@ import { Injectable, ExecutionContext, Logger } from '@nestjs/common'; import { ThrottlerGuard, ThrottlerLimitDetail } from '@nestjs/throttler'; import { WsException } from '@nestjs/websockets'; +/** + * Protects ws Throttler execution paths. + */ @Injectable() export class WsThrottlerGuard extends ThrottlerGuard { private readonly wsLogger = new Logger(WsThrottlerGuard.name); diff --git a/src/common/interceptors/api-version.interceptor.ts b/src/common/interceptors/api-version.interceptor.ts index 69ee5efb..1cf0a6ec 100644 --- a/src/common/interceptors/api-version.interceptor.ts +++ b/src/common/interceptors/api-version.interceptor.ts @@ -1,5 +1,12 @@ -import { CallHandler, ExecutionContext, Injectable, NestInterceptor } from '@nestjs/common'; -import { Observable } from 'rxjs'; +import { + CallHandler, + createParamDecorator, + ExecutionContext, + Injectable, + Logger, + NestInterceptor, +} from '@nestjs/common'; +import { Observable, tap } from 'rxjs'; export const API_VERSION_HEADER = process.env.API_VERSION_HEADER_NAME?.trim() || 'X-API-Version'; export const API_VERSION_HEADER_KEY = API_VERSION_HEADER.toLowerCase(); @@ -30,6 +37,11 @@ export function normalizeRequestedApiVersion(version?: string | string[]): strin return match[1]; } +/** + * Normalizes a configured API version string. + * @param version The configured version value. + * @returns The normalized major version. + */ export function normalizeConfiguredVersion(version: string): string { const normalized = normalizeRequestedApiVersion(version); return normalized || '1'; diff --git a/src/common/interceptors/cache.interceptor.ts b/src/common/interceptors/cache.interceptor.ts index 00e483ee..8192d507 100644 --- a/src/common/interceptors/cache.interceptor.ts +++ b/src/common/interceptors/cache.interceptor.ts @@ -3,10 +3,19 @@ import { Cache } from 'cache-manager'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; +/** + * Intercepts cache request handling. + */ @Injectable() export class CacheInterceptor implements NestInterceptor { constructor(private cacheManager: Cache) {} + /** + * Executes intercept. + * @param context The context. + * @param next The next. + * @returns The resulting observable. + */ async intercept(context: ExecutionContext, next: CallHandler): Promise> { const req = context.switchToHttp().getRequest(); const res = context.switchToHttp().getResponse(); diff --git a/src/common/interceptors/global-exception.filter.ts b/src/common/interceptors/global-exception.filter.ts index 2e4a0937..9cf44b2c 100644 --- a/src/common/interceptors/global-exception.filter.ts +++ b/src/common/interceptors/global-exception.filter.ts @@ -12,11 +12,19 @@ import { QueryFailedError, EntityNotFoundError, OptimisticLockVersionMismatchErr import { IApiError, IValidationErrorDetail } from '../../interfaces/api-error.interface'; import { CORRELATION_ID_HEADER, getCorrelationId } from '../utils/correlation.utils'; +/** + * Provides global Exception Filter behavior. + */ @Catch() export class GlobalExceptionFilter implements ExceptionFilter { private readonly logger = new Logger(GlobalExceptionFilter.name); private readonly isProduction = process.env.NODE_ENV === 'production'; + /** + * Executes catch. + * @param exception The exception. + * @param host The host. + */ catch(exception: unknown, host: ArgumentsHost): void { const ctx = host.switchToHttp(); const response = ctx.getResponse(); diff --git a/src/common/interceptors/logging.interceptor.ts b/src/common/interceptors/logging.interceptor.ts index 404c0d5c..55f86f6f 100644 --- a/src/common/interceptors/logging.interceptor.ts +++ b/src/common/interceptors/logging.interceptor.ts @@ -62,6 +62,12 @@ export class LoggingInterceptor implements NestInterceptor { constructor(private readonly logShipper: LogShipperService) {} + /** + * Executes intercept. + * @param context The context. + * @param next The next. + * @returns The resulting observable. + */ intercept(context: ExecutionContext, next: CallHandler): Observable { // Only intercept HTTP contexts (skip WebSockets, microservices, etc.) if (context.getType() !== 'http') { diff --git a/src/common/interceptors/monitoring.interceptor.ts b/src/common/interceptors/monitoring.interceptor.ts index e8f05f29..f3b3880a 100644 --- a/src/common/interceptors/monitoring.interceptor.ts +++ b/src/common/interceptors/monitoring.interceptor.ts @@ -3,10 +3,19 @@ import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; import { MetricsCollectionService } from '../../monitoring/metrics/metrics-collection.service'; +/** + * Intercepts monitoring request handling. + */ @Injectable() export class MonitoringInterceptor implements NestInterceptor { constructor(private readonly metricsService: MetricsCollectionService) {} + /** + * Executes intercept. + * @param context The context. + * @param next The next. + * @returns The resulting observable. + */ intercept(context: ExecutionContext, next: CallHandler): Observable { const now = Date.now(); const httpContext = context.switchToHttp(); diff --git a/src/common/interceptors/response-transform.interceptor.ts b/src/common/interceptors/response-transform.interceptor.ts index 5bf536d7..f5cf0859 100644 --- a/src/common/interceptors/response-transform.interceptor.ts +++ b/src/common/interceptors/response-transform.interceptor.ts @@ -10,8 +10,17 @@ export interface ApiResponse { metadata?: Record; } +/** + * Intercepts response Transform request handling. + */ @Injectable() export class ResponseTransformInterceptor implements NestInterceptor> { + /** + * Executes intercept. + * @param context The context. + * @param next The next. + * @returns The resulting observable>. + */ intercept(context: ExecutionContext, next: CallHandler): Observable> { const ctx = context.switchToHttp(); const response = ctx.getResponse(); diff --git a/src/common/interceptors/timeout.interceptor.ts b/src/common/interceptors/timeout.interceptor.ts index 6997dafb..2821a9e8 100644 --- a/src/common/interceptors/timeout.interceptor.ts +++ b/src/common/interceptors/timeout.interceptor.ts @@ -13,18 +13,32 @@ import { TimeoutConfigService } from '../timeout/timeout-config.service'; export const DEFAULT_TIMEOUT = parseInt(process.env.REQUEST_TIMEOUT || '30000', 10); // 30 seconds default +/** + * Executes timeout. + * @param ms The ms. + * @returns The resulting method decorator. + */ export function Timeout(ms?: number): MethodDecorator { return (target, propertyKey, descriptor) => { Reflect.defineMetadata('timeout', ms, descriptor.value ?? target); }; } +/** + * Intercepts timeout request handling. + */ @Injectable() export class TimeoutInterceptor implements NestInterceptor { private readonly logger = new Logger(TimeoutInterceptor.name); constructor(@Inject(TimeoutConfigService) private timeoutConfig: TimeoutConfigService) {} + /** + * Executes intercept. + * @param context The context. + * @param next The next. + * @returns The resulting observable. + */ intercept(context: ExecutionContext, next: CallHandler): Observable { const handler = context.getHandler(); const customTimeout = Reflect.getMetadata('timeout', handler); diff --git a/src/common/lazy-loading/lazy-loading.module.ts b/src/common/lazy-loading/lazy-loading.module.ts index adc7aaa3..401f15f9 100644 --- a/src/common/lazy-loading/lazy-loading.module.ts +++ b/src/common/lazy-loading/lazy-loading.module.ts @@ -1,12 +1,19 @@ import { Module, Global, DynamicModule } from '@nestjs/common'; import { LazyModuleLoader } from './lazy-module-loader.service'; +/** + * Registers the lazy Loading module. + */ @Global() @Module({ providers: [LazyModuleLoader], exports: [LazyModuleLoader], }) export class LazyLoadingModule { + /** + * Creates the root application module. + * @returns The resulting dynamic module. + */ static forRoot(): DynamicModule { return { module: LazyLoadingModule, diff --git a/src/common/lazy-loading/lazy-module-loader.service.ts b/src/common/lazy-loading/lazy-module-loader.service.ts index d1888776..9a4df6d1 100644 --- a/src/common/lazy-loading/lazy-module-loader.service.ts +++ b/src/common/lazy-loading/lazy-module-loader.service.ts @@ -15,6 +15,9 @@ export interface IModuleLoadResult { error?: Error; } +/** + * Provides lazy Module Loader operations. + */ @Injectable() export class LazyModuleLoader { private readonly logger = new Logger(LazyModuleLoader.name); diff --git a/src/common/lazy-loading/startup-logger.service.ts b/src/common/lazy-loading/startup-logger.service.ts index 36d330d2..a679437a 100644 --- a/src/common/lazy-loading/startup-logger.service.ts +++ b/src/common/lazy-loading/startup-logger.service.ts @@ -18,6 +18,9 @@ export interface IModuleLoadMetric { dependencies: string[]; } +/** + * Provides startup Logger operations. + */ @Injectable() export class StartupLogger implements OnModuleInit, OnApplicationBootstrap { private readonly logger = new Logger(StartupLogger.name); @@ -32,11 +35,19 @@ export class StartupLogger implements OnModuleInit, OnApplicationBootstrap { this.moduleInitStartTime = this.bootstrapStartTime; } + /** + * Executes on Module Init. + * @returns The operation result. + */ onModuleInit() { this.moduleInitStartTime = Date.now(); this.logger.log('Module initialization started'); } + /** + * Executes on Application Bootstrap. + * @returns The operation result. + */ onApplicationBootstrap() { const metrics = this.generateMetrics(); this.logStartupReport(metrics); diff --git a/src/common/middleware/csrf.middleware.ts b/src/common/middleware/csrf.middleware.ts index 5638fd20..0083d1f7 100644 --- a/src/common/middleware/csrf.middleware.ts +++ b/src/common/middleware/csrf.middleware.ts @@ -3,6 +3,9 @@ import { Request, Response, NextFunction } from 'express'; import { ConfigService } from '@nestjs/config'; import { CsrfService } from '../csrf/csrf.service'; +/** + * Applies csrf middleware behavior. + */ @Injectable() export class CsrfMiddleware implements NestMiddleware { constructor( @@ -10,6 +13,12 @@ export class CsrfMiddleware implements NestMiddleware { private configService: ConfigService, ) {} + /** + * Executes use. + * @param req The req. + * @param res The res. + * @param next The next. + */ use(req: Request, res: Response, next: NextFunction): void { // Skip CSRF for GET, HEAD, OPTIONS requests if (['GET', 'HEAD', 'OPTIONS'].includes(req.method)) { diff --git a/src/common/modules/api-versioning.module.ts b/src/common/modules/api-versioning.module.ts index 6a2ca389..19eab3b5 100644 --- a/src/common/modules/api-versioning.module.ts +++ b/src/common/modules/api-versioning.module.ts @@ -28,8 +28,17 @@ export const API_VERSIONING_DOCUMENTATION = [ 'Health, metrics, root, and webhook endpoints are version-neutral.', ].join(' '); +/** + * Registers the api Version Validation module. + */ @Injectable() export class ApiVersionValidationMiddleware implements NestMiddleware { + /** + * Executes use. + * @param req The req. + * @param res The res. + * @param next The next. + */ use( req: Request & IVersionedRequest & { headers: Record }, res: Response, @@ -70,6 +79,9 @@ export class ApiVersionValidationMiddleware implements NestMiddleware { } } +/** + * Registers the api Versioning module. + */ @Module({ providers: [ ApiVersionValidationMiddleware, @@ -82,6 +94,10 @@ export class ApiVersionValidationMiddleware implements NestMiddleware { exports: [ApiVersionValidationMiddleware, ApiVersionInterceptor], }) export class ApiVersioningModule implements NestModule { + /** + * Executes configure. + * @param consumer The consumer. + */ configure(consumer: MiddlewareConsumer): void { consumer.apply(ApiVersionValidationMiddleware).forRoutes({ path: '*', diff --git a/src/common/timeout/timeout-config.service.ts b/src/common/timeout/timeout-config.service.ts index bf1d9ed9..5ab1626b 100644 --- a/src/common/timeout/timeout-config.service.ts +++ b/src/common/timeout/timeout-config.service.ts @@ -7,6 +7,9 @@ export interface ITimeoutConfig { methods: Record; } +/** + * Provides timeout Config operations. + */ @Injectable() export class TimeoutConfigService { private readonly config: ITimeoutConfig; @@ -39,10 +42,19 @@ export class TimeoutConfigService { }; } + /** + * Retrieves default Timeout. + * @returns The calculated numeric value. + */ getDefaultTimeout(): number { return this.config.default; } + /** + * Retrieves endpoint Timeout. + * @param path The path. + * @returns The operation result. + */ getEndpointTimeout(path: string): number | null { // Check for exact path match if (this.config.endpoints[path]) { @@ -59,10 +71,21 @@ export class TimeoutConfigService { return null; } + /** + * Retrieves method Timeout. + * @param method The method. + * @returns The operation result. + */ getMethodTimeout(method: string): number | null { return this.config.methods[method.toUpperCase()] || null; } + /** + * Retrieves timeout For Request. + * @param method The method. + * @param path The path. + * @returns The calculated numeric value. + */ getTimeoutForRequest(method: string, path: string): number { // Priority: endpoint > method > default const endpointTimeout = this.getEndpointTimeout(path); @@ -87,14 +110,28 @@ export class TimeoutConfigService { return false; } + /** + * Updates endpoint Timeout. + * @param path The path. + * @param timeout The timeout. + */ updateEndpointTimeout(path: string, timeout: number): void { this.config.endpoints[path] = timeout; } + /** + * Updates method Timeout. + * @param method The method. + * @param timeout The timeout. + */ updateMethodTimeout(method: string, timeout: number): void { this.config.methods[method.toUpperCase()] = timeout; } + /** + * Updates default Timeout. + * @param timeout The timeout. + */ updateDefaultTimeout(timeout: number): void { this.config.default = timeout; } diff --git a/src/common/timeout/timeout.controller.ts b/src/common/timeout/timeout.controller.ts index 92028d21..97579f71 100644 --- a/src/common/timeout/timeout.controller.ts +++ b/src/common/timeout/timeout.controller.ts @@ -3,6 +3,9 @@ import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagg import { JwtAuthGuard } from '../../auth/guards/jwt-auth.guard'; import { TimeoutConfigService, ITimeoutConfig } from './timeout-config.service'; +/** + * Exposes timeout endpoints. + */ @ApiTags('Timeout Configuration') @ApiBearerAuth() @Controller('timeout') @@ -10,6 +13,10 @@ import { TimeoutConfigService, ITimeoutConfig } from './timeout-config.service'; export class TimeoutController { constructor(private readonly timeoutConfig: TimeoutConfigService) {} + /** + * Returns config. + * @returns The resulting timeout config. + */ @Get('config') @ApiOperation({ summary: 'Get current timeout configuration' }) @ApiResponse({ status: 200, description: 'Timeout configuration retrieved successfully' }) @@ -17,6 +24,11 @@ export class TimeoutController { return this.timeoutConfig.getConfig(); } + /** + * Updates default Timeout. + * @param body The body. + * @returns The operation result. + */ @Put('default') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Update default timeout' }) @@ -29,6 +41,11 @@ export class TimeoutController { }; } + /** + * Updates endpoint Timeout. + * @param body The body. + * @returns The operation result. + */ @Put('endpoint') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Update endpoint timeout' }) @@ -40,6 +57,11 @@ export class TimeoutController { }; } + /** + * Updates method Timeout. + * @param body The body. + * @returns The operation result. + */ @Put('method') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Update HTTP method timeout' }) @@ -51,6 +73,11 @@ export class TimeoutController { }; } + /** + * Validates timeout. + * @param body The body. + * @returns The operation result. + */ @Get('check') @ApiOperation({ summary: 'Get timeout for a specific request' }) @ApiResponse({ status: 200, description: 'Timeout calculated successfully' }) diff --git a/src/common/timeout/timeout.module.ts b/src/common/timeout/timeout.module.ts index e2f60ba8..6ffbb14b 100644 --- a/src/common/timeout/timeout.module.ts +++ b/src/common/timeout/timeout.module.ts @@ -3,6 +3,9 @@ import { TimeoutConfigService } from './timeout-config.service'; import { TimeoutController } from './timeout.controller'; import { TimeoutExampleController } from '../examples/timeout-example.controller'; +/** + * Registers the timeout module. + */ @Module({ providers: [TimeoutConfigService], controllers: [TimeoutController, TimeoutExampleController], diff --git a/src/common/utils/correlation.utils.ts b/src/common/utils/correlation.utils.ts index c431ef31..6c440648 100644 --- a/src/common/utils/correlation.utils.ts +++ b/src/common/utils/correlation.utils.ts @@ -9,20 +9,40 @@ export interface ICorrelationContext { const correlationStorage = new AsyncLocalStorage(); +/** + * Generates correlation Id. + * @returns The resulting string value. + */ export function generateCorrelationId(): string { return `cid-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`; } +/** + * Retrieves correlation Id. + * @returns The operation result. + */ export function getCorrelationId(): string | undefined { const store = correlationStorage.getStore(); return store?.correlationId; } +/** + * Sets correlation Id. + * @param req The req. + * @param res The res. + * @param correlationId The correlation identifier. + */ export function setCorrelationId(req: Request, res: Response, correlationId: string): void { (req as Request & { correlationId?: string }).correlationId = correlationId; res.setHeader(CORRELATION_ID_HEADER, correlationId); } +/** + * Executes correlation Middleware. + * @param req The req. + * @param res The res. + * @param next The next. + */ export function correlationMiddleware(req: Request, res: Response, next: NextFunction): void { const incoming = (req.headers[CORRELATION_ID_HEADER] as string) || (req.headers['x-correlation-id'] as string); @@ -34,11 +54,23 @@ export function correlationMiddleware(req: Request, res: Response, next: NextFun }); } +/** + * Executes run With Correlation Id. + * @param callback The callback. + * @param correlationId The correlation identifier. + * @returns The resulting t. + */ export function runWithCorrelationId(callback: () => T, correlationId?: string): T { const id = correlationId || generateCorrelationId(); return correlationStorage.run({ correlationId: id }, callback); } +/** + * Executes inject Correlation Id To Headers. + * @param headers The headers. + * @param correlationId The correlation identifier. + * @returns The resulting record. + */ export function injectCorrelationIdToHeaders( headers: Record = {}, correlationId?: string, diff --git a/src/common/utils/pagination.util.ts b/src/common/utils/pagination.util.ts index c7d60584..7ad78adc 100644 --- a/src/common/utils/pagination.util.ts +++ b/src/common/utils/pagination.util.ts @@ -32,6 +32,12 @@ export interface ICursorPaginatedResponse { }; } +/** + * Paginates query results. + * @param queryBuilder The query value. + * @param options The options. + * @returns The resulting paginated response. + */ export async function paginate( queryBuilder: SelectQueryBuilder, options: PaginationQueryDto, diff --git a/src/common/utils/sanitization.utils.ts b/src/common/utils/sanitization.utils.ts index fa9381c6..7ca8acfe 100644 --- a/src/common/utils/sanitization.utils.ts +++ b/src/common/utils/sanitization.utils.ts @@ -1,3 +1,8 @@ +/** + * Sanitizes sql Like. + * @param input The input. + * @returns The resulting string value. + */ export function sanitizeSqlLike(input: string): string { if (typeof input !== 'string') { throw new TypeError('Expected a string for SQL LIKE sanitization'); @@ -13,6 +18,13 @@ export function sanitizeSqlLike(input: string): string { return normalized.replace(/[\\%_]/g, (char) => `\\${char}`); } +/** + * Executes enforce Whitelisted Value. + * @param value The value. + * @param allowlist The allowlist. + * @param fieldName The field name. + * @returns The operation result. + */ export function enforceWhitelistedValue( value: T | undefined, allowlist: readonly T[], diff --git a/src/common/validators/password.validator.ts b/src/common/validators/password.validator.ts index 9a4c0d97..95e78eeb 100644 --- a/src/common/validators/password.validator.ts +++ b/src/common/validators/password.validator.ts @@ -56,13 +56,26 @@ export function calculatePasswordStrength(password: string): IPasswordStrengthRe }; } +/** + * Provides password Constraint behavior. + */ @ValidatorConstraint({ name: 'password', async: false }) export class PasswordConstraint implements ValidatorConstraintInterface { + /** + * Validates validate. + * @param password The password value. + * @returns Whether the operation succeeded. + */ validate(password: string): boolean { const result = calculatePasswordStrength(password); return result.isValid; } + /** + * Executes default Message. + * @param args The args. + * @returns The resulting string value. + */ defaultMessage(args: ValidationArguments): string { const password = args.value as string; const result = calculatePasswordStrength(password); @@ -73,6 +86,11 @@ export class PasswordConstraint implements ValidatorConstraintInterface { } } +/** + * Executes is Strong Password. + * @param validationOptions The operation options. + * @returns The operation result. + */ export function IsStrongPassword(validationOptions?: ValidationOptions) { return function (object: object, propertyName: string) { registerDecorator({ diff --git a/src/config/swagger.config.ts b/src/config/swagger.config.ts index b74acdf5..122f600e 100644 --- a/src/config/swagger.config.ts +++ b/src/config/swagger.config.ts @@ -2,6 +2,10 @@ import { INestApplication } from '@nestjs/common'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; import { API_VERSIONING_DOCUMENTATION } from '../common/modules/api-versioning.module'; +/** + * Sets setup Swagger. + * @param app The app. + */ export function setupSwagger(app: INestApplication): void { const config = new DocumentBuilder() .setTitle('TeachLink API') diff --git a/src/courses/courses.controller.ts b/src/courses/courses.controller.ts index 3febebd7..8548aa88 100644 --- a/src/courses/courses.controller.ts +++ b/src/courses/courses.controller.ts @@ -21,6 +21,9 @@ import { CreateLessonDto } from './dto/create-lesson.dto'; import { EnrollmentsService } from './enrollments/enrollments.service'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; +/** + * Exposes courses endpoints. + */ @Controller('courses') export class CoursesController { constructor( @@ -30,6 +33,12 @@ export class CoursesController { private readonly enrollmentsService: EnrollmentsService, ) {} + /** + * Creates a new record. + * @param req The req. + * @param createCourseDto The request payload. + * @returns The operation result. + */ @Post() @UseGuards(JwtAuthGuard) create(@Request() req, @Body() createCourseDto: CreateCourseDto) { @@ -44,33 +53,64 @@ export class CoursesController { }); } + /** + * Returns all. + * @param searchDto The request payload. + * @returns The operation result. + */ @Get() findAll(@Query() searchDto: CourseSearchDto) { return this.coursesService.findAll(searchDto); } + /** + * Returns all With Cursor. + * @param searchDto The request payload. + * @returns The operation result. + */ @Get('cursor') findAllWithCursor(@Query() searchDto: CursorCourseSearchDto) { return this.coursesService.findAllWithCursor(searchDto); } + /** + * Returns analytics. + * @param _req The req. + * @returns The operation result. + */ @Get('analytics') @UseGuards(JwtAuthGuard) getAnalytics(@Request() _req) { return this.coursesService.getAnalytics(); } + /** + * Returns one. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id') findOne(@Param('id') id: string) { return this.coursesService.findOne(id); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateCourseDto The request payload. + * @returns The operation result. + */ @Patch(':id') @UseGuards(JwtAuthGuard) update(@Param('id') id: string, @Body() updateCourseDto: UpdateCourseDto) { return this.coursesService.update(id, updateCourseDto); } + /** + * Removes the requested record. + * @param id The identifier. + * @returns The operation result. + */ @Delete(':id') @UseGuards(JwtAuthGuard) remove(@Param('id') id: string) { @@ -78,6 +118,13 @@ export class CoursesController { } // Modules + /** + * Creates module. + * @param req The req. + * @param courseId The course identifier. + * @param createModuleDto The request payload. + * @returns The operation result. + */ @Post(':id/modules') @UseGuards(JwtAuthGuard) createModule( @@ -90,6 +137,13 @@ export class CoursesController { } // Lessons + /** + * Creates lesson. + * @param req The req. + * @param moduleId The module identifier. + * @param createLessonDto The request payload. + * @returns The operation result. + */ @Post('modules/:moduleId/lessons') @UseGuards(JwtAuthGuard) createLesson( @@ -102,6 +156,12 @@ export class CoursesController { } // Enrollments + /** + * Executes enroll. + * @param req The req. + * @param courseId The course identifier. + * @returns The operation result. + */ @Post(':id/enroll') @UseGuards(JwtAuthGuard) enroll(@Request() req, @Param('id') courseId: string) { diff --git a/src/courses/courses.module.ts b/src/courses/courses.module.ts index d99c9881..160a28e6 100644 --- a/src/courses/courses.module.ts +++ b/src/courses/courses.module.ts @@ -13,6 +13,9 @@ import { User } from '../users/entities/user.entity'; import { SearchModule } from '../search/search.module'; import { CourseSearchSyncService } from './search-sync/course-search-sync.service'; +/** + * Registers the courses module. + */ @Module({ imports: [ TypeOrmModule.forFeature([Course, CourseModuleEntity, Lesson, Enrollment, User]), diff --git a/src/courses/courses.service.ts b/src/courses/courses.service.ts index 812e3dfb..3644a074 100644 --- a/src/courses/courses.service.ts +++ b/src/courses/courses.service.ts @@ -18,6 +18,9 @@ import { sanitizeSqlLike, enforceWhitelistedValue } from '../common/utils/saniti import { CourseModule } from './entities/course-module.entity'; import { Lesson } from './entities/lesson.entity'; +/** + * Provides course operations. + */ @Injectable() export class CoursesService { constructor( @@ -28,6 +31,11 @@ export class CoursesService { private readonly eventEmitter: EventEmitter2, ) {} + /** + * Creates a new record. + * @param createCourseDto The request payload. + * @returns The resulting course. + */ async create(createCourseDto: any): Promise { const course = this.coursesRepository.create({ ...createCourseDto, @@ -77,6 +85,11 @@ export class CoursesService { ); } + /** + * Retrieves all With Cursor. + * @param filter The filter criteria. + * @returns The resulting cursor paginated response. + */ async findAllWithCursor( filter?: CursorCourseSearchDto, ): Promise> { @@ -119,11 +132,21 @@ export class CoursesService { ); } + /** + * Retrieves records by their identifiers. + * @param ids The identifiers. + * @returns The matching results. + */ async findByIds(ids: string[]): Promise { if (ids.length === 0) return []; return await this.coursesRepository.findByIds(ids); } + /** + * Retrieves by Instructor. + * @param instructorId The instructor identifier. + * @returns The matching results. + */ async findByInstructor(instructorId: string): Promise { return await this.coursesRepository.find({ where: { instructor: { id: instructorId } }, @@ -131,6 +154,11 @@ export class CoursesService { }); } + /** + * Retrieves by Instructor Ids. + * @param instructorIds The instructor identifiers. + * @returns The matching results. + */ async findByInstructorIds(instructorIds: string[]): Promise { if (instructorIds.length === 0) return []; return await this.coursesRepository @@ -140,6 +168,11 @@ export class CoursesService { .getMany(); } + /** + * Retrieves the requested record. + * @param id The identifier. + * @returns The resulting course. + */ async findOne(id: string): Promise { const cacheKey = `${CACHE_PREFIXES.COURSE}:${id}`; @@ -167,6 +200,12 @@ export class CoursesService { ); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateCourseDto The request payload. + * @returns The resulting course. + */ async update(id: string, updateCourseDto: UpdateCourseDto): Promise { const course = await this.coursesRepository.findOne({ where: { id }, @@ -184,6 +223,10 @@ export class CoursesService { return saved; } + /** + * Removes the requested record. + * @param id The identifier. + */ async remove(id: string): Promise { const course = await this.coursesRepository.findOne({ where: { id }, @@ -208,6 +251,10 @@ export class CoursesService { this.eventEmitter.emit(CACHE_EVENTS.COURSE_DELETED, { courseId: id }); } + /** + * Retrieves analytics. + * @returns The operation result. + */ async getAnalytics(): Promise { const totalCourses = await this.coursesRepository.count(); const publishedCourses = await this.coursesRepository.count({ diff --git a/src/courses/dto/course-search.dto.ts b/src/courses/dto/course-search.dto.ts index 7d10d151..12ad9da5 100644 --- a/src/courses/dto/course-search.dto.ts +++ b/src/courses/dto/course-search.dto.ts @@ -2,6 +2,9 @@ import { IsString, IsOptional, IsNumber, IsUUID } from 'class-validator'; import { ApiPropertyOptional } from '@nestjs/swagger'; import { PaginationQueryDto, CursorPaginationQueryDto } from '../../common/dto/pagination.dto'; +/** + * Defines the course Search payload. + */ export class CourseSearchDto extends PaginationQueryDto { @ApiPropertyOptional() @IsNumber() @@ -23,6 +26,9 @@ export class CourseSearchDto extends PaginationQueryDto { instructorId?: string; } +/** + * Defines the cursor Course Search payload. + */ export class CursorCourseSearchDto extends CursorPaginationQueryDto { @ApiPropertyOptional() @IsNumber() diff --git a/src/courses/dto/create-course.dto.ts b/src/courses/dto/create-course.dto.ts index 81d0100f..2b698fdf 100644 --- a/src/courses/dto/create-course.dto.ts +++ b/src/courses/dto/create-course.dto.ts @@ -9,6 +9,9 @@ import { } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +/** + * Defines the create Course payload. + */ export class CreateCourseDto { @ApiProperty() @IsString({ message: 'Title must be a string' }) diff --git a/src/courses/dto/create-lesson.dto.ts b/src/courses/dto/create-lesson.dto.ts index faaf5aac..52a1a4fd 100644 --- a/src/courses/dto/create-lesson.dto.ts +++ b/src/courses/dto/create-lesson.dto.ts @@ -1,6 +1,9 @@ import { IsString, IsNotEmpty, IsInt, IsOptional, IsUUID, IsUrl, IsNumber } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +/** + * Defines the create Lesson payload. + */ export class CreateLessonDto { @ApiProperty() @IsString() diff --git a/src/courses/dto/create-module.dto.ts b/src/courses/dto/create-module.dto.ts index 4d3b4c70..c8188a48 100644 --- a/src/courses/dto/create-module.dto.ts +++ b/src/courses/dto/create-module.dto.ts @@ -1,6 +1,9 @@ import { IsString, IsNotEmpty, IsInt, IsOptional, IsUUID, IsNumber } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +/** + * Defines the create Module payload. + */ export class CreateModuleDto { @ApiProperty() @IsString() diff --git a/src/courses/dto/update-course.dto.ts b/src/courses/dto/update-course.dto.ts index 28f8c93c..dec505c2 100644 --- a/src/courses/dto/update-course.dto.ts +++ b/src/courses/dto/update-course.dto.ts @@ -2,6 +2,9 @@ import { CreateCourseDto } from './create-course.dto'; import { PartialType, ApiPropertyOptional } from '@nestjs/swagger'; import { IsString, IsOptional, IsEnum } from 'class-validator'; +/** + * Defines the update Course payload. + */ export class UpdateCourseDto extends PartialType(CreateCourseDto) { @ApiPropertyOptional({ enum: ['draft', 'published', 'archived'] }) @IsString() diff --git a/src/courses/enrollments/enrollments.service.ts b/src/courses/enrollments/enrollments.service.ts index 443a771a..c248d900 100644 --- a/src/courses/enrollments/enrollments.service.ts +++ b/src/courses/enrollments/enrollments.service.ts @@ -5,6 +5,9 @@ import { Enrollment } from '../entities/enrollment.entity'; import { Course } from '../entities/course.entity'; import { User } from '../../users/entities/user.entity'; +/** + * Provides enrollments operations. + */ @Injectable() export class EnrollmentsService { constructor( @@ -16,6 +19,12 @@ export class EnrollmentsService { private usersRepository: Repository, ) {} + /** + * Executes enroll. + * @param userId The user identifier. + * @param courseId The course identifier. + * @returns The resulting enrollment. + */ async enroll(userId: string, courseId: string): Promise { const existing = await this.enrollmentsRepository.findOne({ where: { user: { id: userId }, course: { id: courseId } }, @@ -39,6 +48,11 @@ export class EnrollmentsService { return this.enrollmentsRepository.save(enrollment); } + /** + * Retrieves user Enrollments. + * @param userId The user identifier. + * @returns The matching results. + */ async findUserEnrollments(userId: string): Promise { return this.enrollmentsRepository.find({ where: { user: { id: userId } }, @@ -46,6 +60,12 @@ export class EnrollmentsService { }); } + /** + * Updates progress. + * @param enrollmentId The enrollment identifier. + * @param progress The progress. + * @returns The resulting enrollment. + */ async updateProgress(enrollmentId: string, progress: number): Promise { const enrollment = await this.enrollmentsRepository.findOneBy({ id: enrollmentId }); if (!enrollment) throw new NotFoundException('Enrollment not found'); diff --git a/src/courses/entities/course-module.entity.ts b/src/courses/entities/course-module.entity.ts index 2f0fd4c8..988e3c78 100644 --- a/src/courses/entities/course-module.entity.ts +++ b/src/courses/entities/course-module.entity.ts @@ -11,6 +11,9 @@ import { import { Course } from './course.entity'; import { Lesson } from './lesson.entity'; +/** + * Represents the course entity. + */ @Entity() export class CourseModule { @PrimaryGeneratedColumn('uuid') diff --git a/src/courses/entities/course.entity.ts b/src/courses/entities/course.entity.ts index 37b098ca..d80c2b7d 100644 --- a/src/courses/entities/course.entity.ts +++ b/src/courses/entities/course.entity.ts @@ -14,6 +14,9 @@ import { User } from '../../users/entities/user.entity'; import { CourseModule } from './course-module.entity'; import { Enrollment } from './enrollment.entity'; +/** + * Represents the course entity. + */ @Entity() export class Course { @PrimaryGeneratedColumn('uuid') diff --git a/src/courses/entities/enrollment.entity.ts b/src/courses/entities/enrollment.entity.ts index ae9430ae..71a76931 100644 --- a/src/courses/entities/enrollment.entity.ts +++ b/src/courses/entities/enrollment.entity.ts @@ -11,6 +11,9 @@ import { import { User } from '../../users/entities/user.entity'; import { Course } from './course.entity'; +/** + * Represents the enrollment entity. + */ @Entity() @Index(['userId', 'status']) @Index(['courseId', 'status']) diff --git a/src/courses/entities/lesson.entity.ts b/src/courses/entities/lesson.entity.ts index 7b4d84b5..b1630169 100644 --- a/src/courses/entities/lesson.entity.ts +++ b/src/courses/entities/lesson.entity.ts @@ -9,6 +9,9 @@ import { } from 'typeorm'; import { CourseModule } from './course-module.entity'; +/** + * Represents the lesson entity. + */ @Entity() export class Lesson { @PrimaryGeneratedColumn('uuid') diff --git a/src/courses/guards/ws-jwt-auth.guard.ts b/src/courses/guards/ws-jwt-auth.guard.ts index 0ff404e6..b093081b 100644 --- a/src/courses/guards/ws-jwt-auth.guard.ts +++ b/src/courses/guards/ws-jwt-auth.guard.ts @@ -2,10 +2,18 @@ import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { Socket } from 'socket.io'; +/** + * Protects ws Jwt Auth execution paths. + */ @Injectable() export class WsJwtAuthGuard implements CanActivate { constructor(private readonly jwtService: JwtService) {} + /** + * Executes can Activate. + * @param context The context. + * @returns Whether the operation succeeded. + */ async canActivate(context: ExecutionContext): Promise { const client: Socket = context.switchToWs().getClient(); const token = diff --git a/src/courses/lessons/lessons.service.ts b/src/courses/lessons/lessons.service.ts index 233879df..417a2077 100644 --- a/src/courses/lessons/lessons.service.ts +++ b/src/courses/lessons/lessons.service.ts @@ -5,6 +5,9 @@ import { Lesson } from '../entities/lesson.entity'; import { CreateLessonDto } from '../dto/create-lesson.dto'; import { CourseModule } from '../entities/course-module.entity'; +/** + * Provides lessons operations. + */ @Injectable() export class LessonsService { constructor( @@ -14,6 +17,11 @@ export class LessonsService { private modulesRepository: Repository, ) {} + /** + * Creates a new record. + * @param createLessonDto The request payload. + * @returns The resulting lesson. + */ async create(createLessonDto: CreateLessonDto): Promise { const module = await this.modulesRepository.findOneBy({ id: createLessonDto.moduleId }); if (!module) { @@ -27,6 +35,11 @@ export class LessonsService { return this.lessonsRepository.save(lesson); } + /** + * Retrieves the requested record. + * @param id The identifier. + * @returns The resulting lesson. + */ async findOne(id: string): Promise { const lesson = await this.lessonsRepository.findOneBy({ id }); if (!lesson) { @@ -35,12 +48,22 @@ export class LessonsService { return lesson; } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateData The data to process. + * @returns The resulting lesson. + */ async update(id: string, updateData: Partial): Promise { const lesson = await this.findOne(id); Object.assign(lesson, updateData); return this.lessonsRepository.save(lesson); } + /** + * Removes the requested record. + * @param id The identifier. + */ async remove(id: string): Promise { await this.findOne(id); await this.lessonsRepository.softDelete(id); diff --git a/src/courses/modules/modules.service.ts b/src/courses/modules/modules.service.ts index 46ad69fe..f1524e57 100644 --- a/src/courses/modules/modules.service.ts +++ b/src/courses/modules/modules.service.ts @@ -6,6 +6,9 @@ import { CreateModuleDto } from '../dto/create-module.dto'; import { Course } from '../entities/course.entity'; import { Lesson } from '../entities/lesson.entity'; +/** + * Provides modules operations. + */ @Injectable() export class ModulesService { constructor( @@ -15,6 +18,11 @@ export class ModulesService { private coursesRepository: Repository, ) {} + /** + * Creates a new record. + * @param createModuleDto The request payload. + * @returns The resulting course module. + */ async create(createModuleDto: CreateModuleDto): Promise { const course = await this.coursesRepository.findOneBy({ id: createModuleDto.courseId }); if (!course) { @@ -28,6 +36,11 @@ export class ModulesService { return this.modulesRepository.save(module); } + /** + * Retrieves the requested record. + * @param id The identifier. + * @returns The resulting course module. + */ async findOne(id: string): Promise { const module = await this.modulesRepository.findOne({ where: { id }, @@ -44,12 +57,22 @@ export class ModulesService { return module; } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateData The data to process. + * @returns The resulting course module. + */ async update(id: string, updateData: Partial): Promise { const module = await this.findOne(id); Object.assign(module, updateData); return this.modulesRepository.save(module); } + /** + * Removes the requested record. + * @param id The identifier. + */ async remove(id: string): Promise { const module = await this.findOne(id); await this.modulesRepository.manager.transaction(async (manager) => { diff --git a/src/data-warehouse/data-warehouse.controller.ts b/src/data-warehouse/data-warehouse.controller.ts index 6fafeb36..6b3d720b 100644 --- a/src/data-warehouse/data-warehouse.controller.ts +++ b/src/data-warehouse/data-warehouse.controller.ts @@ -7,6 +7,9 @@ import { IncrementalLoaderService } from './loading/incremental-loader.service'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { RolesGuard } from '../auth/guards/roles.guard'; +/** + * Exposes data Warehouse endpoints. + */ @Controller('data-warehouse') @UseGuards(JwtAuthGuard, RolesGuard) export class DataWarehouseController { @@ -19,18 +22,33 @@ export class DataWarehouseController { ) {} // ETL Pipeline endpoints + /** + * Creates eTLPipeline. + * @param config The config. + * @param _req The req. + * @returns The operation result. + */ @Post('etl/pipeline') async createETLPipeline(@Body() config: any, @Request() _req): Promise { const pipeline = await this.etlService.createPipeline(config); return { success: true, pipeline }; } + /** + * Returns eTLPipeline. + * @param id The identifier. + * @returns The operation result. + */ @Get('etl/pipeline/:id') async getETLPipeline(@Param('id') id: string): Promise { const pipeline = await this.etlService.getJobStatus(id); return { success: true, pipeline }; } + /** + * Returns all ETLPipelines. + * @returns The operation result. + */ @Get('etl/pipelines') async getAllETLPipelines(): Promise { const pipelines = await this.etlService.getAllJobs(); @@ -38,6 +56,11 @@ export class DataWarehouseController { } // Dimensional Modeling endpoints + /** + * Creates star Schema. + * @param body The body. + * @returns The operation result. + */ @Post('modeling/star-schema') async createStarSchema( @Body() body: { name: string; factTable: any; dimensionTables: any[] }, @@ -50,6 +73,11 @@ export class DataWarehouseController { return { success: true, model }; } + /** + * Creates snowflake Schema. + * @param body The body. + * @returns The operation result. + */ @Post('modeling/snowflake-schema') async createSnowflakeSchema( @Body() body: { name: string; factTable: any; dimensionTables: any[]; subDimensions: any }, @@ -63,24 +91,44 @@ export class DataWarehouseController { return { success: true, model }; } + /** + * Returns all Models. + * @returns The operation result. + */ @Get('modeling/models') async getAllModels(): Promise { const models = await this.modelingService.getAllModels(); return { success: true, models }; } + /** + * Returns model. + * @param id The identifier. + * @returns The operation result. + */ @Get('modeling/model/:id') async getModel(@Param('id') id: string): Promise { const model = await this.modelingService.getModel(id); return { success: true, model }; } + /** + * Creates query. + * @param queryConfig The configuration values. + * @returns The operation result. + */ @Post('modeling/query') async createQuery(@Body() queryConfig: any): Promise { const query = await this.modelingService.createQuery(queryConfig); return { success: true, query }; } + /** + * Executes execute Query. + * @param id The identifier. + * @param body The body. + * @returns The operation result. + */ @Post('modeling/query/:id/execute') async executeQuery(@Param('id') id: string, @Body() body: { parameters?: any }): Promise { const results = await this.modelingService.executeQuery(id, body.parameters); @@ -88,18 +136,33 @@ export class DataWarehouseController { } // Data Quality endpoints + /** + * Creates quality Profile. + * @param profileConfig The configuration values. + * @returns The operation result. + */ @Post('quality/profile') async createQualityProfile(@Body() profileConfig: any): Promise { const profile = await this.qualityService.createProfile(profileConfig); return { success: true, profile }; } + /** + * Creates standard Profiles. + * @returns The operation result. + */ @Post('quality/profiles/standard') async createStandardProfiles(): Promise { const profiles = await this.qualityService.createStandardProfiles(); return { success: true, profiles }; } + /** + * Executes run Quality Check. + * @param profileId The profile identifier. + * @param body The body. + * @returns The operation result. + */ @Post('quality/check/:profileId') async runQualityCheck( @Param('profileId') profileId: string, @@ -109,12 +172,24 @@ export class DataWarehouseController { return { success: true, check }; } + /** + * Returns quality Checks. + * @param profileId The profile identifier. + * @returns The operation result. + */ @Get('quality/checks/:profileId') async getQualityChecks(@Param('profileId') profileId: string): Promise { const checks = await this.qualityService.getChecksForProfile(profileId); return { success: true, checks }; } + /** + * Returns quality Issues. + * @param profileId The profile identifier. + * @param severity The severity. + * @param resolved The resolved. + * @returns The operation result. + */ @Get('quality/issues') async getQualityIssues( @Query('profileId') profileId?: string, @@ -127,36 +202,68 @@ export class DataWarehouseController { } // Data Lineage endpoints + /** + * Creates lineage Graph. + * @param graphConfig The configuration values. + * @returns The operation result. + */ @Post('lineage/graph') async createLineageGraph(@Body() graphConfig: any): Promise { const graph = await this.lineageService.createGraph(graphConfig); return { success: true, graph }; } + /** + * Creates standard Lineage. + * @returns The operation result. + */ @Post('lineage/graphs/standard') async createStandardLineage(): Promise { const graph = await this.lineageService.createStandardLineage(); return { success: true, graph }; } + /** + * Returns all Lineage Graphs. + * @returns The operation result. + */ @Get('lineage/graphs') async getAllLineageGraphs(): Promise { const graphs = await this.lineageService.getAllGraphs(); return { success: true, graphs }; } + /** + * Executes add Lineage Node. + * @param graphId The graph identifier. + * @param nodeConfig The configuration values. + * @returns The operation result. + */ @Post('lineage/graph/:id/node') async addLineageNode(@Param('id') graphId: string, @Body() nodeConfig: any): Promise { const node = await this.lineageService.addNode(graphId, nodeConfig); return { success: true, node }; } + /** + * Executes add Lineage Edge. + * @param graphId The graph identifier. + * @param edgeConfig The configuration values. + * @returns The operation result. + */ @Post('lineage/graph/:id/edge') async addLineageEdge(@Param('id') graphId: string, @Body() edgeConfig: any): Promise { const edge = await this.lineageService.addEdge(graphId, edgeConfig); return { success: true, edge }; } + /** + * Executes trace Lineage. + * @param graphId The graph identifier. + * @param nodeId The node identifier. + * @param body The body. + * @returns The operation result. + */ @Post('lineage/graph/:id/trace/:nodeId') async traceLineage( @Param('id') graphId: string, @@ -168,6 +275,12 @@ export class DataWarehouseController { return { success: true, trace }; } + /** + * Analyzes impact. + * @param graphId The graph identifier. + * @param nodeId The node identifier. + * @returns The operation result. + */ @Post('lineage/graph/:id/impact/:nodeId') async analyzeImpact(@Param('id') graphId: string, @Param('nodeId') nodeId: string): Promise { const analysis = await this.lineageService.analyzeImpact(graphId, nodeId); @@ -175,12 +288,23 @@ export class DataWarehouseController { } // Incremental Loading endpoints + /** + * Creates load Job. + * @param body The body. + * @returns The operation result. + */ @Post('loading/job') async createLoadJob(@Body() body: { config: any; source: any; target: any }): Promise { const job = await this.loaderService.createLoadJob(body.config, body.source, body.target); return { success: true, job }; } + /** + * Executes execute Load Job. + * @param jobId The job identifier. + * @param body The body. + * @returns The operation result. + */ @Post('loading/job/:id/execute') async executeLoadJob( @Param('id') jobId: string, @@ -190,18 +314,32 @@ export class DataWarehouseController { return { success: true, job }; } + /** + * Returns all Load Jobs. + * @returns The operation result. + */ @Get('loading/jobs') async getAllLoadJobs(): Promise { const jobs = await this.loaderService.getAllJobs(); return { success: true, jobs }; } + /** + * Returns load Job. + * @param id The identifier. + * @returns The operation result. + */ @Get('loading/job/:id') async getLoadJob(@Param('id') id: string): Promise { const job = await this.loaderService.getJobStatus(id); return { success: true, job }; } + /** + * Sets watermark. + * @param body The body. + * @returns The operation result. + */ @Post('loading/watermark') async setWatermark( @Body() body: { tableName: string; columnName: string; value: any }, @@ -214,6 +352,12 @@ export class DataWarehouseController { return { success: true, watermark }; } + /** + * Returns watermark. + * @param tableName The table name. + * @param columnName The column name. + * @returns The operation result. + */ @Get('loading/watermark/:tableName/:columnName') async getWatermark( @Param('tableName') tableName: string, diff --git a/src/data-warehouse/data-warehouse.module.ts b/src/data-warehouse/data-warehouse.module.ts index 841c2207..a9bc031d 100644 --- a/src/data-warehouse/data-warehouse.module.ts +++ b/src/data-warehouse/data-warehouse.module.ts @@ -6,6 +6,9 @@ import { DataLineageService } from './lineage/data-lineage.service'; import { IncrementalLoaderService } from './loading/incremental-loader.service'; import { DataWarehouseController } from './data-warehouse.controller'; +/** + * Registers the data Warehouse module. + */ @Module({ imports: [], controllers: [DataWarehouseController], diff --git a/src/data-warehouse/etl/etl-pipeline.service.ts b/src/data-warehouse/etl/etl-pipeline.service.ts index d9e14cf8..29491f49 100644 --- a/src/data-warehouse/etl/etl-pipeline.service.ts +++ b/src/data-warehouse/etl/etl-pipeline.service.ts @@ -63,6 +63,9 @@ export interface ITransformedData { }; } +/** + * Provides eTLPipeline operations. + */ @Injectable() export class ETLPipelineService { private readonly logger = new Logger(ETLPipelineService.name); diff --git a/src/data-warehouse/lineage/data-lineage.service.ts b/src/data-warehouse/lineage/data-lineage.service.ts index cbff12e6..19a05269 100644 --- a/src/data-warehouse/lineage/data-lineage.service.ts +++ b/src/data-warehouse/lineage/data-lineage.service.ts @@ -57,6 +57,9 @@ export interface ImpactAnalysis { timestamp: Date; } +/** + * Provides data Lineage operations. + */ @Injectable() export class DataLineageService { private readonly logger = new Logger(DataLineageService.name); diff --git a/src/data-warehouse/loading/incremental-loader.service.ts b/src/data-warehouse/loading/incremental-loader.service.ts index 0e453ba5..7bdb6457 100644 --- a/src/data-warehouse/loading/incremental-loader.service.ts +++ b/src/data-warehouse/loading/incremental-loader.service.ts @@ -63,6 +63,9 @@ export interface ICDCEvent { transactionId?: string; } +/** + * Provides incremental Loader operations. + */ @Injectable() export class IncrementalLoaderService { private readonly logger = new Logger(IncrementalLoaderService.name); diff --git a/src/data-warehouse/modeling/dimensional-modeling.service.ts b/src/data-warehouse/modeling/dimensional-modeling.service.ts index 8e7a6ced..fd6b3488 100644 --- a/src/data-warehouse/modeling/dimensional-modeling.service.ts +++ b/src/data-warehouse/modeling/dimensional-modeling.service.ts @@ -100,6 +100,9 @@ export interface IQueryFilter { value: any; } +/** + * Provides dimensional Modeling operations. + */ @Injectable() export class DimensionalModelingService { private readonly logger = new Logger(DimensionalModelingService.name); diff --git a/src/data-warehouse/quality/data-quality.service.ts b/src/data-warehouse/quality/data-quality.service.ts index cb165b8f..09522112 100644 --- a/src/data-warehouse/quality/data-quality.service.ts +++ b/src/data-warehouse/quality/data-quality.service.ts @@ -69,6 +69,9 @@ export interface IDataQualityIssue { resolvedBy?: string; } +/** + * Provides data Quality operations. + */ @Injectable() export class DataQualityService { private readonly logger = new Logger(DataQualityService.name); diff --git a/src/email-marketing/ab-testing/ab-testing.controller.ts b/src/email-marketing/ab-testing/ab-testing.controller.ts index 13704c7e..8edf4d10 100644 --- a/src/email-marketing/ab-testing/ab-testing.controller.ts +++ b/src/email-marketing/ab-testing/ab-testing.controller.ts @@ -5,12 +5,20 @@ import { ABTestingService } from './ab-testing.service'; import { CreateABTestDto } from '../dto/create-ab-test.dto'; import { ABTest } from '../entities/ab-test.entity'; +/** + * Exposes AB testing endpoints. + */ @ApiTags('Email Marketing - A/B Testing') @ApiBearerAuth() @Controller('email-marketing/ab-tests') export class ABTestingController { constructor(private readonly abTestingService: ABTestingService) {} + /** + * Creates a new record. + * @param createABTestDto The request payload. + * @returns The resulting abtest. + */ @Post() @ApiOperation({ summary: 'Create a new A/B test' }) @ApiResponse({ status: 201, description: 'A/B test created successfully' }) @@ -18,6 +26,12 @@ export class ABTestingController { return this.abTestingService.create(createABTestDto); } + /** + * Returns all. + * @param page The page number. + * @param limit The maximum number of results. + * @returns The operation result. + */ @Get() @ApiOperation({ summary: 'Get all A/B tests' }) @ApiQuery({ name: 'page', required: false, type: Number }) @@ -26,6 +40,11 @@ export class ABTestingController { return this.abTestingService.findAll(page, limit); } + /** + * Returns one. + * @param id The identifier. + * @returns The resulting abtest. + */ @Get(':id') @ApiOperation({ summary: 'Get an A/B test by ID' }) @ApiResponse({ status: 404, description: 'A/B test not found' }) @@ -33,18 +52,34 @@ export class ABTestingController { return this.abTestingService.findOne(id); } + /** + * Starts test. + * @param id The identifier. + * @returns The resulting abtest. + */ @Post(':id/start') @ApiOperation({ summary: 'Start an A/B test' }) async startTest(@Param('id', ParseUUIDPipe) id: string): Promise { return this.abTestingService.startTest(id); } + /** + * Returns results. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/results') @ApiOperation({ summary: 'Get A/B test results with statistical analysis' }) async getResults(@Param('id', ParseUUIDPipe) id: string) { return this.abTestingService.getTestResults(id); } + /** + * Executes declare Winner. + * @param id The identifier. + * @param variantId The variant identifier. + * @returns The resulting abtest. + */ @Post(':id/winner/:variantId') @ApiOperation({ summary: 'Declare a winner for the A/B test' }) async declareWinner( diff --git a/src/email-marketing/ab-testing/ab-testing.service.ts b/src/email-marketing/ab-testing/ab-testing.service.ts index a94493ac..325702d6 100644 --- a/src/email-marketing/ab-testing/ab-testing.service.ts +++ b/src/email-marketing/ab-testing/ab-testing.service.ts @@ -21,6 +21,9 @@ export interface IVariantStats { confidenceLevel: number; } +/** + * Provides aBTesting operations. + */ @Injectable() export class ABTestingService { constructor( diff --git a/src/email-marketing/analytics/email-analytics.controller.ts b/src/email-marketing/analytics/email-analytics.controller.ts index 97fcf224..5f3b06ce 100644 --- a/src/email-marketing/analytics/email-analytics.controller.ts +++ b/src/email-marketing/analytics/email-analytics.controller.ts @@ -3,12 +3,20 @@ import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth, ApiQuery } from '@ne import { EmailAnalyticsService } from './email-analytics.service'; +/** + * Exposes email Analytics endpoints. + */ @ApiTags('Email Marketing - Analytics') @ApiBearerAuth() @Controller('email-marketing/analytics') export class EmailAnalyticsController { constructor(private readonly analyticsService: EmailAnalyticsService) {} + /** + * Returns campaign Metrics. + * @param id The identifier. + * @returns The operation result. + */ @Get('campaigns/:id') @ApiOperation({ summary: 'Get campaign performance metrics' }) @ApiResponse({ status: 200, description: 'Campaign metrics' }) @@ -17,6 +25,13 @@ export class EmailAnalyticsController { return this.analyticsService.getCampaignMetrics(id); } + /** + * Returns campaign Timeline. + * @param id The identifier. + * @param startDate The start date. + * @param endDate The end date. + * @returns The operation result. + */ @Get('campaigns/:id/timeline') @ApiOperation({ summary: 'Get campaign time series data' }) @ApiQuery({ name: 'startDate', required: true, type: String }) @@ -29,12 +44,23 @@ export class EmailAnalyticsController { return this.analyticsService.getCampaignTimeSeries(id, new Date(startDate), new Date(endDate)); } + /** + * Returns link Analytics. + * @param id The identifier. + * @returns The operation result. + */ @Get('campaigns/:id/links') @ApiOperation({ summary: 'Get link click analytics for a campaign' }) async getLinkAnalytics(@Param('id', ParseUUIDPipe) id: string) { return this.analyticsService.getLinkAnalytics(id); } + /** + * Returns overall Stats. + * @param startDate The start date. + * @param endDate The end date. + * @returns The operation result. + */ @Get('overview') @ApiOperation({ summary: 'Get overall email marketing statistics' }) @ApiQuery({ name: 'startDate', required: false, type: String }) diff --git a/src/email-marketing/analytics/email-analytics.service.ts b/src/email-marketing/analytics/email-analytics.service.ts index 7c5ebe29..827ed03b 100644 --- a/src/email-marketing/analytics/email-analytics.service.ts +++ b/src/email-marketing/analytics/email-analytics.service.ts @@ -25,6 +25,9 @@ export interface ITimeSeriesData { bounces: number; } +/** + * Provides email Analytics operations. + */ @Injectable() export class EmailAnalyticsService { constructor( diff --git a/src/email-marketing/automation/automation.controller.ts b/src/email-marketing/automation/automation.controller.ts index 2519dd7d..4aadeb86 100644 --- a/src/email-marketing/automation/automation.controller.ts +++ b/src/email-marketing/automation/automation.controller.ts @@ -18,12 +18,20 @@ import { CreateAutomationDto } from '../dto/create-automation.dto'; import { UpdateAutomationDto } from '../dto/update-automation.dto'; import { AutomationWorkflow } from '../entities/automation-workflow.entity'; +/** + * Exposes automation endpoints. + */ @ApiTags('Email Marketing - Automation') @ApiBearerAuth() @Controller('email-marketing/automation') export class AutomationController { constructor(private readonly automationService: AutomationService) {} + /** + * Creates a new record. + * @param createAutomationDto The request payload. + * @returns The resulting automation workflow. + */ @Post() @ApiOperation({ summary: 'Create a new automation workflow' }) @ApiResponse({ status: 201, description: 'Workflow created successfully' }) @@ -32,6 +40,12 @@ export class AutomationController { return this.automationService.create(createAutomationDto); } + /** + * Returns all. + * @param page The page number. + * @param limit The maximum number of results. + * @returns The operation result. + */ @Get() @ApiOperation({ summary: 'Get all automation workflows' }) @ApiQuery({ name: 'page', required: false, type: Number }) @@ -41,6 +55,11 @@ export class AutomationController { return this.automationService.findAll(page, limit); } + /** + * Returns one. + * @param id The identifier. + * @returns The resulting automation workflow. + */ @Get(':id') @ApiOperation({ summary: 'Get an automation workflow by ID' }) @ApiResponse({ status: 200, description: 'Workflow details' }) @@ -49,6 +68,12 @@ export class AutomationController { return this.automationService.findOne(id); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateAutomationDto The request payload. + * @returns The resulting automation workflow. + */ @Put(':id') @ApiOperation({ summary: 'Update an automation workflow' }) @ApiResponse({ status: 200, description: 'Workflow updated successfully' }) @@ -61,6 +86,10 @@ export class AutomationController { return this.automationService.update(id, updateAutomationDto); } + /** + * Removes the requested record. + * @param id The identifier. + */ @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Delete an automation workflow' }) @@ -71,6 +100,11 @@ export class AutomationController { return this.automationService.remove(id); } + /** + * Executes activate. + * @param id The identifier. + * @returns The resulting automation workflow. + */ @Post(':id/activate') @ApiOperation({ summary: 'Activate an automation workflow' }) @ApiResponse({ status: 200, description: 'Workflow activated' }) @@ -79,6 +113,11 @@ export class AutomationController { return this.automationService.activate(id); } + /** + * Executes deactivate. + * @param id The identifier. + * @returns The resulting automation workflow. + */ @Post(':id/deactivate') @ApiOperation({ summary: 'Deactivate an automation workflow' }) @ApiResponse({ status: 200, description: 'Workflow deactivated' }) @@ -86,6 +125,11 @@ export class AutomationController { return this.automationService.deactivate(id); } + /** + * Returns stats. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/stats') @ApiOperation({ summary: 'Get workflow execution statistics' }) @ApiResponse({ status: 200, description: 'Workflow statistics' }) diff --git a/src/email-marketing/automation/automation.service.ts b/src/email-marketing/automation/automation.service.ts index b4b5f76a..e4a6a4f6 100644 --- a/src/email-marketing/automation/automation.service.ts +++ b/src/email-marketing/automation/automation.service.ts @@ -17,6 +17,9 @@ import { TriggerType } from '../enums/trigger-type.enum'; import { ActionType } from '../enums/action-type.enum'; import { WorkflowStatus } from '../enums/workflow-status.enum'; +/** + * Provides automation operations. + */ @Injectable() export class AutomationService { constructor( diff --git a/src/email-marketing/dto/add-segment-members.dto.ts b/src/email-marketing/dto/add-segment-members.dto.ts index 72ec280e..aa80769e 100644 --- a/src/email-marketing/dto/add-segment-members.dto.ts +++ b/src/email-marketing/dto/add-segment-members.dto.ts @@ -1,6 +1,9 @@ import { IsArray, IsString, ArrayNotEmpty, IsNotEmpty } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +/** + * Defines the add Segment Members payload. + */ export class AddSegmentMembersDto { @ApiProperty({ description: 'Array of user IDs to add to the segment', diff --git a/src/email-marketing/dto/create-ab-test.dto.ts b/src/email-marketing/dto/create-ab-test.dto.ts index d88c909f..af1bc563 100644 --- a/src/email-marketing/dto/create-ab-test.dto.ts +++ b/src/email-marketing/dto/create-ab-test.dto.ts @@ -12,6 +12,9 @@ import { import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; +/** + * Defines the create ABTest Variant payload. + */ export class CreateABTestVariantDto { @ApiPropertyOptional({ description: 'Variant name' }) @IsString() @@ -42,6 +45,9 @@ export class CreateABTestVariantDto { weight: number; } +/** + * Defines the create ABTest payload. + */ export class CreateABTestDto { @ApiProperty({ description: 'Test name', example: 'Subject Line Test' }) @IsString() diff --git a/src/email-marketing/dto/create-automation.dto.ts b/src/email-marketing/dto/create-automation.dto.ts index aa76578d..9c8c4193 100644 --- a/src/email-marketing/dto/create-automation.dto.ts +++ b/src/email-marketing/dto/create-automation.dto.ts @@ -4,6 +4,9 @@ import { Type } from 'class-transformer'; import { TriggerType } from '../enums/trigger-type.enum'; import { ActionType } from '../enums/action-type.enum'; +/** + * Defines the create Trigger payload. + */ export class CreateTriggerDto { @ApiProperty({ enum: TriggerType }) @IsEnum(TriggerType) @@ -21,6 +24,9 @@ export class CreateTriggerDto { description?: string; } +/** + * Defines the create Action payload. + */ export class CreateActionDto { @ApiProperty({ enum: ActionType }) @IsEnum(ActionType) @@ -38,6 +44,9 @@ export class CreateActionDto { description?: string; } +/** + * Defines the create Automation payload. + */ export class CreateAutomationDto { @ApiProperty({ description: 'Workflow name', example: 'Welcome Series' }) @IsString() diff --git a/src/email-marketing/dto/create-campaign.dto.ts b/src/email-marketing/dto/create-campaign.dto.ts index 52a2a4cd..933648a6 100644 --- a/src/email-marketing/dto/create-campaign.dto.ts +++ b/src/email-marketing/dto/create-campaign.dto.ts @@ -1,6 +1,9 @@ import { IsString, IsOptional, IsArray, IsUUID, IsNotEmpty, MaxLength } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +/** + * Defines the create Campaign payload. + */ export class CreateCampaignDto { @ApiProperty({ description: 'Campaign name', example: 'Welcome Campaign' }) @IsString() diff --git a/src/email-marketing/dto/create-segment.dto.ts b/src/email-marketing/dto/create-segment.dto.ts index 74df6e9e..7f22899b 100644 --- a/src/email-marketing/dto/create-segment.dto.ts +++ b/src/email-marketing/dto/create-segment.dto.ts @@ -12,6 +12,9 @@ import { Type } from 'class-transformer'; import { SegmentRuleField } from '../enums/segment-rule-field.enum'; import { SegmentRuleOperator } from '../enums/segment-rule-operator.enum'; +/** + * Defines the create Segment Rule payload. + */ export class CreateSegmentRuleDto { @ApiProperty({ enum: SegmentRuleField, example: 'email' }) @IsEnum(SegmentRuleField) @@ -33,6 +36,9 @@ export class CreateSegmentRuleDto { logicalOperator?: 'AND' | 'OR'; } +/** + * Defines the create Segment payload. + */ export class CreateSegmentDto { @ApiProperty({ description: 'Segment name', example: 'Active Users' }) @IsString() diff --git a/src/email-marketing/dto/create-template.dto.ts b/src/email-marketing/dto/create-template.dto.ts index 3ebb26ae..92f04c82 100644 --- a/src/email-marketing/dto/create-template.dto.ts +++ b/src/email-marketing/dto/create-template.dto.ts @@ -1,6 +1,9 @@ import { IsString, IsNotEmpty, IsOptional, MaxLength } from 'class-validator'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +/** + * Defines the create Template payload. + */ export class CreateTemplateDto { @ApiProperty({ description: 'Template name', example: 'Welcome Email' }) @IsString() diff --git a/src/email-marketing/dto/schedule-campaign.dto.ts b/src/email-marketing/dto/schedule-campaign.dto.ts index 00946a87..d88e75dd 100644 --- a/src/email-marketing/dto/schedule-campaign.dto.ts +++ b/src/email-marketing/dto/schedule-campaign.dto.ts @@ -1,6 +1,9 @@ import { IsDateString, IsNotEmpty, IsString } from 'class-validator'; import { ApiProperty } from '@nestjs/swagger'; +/** + * Defines the schedule Campaign payload. + */ export class ScheduleCampaignDto { @ApiProperty({ description: 'Scheduled send time (ISO 8601)', example: '2026-02-01T10:00:00Z' }) @IsDateString() diff --git a/src/email-marketing/dto/update-automation.dto.ts b/src/email-marketing/dto/update-automation.dto.ts index 5f00c82d..91ba19e8 100644 --- a/src/email-marketing/dto/update-automation.dto.ts +++ b/src/email-marketing/dto/update-automation.dto.ts @@ -1,4 +1,7 @@ import { PartialType } from '@nestjs/swagger'; import { CreateAutomationDto } from './create-automation.dto'; +/** + * Defines the update Automation payload. + */ export class UpdateAutomationDto extends PartialType(CreateAutomationDto) {} diff --git a/src/email-marketing/dto/update-campaign.dto.ts b/src/email-marketing/dto/update-campaign.dto.ts index e5a8ecdd..5a77a13d 100644 --- a/src/email-marketing/dto/update-campaign.dto.ts +++ b/src/email-marketing/dto/update-campaign.dto.ts @@ -1,4 +1,7 @@ import { PartialType } from '@nestjs/swagger'; import { CreateCampaignDto } from './create-campaign.dto'; +/** + * Defines the update Campaign payload. + */ export class UpdateCampaignDto extends PartialType(CreateCampaignDto) {} diff --git a/src/email-marketing/dto/update-segment.dto.ts b/src/email-marketing/dto/update-segment.dto.ts index 8cfac3d6..65240ea3 100644 --- a/src/email-marketing/dto/update-segment.dto.ts +++ b/src/email-marketing/dto/update-segment.dto.ts @@ -1,4 +1,7 @@ import { PartialType } from '@nestjs/swagger'; import { CreateSegmentDto } from './create-segment.dto'; +/** + * Defines the update Segment payload. + */ export class UpdateSegmentDto extends PartialType(CreateSegmentDto) {} diff --git a/src/email-marketing/dto/update-template.dto.ts b/src/email-marketing/dto/update-template.dto.ts index 176dc19e..4e185785 100644 --- a/src/email-marketing/dto/update-template.dto.ts +++ b/src/email-marketing/dto/update-template.dto.ts @@ -1,4 +1,7 @@ import { PartialType } from '@nestjs/swagger'; import { CreateTemplateDto } from './create-template.dto'; +/** + * Defines the update Template payload. + */ export class UpdateTemplateDto extends PartialType(CreateTemplateDto) {} diff --git a/src/email-marketing/email-marketing.controller.ts b/src/email-marketing/email-marketing.controller.ts index 4c322977..feefbd19 100644 --- a/src/email-marketing/email-marketing.controller.ts +++ b/src/email-marketing/email-marketing.controller.ts @@ -19,12 +19,20 @@ import { UpdateCampaignDto } from './dto/update-campaign.dto'; import { ScheduleCampaignDto } from './dto/schedule-campaign.dto'; import { Campaign } from './entities/campaign.entity'; +/** + * Exposes email Marketing endpoints. + */ @ApiTags('Email Marketing - Campaigns') @ApiBearerAuth() @Controller('email-marketing/campaigns') export class EmailMarketingController { constructor(private readonly emailMarketingService: EmailMarketingService) {} + /** + * Creates a new record. + * @param createCampaignDto The request payload. + * @returns The resulting campaign. + */ @Post() @ApiOperation({ summary: 'Create a new email campaign' }) @ApiResponse({ status: 201, description: 'Campaign created successfully', type: Campaign }) @@ -33,6 +41,12 @@ export class EmailMarketingController { return this.emailMarketingService.createCampaign(createCampaignDto); } + /** + * Returns all. + * @param page The page number. + * @param limit The maximum number of results. + * @returns The operation result. + */ @Get() @ApiOperation({ summary: 'Get all campaigns with pagination' }) @ApiQuery({ name: 'page', required: false, type: Number, example: 1 }) @@ -42,6 +56,11 @@ export class EmailMarketingController { return this.emailMarketingService.findAll(page, limit); } + /** + * Returns one. + * @param id The identifier. + * @returns The resulting campaign. + */ @Get(':id') @ApiOperation({ summary: 'Get a campaign by ID' }) @ApiResponse({ status: 200, description: 'Campaign details', type: Campaign }) @@ -50,6 +69,12 @@ export class EmailMarketingController { return this.emailMarketingService.findOne(id); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateCampaignDto The request payload. + * @returns The resulting campaign. + */ @Put(':id') @ApiOperation({ summary: 'Update a campaign' }) @ApiResponse({ status: 200, description: 'Campaign updated successfully', type: Campaign }) @@ -62,6 +87,10 @@ export class EmailMarketingController { return this.emailMarketingService.update(id, updateCampaignDto); } + /** + * Removes the requested record. + * @param id The identifier. + */ @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Delete a campaign' }) @@ -72,6 +101,12 @@ export class EmailMarketingController { return this.emailMarketingService.remove(id); } + /** + * Schedules schedule. + * @param id The identifier. + * @param scheduleDto The request payload. + * @returns The resulting campaign. + */ @Post(':id/schedule') @ApiOperation({ summary: 'Schedule a campaign for future sending' }) @ApiResponse({ status: 200, description: 'Campaign scheduled successfully', type: Campaign }) @@ -83,6 +118,11 @@ export class EmailMarketingController { return this.emailMarketingService.scheduleCampaign(id, scheduleDto); } + /** + * Sends send. + * @param id The identifier. + * @returns The resulting campaign. + */ @Post(':id/send') @ApiOperation({ summary: 'Send a campaign immediately' }) @ApiResponse({ status: 200, description: 'Campaign sending initiated', type: Campaign }) @@ -91,6 +131,11 @@ export class EmailMarketingController { return this.emailMarketingService.sendCampaign(id); } + /** + * Pauses pause. + * @param id The identifier. + * @returns The resulting campaign. + */ @Post(':id/pause') @ApiOperation({ summary: 'Pause a scheduled or sending campaign' }) @ApiResponse({ status: 200, description: 'Campaign paused successfully', type: Campaign }) @@ -99,6 +144,11 @@ export class EmailMarketingController { return this.emailMarketingService.pauseCampaign(id); } + /** + * Resumes resume. + * @param id The identifier. + * @returns The resulting campaign. + */ @Post(':id/resume') @ApiOperation({ summary: 'Resume a paused campaign' }) @ApiResponse({ status: 200, description: 'Campaign resumed successfully', type: Campaign }) @@ -107,6 +157,11 @@ export class EmailMarketingController { return this.emailMarketingService.resumeCampaign(id); } + /** + * Executes duplicate. + * @param id The identifier. + * @returns The resulting campaign. + */ @Post(':id/duplicate') @ApiOperation({ summary: 'Duplicate a campaign' }) @ApiResponse({ status: 201, description: 'Campaign duplicated successfully', type: Campaign }) @@ -115,6 +170,11 @@ export class EmailMarketingController { return this.emailMarketingService.duplicateCampaign(id); } + /** + * Returns stats. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/stats') @ApiOperation({ summary: 'Get campaign statistics' }) @ApiResponse({ status: 200, description: 'Campaign statistics' }) diff --git a/src/email-marketing/email-marketing.module.ts b/src/email-marketing/email-marketing.module.ts index 8f7c11d6..a182b5fa 100644 --- a/src/email-marketing/email-marketing.module.ts +++ b/src/email-marketing/email-marketing.module.ts @@ -39,6 +39,9 @@ import { EmailSubscription } from './entities/email-subscription.entity'; // Processors (Bull Queue) import { EmailQueueProcessor } from './processors/email-queue.processor'; +/** + * Registers the email Marketing module. + */ @Module({ imports: [ ConfigModule, diff --git a/src/email-marketing/email-marketing.service.ts b/src/email-marketing/email-marketing.service.ts index f5cc3e0e..d9436c2f 100644 --- a/src/email-marketing/email-marketing.service.ts +++ b/src/email-marketing/email-marketing.service.ts @@ -17,6 +17,9 @@ import { UpdateCampaignDto } from './dto/update-campaign.dto'; import { ScheduleCampaignDto } from './dto/schedule-campaign.dto'; import { CampaignStatus } from './enums/campaign-status.enum'; +/** + * Provides email Marketing operations. + */ @Injectable() export class EmailMarketingService { constructor( diff --git a/src/email-marketing/entities/ab-test-variant.entity.ts b/src/email-marketing/entities/ab-test-variant.entity.ts index fde3b97f..fd77e209 100644 --- a/src/email-marketing/entities/ab-test-variant.entity.ts +++ b/src/email-marketing/entities/ab-test-variant.entity.ts @@ -10,6 +10,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { ABTest } from './ab-test.entity'; +/** + * Represents the aBTest Variant entity. + */ @Entity('ab_test_variants') export class ABTestVariant { @ApiProperty() diff --git a/src/email-marketing/entities/ab-test.entity.ts b/src/email-marketing/entities/ab-test.entity.ts index 3ca32b44..9774d3aa 100644 --- a/src/email-marketing/entities/ab-test.entity.ts +++ b/src/email-marketing/entities/ab-test.entity.ts @@ -14,6 +14,9 @@ import { Campaign } from './campaign.entity'; import { ABTestVariant } from './ab-test-variant.entity'; import { ABTestStatus } from '../enums/ab-test-status.enum'; +/** + * Represents the aBTest entity. + */ @Entity('ab_tests') export class ABTest { @ApiProperty() diff --git a/src/email-marketing/entities/automation-action.entity.ts b/src/email-marketing/entities/automation-action.entity.ts index ce2570e4..6cc7b43b 100644 --- a/src/email-marketing/entities/automation-action.entity.ts +++ b/src/email-marketing/entities/automation-action.entity.ts @@ -12,6 +12,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { AutomationWorkflow } from './automation-workflow.entity'; import { ActionType } from '../enums/action-type.enum'; +/** + * Represents the automation Action entity. + */ @Entity('automation_actions') export class AutomationAction { @ApiProperty() diff --git a/src/email-marketing/entities/automation-trigger.entity.ts b/src/email-marketing/entities/automation-trigger.entity.ts index 71b4eab6..282e0499 100644 --- a/src/email-marketing/entities/automation-trigger.entity.ts +++ b/src/email-marketing/entities/automation-trigger.entity.ts @@ -12,6 +12,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { AutomationWorkflow } from './automation-workflow.entity'; import { TriggerType } from '../enums/trigger-type.enum'; +/** + * Represents the automation Trigger entity. + */ @Entity('automation_triggers') export class AutomationTrigger { @ApiProperty() diff --git a/src/email-marketing/entities/automation-workflow.entity.ts b/src/email-marketing/entities/automation-workflow.entity.ts index a02f4305..fbeca1d2 100644 --- a/src/email-marketing/entities/automation-workflow.entity.ts +++ b/src/email-marketing/entities/automation-workflow.entity.ts @@ -14,6 +14,9 @@ import { AutomationTrigger } from './automation-trigger.entity'; import { AutomationAction } from './automation-action.entity'; import { WorkflowStatus } from '../enums/workflow-status.enum'; +/** + * Represents the automation Workflow entity. + */ @Entity('automation_workflows') export class AutomationWorkflow { @ApiProperty() diff --git a/src/email-marketing/entities/campaign-recipient.entity.ts b/src/email-marketing/entities/campaign-recipient.entity.ts index f75d8adb..5d45e5ed 100644 --- a/src/email-marketing/entities/campaign-recipient.entity.ts +++ b/src/email-marketing/entities/campaign-recipient.entity.ts @@ -13,6 +13,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { Campaign } from './campaign.entity'; import { RecipientStatus } from '../enums/recipient-status.enum'; +/** + * Represents the campaign Recipient entity. + */ @Entity('campaign_recipients') @Index(['campaignId', 'status']) export class CampaignRecipient { diff --git a/src/email-marketing/entities/campaign.entity.ts b/src/email-marketing/entities/campaign.entity.ts index bcfce39d..938886bd 100644 --- a/src/email-marketing/entities/campaign.entity.ts +++ b/src/email-marketing/entities/campaign.entity.ts @@ -19,6 +19,9 @@ import { ABTest } from './ab-test.entity'; import { CampaignRecipient } from './campaign-recipient.entity'; import { CampaignStatus } from '../enums/campaign-status.enum'; +/** + * Represents the campaign entity. + */ @Entity('email_campaigns') export class Campaign { @ApiProperty() diff --git a/src/email-marketing/entities/email-event.entity.ts b/src/email-marketing/entities/email-event.entity.ts index b9b05c9a..9667b2b8 100644 --- a/src/email-marketing/entities/email-event.entity.ts +++ b/src/email-marketing/entities/email-event.entity.ts @@ -10,6 +10,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { EmailEventType } from '../enums/email-event-type.enum'; +/** + * Represents the email Event entity. + */ @Entity('email_events') @Index(['campaignId', 'eventType']) @Index(['recipientId', 'eventType']) diff --git a/src/email-marketing/entities/email-subscription.entity.ts b/src/email-marketing/entities/email-subscription.entity.ts index cd396f5e..5b6d47b7 100644 --- a/src/email-marketing/entities/email-subscription.entity.ts +++ b/src/email-marketing/entities/email-subscription.entity.ts @@ -8,6 +8,9 @@ import { } from 'typeorm'; import { ApiProperty } from '@nestjs/swagger'; +/** + * Represents the email Subscription entity. + */ @Entity('email_subscriptions') @Index(['email'], { unique: true }) export class EmailSubscription { diff --git a/src/email-marketing/entities/email-template.entity.ts b/src/email-marketing/entities/email-template.entity.ts index 0282198d..684a41c2 100644 --- a/src/email-marketing/entities/email-template.entity.ts +++ b/src/email-marketing/entities/email-template.entity.ts @@ -9,6 +9,9 @@ import { } from 'typeorm'; import { ApiProperty } from '@nestjs/swagger'; +/** + * Represents the email Template entity. + */ @Entity('email_templates') export class EmailTemplate { @ApiProperty() diff --git a/src/email-marketing/entities/segment-rule.entity.ts b/src/email-marketing/entities/segment-rule.entity.ts index a4d0683b..160beb37 100644 --- a/src/email-marketing/entities/segment-rule.entity.ts +++ b/src/email-marketing/entities/segment-rule.entity.ts @@ -13,6 +13,9 @@ import { Segment } from './segment.entity'; import { SegmentRuleOperator } from '../enums/segment-rule-operator.enum'; import { SegmentRuleField } from '../enums/segment-rule-field.enum'; +/** + * Represents the segment Rule entity. + */ @Entity('segment_rules') export class SegmentRule { @ApiProperty() diff --git a/src/email-marketing/entities/segment.entity.ts b/src/email-marketing/entities/segment.entity.ts index 7ecbdb0d..eeec0b3a 100644 --- a/src/email-marketing/entities/segment.entity.ts +++ b/src/email-marketing/entities/segment.entity.ts @@ -12,6 +12,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { SegmentRule } from './segment-rule.entity'; +/** + * Represents the segment entity. + */ @Entity('segments') export class Segment { @ApiProperty() diff --git a/src/email-marketing/segmentation/segment.controller.ts b/src/email-marketing/segmentation/segment.controller.ts index 12e499e8..756b1e04 100644 --- a/src/email-marketing/segmentation/segment.controller.ts +++ b/src/email-marketing/segmentation/segment.controller.ts @@ -19,12 +19,20 @@ import { UpdateSegmentDto } from '../dto/update-segment.dto'; import { AddSegmentMembersDto } from '../dto/add-segment-members.dto'; import { Segment } from '../entities/segment.entity'; +/** + * Exposes segment endpoints. + */ @ApiTags('Email Marketing - Segments') @ApiBearerAuth() @Controller('email-marketing/segments') export class SegmentController { constructor(private readonly segmentationService: SegmentationService) {} + /** + * Creates a new record. + * @param createSegmentDto The request payload. + * @returns The resulting segment. + */ @Post() @ApiOperation({ summary: 'Create a new audience segment' }) @ApiResponse({ status: 201, description: 'Segment created successfully' }) @@ -32,6 +40,12 @@ export class SegmentController { return this.segmentationService.create(createSegmentDto); } + /** + * Returns all. + * @param page The page number. + * @param limit The maximum number of results. + * @returns The operation result. + */ @Get() @ApiOperation({ summary: 'Get all segments with pagination' }) @ApiQuery({ name: 'page', required: false, type: Number }) @@ -40,6 +54,11 @@ export class SegmentController { return this.segmentationService.findAll(page, limit); } + /** + * Returns one. + * @param id The identifier. + * @returns The resulting segment. + */ @Get(':id') @ApiOperation({ summary: 'Get a segment by ID' }) @ApiResponse({ status: 404, description: 'Segment not found' }) @@ -47,6 +66,12 @@ export class SegmentController { return this.segmentationService.findOne(id); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateSegmentDto The request payload. + * @returns The resulting segment. + */ @Put(':id') @ApiOperation({ summary: 'Update a segment' }) async update( @@ -56,6 +81,10 @@ export class SegmentController { return this.segmentationService.update(id, updateSegmentDto); } + /** + * Removes the requested record. + * @param id The identifier. + */ @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Delete a segment' }) @@ -63,12 +92,23 @@ export class SegmentController { return this.segmentationService.remove(id); } + /** + * Returns members. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/members') @ApiOperation({ summary: 'Get members of a segment' }) async getMembers(@Param('id', ParseUUIDPipe) id: string) { return this.segmentationService.getSegmentMembers(id); } + /** + * Executes add Members. + * @param id The identifier. + * @param addMembersDto The request payload. + * @returns The operation result. + */ @Post(':id/members') @ApiOperation({ summary: 'Add users to a static segment' }) @ApiResponse({ status: 200, description: 'Users added successfully' }) @@ -83,6 +123,11 @@ export class SegmentController { }; } + /** + * Executes preview. + * @param createSegmentDto The request payload. + * @returns The operation result. + */ @Post('preview') @ApiOperation({ summary: 'Preview segment members without saving' }) async preview(@Body() createSegmentDto: CreateSegmentDto) { diff --git a/src/email-marketing/segmentation/segmentation.service.ts b/src/email-marketing/segmentation/segmentation.service.ts index f9dc8994..3f60f103 100644 --- a/src/email-marketing/segmentation/segmentation.service.ts +++ b/src/email-marketing/segmentation/segmentation.service.ts @@ -21,6 +21,9 @@ export interface IUserProfile { preferences?: Record; } +/** + * Provides segmentation operations. + */ @Injectable() export class SegmentationService { constructor( diff --git a/src/email-marketing/sender/email-sender.service.ts b/src/email-marketing/sender/email-sender.service.ts index 75962eda..cb88a530 100644 --- a/src/email-marketing/sender/email-sender.service.ts +++ b/src/email-marketing/sender/email-sender.service.ts @@ -26,6 +26,9 @@ export interface ISendEmailResult { error?: string; } +/** + * Provides email Sender operations. + */ @Injectable() export class EmailSenderService { private readonly logger = new Logger(EmailSenderService.name); diff --git a/src/email-marketing/templates/template-management.service.ts b/src/email-marketing/templates/template-management.service.ts index eb27d9b6..617b3fd6 100644 --- a/src/email-marketing/templates/template-management.service.ts +++ b/src/email-marketing/templates/template-management.service.ts @@ -7,6 +7,9 @@ import { EmailTemplate } from '../entities/email-template.entity'; import { CreateTemplateDto } from '../dto/create-template.dto'; import { UpdateTemplateDto } from '../dto/update-template.dto'; +/** + * Provides template Management operations. + */ @Injectable() export class TemplateManagementService { constructor( diff --git a/src/email-marketing/templates/template.controller.ts b/src/email-marketing/templates/template.controller.ts index 6e17894a..746dfebd 100644 --- a/src/email-marketing/templates/template.controller.ts +++ b/src/email-marketing/templates/template.controller.ts @@ -18,12 +18,20 @@ import { CreateTemplateDto } from '../dto/create-template.dto'; import { UpdateTemplateDto } from '../dto/update-template.dto'; import { EmailTemplate } from '../entities/email-template.entity'; +/** + * Exposes template endpoints. + */ @ApiTags('Email Marketing - Templates') @ApiBearerAuth() @Controller('email-marketing/templates') export class TemplateController { constructor(private readonly templateService: TemplateManagementService) {} + /** + * Creates a new record. + * @param createTemplateDto The request payload. + * @returns The resulting email template. + */ @Post() @ApiOperation({ summary: 'Create a new email template' }) @ApiResponse({ status: 201, description: 'Template created successfully' }) @@ -31,6 +39,12 @@ export class TemplateController { return this.templateService.create(createTemplateDto); } + /** + * Returns all. + * @param page The page number. + * @param limit The maximum number of results. + * @returns The operation result. + */ @Get() @ApiOperation({ summary: 'Get all email templates' }) @ApiQuery({ name: 'page', required: false, type: Number }) @@ -39,6 +53,11 @@ export class TemplateController { return this.templateService.findAll(page, limit); } + /** + * Returns one. + * @param id The identifier. + * @returns The resulting email template. + */ @Get(':id') @ApiOperation({ summary: 'Get a template by ID' }) @ApiResponse({ status: 404, description: 'Template not found' }) @@ -46,6 +65,12 @@ export class TemplateController { return this.templateService.findOne(id); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateTemplateDto The request payload. + * @returns The resulting email template. + */ @Put(':id') @ApiOperation({ summary: 'Update a template' }) async update( @@ -55,6 +80,10 @@ export class TemplateController { return this.templateService.update(id, updateTemplateDto); } + /** + * Removes the requested record. + * @param id The identifier. + */ @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Delete a template' }) @@ -62,18 +91,35 @@ export class TemplateController { return this.templateService.remove(id); } + /** + * Executes duplicate. + * @param id The identifier. + * @returns The resulting email template. + */ @Post(':id/duplicate') @ApiOperation({ summary: 'Duplicate a template' }) async duplicate(@Param('id', ParseUUIDPipe) id: string): Promise { return this.templateService.duplicate(id); } + /** + * Executes preview. + * @param id The identifier. + * @param sampleData The data to process. + * @returns The operation result. + */ @Post(':id/preview') @ApiOperation({ summary: 'Preview a template with sample data' }) async preview(@Param('id', ParseUUIDPipe) id: string, @Body() sampleData?: Record) { return this.templateService.previewTemplate(id, sampleData); } + /** + * Executes render. + * @param id The identifier. + * @param variables The variables. + * @returns The operation result. + */ @Post(':id/render') @ApiOperation({ summary: 'Render a template with provided variables' }) async render(@Param('id', ParseUUIDPipe) id: string, @Body() variables: Record) { diff --git a/src/feature-flags/analytics/flag-analytics.service.ts b/src/feature-flags/analytics/flag-analytics.service.ts index e5ab9352..fe0a193b 100644 --- a/src/feature-flags/analytics/flag-analytics.service.ts +++ b/src/feature-flags/analytics/flag-analytics.service.ts @@ -9,6 +9,9 @@ import { type TrackEvaluationInput = Omit; +/** + * Provides flag Analytics operations. + */ @Injectable() export class FlagAnalyticsService { /** flagKey → events */ diff --git a/src/feature-flags/evaluation/flag-evaluation.service.ts b/src/feature-flags/evaluation/flag-evaluation.service.ts index fb16623f..8ed54657 100644 --- a/src/feature-flags/evaluation/flag-evaluation.service.ts +++ b/src/feature-flags/evaluation/flag-evaluation.service.ts @@ -11,6 +11,9 @@ import { ExperimentationService } from '../experimentation/experimentation.servi import { RolloutService } from '../rollout/rollout.service'; import { TargetingService } from '../targeting/targeting.service'; +/** + * Provides flag Evaluation operations. + */ @Injectable() export class FlagEvaluationService { private readonly flags = new Map(); @@ -182,6 +185,12 @@ export class FlagEvaluationService { } } + /** + * Updates flag. + * @param flagKey The flag key. + * @param updates The updates. + * @returns The operation result. + */ updateFlag( flagKey: string, updates: Partial>, @@ -202,6 +211,11 @@ export class FlagEvaluationService { return updated; } + /** + * Removes flag. + * @param flagKey The flag key. + * @returns Whether the operation succeeded. + */ removeFlag(flagKey: string): boolean { return this.flags.delete(flagKey); } diff --git a/src/feature-flags/experimentation/experimentation.service.ts b/src/feature-flags/experimentation/experimentation.service.ts index caaea94c..d5bb917f 100644 --- a/src/feature-flags/experimentation/experimentation.service.ts +++ b/src/feature-flags/experimentation/experimentation.service.ts @@ -13,6 +13,9 @@ interface IConversionRecord { timestamp: Date; } +/** + * Provides experimentation operations. + */ @Injectable() export class ExperimentationService { /** variantKey → userId → IConversionRecord[] */ diff --git a/src/feature-flags/feature-flags.module.ts b/src/feature-flags/feature-flags.module.ts index bc91d4ef..3f91b29f 100644 --- a/src/feature-flags/feature-flags.module.ts +++ b/src/feature-flags/feature-flags.module.ts @@ -6,6 +6,9 @@ import { ExperimentationService } from './experimentation/experimentation.servic import { FlagAnalyticsService } from './analytics/flag-analytics.service'; import { FeatureFlagsController } from './feature-flags.controller'; +/** + * Registers the feature Flags module. + */ @Module({ controllers: [FeatureFlagsController], providers: [ diff --git a/src/feature-flags/rollout/rollout.service.ts b/src/feature-flags/rollout/rollout.service.ts index 140f1d31..dff766f0 100644 --- a/src/feature-flags/rollout/rollout.service.ts +++ b/src/feature-flags/rollout/rollout.service.ts @@ -1,6 +1,9 @@ import { Injectable } from '@nestjs/common'; import { IRolloutConfig, IUserContext } from '../interfaces'; +/** + * Provides rollout operations. + */ @Injectable() export class RolloutService { /** diff --git a/src/feature-flags/targeting/targeting.service.ts b/src/feature-flags/targeting/targeting.service.ts index c63cb2be..e43f9c74 100644 --- a/src/feature-flags/targeting/targeting.service.ts +++ b/src/feature-flags/targeting/targeting.service.ts @@ -8,6 +8,9 @@ import { IUserContext, } from '../interfaces'; +/** + * Provides targeting operations. + */ @Injectable() export class TargetingService { /** diff --git a/src/gamification/badges/badges.service.ts b/src/gamification/badges/badges.service.ts index 1fbd63f4..134dc664 100644 --- a/src/gamification/badges/badges.service.ts +++ b/src/gamification/badges/badges.service.ts @@ -5,6 +5,9 @@ import { Badge } from '../entities/badge.entity'; import { UserBadge } from '../entities/user-badge.entity'; import { User } from '../../users/entities/user.entity'; +/** + * Provides badges operations. + */ @Injectable() export class BadgesService { constructor( diff --git a/src/gamification/challenges/challenges.service.ts b/src/gamification/challenges/challenges.service.ts index f5f528d9..14a5c734 100644 --- a/src/gamification/challenges/challenges.service.ts +++ b/src/gamification/challenges/challenges.service.ts @@ -5,6 +5,9 @@ import { Challenge } from '../entities/challenge.entity'; import { UserChallenge } from '../entities/user-challenge.entity'; import { User } from '../../users/entities/user.entity'; +/** + * Provides challenges operations. + */ @Injectable() export class ChallengesService { constructor( diff --git a/src/gamification/entities/badge.entity.ts b/src/gamification/entities/badge.entity.ts index fb0b0776..3be06164 100644 --- a/src/gamification/entities/badge.entity.ts +++ b/src/gamification/entities/badge.entity.ts @@ -1,5 +1,8 @@ import { Entity, PrimaryGeneratedColumn, Column, VersionColumn } from 'typeorm'; +/** + * Represents the badge entity. + */ @Entity('badges') export class Badge { @PrimaryGeneratedColumn('uuid') diff --git a/src/gamification/entities/challenge.entity.ts b/src/gamification/entities/challenge.entity.ts index 7db9f226..24ec96fa 100644 --- a/src/gamification/entities/challenge.entity.ts +++ b/src/gamification/entities/challenge.entity.ts @@ -1,5 +1,8 @@ import { Entity, PrimaryGeneratedColumn, Column, VersionColumn } from 'typeorm'; +/** + * Represents the challenge entity. + */ @Entity('challenges') export class Challenge { @PrimaryGeneratedColumn('uuid') diff --git a/src/gamification/entities/point-transaction.entity.ts b/src/gamification/entities/point-transaction.entity.ts index 933face4..0274e5c3 100644 --- a/src/gamification/entities/point-transaction.entity.ts +++ b/src/gamification/entities/point-transaction.entity.ts @@ -8,6 +8,9 @@ import { } from 'typeorm'; import { User } from '../../users/entities/user.entity'; +/** + * Represents the point Transaction entity. + */ @Entity('point_transactions') export class PointTransaction { @PrimaryGeneratedColumn('uuid') diff --git a/src/gamification/entities/user-badge.entity.ts b/src/gamification/entities/user-badge.entity.ts index 29b48a92..58d6182d 100644 --- a/src/gamification/entities/user-badge.entity.ts +++ b/src/gamification/entities/user-badge.entity.ts @@ -8,6 +8,9 @@ import { import { User } from '../../users/entities/user.entity'; import { Badge } from './badge.entity'; +/** + * Represents the user Badge entity. + */ @Entity('user_badges') export class UserBadge { @PrimaryGeneratedColumn('uuid') diff --git a/src/gamification/entities/user-challenge.entity.ts b/src/gamification/entities/user-challenge.entity.ts index 302c48a6..3e5b09cf 100644 --- a/src/gamification/entities/user-challenge.entity.ts +++ b/src/gamification/entities/user-challenge.entity.ts @@ -2,6 +2,9 @@ import { Entity, PrimaryGeneratedColumn, ManyToOne, Column, VersionColumn } from import { User } from '../../users/entities/user.entity'; import { Challenge } from './challenge.entity'; +/** + * Represents the user Challenge entity. + */ @Entity('user_challenges') export class UserChallenge { @PrimaryGeneratedColumn('uuid') diff --git a/src/gamification/entities/user-progress.entity.ts b/src/gamification/entities/user-progress.entity.ts index 50ad15cc..f54e9a13 100644 --- a/src/gamification/entities/user-progress.entity.ts +++ b/src/gamification/entities/user-progress.entity.ts @@ -9,6 +9,9 @@ import { } from 'typeorm'; import { User } from '../../users/entities/user.entity'; +/** + * Represents the user Progress entity. + */ @Entity('user_progress') export class UserProgress { @PrimaryGeneratedColumn('uuid') diff --git a/src/gamification/gamification.controller.ts b/src/gamification/gamification.controller.ts index b8f8305a..808be5e5 100644 --- a/src/gamification/gamification.controller.ts +++ b/src/gamification/gamification.controller.ts @@ -5,6 +5,9 @@ import { BadgesService } from './badges/badges.service'; import { LeaderboardService } from './leaderboards/leaderboards.service'; import { ChallengesService } from './challenges/challenges.service'; +/** + * Exposes gamification endpoints. + */ @Controller('gamification') export class GamificationController { constructor( @@ -15,26 +18,53 @@ export class GamificationController { private readonly challengesService: ChallengesService, ) {} + /** + * Returns progress. + * @param userId The user identifier. + * @returns The operation result. + */ @Get('progress/:userId') async getProgress(@Param('userId') userId: string) { return this.pointsService.getUserProgress(userId); } + /** + * Returns badges. + * @param userId The user identifier. + * @returns The operation result. + */ @Get('badges/:userId') async getBadges(@Param('userId') userId: string) { return this.badgesService.getUserBadges(userId); } + /** + * Returns challenges. + * @param userId The user identifier. + * @returns The operation result. + */ @Get('challenges/:userId') async getChallenges(@Param('userId') userId: string) { return this.challengesService.getUserChallenges(userId); } + /** + * Returns leaderboard. + * @param limit The maximum number of results. + * @returns The operation result. + */ @Get('leaderboard') async getLeaderboard(@Query('limit') limit?: number) { return this.leaderboardService.getTopPlayers(limit); } + /** + * Records activity. + * @param userId The user identifier. + * @param type The type. + * @param points The points. + * @returns The operation result. + */ @Post('activity/:userId') async recordActivity( @Param('userId') userId: string, diff --git a/src/gamification/gamification.module.ts b/src/gamification/gamification.module.ts index eed57136..4e19788b 100644 --- a/src/gamification/gamification.module.ts +++ b/src/gamification/gamification.module.ts @@ -13,6 +13,9 @@ import { ChallengesService } from './challenges/challenges.service'; import { GamificationService } from './gamification.service'; import { GamificationController } from './gamification.controller'; +/** + * Registers the gamification module. + */ @Module({ imports: [ TypeOrmModule.forFeature([ diff --git a/src/gamification/gamification.service.ts b/src/gamification/gamification.service.ts index a712bf38..f12bbd73 100644 --- a/src/gamification/gamification.service.ts +++ b/src/gamification/gamification.service.ts @@ -3,6 +3,9 @@ import { PointsService } from './points/points.service'; import { BadgesService } from './badges/badges.service'; import { ChallengesService } from './challenges/challenges.service'; +/** + * Provides gamification operations. + */ @Injectable() export class GamificationService { constructor( diff --git a/src/gamification/leaderboards/leaderboards.service.ts b/src/gamification/leaderboards/leaderboards.service.ts index 26d3c755..a42e11d1 100644 --- a/src/gamification/leaderboards/leaderboards.service.ts +++ b/src/gamification/leaderboards/leaderboards.service.ts @@ -3,6 +3,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { UserProgress } from '../entities/user-progress.entity'; +/** + * Provides leaderboard operations. + */ @Injectable() export class LeaderboardService { constructor( diff --git a/src/gamification/points/points.service.ts b/src/gamification/points/points.service.ts index c3816e22..e7199eec 100644 --- a/src/gamification/points/points.service.ts +++ b/src/gamification/points/points.service.ts @@ -5,6 +5,9 @@ import { UserProgress } from '../entities/user-progress.entity'; import { PointTransaction } from '../entities/point-transaction.entity'; import { User } from '../../users/entities/user.entity'; +/** + * Provides points operations. + */ @Injectable() export class PointsService { constructor( diff --git a/src/gateways/messaging/messaging.gateway.ts b/src/gateways/messaging/messaging.gateway.ts index 5f27911b..d72db0ba 100644 --- a/src/gateways/messaging/messaging.gateway.ts +++ b/src/gateways/messaging/messaging.gateway.ts @@ -14,6 +14,9 @@ import { wsManager } from '../../common/utils/websocket.utils'; import { JwtService } from '@nestjs/jwt'; import { MESSAGING_GATEWAY_EVENTS } from '../../collaboration/constants/collaboration-events.constants'; +/** + * Handles messaging gateway events. + */ @WebSocketGateway({ namespace: '/messaging' }) @UseGuards(WsThrottlerGuard) export class MessagingGateway implements OnGatewayConnection, OnGatewayDisconnect { @@ -21,6 +24,11 @@ export class MessagingGateway implements OnGatewayConnection, OnGatewayDisconnec constructor(private readonly jwtService: JwtService) {} + /** + * Handles connection. + * @param client The client. + * @returns The operation result. + */ async handleConnection(client: Socket) { try { const token = @@ -43,11 +51,22 @@ export class MessagingGateway implements OnGatewayConnection, OnGatewayDisconnec } } + /** + * Handles disconnect. + * @param client The client. + * @returns The operation result. + */ handleDisconnect(client: Socket) { wsManager.cleanupSocket(client); this.logger.log(`Client disconnected: ${client.id}`); } + /** + * Handles message. + * @param data The data to process. + * @param client The client. + * @returns The operation result. + */ @UseGuards(WsJwtAuthGuard) @SubscribeMessage(MESSAGING_GATEWAY_EVENTS.SEND_MESSAGE) async handleMessage(@MessageBody() data: any, @ConnectedSocket() client: Socket) { diff --git a/src/graphql/graphql.module.ts b/src/graphql/graphql.module.ts index 06309ed9..0a80f58e 100644 --- a/src/graphql/graphql.module.ts +++ b/src/graphql/graphql.module.ts @@ -20,6 +20,9 @@ import { SchemaLintService } from './services/schema-lint.service'; import { DirectiveValidationService } from './services/directive-validation.service'; import { ComplexityAnalysisService } from './services/complexity-analysis.service'; +/** + * Registers the graph QL module. + */ @Module({ imports: [ NestGraphQLModule.forRootAsync({ diff --git a/src/graphql/inputs/assessment.input.ts b/src/graphql/inputs/assessment.input.ts index a8d0964d..5de478a2 100644 --- a/src/graphql/inputs/assessment.input.ts +++ b/src/graphql/inputs/assessment.input.ts @@ -1,6 +1,9 @@ import { InputType, Field, Int } from '@nestjs/graphql'; import { IsString, IsNumber, IsOptional, IsArray, Min } from 'class-validator'; +/** + * Provides question Input behavior. + */ @InputType() export class QuestionInput { @Field() @@ -27,6 +30,9 @@ export class QuestionInput { points: number; } +/** + * Provides create Assessment Input behavior. + */ @InputType() export class CreateAssessmentInput { @Field() @@ -48,6 +54,9 @@ export class CreateAssessmentInput { questions: QuestionInput[]; } +/** + * Provides update Assessment Input behavior. + */ @InputType() export class UpdateAssessmentInput { @Field({ nullable: true }) diff --git a/src/graphql/inputs/course.input.ts b/src/graphql/inputs/course.input.ts index bc49b37c..b0808b75 100644 --- a/src/graphql/inputs/course.input.ts +++ b/src/graphql/inputs/course.input.ts @@ -1,6 +1,9 @@ import { InputType, Field, Float } from '@nestjs/graphql'; import { IsString, IsNumber, IsOptional, Min } from 'class-validator'; +/** + * Provides create Course Input behavior. + */ @InputType() export class CreateCourseInput { @Field() @@ -26,6 +29,9 @@ export class CreateCourseInput { instructorId: string; } +/** + * Provides update Course Input behavior. + */ @InputType() export class UpdateCourseInput { @Field({ nullable: true }) @@ -55,6 +61,9 @@ export class UpdateCourseInput { thumbnailUrl?: string; } +/** + * Provides course Filter Input behavior. + */ @InputType() export class CourseFilterInput { @Field({ nullable: true }) diff --git a/src/graphql/inputs/user.input.ts b/src/graphql/inputs/user.input.ts index c6bdf1bd..974d0015 100644 --- a/src/graphql/inputs/user.input.ts +++ b/src/graphql/inputs/user.input.ts @@ -2,6 +2,9 @@ import { InputType, Field } from '@nestjs/graphql'; import { IsEmail, IsString, MinLength, IsOptional, IsEnum } from 'class-validator'; import { UserRole, UserStatus } from '../../users/entities/user.entity'; +/** + * Provides create User Input behavior. + */ @InputType() export class CreateUserInput { @Field() @@ -32,6 +35,9 @@ export class CreateUserInput { role?: UserRole; } +/** + * Provides update User Input behavior. + */ @InputType() export class UpdateUserInput { @Field({ nullable: true }) @@ -60,6 +66,9 @@ export class UpdateUserInput { status?: UserStatus; } +/** + * Provides user Filter Input behavior. + */ @InputType() export class UserFilterInput { @Field({ nullable: true }) diff --git a/src/graphql/middleware/dataloader.middleware.ts b/src/graphql/middleware/dataloader.middleware.ts index 58cc027e..4bfce3be 100644 --- a/src/graphql/middleware/dataloader.middleware.ts +++ b/src/graphql/middleware/dataloader.middleware.ts @@ -10,6 +10,13 @@ import { DataLoaderService } from '../services/dataloader.service'; export class DataLoaderMiddleware implements NestMiddleware { constructor(private readonly dataLoaderService: DataLoaderService) {} + /** + * Executes use. + * @param req The req. + * @param res The res. + * @param next The next. + * @returns The operation result. + */ use(req: Request, res: Response, next: NextFunction) { // Attach loaders to request object for GraphQL context (req as any).loaders = this.dataLoaderService.createLoaders(); diff --git a/src/graphql/resolvers/assessment.resolver.ts b/src/graphql/resolvers/assessment.resolver.ts index 58877133..1ce428d4 100644 --- a/src/graphql/resolvers/assessment.resolver.ts +++ b/src/graphql/resolvers/assessment.resolver.ts @@ -7,6 +7,11 @@ import { AssessmentType, QuestionType } from '../types/assessment.type'; */ @Resolver(() => AssessmentType) export class AssessmentResolver { + /** + * Executes questions. + * @param assessment The assessment. + * @returns The matching results. + */ @ResolveField(() => [QuestionType]) async questions(@Parent() assessment: AssessmentType): Promise { // Questions are typically loaded with the assessment diff --git a/src/graphql/resolvers/course.resolver.ts b/src/graphql/resolvers/course.resolver.ts index f1ab6a65..64019381 100644 --- a/src/graphql/resolvers/course.resolver.ts +++ b/src/graphql/resolvers/course.resolver.ts @@ -11,6 +11,12 @@ import { UsersService } from '../../users/users.service'; export class CourseResolver { constructor(private readonly usersService: UsersService) {} + /** + * Executes instructor. + * @param course The course. + * @param context The context. + * @returns The operation result. + */ @ResolveField(() => UserType, { nullable: true }) async instructor( @Parent() course: CourseType, diff --git a/src/graphql/resolvers/mutation.resolver.ts b/src/graphql/resolvers/mutation.resolver.ts index c99fa1be..2e095276 100644 --- a/src/graphql/resolvers/mutation.resolver.ts +++ b/src/graphql/resolvers/mutation.resolver.ts @@ -26,6 +26,11 @@ export class MutationResolver { ) {} // User Mutations + /** + * Creates user. + * @param input The input. + * @returns The resulting user type. + */ @Mutation(() => UserType) async createUser(@Args('input') input: CreateUserInput): Promise { const user = await this.usersService.create(input); @@ -33,6 +38,12 @@ export class MutationResolver { return user; } + /** + * Updates user. + * @param id The identifier. + * @param input The input. + * @returns The resulting user type. + */ @Mutation(() => UserType) @UseGuards(JwtAuthGuard) async updateUser( @@ -44,6 +55,11 @@ export class MutationResolver { return user; } + /** + * Removes user. + * @param id The identifier. + * @returns Whether the operation succeeded. + */ @Mutation(() => Boolean) @UseGuards(JwtAuthGuard) async deleteUser(@Args('id', { type: () => ID }) id: string): Promise { @@ -53,6 +69,11 @@ export class MutationResolver { } // Course Mutations + /** + * Creates course. + * @param input The input. + * @returns The resulting course type. + */ @Mutation(() => CourseType) @UseGuards(JwtAuthGuard) async createCourse(@Args('input') input: CreateCourseInput): Promise { @@ -61,6 +82,12 @@ export class MutationResolver { return course; } + /** + * Updates course. + * @param id The identifier. + * @param input The input. + * @returns The resulting course type. + */ @Mutation(() => CourseType) @UseGuards(JwtAuthGuard) async updateCourse( @@ -72,6 +99,11 @@ export class MutationResolver { return course; } + /** + * Removes course. + * @param id The identifier. + * @returns Whether the operation succeeded. + */ @Mutation(() => Boolean) @UseGuards(JwtAuthGuard) async deleteCourse(@Args('id', { type: () => ID }) id: string): Promise { @@ -81,6 +113,11 @@ export class MutationResolver { } // Assessment Mutations + /** + * Creates assessment. + * @param input The input. + * @returns The resulting assessment type. + */ @Mutation(() => AssessmentType) @UseGuards(JwtAuthGuard) async createAssessment(@Args('input') input: CreateAssessmentInput): Promise { @@ -91,6 +128,12 @@ export class MutationResolver { return assessment; } + /** + * Updates assessment. + * @param id The identifier. + * @param input The input. + * @returns The resulting assessment type. + */ @Mutation(() => AssessmentType) @UseGuards(JwtAuthGuard) async updateAssessment( @@ -104,6 +147,11 @@ export class MutationResolver { return assessment; } + /** + * Removes assessment. + * @param id The identifier. + * @returns Whether the operation succeeded. + */ @Mutation(() => Boolean) @UseGuards(JwtAuthGuard) async deleteAssessment(@Args('id', { type: () => ID }) id: string): Promise { diff --git a/src/graphql/resolvers/query.resolver.ts b/src/graphql/resolvers/query.resolver.ts index 9548f724..63a528f2 100644 --- a/src/graphql/resolvers/query.resolver.ts +++ b/src/graphql/resolvers/query.resolver.ts @@ -24,6 +24,12 @@ export class QueryResolver { ) {} // User Queries + /** + * Executes user. + * @param id The identifier. + * @param context The context. + * @returns The resulting user type. + */ @Query(() => UserType, { nullable: true }) @UseGuards(JwtAuthGuard) async user( @@ -37,6 +43,11 @@ export class QueryResolver { return this.usersService.findOne(id); } + /** + * Executes users. + * @param filter The filter criteria. + * @returns The resulting paginated response. + */ @Query(() => [UserType]) @UseGuards(JwtAuthGuard) async users( @@ -46,6 +57,11 @@ export class QueryResolver { return this.usersService.findAll(filter); } + /** + * Executes me. + * @param context The context. + * @returns The resulting user type. + */ @Query(() => UserType) @UseGuards(JwtAuthGuard) async me(@Context() context: any): Promise { @@ -57,6 +73,12 @@ export class QueryResolver { } // Course Queries + /** + * Executes course. + * @param id The identifier. + * @param context The context. + * @returns The resulting course type. + */ @Query(() => CourseType, { nullable: true }) async course( @Args('id', { type: () => ID }) id: string, @@ -69,6 +91,11 @@ export class QueryResolver { return this.coursesService.findOne(id); } + /** + * Executes courses. + * @param filter The filter criteria. + * @returns The resulting paginated response. + */ @Query(() => [CourseType]) async courses( @Args('filter', { type: () => CourseFilterInput, nullable: true }) @@ -77,6 +104,11 @@ export class QueryResolver { return this.coursesService.findAll(filter); } + /** + * Executes my Courses. + * @param context The context. + * @returns The matching results. + */ @Query(() => [CourseType]) @UseGuards(JwtAuthGuard) async myCourses(@Context() context: any): Promise { @@ -88,6 +120,12 @@ export class QueryResolver { } // Assessment Queries + /** + * Executes assessment. + * @param id The identifier. + * @param context The context. + * @returns The resulting assessment type. + */ @Query(() => AssessmentType, { nullable: true }) @UseGuards(JwtAuthGuard) async assessment( @@ -101,6 +139,10 @@ export class QueryResolver { return this.assessmentsService.findOne(id); } + /** + * Executes assessments. + * @returns The matching results. + */ @Query(() => [AssessmentType]) @UseGuards(JwtAuthGuard) async assessments(): Promise { diff --git a/src/graphql/resolvers/subscription.resolver.ts b/src/graphql/resolvers/subscription.resolver.ts index d6ff2cf4..3a9fb0fe 100644 --- a/src/graphql/resolvers/subscription.resolver.ts +++ b/src/graphql/resolvers/subscription.resolver.ts @@ -14,6 +14,10 @@ export class SubscriptionResolver { constructor(@Inject('PUB_SUB') private readonly pubSub: PubSub) {} // User Subscriptions + /** + * Executes user Created. + * @returns The operation result. + */ @Subscription(() => UserType, { name: 'userCreated', description: 'Subscribe to new user creation events', @@ -22,6 +26,10 @@ export class SubscriptionResolver { return this.pubSub.asyncIterableIterator('userCreated'); } + /** + * Executes user Updated. + * @returns The operation result. + */ @Subscription(() => UserType, { name: 'userUpdated', description: 'Subscribe to user update events', @@ -30,6 +38,10 @@ export class SubscriptionResolver { return this.pubSub.asyncIterableIterator('userUpdated'); } + /** + * Executes user Deleted. + * @returns The operation result. + */ @Subscription(() => UserType, { name: 'userDeleted', description: 'Subscribe to user deletion events', @@ -39,6 +51,10 @@ export class SubscriptionResolver { } // Course Subscriptions + /** + * Executes course Created. + * @returns The operation result. + */ @Subscription(() => CourseType, { name: 'courseCreated', description: 'Subscribe to new course creation events', @@ -47,6 +63,10 @@ export class SubscriptionResolver { return this.pubSub.asyncIterableIterator('courseCreated'); } + /** + * Executes course Updated. + * @returns The operation result. + */ @Subscription(() => CourseType, { name: 'courseUpdated', description: 'Subscribe to course update events', @@ -55,6 +75,10 @@ export class SubscriptionResolver { return this.pubSub.asyncIterableIterator('courseUpdated'); } + /** + * Executes course Deleted. + * @returns The operation result. + */ @Subscription(() => CourseType, { name: 'courseDeleted', description: 'Subscribe to course deletion events', @@ -64,6 +88,10 @@ export class SubscriptionResolver { } // Assessment Subscriptions + /** + * Executes assessment Created. + * @returns The operation result. + */ @Subscription(() => AssessmentType, { name: 'assessmentCreated', description: 'Subscribe to new assessment creation events', @@ -72,6 +100,10 @@ export class SubscriptionResolver { return this.pubSub.asyncIterableIterator('assessmentCreated'); } + /** + * Executes assessment Updated. + * @returns The operation result. + */ @Subscription(() => AssessmentType, { name: 'assessmentUpdated', description: 'Subscribe to assessment update events', @@ -80,6 +112,10 @@ export class SubscriptionResolver { return this.pubSub.asyncIterableIterator('assessmentUpdated'); } + /** + * Executes assessment Deleted. + * @returns The operation result. + */ @Subscription(() => AssessmentType, { name: 'assessmentDeleted', description: 'Subscribe to assessment deletion events', diff --git a/src/graphql/resolvers/user.resolver.ts b/src/graphql/resolvers/user.resolver.ts index b588a0d0..7399818f 100644 --- a/src/graphql/resolvers/user.resolver.ts +++ b/src/graphql/resolvers/user.resolver.ts @@ -11,6 +11,12 @@ import { CoursesService } from '../../courses/courses.service'; export class UserResolver { constructor(private readonly coursesService: CoursesService) {} + /** + * Executes courses. + * @param user The user. + * @param context The context. + * @returns The matching results. + */ @ResolveField(() => [CourseType]) async courses(@Parent() user: UserType, @Context() context: any): Promise { const { coursesByInstructorLoader } = context.loaders || {}; diff --git a/src/graphql/types/assessment.type.ts b/src/graphql/types/assessment.type.ts index 8d43d3e5..d3c2a232 100644 --- a/src/graphql/types/assessment.type.ts +++ b/src/graphql/types/assessment.type.ts @@ -1,5 +1,8 @@ import { ObjectType, Field, ID, Int } from '@nestjs/graphql'; +/** + * Provides question Type behavior. + */ @ObjectType() export class QuestionType { @Field(() => ID) @@ -21,6 +24,9 @@ export class QuestionType { points: number; } +/** + * Provides assessment Type behavior. + */ @ObjectType() export class AssessmentType { @Field(() => ID) diff --git a/src/graphql/types/course.type.ts b/src/graphql/types/course.type.ts index 153ab5c6..3e4a9153 100644 --- a/src/graphql/types/course.type.ts +++ b/src/graphql/types/course.type.ts @@ -1,6 +1,9 @@ import { ObjectType, Field, ID, Float } from '@nestjs/graphql'; import { UserType } from './user.type'; +/** + * Provides course Type behavior. + */ @ObjectType() export class CourseType { @Field(() => ID) diff --git a/src/graphql/types/user.type.ts b/src/graphql/types/user.type.ts index 9b98792e..95c05618 100644 --- a/src/graphql/types/user.type.ts +++ b/src/graphql/types/user.type.ts @@ -12,6 +12,9 @@ registerEnumType(UserStatus, { description: 'User account status', }); +/** + * Provides user Type behavior. + */ @ObjectType() export class UserType { @Field(() => ID) diff --git a/src/health/health.controller.ts b/src/health/health.controller.ts index efa517ca..2998bb68 100644 --- a/src/health/health.controller.ts +++ b/src/health/health.controller.ts @@ -52,6 +52,10 @@ export class HealthController implements OnModuleDestroy { return healthStatus; } + /** + * Validates liveness. + * @returns The operation result. + */ @Get('liveness') @ApiResponse({ status: HttpStatus.OK, description: 'Liveness check response' }) @ApiResponse({ @@ -72,6 +76,10 @@ export class HealthController implements OnModuleDestroy { }); } + /** + * Validates readiness. + * @returns The operation result. + */ @Get('readiness') @ApiResponse({ status: HttpStatus.OK, @@ -93,6 +101,11 @@ export class HealthController implements OnModuleDestroy { return res.status(HttpStatus.OK).json(healthStatus); } + /** + * Validates dependencies. + * @param service The service. + * @returns The operation result. + */ @Get('dependencies') async checkDependencies(@Query('service') service?: string) { const healthStatus = await this.healthService.checkHealth(this.dataSource, this.redis); @@ -114,6 +127,10 @@ export class HealthController implements OnModuleDestroy { }; } + /** + * Validates database. + * @returns The operation result. + */ @Get('database') async checkDatabase() { const healthStatus = await this.healthService.checkHealth(this.dataSource, this.redis); @@ -125,6 +142,10 @@ export class HealthController implements OnModuleDestroy { }; } + /** + * Validates redis. + * @returns The operation result. + */ @Get('redis') async checkRedis() { const healthStatus = await this.healthService.checkHealth(this.dataSource, this.redis); @@ -136,6 +157,10 @@ export class HealthController implements OnModuleDestroy { }; } + /** + * Validates queue. + * @returns The operation result. + */ @Get('queue') async checkQueue() { const healthStatus = await this.healthService.checkHealth(this.dataSource, this.redis); @@ -147,6 +172,10 @@ export class HealthController implements OnModuleDestroy { }; } + /** + * Validates cache. + * @returns The operation result. + */ @Get('cache') async checkCache() { const healthStatus = await this.healthService.checkHealth(this.dataSource, this.redis); @@ -158,6 +187,10 @@ export class HealthController implements OnModuleDestroy { }; } + /** + * Returns health Summary. + * @returns The operation result. + */ @Get('summary') async getHealthSummary() { const healthStatus = await this.healthService.checkHealth(this.dataSource, this.redis); diff --git a/src/health/health.module.ts b/src/health/health.module.ts index a38cb2c8..e67cc294 100644 --- a/src/health/health.module.ts +++ b/src/health/health.module.ts @@ -2,6 +2,9 @@ import { Module } from '@nestjs/common'; import { HealthController } from './health.controller'; import { HealthService } from './health.service'; +/** + * Registers the health module. + */ @Module({ controllers: [HealthController], providers: [HealthService], diff --git a/src/health/health.service.ts b/src/health/health.service.ts index 7bc0929c..94dad592 100644 --- a/src/health/health.service.ts +++ b/src/health/health.service.ts @@ -66,6 +66,9 @@ export interface IHealthStatus { }; } +/** + * Provides health operations. + */ @Injectable() export class HealthService { private readonly logger = new Logger(HealthService.name); diff --git a/src/learning-paths/learning-paths.controller.ts b/src/learning-paths/learning-paths.controller.ts index 4467c4f5..d34b7a5d 100644 --- a/src/learning-paths/learning-paths.controller.ts +++ b/src/learning-paths/learning-paths.controller.ts @@ -1,10 +1,18 @@ import { Controller, Post, Body } from '@nestjs/common'; import { LearningPathsService } from './learning-paths.service'; +/** + * Exposes learning Paths endpoints. + */ @Controller('learning-paths') export class LearningPathsController { constructor(private readonly learningPathsService: LearningPathsService) {} + /** + * Generates learning Path. + * @param payload The payload to process. + * @returns The operation result. + */ @Post('generate') generateLearningPath(@Body() payload: any) { return this.learningPathsService.generateLearningPath(payload); diff --git a/src/learning-paths/learning-paths.module.ts b/src/learning-paths/learning-paths.module.ts index e28653ba..20f6692b 100644 --- a/src/learning-paths/learning-paths.module.ts +++ b/src/learning-paths/learning-paths.module.ts @@ -5,6 +5,9 @@ import { SkillAssessmentService } from './services/skill-assessment.service'; import { PathGenerationService } from './services/path-generation.service'; import { MilestoneTrackingService } from './services/milestone-tracking.service'; +/** + * Registers the learning Paths module. + */ @Module({ controllers: [LearningPathsController], providers: [ diff --git a/src/learning-paths/learning-paths.service.ts b/src/learning-paths/learning-paths.service.ts index ffef2d72..b1d2e4cc 100644 --- a/src/learning-paths/learning-paths.service.ts +++ b/src/learning-paths/learning-paths.service.ts @@ -3,6 +3,9 @@ import { SkillAssessmentService } from './services/skill-assessment.service'; import { PathGenerationService } from './services/path-generation.service'; import { MilestoneTrackingService } from './services/milestone-tracking.service'; +/** + * Provides learning Paths operations. + */ @Injectable() export class LearningPathsService { constructor( @@ -11,6 +14,11 @@ export class LearningPathsService { private readonly milestoneTrackingService: MilestoneTrackingService, ) {} + /** + * Generates learning Path. + * @param input The input. + * @returns The operation result. + */ generateLearningPath(input: any) { const assessment = this.skillAssessmentService.assess(input); const path = this.pathGenerationService.generate(assessment); diff --git a/src/learning-paths/services/milestone-tracking.service.ts b/src/learning-paths/services/milestone-tracking.service.ts index aa01432d..dfd36eeb 100644 --- a/src/learning-paths/services/milestone-tracking.service.ts +++ b/src/learning-paths/services/milestone-tracking.service.ts @@ -1,7 +1,15 @@ import { Injectable } from '@nestjs/common'; +/** + * Provides milestone Tracking operations. + */ @Injectable() export class MilestoneTrackingService { + /** + * Executes initialize. + * @param path The path. + * @returns The operation result. + */ initialize(path: any) { return { ...path, diff --git a/src/learning-paths/services/path-generation.service.ts b/src/learning-paths/services/path-generation.service.ts index 9384dca3..96dcb290 100644 --- a/src/learning-paths/services/path-generation.service.ts +++ b/src/learning-paths/services/path-generation.service.ts @@ -1,7 +1,15 @@ import { Injectable } from '@nestjs/common'; +/** + * Provides path Generation operations. + */ @Injectable() export class PathGenerationService { + /** + * Generates generate. + * @param assessment The assessment. + * @returns The operation result. + */ generate(assessment: { level: string; goal: string }) { const milestones = []; diff --git a/src/learning-paths/services/skill-assessment.service.ts b/src/learning-paths/services/skill-assessment.service.ts index 93f79c29..10b0feb1 100644 --- a/src/learning-paths/services/skill-assessment.service.ts +++ b/src/learning-paths/services/skill-assessment.service.ts @@ -1,7 +1,15 @@ import { Injectable } from '@nestjs/common'; +/** + * Provides skill Assessment operations. + */ @Injectable() export class SkillAssessmentService { + /** + * Executes assess. + * @param input The input. + * @returns The operation result. + */ assess(input: any) { return { level: input?.level ?? 'beginner', diff --git a/src/localization/dto/bundle-query.dto.ts b/src/localization/dto/bundle-query.dto.ts index c74cc259..3f403ff7 100644 --- a/src/localization/dto/bundle-query.dto.ts +++ b/src/localization/dto/bundle-query.dto.ts @@ -1,6 +1,9 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator'; +/** + * Defines the bundle Query payload. + */ export class BundleQueryDto { @ApiProperty({ example: 'errors' }) @IsString() diff --git a/src/localization/dto/create-translation.dto.ts b/src/localization/dto/create-translation.dto.ts index 36cc28b0..05d56b94 100644 --- a/src/localization/dto/create-translation.dto.ts +++ b/src/localization/dto/create-translation.dto.ts @@ -1,6 +1,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsNotEmpty, IsString, MaxLength } from 'class-validator'; +/** + * Defines the create Translation payload. + */ export class CreateTranslationDto { @ApiProperty({ example: 'errors' }) @IsString() diff --git a/src/localization/dto/export-query.dto.ts b/src/localization/dto/export-query.dto.ts index 6067cf4f..86f5451e 100644 --- a/src/localization/dto/export-query.dto.ts +++ b/src/localization/dto/export-query.dto.ts @@ -1,6 +1,9 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsIn, IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator'; +/** + * Defines the export Query payload. + */ export class ExportQueryDto { @ApiProperty({ example: 'errors' }) @IsString() diff --git a/src/localization/dto/import-translations.dto.ts b/src/localization/dto/import-translations.dto.ts index ca39c269..cab78610 100644 --- a/src/localization/dto/import-translations.dto.ts +++ b/src/localization/dto/import-translations.dto.ts @@ -9,6 +9,9 @@ import { ValidateNested, } from 'class-validator'; +/** + * Defines the translation Import Row payload. + */ export class TranslationImportRowDto { @ApiProperty({ example: 'errors' }) @IsString() diff --git a/src/localization/dto/list-translations-query.dto.ts b/src/localization/dto/list-translations-query.dto.ts index d22205d9..f2d1eb59 100644 --- a/src/localization/dto/list-translations-query.dto.ts +++ b/src/localization/dto/list-translations-query.dto.ts @@ -2,6 +2,9 @@ import { ApiPropertyOptional } from '@nestjs/swagger'; import { Type } from 'class-transformer'; import { IsInt, IsOptional, IsString, Max, MaxLength, Min } from 'class-validator'; +/** + * Defines the list Translations Query payload. + */ export class ListTranslationsQueryDto { @ApiPropertyOptional({ example: 'errors' }) @IsOptional() diff --git a/src/localization/dto/update-translation.dto.ts b/src/localization/dto/update-translation.dto.ts index c78caa78..8c440fb6 100644 --- a/src/localization/dto/update-translation.dto.ts +++ b/src/localization/dto/update-translation.dto.ts @@ -1,6 +1,9 @@ import { ApiPropertyOptional } from '@nestjs/swagger'; import { IsOptional, IsString, MaxLength } from 'class-validator'; +/** + * Defines the update Translation payload. + */ export class UpdateTranslationDto { @ApiPropertyOptional({ example: 'errors' }) @IsOptional() diff --git a/src/localization/entities/translation.entity.ts b/src/localization/entities/translation.entity.ts index b6a1184e..fab62348 100644 --- a/src/localization/entities/translation.entity.ts +++ b/src/localization/entities/translation.entity.ts @@ -10,6 +10,9 @@ import { VersionColumn, } from 'typeorm'; +/** + * Represents the translation entity. + */ @Entity('translations') @Unique(['namespace', 'translationKey', 'locale']) @Index('IDX_translations_namespace_locale', ['namespace', 'locale']) diff --git a/src/localization/language-detection.service.ts b/src/localization/language-detection.service.ts index d9473c52..a554852c 100644 --- a/src/localization/language-detection.service.ts +++ b/src/localization/language-detection.service.ts @@ -9,14 +9,25 @@ export interface IResolvedLocale { source: LocaleResolutionSource; } +/** + * Provides language Detection operations. + */ @Injectable() export class LanguageDetectionService { constructor(private readonly configService: ConfigService) {} + /** + * Retrieves default Locale. + * @returns The resulting string value. + */ getDefaultLocale(): string { return this.configService.get('I18N_DEFAULT_LOCALE')?.trim().toLowerCase() || 'en'; } + /** + * Retrieves supported Locales. + * @returns The matching results. + */ getSupportedLocales(): string[] { const raw = this.configService.get('I18N_SUPPORTED_LOCALES') || @@ -28,6 +39,11 @@ export class LanguageDetectionService { .filter(Boolean); } + /** + * Executes normalize Locale Tag. + * @param tag The tag. + * @returns The resulting string value. + */ normalizeLocaleTag(tag: string): string { if (!tag) return ''; return tag.trim().toLowerCase().replace(/_/g, '-'); @@ -70,6 +86,12 @@ export class LanguageDetectionService { return { locale: defaultLocale, source: 'default' }; } + /** + * Resolves locale. + * @param req The req. + * @param queryLang The query value. + * @returns The resulting string value. + */ resolveLocale(req: Request, queryLang?: string): string { return this.resolveWithSource(req, queryLang).locale; } diff --git a/src/localization/language.middleware.ts b/src/localization/language.middleware.ts index cefa5972..cde40850 100644 --- a/src/localization/language.middleware.ts +++ b/src/localization/language.middleware.ts @@ -3,10 +3,19 @@ import { NextFunction, Response } from 'express'; import { RequestWithLocale } from '../common/types/request-with-locale'; import { LanguageDetectionService } from './language-detection.service'; +/** + * Applies language middleware behavior. + */ @Injectable() export class LanguageMiddleware implements NestMiddleware { constructor(private readonly languageDetection: LanguageDetectionService) {} + /** + * Executes use. + * @param req The req. + * @param _res The res. + * @param next The next. + */ use(req: RequestWithLocale, _res: Response, next: NextFunction): void { const raw = req.query?.lang; const queryLang = diff --git a/src/localization/localization.constants.ts b/src/localization/localization.constants.ts index 8bc56c40..f69b3b56 100644 --- a/src/localization/localization.constants.ts +++ b/src/localization/localization.constants.ts @@ -1,5 +1,11 @@ export const I18N_CACHE_KEY_PREFIX = 'i18n:ns:'; +/** + * Executes bundle Cache Key. + * @param namespace The namespace. + * @param locale The locale. + * @returns The resulting string value. + */ export function bundleCacheKey(namespace: string, locale: string): string { return `${I18N_CACHE_KEY_PREFIX}${namespace}:${locale}`; } diff --git a/src/localization/localization.controller.ts b/src/localization/localization.controller.ts index 7455ce06..1f836f71 100644 --- a/src/localization/localization.controller.ts +++ b/src/localization/localization.controller.ts @@ -28,6 +28,9 @@ import { UpdateTranslationDto } from './dto/update-translation.dto'; import { LanguageDetectionService } from './language-detection.service'; import { LocalizationService } from './localization.service'; +/** + * Exposes localization endpoints. + */ @ApiTags('localization') @Controller('localization') export class LocalizationController { @@ -36,6 +39,12 @@ export class LocalizationController { private readonly languageDetection: LanguageDetectionService, ) {} + /** + * Returns bundle. + * @param query The query value. + * @param req The req. + * @returns The operation result. + */ @Get('bundle') @ApiOperation({ summary: 'Get merged translation bundle for a namespace' }) async getBundle(@Query() query: BundleQueryDto, @Req() req: RequestWithLocale) { @@ -44,6 +53,12 @@ export class LocalizationController { return this.localizationService.getBundleForApi(query.namespace, locale); } + /** + * Executes detect. + * @param req The req. + * @param lang The lang. + * @returns The operation result. + */ @Get('detect') @ApiOperation({ summary: 'Show how the request locale was resolved' }) @ApiQuery({ name: 'lang', required: false }) @@ -51,6 +66,11 @@ export class LocalizationController { return this.languageDetection.resolveWithSource(req, lang); } + /** + * Returns admin. + * @param query The query value. + * @returns The operation result. + */ @Get('admin/translations') @UseGuards(JwtAuthGuard, RolesGuard) @Roles(UserRole.ADMIN) @@ -60,6 +80,11 @@ export class LocalizationController { return this.localizationService.findAll(query); } + /** + * Returns one. + * @param id The identifier. + * @returns The operation result. + */ @Get('admin/translations/:id') @UseGuards(JwtAuthGuard, RolesGuard) @Roles(UserRole.ADMIN) @@ -69,6 +94,11 @@ export class LocalizationController { return this.localizationService.findOne(id); } + /** + * Creates a new record. + * @param dto The dto. + * @returns The operation result. + */ @Post('admin/translations') @UseGuards(JwtAuthGuard, RolesGuard) @Roles(UserRole.ADMIN) @@ -78,6 +108,12 @@ export class LocalizationController { return this.localizationService.create(dto); } + /** + * Updates the requested record. + * @param id The identifier. + * @param dto The dto. + * @returns The operation result. + */ @Patch('admin/translations/:id') @UseGuards(JwtAuthGuard, RolesGuard) @Roles(UserRole.ADMIN) @@ -87,6 +123,11 @@ export class LocalizationController { return this.localizationService.update(id, dto); } + /** + * Removes the requested record. + * @param id The identifier. + * @returns The operation result. + */ @Delete('admin/translations/:id') @UseGuards(JwtAuthGuard, RolesGuard) @Roles(UserRole.ADMIN) @@ -97,6 +138,11 @@ export class LocalizationController { return { deleted: true }; } + /** + * Imports import. + * @param body The body. + * @returns The operation result. + */ @Post('admin/import') @UseGuards(JwtAuthGuard, RolesGuard) @Roles(UserRole.ADMIN) @@ -110,6 +156,12 @@ export class LocalizationController { return this.localizationService.importRows(rows); } + /** + * Exports export. + * @param query The query value. + * @param res The res. + * @returns The operation result. + */ @Get('admin/export') @UseGuards(JwtAuthGuard, RolesGuard) @Roles(UserRole.ADMIN) diff --git a/src/localization/localization.module.ts b/src/localization/localization.module.ts index bc27f392..877e3ca9 100644 --- a/src/localization/localization.module.ts +++ b/src/localization/localization.module.ts @@ -8,6 +8,9 @@ import { LanguageMiddleware } from './language.middleware'; import { LocalizationController } from './localization.controller'; import { LocalizationService } from './localization.service'; +/** + * Registers the localization module. + */ @Module({ imports: [TypeOrmModule.forFeature([Translation])], controllers: [LocalizationController], @@ -21,6 +24,11 @@ import { LocalizationService } from './localization.service'; exports: [LocalizationService, LanguageDetectionService], }) export class LocalizationModule implements NestModule { + /** + * Executes configure. + * @param consumer The consumer. + * @returns The operation result. + */ configure(consumer: MiddlewareConsumer) { consumer.apply(LanguageMiddleware).forRoutes(LocalizationController); } diff --git a/src/localization/localization.service.ts b/src/localization/localization.service.ts index 7434b8cf..e456dc6d 100644 --- a/src/localization/localization.service.ts +++ b/src/localization/localization.service.ts @@ -35,6 +35,9 @@ export interface IPaginatedTranslations { limit: number; } +/** + * Provides localization operations. + */ @Injectable() export class LocalizationService { constructor( @@ -66,6 +69,10 @@ export class LocalizationService { }; } + /** + * Invalidates bundles. + * @param pairs The pairs. + */ async invalidateBundles(pairs: Array<{ namespace: string; locale: string }>): Promise { const seen = new Set(); for (const { namespace, locale } of pairs) { @@ -91,6 +98,12 @@ export class LocalizationService { return map; } + /** + * Retrieves raw Bundle Cached. + * @param namespace The namespace. + * @param locale The locale. + * @returns The resulting record. + */ async getRawBundleCached(namespace: string, locale: string): Promise> { const loc = languageDetectionNormalize(locale); const key = bundleCacheKey(namespace, loc); @@ -106,6 +119,12 @@ export class LocalizationService { return fresh; } + /** + * Retrieves messages Merged. + * @param namespace The namespace. + * @param locale The locale. + * @returns The resulting record. + */ async getMessagesMerged(namespace: string, locale: string): Promise> { const loc = this.languageDetection.pickSupported(locale) || this.getDefaultLocale(); const primary = await this.getRawBundleCached(namespace, loc); @@ -117,6 +136,12 @@ export class LocalizationService { return { ...fallback, ...primary }; } + /** + * Executes interpolate. + * @param template The template. + * @param vars The vars. + * @returns The resulting string value. + */ interpolate(template: string, vars?: Record): string { if (!vars) return template; return template.replace(/\{\{\s*(\w+)\s*\}\}/g, (_, k) => @@ -124,6 +149,14 @@ export class LocalizationService { ); } + /** + * Executes translate. + * @param namespace The namespace. + * @param key The key. + * @param locale The locale. + * @param vars The vars. + * @returns The resulting string value. + */ async translate( namespace: string, key: string, @@ -139,6 +172,12 @@ export class LocalizationService { return this.interpolate(text, vars); } + /** + * Retrieves bundle For Api. + * @param namespace The namespace. + * @param locale The locale. + * @returns The operation result. + */ async getBundleForApi( namespace: string, locale: string, @@ -248,6 +287,10 @@ export class LocalizationService { } } + /** + * Removes the requested record. + * @param id The identifier. + */ async remove(id: string): Promise { const row = await this.translationRepo.findOne({ where: { id } }); if (!row) throw new NotFoundException('Translation not found'); @@ -255,6 +298,11 @@ export class LocalizationService { await this.invalidateBundles([{ namespace: row.namespace, locale: row.locale }]); } + /** + * Imports rows. + * @param rows The rows. + * @returns The operation result. + */ async importRows(rows: TranslationImportRowDto[]): Promise<{ upserted: number }> { if (!rows?.length) { throw new BadRequestException('Import payload must contain at least one row'); @@ -294,6 +342,12 @@ export class LocalizationService { return { upserted: rows.length }; } + /** + * Exports rows. + * @param namespace The namespace. + * @param locale The locale. + * @returns The resulting array<{ namespace: string; key: string; locale: string; value: string }>. + */ async exportRows( namespace: string, locale?: string, @@ -314,6 +368,11 @@ export class LocalizationService { })); } + /** + * Executes to Csv. + * @param rows The rows. + * @returns The resulting string value. + */ static toCsv( rows: Array<{ namespace: string; key: string; locale: string; value: string }>, ): string { diff --git a/src/media/media.controller.ts b/src/media/media.controller.ts index f1e98e69..ab3b3bb8 100644 --- a/src/media/media.controller.ts +++ b/src/media/media.controller.ts @@ -33,6 +33,9 @@ import { } from './validation/upload-validation.util'; import { BulkDeleteMediaDto } from './dto/media.dto'; +/** + * Exposes media endpoints. + */ @ApiTags('Media') @ApiBearerAuth() @Controller('media') @@ -41,6 +44,13 @@ export class MediaController { constructor(private readonly mediaService: MediaService) {} + /** + * Uploads upload. + * @param file The file to process. + * @param req The req. + * @param body The body. + * @returns The operation result. + */ @Post('upload') @Throttle({ default: THROTTLE.MODERATE }) @UseGuards(JwtAuthGuard) @@ -110,6 +120,11 @@ export class MediaController { return result; } + /** + * Returns upload Progress. + * @param uploadId The upload identifier. + * @returns The operation result. + */ @Get('uploads/progress/:uploadId') @UseGuards(JwtAuthGuard) @ApiOperation({ summary: 'Get upload progress by ID' }) @@ -124,6 +139,10 @@ export class MediaController { return progress; } + /** + * Returns active Uploads. + * @returns The operation result. + */ @Get('uploads/active') @UseGuards(JwtAuthGuard) @ApiOperation({ summary: 'List active uploads' }) @@ -132,6 +151,10 @@ export class MediaController { return this.mediaService.listActiveUploads(); } + /** + * Returns upload Statistics. + * @returns The operation result. + */ @Get('uploads/statistics') @UseGuards(JwtAuthGuard) @ApiOperation({ summary: 'Get upload statistics' }) @@ -140,6 +163,12 @@ export class MediaController { return this.mediaService.getUploadStatistics(); } + /** + * Returns metadata. + * @param contentId The content identifier. + * @param req The req. + * @returns The operation result. + */ @Get(':contentId') @UseGuards(JwtAuthGuard) @ApiOperation({ summary: 'Get media metadata by content ID' }) diff --git a/src/media/media.module.ts b/src/media/media.module.ts index 175dc2d9..528391fb 100644 --- a/src/media/media.module.ts +++ b/src/media/media.module.ts @@ -15,6 +15,9 @@ import { ContentMetadata } from '../cdn/entities/content-metadata.entity'; import { VideoProcessor } from './processing/video.processor'; import { FileCleanupTask } from './file-cleanup.task'; +/** + * Registers the media module. + */ @Module({ imports: [ TypeOrmModule.forFeature([ContentMetadata]), diff --git a/src/media/media.service.ts b/src/media/media.service.ts index 92e35008..435126ac 100644 --- a/src/media/media.service.ts +++ b/src/media/media.service.ts @@ -36,6 +36,9 @@ export interface IUploadResult { scanResult?: { clean: boolean; threats: string[] }; } +/** + * Provides media operations. + */ @Injectable() export class MediaService { private readonly logger = new Logger(MediaService.name); @@ -51,6 +54,14 @@ export class MediaService { private readonly uploadProgress: UploadProgressService, ) {} + /** + * Creates from Upload. + * @param ownerId The owner identifier. + * @param tenantId The tenant identifier. + * @param file The file to process. + * @param options The options. + * @returns The resulting upload result. + */ async createFromUpload( ownerId: string, tenantId: string | undefined, diff --git a/src/media/processing/document-processing.service.ts b/src/media/processing/document-processing.service.ts index 2e884a36..78493d6b 100644 --- a/src/media/processing/document-processing.service.ts +++ b/src/media/processing/document-processing.service.ts @@ -5,6 +5,9 @@ import { Repository } from 'typeorm'; import { ContentMetadata } from '../../cdn/entities/content-metadata.entity'; import { FileStorageService } from '../storage/file-storage.service'; +/** + * Provides document Processing operations. + */ @Injectable() export class DocumentProcessingService { private readonly logger = new Logger(DocumentProcessingService.name); @@ -15,6 +18,11 @@ export class DocumentProcessingService { private readonly contentRepo: Repository, ) {} + /** + * Executes parse Pdf From Content. + * @param contentId The content identifier. + * @returns The operation result. + */ async parsePdfFromContent(contentId: string) { const meta = await this.contentRepo.findOne({ where: { contentId } }); if (!meta) return null; diff --git a/src/media/processing/image-processing.service.ts b/src/media/processing/image-processing.service.ts index 7cd2e353..efd74b82 100644 --- a/src/media/processing/image-processing.service.ts +++ b/src/media/processing/image-processing.service.ts @@ -36,6 +36,9 @@ export interface ImageMetadata { channels?: number; } +/** + * Provides image Processing operations. + */ @Injectable() export class ImageProcessingService { private readonly logger = new Logger(ImageProcessingService.name); diff --git a/src/media/processing/video-processing.service.ts b/src/media/processing/video-processing.service.ts index ef3cf2eb..1a67e08b 100644 --- a/src/media/processing/video-processing.service.ts +++ b/src/media/processing/video-processing.service.ts @@ -4,12 +4,20 @@ import { Queue } from 'bull'; import { QUEUE_NAMES, JOB_NAMES } from '../../common/constants/queue.constants'; import { ContentMetadata } from '../../cdn/entities/content-metadata.entity'; +/** + * Provides video Processing operations. + */ @Injectable() export class VideoProcessingService { private readonly logger = new Logger(VideoProcessingService.name); constructor(@InjectQueue(QUEUE_NAMES.MEDIA_PROCESSING) private readonly queue: Queue) {} + /** + * Executes enqueue Transcode. + * @param content The content. + * @returns The operation result. + */ async enqueueTranscode(content: ContentMetadata) { await this.queue.add( JOB_NAMES.TRANSCODE_VIDEO, diff --git a/src/media/processing/video.processor.ts b/src/media/processing/video.processor.ts index 684b230b..a4932b06 100644 --- a/src/media/processing/video.processor.ts +++ b/src/media/processing/video.processor.ts @@ -105,11 +105,23 @@ export class VideoProcessor { return { uploaded }; } + /** + * Executes on Failed. + * @param job The job. + * @param err The err. + * @returns The operation result. + */ @OnQueueFailed() async onFailed(job: Job, err: Error) { this.logger.error(`Job ${job.id} failed: ${err.message}`); } + /** + * Executes on Complete. + * @param job The job. + * @param _result The result. + * @returns The operation result. + */ @OnQueueCompleted() async onComplete(job: Job, _result: any) { this.logger.log(`Job ${job.id} completed`); diff --git a/src/media/storage/file-storage.service.ts b/src/media/storage/file-storage.service.ts index 5b9cf056..513b85b0 100644 --- a/src/media/storage/file-storage.service.ts +++ b/src/media/storage/file-storage.service.ts @@ -10,6 +10,9 @@ import { Readable } from 'stream'; import { ContentMetadata } from '../../cdn/entities/content-metadata.entity'; import { UploadedFile } from '@nestjs/common'; +/** + * Provides file Storage operations. + */ @Injectable() export class FileStorageService { private readonly logger = new Logger(FileStorageService.name); @@ -40,6 +43,12 @@ export class FileStorageService { } // Legacy method for backward compatibility + /** + * Uploads file. + * @param file The file to process. + * @param metadata The data to process. + * @returns The operation result. + */ async uploadFile( file: UploadedFile, metadata: ContentMetadata, @@ -83,6 +92,11 @@ export class FileStorageService { return result.ETag; } + /** + * Downloads file. + * @param storageKey The storage key. + * @returns The resulting buffer. + */ async downloadFile(storageKey: string): Promise { const command = new GetObjectCommand({ Bucket: this.bucketName, @@ -100,6 +114,10 @@ export class FileStorageService { return Buffer.concat(chunks); } + /** + * Removes file. + * @param storageKey The storage key. + */ async deleteFile(storageKey: string): Promise { const command = new DeleteObjectCommand({ Bucket: this.bucketName, diff --git a/src/media/validation/file-validation.service.ts b/src/media/validation/file-validation.service.ts index 13fbf3b2..4aef1d8b 100644 --- a/src/media/validation/file-validation.service.ts +++ b/src/media/validation/file-validation.service.ts @@ -31,6 +31,9 @@ export interface ImageDimensions { height: number; } +/** + * Provides file Validation operations. + */ @Injectable() export class FileValidationService { private readonly logger = new Logger(FileValidationService.name); diff --git a/src/media/validation/malware-scanning.service.ts b/src/media/validation/malware-scanning.service.ts index 2b018c9f..0219da84 100644 --- a/src/media/validation/malware-scanning.service.ts +++ b/src/media/validation/malware-scanning.service.ts @@ -36,6 +36,9 @@ export interface IVirusTotalReport { }; } +/** + * Provides malware Scanning operations. + */ @Injectable() export class MalwareScanningService { private readonly logger = new Logger(MalwareScanningService.name); diff --git a/src/media/validation/upload-progress.service.ts b/src/media/validation/upload-progress.service.ts index be1a17e0..aa56c653 100644 --- a/src/media/validation/upload-progress.service.ts +++ b/src/media/validation/upload-progress.service.ts @@ -39,6 +39,9 @@ export interface IProgressUpdate { result?: IUploadProgress['result']; } +/** + * Provides upload Progress operations. + */ @Injectable() export class UploadProgressService { private readonly logger = new Logger(UploadProgressService.name); diff --git a/src/media/validation/upload-validation.util.ts b/src/media/validation/upload-validation.util.ts index 55149d1b..ba4fc424 100644 --- a/src/media/validation/upload-validation.util.ts +++ b/src/media/validation/upload-validation.util.ts @@ -45,6 +45,10 @@ export const MEDIA_UPLOAD_INTERCEPTOR_OPTIONS = { }, } as const; +/** + * Builds upload Validation Details. + * @returns The operation result. + */ export function buildUploadValidationDetails() { return { allowedTypes: ALL_ALLOWED_FILE_TYPES, diff --git a/src/messaging/circuit-breaker/circuit-breaker.service.ts b/src/messaging/circuit-breaker/circuit-breaker.service.ts index 647ac9d0..8e9bbe84 100644 --- a/src/messaging/circuit-breaker/circuit-breaker.service.ts +++ b/src/messaging/circuit-breaker/circuit-breaker.service.ts @@ -9,6 +9,9 @@ export interface ICircuitBreakerConfig { export type CircuitState = 'CLOSED' | 'OPEN' | 'HALF_OPEN'; +/** + * Provides circuit Breaker operations. + */ @Injectable() export class CircuitBreakerService { private readonly logger = new Logger(CircuitBreakerService.name); @@ -24,6 +27,13 @@ export class CircuitBreakerService { constructor(private readonly tracingService: TracingService) {} + /** + * Executes execute. + * @param key The key. + * @param operation The operation. + * @param config The config. + * @returns The resulting t. + */ async execute( key: string, operation: () => Promise, @@ -97,11 +107,21 @@ export class CircuitBreakerService { } } + /** + * Retrieves circuit State. + * @param key The key. + * @returns The operation result. + */ async getCircuitState(key: string): Promise { const circuit = this.circuits.get(key); return circuit ? circuit.state : null; } + /** + * Retrieves circuit Stats. + * @param key The key. + * @returns The operation result. + */ async getCircuitStats(key: string): Promise<{ state: CircuitState; failures: number; @@ -117,6 +137,10 @@ export class CircuitBreakerService { }; } + /** + * Resets circuit. + * @param key The key. + */ async resetCircuit(key: string): Promise { const circuit = this.circuits.get(key); if (circuit) { @@ -127,6 +151,19 @@ export class CircuitBreakerService { } } + /** + * Retrieves all Circuits. + * @returns The resulting promise< + record< + string, + { + state: circuit state; + failures: number; + last failure time: number; + } + > + >. + */ async getAllCircuits(): Promise< Record< string, diff --git a/src/messaging/discovery/service-discovery.service.ts b/src/messaging/discovery/service-discovery.service.ts index 59615d10..1c20267a 100644 --- a/src/messaging/discovery/service-discovery.service.ts +++ b/src/messaging/discovery/service-discovery.service.ts @@ -12,6 +12,9 @@ export interface IServiceInstance { metadata?: Record; } +/** + * Provides service Discovery operations. + */ @Injectable() export class ServiceDiscoveryService implements OnModuleInit, OnModuleDestroy { private readonly logger = new Logger(ServiceDiscoveryService.name); @@ -22,6 +25,9 @@ export class ServiceDiscoveryService implements OnModuleInit, OnModuleDestroy { constructor(private readonly tracingService: TracingService) {} + /** + * Executes on Module Init. + */ async onModuleInit(): Promise { this.redis = new Redis({ host: process.env.REDIS_HOST || 'localhost', @@ -36,6 +42,9 @@ export class ServiceDiscoveryService implements OnModuleInit, OnModuleDestroy { this.startHeartbeat(); } + /** + * Executes on Module Destroy. + */ async onModuleDestroy(): Promise { if (this.heartbeatTimer) { clearInterval(this.heartbeatTimer); @@ -65,6 +74,11 @@ export class ServiceDiscoveryService implements OnModuleInit, OnModuleDestroy { } } + /** + * Executes deregister Service. + * @param serviceName The service name. + * @param serviceId The service identifier. + */ async deregisterService(serviceName: string, serviceId: string): Promise { const span = this.tracingService.startSpan('deregister-service'); try { @@ -101,6 +115,12 @@ export class ServiceDiscoveryService implements OnModuleInit, OnModuleDestroy { } } + /** + * Updates health. + * @param serviceName The service name. + * @param serviceId The service identifier. + * @param health The health. + */ async updateHealth( serviceName: string, serviceId: string, diff --git a/src/messaging/event-bus/event-bus.service.ts b/src/messaging/event-bus/event-bus.service.ts index 8dc72804..65ccb430 100644 --- a/src/messaging/event-bus/event-bus.service.ts +++ b/src/messaging/event-bus/event-bus.service.ts @@ -9,6 +9,9 @@ export interface IEventData { timestamp: Date; } +/** + * Provides event Bus operations. + */ @Injectable() export class EventBusService { private readonly logger = new Logger(EventBusService.name); @@ -18,6 +21,12 @@ export class EventBusService { private readonly tracingService: TracingService, ) {} + /** + * Executes publish. + * @param eventType The event type. + * @param payload The payload to process. + * @param source The source. + */ async publish(eventType: string, payload: any, source: string = 'unknown'): Promise { const span = this.tracingService.startSpan(`publish-event-${eventType}`); try { @@ -53,10 +62,21 @@ export class EventBusService { this.logger.log(`Unsubscribed from event: ${eventType}`); } + /** + * Retrieves listeners. + * @param eventType The event type. + * @returns The matching results. + */ async getListeners(eventType: string): Promise { return this.eventEmitter.listeners(eventType); } + /** + * Executes emit Async. + * @param eventType The event type. + * @param payload The payload to process. + * @param source The source. + */ async emitAsync(eventType: string, payload: any, source: string = 'unknown'): Promise { const span = this.tracingService.startSpan(`emit-async-event-${eventType}`); try { diff --git a/src/messaging/messaging.module.ts b/src/messaging/messaging.module.ts index 88b407e1..b42a18cb 100644 --- a/src/messaging/messaging.module.ts +++ b/src/messaging/messaging.module.ts @@ -9,6 +9,9 @@ import { CircuitBreakerService } from './circuit-breaker/circuit-breaker.service import { TracingService } from './tracing/tracing.service'; import { createBullRedisClient } from '../common/utils/bull-redis.util'; +/** + * Registers the messaging module. + */ @Module({ imports: [ BullModule.forRoot({ diff --git a/src/messaging/messaging.service.ts b/src/messaging/messaging.service.ts index 291a50e0..d5e7dc9b 100644 --- a/src/messaging/messaging.service.ts +++ b/src/messaging/messaging.service.ts @@ -4,6 +4,9 @@ import { Queue, Job } from 'bull'; import { QUEUE_NAMES } from '../common/constants/queue.constants'; import { TracingService } from './tracing/tracing.service'; +/** + * Provides messaging operations. + */ @Injectable() export class MessagingService { private readonly logger = new Logger(MessagingService.name); @@ -14,6 +17,12 @@ export class MessagingService { private readonly tracingService: TracingService, ) {} + /** + * Executes add Message To Queue. + * @param data The data to process. + * @param options The options. + * @returns The resulting job. + */ async addMessageToQueue(data: any, options?: any): Promise> { const span = this.tracingService.startSpan('add-message-to-queue'); try { @@ -28,6 +37,9 @@ export class MessagingService { } } + /** + * Processes messages. + */ async processMessages(): Promise { this.messageQueue.process(async (job: Job) => { const span = this.tracingService.startSpan('process-message'); @@ -50,6 +62,10 @@ export class MessagingService { this.logger.log('Handling message:', data); } + /** + * Retrieves queue Status. + * @returns The operation result. + */ async getQueueStatus(): Promise { const waiting = await this.messageQueue.getWaiting(); const active = await this.messageQueue.getActive(); diff --git a/src/messaging/tracing/tracing.service.ts b/src/messaging/tracing/tracing.service.ts index aa6e4fa9..0d2dbe1d 100644 --- a/src/messaging/tracing/tracing.service.ts +++ b/src/messaging/tracing/tracing.service.ts @@ -1,11 +1,20 @@ import { Injectable, Logger } from '@nestjs/common'; import { trace, Span, SpanStatusCode, SpanOptions } from '@opentelemetry/api'; +/** + * Provides tracing operations. + */ @Injectable() export class TracingService { private readonly logger = new Logger(TracingService.name); private readonly tracer = trace.getTracer('teachlink-messaging', '1.0.0'); + /** + * Starts span. + * @param name The name. + * @param parentSpan The parent span. + * @returns The resulting span. + */ startSpan(name: string, parentSpan?: Span): Span { const spanOptions: SpanOptions = {}; if (parentSpan) { @@ -17,40 +26,83 @@ export class TracingService { return span; } + /** + * Executes end Span. + * @param span The span. + */ endSpan(span: Span): void { span.end(); this.logger.debug(`Ended span: ${span.constructor.name || 'Span'}`); } + /** + * Sets span Attribute. + * @param span The span. + * @param key The key. + * @param value The value. + */ setSpanAttribute(span: Span, key: string, value: string | number | boolean): void { span.setAttribute(key, value); } + /** + * Sets span Attributes. + * @param span The span. + * @param attributes The attributes. + */ setSpanAttributes(span: Span, attributes: Record): void { Object.entries(attributes).forEach(([key, value]) => { span.setAttribute(key, value); }); } + /** + * Records exception. + * @param span The span. + * @param error The error. + */ recordException(span: Span, error: Error): void { span.recordException(error); span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); } + /** + * Executes add Event. + * @param span The span. + * @param name The name. + * @param attributes The attributes. + */ addEvent(span: Span, name: string, attributes?: Record): void { span.addEvent(name, attributes); } + /** + * Creates child Span. + * @param parentSpan The parent span. + * @param name The name. + * @returns The resulting span. + */ createChildSpan(parentSpan: Span, name: string): Span { // In newer OpenTelemetry versions, parent span handling is different return this.tracer.startSpan(name); } + /** + * Retrieves current Span. + * @returns The operation result. + */ getCurrentSpan(): Span | undefined { // getActiveContext doesn't exist in the newer API return trace.getActiveSpan(); } + /** + * Executes run In Span. + * @param name The name. + * @param fn The fn. + * @param parentSpan The parent span. + * @returns The resulting t. + */ async runInSpan(name: string, fn: (span: Span) => Promise, parentSpan?: Span): Promise { const span = this.startSpan(name, parentSpan); try { @@ -65,6 +117,11 @@ export class TracingService { } } + /** + * Executes inject Context. + * @param span The span. + * @returns The resulting record. + */ injectContext(span: Span): Record { // This would typically inject tracing headers for distributed calls // For simplicity, return basic span context @@ -74,6 +131,11 @@ export class TracingService { }; } + /** + * Executes extract Context. + * @param headers The headers. + * @returns The operation result. + */ extractContext(headers: Record): any { // Extract tracing context from headers // This would be used to continue traces across service boundaries diff --git a/src/migrations/conflicts/conflict-resolution.service.ts b/src/migrations/conflicts/conflict-resolution.service.ts index c21aac71..b2cde5d6 100644 --- a/src/migrations/conflicts/conflict-resolution.service.ts +++ b/src/migrations/conflicts/conflict-resolution.service.ts @@ -19,6 +19,9 @@ export interface IMigrationConflict { resolvedBy?: string; } +/** + * Provides conflict Resolution operations. + */ @Injectable() export class ConflictResolutionService { private readonly logger = new Logger(ConflictResolutionService.name); diff --git a/src/migrations/entities/migration.entity.ts b/src/migrations/entities/migration.entity.ts index 96da2afb..2e8851cf 100644 --- a/src/migrations/entities/migration.entity.ts +++ b/src/migrations/entities/migration.entity.ts @@ -14,6 +14,9 @@ export enum MigrationStatus { ROLLED_BACK = 'rolled_back', } +/** + * Represents the migration entity. + */ @Entity({ name: 'migrations' }) export class Migration { @PrimaryGeneratedColumn('uuid') diff --git a/src/migrations/environments/environment-sync.service.ts b/src/migrations/environments/environment-sync.service.ts index 3b402364..80720a5a 100644 --- a/src/migrations/environments/environment-sync.service.ts +++ b/src/migrations/environments/environment-sync.service.ts @@ -9,6 +9,9 @@ export enum EnvironmentType { TEST = 'test', } +/** + * Provides environment Sync operations. + */ @Injectable() export class EnvironmentSyncService { private readonly logger = new Logger(EnvironmentSyncService.name); diff --git a/src/migrations/migration-runner.service.ts b/src/migrations/migration-runner.service.ts index 591ea001..66519f09 100644 --- a/src/migrations/migration-runner.service.ts +++ b/src/migrations/migration-runner.service.ts @@ -1,12 +1,19 @@ import { Injectable, Logger, OnApplicationBootstrap } from '@nestjs/common'; import { MigrationService } from './migration.service'; +/** + * Provides migration Runner operations. + */ @Injectable() export class MigrationRunnerService implements OnApplicationBootstrap { private readonly logger = new Logger(MigrationRunnerService.name); constructor(private migrationService: MigrationService) {} + /** + * Executes on Application Bootstrap. + * @returns The operation result. + */ async onApplicationBootstrap() { // Optionally run migrations automatically when the application starts // This can be controlled via configuration diff --git a/src/migrations/migration.controller.ts b/src/migrations/migration.controller.ts index 6e5161dd..92a3cbf3 100644 --- a/src/migrations/migration.controller.ts +++ b/src/migrations/migration.controller.ts @@ -15,6 +15,9 @@ import { MigrationService } from './migration.service'; import { RollbackService } from './rollback/rollback.service'; import { ConflictResolutionService } from './conflicts/conflict-resolution.service'; +/** + * Exposes migration endpoints. + */ @Controller('migrations') export class MigrationController { private readonly logger = new Logger(MigrationController.name); @@ -25,12 +28,21 @@ export class MigrationController { private conflictResolutionService: ConflictResolutionService, ) {} + /** + * Returns all Migrations. + * @returns The operation result. + */ @Get() async getAllMigrations(): Promise { this.logger.log('Fetching all migrations'); return await this.migrationService.listMigrations(); } + /** + * Executes run Migrations. + * @param res The res. + * @returns The operation result. + */ @Post('run') @HttpCode(HttpStatus.OK) async runMigrations(@Res() res: Response): Promise { @@ -52,12 +64,23 @@ export class MigrationController { } } + /** + * Executes rollback Migrations Default. + * @param res The res. + * @returns The operation result. + */ @Post('rollback') @HttpCode(HttpStatus.OK) async rollbackMigrationsDefault(@Res() res: Response): Promise { return this.rollbackMigrationsWithCount('1', res); } + /** + * Executes rollback Migrations With Count. + * @param count The count. + * @param res The res. + * @returns The operation result. + */ @Post('rollback/:count') @HttpCode(HttpStatus.OK) async rollbackMigrationsWithCount( @@ -84,6 +107,11 @@ export class MigrationController { } } + /** + * Resets all Migrations. + * @param res The res. + * @returns The operation result. + */ @Delete('reset') @HttpCode(HttpStatus.OK) async resetAllMigrations(@Res() res: Response): Promise { @@ -105,6 +133,12 @@ export class MigrationController { } } + /** + * Executes rollback Specific Migration. + * @param migrationName The migration name. + * @param res The res. + * @returns The operation result. + */ @Put(':migrationName/rollback') @HttpCode(HttpStatus.OK) async rollbackSpecificMigration( @@ -129,6 +163,12 @@ export class MigrationController { } } + /** + * Executes rollback To Version. + * @param migrationName The migration name. + * @param res The res. + * @returns The operation result. + */ @Post('rollback/to/:migrationName') @HttpCode(HttpStatus.OK) async rollbackToVersion( @@ -153,12 +193,21 @@ export class MigrationController { } } + /** + * Returns migration Conflicts. + * @returns The operation result. + */ @Get('conflicts') async getMigrationConflicts(): Promise { this.logger.log('Fetching migration conflicts'); return this.conflictResolutionService.getConflictHistory(); } + /** + * Synchronizes environments. + * @param res The res. + * @returns The operation result. + */ @Post('sync-environments') @HttpCode(HttpStatus.OK) async syncEnvironments(@Res() res: Response): Promise { diff --git a/src/migrations/migration.module.ts b/src/migrations/migration.module.ts index f5eba3b6..feda8abc 100644 --- a/src/migrations/migration.module.ts +++ b/src/migrations/migration.module.ts @@ -9,6 +9,9 @@ import { ConflictResolutionService } from './conflicts/conflict-resolution.servi import { MigrationController } from './migration.controller'; import { MigrationRunnerService } from './migration-runner.service'; +/** + * Registers the migration module. + */ @Module({ imports: [TypeOrmModule.forFeature([Migration])], controllers: [MigrationController], diff --git a/src/migrations/migration.service.ts b/src/migrations/migration.service.ts index bb4742f2..0c4e9cbd 100644 --- a/src/migrations/migration.service.ts +++ b/src/migrations/migration.service.ts @@ -16,6 +16,9 @@ export interface IMigrationConfig { dependencies?: string[]; } +/** + * Provides migration operations. + */ @Injectable() export class MigrationService { private readonly logger = new Logger(MigrationService.name); diff --git a/src/migrations/rollback/rollback.service.ts b/src/migrations/rollback/rollback.service.ts index 53fbcbd4..8eacbd20 100644 --- a/src/migrations/rollback/rollback.service.ts +++ b/src/migrations/rollback/rollback.service.ts @@ -5,6 +5,9 @@ import { Migration, MigrationStatus } from '../entities/migration.entity'; import { IMigrationConfig } from '../migration.service'; import { MIGRATION_REGISTRY } from '../migration.registry'; +/** + * Provides rollback operations. + */ @Injectable() export class RollbackService { private readonly logger = new Logger(RollbackService.name); @@ -180,6 +183,11 @@ export class RollbackService { await this.rollbackMigration(migrationConfig); } + /** + * Executes can Rollback Migration. + * @param migrationName The migration name. + * @returns Whether the operation succeeded. + */ async canRollbackMigration(migrationName: string): Promise { // Check if the migration exists and is completed const migration = await this.migrationRepository.findOne({ diff --git a/src/migrations/samples/001-create-users-table.migration.ts b/src/migrations/samples/001-create-users-table.migration.ts index a343a704..a76a7c1b 100644 --- a/src/migrations/samples/001-create-users-table.migration.ts +++ b/src/migrations/samples/001-create-users-table.migration.ts @@ -15,6 +15,10 @@ export class CreateUsersTableMigration implements IMigrationConfig { private readonly logger = new Logger(CreateUsersTableMigration.name); + /** + * Executes up. + * @param connection The connection. + */ async up(connection: any): Promise { this.logger.log('Applying migration: create users table'); @@ -64,6 +68,10 @@ export class CreateUsersTableMigration implements IMigrationConfig { this.logger.log('Migration applied: create users table'); } + /** + * Executes down. + * @param connection The connection. + */ async down(connection: any): Promise { this.logger.log('Rolling back migration: create users table'); diff --git a/src/migrations/samples/002-create-courses-table.migration.ts b/src/migrations/samples/002-create-courses-table.migration.ts index 69fe51de..26f73429 100644 --- a/src/migrations/samples/002-create-courses-table.migration.ts +++ b/src/migrations/samples/002-create-courses-table.migration.ts @@ -17,6 +17,10 @@ export class CreateCoursesTableMigration implements IMigrationConfig { private readonly logger = new Logger(CreateCoursesTableMigration.name); + /** + * Executes up. + * @param connection The connection. + */ async up(connection: any): Promise { this.logger.log('Applying migration: create courses table'); @@ -44,6 +48,10 @@ export class CreateCoursesTableMigration implements IMigrationConfig { this.logger.log('Migration applied: create courses table'); } + /** + * Executes down. + * @param connection The connection. + */ async down(connection: any): Promise { this.logger.log('Rolling back migration: create courses table'); diff --git a/src/migrations/samples/003-create-course-modules-table.migration.ts b/src/migrations/samples/003-create-course-modules-table.migration.ts index ea06d70f..13b1176d 100644 --- a/src/migrations/samples/003-create-course-modules-table.migration.ts +++ b/src/migrations/samples/003-create-course-modules-table.migration.ts @@ -17,6 +17,10 @@ export class CreateCourseModulesTableMigration implements IMigrationConfig { private readonly logger = new Logger(CreateCourseModulesTableMigration.name); + /** + * Executes up. + * @param connection The connection. + */ async up(connection: any): Promise { this.logger.log('Applying migration: create course_module table'); @@ -36,6 +40,10 @@ export class CreateCourseModulesTableMigration implements IMigrationConfig { this.logger.log('Migration applied: create course_module table'); } + /** + * Executes down. + * @param connection The connection. + */ async down(connection: any): Promise { this.logger.log('Rolling back migration: create course_module table'); diff --git a/src/migrations/samples/004-create-lessons-table.migration.ts b/src/migrations/samples/004-create-lessons-table.migration.ts index 4c64bf17..64e6404b 100644 --- a/src/migrations/samples/004-create-lessons-table.migration.ts +++ b/src/migrations/samples/004-create-lessons-table.migration.ts @@ -17,6 +17,10 @@ export class CreateLessonsTableMigration implements IMigrationConfig { private readonly logger = new Logger(CreateLessonsTableMigration.name); + /** + * Executes up. + * @param connection The connection. + */ async up(connection: any): Promise { this.logger.log('Applying migration: create lesson table'); @@ -39,6 +43,10 @@ export class CreateLessonsTableMigration implements IMigrationConfig { this.logger.log('Migration applied: create lesson table'); } + /** + * Executes down. + * @param connection The connection. + */ async down(connection: any): Promise { this.logger.log('Rolling back migration: create lesson table'); diff --git a/src/migrations/samples/005-create-enrollments-table.migration.ts b/src/migrations/samples/005-create-enrollments-table.migration.ts index 438aef2a..0627ba21 100644 --- a/src/migrations/samples/005-create-enrollments-table.migration.ts +++ b/src/migrations/samples/005-create-enrollments-table.migration.ts @@ -17,6 +17,10 @@ export class CreateEnrollmentsTableMigration implements IMigrationConfig { private readonly logger = new Logger(CreateEnrollmentsTableMigration.name); + /** + * Executes up. + * @param connection The connection. + */ async up(connection: any): Promise { this.logger.log('Applying migration: create enrollment table'); @@ -51,6 +55,10 @@ export class CreateEnrollmentsTableMigration implements IMigrationConfig { this.logger.log('Migration applied: create enrollment table'); } + /** + * Executes down. + * @param connection The connection. + */ async down(connection: any): Promise { this.logger.log('Rolling back migration: create enrollment table'); diff --git a/src/migrations/samples/006-create-migrations-tracking-table.migration.ts b/src/migrations/samples/006-create-migrations-tracking-table.migration.ts index f8475f78..2a1977bb 100644 --- a/src/migrations/samples/006-create-migrations-tracking-table.migration.ts +++ b/src/migrations/samples/006-create-migrations-tracking-table.migration.ts @@ -20,6 +20,10 @@ export class CreateMigrationsTrackingTableMigration implements IMigrationConfig private readonly logger = new Logger(CreateMigrationsTrackingTableMigration.name); + /** + * Executes up. + * @param connection The connection. + */ async up(connection: any): Promise { this.logger.log('Applying migration: create migrations tracking table'); @@ -47,6 +51,10 @@ export class CreateMigrationsTrackingTableMigration implements IMigrationConfig this.logger.log('Migration applied: create migrations tracking table'); } + /** + * Executes down. + * @param connection The connection. + */ async down(connection: any): Promise { this.logger.log('Rolling back migration: create migrations tracking table'); diff --git a/src/migrations/samples/sample-user-table.migration.ts b/src/migrations/samples/sample-user-table.migration.ts index 77423c57..e748a789 100644 --- a/src/migrations/samples/sample-user-table.migration.ts +++ b/src/migrations/samples/sample-user-table.migration.ts @@ -1,6 +1,9 @@ import { Injectable, Logger } from '@nestjs/common'; import { IMigrationConfig } from '../migration.service'; +/** + * Provides sample User Table Migration behavior. + */ @Injectable() export class SampleUserTableMigration implements IMigrationConfig { name = 'sample-user-table'; @@ -9,6 +12,10 @@ export class SampleUserTableMigration implements IMigrationConfig { private readonly logger = new Logger(SampleUserTableMigration.name); + /** + * Executes up. + * @param _connection The connection. + */ async up(_connection: any): Promise { this.logger.log('Applying sample user table migration'); @@ -31,6 +38,10 @@ export class SampleUserTableMigration implements IMigrationConfig { console.log('Creating users table...'); } + /** + * Executes down. + * @param _connection The connection. + */ async down(_connection: any): Promise { this.logger.log('Rolling back sample user table migration'); diff --git a/src/migrations/validation/schema-validation.service.ts b/src/migrations/validation/schema-validation.service.ts index 0a0d836a..0a1261b0 100644 --- a/src/migrations/validation/schema-validation.service.ts +++ b/src/migrations/validation/schema-validation.service.ts @@ -2,6 +2,9 @@ import { Injectable, Logger, BadRequestException } from '@nestjs/common'; // import { Connection, QueryRunner } from 'typeorm'; import { IMigrationConfig } from '../migration.service'; +/** + * Provides schema Validation operations. + */ @Injectable() export class SchemaValidationService { private readonly logger = new Logger(SchemaValidationService.name); diff --git a/src/moderation/analytics/moderation-analytics.service.ts b/src/moderation/analytics/moderation-analytics.service.ts index 1bb0cfd5..89ddc777 100644 --- a/src/moderation/analytics/moderation-analytics.service.ts +++ b/src/moderation/analytics/moderation-analytics.service.ts @@ -3,6 +3,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ModerationEvent } from './moderation-event.entity'; +/** + * Provides moderation Analytics operations. + */ @Injectable() export class ModerationAnalyticsService { constructor( @@ -10,11 +13,22 @@ export class ModerationAnalyticsService { private readonly eventRepo: Repository, ) {} + /** + * Executes log Moderation Event. + * @param content The content. + * @param score The score. + * @param status The status value. + * @returns The operation result. + */ async logModerationEvent(content: string, score: number, status: string) { const event = this.eventRepo.create({ content, score, status }); await this.eventRepo.save(event); } + /** + * Retrieves analytics. + * @returns The operation result. + */ async getAnalytics() { return this.eventRepo.find({ order: { timestamp: 'DESC' } }); } diff --git a/src/moderation/analytics/moderation-event.entity.ts b/src/moderation/analytics/moderation-event.entity.ts index 5842b1e4..258b9e77 100644 --- a/src/moderation/analytics/moderation-event.entity.ts +++ b/src/moderation/analytics/moderation-event.entity.ts @@ -1,5 +1,8 @@ import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, VersionColumn } from 'typeorm'; +/** + * Represents the moderation Event entity. + */ @Entity() export class ModerationEvent { @PrimaryGeneratedColumn() diff --git a/src/moderation/auto/auto-moderation.service.ts b/src/moderation/auto/auto-moderation.service.ts index 687cf58c..ee825ffc 100644 --- a/src/moderation/auto/auto-moderation.service.ts +++ b/src/moderation/auto/auto-moderation.service.ts @@ -1,6 +1,9 @@ import { Injectable } from '@nestjs/common'; import { HfInference } from '@huggingface/inference'; +/** + * Provides auto Moderation operations. + */ @Injectable() export class AutoModerationService { private hf: HfInference; @@ -9,6 +12,11 @@ export class AutoModerationService { this.hf = new HfInference(process.env.HUGGINGFACE_API_KEY); } + /** + * Analyzes analyze. + * @param content The content. + * @returns The operation result. + */ async analyze(content: string): Promise<{ flagged: boolean; reasons: string[]; score: number }> { const result = await this.hf.textClassification({ model: 's-nlp/roberta_toxicity_classifier', // or 'unitary/toxic-bert' diff --git a/src/moderation/manual/manual-review.service.ts b/src/moderation/manual/manual-review.service.ts index 4dcca2e7..8c0c3324 100644 --- a/src/moderation/manual/manual-review.service.ts +++ b/src/moderation/manual/manual-review.service.ts @@ -3,6 +3,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { ReviewItem } from './review-item.entity'; +/** + * Provides manual Review operations. + */ @Injectable() export class ManualReviewService { constructor( @@ -10,11 +13,21 @@ export class ManualReviewService { private readonly reviewRepo: Repository, ) {} + /** + * Executes enqueue. + * @param content The content. + * @param safetyScore The safety score. + * @returns The operation result. + */ async enqueue(content: string, safetyScore: number) { const item = this.reviewRepo.create({ content, safetyScore, status: 'pending' }); await this.reviewRepo.save(item); } + /** + * Retrieves queue. + * @returns The matching results. + */ async getQueue(): Promise { return this.reviewRepo.find({ where: { status: 'pending' }, @@ -22,6 +35,11 @@ export class ManualReviewService { }); } + /** + * Marks reviewed. + * @param id The identifier. + * @returns The operation result. + */ async markReviewed(id: number) { await this.reviewRepo.update(id, { status: 'reviewed' }); } diff --git a/src/moderation/manual/review-item.entity.ts b/src/moderation/manual/review-item.entity.ts index 80e0d5e1..dd67be0a 100644 --- a/src/moderation/manual/review-item.entity.ts +++ b/src/moderation/manual/review-item.entity.ts @@ -1,5 +1,8 @@ import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, VersionColumn } from 'typeorm'; +/** + * Represents the review Item entity. + */ @Entity() export class ReviewItem { @PrimaryGeneratedColumn() diff --git a/src/moderation/moderation.module.ts b/src/moderation/moderation.module.ts index b3aa6ef2..9f17270a 100644 --- a/src/moderation/moderation.module.ts +++ b/src/moderation/moderation.module.ts @@ -8,6 +8,9 @@ import { ModerationAnalyticsService } from './analytics/moderation-analytics.ser import { ReviewItem } from './manual/review-item.entity'; import { ModerationEvent } from './analytics/moderation-event.entity'; +/** + * Registers the moderation module. + */ @Module({ imports: [TypeOrmModule.forFeature([ReviewItem, ModerationEvent])], providers: [ diff --git a/src/moderation/moderation.service.ts b/src/moderation/moderation.service.ts index 271caea9..67650d30 100644 --- a/src/moderation/moderation.service.ts +++ b/src/moderation/moderation.service.ts @@ -4,6 +4,9 @@ import { ManualReviewService } from './manual/manual-review.service'; import { ContentSafetyService } from './safety/content-safety.service'; import { ModerationAnalyticsService } from './analytics/moderation-analytics.service'; +/** + * Provides moderation operations. + */ @Injectable() export class ModerationService { constructor( @@ -13,6 +16,11 @@ export class ModerationService { private readonly analytics: ModerationAnalyticsService, ) {} + /** + * Moderates content. + * @param content The content. + * @returns The operation result. + */ async moderateContent(content: string) { const autoResult = await this.autoModeration.analyze(content); const safetyScore = this.safetyService.scoreContent(content); diff --git a/src/moderation/safety/content-safety.service.ts b/src/moderation/safety/content-safety.service.ts index 9b71ccce..215deade 100644 --- a/src/moderation/safety/content-safety.service.ts +++ b/src/moderation/safety/content-safety.service.ts @@ -1,7 +1,15 @@ import { Injectable } from '@nestjs/common'; +/** + * Provides content Safety operations. + */ @Injectable() export class ContentSafetyService { + /** + * Executes score Content. + * @param content The content. + * @returns The calculated numeric value. + */ scoreContent(content: string): number { // Simple scoring logic (replace with ML model later) let score = 0; diff --git a/src/monitoring/alerting/alerting.service.ts b/src/monitoring/alerting/alerting.service.ts index 8da5eecd..055bcc4b 100644 --- a/src/monitoring/alerting/alerting.service.ts +++ b/src/monitoring/alerting/alerting.service.ts @@ -100,6 +100,9 @@ export const ALERT_RULES: IAlertRule[] = [ }, ]; +/** + * Provides alerting operations. + */ @Injectable() export class AlertingService { private readonly logger = new Logger(AlertingService.name); diff --git a/src/monitoring/logging/typeorm-logger.ts b/src/monitoring/logging/typeorm-logger.ts index c82d2995..dc8c2bb9 100644 --- a/src/monitoring/logging/typeorm-logger.ts +++ b/src/monitoring/logging/typeorm-logger.ts @@ -1,13 +1,31 @@ import { Logger, QueryRunner } from 'typeorm'; import { MetricsCollectionService } from '../metrics/metrics-collection.service'; +/** + * Provides type Orm Monitoring Logger behavior. + */ export class TypeOrmMonitoringLogger implements Logger { constructor(private readonly metricsService: MetricsCollectionService) {} + /** + * Executes log Query. + * @param _query The query value. + * @param _parameters The parameters. + * @param _queryRunner The query value. + * @returns The operation result. + */ logQuery(_query: string, _parameters?: any[], _queryRunner?: QueryRunner) { // Optional: console.log(`[Query]: ${query}`); } + /** + * Executes log Query Error. + * @param error The error. + * @param query The query value. + * @param _parameters The parameters. + * @param _queryRunner The query value. + * @returns The operation result. + */ logQueryError( error: string | Error, query: string, @@ -17,6 +35,14 @@ export class TypeOrmMonitoringLogger implements Logger { console.error(`[Query Error]: ${error}`, query); } + /** + * Executes log Query Slow. + * @param time The time. + * @param query The query value. + * @param _parameters The parameters. + * @param _queryRunner The query value. + * @returns The operation result. + */ logQuerySlow(time: number, query: string, _parameters?: any[], _queryRunner?: QueryRunner) { console.warn(`[Slow Query]: ${time}ms - ${query}`); const table = this.extractTable(query); @@ -24,12 +50,31 @@ export class TypeOrmMonitoringLogger implements Logger { this.metricsService.recordDbQuery('slow_query', table, time / 1000); } + /** + * Executes log Schema Build. + * @param _message The message. + * @param _queryRunner The query value. + * @returns The operation result. + */ logSchemaBuild(_message: string, _queryRunner?: QueryRunner) { // console.log(`[Schema Build]: ${message}`); } + /** + * Executes log Migration. + * @param _message The message. + * @param _queryRunner The query value. + * @returns The operation result. + */ logMigration(_message: string, _queryRunner?: QueryRunner) { // console.log(`[Migration]: ${message}`); } + /** + * Executes log. + * @param level The level. + * @param _message The message. + * @param _queryRunner The query value. + * @returns The operation result. + */ log(level: 'log' | 'info' | 'warn', _message: any, _queryRunner?: QueryRunner) { switch (level) { case 'log': diff --git a/src/monitoring/metrics/metrics-collection.service.ts b/src/monitoring/metrics/metrics-collection.service.ts index 9cc675a4..1ac3d668 100644 --- a/src/monitoring/metrics/metrics-collection.service.ts +++ b/src/monitoring/metrics/metrics-collection.service.ts @@ -1,6 +1,9 @@ import { Injectable, OnModuleInit } from '@nestjs/common'; import { Registry, collectDefaultMetrics, Histogram, Gauge, Counter } from 'prom-client'; +/** + * Provides metrics Collection operations. + */ @Injectable() export class MetricsCollectionService implements OnModuleInit { private registry: Registry; @@ -126,52 +129,123 @@ export class MetricsCollectionService implements OnModuleInit { }); } + /** + * Executes on Module Init. + * @returns The operation result. + */ onModuleInit() { // Collect default system metrics (CPU, Memory, Event Loop, etc.) collectDefaultMetrics({ register: this.registry }); } + /** + * Retrieves registry. + * @returns The resulting registry. + */ getRegistry(): Registry { return this.registry; } + /** + * Retrieves metrics. + * @returns The resulting string value. + */ async getMetrics(): Promise { return this.registry.metrics(); } + /** + * Records http Request. + * @param method The method. + * @param route The route. + * @param statusCode The status value. + * @param duration The duration. + * @returns The operation result. + */ recordHttpRequest(method: string, route: string, statusCode: number, duration: number) { this.httpRequestDuration.observe({ method, route, status_code: statusCode }, duration); } + /** + * Records db Query. + * @param queryType The query value. + * @param table The table. + * @param duration The duration. + * @returns The operation result. + */ recordDbQuery(queryType: string, table: string, duration: number) { this.dbQueryDuration.observe({ query_type: queryType, table }, duration); } // Custom business metrics methods + /** + * Records user Registration. + * @param userType The user type. + * @param source The source. + * @returns The operation result. + */ recordUserRegistration(userType: string, source: string) { this.userRegistrations.inc({ user_type: userType, source }); } + /** + * Records assessment Completion. + * @param assessmentType The assessment type. + * @param difficulty The difficulty. + * @returns The operation result. + */ recordAssessmentCompletion(assessmentType: string, difficulty: string) { this.assessmentCompletions.inc({ assessment_type: assessmentType, difficulty }); } + /** + * Updates learning Path Progress. + * @param pathId The path identifier. + * @param userId The user identifier. + * @param progress The progress. + * @returns The operation result. + */ updateLearningPathProgress(pathId: string, userId: string, progress: number) { this.learningPathProgress.set({ path_id: pathId, user_id: userId }, progress); } + /** + * Updates cache Hit Rate. + * @param cacheType The cache type. + * @param hitRate The hit rate. + * @returns The operation result. + */ updateCacheHitRate(cacheType: string, hitRate: number) { this.cacheHitRate.set({ cache_type: cacheType }, hitRate); } + /** + * Records queue Processing Time. + * @param queueName The queue name. + * @param jobType The job type. + * @param duration The duration. + * @returns The operation result. + */ recordQueueProcessingTime(queueName: string, jobType: string, duration: number) { this.queueProcessingTime.observe({ queue_name: queueName, job_type: jobType }, duration); } + /** + * Records email Campaign Sent. + * @param campaignType The campaign type. + * @param status The status value. + * @returns The operation result. + */ recordEmailCampaignSent(campaignType: string, status: string) { this.emailCampaignsSent.inc({ campaign_type: campaignType, status }); } + /** + * Records backup Operation. + * @param operationType The operation type. + * @param status The status value. + * @returns The operation result. + */ recordBackupOperation(operationType: string, status: string) { this.backupOperations.inc({ operation_type: operationType, status }); } diff --git a/src/monitoring/monitoring.controller.ts b/src/monitoring/monitoring.controller.ts index e6b7cb33..92592e6c 100644 --- a/src/monitoring/monitoring.controller.ts +++ b/src/monitoring/monitoring.controller.ts @@ -15,6 +15,11 @@ export class MonitoringController { @Optional() private readonly costTrackingService?: CostTrackingService, ) {} + /** + * Returns metrics. + * @param res The res. + * @returns The operation result. + */ @Get() async getMetrics(@Res() res: Response) { const metrics = await this.metricsService.getMetrics(); @@ -22,6 +27,13 @@ export class MonitoringController { res.send(metrics); } + /** + * Returns unified Metrics. + * @param format The format. + * @param include The include. + * @param exclude The exclude. + * @returns The operation result. + */ @Get('unified') async getUnifiedMetrics( @Query('format') format?: string, @@ -60,6 +72,10 @@ export class MonitoringController { return metrics; } + /** + * Returns metrics Health. + * @returns The operation result. + */ @Get('health') async getMetricsHealth() { return { @@ -77,6 +93,11 @@ export class MonitoringController { }; } + /** + * Returns custom Metrics. + * @param type The type. + * @returns The operation result. + */ @Get('custom') async getCustomMetrics(@Query('type') type?: string) { const customMetrics = { diff --git a/src/monitoring/monitoring.module.ts b/src/monitoring/monitoring.module.ts index 96e14ac5..457e1862 100644 --- a/src/monitoring/monitoring.module.ts +++ b/src/monitoring/monitoring.module.ts @@ -11,6 +11,9 @@ import { ScheduledTaskMonitoringService } from './scheduled-task-monitoring.serv import { CostSchedulerService } from './cost-scheduler.service'; import { AwsCostCollectorService } from './cloud/aws-cost-collector.service'; +/** + * Registers the monitoring module. + */ @Module({ imports: [ScheduleModule.forRoot()], controllers: [MonitoringController], diff --git a/src/monitoring/monitoring.service.ts b/src/monitoring/monitoring.service.ts index 8365cea3..8440964a 100644 --- a/src/monitoring/monitoring.service.ts +++ b/src/monitoring/monitoring.service.ts @@ -4,6 +4,9 @@ import { PerformanceAnalysisService } from './performance/performance-analysis.s import { OptimizationService } from './optimization/optimization.service'; import { AlertingService } from './alerting/alerting.service'; +/** + * Provides monitoring operations. + */ @Injectable() export class MonitoringService { private readonly logger = new Logger(MonitoringService.name); @@ -14,6 +17,10 @@ export class MonitoringService { private readonly alertingService: AlertingService, ) {} + /** + * Handles cron. + * @returns The operation result. + */ @Cron(CronExpression.EVERY_MINUTE) async handleCron() { this.logger.debug('Running system performance analysis...'); diff --git a/src/monitoring/optimization/optimization.service.ts b/src/monitoring/optimization/optimization.service.ts index 82f75e0b..9032fde6 100644 --- a/src/monitoring/optimization/optimization.service.ts +++ b/src/monitoring/optimization/optimization.service.ts @@ -1,9 +1,17 @@ import { Injectable, Logger } from '@nestjs/common'; +/** + * Provides optimization operations. + */ @Injectable() export class OptimizationService { private readonly logger = new Logger(OptimizationService.name); + /** + * Retrieves optimization Recommendations. + * @param analysisResult The analysis result. + * @returns The matching results. + */ getOptimizationRecommendations(analysisResult: any): string[] { const recommendations: string[] = []; diff --git a/src/monitoring/performance/performance-analysis.service.ts b/src/monitoring/performance/performance-analysis.service.ts index 97316c60..06255ac4 100644 --- a/src/monitoring/performance/performance-analysis.service.ts +++ b/src/monitoring/performance/performance-analysis.service.ts @@ -2,12 +2,19 @@ import { Injectable, Logger } from '@nestjs/common'; import { MetricsCollectionService } from '../metrics/metrics-collection.service'; import * as os from 'os'; +/** + * Provides performance Analysis operations. + */ @Injectable() export class PerformanceAnalysisService { private readonly logger = new Logger(PerformanceAnalysisService.name); constructor(private readonly metricsService: MetricsCollectionService) {} + /** + * Analyzes analyze. + * @returns The operation result. + */ async analyze(): Promise { const metrics = await this.metricsService.getRegistry().getMetricsAsJSON(); diff --git a/src/monitoring/scheduled-task-monitoring.service.ts b/src/monitoring/scheduled-task-monitoring.service.ts index 316409a5..43fb4bed 100644 --- a/src/monitoring/scheduled-task-monitoring.service.ts +++ b/src/monitoring/scheduled-task-monitoring.service.ts @@ -25,6 +25,9 @@ export interface IScheduledTaskExecution { metadata?: Record; } +/** + * Provides scheduled Task Monitoring operations. + */ @Injectable() export class ScheduledTaskMonitoringService { private readonly logger = new Logger(ScheduledTaskMonitoringService.name); @@ -51,6 +54,13 @@ export class ScheduledTaskMonitoringService { }); } + /** + * Starts execution. + * @param taskName The task name. + * @param config The config. + * @param metadata The data to process. + * @returns The resulting string value. + */ startExecution( taskName: string, config: IScheduledTaskConfig, @@ -75,6 +85,11 @@ export class ScheduledTaskMonitoringService { return executionId; } + /** + * Marks success. + * @param executionId The execution identifier. + * @param metadata The data to process. + */ markSuccess(executionId: string, metadata: Record = {}): void { const execution = this.activeExecutions.get(executionId); if (!execution) { @@ -98,6 +113,12 @@ export class ScheduledTaskMonitoringService { ); } + /** + * Marks failure. + * @param executionId The execution identifier. + * @param error The error. + * @param metadata The data to process. + */ markFailure( executionId: string, error: Error | string, @@ -128,6 +149,13 @@ export class ScheduledTaskMonitoringService { ); } + /** + * Records retry. + * @param taskName The task name. + * @param attempt The attempt. + * @param maxRetries The max retries. + * @param reason The reason. + */ recordRetry(taskName: string, attempt: number, maxRetries: number, reason?: string): void { const current = this.retryStats.get(taskName) || { totalRetries: 0 }; current.totalRetries += 1; @@ -141,6 +169,9 @@ export class ScheduledTaskMonitoringService { ); } + /** + * Executes monitor Scheduled Tasks. + */ @Cron(CronExpression.EVERY_MINUTE) monitorScheduledTasks(): void { const now = new Date(); @@ -195,6 +226,10 @@ export class ScheduledTaskMonitoringService { } } + /** + * Retrieves dashboard. + * @returns The operation result. + */ getDashboard() { const now = new Date(); diff --git a/src/notifications/dto/notification.dto.ts b/src/notifications/dto/notification.dto.ts index 48e702b3..a456920f 100644 --- a/src/notifications/dto/notification.dto.ts +++ b/src/notifications/dto/notification.dto.ts @@ -10,6 +10,9 @@ import { } from 'class-validator'; import { NotificationType, NotificationPriority } from '../entities/notification.entity'; +/** + * Defines the create Notification payload. + */ export class CreateNotificationDto { @ApiProperty({ description: 'The ID of the user the notification is for' }) @IsUUID() @@ -42,6 +45,9 @@ export class CreateNotificationDto { metadata?: Record; } +/** + * Defines the update Notification payload. + */ export class UpdateNotificationDto { @ApiPropertyOptional({ description: 'Mark as read or unread' }) @IsBoolean() @@ -49,6 +55,9 @@ export class UpdateNotificationDto { isRead?: boolean; } +/** + * Defines the notification Response payload. + */ export class NotificationResponseDto { @ApiProperty() id: string; diff --git a/src/notifications/email/email.service.ts b/src/notifications/email/email.service.ts index 2becfafd..2b10c243 100644 --- a/src/notifications/email/email.service.ts +++ b/src/notifications/email/email.service.ts @@ -16,6 +16,9 @@ export interface IEmailOptions { context: Record; } +/** + * Provides email operations. + */ @Injectable() export class EmailService { private readonly logger = new Logger(EmailService.name); @@ -41,6 +44,11 @@ export class EmailService { }); } + /** + * Sends verification Email. + * @param email The email address. + * @param token The token value. + */ async sendVerificationEmail(email: string, token: string): Promise { const appUrl = this.configService.get('APP_URL') || 'http://localhost:3000'; @@ -67,6 +75,11 @@ export class EmailService { this.logger.log(`Verification email queued for ${email}`); } + /** + * Sends password Reset Email. + * @param email The email address. + * @param token The token value. + */ async sendPasswordResetEmail(email: string, token: string): Promise { const appUrl = this.configService.get('APP_URL') || 'http://localhost:3000'; @@ -140,6 +153,10 @@ export class EmailService { return template; } + /** + * Validates connection. + * @returns Whether the operation succeeded. + */ async verifyConnection(): Promise { try { await this.transporter.verify(); diff --git a/src/notifications/entities/notification-preferences.entity.ts b/src/notifications/entities/notification-preferences.entity.ts index ed253397..272e8f0a 100644 --- a/src/notifications/entities/notification-preferences.entity.ts +++ b/src/notifications/entities/notification-preferences.entity.ts @@ -10,6 +10,9 @@ import { } from 'typeorm'; import { User } from '../../users/entities/user.entity'; +/** + * Represents the notification Preferences entity. + */ @Entity('notification_preferences') export class NotificationPreferences { @PrimaryGeneratedColumn('uuid') diff --git a/src/notifications/notification-templates.service.ts b/src/notifications/notification-templates.service.ts index 0ab189ac..404ae81e 100644 --- a/src/notifications/notification-templates.service.ts +++ b/src/notifications/notification-templates.service.ts @@ -6,6 +6,9 @@ export interface INotificationTemplate { content: string; } +/** + * Provides notification Templates operations. + */ @Injectable() export class NotificationTemplatesService { private readonly logger = new Logger(NotificationTemplatesService.name); diff --git a/src/notifications/notifications.controller.ts b/src/notifications/notifications.controller.ts index 3cb67cbc..8ed1fad9 100644 --- a/src/notifications/notifications.controller.ts +++ b/src/notifications/notifications.controller.ts @@ -17,6 +17,9 @@ import { CurrentUser } from '../auth/decorators/current-user.decorator'; import { NotificationResponseDto, BulkOperationDto } from './dto/notification.dto'; import { NotificationPreferences } from './entities/notification-preferences.entity'; +/** + * Exposes notifications endpoints. + */ @ApiTags('Notifications') @ApiBearerAuth() @UseGuards(JwtAuthGuard) @@ -24,6 +27,14 @@ import { NotificationPreferences } from './entities/notification-preferences.ent export class NotificationsController { constructor(private readonly notificationsService: NotificationsService) {} + /** + * Returns my Notifications. + * @param userId The user identifier. + * @param isRead The is read. + * @param limit The maximum number of results. + * @param offset The offset. + * @returns The operation result. + */ @Get() @ApiOperation({ summary: 'Get all notifications for current user' }) @ApiResponse({ status: 200, type: [NotificationResponseDto] }) @@ -41,6 +52,12 @@ export class NotificationsController { return { data, total }; } + /** + * Marks as Read. + * @param id The identifier. + * @param userId The user identifier. + * @returns The operation result. + */ @Patch(':id/read') @ApiOperation({ summary: 'Mark a notification as read' }) @ApiParam({ name: 'id', description: 'Notification ID' }) @@ -48,6 +65,11 @@ export class NotificationsController { return this.notificationsService.markAsRead(id, userId); } + /** + * Marks all As Read. + * @param userId The user identifier. + * @returns The operation result. + */ @Patch('read-all') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Mark all notifications as read' }) @@ -55,6 +77,12 @@ export class NotificationsController { await this.notificationsService.markAllAsRead(userId); } + /** + * Removes notification. + * @param id The identifier. + * @param userId The user identifier. + * @returns The operation result. + */ @Delete(':id') @HttpCode(HttpStatus.NO_CONTENT) @ApiOperation({ summary: 'Delete a notification' }) @@ -81,6 +109,12 @@ export class NotificationsController { return this.notificationsService.getPreferences(userId); } + /** + * Updates preferences. + * @param userId The user identifier. + * @param preferencesDto The request payload. + * @returns The operation result. + */ @Patch('preferences') @ApiOperation({ summary: 'Update notification preferences' }) async updatePreferences( diff --git a/src/notifications/notifications.module.ts b/src/notifications/notifications.module.ts index 2c27cc0c..c94015e5 100644 --- a/src/notifications/notifications.module.ts +++ b/src/notifications/notifications.module.ts @@ -15,6 +15,9 @@ import { NotificationsQueueService } from './notifications.queue'; import { Notification } from './entities/notification.entity'; import { NotificationPreferences } from './entities/notification-preferences.entity'; +/** + * Registers the notifications module. + */ @Global() @Module({ imports: [ diff --git a/src/notifications/notifications.service.ts b/src/notifications/notifications.service.ts index f977acc3..764f9b75 100644 --- a/src/notifications/notifications.service.ts +++ b/src/notifications/notifications.service.ts @@ -18,6 +18,9 @@ import { PreferencesService } from './preferences/preferences.service'; import { EmailService } from './email/email.service'; import { sanitizeEmail } from '../common/utils/pii-sanitizer.utils'; +/** + * Provides notification operations. + */ @Injectable() export class NotificationsService { private readonly logger = new Logger(NotificationsService.name); @@ -32,6 +35,11 @@ export class NotificationsService { private readonly queueService: NotificationsQueueService, ) {} + /** + * Sends verification Email. + * @param email The email address. + * @param token The token value. + */ async sendVerificationEmail(email: string, token: string): Promise { try { await this.emailService.sendVerificationEmail(email, token); @@ -45,6 +53,11 @@ export class NotificationsService { } } + /** + * Sends password Reset Email. + * @param email The email address. + * @param token The token value. + */ async sendPasswordResetEmail(email: string, token: string): Promise { try { await this.emailService.sendPasswordResetEmail(email, token); diff --git a/src/notifications/preferences/preferences.service.ts b/src/notifications/preferences/preferences.service.ts index 77fab88c..f7a786e0 100644 --- a/src/notifications/preferences/preferences.service.ts +++ b/src/notifications/preferences/preferences.service.ts @@ -3,6 +3,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { NotificationPreferences } from '../entities/notification-preferences.entity'; +/** + * Provides preferences operations. + */ @Injectable() export class PreferencesService { private readonly logger = new Logger(PreferencesService.name); diff --git a/src/observability/logging/structured-logger.service.ts b/src/observability/logging/structured-logger.service.ts index b8381d2f..bf426f8e 100644 --- a/src/observability/logging/structured-logger.service.ts +++ b/src/observability/logging/structured-logger.service.ts @@ -64,7 +64,19 @@ export class StructuredLoggerService implements LoggerService { * Log info message */ log(message: string, metadata?: Record): void; + /** + * Executes log. + * @param level The level. + * @param message The message. + * @param metadata The data to process. + */ log(level: LogLevel, message: string, metadata?: Record): void; + /** + * Executes log. + * @param messageOrLevel The message or level. + * @param messageOrMetadata The data to process. + * @param metadata The data to process. + */ log( messageOrLevel: string | LogLevel, messageOrMetadata?: string | Record, @@ -105,7 +117,19 @@ export class StructuredLoggerService implements LoggerService { * Log error message */ error(message: string, trace?: string, metadata?: Record): void; + /** + * Executes error. + * @param message The message. + * @param error The error. + * @param metadata The data to process. + */ error(message: string, error?: Error, metadata?: Record): void; + /** + * Executes error. + * @param message The message. + * @param traceOrError The trace or error. + * @param metadata The data to process. + */ error(message: string, traceOrError?: string | Error, metadata?: Record): void { let errorDetails: IErrorDetails | undefined; diff --git a/src/orchestration/discovery/service-discovery.service.ts b/src/orchestration/discovery/service-discovery.service.ts index 3be2d2db..e5f758df 100644 --- a/src/orchestration/discovery/service-discovery.service.ts +++ b/src/orchestration/discovery/service-discovery.service.ts @@ -18,6 +18,9 @@ interface IRegisterServiceInput extends Omit { boundary?: IServiceBoundaryDefinition; } +/** + * Provides service Discovery operations. + */ @Injectable() export class ServiceDiscoveryService { private readonly services = new Map(); diff --git a/src/orchestration/health/health-checker.service.ts b/src/orchestration/health/health-checker.service.ts index 78894eea..9d7de29a 100644 --- a/src/orchestration/health/health-checker.service.ts +++ b/src/orchestration/health/health-checker.service.ts @@ -2,10 +2,18 @@ import { Injectable } from '@nestjs/common'; import { ServiceDiscoveryService } from '../discovery/service-discovery.service'; import axios from 'axios'; +/** + * Provides health Checker operations. + */ @Injectable() export class HealthCheckerService { constructor(private readonly discovery: ServiceDiscoveryService) {} + /** + * Validates check. + * @param serviceName The service name. + * @returns The operation result. + */ async check(serviceName: string) { const service = await this.discovery.getService(serviceName); diff --git a/src/orchestration/locks/distributed-lock.service.ts b/src/orchestration/locks/distributed-lock.service.ts index 219c9dff..273a2903 100644 --- a/src/orchestration/locks/distributed-lock.service.ts +++ b/src/orchestration/locks/distributed-lock.service.ts @@ -1,6 +1,9 @@ import { Injectable } from '@nestjs/common'; import Redis from 'ioredis'; +/** + * Provides distributed Lock operations. + */ @Injectable() export class DistributedLockService { private redis = new Redis(process.env.REDIS_URL); @@ -11,11 +14,21 @@ export class DistributedLockService { }); } + /** + * Executes acquire Lock. + * @param key The key. + * @param ttl The ttl. + * @returns Whether the operation succeeded. + */ async acquireLock(key: string, ttl = 5000): Promise { const result = await this.redis.set(key, 'locked', 'PX', ttl, 'NX'); return result === 'OK'; } + /** + * Executes release Lock. + * @param key The key. + */ async releaseLock(key: string): Promise { await this.redis.del(key); } diff --git a/src/orchestration/orchestration.module.ts b/src/orchestration/orchestration.module.ts index bf610c06..237a3fb3 100644 --- a/src/orchestration/orchestration.module.ts +++ b/src/orchestration/orchestration.module.ts @@ -6,6 +6,9 @@ import { DistributedLockService } from './locks/distributed-lock.service'; import { ServiceDiscoveryService } from './discovery/service-discovery.service'; import { HealthCheckerService } from './health/health-checker.service'; +/** + * Registers the orchestration module. + */ @Global() @Module({ imports: [HttpModule], diff --git a/src/orchestration/service-mesh/service-mesh.service.ts b/src/orchestration/service-mesh/service-mesh.service.ts index cb60c0e1..b6e852c6 100644 --- a/src/orchestration/service-mesh/service-mesh.service.ts +++ b/src/orchestration/service-mesh/service-mesh.service.ts @@ -8,6 +8,9 @@ import { getCorrelationId, } from '../../common/utils/correlation.utils'; +/** + * Provides service Mesh operations. + */ @Injectable() export class ServiceMeshService { constructor( @@ -15,6 +18,14 @@ export class ServiceMeshService { private readonly httpService: HttpService, ) {} + /** + * Executes request. + * @param serviceName The service name. + * @param path The path. + * @param method The method. + * @param data The data to process. + * @returns The resulting t. + */ async request( serviceName: string, path: string, diff --git a/src/orchestration/workflow/workflow-engine.service.ts b/src/orchestration/workflow/workflow-engine.service.ts index 95f78b02..eed17311 100644 --- a/src/orchestration/workflow/workflow-engine.service.ts +++ b/src/orchestration/workflow/workflow-engine.service.ts @@ -6,6 +6,9 @@ interface IWorkflowStep { compensate?: () => Promise; } +/** + * Provides workflow Engine operations. + */ @Injectable() export class WorkflowEngineService { private readonly logger = new Logger(WorkflowEngineService.name); diff --git a/src/payments/dto/create-payment.dto.ts b/src/payments/dto/create-payment.dto.ts index 66c1e1e2..ade55f53 100644 --- a/src/payments/dto/create-payment.dto.ts +++ b/src/payments/dto/create-payment.dto.ts @@ -10,6 +10,9 @@ import { } from 'class-validator'; import { PaymentMethod } from '../entities/payment.entity'; +/** + * Defines the create Payment payload. + */ export class CreatePaymentDto { @IsUUID('4', { message: 'courseId must be a valid UUID v4' }) courseId: string; diff --git a/src/payments/dto/create-subscription.dto.ts b/src/payments/dto/create-subscription.dto.ts index 51528575..c5db6fdc 100644 --- a/src/payments/dto/create-subscription.dto.ts +++ b/src/payments/dto/create-subscription.dto.ts @@ -2,6 +2,9 @@ import { IsString, IsEnum, IsOptional, IsNotEmpty, IsUUID } from 'class-validato import { PaymentMethod } from '../entities/payment.entity'; import { SubscriptionInterval } from '../entities/subscription.entity'; +/** + * Defines the create Subscription payload. + */ export class CreateSubscriptionDto { @IsString() @IsNotEmpty() diff --git a/src/payments/dto/refund.dto.ts b/src/payments/dto/refund.dto.ts index dd9edb06..b8e2f108 100644 --- a/src/payments/dto/refund.dto.ts +++ b/src/payments/dto/refund.dto.ts @@ -10,6 +10,9 @@ import { } from 'class-validator'; import { RefundStatus } from '../entities/refund.entity'; +/** + * Defines the refund payload. + */ export class RefundDto { @IsString() @IsNotEmpty() diff --git a/src/payments/dto/update-payment.dto.ts b/src/payments/dto/update-payment.dto.ts index 0293332c..92e0b8dc 100644 --- a/src/payments/dto/update-payment.dto.ts +++ b/src/payments/dto/update-payment.dto.ts @@ -1,4 +1,7 @@ import { PartialType } from '@nestjs/mapped-types'; import { CreatePaymentDto } from './create-payment.dto'; +/** + * Defines the update Payment payload. + */ export class UpdatePaymentDto extends PartialType(CreatePaymentDto) {} diff --git a/src/payments/entities/invoice.entity.ts b/src/payments/entities/invoice.entity.ts index 785a3a8f..163b8df7 100644 --- a/src/payments/entities/invoice.entity.ts +++ b/src/payments/entities/invoice.entity.ts @@ -27,6 +27,9 @@ interface InvoiceItem { taxRate?: number; } +/** + * Represents the invoice entity. + */ @Entity('invoices') export class Invoice { @PrimaryGeneratedColumn('uuid') diff --git a/src/payments/entities/payment.entity.ts b/src/payments/entities/payment.entity.ts index a96fb33a..e80ca6c0 100644 --- a/src/payments/entities/payment.entity.ts +++ b/src/payments/entities/payment.entity.ts @@ -29,6 +29,9 @@ export enum PaymentMethod { WALLET = 'wallet', } +/** + * Represents the payment entity. + */ @Entity('payments') @Index(['userId', 'status']) export class Payment { diff --git a/src/payments/entities/refund.entity.ts b/src/payments/entities/refund.entity.ts index 4daa9477..36f55f01 100644 --- a/src/payments/entities/refund.entity.ts +++ b/src/payments/entities/refund.entity.ts @@ -19,6 +19,9 @@ export enum RefundStatus { FAILED = 'failed', } +/** + * Represents the refund entity. + */ @Entity('refunds') export class Refund { @PrimaryGeneratedColumn('uuid') diff --git a/src/payments/entities/subscription.entity.ts b/src/payments/entities/subscription.entity.ts index fe21f001..838464d5 100644 --- a/src/payments/entities/subscription.entity.ts +++ b/src/payments/entities/subscription.entity.ts @@ -27,6 +27,9 @@ export enum SubscriptionInterval { WEEKLY = 'weekly', } +/** + * Represents the subscription entity. + */ @Entity('subscriptions') @Index(['userId', 'status']) export class Subscription { diff --git a/src/payments/payments.controller.ts b/src/payments/payments.controller.ts index 06801474..ffac4939 100644 --- a/src/payments/payments.controller.ts +++ b/src/payments/payments.controller.ts @@ -40,12 +40,21 @@ interface IAuthenticatedRequest { }; } +/** + * Exposes payments endpoints. + */ @ApiTags('payments') @Controller('payments') @UseGuards(JwtAuthGuard, RolesGuard) export class PaymentsController { constructor(private readonly paymentsService: PaymentsService) {} + /** + * Creates payment Intent. + * @param req The req. + * @param createPaymentDto The request payload. + * @returns The resulting create payment intent result. + */ @Post('create-intent') @Throttle({ default: THROTTLE.MODERATE }) // 10 requests per hour @Roles(UserRole.STUDENT, UserRole.TEACHER) @@ -66,6 +75,12 @@ export class PaymentsController { return this.paymentsService.createPaymentIntent(req.user.id, createPaymentDto, idempotencyKey); } + /** + * Creates subscription. + * @param req The req. + * @param createSubscriptionDto The request payload. + * @returns The resulting create subscription result. + */ @Post('subscriptions') @Throttle({ default: THROTTLE.AUTH_DEFAULT }) // 5 requests per hour @Roles(UserRole.STUDENT, UserRole.TEACHER) @@ -90,6 +105,11 @@ export class PaymentsController { ); } + /** + * Processes refund. + * @param refundDto The request payload. + * @returns The resulting process refund result. + */ @Post('refund') @Roles(UserRole.ADMIN, UserRole.TEACHER) @Idempotent({ ttl: 86400 }) @@ -108,6 +128,12 @@ export class PaymentsController { return this.paymentsService.processRefund(refundDto, idempotencyKey); } + /** + * Returns invoice. + * @param paymentId The payment identifier. + * @param req The req. + * @returns The resulting invoice. + */ @Get('invoices/:paymentId') @Roles(UserRole.STUDENT, UserRole.TEACHER, UserRole.ADMIN) @ApiOperation({ summary: 'Get invoice for a payment' }) @@ -119,6 +145,13 @@ export class PaymentsController { return this.paymentsService.getInvoice(paymentId, req.user.id); } + /** + * Returns user Payments. + * @param req The req. + * @param limit The maximum number of results. + * @param page The page number. + * @returns The matching results. + */ @Get('user/payments') @Roles(UserRole.STUDENT, UserRole.TEACHER, UserRole.ADMIN) @ApiOperation({ summary: 'Get user payment history' }) @@ -131,6 +164,11 @@ export class PaymentsController { return this.paymentsService.getUserPayments(req.user.id, limit, page); } + /** + * Returns user Subscriptions. + * @param req The req. + * @returns The matching results. + */ @Get('user/subscriptions') @Roles(UserRole.STUDENT, UserRole.TEACHER, UserRole.ADMIN) @ApiOperation({ summary: 'Get user subscriptions' }) diff --git a/src/payments/payments.module.ts b/src/payments/payments.module.ts index fe4b40d1..3ed67391 100644 --- a/src/payments/payments.module.ts +++ b/src/payments/payments.module.ts @@ -26,6 +26,9 @@ import { TransactionService } from '../common/database/transaction.service'; import { TransactionHelperService } from '../common/database/transaction-helper.service'; import { IdempotencyService } from '../common/services/idempotency.service'; +/** + * Registers the payments module. + */ @Module({ imports: [ ConfigModule, diff --git a/src/payments/payments.service.ts b/src/payments/payments.service.ts index 03ddc62f..d4a4a876 100644 --- a/src/payments/payments.service.ts +++ b/src/payments/payments.service.ts @@ -27,6 +27,9 @@ import { IRefundWebhookData, } from './interfaces/payment-provider.interface'; +/** + * Provides payment operations. + */ @Injectable() export class PaymentsService { private readonly logger = new Logger(PaymentsService.name); @@ -139,6 +142,12 @@ export class PaymentsService { }; } + /** + * Creates subscription. + * @param userId The user identifier. + * @param createSubscriptionDto The request payload. + * @returns The resulting create subscription result. + */ async createSubscription( userId: string, createSubscriptionDto: CreateSubscriptionDto, @@ -270,6 +279,13 @@ export class PaymentsService { }; } + /** + * Retrieves user Payments. + * @param userId The user identifier. + * @param limit The maximum number of results. + * @param page The page number. + * @returns The matching results. + */ async getUserPayments(userId: string, limit: number, page: number): Promise { const skip = (page - 1) * limit; @@ -281,6 +297,11 @@ export class PaymentsService { }); } + /** + * Retrieves user Subscriptions. + * @param userId The user identifier. + * @returns The matching results. + */ async getUserSubscriptions(userId: string): Promise { return await this.subscriptionRepository.find({ where: { userId }, @@ -334,6 +355,12 @@ export class PaymentsService { return invoice; } + /** + * Updates payment Status. + * @param paymentId The payment identifier. + * @param status The status value. + * @param metadata The data to process. + */ async updatePaymentStatus( paymentId: string, status: PaymentStatus, diff --git a/src/payments/providers/provider-factory.service.ts b/src/payments/providers/provider-factory.service.ts index 8df38888..b99904be 100644 --- a/src/payments/providers/provider-factory.service.ts +++ b/src/payments/providers/provider-factory.service.ts @@ -1,6 +1,9 @@ import { Injectable } from '@nestjs/common'; import { StripeService } from './stripe.service'; +/** + * Provides provider Factory operations. + */ @Injectable() export class ProviderFactoryService { constructor(private readonly stripeService: StripeService) {} diff --git a/src/payments/providers/stripe.service.ts b/src/payments/providers/stripe.service.ts index a47c8c8e..c4f13103 100644 --- a/src/payments/providers/stripe.service.ts +++ b/src/payments/providers/stripe.service.ts @@ -2,6 +2,9 @@ import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common import { ConfigService } from '@nestjs/config'; import Stripe from 'stripe'; +/** + * Provides stripe operations. + */ @Injectable() export class StripeService { private readonly stripe: Stripe; diff --git a/src/payments/subscriptions/subscriptions.service.ts b/src/payments/subscriptions/subscriptions.service.ts index dd177832..887b62f9 100644 --- a/src/payments/subscriptions/subscriptions.service.ts +++ b/src/payments/subscriptions/subscriptions.service.ts @@ -1,5 +1,8 @@ import { Injectable } from '@nestjs/common'; +/** + * Provides subscriptions operations. + */ @Injectable() export class SubscriptionsService { // Placeholder implementation diff --git a/src/payments/webhooks/dto/webhook-retry.dto.ts b/src/payments/webhooks/dto/webhook-retry.dto.ts index d60ba58b..cb0472d0 100644 --- a/src/payments/webhooks/dto/webhook-retry.dto.ts +++ b/src/payments/webhooks/dto/webhook-retry.dto.ts @@ -2,6 +2,9 @@ import { IsUUID, IsEnum, IsInt, IsDateString, IsOptional, IsObject } from 'class import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { WebhookStatus, WebhookProvider } from '../entities/webhook-retry.entity'; +/** + * Defines the webhook Retry payload. + */ export class WebhookRetryDto { @ApiProperty({ description: 'Webhook retry ID' }) @IsUUID() @@ -54,6 +57,9 @@ export class WebhookRetryDto { processedAt?: Date; } +/** + * Defines the webhook Retry Response payload. + */ export class WebhookRetryResponseDto { @ApiProperty({ description: 'Success status' }) success: boolean; @@ -65,6 +71,9 @@ export class WebhookRetryResponseDto { error?: string; } +/** + * Defines the dead Letter Webhook payload. + */ export class DeadLetterWebhookDto extends WebhookRetryDto { @ApiProperty({ description: 'Indicates this is a dead letter webhook' }) isDead: boolean = true; diff --git a/src/payments/webhooks/entities/webhook-retry.entity.ts b/src/payments/webhooks/entities/webhook-retry.entity.ts index 8d08a320..50de5d97 100644 --- a/src/payments/webhooks/entities/webhook-retry.entity.ts +++ b/src/payments/webhooks/entities/webhook-retry.entity.ts @@ -21,6 +21,9 @@ export enum WebhookProvider { PAYPAL = 'paypal', } +/** + * Represents the webhook Retry entity. + */ @Entity('webhook_retries') @Index(['provider', 'externalEventId'], { unique: true }) @Index(['status', 'nextRetryTime']) diff --git a/src/payments/webhooks/webhook-management.controller.ts b/src/payments/webhooks/webhook-management.controller.ts index e155b89e..ea043313 100644 --- a/src/payments/webhooks/webhook-management.controller.ts +++ b/src/payments/webhooks/webhook-management.controller.ts @@ -3,11 +3,19 @@ import { ApiTags, ApiOperation, ApiResponse, ApiQuery } from '@nestjs/swagger'; import { WebhookQueueService } from './webhook-queue.service'; import { WebhookRetry } from './entities/webhook-retry.entity'; +/** + * Exposes webhook Management endpoints. + */ @ApiTags('webhooks') @Controller('webhooks') export class WebhookManagementController { constructor(private readonly webhookQueueService: WebhookQueueService) {} + /** + * Returns webhook Status. + * @param id The identifier. + * @returns The operation result. + */ @Get('status/:id') @ApiOperation({ summary: 'Get webhook retry status' }) @ApiResponse({ status: 200, description: 'Webhook status retrieved' }) @@ -15,6 +23,11 @@ export class WebhookManagementController { return this.webhookQueueService.getWebhookStatus(id); } + /** + * Returns dead Letter Webhooks. + * @param limit The maximum number of results. + * @returns The matching results. + */ @Get('dead-letter') @ApiOperation({ summary: 'Get dead letter webhooks' }) @ApiResponse({ status: 200, description: 'Dead letter webhooks retrieved' }) @@ -23,6 +36,11 @@ export class WebhookManagementController { return this.webhookQueueService.getDeadLetterWebhooks(limit || 100); } + /** + * Returns pending Webhooks. + * @param limit The maximum number of results. + * @returns The matching results. + */ @Get('pending') @ApiOperation({ summary: 'Get pending webhooks' }) @ApiResponse({ status: 200, description: 'Pending webhooks retrieved' }) @@ -31,6 +49,10 @@ export class WebhookManagementController { return this.webhookQueueService.getPendingWebhooks(limit || 100); } + /** + * Returns processing Webhooks. + * @returns The matching results. + */ @Get('processing') @ApiOperation({ summary: 'Get processing webhooks' }) @ApiResponse({ status: 200, description: 'Processing webhooks retrieved' }) @@ -38,6 +60,11 @@ export class WebhookManagementController { return this.webhookQueueService.getProcessingWebhooks(); } + /** + * Executes requeue Dead Letter Webhook. + * @param id The identifier. + * @returns The operation result. + */ @Post('requeue/:id') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Requeue a dead letter webhook' }) diff --git a/src/payments/webhooks/webhook-queue.service.ts b/src/payments/webhooks/webhook-queue.service.ts index 3caa949f..9af5b9cf 100644 --- a/src/payments/webhooks/webhook-queue.service.ts +++ b/src/payments/webhooks/webhook-queue.service.ts @@ -16,6 +16,9 @@ export interface IWebhookQueuePayload { headers?: Record; } +/** + * Provides webhook Queue operations. + */ @Injectable() export class WebhookQueueService { private readonly logger = new Logger(WebhookQueueService.name); diff --git a/src/payments/webhooks/webhook-retry.processor.ts b/src/payments/webhooks/webhook-retry.processor.ts index aa00dcdb..72b99883 100644 --- a/src/payments/webhooks/webhook-retry.processor.ts +++ b/src/payments/webhooks/webhook-retry.processor.ts @@ -46,6 +46,9 @@ interface IWebhookJobData { headers?: Record; } +/** + * Processes webhook Retry jobs. + */ @Injectable() @Processor(QUEUE_NAMES.WEBHOOKS) export class WebhookRetryProcessor { diff --git a/src/payments/webhooks/webhook.controller.ts b/src/payments/webhooks/webhook.controller.ts index d64b5278..906f95cf 100644 --- a/src/payments/webhooks/webhook.controller.ts +++ b/src/payments/webhooks/webhook.controller.ts @@ -15,12 +15,21 @@ import { SkipThrottle } from '@nestjs/throttler'; import { WebhookService } from './webhook.service'; import { StripeWebhookGuard } from './stripe-webhook.guard'; +/** + * Exposes webhook endpoints. + */ @SkipThrottle() @ApiTags('webhooks') @Controller('webhooks') export class WebhookController { constructor(private readonly webhookService: WebhookService) {} + /** + * Handles stripe Webhook. + * @param signature The signature. + * @param req The req. + * @returns The operation result. + */ @Post('stripe') @HttpCode(HttpStatus.OK) @UseGuards(StripeWebhookGuard) @@ -33,6 +42,16 @@ export class WebhookController { return this.webhookService.handleStripeWebhook(req.rawBody, signature); } + /** + * Handles pay Pal Webhook. + * @param transmissionId The transmission identifier. + * @param transmissionTime The transmission time. + * @param transmissionSig The transmission sig. + * @param certUrl The cert url. + * @param authAlgo The auth algo. + * @param payload The payload to process. + * @returns The operation result. + */ @Post('paypal') @HttpCode(HttpStatus.OK) @ApiOperation({ summary: 'Handle PayPal webhook events' }) diff --git a/src/payments/webhooks/webhook.service.ts b/src/payments/webhooks/webhook.service.ts index b03e96b7..a19abf77 100644 --- a/src/payments/webhooks/webhook.service.ts +++ b/src/payments/webhooks/webhook.service.ts @@ -32,6 +32,9 @@ interface IPayPalWebhookPayload { resource: IPayPalResource; } +/** + * Provides webhook operations. + */ @Injectable() export class WebhookService { private readonly logger = new Logger(WebhookService.name); @@ -42,6 +45,12 @@ export class WebhookService { private readonly webhookQueueService: WebhookQueueService, ) {} + /** + * Handles stripe Webhook. + * @param payload The payload to process. + * @param signature The signature. + * @returns The operation result. + */ async handleStripeWebhook( payload: Buffer | undefined, signature: string, @@ -109,6 +118,16 @@ export class WebhookService { await this.paymentsService.handleSubscriptionEvent(event); } + /** + * Handles pay Pal Webhook. + * @param payload The payload to process. + * @param _transmissionId The transmission identifier. + * @param _transmissionTime The transmission time. + * @param _transmissionSig The transmission sig. + * @param _certUrl The cert url. + * @param _authAlgo The auth algo. + * @returns The operation result. + */ async handlePayPalWebhook( payload: Record, _transmissionId: string, diff --git a/src/queues/processors/default-queue.processor.ts b/src/queues/processors/default-queue.processor.ts index ad2e71fe..14a6d1a6 100644 --- a/src/queues/processors/default-queue.processor.ts +++ b/src/queues/processors/default-queue.processor.ts @@ -19,6 +19,11 @@ export class DefaultQueueProcessor { private readonly workerOrchestration: WorkerOrchestrationService, ) {} + /** + * Handles job. + * @param job The job. + * @returns The operation result. + */ @Process('*') async handleJob(job: Job): Promise { this.logger.log(`Processing job ${job.name} (ID: ${job.id}) - Attempt ${job.attemptsMade + 1}`); @@ -45,6 +50,12 @@ export class DefaultQueueProcessor { ); } + /** + * Executes on Completed. + * @param job The job. + * @param result The result. + * @returns The operation result. + */ @OnQueueCompleted() onCompleted(job: Job, result: any) { const processingTime = (job.finishedOn ?? Date.now()) - (job.processedOn ?? Date.now()); @@ -55,6 +66,12 @@ export class DefaultQueueProcessor { ); } + /** + * Executes on Failed. + * @param job The job. + * @param error The error. + * @returns The operation result. + */ @OnQueueFailed() async onFailed(job: Job, error: Error) { const strategy = this.retryLogicService.getDefaultStrategy(job.name); diff --git a/src/rate-limiting/dto/create-rate-limiting.dto.ts b/src/rate-limiting/dto/create-rate-limiting.dto.ts index fb2a97f7..300132a0 100644 --- a/src/rate-limiting/dto/create-rate-limiting.dto.ts +++ b/src/rate-limiting/dto/create-rate-limiting.dto.ts @@ -17,6 +17,9 @@ export enum RateLimitType { GLOBAL = 'global', } +/** + * Defines the create Rate Limiting payload. + */ export class CreateRateLimitingDto { @ApiProperty({ description: 'Name of the rate limit rule', diff --git a/src/rate-limiting/dto/update-rate-limiting.dto.ts b/src/rate-limiting/dto/update-rate-limiting.dto.ts index e9d61f08..e9c1c06c 100644 --- a/src/rate-limiting/dto/update-rate-limiting.dto.ts +++ b/src/rate-limiting/dto/update-rate-limiting.dto.ts @@ -1,4 +1,7 @@ import { PartialType } from '@nestjs/swagger'; import { CreateRateLimitingDto } from './create-rate-limiting.dto'; +/** + * Defines the update Rate Limiting payload. + */ export class UpdateRateLimitingDto extends PartialType(CreateRateLimitingDto) {} diff --git a/src/rate-limiting/entities/rate-limiting.entity.ts b/src/rate-limiting/entities/rate-limiting.entity.ts index b5bd6b83..37bec8bb 100644 --- a/src/rate-limiting/entities/rate-limiting.entity.ts +++ b/src/rate-limiting/entities/rate-limiting.entity.ts @@ -1 +1,4 @@ +/** + * Represents the rate Limiting entity. + */ export class RateLimiting {} diff --git a/src/rate-limiting/rate-limiting.controller.ts b/src/rate-limiting/rate-limiting.controller.ts index fcee8a74..b689c0c5 100644 --- a/src/rate-limiting/rate-limiting.controller.ts +++ b/src/rate-limiting/rate-limiting.controller.ts @@ -5,31 +5,59 @@ import { CreateRateLimitingDto } from './dto/create-rate-limiting.dto'; import { UpdateRateLimitingDto } from './dto/update-rate-limiting.dto'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; +/** + * Exposes rate Limiting endpoints. + */ @Controller('rate-limiting') export class RateLimitingController { constructor(private readonly rateLimitingService: RateLimitingService) {} + /** + * Creates a new record. + * @param createRateLimitingDto The request payload. + * @returns The operation result. + */ @Post() create(@Body() createRateLimitingDto: CreateRateLimitingDto) { return this.rateLimitingService.create(createRateLimitingDto); } + /** + * Returns all. + * @returns The operation result. + */ @UseGuards(JwtAuthGuard, RateLimitGuard) @Get() findAll() { return this.rateLimitingService.findAll(); } + /** + * Returns one. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id') findOne(@Param('id') id: string) { return this.rateLimitingService.findOne(+id); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateRateLimitingDto The request payload. + * @returns The operation result. + */ @Patch(':id') update(@Param('id') id: string, @Body() updateRateLimitingDto: UpdateRateLimitingDto) { return this.rateLimitingService.update(+id, updateRateLimitingDto); } + /** + * Removes the requested record. + * @param id The identifier. + * @returns The operation result. + */ @Delete(':id') remove(@Param('id') id: string) { return this.rateLimitingService.remove(+id); diff --git a/src/rate-limiting/rate-limiting.service.ts b/src/rate-limiting/rate-limiting.service.ts index 3e63873f..cf14b99e 100644 --- a/src/rate-limiting/rate-limiting.service.ts +++ b/src/rate-limiting/rate-limiting.service.ts @@ -4,25 +4,60 @@ import { UserTier } from './services/quota.service'; import { CreateRateLimitingDto } from './dto/create-rate-limiting.dto'; import { UpdateRateLimitingDto } from './dto/update-rate-limiting.dto'; +/** + * Provides rate Limiting operations. + */ @Injectable() export class RateLimitingService { + /** + * Creates a new record. + * @param _createRateLimitingDto The request payload. + * @returns The operation result. + */ create(_createRateLimitingDto: CreateRateLimitingDto) { throw new Error('Method not implemented.'); } + /** + * Retrieves all matching results. + * @returns The operation result. + */ findAll() { throw new Error('Method not implemented.'); } + /** + * Retrieves the requested record. + * @param _arg0 The arg0. + * @returns The operation result. + */ findOne(_arg0: number) { throw new Error('Method not implemented.'); } + /** + * Updates the requested record. + * @param _arg0 The arg0. + * @param _updateRateLimitingDto The request payload. + * @returns The operation result. + */ update(_arg0: number, _updateRateLimitingDto: UpdateRateLimitingDto) { throw new Error('Method not implemented.'); } + /** + * Removes the requested record. + * @param _arg0 The arg0. + * @returns The operation result. + */ remove(_arg0: number) { throw new Error('Method not implemented.'); } constructor(private readonly throttlingService: ThrottlingService) {} + /** + * Executes protect. + * @param userId The user identifier. + * @param tier The tier. + * @param endpoint The endpoint. + * @returns The operation result. + */ async protect(userId: string, tier: UserTier, endpoint: string) { await this.throttlingService.handleRequest(userId, tier, endpoint); } diff --git a/src/rate-limiting/services/adaptive-rate-limiting.service.ts b/src/rate-limiting/services/adaptive-rate-limiting.service.ts index f896655e..07a6f84f 100644 --- a/src/rate-limiting/services/adaptive-rate-limiting.service.ts +++ b/src/rate-limiting/services/adaptive-rate-limiting.service.ts @@ -1,8 +1,15 @@ import { Injectable } from '@nestjs/common'; import * as os from 'os'; +/** + * Provides adaptive Rate Limiting operations. + */ @Injectable() export class AdaptiveRateLimitingService { + /** + * Retrieves system Load Factor. + * @returns The calculated numeric value. + */ getSystemLoadFactor(): number { const load = os.loadavg()[0]; // 1-minute average const cpuCount = os.cpus().length; @@ -14,6 +21,11 @@ export class AdaptiveRateLimitingService { return 1; } + /** + * Executes adjust Limit. + * @param baseLimit The maximum number of results. + * @returns The calculated numeric value. + */ adjustLimit(baseLimit: number): number { const factor = this.getSystemLoadFactor(); return Math.floor(baseLimit * factor); diff --git a/src/rate-limiting/services/distrubutes.service.ts b/src/rate-limiting/services/distrubutes.service.ts index c6d13431..10125e0a 100644 --- a/src/rate-limiting/services/distrubutes.service.ts +++ b/src/rate-limiting/services/distrubutes.service.ts @@ -1,6 +1,9 @@ import { Injectable, ForbiddenException } from '@nestjs/common'; import Redis from 'ioredis'; +/** + * Provides distributed Limiter operations. + */ @Injectable() export class DistributedLimiterService { private redis: Redis; @@ -12,6 +15,12 @@ export class DistributedLimiterService { }); } + /** + * Executes sliding Window Check. + * @param key The key. + * @param limit The maximum number of results. + * @param windowInSeconds The window in seconds. + */ async slidingWindowCheck(key: string, limit: number, windowInSeconds: number): Promise { const now = Date.now(); const windowStart = now - windowInSeconds * 1000; diff --git a/src/rate-limiting/services/limit-guard/guard.ts b/src/rate-limiting/services/limit-guard/guard.ts index 7bea66f6..68e0fd18 100644 --- a/src/rate-limiting/services/limit-guard/guard.ts +++ b/src/rate-limiting/services/limit-guard/guard.ts @@ -1,10 +1,18 @@ import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; import { RateLimitingService } from '../../rate-limiting.service'; +/** + * Provides rate Limit Guard behavior. + */ @Injectable() export class RateLimitGuard implements CanActivate { constructor(private rateLimiting: RateLimitingService) {} + /** + * Executes can Activate. + * @param context The context. + * @returns Whether the operation succeeded. + */ async canActivate(context: ExecutionContext): Promise { const req = context.switchToHttp().getRequest(); diff --git a/src/rate-limiting/services/quota.service.ts b/src/rate-limiting/services/quota.service.ts index 6f62f864..d37913a0 100644 --- a/src/rate-limiting/services/quota.service.ts +++ b/src/rate-limiting/services/quota.service.ts @@ -7,8 +7,16 @@ export enum UserTier { PREMIUM = 'PREMIUM', } +/** + * Provides quota Management operations. + */ @Injectable() export class QuotaManagementService { + /** + * Retrieves quota For Tier. + * @param tier The tier. + * @returns The operation result. + */ getQuotaForTier(tier: UserTier) { return QUOTA_LIMITS[tier] || QUOTA_LIMITS.DEFAULT; } diff --git a/src/rate-limiting/services/rate-limiting.module.ts b/src/rate-limiting/services/rate-limiting.module.ts index 058e9330..bc751025 100644 --- a/src/rate-limiting/services/rate-limiting.module.ts +++ b/src/rate-limiting/services/rate-limiting.module.ts @@ -5,6 +5,9 @@ import { QuotaManagementService } from './quota.service'; import { AdaptiveRateLimitingService } from './adaptive-rate-limiting.service'; import { DistributedLimiterService } from './distrubutes.service'; +/** + * Registers the rate Limiting module. + */ @Module({ providers: [ RateLimitingService, diff --git a/src/rate-limiting/services/throttling.service.ts b/src/rate-limiting/services/throttling.service.ts index 4aad34ec..9d55d7f5 100644 --- a/src/rate-limiting/services/throttling.service.ts +++ b/src/rate-limiting/services/throttling.service.ts @@ -3,6 +3,9 @@ import { DistributedLimiterService } from './distrubutes.service'; import { QuotaManagementService, UserTier } from './quota.service'; import { AdaptiveRateLimitingService } from './adaptive-rate-limiting.service'; +/** + * Provides throttling operations. + */ @Injectable() export class ThrottlingService { constructor( @@ -11,6 +14,13 @@ export class ThrottlingService { private readonly adaptiveService: AdaptiveRateLimitingService, ) {} + /** + * Handles request. + * @param userId The user identifier. + * @param tier The tier. + * @param endpoint The endpoint. + * @returns The operation result. + */ async handleRequest(userId: string, tier: UserTier, endpoint: string) { if (tier === UserTier.PREMIUM) { return; // bypass diff --git a/src/search/autocomplete/autocomplete.service.ts b/src/search/autocomplete/autocomplete.service.ts index fa175aac..8cb3e0a4 100644 --- a/src/search/autocomplete/autocomplete.service.ts +++ b/src/search/autocomplete/autocomplete.service.ts @@ -3,10 +3,18 @@ import { ElasticsearchService } from '@nestjs/elasticsearch'; import { COURSES_INDEX } from '../search.service'; import { SEARCH_CONSTANTS } from '../search.constants'; +/** + * Provides auto Complete operations. + */ @Injectable() export class AutoCompleteService { constructor(private readonly elasticsearchService: ElasticsearchService) {} + /** + * Retrieves suggestions. + * @param query The query value. + * @returns The matching results. + */ async getSuggestions(query: string): Promise { const sanitizedQuery = (query ?? '').trim().slice(0, 100); if (!sanitizedQuery) { diff --git a/src/search/filters/search-filters.service.ts b/src/search/filters/search-filters.service.ts index bce8c339..91e177a8 100644 --- a/src/search/filters/search-filters.service.ts +++ b/src/search/filters/search-filters.service.ts @@ -3,6 +3,9 @@ import { ElasticsearchService } from '@nestjs/elasticsearch'; import { COURSES_INDEX } from '../search.service'; import { SEARCH_CONSTANTS } from '../search.constants'; +/** + * Provides search Filters operations. + */ @Injectable() export class SearchFiltersService { constructor(private readonly elasticsearchService: ElasticsearchService) {} diff --git a/src/search/indexing/indexing.service.ts b/src/search/indexing/indexing.service.ts index 9216e3a2..c550c27d 100644 --- a/src/search/indexing/indexing.service.ts +++ b/src/search/indexing/indexing.service.ts @@ -2,6 +2,9 @@ import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { ElasticsearchService } from '@nestjs/elasticsearch'; import { COURSES_INDEX, SEARCH_ANALYTICS_INDEX } from '../search.service'; +/** + * Provides indexing operations. + */ @Injectable() export class IndexingService implements OnModuleInit { private readonly logger = new Logger(IndexingService.name); diff --git a/src/search/search.controller.ts b/src/search/search.controller.ts index 9f5e2d2b..9fb6e047 100644 --- a/src/search/search.controller.ts +++ b/src/search/search.controller.ts @@ -8,6 +8,15 @@ import { SearchService } from './search.service'; export class SearchController { constructor(private readonly searchService: SearchService) {} + /** + * Returns search. + * @param query The query value. + * @param filters The filter criteria. + * @param sort The sort. + * @param page The page number. + * @param limit The maximum number of results. + * @returns The operation result. + */ @Get() async search( @Query('q') query: string, @@ -42,16 +51,30 @@ export class SearchController { }); } + /** + * Executes autocomplete. + * @param query The query value. + * @returns The operation result. + */ @Get('autocomplete') async autocomplete(@Query('q') query: string): Promise { return this.searchService.getAutoComplete(query); } + /** + * Returns filters. + * @returns The operation result. + */ @Get('filters') async getFilters(): Promise { return this.searchService.getAvailableFilters(); } + /** + * Returns analytics. + * @param days The days. + * @returns The operation result. + */ @Get('analytics') async getAnalytics(@Query('days') days?: string): Promise { const parsedDays = days ? parseInt(days, 10) : 7; diff --git a/src/search/search.module.ts b/src/search/search.module.ts index 9bc01d1b..9cf8f911 100644 --- a/src/search/search.module.ts +++ b/src/search/search.module.ts @@ -10,6 +10,9 @@ import { SearchIndexOptimizerService } from './indexing/search-index-optimizer.s import { createElasticsearchConfig } from '../config/elasticsearch.config'; import { ElasticsearchService } from './elasticsearch/elasticsearch.service'; +/** + * Registers the search module. + */ @Module({ imports: [ ConfigModule, diff --git a/src/search/search.service.ts b/src/search/search.service.ts index 8202e71c..7c1a0524 100644 --- a/src/search/search.service.ts +++ b/src/search/search.service.ts @@ -42,6 +42,9 @@ type SearchFilters = { price?: { gte?: number; lte?: number; gt?: number; lt?: number }; }; +/** + * Provides search operations. + */ @Injectable() export class SearchService { private readonly logger = new Logger(SearchService.name); @@ -53,6 +56,14 @@ export class SearchService { private readonly cachingService: CachingService, ) {} + /** + * Executes perform Search. + * @param query The query value. + * @param filters The filter criteria. + * @param sort The sort. + * @param options The options. + * @returns The operation result. + */ async performSearch(query: string, filters: any, sort?: string, options: SearchOptions = {}) { const sanitizedQuery = (query ?? '').trim().slice(0, SEARCH_CONSTANTS.MAX_QUERY_LENGTH); const page = Math.max(1, options.page ?? 1); @@ -178,6 +189,11 @@ export class SearchService { ); } + /** + * Retrieves auto Complete. + * @param query The query value. + * @returns The operation result. + */ async getAutoComplete(query: string) { const sanitizedQuery = (query ?? '').trim().slice(0, 100); const cacheKey = `${CACHE_PREFIXES.SEARCH}:autocomplete:${sanitizedQuery}`; @@ -189,6 +205,10 @@ export class SearchService { ); } + /** + * Retrieves available Filters. + * @returns The operation result. + */ async getAvailableFilters() { const cacheKey = `${CACHE_PREFIXES.SEARCH}:filters`; @@ -199,6 +219,11 @@ export class SearchService { ); } + /** + * Retrieves search Analytics. + * @param days The days. + * @returns The operation result. + */ async getSearchAnalytics(days = 7) { const from = new Date(); from.setDate(from.getDate() - days); diff --git a/src/security/audit/audit-logging.service.ts b/src/security/audit/audit-logging.service.ts index 30d22583..563f0a13 100644 --- a/src/security/audit/audit-logging.service.ts +++ b/src/security/audit/audit-logging.service.ts @@ -1,5 +1,8 @@ import { Injectable, Logger } from '@nestjs/common'; +/** + * Provides audit Logging operations. + */ @Injectable() export class AuditLoggingService { private readonly logger = new Logger(AuditLoggingService.name); diff --git a/src/security/compliance/compliance.service.ts b/src/security/compliance/compliance.service.ts index 7e88fe6d..478dacb5 100644 --- a/src/security/compliance/compliance.service.ts +++ b/src/security/compliance/compliance.service.ts @@ -1,5 +1,8 @@ import { Injectable } from '@nestjs/common'; +/** + * Provides compliance operations. + */ @Injectable() export class ComplianceService { async exportUserData(userId: string): Promise { diff --git a/src/security/encryption/encryption.service.ts b/src/security/encryption/encryption.service.ts index 6c1abfe8..722d95ac 100644 --- a/src/security/encryption/encryption.service.ts +++ b/src/security/encryption/encryption.service.ts @@ -1,6 +1,9 @@ import { Injectable } from '@nestjs/common'; import * as crypto from 'crypto'; +/** + * Provides encryption operations. + */ @Injectable() export class EncryptionService { private readonly algorithm = 'aes-256-gcm'; @@ -16,6 +19,11 @@ export class EncryptionService { return secret; } + /** + * Executes encrypt. + * @param text The text. + * @returns The operation result. + */ encrypt(text: string) { const iv = crypto.randomBytes(16); const cipher = crypto.createCipheriv(this.algorithm, this.key, iv); @@ -29,6 +37,11 @@ export class EncryptionService { }; } + /** + * Executes decrypt. + * @param payload The payload to process. + * @returns The operation result. + */ decrypt(payload: { iv: string; content: string; tag: string }) { const decipher = crypto.createDecipheriv( this.algorithm, diff --git a/src/security/security.module.ts b/src/security/security.module.ts index 78e3dff9..c6454ff8 100644 --- a/src/security/security.module.ts +++ b/src/security/security.module.ts @@ -7,6 +7,9 @@ import { ComplianceService } from './compliance/compliance.service'; import { AuditLoggingService } from './audit/audit-logging.service'; import { SecretsModule } from './secrets/secrets.module'; +/** + * Registers the security module. + */ @Module({ imports: [ScheduleModule.forRoot(), SecretsModule], providers: [ diff --git a/src/security/security.service.ts b/src/security/security.service.ts index 7ed9ea5c..de042b5d 100644 --- a/src/security/security.service.ts +++ b/src/security/security.service.ts @@ -1,8 +1,15 @@ import { Injectable } from '@nestjs/common'; import { Cron } from '@nestjs/schedule'; +/** + * Provides security operations. + */ @Injectable() export class SecurityService { + /** + * Executes enforce Retention Policy. + * @returns The operation result. + */ @Cron('0 2 * * *') async enforceRetentionPolicy(): Promise { const retentionDays = Number(process.env.DATA_RETENTION_DAYS); diff --git a/src/security/threats/threat-detection.service.ts b/src/security/threats/threat-detection.service.ts index 76c14e5f..63d49aef 100644 --- a/src/security/threats/threat-detection.service.ts +++ b/src/security/threats/threat-detection.service.ts @@ -1,5 +1,8 @@ import { Injectable, ForbiddenException } from '@nestjs/common'; +/** + * Provides threat Detection operations. + */ @Injectable() export class ThreatDetectionService { private failedAttempts = new Map(); diff --git a/src/session/session.module.ts b/src/session/session.module.ts index 4b9a213c..ca2ed7da 100644 --- a/src/session/session.module.ts +++ b/src/session/session.module.ts @@ -4,6 +4,9 @@ import { getSharedRedisClient } from '../config/cache.config'; import { SESSION_REDIS_CLIENT } from './session.constants'; import { SessionService } from './session.service'; +/** + * Registers the session module. + */ @Global() @Module({ imports: [ConfigModule], diff --git a/src/session/session.service.ts b/src/session/session.service.ts index 85c3ac2e..e3b5231f 100644 --- a/src/session/session.service.ts +++ b/src/session/session.service.ts @@ -13,6 +13,9 @@ interface ISessionRecord { updatedAt: number; } +/** + * Provides session operations. + */ @Injectable() export class SessionService implements OnModuleDestroy { private readonly logger = new Logger(SessionService.name); @@ -45,12 +48,21 @@ export class SessionService implements OnModuleDestroy { ); } + /** + * Executes on Module Destroy. + */ async onModuleDestroy(): Promise { if (this.redis.status !== 'end') { await this.redis.quit(); } } + /** + * Creates session. + * @param userId The user identifier. + * @param metadata The data to process. + * @returns The resulting string value. + */ async createSession(userId: string, metadata: Record = {}): Promise { const sid = randomUUID(); const now = Date.now(); @@ -86,6 +98,11 @@ export class SessionService implements OnModuleDestroy { } } + /** + * Executes touch Session. + * @param sid The sid. + * @param metadataPatch The data to process. + */ async touchSession(sid: string, metadataPatch: Record = {}): Promise { const session = await this.getSession(sid); if (!session) { @@ -109,10 +126,20 @@ export class SessionService implements OnModuleDestroy { .exec(); } + /** + * Removes session. + * @param sid The sid. + */ async removeSession(sid: string): Promise { await this.redis.del(this.sessionKey(sid)); } + /** + * Executes migrate Session. + * @param oldSid The old sid. + * @param newSid The new sid. + * @returns The resulting string value. + */ async migrateSession(oldSid: string, newSid = randomUUID()): Promise { const existing = await this.getSession(oldSid); if (!existing) { @@ -135,6 +162,12 @@ export class SessionService implements OnModuleDestroy { return newSid; } + /** + * Executes with Lock. + * @param lockName The lock name. + * @param handler The handler. + * @returns The resulting t. + */ async withLock(lockName: string, handler: () => Promise): Promise { const lockKey = `lock:${lockName}`; const lockToken = randomUUID(); diff --git a/src/sync/cache/cache-invalidation.service.ts b/src/sync/cache/cache-invalidation.service.ts index 90310b0f..817276f4 100644 --- a/src/sync/cache/cache-invalidation.service.ts +++ b/src/sync/cache/cache-invalidation.service.ts @@ -4,6 +4,9 @@ import { Cache } from 'cache-manager'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { APP_EVENTS } from '../../common/constants/event.constants'; +/** + * Provides cache Invalidation operations. + */ @Injectable() export class CacheInvalidationService { private readonly logger = new Logger(CacheInvalidationService.name); diff --git a/src/sync/conflicts/conflict-resolution.service.ts b/src/sync/conflicts/conflict-resolution.service.ts index 7a5e0175..8bc24ddc 100644 --- a/src/sync/conflicts/conflict-resolution.service.ts +++ b/src/sync/conflicts/conflict-resolution.service.ts @@ -13,6 +13,9 @@ export interface ISyncData { data: any; } +/** + * Provides conflict Resolution operations. + */ @Injectable() export class ConflictResolutionService { private readonly logger = new Logger(ConflictResolutionService.name); diff --git a/src/sync/consistency/data-consistency.service.ts b/src/sync/consistency/data-consistency.service.ts index 6c3d1b63..cc40855b 100644 --- a/src/sync/consistency/data-consistency.service.ts +++ b/src/sync/consistency/data-consistency.service.ts @@ -12,6 +12,9 @@ export interface IntegrityCheckResult { timestamp: Date; } +/** + * Provides data Consistency operations. + */ @Injectable() export class DataConsistencyService { private readonly logger = new Logger(DataConsistencyService.name); diff --git a/src/sync/replication/replication.service.ts b/src/sync/replication/replication.service.ts index 31ee9769..dc2e2970 100644 --- a/src/sync/replication/replication.service.ts +++ b/src/sync/replication/replication.service.ts @@ -13,6 +13,9 @@ export interface IReplicationEvent { timestamp: Date; } +/** + * Provides replication operations. + */ @Injectable() export class ReplicationService { private readonly logger = new Logger(ReplicationService.name); diff --git a/src/sync/sync.module.ts b/src/sync/sync.module.ts index 21f09848..fa410e5d 100644 --- a/src/sync/sync.module.ts +++ b/src/sync/sync.module.ts @@ -7,6 +7,9 @@ import { ConflictResolutionService } from './conflicts/conflict-resolution.servi import { CacheInvalidationService } from './cache/cache-invalidation.service'; import { ReplicationService } from './replication/replication.service'; +/** + * Registers the sync module. + */ @Module({ imports: [ BullModule.registerQueue({ diff --git a/src/sync/sync.service.ts b/src/sync/sync.service.ts index 9dd62360..6b6550ae 100644 --- a/src/sync/sync.service.ts +++ b/src/sync/sync.service.ts @@ -10,6 +10,9 @@ import { DataConsistencyService } from './consistency/data-consistency.service'; import { CacheInvalidationService } from './cache/cache-invalidation.service'; import { ReplicationService } from './replication/replication.service'; +/** + * Provides sync operations. + */ @Injectable() export class SyncService { private readonly logger = new Logger(SyncService.name); diff --git a/src/tenancy/admin/tenant-admin.service.ts b/src/tenancy/admin/tenant-admin.service.ts index 8d20822b..ff564be0 100644 --- a/src/tenancy/admin/tenant-admin.service.ts +++ b/src/tenancy/admin/tenant-admin.service.ts @@ -22,6 +22,9 @@ export interface ITenantHealth { score: number; } +/** + * Provides tenant Admin operations. + */ @Injectable() export class TenantAdminService { constructor( diff --git a/src/tenancy/billing/tenant-billing.service.ts b/src/tenancy/billing/tenant-billing.service.ts index 4fecf748..2dd15d44 100644 --- a/src/tenancy/billing/tenant-billing.service.ts +++ b/src/tenancy/billing/tenant-billing.service.ts @@ -20,6 +20,9 @@ export interface IBillingRecord { invoiceId?: string; } +/** + * Provides tenant Billing operations. + */ @Injectable() export class TenantBillingService { constructor( diff --git a/src/tenancy/customization/customization.service.ts b/src/tenancy/customization/customization.service.ts index 02534003..c1ad6ba8 100644 --- a/src/tenancy/customization/customization.service.ts +++ b/src/tenancy/customization/customization.service.ts @@ -4,6 +4,9 @@ import { Repository } from 'typeorm'; import { TenantCustomization } from '../entities/tenant-customization.entity'; import { UpdateTenantCustomizationDto } from '../dto/tenant.dto'; +/** + * Provides customization operations. + */ @Injectable() export class CustomizationService { constructor( diff --git a/src/tenancy/dto/tenant.dto.ts b/src/tenancy/dto/tenant.dto.ts index 91a62edf..9e8b1498 100644 --- a/src/tenancy/dto/tenant.dto.ts +++ b/src/tenancy/dto/tenant.dto.ts @@ -13,6 +13,9 @@ import { import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { TenantStatus, TenantPlan } from '../entities/tenant.entity'; +/** + * Defines the create Tenant payload. + */ export class CreateTenantDto { @ApiProperty({ example: 'acme-corp' }) @IsString() @@ -77,6 +80,9 @@ export class CreateTenantDto { metadata?: Record; } +/** + * Defines the update Tenant payload. + */ export class UpdateTenantDto { @ApiPropertyOptional({ example: 'Acme Corporation' }) @IsOptional() @@ -135,6 +141,9 @@ export class UpdateTenantDto { metadata?: Record; } +/** + * Defines the update Tenant Config payload. + */ export class UpdateTenantConfigDto { @ApiPropertyOptional({ example: 'en' }) @IsOptional() @@ -182,6 +191,9 @@ export class UpdateTenantConfigDto { customSettings?: Record; } +/** + * Defines the update Tenant Customization payload. + */ export class UpdateTenantCustomizationDto { @ApiPropertyOptional({ example: 'https://example.com/logo.png' }) @IsOptional() diff --git a/src/tenancy/entities/tenant-billing.entity.ts b/src/tenancy/entities/tenant-billing.entity.ts index 8c140184..64464d05 100644 --- a/src/tenancy/entities/tenant-billing.entity.ts +++ b/src/tenancy/entities/tenant-billing.entity.ts @@ -18,6 +18,9 @@ export enum BillingCycle { YEARLY = 'yearly', } +/** + * Represents the tenant Billing entity. + */ @Entity('tenant_billing') export class TenantBilling { @PrimaryGeneratedColumn('uuid') diff --git a/src/tenancy/entities/tenant-config.entity.ts b/src/tenancy/entities/tenant-config.entity.ts index f811ca39..f729ec0a 100644 --- a/src/tenancy/entities/tenant-config.entity.ts +++ b/src/tenancy/entities/tenant-config.entity.ts @@ -12,6 +12,9 @@ import { } from 'typeorm'; import { Tenant } from './tenant.entity'; +/** + * Represents the tenant Config entity. + */ @Entity('tenant_configs') export class TenantConfig { @PrimaryGeneratedColumn('uuid') diff --git a/src/tenancy/entities/tenant-customization.entity.ts b/src/tenancy/entities/tenant-customization.entity.ts index 122c5512..1dc4a2d1 100644 --- a/src/tenancy/entities/tenant-customization.entity.ts +++ b/src/tenancy/entities/tenant-customization.entity.ts @@ -12,6 +12,9 @@ import { } from 'typeorm'; import { Tenant } from './tenant.entity'; +/** + * Represents the tenant Customization entity. + */ @Entity('tenant_customizations') export class TenantCustomization { @PrimaryGeneratedColumn('uuid') diff --git a/src/tenancy/entities/tenant.entity.ts b/src/tenancy/entities/tenant.entity.ts index a298f594..82a1a236 100644 --- a/src/tenancy/entities/tenant.entity.ts +++ b/src/tenancy/entities/tenant.entity.ts @@ -23,6 +23,9 @@ export enum TenantPlan { ENTERPRISE = 'enterprise', } +/** + * Represents the tenant entity. + */ @Entity('tenants') export class Tenant { @PrimaryGeneratedColumn('uuid') diff --git a/src/tenancy/guards/tenant.guard.ts b/src/tenancy/guards/tenant.guard.ts index aadefcb3..315d3e98 100644 --- a/src/tenancy/guards/tenant.guard.ts +++ b/src/tenancy/guards/tenant.guard.ts @@ -3,6 +3,9 @@ import { Reflector } from '@nestjs/core'; import { TENANT_KEY } from '../decorators/requires-tenant.decorator'; import { IsolationService } from '../isolation/isolation.service'; +/** + * Protects tenant execution paths. + */ @Injectable() export class TenantGuard implements CanActivate { constructor( @@ -10,6 +13,11 @@ export class TenantGuard implements CanActivate { private isolationService: IsolationService, ) {} + /** + * Executes can Activate. + * @param context The context. + * @returns Whether the operation succeeded. + */ async canActivate(context: ExecutionContext): Promise { const requiresTenant = this.reflector.getAllAndOverride(TENANT_KEY, [ context.getHandler(), diff --git a/src/tenancy/tenancy.controller.ts b/src/tenancy/tenancy.controller.ts index eba6e926..3968c04c 100644 --- a/src/tenancy/tenancy.controller.ts +++ b/src/tenancy/tenancy.controller.ts @@ -26,6 +26,9 @@ import { Roles } from '../auth/decorators/roles.decorator'; import { UserRole } from '../users/entities/user.entity'; import { TenantPlan } from './entities/tenant.entity'; +/** + * Exposes tenancy endpoints. + */ @ApiTags('tenancy') @Controller('tenants') @UseGuards(JwtAuthGuard, RolesGuard) @@ -38,6 +41,11 @@ export class TenancyController { private readonly customizationService: CustomizationService, ) {} + /** + * Creates a new record. + * @param createTenantDto The request payload. + * @returns The operation result. + */ @Post() @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Create a new tenant (Admin only)' }) @@ -45,6 +53,12 @@ export class TenancyController { return this.tenancyService.create(createTenantDto); } + /** + * Returns all. + * @param page The page number. + * @param limit The maximum number of results. + * @returns The operation result. + */ @Get() @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Get all tenants (Admin only)' }) @@ -54,6 +68,11 @@ export class TenancyController { return this.tenancyService.findAll(page, limit); } + /** + * Returns search. + * @param query The query value. + * @returns The operation result. + */ @Get('search') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Search tenants (Admin only)' }) @@ -62,30 +81,56 @@ export class TenancyController { return this.adminService.searchTenants(query); } + /** + * Returns one. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id') @ApiOperation({ summary: 'Get tenant by ID' }) findOne(@Param('id') id: string) { return this.tenancyService.findOne(id); } + /** + * Returns tenant With Relations. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/full') @ApiOperation({ summary: 'Get tenant with all related data' }) getTenantWithRelations(@Param('id') id: string) { return this.tenancyService.getTenantWithRelations(id); } + /** + * Returns statistics. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/statistics') @ApiOperation({ summary: 'Get tenant statistics' }) getStatistics(@Param('id') id: string) { return this.adminService.getTenantStatistics(id); } + /** + * Validates health. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/health') @ApiOperation({ summary: 'Check tenant health' }) checkHealth(@Param('id') id: string) { return this.adminService.checkTenantHealth(id); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateTenantDto The request payload. + * @returns The operation result. + */ @Patch(':id') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Update tenant (Admin only)' }) @@ -93,6 +138,11 @@ export class TenancyController { return this.tenancyService.update(id, updateTenantDto); } + /** + * Removes the requested record. + * @param id The identifier. + * @returns The operation result. + */ @Delete(':id') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Delete tenant (Admin only)' }) @@ -101,12 +151,23 @@ export class TenancyController { } // Configuration endpoints + /** + * Returns config. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/config') @ApiOperation({ summary: 'Get tenant configuration' }) getConfig(@Param('id') id: string) { return this.tenancyService.getConfig(id); } + /** + * Updates config. + * @param id The identifier. + * @param updateConfigDto The request payload. + * @returns The operation result. + */ @Patch(':id/config') @ApiOperation({ summary: 'Update tenant configuration' }) updateConfig(@Param('id') id: string, @Body() updateConfigDto: UpdateTenantConfigDto) { @@ -114,18 +175,33 @@ export class TenancyController { } // Billing endpoints + /** + * Returns billing. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/billing') @ApiOperation({ summary: 'Get tenant billing information' }) getBilling(@Param('id') id: string) { return this.billingService.getBillingInfo(id); } + /** + * Returns billing History. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/billing/history') @ApiOperation({ summary: 'Get tenant billing history' }) getBillingHistory(@Param('id') id: string) { return this.billingService.getBillingHistory(id); } + /** + * Generates invoice. + * @param id The identifier. + * @returns The operation result. + */ @Post(':id/billing/invoice') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Generate invoice for tenant (Admin only)' }) @@ -134,12 +210,23 @@ export class TenancyController { } // Customization endpoints + /** + * Returns customization. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/customization') @ApiOperation({ summary: 'Get tenant customization' }) getCustomization(@Param('id') id: string) { return this.customizationService.getCustomization(id); } + /** + * Updates customization. + * @param id The identifier. + * @param updateCustomizationDto The request payload. + * @returns The operation result. + */ @Patch(':id/customization') @ApiOperation({ summary: 'Update tenant customization' }) updateCustomization( @@ -150,6 +237,12 @@ export class TenancyController { } // Admin operations + /** + * Executes suspend. + * @param id The identifier. + * @param reason The reason. + * @returns The operation result. + */ @Post(':id/suspend') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Suspend tenant (Admin only)' }) @@ -157,6 +250,11 @@ export class TenancyController { return this.adminService.suspendTenant(id, reason); } + /** + * Executes activate. + * @param id The identifier. + * @returns The operation result. + */ @Post(':id/activate') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Activate tenant (Admin only)' }) @@ -164,6 +262,12 @@ export class TenancyController { return this.adminService.activateTenant(id); } + /** + * Executes upgrade Plan. + * @param id The identifier. + * @param plan The plan. + * @returns The operation result. + */ @Post(':id/upgrade') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Upgrade tenant plan (Admin only)' }) @@ -171,6 +275,11 @@ export class TenancyController { return this.adminService.upgradePlan(id, plan); } + /** + * Resets data. + * @param id The identifier. + * @returns The operation result. + */ @Post(':id/reset-data') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Reset tenant data (Admin only)' }) @@ -178,6 +287,11 @@ export class TenancyController { return this.adminService.resetTenantData(id); } + /** + * Exports data. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id/export') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Export tenant data (Admin only)' }) diff --git a/src/tenancy/tenancy.module.ts b/src/tenancy/tenancy.module.ts index ec57a7eb..d69b880b 100644 --- a/src/tenancy/tenancy.module.ts +++ b/src/tenancy/tenancy.module.ts @@ -15,6 +15,9 @@ import { TenantMiddleware } from '../middleware/tenant/tenant.middleware'; import { TenantRlsSubscriber } from '../middleware/tenant/tenant-rls.subscriber'; import { TenantAccessValidationGuard } from '../middleware/tenant/tenant-access-validation.guard'; +/** + * Registers the tenancy module. + */ @Module({ imports: [TypeOrmModule.forFeature([Tenant, TenantConfig, TenantBilling, TenantCustomization])], controllers: [TenancyController], diff --git a/src/tenancy/tenancy.service.ts b/src/tenancy/tenancy.service.ts index cbe4860a..b00c39d9 100644 --- a/src/tenancy/tenancy.service.ts +++ b/src/tenancy/tenancy.service.ts @@ -10,6 +10,9 @@ import { TenantBillingService } from './billing/tenant-billing.service'; import { CustomizationService } from './customization/customization.service'; import { TENANT_DEFAULTS } from './tenancy.constants'; +/** + * Provides tenancy operations. + */ @Injectable() export class TenancyService { constructor( diff --git a/src/users/dto/create-user.dto.ts b/src/users/dto/create-user.dto.ts index c6fa115d..25df487b 100644 --- a/src/users/dto/create-user.dto.ts +++ b/src/users/dto/create-user.dto.ts @@ -3,6 +3,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { UserRole } from '../entities/user.entity'; import { IsStrongPassword } from '../../common/validators/password.validator'; +/** + * Defines the create User payload. + */ export class CreateUserDto { @ApiProperty({ example: 'john.doe@example.com' }) @IsEmail({}, { message: 'Please provide a valid email format' }) diff --git a/src/users/dto/get-users.dto.ts b/src/users/dto/get-users.dto.ts index 559d1e5e..edaaecb5 100644 --- a/src/users/dto/get-users.dto.ts +++ b/src/users/dto/get-users.dto.ts @@ -1,6 +1,9 @@ import { IsOptional, IsString } from 'class-validator'; import { PaginationQueryDto } from '../../common/dto/pagination.dto'; +/** + * Defines the get Users payload. + */ export class GetUsersDto extends PaginationQueryDto { @IsOptional() @IsString() diff --git a/src/users/dto/update-user.dto.ts b/src/users/dto/update-user.dto.ts index a03365ad..383d9b0f 100644 --- a/src/users/dto/update-user.dto.ts +++ b/src/users/dto/update-user.dto.ts @@ -2,6 +2,9 @@ import { PartialType } from '@nestjs/swagger'; import { IsBoolean, IsOptional, IsString, MinLength, IsEmail } from 'class-validator'; import { CreateUserDto } from './create-user.dto'; +/** + * Defines the update User payload. + */ export class UpdateUserDto extends PartialType(CreateUserDto) { @IsOptional() @IsString() diff --git a/src/users/entities/user.entity.ts b/src/users/entities/user.entity.ts index 6e20c3fc..c8c5406c 100644 --- a/src/users/entities/user.entity.ts +++ b/src/users/entities/user.entity.ts @@ -24,6 +24,9 @@ export enum UserStatus { SUSPENDED = 'suspended', } +/** + * Represents the user entity. + */ @Entity('users') export class User { @PrimaryGeneratedColumn('uuid') diff --git a/src/users/users.controller.ts b/src/users/users.controller.ts index 8dd1cd09..e7c3dae6 100644 --- a/src/users/users.controller.ts +++ b/src/users/users.controller.ts @@ -26,6 +26,9 @@ import { UserRole } from './entities/user.entity'; import { ExportFormat, ExportService } from '../common/export/export.service'; import { MaskingInterceptor } from '../utils/masking/masking.interceptor'; +/** + * Exposes users endpoints. + */ @ApiTags('users') @Controller('users') @UseGuards(JwtAuthGuard, RolesGuard) @@ -37,6 +40,11 @@ export class UsersController { private readonly exportService: ExportService, ) {} + /** + * Creates a new record. + * @param createUserDto The request payload. + * @returns The operation result. + */ @Post() @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Create a new user (Admin only)' }) @@ -44,6 +52,10 @@ export class UsersController { return this.usersService.create(createUserDto); } + /** + * Returns all. + * @returns The operation result. + */ @Get() @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Get all users (Admin only)' }) @@ -51,18 +63,34 @@ export class UsersController { return this.usersService.findAll(); } + /** + * Returns one. + * @param id The identifier. + * @returns The operation result. + */ @Get(':id') @ApiOperation({ summary: 'Get user by ID' }) findOne(@Param('id') id: string) { return this.usersService.findOne(id); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateUserDto The request payload. + * @returns The operation result. + */ @Patch(':id') @ApiOperation({ summary: 'Update user' }) update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) { return this.usersService.update(id, updateUserDto); } + /** + * Removes the requested record. + * @param id The identifier. + * @returns The operation result. + */ @Delete(':id') @Roles(UserRole.ADMIN) @ApiOperation({ summary: 'Delete user (Admin only)' }) @@ -94,12 +122,24 @@ export class UsersController { return this.exportService.requestUserDataExport(user.userId, body?.format ?? 'json'); } + /** + * Returns export History. + * @param user The user. + * @returns The operation result. + */ @Get('me/export/history') @ApiOperation({ summary: 'Get export request history for the current user' }) getExportHistory(@CurrentUser() user: { userId: string }) { return this.exportService.getUserExportHistory(user.userId); } + /** + * Downloads export. + * @param user The user. + * @param exportId The export identifier. + * @param res The res. + * @returns The operation result. + */ @Get('me/export/:exportId') @ApiOperation({ summary: 'Download a completed user export file' }) async downloadExport( diff --git a/src/users/users.module.ts b/src/users/users.module.ts index 19a844a5..6416d473 100644 --- a/src/users/users.module.ts +++ b/src/users/users.module.ts @@ -18,6 +18,9 @@ import { AuditLogModule } from '../audit-log/audit-log.module'; import { MaskingAuditService } from '../utils/masking/masking-audit.service'; import { MaskingInterceptor } from '../utils/masking/masking.interceptor'; +/** + * Registers the users module. + */ @Module({ imports: [ TypeOrmModule.forFeature([User, Enrollment, UserExportHistory]), diff --git a/src/users/users.service.ts b/src/users/users.service.ts index c5ffe248..4dc51fc4 100644 --- a/src/users/users.service.ts +++ b/src/users/users.service.ts @@ -16,6 +16,9 @@ import { EventEmitter2 } from '@nestjs/event-emitter'; import { ConfigService } from '@nestjs/config'; import { USER_CONSTANTS } from './user.constants'; +/** + * Provides user operations. + */ @Injectable() export class UsersService { constructor( @@ -26,6 +29,11 @@ export class UsersService { private readonly configService: ConfigService, ) {} + /** + * Creates a new record. + * @param createUserDto The request payload. + * @returns The resulting user. + */ async create(createUserDto: CreateUserDto): Promise { // Check if user already exists const existingUser = await this.userRepository.findOne({ @@ -85,6 +93,11 @@ export class UsersService { ); } + /** + * Retrieves records by their identifiers. + * @param ids The identifiers. + * @returns The matching results. + */ async findByIds(ids: string[]): Promise { if (ids.length === 0) return []; return await this.userRepository.findByIds(ids); @@ -99,6 +112,11 @@ export class UsersService { return ensureUserExists(user, 'User not found'); } + /** + * Retrieves the requested record. + * @param id The identifier. + * @returns The resulting user. + */ async findOne(id: string): Promise { const cacheKey = `${CACHE_PREFIXES.USER_PROFILE}:${id}`; @@ -111,22 +129,43 @@ export class UsersService { ); } + /** + * Retrieves a record by email address. + * @param email The email address. + * @returns The operation result. + */ async findByEmail(email: string): Promise { return await this.userRepository.findOne({ where: { email } }); } + /** + * Retrieves a record by password reset token. + * @param token The token value. + * @returns The operation result. + */ async findByPasswordResetToken(token: string): Promise { return await this.userRepository.findOne({ where: { passwordResetToken: token }, }); } + /** + * Retrieves a record by email verification token. + * @param token The token value. + * @returns The operation result. + */ async findByEmailVerificationToken(token: string): Promise { return await this.userRepository.findOne({ where: { emailVerificationToken: token }, }); } + /** + * Updates the requested record. + * @param id The identifier. + * @param updateUserDto The request payload. + * @returns The resulting user. + */ async update(id: string, updateUserDto: UpdateUserDto): Promise { const user = await this.findUserOrThrow(id); @@ -160,12 +199,23 @@ export class UsersService { return saved; } + /** + * Updates the stored refresh token. + * @param userId The user identifier. + * @param refreshToken The token value. + */ async updateRefreshToken(userId: string, refreshToken: string | null): Promise { await this.userRepository.update(userId, { refreshToken: refreshToken as unknown as string }); // Invalidate user cache this.eventEmitter.emit(CACHE_EVENTS.USER_UPDATED, { userId }); } + /** + * Updates the password reset token. + * @param userId The user identifier. + * @param token The token value. + * @param expires The expires. + */ async updatePasswordResetToken( userId: string, token: string | null, @@ -177,6 +227,12 @@ export class UsersService { }); } + /** + * Updates the email verification token. + * @param userId The user identifier. + * @param token The token value. + * @param expires The expires. + */ async updateEmailVerificationToken( userId: string, token: string | null, @@ -188,10 +244,18 @@ export class UsersService { }); } + /** + * Updates the last login timestamp. + * @param userId The user identifier. + */ async updateLastLogin(userId: string): Promise { await this.userRepository.update(userId, { lastLoginAt: new Date() }); } + /** + * Removes the requested record. + * @param id The identifier. + */ async remove(id: string): Promise { await this.findUserOrThrow(id); await this.userRepository.softDelete(id);