Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
130 changes: 130 additions & 0 deletions src/ab-testing/ab-testing.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -35,19 +38,33 @@ export class ABTestingController {
private reportsService: ABTestingReportsService,
) {}

/**
* Returns all Experiments.
* @returns The operation result.
*/
@Get('experiments')
@Roles(UserRole.ADMIN, UserRole.TEACHER)
async getAllExperiments(): Promise<any> {
this.logger.log('Fetching all experiments');
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<any> {
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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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<any> {
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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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<any> {
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<any> {
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)
Expand All @@ -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<any> {
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)
Expand All @@ -159,31 +245,54 @@ 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<any> {
this.logger.log('Generating dashboard summary');
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<any> {
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<any> {
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<any> {
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<any> {
this.logger.log(`Exporting data for experiment: ${id}`);
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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(
Expand Down
3 changes: 3 additions & 0 deletions src/ab-testing/ab-testing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand Down
3 changes: 3 additions & 0 deletions src/ab-testing/ab-testing.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export interface ICreateMetricDto {
configuration?: any;
}

/**
* Provides aBTesting operations.
*/
@Injectable()
export class ABTestingService {
private readonly logger = new Logger(ABTestingService.name);
Expand Down
3 changes: 3 additions & 0 deletions src/ab-testing/analysis/statistical-analysis.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src/ab-testing/automation/automated-decision.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions src/ab-testing/entities/experiment-metric.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ export enum MetricType {
CUSTOM = 'custom',
}

/**
* Represents the experiment Metric entity.
*/
@Entity({ name: 'experiment_metrics' })
export class ExperimentMetric {
@PrimaryGeneratedColumn('uuid')
Expand Down
3 changes: 3 additions & 0 deletions src/ab-testing/entities/experiment-variant.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
3 changes: 3 additions & 0 deletions src/ab-testing/entities/experiment.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
3 changes: 3 additions & 0 deletions src/ab-testing/entities/variant-metric.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
3 changes: 3 additions & 0 deletions src/ab-testing/experiments/experiment.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading
Loading