From 0563d4bc9ba7e72302fbc6d62746fdcf17cee919 Mon Sep 17 00:00:00 2001 From: Adrian Flores Cortes Date: Mon, 26 Jan 2026 18:02:18 -0600 Subject: [PATCH] fix(coherence): Align education types with DDL (E-COH-005, ST1.5) - Updated src/modules/education/types/education.types.ts with DDL alignment - Added all missing enums: DifficultyLevel, CourseStatus, LessonContentType, etc. - Added AchievementType enum (course_completion, quiz_perfect_score, etc.) - Updated Course interface to match DDL fields exactly - Updated Module interface (displayOrder, xpReward) - Updated Lesson interface (LessonContentType, attachments, displayOrder) - Updated Enrollment interface (completedLessons, totalLessons, totalXpEarned) - Updated LessonProgress interface (isCompleted, videoProgressSeconds, xpEarned) - Updated Quiz interface (passingScorePercentage, xpReward, xpPerfectScoreBonus) - Updated QuizQuestion interface (displayOrder) - Updated QuizAttempt interface (scorePoints, maxPoints, scorePercentage, xpEarned) - Added new interfaces: Certificate, UserAchievement, UserGamificationProfile, UserActivityLog - Added LessonAttachment interface for JSONB attachments field - Deprecated old type aliases for backward compatibility All types now fully aligned with education.* DDL schema. Note: Services will need migration in separate task (breaking changes documented). Co-Authored-By: Claude Opus 4.5 --- .../education/types/education.types.ts | 355 ++++++++++++++---- 1 file changed, 273 insertions(+), 82 deletions(-) diff --git a/src/modules/education/types/education.types.ts b/src/modules/education/types/education.types.ts index 6e5c6c3..e5cb1cb 100644 --- a/src/modules/education/types/education.types.ts +++ b/src/modules/education/types/education.types.ts @@ -1,16 +1,83 @@ /** * Education Module Types + * Type definitions for education module + * Aligned with education.* DDL schema (apps/database/ddl/schemas/education/00-enums.sql) */ // ============================================================================ -// Enums +// Enums (Aligned with DDL) // ============================================================================ -export type CourseLevel = 'beginner' | 'intermediate' | 'advanced' | 'expert'; +// Alineado con education.difficulty_level (DDL) +export type DifficultyLevel = 'beginner' | 'intermediate' | 'advanced' | 'expert'; + +export enum DifficultyLevelEnum { + BEGINNER = 'beginner', + INTERMEDIATE = 'intermediate', + ADVANCED = 'advanced', + EXPERT = 'expert', +} + +/** + * @deprecated Use DifficultyLevel instead for DDL alignment + */ +export type CourseLevel = DifficultyLevel; + +// Alineado con education.course_status (DDL) export type CourseStatus = 'draft' | 'published' | 'archived'; + +export enum CourseStatusEnum { + DRAFT = 'draft', + PUBLISHED = 'published', + ARCHIVED = 'archived', +} + +// Alineado con education.lesson_content_type (DDL) +export type LessonContentType = 'video' | 'article' | 'interactive' | 'quiz'; + +export enum LessonContentTypeEnum { + VIDEO = 'video', + ARTICLE = 'article', + INTERACTIVE = 'interactive', + QUIZ = 'quiz', +} + +/** + * @deprecated Use LessonContentType instead for DDL alignment + */ export type ContentType = 'video' | 'text' | 'quiz' | 'exercise' | 'resource'; + +// Alineado con education.enrollment_status (DDL) export type EnrollmentStatus = 'active' | 'completed' | 'expired' | 'cancelled'; -export type QuestionType = 'multiple_choice' | 'true_false' | 'multiple_answer' | 'short_answer'; + +export enum EnrollmentStatusEnum { + ACTIVE = 'active', + COMPLETED = 'completed', + EXPIRED = 'expired', + CANCELLED = 'cancelled', +} + +// Alineado con education.question_type (DDL) +export type QuestionType = 'multiple_choice' | 'true_false' | 'multiple_select' | 'fill_blank' | 'code_challenge'; + +export enum QuestionTypeEnum { + MULTIPLE_CHOICE = 'multiple_choice', + TRUE_FALSE = 'true_false', + MULTIPLE_SELECT = 'multiple_select', + FILL_BLANK = 'fill_blank', + CODE_CHALLENGE = 'code_challenge', +} + +// Alineado con education.achievement_type (DDL) +export type AchievementType = 'course_completion' | 'quiz_perfect_score' | 'streak_milestone' | 'level_up' | 'special_event'; + +export enum AchievementTypeEnum { + COURSE_COMPLETION = 'course_completion', + QUIZ_PERFECT_SCORE = 'quiz_perfect_score', + STREAK_MILESTONE = 'streak_milestone', + LEVEL_UP = 'level_up', + SPECIAL_EVENT = 'special_event', +} // ============================================================================ // Category @@ -38,34 +105,34 @@ export interface CreateCategoryInput { } // ============================================================================ -// Course +// Course (Aligned with education.courses DDL) // ============================================================================ export interface Course { id: string; title: string; slug: string; - description?: string; shortDescription?: string; + fullDescription?: string; + categoryId: string; + difficultyLevel: DifficultyLevel; thumbnailUrl?: string; - previewVideoUrl?: string; - categoryId?: string; - level: CourseLevel; - tags: string[]; - isFree: boolean; - price: number; - currency: string; - requiresSubscription: boolean; - minSubscriptionTier?: string; + trailerUrl?: string; durationMinutes?: number; - lessonsCount: number; - enrolledCount: number; - averageRating: number; - ratingsCount: number; + prerequisites?: string[]; + learningObjectives?: string[]; + instructorId: string; + instructorName?: string; + isFree: boolean; + priceUsd?: number; + xpReward: number; status: CourseStatus; publishedAt?: Date; - instructorId?: string; - aiGenerated: boolean; + totalModules: number; + totalLessons: number; + totalEnrollments: number; + avgRating: number; + totalReviews: number; createdAt: Date; updatedAt: Date; } @@ -119,7 +186,7 @@ export interface CourseFilters { } // ============================================================================ -// Module +// Module (Aligned with education.modules DDL) // ============================================================================ export interface Module { @@ -127,8 +194,8 @@ export interface Module { courseId: string; title: string; description?: string; - sortOrder: number; - unlockAfterModuleId?: string; + displayOrder: number; + xpReward: number; createdAt: Date; updatedAt: Date; } @@ -146,32 +213,25 @@ export interface CreateModuleInput { } // ============================================================================ -// Lesson +// Lesson (Aligned with education.lessons DDL) // ============================================================================ -export interface LessonResource { - name: string; - url: string; - type: string; -} - export interface Lesson { id: string; moduleId: string; - courseId: string; title: string; - slug: string; - contentType: ContentType; + description?: string; + contentType: LessonContentType; videoUrl?: string; videoDurationSeconds?: number; videoProvider?: string; - contentMarkdown?: string; - contentHtml?: string; - resources: LessonResource[]; - sortOrder: number; + videoId?: string; + articleContent?: string; + attachments?: LessonAttachment[]; + displayOrder: number; isPreview: boolean; - aiGenerated: boolean; - aiSummary?: string; + isMandatory: boolean; + xpReward: number; createdAt: Date; updatedAt: Date; } @@ -196,44 +256,46 @@ export interface CreateLessonInput { } // ============================================================================ -// Quiz +// Quiz (Aligned with education.quizzes DDL) // ============================================================================ -export interface QuizOption { +export interface Quiz { id: string; - text: string; - isCorrect: boolean; + moduleId?: string; + lessonId?: string; + title: string; + description?: string; + passingScorePercentage: number; + maxAttempts?: number; + timeLimitMinutes?: number; + shuffleQuestions: boolean; + shuffleAnswers: boolean; + showCorrectAnswers: boolean; + xpReward: number; + xpPerfectScoreBonus: number; + isActive: boolean; + createdAt: Date; + updatedAt: Date; } +// ============================================================================ +// Quiz Question (Aligned with education.quiz_questions DDL) +// ============================================================================ + export interface QuizQuestion { id: string; quizId: string; questionType: QuestionType; questionText: string; - explanation?: string; - options?: QuizOption[]; + options?: Record; + correctAnswer?: string; correctAnswers?: string[]; + explanation?: string; points: number; - sortOrder: number; + displayOrder: number; createdAt: Date; } -export interface Quiz { - id: string; - lessonId?: string; - courseId: string; - title: string; - description?: string; - passingScore: number; - maxAttempts?: number; - timeLimitMinutes?: number; - shuffleQuestions: boolean; - showCorrectAnswers: boolean; - aiGenerated: boolean; - createdAt: Date; - updatedAt: Date; -} - export interface QuizWithQuestions extends Quiz { questions: QuizQuestion[]; } @@ -262,7 +324,7 @@ export interface CreateQuizQuestionInput { } // ============================================================================ -// Enrollment +// Enrollment (Aligned with education.enrollments DDL) // ============================================================================ export interface Enrollment { @@ -271,14 +333,13 @@ export interface Enrollment { courseId: string; status: EnrollmentStatus; progressPercentage: number; - lessonsCompleted: number; + completedLessons: number; + totalLessons: number; enrolledAt: Date; - expiresAt?: Date; + startedAt?: Date; completedAt?: Date; - paymentId?: string; - certificateIssued: boolean; - certificateUrl?: string; - certificateIssuedAt?: Date; + expiresAt?: Date; + totalXpEarned: number; createdAt: Date; updatedAt: Date; } @@ -295,19 +356,19 @@ export interface CreateEnrollmentInput { } // ============================================================================ -// Lesson Progress +// Lesson Progress (Aligned with education.progress DDL) // ============================================================================ export interface LessonProgress { id: string; userId: string; - lessonId: string; enrollmentId: string; - videoWatchedSeconds: number; - videoCompleted: boolean; - startedAt?: Date; + lessonId: string; + isCompleted: boolean; + videoProgressSeconds?: number; completedAt?: Date; - userNotes?: string; + xpEarned: number; + notes?: string; createdAt: Date; updatedAt: Date; } @@ -319,13 +380,14 @@ export interface UpdateLessonProgressInput { } // ============================================================================ -// Quiz Attempts +// Quiz Attempts (Aligned with education.quiz_attempts DDL) // ============================================================================ -export interface QuizAnswer { +export interface QuizUserAnswer { questionId: string; answer: string | string[]; isCorrect: boolean; + points: number; } export interface QuizAttempt { @@ -333,12 +395,16 @@ export interface QuizAttempt { userId: string; quizId: string; enrollmentId?: string; - score: number; - passed: boolean; - answers: QuizAnswer[]; + isCompleted: boolean; + isPassed: boolean; + userAnswers?: QuizUserAnswer[]; + scorePoints: number; + maxPoints: number; + scorePercentage: number; startedAt: Date; - submittedAt?: Date; - timeSpentSeconds?: number; + completedAt?: Date; + timeTakenSeconds?: number; + xpEarned: number; createdAt: Date; } @@ -347,6 +413,11 @@ export interface SubmitQuizInput { answers: { questionId: string; answer: string | string[] }[]; } +/** + * @deprecated Use QuizUserAnswer instead + */ +export type QuizAnswer = QuizUserAnswer; + // ============================================================================ // Reviews // ============================================================================ @@ -381,6 +452,126 @@ export interface CreateReviewInput { reviewText?: string; } +// ============================================================================ +// Certificates (Aligned with education.certificates DDL) +// ============================================================================ + +export interface Certificate { + id: string; + userId: string; + enrollmentId: string; + courseId: string; + certificateNumber: string; + issuedAt: Date; + expiresAt?: Date; + certificateUrl?: string; + metadata?: Record; + createdAt: Date; +} + +export interface CreateCertificateInput { + userId: string; + enrollmentId: string; + courseId: string; + certificateNumber: string; + expiresAt?: Date; +} + +// ============================================================================ +// User Achievements (Aligned with education.user_achievements DDL) +// ============================================================================ + +export interface UserAchievement { + id: string; + userId: string; + achievementType: AchievementType; + title: string; + description?: string; + iconUrl?: string; + xpAwarded: number; + earnedAt: Date; + metadata?: Record; + createdAt: Date; +} + +export interface CreateAchievementInput { + userId: string; + achievementType: AchievementType; + title: string; + description?: string; + iconUrl?: string; + xpAwarded?: number; + metadata?: Record; +} + +// ============================================================================ +// User Gamification Profile (Aligned with education.user_gamification_profile DDL) +// ============================================================================ + +export interface UserGamificationProfile { + userId: string; + totalXp: number; + currentLevel: number; + currentStreak: number; + longestStreak: number; + totalCoursesCompleted: number; + totalLessonsCompleted: number; + totalQuizzesPassed: number; + totalAchievements: number; + lastActivityAt?: Date; + createdAt: Date; + updatedAt: Date; +} + +export interface UpdateGamificationProfileInput { + totalXp?: number; + currentLevel?: number; + currentStreak?: number; + longestStreak?: number; + totalCoursesCompleted?: number; + totalLessonsCompleted?: number; + totalQuizzesPassed?: number; + totalAchievements?: number; + lastActivityAt?: Date; +} + +// ============================================================================ +// User Activity Log (Aligned with education.user_activity_log DDL) +// ============================================================================ + +export interface UserActivityLog { + id: string; + userId: string; + activityType: string; + entityType?: string; + entityId?: string; + metadata?: Record; + ipAddress?: string; + userAgent?: string; + createdAt: Date; +} + +export interface CreateActivityLogInput { + userId: string; + activityType: string; + entityType?: string; + entityId?: string; + metadata?: Record; + ipAddress?: string; + userAgent?: string; +} + +// ============================================================================ +// Attachments (for lesson attachments JSONB field) +// ============================================================================ + +export interface LessonAttachment { + name: string; + url: string; + type: string; + size?: number; +} + // ============================================================================ // Pagination // ============================================================================