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 <noreply@anthropic.com>
This commit is contained in:
parent
d73253130f
commit
0563d4bc9b
@ -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<string, unknown>;
|
||||
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<string, unknown>;
|
||||
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<string, unknown>;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export interface CreateAchievementInput {
|
||||
userId: string;
|
||||
achievementType: AchievementType;
|
||||
title: string;
|
||||
description?: string;
|
||||
iconUrl?: string;
|
||||
xpAwarded?: number;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 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<string, unknown>;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
createdAt: Date;
|
||||
}
|
||||
|
||||
export interface CreateActivityLogInput {
|
||||
userId: string;
|
||||
activityType: string;
|
||||
entityType?: string;
|
||||
entityId?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Attachments (for lesson attachments JSONB field)
|
||||
// ============================================================================
|
||||
|
||||
export interface LessonAttachment {
|
||||
name: string;
|
||||
url: string;
|
||||
type: string;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Pagination
|
||||
// ============================================================================
|
||||
|
||||
Loading…
Reference in New Issue
Block a user