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
|
* 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 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';
|
export type ContentType = 'video' | 'text' | 'quiz' | 'exercise' | 'resource';
|
||||||
|
|
||||||
|
// Alineado con education.enrollment_status (DDL)
|
||||||
export type EnrollmentStatus = 'active' | 'completed' | 'expired' | 'cancelled';
|
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
|
// Category
|
||||||
@ -38,34 +105,34 @@ export interface CreateCategoryInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Course
|
// Course (Aligned with education.courses DDL)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
export interface Course {
|
export interface Course {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
description?: string;
|
|
||||||
shortDescription?: string;
|
shortDescription?: string;
|
||||||
|
fullDescription?: string;
|
||||||
|
categoryId: string;
|
||||||
|
difficultyLevel: DifficultyLevel;
|
||||||
thumbnailUrl?: string;
|
thumbnailUrl?: string;
|
||||||
previewVideoUrl?: string;
|
trailerUrl?: string;
|
||||||
categoryId?: string;
|
|
||||||
level: CourseLevel;
|
|
||||||
tags: string[];
|
|
||||||
isFree: boolean;
|
|
||||||
price: number;
|
|
||||||
currency: string;
|
|
||||||
requiresSubscription: boolean;
|
|
||||||
minSubscriptionTier?: string;
|
|
||||||
durationMinutes?: number;
|
durationMinutes?: number;
|
||||||
lessonsCount: number;
|
prerequisites?: string[];
|
||||||
enrolledCount: number;
|
learningObjectives?: string[];
|
||||||
averageRating: number;
|
instructorId: string;
|
||||||
ratingsCount: number;
|
instructorName?: string;
|
||||||
|
isFree: boolean;
|
||||||
|
priceUsd?: number;
|
||||||
|
xpReward: number;
|
||||||
status: CourseStatus;
|
status: CourseStatus;
|
||||||
publishedAt?: Date;
|
publishedAt?: Date;
|
||||||
instructorId?: string;
|
totalModules: number;
|
||||||
aiGenerated: boolean;
|
totalLessons: number;
|
||||||
|
totalEnrollments: number;
|
||||||
|
avgRating: number;
|
||||||
|
totalReviews: number;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
@ -119,7 +186,7 @@ export interface CourseFilters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Module
|
// Module (Aligned with education.modules DDL)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
export interface Module {
|
export interface Module {
|
||||||
@ -127,8 +194,8 @@ export interface Module {
|
|||||||
courseId: string;
|
courseId: string;
|
||||||
title: string;
|
title: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
sortOrder: number;
|
displayOrder: number;
|
||||||
unlockAfterModuleId?: string;
|
xpReward: number;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: 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 {
|
export interface Lesson {
|
||||||
id: string;
|
id: string;
|
||||||
moduleId: string;
|
moduleId: string;
|
||||||
courseId: string;
|
|
||||||
title: string;
|
title: string;
|
||||||
slug: string;
|
description?: string;
|
||||||
contentType: ContentType;
|
contentType: LessonContentType;
|
||||||
videoUrl?: string;
|
videoUrl?: string;
|
||||||
videoDurationSeconds?: number;
|
videoDurationSeconds?: number;
|
||||||
videoProvider?: string;
|
videoProvider?: string;
|
||||||
contentMarkdown?: string;
|
videoId?: string;
|
||||||
contentHtml?: string;
|
articleContent?: string;
|
||||||
resources: LessonResource[];
|
attachments?: LessonAttachment[];
|
||||||
sortOrder: number;
|
displayOrder: number;
|
||||||
isPreview: boolean;
|
isPreview: boolean;
|
||||||
aiGenerated: boolean;
|
isMandatory: boolean;
|
||||||
aiSummary?: string;
|
xpReward: number;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: 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;
|
id: string;
|
||||||
text: string;
|
moduleId?: string;
|
||||||
isCorrect: boolean;
|
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 {
|
export interface QuizQuestion {
|
||||||
id: string;
|
id: string;
|
||||||
quizId: string;
|
quizId: string;
|
||||||
questionType: QuestionType;
|
questionType: QuestionType;
|
||||||
questionText: string;
|
questionText: string;
|
||||||
explanation?: string;
|
options?: Record<string, unknown>;
|
||||||
options?: QuizOption[];
|
correctAnswer?: string;
|
||||||
correctAnswers?: string[];
|
correctAnswers?: string[];
|
||||||
|
explanation?: string;
|
||||||
points: number;
|
points: number;
|
||||||
sortOrder: number;
|
displayOrder: number;
|
||||||
createdAt: Date;
|
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 {
|
export interface QuizWithQuestions extends Quiz {
|
||||||
questions: QuizQuestion[];
|
questions: QuizQuestion[];
|
||||||
}
|
}
|
||||||
@ -262,7 +324,7 @@ export interface CreateQuizQuestionInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Enrollment
|
// Enrollment (Aligned with education.enrollments DDL)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
export interface Enrollment {
|
export interface Enrollment {
|
||||||
@ -271,14 +333,13 @@ export interface Enrollment {
|
|||||||
courseId: string;
|
courseId: string;
|
||||||
status: EnrollmentStatus;
|
status: EnrollmentStatus;
|
||||||
progressPercentage: number;
|
progressPercentage: number;
|
||||||
lessonsCompleted: number;
|
completedLessons: number;
|
||||||
|
totalLessons: number;
|
||||||
enrolledAt: Date;
|
enrolledAt: Date;
|
||||||
expiresAt?: Date;
|
startedAt?: Date;
|
||||||
completedAt?: Date;
|
completedAt?: Date;
|
||||||
paymentId?: string;
|
expiresAt?: Date;
|
||||||
certificateIssued: boolean;
|
totalXpEarned: number;
|
||||||
certificateUrl?: string;
|
|
||||||
certificateIssuedAt?: Date;
|
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: Date;
|
updatedAt: Date;
|
||||||
}
|
}
|
||||||
@ -295,19 +356,19 @@ export interface CreateEnrollmentInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Lesson Progress
|
// Lesson Progress (Aligned with education.progress DDL)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
export interface LessonProgress {
|
export interface LessonProgress {
|
||||||
id: string;
|
id: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
lessonId: string;
|
|
||||||
enrollmentId: string;
|
enrollmentId: string;
|
||||||
videoWatchedSeconds: number;
|
lessonId: string;
|
||||||
videoCompleted: boolean;
|
isCompleted: boolean;
|
||||||
startedAt?: Date;
|
videoProgressSeconds?: number;
|
||||||
completedAt?: Date;
|
completedAt?: Date;
|
||||||
userNotes?: string;
|
xpEarned: number;
|
||||||
|
notes?: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
updatedAt: 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;
|
questionId: string;
|
||||||
answer: string | string[];
|
answer: string | string[];
|
||||||
isCorrect: boolean;
|
isCorrect: boolean;
|
||||||
|
points: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface QuizAttempt {
|
export interface QuizAttempt {
|
||||||
@ -333,12 +395,16 @@ export interface QuizAttempt {
|
|||||||
userId: string;
|
userId: string;
|
||||||
quizId: string;
|
quizId: string;
|
||||||
enrollmentId?: string;
|
enrollmentId?: string;
|
||||||
score: number;
|
isCompleted: boolean;
|
||||||
passed: boolean;
|
isPassed: boolean;
|
||||||
answers: QuizAnswer[];
|
userAnswers?: QuizUserAnswer[];
|
||||||
|
scorePoints: number;
|
||||||
|
maxPoints: number;
|
||||||
|
scorePercentage: number;
|
||||||
startedAt: Date;
|
startedAt: Date;
|
||||||
submittedAt?: Date;
|
completedAt?: Date;
|
||||||
timeSpentSeconds?: number;
|
timeTakenSeconds?: number;
|
||||||
|
xpEarned: number;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,6 +413,11 @@ export interface SubmitQuizInput {
|
|||||||
answers: { questionId: string; answer: string | string[] }[];
|
answers: { questionId: string; answer: string | string[] }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use QuizUserAnswer instead
|
||||||
|
*/
|
||||||
|
export type QuizAnswer = QuizUserAnswer;
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Reviews
|
// Reviews
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@ -381,6 +452,126 @@ export interface CreateReviewInput {
|
|||||||
reviewText?: string;
|
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
|
// Pagination
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user