mcp-quiz-server
Version:
🧠AI-Powered Quiz Management via Model Context Protocol (MCP) - Create, manage, and take quizzes directly from VS Code, Claude, and other AI agents.
185 lines (184 loc) • 5.45 kB
JavaScript
"use strict";
/**
* @fileoverview Quiz Completed Domain Event
* @version 1.0.0
* @since 2025-07-29
* @lastUpdated 2025-07-29
* @module QuizCompletedEvent Domain Event
* @description Domain event fired when a user completes a quiz
* @contributors Claude Code Agent
* @dependencies DomainEvent base class
* @requirements REQ-ARCH-001 (Clean Architecture Domain Layer)
* @testCoverage Unit tests for event creation and serialization
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.QuizCompletedEvent = void 0;
const DomainEvent_1 = require("./DomainEvent");
/**
* Quiz Completed Event
*
* @description Domain event that signals a user has completed a quiz.
* This event can trigger score calculations, analytics updates,
* achievements, notifications, or leaderboard updates.
*
* @example
* ```typescript
* const event = new QuizCompletedEvent(
* 'quiz-123',
* 'user-456',
* 8,
* 10,
* 80.0,
* { 'q1': 'answer1', 'q2': 'answer2' }
* );
* ```
*
* @since 2025-07-29
* @author Claude Code Agent
* @requirements REQ-ARCH-001 (Clean Architecture Domain Layer)
*/
class QuizCompletedEvent extends DomainEvent_1.DomainEvent {
constructor(quizId, userId, score, totalQuestions, percentage, answers, completionTimeMs) {
super('QuizCompleted', 1);
this.quizId = quizId;
this.userId = userId;
this.score = score;
this.totalQuestions = totalQuestions;
this.percentage = percentage;
this.answers = answers;
this.completionTimeMs = completionTimeMs;
}
/**
* Get the aggregate ID (Quiz ID) that this event relates to
*/
getAggregateId() {
return this.quizId;
}
/**
* Get event payload for serialization
*/
getEventData() {
return {
quizId: this.quizId,
userId: this.userId,
score: this.score,
totalQuestions: this.totalQuestions,
percentage: this.percentage,
answersCount: Object.keys(this.answers).length,
completionTimeMs: this.completionTimeMs,
// Note: We don't include actual answers for privacy/security
answerIds: Object.keys(this.answers),
};
}
/**
* Business Logic Methods
*/
/**
* Check if this is a perfect score
*/
get isPerfectScore() {
return this.score === this.totalQuestions;
}
/**
* Check if this is a passing score (>= 70%)
*/
get isPassingScore() {
return this.percentage >= 70;
}
/**
* Check if this is a high score (>= 90%)
*/
get isHighScore() {
return this.percentage >= 90;
}
/**
* Get performance level
*/
get performanceLevel() {
if (this.percentage >= 90)
return 'excellent';
if (this.percentage >= 80)
return 'good';
if (this.percentage >= 70)
return 'average';
return 'needs_improvement';
}
/**
* Get grade letter based on percentage
*/
get letterGrade() {
if (this.percentage >= 90)
return 'A';
if (this.percentage >= 80)
return 'B';
if (this.percentage >= 70)
return 'C';
if (this.percentage >= 60)
return 'D';
return 'F';
}
/**
* Check if all questions were answered
*/
get areAllQuestionsAnswered() {
return Object.keys(this.answers).length === this.totalQuestions;
}
/**
* Get completion rate as a decimal (0-1)
*/
get completionRate() {
return Object.keys(this.answers).length / this.totalQuestions;
}
/**
* Check if completion was fast (if time data available)
*/
get isFastCompletion() {
if (!this.completionTimeMs)
return false;
// Business rule: Less than 30 seconds per question is considered fast
const averageTimePerQuestion = this.completionTimeMs / this.totalQuestions;
return averageTimePerQuestion < 30000; // 30 seconds in ms
}
/**
* Get achievement triggers based on performance
*/
get achievements() {
const achievements = [];
if (this.isPerfectScore)
achievements.push('perfect_score');
if (this.isHighScore)
achievements.push('high_score');
if (this.areAllQuestionsAnswered)
achievements.push('completionist');
if (this.isFastCompletion)
achievements.push('speed_demon');
if (this.isPassingScore)
achievements.push('passed');
return achievements;
}
/**
* Check if this result should trigger notifications
*/
get shouldNotify() {
return this.isPerfectScore || this.isHighScore || !this.isPassingScore;
}
/**
* Get notification priority level
*/
get notificationPriority() {
if (this.isPerfectScore)
return 'high';
if (this.isHighScore)
return 'medium';
if (!this.isPassingScore)
return 'medium';
return 'low';
}
/**
* String representation for logging
*/
toString() {
return `QuizCompleted: User ${this.userId} scored ${this.score}/${this.totalQuestions} (${this.percentage}%) on quiz ${this.quizId}`;
}
}
exports.QuizCompletedEvent = QuizCompletedEvent;