@lssm/module.learning-journey 0.0.0-canary-20251212004227

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,187 @@
1
+ # @lssm/module.learning-journey
2
+
3
+ Comprehensive learning journey engine for ContractSpec applications.
4
+
5
+ ## Overview
6
+
7
+ This module provides a complete learning platform engine that supports multiple use cases:
8
+
9
+ - **Product Onboarding**: Event-driven completion tied to product actions
10
+ - **Learning Management System (LMS)**: Courses, modules, lessons, certifications
11
+ - **Flashcards & Spaced Repetition (SRS)**: SM-2 algorithm for optimal retention
12
+ - **Quizzes & Assessments**: Multiple question types, skill tracking
13
+ - **Gamification**: XP, streaks, achievements, leaderboards (Duolingo-style)
14
+ - **AI-Powered Personalization**: Adaptive paths, recommendations, gap detection
15
+
16
+ ## Features
17
+
18
+ ### Core Learning Structure
19
+
20
+ - **Courses**: Structured learning content with prerequisites and difficulty levels
21
+ - **Modules**: Groups of related lessons within a course
22
+ - **Lessons**: Individual learning units (content, video, interactive, quiz)
23
+ - **Progress Tracking**: Track completion, time spent, scores
24
+
25
+ ### Product Onboarding
26
+
27
+ - **Onboarding Tracks**: Product-specific onboarding journeys
28
+ - **Event-Driven Completion**: Steps auto-complete when product events fire
29
+ - **Example**: "Create your first project" completes on `ProjectCreated` event
30
+
31
+ ### Flashcards & Spaced Repetition
32
+
33
+ - **Decks & Cards**: Organize flashcards by topic
34
+ - **SM-2 Algorithm**: Optimized review scheduling
35
+ - **Review Sessions**: Get cards due for review
36
+ - **Retention Metrics**: Track long-term retention
37
+
38
+ ### Quizzes & Assessments
39
+
40
+ - **Question Types**: Multiple choice, true/false, fill-in-blank, matching
41
+ - **Timed Quizzes**: Optional time limits
42
+ - **Skill Assessment**: Map quiz performance to skills
43
+
44
+ ### Gamification
45
+
46
+ - **Experience Points (XP)**: Earn XP for completing activities
47
+ - **Streaks**: Maintain daily learning streaks
48
+ - **Achievements**: Unlock achievements for milestones
49
+ - **Leaderboards**: Compete with others (daily/weekly/monthly)
50
+ - **Lives System**: Optional hearts/lives for quiz attempts
51
+
52
+ ### AI Personalization
53
+
54
+ - **Learner Profiles**: Track learning style, preferences, goals
55
+ - **Skill Maps**: Map proficiency across skills
56
+ - **Adaptive Paths**: Generate personalized learning sequences
57
+ - **Recommendations**: AI-powered content suggestions
58
+ - **Gap Detection**: Identify and address learning gaps
59
+
60
+ ## Entities
61
+
62
+ ### Course Structure
63
+ - `Course`, `Module`, `Lesson`, `LessonContent`
64
+
65
+ ### Learner & Progress
66
+ - `Learner`, `Enrollment`, `LessonProgress`, `ModuleCompletion`, `Certificate`
67
+
68
+ ### Onboarding
69
+ - `OnboardingTrack`, `OnboardingStep`, `OnboardingProgress`
70
+
71
+ ### Flashcards
72
+ - `Deck`, `Card`, `CardReview`, `CardSchedule`
73
+
74
+ ### Quizzes
75
+ - `Quiz`, `Question`, `QuestionOption`, `QuizAttempt`, `SkillAssessment`
76
+
77
+ ### Gamification
78
+ - `Achievement`, `LearnerAchievement`, `Streak`, `DailyGoal`, `LeaderboardEntry`, `Heart`
79
+
80
+ ### AI
81
+ - `LearnerProfile`, `SkillMap`, `LearningPath`, `Recommendation`
82
+
83
+ ## Engines
84
+
85
+ ### Spaced Repetition Engine (SRS)
86
+
87
+ ```typescript
88
+ import { SRSEngine } from '@lssm/module.learning-journey/engines/srs';
89
+
90
+ const engine = new SRSEngine();
91
+ const nextReview = engine.calculateNextReview({
92
+ rating: 'good', // again, hard, good, easy
93
+ currentInterval: 1,
94
+ easeFactor: 2.5,
95
+ repetitions: 3,
96
+ });
97
+ ```
98
+
99
+ ### XP Engine
100
+
101
+ ```typescript
102
+ import { XPEngine } from '@lssm/module.learning-journey/engines/xp';
103
+
104
+ const engine = new XPEngine();
105
+ const xp = engine.calculate({
106
+ activity: 'lesson_complete',
107
+ score: 95,
108
+ streakBonus: true,
109
+ });
110
+ ```
111
+
112
+ ### Streak Engine
113
+
114
+ ```typescript
115
+ import { StreakEngine } from '@lssm/module.learning-journey/engines/streak';
116
+
117
+ const engine = new StreakEngine();
118
+ const streak = engine.update({
119
+ lastActivityAt: new Date('2024-01-14'),
120
+ currentStreak: 5,
121
+ });
122
+ ```
123
+
124
+ ## Usage
125
+
126
+ ```typescript
127
+ import {
128
+ CourseEntity,
129
+ LearnerEntity,
130
+ SRSEngine,
131
+ } from '@lssm/module.learning-journey';
132
+
133
+ // Enroll learner in course
134
+ await enrollmentService.enroll({
135
+ learnerId: 'learner-123',
136
+ courseId: 'course-456',
137
+ });
138
+
139
+ // Complete a lesson
140
+ await progressService.completeLesson({
141
+ learnerId: 'learner-123',
142
+ lessonId: 'lesson-789',
143
+ score: 95,
144
+ });
145
+
146
+ // Get flashcards due for review
147
+ const cards = await flashcardService.getDueCards({
148
+ learnerId: 'learner-123',
149
+ limit: 20,
150
+ });
151
+
152
+ // Submit flashcard review
153
+ await flashcardService.submitReview({
154
+ learnerId: 'learner-123',
155
+ cardId: 'card-abc',
156
+ rating: 'good',
157
+ });
158
+ ```
159
+
160
+ ## Integration
161
+
162
+ This module integrates with:
163
+
164
+ - `@lssm/lib.identity-rbac` - Learner identity
165
+ - `@lssm/lib.files` - Media attachments
166
+ - `@lssm/lib.jobs` - Scheduled reminders, streak checks
167
+ - `@lssm/lib.ai-agent` - AI-powered features
168
+ - `@lssm/module.notifications` - Learning reminders
169
+
170
+ ## Schema Contribution
171
+
172
+ ```typescript
173
+ import { learningJourneySchemaContribution } from '@lssm/module.learning-journey';
174
+
175
+ export const schemaComposition = {
176
+ modules: [
177
+ learningJourneySchemaContribution,
178
+ // ... other modules
179
+ ],
180
+ };
181
+ ```
182
+
183
+
184
+
185
+
186
+
187
+
@@ -0,0 +1 @@
1
+ import{LEARNING_JOURNEY_OWNERS as e}from"./shared.js";import{AchievementModel as t,CardModel as n,CompleteLessonInput as r,CourseModel as i,DeckModel as a,EnrollInCourseInput as o,EnrollmentModel as s,GetDueCardsInput as c,GetDueCardsOutput as l,GetLearnerDashboardInput as u,LearnerDashboardModel as d,LearnerModel as f,ProgressModel as p,SubmitCardReviewInput as m,SuccessOutput as h}from"./models.js";import{CompleteLessonContract as g,EnrollInCourseContract as _,GetDueCardsContract as v,GetLearnerDashboardContract as y,SubmitCardReviewContract as b}from"./operations.js";import{GetOnboardingProgressContract as x,ListOnboardingTracksContract as S,OnboardingProgressModel as C,OnboardingStepModel as w,OnboardingStepProgressModel as T,OnboardingTrackModel as E,RecordOnboardingEventContract as D}from"./onboarding.js";export{t as AchievementModel,n as CardModel,g as CompleteLessonContract,r as CompleteLessonInput,i as CourseModel,a as DeckModel,_ as EnrollInCourseContract,o as EnrollInCourseInput,s as EnrollmentModel,v as GetDueCardsContract,c as GetDueCardsInput,l as GetDueCardsOutput,y as GetLearnerDashboardContract,u as GetLearnerDashboardInput,x as GetOnboardingProgressContract,e as LEARNING_JOURNEY_OWNERS,d as LearnerDashboardModel,f as LearnerModel,S as ListOnboardingTracksContract,C as OnboardingProgressModel,w as OnboardingStepModel,T as OnboardingStepProgressModel,E as OnboardingTrackModel,p as ProgressModel,D as RecordOnboardingEventContract,b as SubmitCardReviewContract,m as SubmitCardReviewInput,h as SuccessOutput};
@@ -0,0 +1 @@
1
+ import{ScalarTypeEnum as e,defineSchemaModel as t}from"@lssm/lib.schema";const n=t({name:`Course`,description:`A learning course`,fields:{id:{type:e.String_unsecure(),isOptional:!1},title:{type:e.String_unsecure(),isOptional:!1},slug:{type:e.String_unsecure(),isOptional:!1},description:{type:e.String_unsecure(),isOptional:!0},difficulty:{type:e.String_unsecure(),isOptional:!1},status:{type:e.String_unsecure(),isOptional:!1},estimatedDuration:{type:e.Int_unsecure(),isOptional:!0},thumbnailUrl:{type:e.String_unsecure(),isOptional:!0},createdAt:{type:e.DateTime(),isOptional:!1}}}),r=t({name:`Learner`,description:`A learner profile`,fields:{id:{type:e.String_unsecure(),isOptional:!1},userId:{type:e.String_unsecure(),isOptional:!1},displayName:{type:e.String_unsecure(),isOptional:!0},level:{type:e.Int_unsecure(),isOptional:!1},totalXp:{type:e.Int_unsecure(),isOptional:!1},currentStreak:{type:e.Int_unsecure(),isOptional:!1},longestStreak:{type:e.Int_unsecure(),isOptional:!1},createdAt:{type:e.DateTime(),isOptional:!1}}}),i=t({name:`Enrollment`,description:`A course enrollment`,fields:{id:{type:e.String_unsecure(),isOptional:!1},learnerId:{type:e.String_unsecure(),isOptional:!1},courseId:{type:e.String_unsecure(),isOptional:!1},status:{type:e.String_unsecure(),isOptional:!1},progress:{type:e.Int_unsecure(),isOptional:!1},startedAt:{type:e.DateTime(),isOptional:!0},completedAt:{type:e.DateTime(),isOptional:!0}}}),a=t({name:`LessonProgress`,description:`Lesson progress`,fields:{id:{type:e.String_unsecure(),isOptional:!1},learnerId:{type:e.String_unsecure(),isOptional:!1},lessonId:{type:e.String_unsecure(),isOptional:!1},status:{type:e.String_unsecure(),isOptional:!1},progress:{type:e.Int_unsecure(),isOptional:!1},score:{type:e.Int_unsecure(),isOptional:!0},timeSpent:{type:e.Int_unsecure(),isOptional:!1},completedAt:{type:e.DateTime(),isOptional:!0}}}),o=t({name:`Deck`,description:`A flashcard deck`,fields:{id:{type:e.String_unsecure(),isOptional:!1},title:{type:e.String_unsecure(),isOptional:!1},description:{type:e.String_unsecure(),isOptional:!0},cardCount:{type:e.Int_unsecure(),isOptional:!1},isPublic:{type:e.Boolean(),isOptional:!1},createdAt:{type:e.DateTime(),isOptional:!1}}}),s=t({name:`Card`,description:`A flashcard`,fields:{id:{type:e.String_unsecure(),isOptional:!1},deckId:{type:e.String_unsecure(),isOptional:!1},front:{type:e.String_unsecure(),isOptional:!1},back:{type:e.String_unsecure(),isOptional:!1},hints:{type:e.JSON(),isOptional:!0},isDue:{type:e.Boolean(),isOptional:!1},nextReviewAt:{type:e.DateTime(),isOptional:!0}}}),c=t({name:`Achievement`,description:`An achievement`,fields:{id:{type:e.String_unsecure(),isOptional:!1},key:{type:e.String_unsecure(),isOptional:!1},name:{type:e.String_unsecure(),isOptional:!1},description:{type:e.String_unsecure(),isOptional:!1},icon:{type:e.String_unsecure(),isOptional:!0},xpReward:{type:e.Int_unsecure(),isOptional:!1},unlockedAt:{type:e.DateTime(),isOptional:!0}}}),l=t({name:`EnrollInCourseInput`,description:`Input for enrolling in a course`,fields:{courseId:{type:e.String_unsecure(),isOptional:!1}}}),u=t({name:`CompleteLessonInput`,description:`Input for completing a lesson`,fields:{lessonId:{type:e.String_unsecure(),isOptional:!1},score:{type:e.Int_unsecure(),isOptional:!0},timeSpent:{type:e.Int_unsecure(),isOptional:!1}}}),d=t({name:`SubmitCardReviewInput`,description:`Input for submitting a card review`,fields:{cardId:{type:e.String_unsecure(),isOptional:!1},rating:{type:e.String_unsecure(),isOptional:!1},responseTimeMs:{type:e.Int_unsecure(),isOptional:!0}}}),f=t({name:`GetDueCardsInput`,description:`Input for getting due cards`,fields:{deckId:{type:e.String_unsecure(),isOptional:!0},limit:{type:e.Int_unsecure(),isOptional:!0}}}),p=t({name:`GetDueCardsOutput`,description:`Output for getting due cards`,fields:{cards:{type:s,isArray:!0,isOptional:!1},total:{type:e.Int_unsecure(),isOptional:!1}}}),m=t({name:`GetLearnerDashboardInput`,description:`Input for getting learner dashboard`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!0}}}),h=t({name:`LearnerDashboard`,description:`Learner dashboard data`,fields:{learner:{type:r,isOptional:!1},currentStreak:{type:e.Int_unsecure(),isOptional:!1},dailyXpGoal:{type:e.Int_unsecure(),isOptional:!1},dailyXpProgress:{type:e.Int_unsecure(),isOptional:!1},activeEnrollments:{type:i,isArray:!0,isOptional:!1},recentAchievements:{type:c,isArray:!0,isOptional:!1},dueCardCount:{type:e.Int_unsecure(),isOptional:!1}}}),g=t({name:`SuccessOutput`,description:`Generic success output`,fields:{success:{type:e.Boolean(),isOptional:!1},xpEarned:{type:e.Int_unsecure(),isOptional:!0}}});export{c as AchievementModel,s as CardModel,u as CompleteLessonInput,n as CourseModel,o as DeckModel,l as EnrollInCourseInput,i as EnrollmentModel,f as GetDueCardsInput,p as GetDueCardsOutput,m as GetLearnerDashboardInput,h as LearnerDashboardModel,r as LearnerModel,a as ProgressModel,d as SubmitCardReviewInput,g as SuccessOutput};
@@ -0,0 +1 @@
1
+ import{LEARNING_JOURNEY_OWNERS as e}from"./shared.js";import{SuccessOutput as t}from"./models.js";import{ScalarTypeEnum as n,defineSchemaModel as r}from"@lssm/lib.schema";import{defineCommand as i,defineQuery as a}from"@lssm/lib.contracts";const o=r({name:`OnboardingStepCondition`,description:`Structured completion condition for onboarding steps.`,fields:{eventName:{type:n.String_unsecure(),isOptional:!1},eventVersion:{type:n.Int_unsecure(),isOptional:!0},sourceModule:{type:n.String_unsecure(),isOptional:!0},payloadFilter:{type:n.JSON(),isOptional:!0}}}),s=r({name:`OnboardingStep`,description:`Declarative onboarding step definition.`,fields:{id:{type:n.String_unsecure(),isOptional:!1},trackId:{type:n.String_unsecure(),isOptional:!1},title:{type:n.String_unsecure(),isOptional:!1},description:{type:n.String_unsecure(),isOptional:!0},instructions:{type:n.String_unsecure(),isOptional:!0},helpUrl:{type:n.String_unsecure(),isOptional:!0},order:{type:n.Int_unsecure(),isOptional:!1},completionEvent:{type:n.String_unsecure(),isOptional:!1},completionCondition:{type:o,isOptional:!0},xpReward:{type:n.Int_unsecure(),isOptional:!0},isRequired:{type:n.Boolean(),isOptional:!0},canSkip:{type:n.Boolean(),isOptional:!0},actionUrl:{type:n.String_unsecure(),isOptional:!0},actionLabel:{type:n.String_unsecure(),isOptional:!0},metadata:{type:n.JSON(),isOptional:!0}}}),c=r({name:`OnboardingTrack`,description:`Onboarding track metadata and steps.`,fields:{id:{type:n.String_unsecure(),isOptional:!1},productId:{type:n.String_unsecure(),isOptional:!0},name:{type:n.String_unsecure(),isOptional:!1},description:{type:n.String_unsecure(),isOptional:!0},targetUserSegment:{type:n.String_unsecure(),isOptional:!0},targetRole:{type:n.String_unsecure(),isOptional:!0},isActive:{type:n.Boolean(),isOptional:!0},isRequired:{type:n.Boolean(),isOptional:!0},canSkip:{type:n.Boolean(),isOptional:!0},totalXp:{type:n.Int_unsecure(),isOptional:!0},completionXpBonus:{type:n.Int_unsecure(),isOptional:!0},completionBadgeKey:{type:n.String_unsecure(),isOptional:!0},streakHoursWindow:{type:n.Int_unsecure(),isOptional:!0},streakBonusXp:{type:n.Int_unsecure(),isOptional:!0},metadata:{type:n.JSON(),isOptional:!0},steps:{type:s,isArray:!0,isOptional:!1}}}),l=r({name:`OnboardingStepProgress`,description:`Progress for a specific onboarding step.`,fields:{stepId:{type:n.String_unsecure(),isOptional:!1},status:{type:n.String_unsecure(),isOptional:!1},xpEarned:{type:n.Int_unsecure(),isOptional:!0},triggeringEvent:{type:n.String_unsecure(),isOptional:!0},eventPayload:{type:n.JSON(),isOptional:!0},completedAt:{type:n.DateTime(),isOptional:!0}}}),u=r({name:`OnboardingProgress`,description:`Aggregated progress for an onboarding track.`,fields:{learnerId:{type:n.String_unsecure(),isOptional:!0},trackId:{type:n.String_unsecure(),isOptional:!1},progress:{type:n.Int_unsecure(),isOptional:!1},isCompleted:{type:n.Boolean(),isOptional:!1},xpEarned:{type:n.Int_unsecure(),isOptional:!0},startedAt:{type:n.DateTime(),isOptional:!0},completedAt:{type:n.DateTime(),isOptional:!0},lastActivityAt:{type:n.DateTime(),isOptional:!0},steps:{type:l,isArray:!0,isOptional:!0}}}),d=r({name:`ListOnboardingTracksInput`,description:`Filters for listing onboarding tracks.`,fields:{learnerId:{type:n.String_unsecure(),isOptional:!0},productId:{type:n.String_unsecure(),isOptional:!0},trackIds:{type:n.String_unsecure(),isArray:!0,isOptional:!0},includeProgress:{type:n.Boolean(),isOptional:!0}}}),f=r({name:`ListOnboardingTracksOutput`,description:`Available onboarding tracks with optional progress.`,fields:{tracks:{type:c,isArray:!0,isOptional:!1},progress:{type:u,isArray:!0,isOptional:!0}}}),p=r({name:`GetOnboardingProgressInput`,description:`Input for fetching onboarding progress for a track.`,fields:{trackId:{type:n.String_unsecure(),isOptional:!1},learnerId:{type:n.String_unsecure(),isOptional:!0}}}),m=r({name:`RecordOnboardingEventInput`,description:`Record a domain event to advance onboarding progress via completion conditions.`,fields:{learnerId:{type:n.String_unsecure(),isOptional:!1},trackId:{type:n.String_unsecure(),isOptional:!0},eventName:{type:n.String_unsecure(),isOptional:!1},eventVersion:{type:n.Int_unsecure(),isOptional:!0},eventPayload:{type:n.JSON(),isOptional:!0},occurredAt:{type:n.DateTime(),isOptional:!0}}}),h=a({meta:{name:`learning.onboarding.listTracks`,version:1,stability:`stable`,owners:[...e],tags:[`learning`,`onboarding`,`journey`],description:`List onboarding tracks available to a learner or product.`,goal:`Expose track catalog for UI/API surfaces.`,context:`Called when showing onboarding/learning journey catalog.`},io:{input:d,output:f},policy:{auth:`user`}}),g=a({meta:{name:`learning.onboarding.getProgress`,version:1,stability:`stable`,owners:[...e],tags:[`learning`,`onboarding`,`journey`],description:`Fetch onboarding progress for a specific track.`,goal:`Display learner progress and remaining steps.`,context:`Called when rendering a track detail or widget.`},io:{input:p,output:u},policy:{auth:`user`}}),_=i({meta:{name:`learning.onboarding.recordEvent`,version:1,stability:`stable`,owners:[...e],tags:[`learning`,`onboarding`,`events`],description:`Record a domain event to evaluate onboarding step completion conditions.`,goal:`Advance onboarding automatically from product events.`,context:`Called by event bus handlers when relevant product events fire (e.g., deal.created).`},io:{input:m,output:t,errors:{TRACK_NOT_FOUND:{description:`Track not found for event routing`,http:404,gqlCode:`TRACK_NOT_FOUND`,when:`Track ID or routing context is invalid`},STEP_NOT_FOUND:{description:`Step not found for completion condition`,http:404,gqlCode:`STEP_NOT_FOUND`,when:`No step matches the incoming event`}}},policy:{auth:`user`}});export{g as GetOnboardingProgressContract,h as ListOnboardingTracksContract,u as OnboardingProgressModel,s as OnboardingStepModel,l as OnboardingStepProgressModel,c as OnboardingTrackModel,_ as RecordOnboardingEventContract};
@@ -0,0 +1 @@
1
+ import{LEARNING_JOURNEY_OWNERS as e}from"./shared.js";import{CompleteLessonInput as t,EnrollInCourseInput as n,EnrollmentModel as r,GetDueCardsInput as i,GetDueCardsOutput as a,GetLearnerDashboardInput as o,LearnerDashboardModel as s,SubmitCardReviewInput as c,SuccessOutput as l}from"./models.js";import{defineCommand as u,defineQuery as d}from"@lssm/lib.contracts";const f=u({meta:{name:`learning.enroll`,version:1,stability:`stable`,owners:[...e],tags:[`learning`,`enrollment`],description:`Enroll in a course.`,goal:`Start learning a new course.`,context:`Called when a learner wants to start a course.`},io:{input:n,output:r,errors:{COURSE_NOT_FOUND:{description:`Course does not exist`,http:404,gqlCode:`COURSE_NOT_FOUND`,when:`Course ID is invalid`},ALREADY_ENROLLED:{description:`Already enrolled in course`,http:409,gqlCode:`ALREADY_ENROLLED`,when:`Learner is already enrolled`}}},policy:{auth:`user`}}),p=u({meta:{name:`learning.completeLesson`,version:1,stability:`stable`,owners:[...e],tags:[`learning`,`progress`],description:`Mark a lesson as completed.`,goal:`Record lesson completion and earn XP.`,context:`Called when a learner finishes a lesson.`},io:{input:t,output:l,errors:{LESSON_NOT_FOUND:{description:`Lesson does not exist`,http:404,gqlCode:`LESSON_NOT_FOUND`,when:`Lesson ID is invalid`},NOT_ENROLLED:{description:`Not enrolled in course`,http:403,gqlCode:`NOT_ENROLLED`,when:`Learner is not enrolled in the course`}}},policy:{auth:`user`}}),m=u({meta:{name:`learning.submitCardReview`,version:1,stability:`stable`,owners:[...e],tags:[`learning`,`flashcards`],description:`Submit a flashcard review.`,goal:`Record review and update SRS schedule.`,context:`Called when reviewing flashcards.`},io:{input:c,output:l,errors:{CARD_NOT_FOUND:{description:`Card does not exist`,http:404,gqlCode:`CARD_NOT_FOUND`,when:`Card ID is invalid`},INVALID_RATING:{description:`Invalid rating`,http:400,gqlCode:`INVALID_RATING`,when:`Rating must be AGAIN, HARD, GOOD, or EASY`}}},policy:{auth:`user`}}),h=d({meta:{name:`learning.getDueCards`,version:1,stability:`stable`,owners:[...e],tags:[`learning`,`flashcards`],description:`Get flashcards due for review.`,goal:`Get the next batch of cards to review.`,context:`Called when starting a review session.`},io:{input:i,output:a},policy:{auth:`user`}}),g=d({meta:{name:`learning.getDashboard`,version:1,stability:`stable`,owners:[...e],tags:[`learning`,`dashboard`],description:`Get learner dashboard data.`,goal:`Display learner progress and stats.`,context:`Called when viewing the learning dashboard.`},io:{input:o,output:s},policy:{auth:`user`}});export{p as CompleteLessonContract,f as EnrollInCourseContract,h as GetDueCardsContract,g as GetLearnerDashboardContract,m as SubmitCardReviewContract};
@@ -0,0 +1 @@
1
+ const e=[`modules.learning-journey`];export{e as LEARNING_JOURNEY_OWNERS};
@@ -0,0 +1 @@
1
+ import"./learning-journey.docblock.js";
@@ -0,0 +1,80 @@
1
+ import{registerDocBlocks as e}from"@lssm/lib.contracts/docs";e([{id:`docs.learning-journey.engine`,title:`Learning Journey Engine`,summary:`Tracks learners, tracks/modules/steps, progress, quizzes, streaks, XP, and AI coaching hooks for product-integrated onboarding.`,kind:`reference`,visibility:`public`,route:`/docs/learning-journey/engine`,tags:[`learning`,`onboarding`,`journey`,`education`],body:`## Capabilities
2
+
3
+ - **Entities**: Learner, Track, Module, Step, Progress, Quiz, Flashcard, AI Coach, Gamification (XP, streaks, badges).
4
+ - **Contracts**: enroll/resume/advance steps, complete quizzes, record streaks, assign XP, fetch progress dashboards, onboarding list/progress/recordEvent.
5
+ - **Engines**: spaced-repetition (SRS), streak calculator, XP progression.
6
+ - **Events**: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded, onboarding.started/completed/step_completed.
7
+
8
+ ## Completion conditions
9
+ - Event-based: name/version/source + payload filter
10
+ - Count-based: require N events (optional time window)
11
+ - Time-bounded: must complete within a window; steps can unlock by day/hour
12
+ - SRS mastery: complete when cards/skills hit mastery thresholds (with required counts)
13
+
14
+ ## Usage
15
+
16
+ 1) Compose schema
17
+ - Include \`learningJourneySchemaContribution\` (entities export) in composition.
18
+
19
+ 2) Register contracts/events
20
+ - Import from \`@lssm/module.learning-journey\` into your spec registry.
21
+
22
+ 3) Bind to product actions
23
+ - Tie \`Step\` completion conditions to domain events (e.g., deal.created, agent.run.completed, drill.session.completed).
24
+ - Trigger notifications via Notification Center and audits on completion.
25
+
26
+ 4) Gamification
27
+ - Use \`XP\` and \`Streak\` engines to update learner stats; emit analytics for UI.
28
+
29
+ ## Example
30
+
31
+ \`\`\`ts
32
+ import { learningJourneyEntities } from '@lssm/module.learning-journey';
33
+ import { StreakEngine } from '@lssm/module.learning-journey/engines';
34
+
35
+ const streak = new StreakEngine({ graceDays: 1 });
36
+ const updated = streak.compute({ lastActiveAt: new Date(), today: new Date() });
37
+ \`\`\`,
38
+
39
+ ## Guardrails
40
+
41
+ - Keep steps bound to real product events, not just button clicks.
42
+ - Avoid storing PII in content; keep org/user scoping for multi-tenant isolation.
43
+ - Emit analytics and audit logs for completions; respect \`prefers-reduced-motion\` in UIs consuming these specs.
44
+ - Track completion bonuses: \`completionXpBonus\`, \`completionBadgeKey\`, optional \`streakHoursWindow\` + \`streakBonusXp\`.
45
+ `},{id:`docs.learning-journey.goal`,title:`Learning Journey — Goal`,summary:`Why the learning journey engine exists and the outcomes it targets.`,kind:`goal`,visibility:`public`,route:`/docs/learning-journey/goal`,tags:[`learning`,`goal`],body:`## Why it matters
46
+ - Provides a regenerable onboarding/education engine tied to product signals.
47
+ - Keeps tracks, steps, quizzes, and gamification consistent across surfaces.
48
+
49
+ ## Business/Product goal
50
+ - Drive activation and retention with measurable progress, SRS, and streaks.
51
+ - Allow product teams to adjust journeys safely via specs.
52
+
53
+ ## Success criteria
54
+ - Journey changes regenerate UI/API/events without drift.
55
+ - Analytics/audit hooks exist for completions and streaks.`},{id:`docs.learning-journey.usage`,title:`Learning Journey — Usage`,summary:`How to compose, bind, and regenerate journeys safely.`,kind:`usage`,visibility:`public`,route:`/docs/learning-journey/usage`,tags:[`learning`,`usage`],body:`## Setup
56
+ 1) Include \`learningJourneyEntities\` in schema composition.
57
+ 2) Register contracts/events from \`@lssm/module.learning-journey\`.
58
+ 3) Bind steps to real product events (e.g., deal.created, run.completed).
59
+
60
+ ## Extend & regenerate
61
+ 1) Update track/module/step definitions or quiz schemas in spec.
62
+ 2) Regenerate to sync UI/API/events; mark PII paths where needed.
63
+ 3) Use Feature Flags to trial new tracks or streak rules.
64
+
65
+ ## Guardrails
66
+ - Avoid hardcoded progression; keep engines declarative.
67
+ - Emit analytics/audit for completions; respect user locale/accessibility in presentations.
68
+ - Keep content free of PII; scope learners by org/tenant.`},{id:`docs.learning-journey.constraints`,title:`Learning Journey — Constraints & Safety`,summary:`Internal guardrails for progression, telemetry, and regeneration semantics.`,kind:`reference`,visibility:`internal`,route:`/docs/learning-journey/constraints`,tags:[`learning`,`constraints`,`internal`],body:`## Constraints
69
+ - Progression (tracks/modules/steps) and engines (SRS, streaks, XP) must stay declarative in spec.
70
+ - Events to emit: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded.
71
+ - Regeneration should not change scoring/streak rules without explicit spec change.
72
+
73
+ ## PII & Telemetry
74
+ - Mark PII (learner identifiers) and redact in presentations; keep telemetry aggregated when possible.
75
+ - Respect accessibility (prefers-reduced-motion) in UIs consuming these specs.
76
+
77
+ ## Verification
78
+ - Add fixtures for streak/XP rule changes and quiz scoring.
79
+ - Ensure Notifications/Audit wiring persists for completions; analytics emitted for progress.
80
+ - Use Feature Flags to trial new tracks or reward rules; default safe/off.`}]);
@@ -0,0 +1 @@
1
+ import{DEFAULT_SRS_CONFIG as e,SRSEngine as t,srsEngine as n}from"./srs.js";import{DEFAULT_XP_CONFIG as r,XPEngine as i,xpEngine as a}from"./xp.js";import{DEFAULT_STREAK_CONFIG as o,StreakEngine as s,streakEngine as c}from"./streak.js";export{e as DEFAULT_SRS_CONFIG,o as DEFAULT_STREAK_CONFIG,r as DEFAULT_XP_CONFIG,t as SRSEngine,s as StreakEngine,i as XPEngine,n as srsEngine,c as streakEngine,a as xpEngine};
@@ -0,0 +1 @@
1
+ const e={learningSteps:[1,10],graduatingInterval:1,easyInterval:4,relearningSteps:[10],minEaseFactor:1.3,maxInterval:365,intervalModifier:1,newIntervalModifier:.5,hardIntervalModifier:1.2,easyBonus:1.3};var t=class{config;constructor(t={}){this.config={...e,...t}}calculateNextReview(e,t,n=new Date){return!e.isGraduated&&!e.isRelearning?this.handleLearningCard(e,t,n):e.isRelearning?this.handleRelearningCard(e,t,n):this.handleReviewCard(e,t,n)}handleLearningCard(e,t,n){let r=this.config.learningSteps,i=e.learningStep,a=!1,o=0,s;switch(t){case`AGAIN`:i=0,o=r[0]??1,s=this.addMinutes(n,o);break;case`HARD`:o=r[i]??r[0]??1,s=this.addMinutes(n,o);break;case`GOOD`:i++,i>=r.length?(a=!0,o=this.config.graduatingInterval,s=this.addDays(n,o)):(o=r[i]??10,s=this.addMinutes(n,o));break;case`EASY`:a=!0,o=this.config.easyInterval,s=this.addDays(n,o);break}return{interval:a?o:0,easeFactor:e.easeFactor,repetitions:a?1:0,nextReviewAt:s,learningStep:i,isGraduated:a,isRelearning:!1,lapses:e.lapses}}handleRelearningCard(e,t,n){let r=this.config.relearningSteps,i=e.learningStep,a=!0,o=0,s;switch(t){case`AGAIN`:i=0,o=r[0]??10,s=this.addMinutes(n,o);break;case`HARD`:o=r[i]??r[0]??10,s=this.addMinutes(n,o);break;case`GOOD`:i++,i>=r.length?(a=!1,o=Math.max(1,Math.floor(e.interval*this.config.newIntervalModifier)),s=this.addDays(n,o)):(o=r[i]??10,s=this.addMinutes(n,o));break;case`EASY`:a=!1,o=Math.max(1,Math.floor(e.interval*this.config.newIntervalModifier*1.5)),s=this.addDays(n,o);break}return{interval:a?e.interval:o,easeFactor:e.easeFactor,repetitions:a?e.repetitions:e.repetitions+1,nextReviewAt:s,learningStep:i,isGraduated:!0,isRelearning:a,lapses:e.lapses}}handleReviewCard(e,t,n){let r,i=e.easeFactor,a=e.repetitions,o=!1,s=0,c=e.lapses;switch(t){case`AGAIN`:c++,o=!0,s=0,i=Math.max(this.config.minEaseFactor,i-.2),r=e.interval;let t=this.config.relearningSteps[0]??10;return{interval:r,easeFactor:i,repetitions:a,nextReviewAt:this.addMinutes(n,t),learningStep:s,isGraduated:!0,isRelearning:!0,lapses:c};case`HARD`:i=Math.max(this.config.minEaseFactor,i-.15),r=Math.max(e.interval+1,e.interval*this.config.hardIntervalModifier);break;case`GOOD`:r=e.interval*i*this.config.intervalModifier,a++;break;case`EASY`:i+=.15,r=e.interval*i*this.config.easyBonus*this.config.intervalModifier,a++;break}return r=Math.min(Math.round(r),this.config.maxInterval),r=Math.max(1,r),{interval:r,easeFactor:i,repetitions:a,nextReviewAt:this.addDays(n,r),learningStep:s,isGraduated:!0,isRelearning:o,lapses:c}}getInitialState(){return{interval:0,easeFactor:2.5,repetitions:0,learningStep:0,isGraduated:!1,isRelearning:!1,lapses:0}}isDue(e,t=new Date){return e<=t}getOverdueDays(e,t=new Date){let n=t.getTime()-e.getTime();return Math.floor(n/(1e3*60*60*24))}addMinutes(e,t){return new Date(e.getTime()+t*60*1e3)}addDays(e,t){return new Date(e.getTime()+t*24*60*60*1e3)}};const n=new t;export{e as DEFAULT_SRS_CONFIG,t as SRSEngine,n as srsEngine};
@@ -0,0 +1 @@
1
+ const e={timezone:`UTC`,freezesPerMonth:2,maxFreezes:5,gracePeriodHours:4};var t=class{config;constructor(t={}){this.config={...e,...t}}update(e,t=new Date){let n=this.getDateString(t),r={state:{...e},streakMaintained:!1,streakLost:!1,freezeUsed:!1,newStreak:!1,daysMissed:0};if(!e.lastActivityDate)return r.state.currentStreak=1,r.state.longestStreak=Math.max(1,e.longestStreak),r.state.lastActivityAt=t,r.state.lastActivityDate=n,r.newStreak=!0,r.streakMaintained=!0,r;if(e.lastActivityDate===n)return r.state.lastActivityAt=t,r.streakMaintained=!0,r;let i=this.getDaysBetween(e.lastActivityDate,n);if(i===1)return r.state.currentStreak=e.currentStreak+1,r.state.longestStreak=Math.max(r.state.currentStreak,e.longestStreak),r.state.lastActivityAt=t,r.state.lastActivityDate=n,r.streakMaintained=!0,r;r.daysMissed=i-1;let a=r.daysMissed;return a<=e.freezesRemaining?(r.state.freezesRemaining=e.freezesRemaining-a,r.state.freezeUsedAt=t,r.state.currentStreak=e.currentStreak+1,r.state.longestStreak=Math.max(r.state.currentStreak,e.longestStreak),r.state.lastActivityAt=t,r.state.lastActivityDate=n,r.freezeUsed=!0,r.streakMaintained=!0,r):(r.streakLost=!0,r.state.currentStreak=1,r.state.lastActivityAt=t,r.state.lastActivityDate=n,r.newStreak=!0,r)}checkStatus(e,t=new Date){if(!e.lastActivityDate)return{isActive:!1,willExpireAt:null,canUseFreeze:!1,daysUntilExpiry:0};let n=this.getDateString(t),r=this.getDaysBetween(e.lastActivityDate,n);if(r===0){let n=this.addDays(t,1);return n.setHours(23,59,59,999),{isActive:!0,willExpireAt:n,canUseFreeze:e.freezesRemaining>0,daysUntilExpiry:1}}if(r===1){let n=new Date(t);return n.setHours(23+this.config.gracePeriodHours,59,59,999),{isActive:!0,willExpireAt:n,canUseFreeze:e.freezesRemaining>0,daysUntilExpiry:0}}let i=r-1;return{isActive:i<=e.freezesRemaining,willExpireAt:null,canUseFreeze:i<=e.freezesRemaining,daysUntilExpiry:-i}}useFreeze(e,t=new Date){return e.freezesRemaining<=0?null:{...e,freezesRemaining:e.freezesRemaining-1,freezeUsedAt:t}}awardMonthlyFreezes(e){return{...e,freezesRemaining:Math.min(e.freezesRemaining+this.config.freezesPerMonth,this.config.maxFreezes)}}getInitialState(){return{currentStreak:0,longestStreak:0,lastActivityAt:null,lastActivityDate:null,freezesRemaining:this.config.freezesPerMonth,freezeUsedAt:null}}getMilestones(e){let t=[3,7,14,30,60,90,180,365,500,1e3];return{achieved:t.filter(t=>e>=t),next:t.find(t=>e<t)??null}}getDateString(e){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}getDaysBetween(e,t){let n=new Date(e),r=new Date(t).getTime()-n.getTime();return Math.floor(r/(1e3*60*60*24))}addDays(e,t){return new Date(e.getTime()+t*24*60*60*1e3)}};const n=new t;export{e as DEFAULT_STREAK_CONFIG,t as StreakEngine,n as streakEngine};
@@ -0,0 +1 @@
1
+ const e={baseValues:{lesson_complete:10,quiz_pass:20,quiz_perfect:50,flashcard_review:1,course_complete:200,module_complete:50,streak_bonus:5,achievement_unlock:0,daily_goal_complete:15,first_lesson:25,onboarding_step:5,onboarding_complete:50},scoreThresholds:[{min:90,multiplier:1.5},{min:80,multiplier:1.25},{min:70,multiplier:1},{min:60,multiplier:.75},{min:0,multiplier:.5}],streakTiers:[{days:365,bonus:50},{days:180,bonus:30},{days:90,bonus:20},{days:30,bonus:15},{days:14,bonus:10},{days:7,bonus:5},{days:3,bonus:2},{days:1,bonus:0}],perfectScoreMultiplier:1.5,firstAttemptBonus:10,retryPenalty:.5,speedBonusMultiplier:1.2,speedBonusThreshold:.8};var t=class{config;constructor(t={}){this.config={...e,...t,baseValues:{...e.baseValues,...t.baseValues},scoreThresholds:t.scoreThresholds||e.scoreThresholds,streakTiers:t.streakTiers||e.streakTiers}}calculate(e){let t=[],n=e.baseXp??this.config.baseValues[e.activity],r=n;if(t.push({source:`base`,amount:n}),e.score!==void 0){let i=this.getScoreMultiplier(e.score);if(i!==1){let e=Math.round(n*(i-1));r+=e,t.push({source:`score_bonus`,amount:e,multiplier:i})}if(e.score===100){let e=Math.round(n*(this.config.perfectScoreMultiplier-1));r+=e,t.push({source:`perfect_score`,amount:e,multiplier:this.config.perfectScoreMultiplier})}}if(e.attemptNumber===1&&!e.isRetry&&(r+=this.config.firstAttemptBonus,t.push({source:`first_attempt`,amount:this.config.firstAttemptBonus})),e.isRetry){let e=Math.round(r*(1-this.config.retryPenalty));r-=e,t.push({source:`retry_penalty`,amount:-e,multiplier:this.config.retryPenalty})}if(e.currentStreak&&e.currentStreak>0){let n=this.getStreakBonus(e.currentStreak);n>0&&(r+=n,t.push({source:`streak_bonus`,amount:n}))}return n>0&&(r=Math.max(1,r)),{totalXp:Math.round(r),baseXp:n,breakdown:t}}calculateStreakBonus(e){let t=this.getStreakBonus(e);return{totalXp:t,baseXp:t,breakdown:[{source:`streak_bonus`,amount:t}]}}getXpForLevel(e){return e<=1?0:Math.round(100*(e-1)**1.5)}getLevelFromXp(e){let t=1,n=this.getXpForLevel(t+1);for(;e>=n&&t<1e3;)t++,n=this.getXpForLevel(t+1);let r=this.getXpForLevel(t),i=this.getXpForLevel(t+1);return{level:t,xpInLevel:e-r,xpForNextLevel:i-r}}getScoreMultiplier(e){for(let t of this.config.scoreThresholds)if(e>=t.min)return t.multiplier;return 1}getStreakBonus(e){for(let t of this.config.streakTiers)if(e>=t.days)return t.bonus;return 0}};const n=new t;export{e as DEFAULT_XP_CONFIG,t as XPEngine,n as xpEngine};
@@ -0,0 +1 @@
1
+ import{defineEntity as e,defineEntityEnum as t,field as n,index as r}from"@lssm/lib.schema";const i=t({name:`LearningStyle`,values:[`VISUAL`,`AUDITORY`,`READING`,`KINESTHETIC`,`MIXED`],schema:`lssm_learning`,description:`Preferred learning style.`}),a=t({name:`RecommendationType`,values:[`COURSE`,`LESSON`,`REVIEW`,`PRACTICE`,`ASSESSMENT`,`DECK`],schema:`lssm_learning`,description:`Type of learning recommendation.`}),o=e({name:`LearnerProfile`,description:`AI personalization profile for a learner.`,schema:`lssm_learning`,map:`learner_profile`,fields:{id:n.id({description:`Unique profile identifier`}),learnerId:n.foreignKey({description:`Learner`}),learningStyle:n.enum(`LearningStyle`,{default:`MIXED`,description:`Preferred learning style`}),preferredDifficulty:n.string({default:`"adaptive"`,description:`Difficulty preference`}),preferredSessionLength:n.int({default:30,description:`Preferred session length in minutes`}),interests:n.json({isOptional:!0,description:`Topic interests`}),goals:n.json({isOptional:!0,description:`Learning goals`}),pacePreference:n.string({default:`"normal"`,description:`Learning pace: slow, normal, fast`}),bestTimeOfDay:n.string({isOptional:!0,description:`Best time for learning`}),averageSessionLength:n.int({isOptional:!0,description:`Average session length`}),daysActivePerWeek:n.int({isOptional:!0,description:`Days active per week`}),avgQuizScore:n.int({isOptional:!0,description:`Average quiz score`}),avgLessonCompletionTime:n.int({isOptional:!0,description:`Avg lesson completion time`}),strengths:n.json({isOptional:!0,description:`Identified strengths`}),weaknesses:n.json({isOptional:!0,description:`Areas for improvement`}),lastAnalyzedAt:n.dateTime({isOptional:!0,description:`Last AI analysis`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`],{name:`learner_profile_unique`}),r.on([`learningStyle`])],enums:[i]}),s=e({name:`SkillMap`,description:`Maps learner proficiency across skills.`,schema:`lssm_learning`,map:`skill_map`,fields:{id:n.id({description:`Unique skill map identifier`}),learnerId:n.foreignKey({description:`Learner`}),skillId:n.string({description:`Skill identifier`}),skillName:n.string({description:`Skill name`}),skillCategory:n.string({isOptional:!0,description:`Skill category`}),level:n.int({default:0,description:`Proficiency level (0-100)`}),confidence:n.decimal({default:.5,description:`Confidence in assessment`}),lessonsCompleted:n.int({default:0,description:`Related lessons completed`}),quizzesCompleted:n.int({default:0,description:`Related quizzes completed`}),practiceTime:n.int({default:0,description:`Practice time in minutes`}),lastPracticedAt:n.dateTime({isOptional:!0,description:`Last practice time`}),learningVelocity:n.decimal({isOptional:!0,description:`Learning speed for this skill`}),predictedTimeToMastery:n.int({isOptional:!0,description:`Predicted time to mastery (minutes)`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`skillId`],{name:`skill_map_unique`}),r.on([`skillId`,`level`]),r.on([`learnerId`,`level`])]}),c=e({name:`LearningPath`,description:`AI-generated personalized learning path.`,schema:`lssm_learning`,map:`learning_path`,fields:{id:n.id({description:`Unique path identifier`}),learnerId:n.foreignKey({description:`Learner`}),name:n.string({description:`Path name`}),description:n.string({isOptional:!0,description:`Path description`}),goal:n.string({isOptional:!0,description:`Path goal`}),steps:n.json({description:`Ordered list of learning steps`}),currentStepIndex:n.int({default:0,description:`Current step index`}),progress:n.int({default:0,description:`Completion percentage`}),completedSteps:n.int({default:0,description:`Steps completed`}),totalSteps:n.int({default:0,description:`Total steps`}),generatedAt:n.dateTime({description:`When path was generated`}),adaptedFrom:n.string({isOptional:!0,description:`Original path ID if adapted`}),generationParams:n.json({isOptional:!0,description:`AI generation parameters`}),adaptationHistory:n.json({isOptional:!0,description:`Path adaptation history`}),isActive:n.boolean({default:!0,description:`Whether path is active`}),isCompleted:n.boolean({default:!1,description:`Whether path is completed`}),startedAt:n.dateTime({isOptional:!0,description:`When started`}),completedAt:n.dateTime({isOptional:!0,description:`When completed`}),estimatedCompletionDate:n.dateTime({isOptional:!0,description:`Estimated completion`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`learnerId`,`isActive`]),r.on([`generatedAt`])]}),l=e({name:`Recommendation`,description:`AI-powered learning recommendation.`,schema:`lssm_learning`,map:`recommendation`,fields:{id:n.id({description:`Unique recommendation identifier`}),learnerId:n.foreignKey({description:`Learner`}),type:n.enum(`RecommendationType`,{description:`Recommendation type`}),itemId:n.string({description:`Recommended item ID`}),itemType:n.string({description:`Item type (course, lesson, deck, etc.)`}),score:n.decimal({description:`Recommendation score (0-1)`}),confidence:n.decimal({description:`Confidence in recommendation`}),reason:n.string({description:`Human-readable reason`}),factors:n.json({isOptional:!0,description:`Factors that contributed to recommendation`}),status:n.string({default:`"pending"`,description:`Status: pending, viewed, accepted, dismissed`}),viewedAt:n.dateTime({isOptional:!0,description:`When viewed`}),acceptedAt:n.dateTime({isOptional:!0,description:`When accepted`}),dismissedAt:n.dateTime({isOptional:!0,description:`When dismissed`}),feedback:n.string({isOptional:!0,description:`User feedback`}),feedbackRating:n.int({isOptional:!0,description:`Feedback rating (1-5)`}),expiresAt:n.dateTime({isOptional:!0,description:`When recommendation expires`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`learnerId`,`status`,`score`]),r.on([`type`,`status`]),r.on([`expiresAt`])],enums:[a]}),u=e({name:`LearningGap`,description:`Identified learning gap.`,schema:`lssm_learning`,map:`learning_gap`,fields:{id:n.id({description:`Unique gap identifier`}),learnerId:n.foreignKey({description:`Learner`}),skillId:n.string({description:`Skill with gap`}),skillName:n.string({description:`Skill name`}),severity:n.string({default:`"moderate"`,description:`Gap severity: minor, moderate, major`}),confidence:n.decimal({description:`Confidence in gap detection`}),evidence:n.json({isOptional:!0,description:`Evidence for gap`}),relatedQuestions:n.json({isOptional:!0,description:`Questions that revealed gap`}),suggestedRemediation:n.json({isOptional:!0,description:`Suggested remediation`}),remediationProgress:n.int({default:0,description:`Remediation progress`}),status:n.string({default:`"open"`,description:`Status: open, in_progress, resolved`}),resolvedAt:n.dateTime({isOptional:!0,description:`When resolved`}),detectedAt:n.dateTime({description:`When gap was detected`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`learnerId`,`status`]),r.on([`skillId`,`status`]),r.on([`severity`,`status`])]}),d=[o,s,c,l,u],f=[i,a];export{o as LearnerProfileEntity,u as LearningGapEntity,c as LearningPathEntity,i as LearningStyleEnum,l as RecommendationEntity,a as RecommendationTypeEnum,s as SkillMapEntity,d as aiEntities,f as aiEnums};
@@ -0,0 +1 @@
1
+ import{defineEntity as e,defineEntityEnum as t,field as n,index as r}from"@lssm/lib.schema";const i=t({name:`CourseDifficulty`,values:[`BEGINNER`,`INTERMEDIATE`,`ADVANCED`,`EXPERT`],schema:`lssm_learning`,description:`Difficulty level of a course.`}),a=t({name:`CourseStatus`,values:[`DRAFT`,`PUBLISHED`,`ARCHIVED`],schema:`lssm_learning`,description:`Publication status of a course.`}),o=t({name:`LessonType`,values:[`CONTENT`,`VIDEO`,`INTERACTIVE`,`QUIZ`,`PRACTICE`,`PROJECT`],schema:`lssm_learning`,description:`Type of lesson content.`}),s=t({name:`ContentType`,values:[`MARKDOWN`,`VIDEO`,`AUDIO`,`EMBED`,`SCORM`,`CUSTOM`],schema:`lssm_learning`,description:`Type of lesson content format.`}),c=e({name:`Course`,description:`A structured learning course.`,schema:`lssm_learning`,map:`course`,fields:{id:n.id({description:`Unique course identifier`}),title:n.string({description:`Course title`}),slug:n.string({isUnique:!0,description:`URL-friendly slug`}),description:n.string({isOptional:!0,description:`Course description`}),summary:n.string({isOptional:!0,description:`Short summary`}),difficulty:n.enum(`CourseDifficulty`,{default:`BEGINNER`,description:`Difficulty level`}),category:n.string({isOptional:!0,description:`Course category`}),tags:n.json({isOptional:!0,description:`Tags for discovery`}),prerequisites:n.json({isOptional:!0,description:`Required course IDs`}),requiredSkills:n.json({isOptional:!0,description:`Required skill levels`}),estimatedDuration:n.int({isOptional:!0,description:`Estimated duration in minutes`}),thumbnailUrl:n.string({isOptional:!0,description:`Thumbnail image URL`}),coverImageUrl:n.string({isOptional:!0,description:`Cover image URL`}),promoVideoUrl:n.string({isOptional:!0,description:`Promo video URL`}),status:n.enum(`CourseStatus`,{default:`DRAFT`,description:`Publication status`}),publishedAt:n.dateTime({isOptional:!0,description:`When published`}),authorId:n.string({description:`Author user ID`}),orgId:n.string({isOptional:!0,description:`Organization scope`}),isPublic:n.boolean({default:!1,description:`Whether course is publicly accessible`}),isFeatured:n.boolean({default:!1,description:`Whether course is featured`}),certificateEnabled:n.boolean({default:!1,description:`Award certificate on completion`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),modules:n.hasMany(`CourseModule`),enrollments:n.hasMany(`Enrollment`)},indexes:[r.on([`orgId`,`status`]),r.on([`category`]),r.on([`difficulty`]),r.on([`authorId`])],enums:[i,a]}),l=e({name:`CourseModule`,description:`A module (section) within a course.`,schema:`lssm_learning`,map:`course_module`,fields:{id:n.id({description:`Unique module identifier`}),courseId:n.foreignKey({description:`Parent course`}),title:n.string({description:`Module title`}),description:n.string({isOptional:!0,description:`Module description`}),order:n.int({default:0,description:`Display order`}),unlockCondition:n.json({isOptional:!0,description:`Conditions to unlock module`}),prerequisiteModuleIds:n.json({isOptional:!0,description:`Required modules to complete first`}),estimatedDuration:n.int({isOptional:!0,description:`Estimated duration in minutes`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),course:n.belongsTo(`Course`,[`courseId`],[`id`],{onDelete:`Cascade`}),lessons:n.hasMany(`Lesson`),completions:n.hasMany(`ModuleCompletion`)},indexes:[r.on([`courseId`,`order`])]}),u=e({name:`Lesson`,description:`An individual lesson within a module.`,schema:`lssm_learning`,map:`lesson`,fields:{id:n.id({description:`Unique lesson identifier`}),moduleId:n.foreignKey({description:`Parent module`}),title:n.string({description:`Lesson title`}),description:n.string({isOptional:!0,description:`Lesson description`}),type:n.enum(`LessonType`,{default:`CONTENT`,description:`Lesson type`}),order:n.int({default:0,description:`Display order`}),estimatedDuration:n.int({isOptional:!0,description:`Estimated duration in minutes`}),xpReward:n.int({default:10,description:`XP awarded on completion`}),isFree:n.boolean({default:!1,description:`Whether lesson is free preview`}),isRequired:n.boolean({default:!0,description:`Whether lesson is required for completion`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),module:n.belongsTo(`CourseModule`,[`moduleId`],[`id`],{onDelete:`Cascade`}),contents:n.hasMany(`LessonContent`),progress:n.hasMany(`LessonProgress`),quizzes:n.hasMany(`Quiz`)},indexes:[r.on([`moduleId`,`order`]),r.on([`type`])],enums:[o]}),d=e({name:`LessonContent`,description:`Content block within a lesson.`,schema:`lssm_learning`,map:`lesson_content`,fields:{id:n.id({description:`Unique content identifier`}),lessonId:n.foreignKey({description:`Parent lesson`}),contentType:n.enum(`ContentType`,{description:`Content format`}),content:n.string({isOptional:!0,description:`Text content (markdown, etc.)`}),mediaUrl:n.string({isOptional:!0,description:`Media URL for video/audio`}),embedData:n.json({isOptional:!0,description:`Embed data for external content`}),order:n.int({default:0,description:`Display order`}),duration:n.int({isOptional:!0,description:`Content duration in seconds`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),lesson:n.belongsTo(`Lesson`,[`lessonId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`lessonId`,`order`])],enums:[s]}),f=[c,l,u,d],p=[i,a,o,s];export{s as ContentTypeEnum,i as CourseDifficultyEnum,c as CourseEntity,l as CourseModuleEntity,a as CourseStatusEnum,d as LessonContentEntity,u as LessonEntity,o as LessonTypeEnum,f as courseEntities,p as courseEnums};
@@ -0,0 +1 @@
1
+ import{defineEntity as e,defineEntityEnum as t,field as n,index as r}from"@lssm/lib.schema";const i=t({name:`CardRating`,values:[`AGAIN`,`HARD`,`GOOD`,`EASY`],schema:`lssm_learning`,description:`Rating for a flashcard review.`}),a=e({name:`Deck`,description:`A collection of flashcards.`,schema:`lssm_learning`,map:`deck`,fields:{id:n.id({description:`Unique deck identifier`}),ownerId:n.foreignKey({description:`Deck owner (learner)`}),title:n.string({description:`Deck title`}),description:n.string({isOptional:!0,description:`Deck description`}),category:n.string({isOptional:!0,description:`Deck category`}),tags:n.json({isOptional:!0,description:`Tags for discovery`}),isPublic:n.boolean({default:!1,description:`Whether deck is publicly visible`}),cardCount:n.int({default:0,description:`Number of cards`}),coverImageUrl:n.string({isOptional:!0,description:`Cover image URL`}),orgId:n.string({isOptional:!0,description:`Organization scope`}),newCardsPerDay:n.int({default:20,description:`New cards to introduce per day`}),reviewsPerDay:n.int({default:100,description:`Maximum reviews per day`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),owner:n.belongsTo(`Learner`,[`ownerId`],[`id`],{onDelete:`Cascade`}),cards:n.hasMany(`Card`)},indexes:[r.on([`ownerId`]),r.on([`isPublic`,`category`]),r.on([`orgId`])]}),o=e({name:`Card`,description:`An individual flashcard.`,schema:`lssm_learning`,map:`card`,fields:{id:n.id({description:`Unique card identifier`}),deckId:n.foreignKey({description:`Parent deck`}),front:n.string({description:`Front of card (question)`}),back:n.string({description:`Back of card (answer)`}),hints:n.json({isOptional:!0,description:`Hints for the card`}),explanation:n.string({isOptional:!0,description:`Detailed explanation`}),frontMediaUrl:n.string({isOptional:!0,description:`Media for front`}),backMediaUrl:n.string({isOptional:!0,description:`Media for back`}),audioUrl:n.string({isOptional:!0,description:`Audio pronunciation`}),tags:n.json({isOptional:!0,description:`Card tags`}),difficulty:n.int({default:0,description:`Card difficulty (0-5)`}),order:n.int({default:0,description:`Card order in deck`}),isSuspended:n.boolean({default:!1,description:`Whether card is suspended`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),deck:n.belongsTo(`Deck`,[`deckId`],[`id`],{onDelete:`Cascade`}),reviews:n.hasMany(`CardReview`),schedules:n.hasMany(`CardSchedule`)},indexes:[r.on([`deckId`,`order`]),r.on([`isSuspended`])]}),s=e({name:`CardReview`,description:`A single review of a flashcard.`,schema:`lssm_learning`,map:`card_review`,fields:{id:n.id({description:`Unique review identifier`}),learnerId:n.foreignKey({description:`Reviewer`}),cardId:n.foreignKey({description:`Reviewed card`}),rating:n.enum(`CardRating`,{description:`Review rating`}),responseTimeMs:n.int({isOptional:!0,description:`Time to respond in ms`}),intervalBefore:n.int({description:`Interval before review (days)`}),easeFactorBefore:n.decimal({description:`Ease factor before review`}),intervalAfter:n.int({description:`Interval after review (days)`}),easeFactorAfter:n.decimal({description:`Ease factor after review`}),reviewType:n.string({default:`"review"`,description:`Type: new, learning, review, relearning`}),reviewedAt:n.dateTime({description:`When reviewed`}),createdAt:n.createdAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`}),card:n.belongsTo(`Card`,[`cardId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`learnerId`,`reviewedAt`]),r.on([`cardId`,`reviewedAt`]),r.on([`rating`])],enums:[i]}),c=e({name:`CardSchedule`,description:`SRS schedule for a learner/card pair.`,schema:`lssm_learning`,map:`card_schedule`,fields:{id:n.id({description:`Unique schedule identifier`}),learnerId:n.foreignKey({description:`Learner`}),cardId:n.foreignKey({description:`Card`}),interval:n.int({default:0,description:`Current interval in days`}),easeFactor:n.decimal({default:2.5,description:`Ease factor (SM-2)`}),repetitions:n.int({default:0,description:`Number of successful repetitions`}),nextReviewAt:n.dateTime({description:`When next review is due`}),lastReviewAt:n.dateTime({isOptional:!0,description:`When last reviewed`}),learningStep:n.int({default:0,description:`Current learning step`}),isGraduated:n.boolean({default:!1,description:`Whether card has graduated`}),isRelearning:n.boolean({default:!1,description:`Whether card is being relearned`}),lapses:n.int({default:0,description:`Number of times card was forgotten`}),reviewCount:n.int({default:0,description:`Total review count`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`}),card:n.belongsTo(`Card`,[`cardId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`cardId`],{name:`card_schedule_unique`}),r.on([`learnerId`,`nextReviewAt`]),r.on([`nextReviewAt`])]}),l=[a,o,s,c],u=[i];export{o as CardEntity,i as CardRatingEnum,s as CardReviewEntity,c as CardScheduleEntity,a as DeckEntity,l as flashcardEntities,u as flashcardEnums};
@@ -0,0 +1 @@
1
+ import{defineEntity as e,defineEntityEnum as t,field as n,index as r}from"@lssm/lib.schema";const i=t({name:`AchievementType`,values:[`MILESTONE`,`STREAK`,`SKILL`,`SOCIAL`,`SPECIAL`,`SEASONAL`],schema:`lssm_learning`,description:`Type of achievement.`}),a=t({name:`LeaderboardPeriod`,values:[`DAILY`,`WEEKLY`,`MONTHLY`,`ALL_TIME`],schema:`lssm_learning`,description:`Leaderboard time period.`}),o=e({name:`Achievement`,description:`An achievement that can be unlocked.`,schema:`lssm_learning`,map:`achievement`,fields:{id:n.id({description:`Unique achievement identifier`}),key:n.string({isUnique:!0,description:`Achievement key`}),name:n.string({description:`Achievement name`}),description:n.string({description:`Achievement description`}),icon:n.string({isOptional:!0,description:`Icon name or URL`}),color:n.string({isOptional:!0,description:`Display color`}),badgeUrl:n.string({isOptional:!0,description:`Badge image URL`}),type:n.enum(`AchievementType`,{default:`MILESTONE`,description:`Achievement type`}),category:n.string({isOptional:!0,description:`Achievement category`}),rarity:n.string({default:`"common"`,description:`Rarity: common, rare, epic, legendary`}),xpReward:n.int({default:50,description:`XP awarded`}),condition:n.json({description:`Unlock condition`}),order:n.int({default:0,description:`Display order`}),isHidden:n.boolean({default:!1,description:`Hide until unlocked`}),isActive:n.boolean({default:!0,description:`Whether achievement is active`}),orgId:n.string({isOptional:!0,description:`Organization scope`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learnerAchievements:n.hasMany(`LearnerAchievement`)},indexes:[r.on([`type`]),r.on([`category`]),r.on([`isActive`]),r.on([`orgId`])],enums:[i]}),s=e({name:`LearnerAchievement`,description:`An achievement unlocked by a learner.`,schema:`lssm_learning`,map:`learner_achievement`,fields:{id:n.id({description:`Unique record identifier`}),learnerId:n.foreignKey({description:`Learner`}),achievementId:n.foreignKey({description:`Achievement`}),xpEarned:n.int({default:0,description:`XP earned`}),progress:n.int({default:100,description:`Progress percentage`}),currentValue:n.int({isOptional:!0,description:`Current value towards goal`}),targetValue:n.int({isOptional:!0,description:`Target value for completion`}),unlockedAt:n.dateTime({description:`When unlocked`}),createdAt:n.createdAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`}),achievement:n.belongsTo(`Achievement`,[`achievementId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`achievementId`],{name:`learner_achievement_unique`}),r.on([`learnerId`,`unlockedAt`]),r.on([`achievementId`])]}),c=e({name:`Streak`,description:`Tracks daily learning streaks.`,schema:`lssm_learning`,map:`streak`,fields:{id:n.id({description:`Unique streak identifier`}),learnerId:n.foreignKey({description:`Learner`}),currentStreak:n.int({default:0,description:`Current streak days`}),longestStreak:n.int({default:0,description:`Longest streak ever`}),lastActivityAt:n.dateTime({isOptional:!0,description:`Last learning activity`}),lastActivityDate:n.string({isOptional:!0,description:`Last activity date (YYYY-MM-DD)`}),freezesRemaining:n.int({default:0,description:`Streak freezes available`}),freezeUsedAt:n.dateTime({isOptional:!0,description:`When last freeze was used`}),streakHistory:n.json({isOptional:!0,description:`Historical streak data`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`],{name:`streak_learner_unique`}),r.on([`currentStreak`]),r.on([`longestStreak`])]}),l=e({name:`DailyGoal`,description:`Daily XP goal tracking.`,schema:`lssm_learning`,map:`daily_goal`,fields:{id:n.id({description:`Unique goal identifier`}),learnerId:n.foreignKey({description:`Learner`}),date:n.string({description:`Date (YYYY-MM-DD)`}),targetXp:n.int({description:`Target XP for the day`}),currentXp:n.int({default:0,description:`XP earned today`}),isCompleted:n.boolean({default:!1,description:`Whether goal was met`}),completedAt:n.dateTime({isOptional:!0,description:`When goal was completed`}),xpBreakdown:n.json({isOptional:!0,description:`XP sources breakdown`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`date`],{name:`daily_goal_unique`}),r.on([`date`,`isCompleted`])]}),u=e({name:`LeaderboardEntry`,description:`Leaderboard entry for a learner.`,schema:`lssm_learning`,map:`leaderboard_entry`,fields:{id:n.id({description:`Unique entry identifier`}),learnerId:n.foreignKey({description:`Learner`}),periodType:n.enum(`LeaderboardPeriod`,{description:`Period type`}),periodKey:n.string({description:`Period key (e.g., 2024-W01)`}),xp:n.int({default:0,description:`XP earned in period`}),rank:n.int({isOptional:!0,description:`Rank in leaderboard`}),lessonsCompleted:n.int({default:0,description:`Lessons completed`}),quizzesPassed:n.int({default:0,description:`Quizzes passed`}),cardsReviewed:n.int({default:0,description:`Cards reviewed`}),streakDays:n.int({default:0,description:`Streak days in period`}),league:n.string({isOptional:!0,description:`League tier`}),orgId:n.string({isOptional:!0,description:`Organization scope`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`periodType`,`periodKey`],{name:`leaderboard_entry_unique`}),r.on([`periodType`,`periodKey`,`xp`]),r.on([`orgId`,`periodType`,`periodKey`,`xp`])],enums:[a]}),d=e({name:`Heart`,description:`Lives/hearts system for quiz attempts.`,schema:`lssm_learning`,map:`heart`,fields:{id:n.id({description:`Unique heart record identifier`}),learnerId:n.foreignKey({description:`Learner`}),current:n.int({default:5,description:`Current hearts`}),max:n.int({default:5,description:`Maximum hearts`}),lastRefillAt:n.dateTime({isOptional:!0,description:`Last refill time`}),nextRefillAt:n.dateTime({isOptional:!0,description:`Next refill time`}),refillIntervalMinutes:n.int({default:240,description:`Minutes between refills`}),infiniteUntil:n.dateTime({isOptional:!0,description:`Infinite hearts until`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`],{name:`heart_learner_unique`}),r.on([`nextRefillAt`])]}),f=e({name:`XPTransaction`,description:`Record of XP earned or spent.`,schema:`lssm_learning`,map:`xp_transaction`,fields:{id:n.id({description:`Unique transaction identifier`}),learnerId:n.foreignKey({description:`Learner`}),amount:n.int({description:`XP amount (positive = earned, negative = spent)`}),type:n.string({description:`Transaction type (lesson, quiz, streak, achievement, etc.)`}),sourceType:n.string({isOptional:!0,description:`Source entity type`}),sourceId:n.string({isOptional:!0,description:`Source entity ID`}),description:n.string({isOptional:!0,description:`Human-readable description`}),balanceAfter:n.int({description:`Total XP after transaction`}),createdAt:n.createdAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`learnerId`,`createdAt`]),r.on([`type`]),r.on([`sourceType`,`sourceId`])]}),p=[o,s,c,l,u,d,f],m=[i,a];export{o as AchievementEntity,i as AchievementTypeEnum,l as DailyGoalEntity,d as HeartEntity,u as LeaderboardEntryEntity,a as LeaderboardPeriodEnum,s as LearnerAchievementEntity,c as StreakEntity,f as XPTransactionEntity,p as gamificationEntities,m as gamificationEnums};
@@ -0,0 +1 @@
1
+ import{ContentTypeEnum as e,CourseDifficultyEnum as t,CourseEntity as n,CourseModuleEntity as r,CourseStatusEnum as ee,LessonContentEntity as i,LessonEntity as a,LessonTypeEnum as o,courseEntities as s,courseEnums as c}from"./course.js";import{CertificateEntity as te,EnrollmentEntity as l,EnrollmentStatusEnum as u,LearnerEntity as d,LessonProgressEntity as ne,ModuleCompletionEntity as re,ProgressStatusEnum as ie,learnerEntities as f,learnerEnums as p}from"./learner.js";import{OnboardingProgressEntity as m,OnboardingStepCompletionEntity as h,OnboardingStepEntity as g,OnboardingStepStatusEnum as _,OnboardingTrackEntity as v,onboardingEntities as y,onboardingEnums as b}from"./onboarding.js";import{CardEntity as x,CardRatingEnum as S,CardReviewEntity as C,CardScheduleEntity as w,DeckEntity as T,flashcardEntities as E,flashcardEnums as D}from"./flashcard.js";import{AttemptStatusEnum as O,QuestionEntity as k,QuestionOptionEntity as A,QuestionTypeEnum as j,QuizAttemptEntity as M,QuizEntity as N,QuizStatusEnum as P,SkillAssessmentEntity as F,quizEntities as I,quizEnums as L}from"./quiz.js";import{AchievementEntity as R,AchievementTypeEnum as z,DailyGoalEntity as B,HeartEntity as V,LeaderboardEntryEntity as H,LeaderboardPeriodEnum as U,LearnerAchievementEntity as W,StreakEntity as G,XPTransactionEntity as K,gamificationEntities as q,gamificationEnums as J}from"./gamification.js";import{LearnerProfileEntity as Y,LearningGapEntity as ae,LearningPathEntity as oe,LearningStyleEnum as se,RecommendationEntity as ce,RecommendationTypeEnum as le,SkillMapEntity as ue,aiEntities as X,aiEnums as Z}from"./ai.js";const Q=[...s,...f,...y,...E,...I,...q,...X],$=[...c,...p,...b,...D,...L,...J,...Z],de={moduleId:`@lssm/module.learning-journey`,entities:Q,enums:$};export{R as AchievementEntity,z as AchievementTypeEnum,O as AttemptStatusEnum,x as CardEntity,S as CardRatingEnum,C as CardReviewEntity,w as CardScheduleEntity,te as CertificateEntity,e as ContentTypeEnum,t as CourseDifficultyEnum,n as CourseEntity,r as CourseModuleEntity,ee as CourseStatusEnum,B as DailyGoalEntity,T as DeckEntity,l as EnrollmentEntity,u as EnrollmentStatusEnum,V as HeartEntity,H as LeaderboardEntryEntity,U as LeaderboardPeriodEnum,W as LearnerAchievementEntity,d as LearnerEntity,Y as LearnerProfileEntity,ae as LearningGapEntity,oe as LearningPathEntity,se as LearningStyleEnum,i as LessonContentEntity,a as LessonEntity,ne as LessonProgressEntity,o as LessonTypeEnum,re as ModuleCompletionEntity,m as OnboardingProgressEntity,h as OnboardingStepCompletionEntity,g as OnboardingStepEntity,_ as OnboardingStepStatusEnum,v as OnboardingTrackEntity,ie as ProgressStatusEnum,k as QuestionEntity,A as QuestionOptionEntity,j as QuestionTypeEnum,M as QuizAttemptEntity,N as QuizEntity,P as QuizStatusEnum,ce as RecommendationEntity,le as RecommendationTypeEnum,F as SkillAssessmentEntity,ue as SkillMapEntity,G as StreakEntity,K as XPTransactionEntity,X as aiEntities,Z as aiEnums,s as courseEntities,c as courseEnums,E as flashcardEntities,D as flashcardEnums,q as gamificationEntities,J as gamificationEnums,f as learnerEntities,p as learnerEnums,Q as learningJourneyEntities,$ as learningJourneyEnums,de as learningJourneySchemaContribution,y as onboardingEntities,b as onboardingEnums,I as quizEntities,L as quizEnums};
@@ -0,0 +1 @@
1
+ import{defineEntity as e,defineEntityEnum as t,field as n,index as r}from"@lssm/lib.schema";const i=t({name:`EnrollmentStatus`,values:[`ENROLLED`,`IN_PROGRESS`,`COMPLETED`,`DROPPED`,`EXPIRED`],schema:`lssm_learning`,description:`Status of a course enrollment.`}),a=t({name:`ProgressStatus`,values:[`NOT_STARTED`,`IN_PROGRESS`,`COMPLETED`,`SKIPPED`],schema:`lssm_learning`,description:`Status of lesson progress.`}),o=e({name:`Learner`,description:`A learner profile.`,schema:`lssm_learning`,map:`learner`,fields:{id:n.id({description:`Unique learner identifier`}),userId:n.string({isUnique:!0,description:`Associated user ID`}),displayName:n.string({isOptional:!0,description:`Display name`}),avatarUrl:n.string({isOptional:!0,description:`Avatar URL`}),bio:n.string({isOptional:!0,description:`Short bio`}),level:n.int({default:1,description:`Current level`}),totalXp:n.int({default:0,description:`Total XP earned`}),currentStreak:n.int({default:0,description:`Current streak days`}),longestStreak:n.int({default:0,description:`Longest streak ever`}),lastActivityAt:n.dateTime({isOptional:!0,description:`Last learning activity`}),timezone:n.string({default:`"UTC"`,description:`Learner timezone`}),dailyGoalXp:n.int({default:50,description:`Daily XP goal`}),reminderEnabled:n.boolean({default:!0,description:`Enable reminders`}),reminderTime:n.string({isOptional:!0,description:`Preferred reminder time`}),orgId:n.string({isOptional:!0,description:`Organization scope`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),enrollments:n.hasMany(`Enrollment`),lessonProgress:n.hasMany(`LessonProgress`),achievements:n.hasMany(`LearnerAchievement`),decks:n.hasMany(`Deck`),profile:n.hasOne(`LearnerProfile`)},indexes:[r.on([`orgId`]),r.on([`totalXp`]),r.on([`level`]),r.on([`currentStreak`])]}),s=e({name:`Enrollment`,description:`A learner enrollment in a course.`,schema:`lssm_learning`,map:`enrollment`,fields:{id:n.id({description:`Unique enrollment identifier`}),learnerId:n.foreignKey({description:`Enrolled learner`}),courseId:n.foreignKey({description:`Enrolled course`}),status:n.enum(`EnrollmentStatus`,{default:`ENROLLED`,description:`Enrollment status`}),progress:n.int({default:0,description:`Completion percentage (0-100)`}),completedLessons:n.int({default:0,description:`Number of completed lessons`}),totalLessons:n.int({default:0,description:`Total lessons in course`}),xpEarned:n.int({default:0,description:`XP earned in this course`}),startedAt:n.dateTime({isOptional:!0,description:`When learner started`}),completedAt:n.dateTime({isOptional:!0,description:`When learner completed`}),lastAccessedAt:n.dateTime({isOptional:!0,description:`Last access time`}),certificateId:n.string({isOptional:!0,description:`Issued certificate ID`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`}),course:n.belongsTo(`Course`,[`courseId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`courseId`],{name:`enrollment_unique`}),r.on([`learnerId`,`status`]),r.on([`courseId`,`status`])],enums:[i]}),c=e({name:`LessonProgress`,description:`Progress tracking for a lesson.`,schema:`lssm_learning`,map:`lesson_progress`,fields:{id:n.id({description:`Unique progress identifier`}),learnerId:n.foreignKey({description:`Learner`}),lessonId:n.foreignKey({description:`Lesson`}),status:n.enum(`ProgressStatus`,{default:`NOT_STARTED`,description:`Progress status`}),progress:n.int({default:0,description:`Completion percentage (0-100)`}),score:n.int({isOptional:!0,description:`Score achieved (for quizzes)`}),attempts:n.int({default:0,description:`Number of attempts`}),bestScore:n.int({isOptional:!0,description:`Best score across attempts`}),timeSpent:n.int({default:0,description:`Time spent in seconds`}),xpEarned:n.int({default:0,description:`XP earned from this lesson`}),startedAt:n.dateTime({isOptional:!0,description:`When started`}),completedAt:n.dateTime({isOptional:!0,description:`When completed`}),lastAccessedAt:n.dateTime({isOptional:!0,description:`Last access time`}),bookmarks:n.json({isOptional:!0,description:`Content bookmarks`}),notes:n.string({isOptional:!0,description:`Learner notes`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`}),lesson:n.belongsTo(`Lesson`,[`lessonId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`lessonId`],{name:`lesson_progress_unique`}),r.on([`learnerId`,`status`]),r.on([`lessonId`])],enums:[a]}),l=e({name:`ModuleCompletion`,description:`Module completion record.`,schema:`lssm_learning`,map:`module_completion`,fields:{id:n.id({description:`Unique completion identifier`}),learnerId:n.foreignKey({description:`Learner`}),moduleId:n.foreignKey({description:`Module`}),score:n.int({isOptional:!0,description:`Average score`}),xpEarned:n.int({default:0,description:`XP earned`}),timeSpent:n.int({default:0,description:`Time spent in seconds`}),completedAt:n.dateTime({description:`When completed`}),createdAt:n.createdAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`}),module:n.belongsTo(`CourseModule`,[`moduleId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`moduleId`],{name:`module_completion_unique`}),r.on([`learnerId`,`completedAt`])]}),u=e({name:`Certificate`,description:`Course completion certificate.`,schema:`lssm_learning`,map:`certificate`,fields:{id:n.id({description:`Unique certificate identifier`}),learnerId:n.foreignKey({description:`Certificate holder`}),courseId:n.foreignKey({description:`Completed course`}),enrollmentId:n.foreignKey({description:`Associated enrollment`}),certificateNumber:n.string({isUnique:!0,description:`Unique certificate number`}),title:n.string({description:`Certificate title`}),description:n.string({isOptional:!0,description:`Certificate description`}),score:n.int({isOptional:!0,description:`Final score`}),grade:n.string({isOptional:!0,description:`Grade awarded`}),issuedAt:n.dateTime({description:`When issued`}),validUntil:n.dateTime({isOptional:!0,description:`Expiration date`}),verificationUrl:n.string({isOptional:!0,description:`Verification URL`}),credentialHash:n.string({isOptional:!0,description:`Credential hash for verification`}),isRevoked:n.boolean({default:!1,description:`Whether certificate is revoked`}),revokedAt:n.dateTime({isOptional:!0,description:`When revoked`}),revokedReason:n.string({isOptional:!0,description:`Revocation reason`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`}),course:n.belongsTo(`Course`,[`courseId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`learnerId`]),r.on([`courseId`]),r.on([`issuedAt`])]}),d=[o,s,c,l,u],f=[i,a];export{u as CertificateEntity,s as EnrollmentEntity,i as EnrollmentStatusEnum,o as LearnerEntity,c as LessonProgressEntity,l as ModuleCompletionEntity,a as ProgressStatusEnum,d as learnerEntities,f as learnerEnums};
@@ -0,0 +1 @@
1
+ import{defineEntity as e,defineEntityEnum as t,field as n,index as r}from"@lssm/lib.schema";const i=t({name:`OnboardingStepStatus`,values:[`PENDING`,`IN_PROGRESS`,`COMPLETED`,`SKIPPED`],schema:`lssm_learning`,description:`Status of an onboarding step.`}),a=e({name:`OnboardingTrack`,description:`An onboarding track for a product.`,schema:`lssm_learning`,map:`onboarding_track`,fields:{id:n.id({description:`Unique track identifier`}),productId:n.string({description:`Product this track is for`}),name:n.string({description:`Track name`}),description:n.string({isOptional:!0,description:`Track description`}),targetUserSegment:n.string({isOptional:!0,description:`Target user segment`}),targetRole:n.string({isOptional:!0,description:`Target user role`}),welcomeTitle:n.string({isOptional:!0,description:`Welcome message title`}),welcomeMessage:n.string({isOptional:!0,description:`Welcome message`}),completionTitle:n.string({isOptional:!0,description:`Completion message title`}),completionMessage:n.string({isOptional:!0,description:`Completion message`}),isActive:n.boolean({default:!0,description:`Whether track is active`}),isRequired:n.boolean({default:!1,description:`Whether track is required`}),canSkip:n.boolean({default:!0,description:`Whether steps can be skipped`}),totalXp:n.int({default:100,description:`Total XP for completing track`}),completionXpBonus:n.int({isOptional:!0,description:`Bonus XP for completing track`}),completionBadgeKey:n.string({isOptional:!0,description:`Badge awarded on completion`}),streakHoursWindow:n.int({isOptional:!0,description:`Hours window to finish for streak bonus`}),streakBonusXp:n.int({isOptional:!0,description:`Bonus XP if completed within streak window`}),orgId:n.string({isOptional:!0,description:`Organization scope`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),steps:n.hasMany(`OnboardingStep`),progress:n.hasMany(`OnboardingProgress`)},indexes:[r.on([`productId`,`isActive`]),r.on([`orgId`]),r.unique([`productId`,`targetUserSegment`,`targetRole`],{name:`onboarding_track_target`})]}),o=e({name:`OnboardingStep`,description:`A step in an onboarding track.`,schema:`lssm_learning`,map:`onboarding_step`,fields:{id:n.id({description:`Unique step identifier`}),trackId:n.foreignKey({description:`Parent track`}),title:n.string({description:`Step title`}),description:n.string({isOptional:!0,description:`Step description`}),instructions:n.string({isOptional:!0,description:`How to complete the step`}),helpUrl:n.string({isOptional:!0,description:`Link to help documentation`}),order:n.int({default:0,description:`Display order`}),triggerEvent:n.string({isOptional:!0,description:`Event that triggers step start`}),completionEvent:n.string({description:`Event that completes the step`}),completionEventVersion:n.int({isOptional:!0,description:`Version of the completion event`}),completionSourceModule:n.string({isOptional:!0,description:`Module emitting the completion event`}),completionEventFilter:n.json({isOptional:!0,description:`Filter for completion event`}),actionUrl:n.string({isOptional:!0,description:`URL to navigate to complete`}),actionLabel:n.string({isOptional:!0,description:`Action button label`}),highlightSelector:n.string({isOptional:!0,description:`CSS selector to highlight`}),tooltipPosition:n.string({isOptional:!0,description:`Tooltip position`}),xpReward:n.int({default:10,description:`XP for completing step`}),isRequired:n.boolean({default:!0,description:`Whether step is required`}),canSkip:n.boolean({default:!0,description:`Whether step can be skipped`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),track:n.belongsTo(`OnboardingTrack`,[`trackId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`trackId`,`order`]),r.on([`completionEvent`])]}),s=e({name:`OnboardingProgress`,description:`Tracks user progress through an onboarding track.`,schema:`lssm_learning`,map:`onboarding_progress`,fields:{id:n.id({description:`Unique progress identifier`}),learnerId:n.foreignKey({description:`Learner`}),trackId:n.foreignKey({description:`Onboarding track`}),currentStepId:n.string({isOptional:!0,description:`Current step ID`}),completedSteps:n.json({default:`[]`,description:`Array of completed step IDs`}),skippedSteps:n.json({default:`[]`,description:`Array of skipped step IDs`}),progress:n.int({default:0,description:`Completion percentage (0-100)`}),isCompleted:n.boolean({default:!1,description:`Whether track is completed`}),xpEarned:n.int({default:0,description:`XP earned from track`}),startedAt:n.dateTime({description:`When user started`}),completedAt:n.dateTime({isOptional:!0,description:`When user completed`}),lastActivityAt:n.dateTime({isOptional:!0,description:`Last activity`}),isDismissed:n.boolean({default:!1,description:`Whether user dismissed onboarding`}),dismissedAt:n.dateTime({isOptional:!0,description:`When dismissed`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`}),track:n.belongsTo(`OnboardingTrack`,[`trackId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`trackId`],{name:`onboarding_progress_unique`}),r.on([`learnerId`,`isCompleted`]),r.on([`trackId`])],enums:[i]}),c=e({name:`OnboardingStepCompletion`,description:`Individual step completion record.`,schema:`lssm_learning`,map:`onboarding_step_completion`,fields:{id:n.id({description:`Unique completion identifier`}),progressId:n.foreignKey({description:`Parent progress record`}),stepId:n.foreignKey({description:`Completed step`}),status:n.enum(`OnboardingStepStatus`,{description:`Completion status`}),xpEarned:n.int({default:0,description:`XP earned`}),triggeringEvent:n.string({isOptional:!0,description:`Event that triggered completion`}),eventPayload:n.json({isOptional:!0,description:`Event payload`}),completedAt:n.dateTime({description:`When completed`}),createdAt:n.createdAt(),progress:n.belongsTo(`OnboardingProgress`,[`progressId`],[`id`],{onDelete:`Cascade`}),step:n.belongsTo(`OnboardingStep`,[`stepId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`progressId`,`stepId`],{name:`step_completion_unique`}),r.on([`completedAt`])]}),l=[a,o,s,c],u=[i];export{s as OnboardingProgressEntity,c as OnboardingStepCompletionEntity,o as OnboardingStepEntity,i as OnboardingStepStatusEnum,a as OnboardingTrackEntity,l as onboardingEntities,u as onboardingEnums};
@@ -0,0 +1 @@
1
+ import{defineEntity as e,defineEntityEnum as t,field as n,index as r}from"@lssm/lib.schema";const i=t({name:`QuestionType`,values:[`MULTIPLE_CHOICE`,`TRUE_FALSE`,`FILL_BLANK`,`MATCHING`,`SHORT_ANSWER`,`CODE`],schema:`lssm_learning`,description:`Type of quiz question.`}),a=t({name:`QuizStatus`,values:[`DRAFT`,`PUBLISHED`,`ARCHIVED`],schema:`lssm_learning`,description:`Publication status of a quiz.`}),o=t({name:`AttemptStatus`,values:[`IN_PROGRESS`,`COMPLETED`,`TIMED_OUT`,`ABANDONED`],schema:`lssm_learning`,description:`Status of a quiz attempt.`}),s=e({name:`Quiz`,description:`A quiz assessment.`,schema:`lssm_learning`,map:`quiz`,fields:{id:n.id({description:`Unique quiz identifier`}),lessonId:n.foreignKey({isOptional:!0,description:`Associated lesson`}),title:n.string({description:`Quiz title`}),description:n.string({isOptional:!0,description:`Quiz description`}),instructions:n.string({isOptional:!0,description:`Quiz instructions`}),passingScore:n.int({default:70,description:`Passing score percentage`}),timeLimit:n.int({isOptional:!0,description:`Time limit in seconds`}),maxAttempts:n.int({isOptional:!0,description:`Maximum attempts allowed`}),shuffleQuestions:n.boolean({default:!1,description:`Shuffle question order`}),shuffleOptions:n.boolean({default:!1,description:`Shuffle answer options`}),showCorrectAnswers:n.boolean({default:!0,description:`Show correct answers after`}),showExplanations:n.boolean({default:!0,description:`Show explanations after`}),status:n.enum(`QuizStatus`,{default:`DRAFT`,description:`Publication status`}),totalPoints:n.int({default:0,description:`Total points available`}),xpReward:n.int({default:20,description:`XP for passing`}),orgId:n.string({isOptional:!0,description:`Organization scope`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),lesson:n.belongsTo(`Lesson`,[`lessonId`],[`id`],{onDelete:`Cascade`}),questions:n.hasMany(`Question`),attempts:n.hasMany(`QuizAttempt`)},indexes:[r.on([`lessonId`]),r.on([`status`]),r.on([`orgId`])],enums:[a]}),c=e({name:`Question`,description:`A quiz question.`,schema:`lssm_learning`,map:`question`,fields:{id:n.id({description:`Unique question identifier`}),quizId:n.foreignKey({description:`Parent quiz`}),type:n.enum(`QuestionType`,{description:`Question type`}),content:n.string({description:`Question text`}),mediaUrl:n.string({isOptional:!0,description:`Question media`}),points:n.int({default:1,description:`Points for correct answer`}),codeLanguage:n.string({isOptional:!0,description:`Programming language`}),codeTemplate:n.string({isOptional:!0,description:`Starter code template`}),testCases:n.json({isOptional:!0,description:`Test cases for code validation`}),explanation:n.string({isOptional:!0,description:`Explanation of correct answer`}),hint:n.string({isOptional:!0,description:`Hint for the question`}),order:n.int({default:0,description:`Display order`}),skillId:n.string({isOptional:!0,description:`Associated skill`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),quiz:n.belongsTo(`Quiz`,[`quizId`],[`id`],{onDelete:`Cascade`}),options:n.hasMany(`QuestionOption`)},indexes:[r.on([`quizId`,`order`]),r.on([`type`]),r.on([`skillId`])],enums:[i]}),l=e({name:`QuestionOption`,description:`An answer option for a question.`,schema:`lssm_learning`,map:`question_option`,fields:{id:n.id({description:`Unique option identifier`}),questionId:n.foreignKey({description:`Parent question`}),content:n.string({description:`Option text`}),matchContent:n.string({isOptional:!0,description:`Match pair content`}),isCorrect:n.boolean({default:!1,description:`Whether option is correct`}),feedback:n.string({isOptional:!0,description:`Feedback when selected`}),order:n.int({default:0,description:`Display order`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),question:n.belongsTo(`Question`,[`questionId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`questionId`,`order`])]}),u=e({name:`QuizAttempt`,description:`A learner quiz attempt.`,schema:`lssm_learning`,map:`quiz_attempt`,fields:{id:n.id({description:`Unique attempt identifier`}),learnerId:n.foreignKey({description:`Learner`}),quizId:n.foreignKey({description:`Quiz`}),status:n.enum(`AttemptStatus`,{default:`IN_PROGRESS`,description:`Attempt status`}),score:n.int({isOptional:!0,description:`Score achieved`}),percentageScore:n.int({isOptional:!0,description:`Percentage score`}),passed:n.boolean({isOptional:!0,description:`Whether passed`}),totalQuestions:n.int({default:0,description:`Total questions`}),answeredQuestions:n.int({default:0,description:`Questions answered`}),correctAnswers:n.int({default:0,description:`Correct answers`}),answers:n.json({isOptional:!0,description:`Submitted answers`}),xpEarned:n.int({default:0,description:`XP earned`}),timeSpent:n.int({default:0,description:`Time spent in seconds`}),startedAt:n.dateTime({description:`When started`}),completedAt:n.dateTime({isOptional:!0,description:`When completed`}),attemptNumber:n.int({default:1,description:`Which attempt this is`}),metadata:n.json({isOptional:!0,description:`Additional metadata`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`}),quiz:n.belongsTo(`Quiz`,[`quizId`],[`id`],{onDelete:`Cascade`})},indexes:[r.on([`learnerId`,`quizId`]),r.on([`learnerId`,`status`]),r.on([`quizId`,`status`])],enums:[o]}),d=e({name:`SkillAssessment`,description:`Assessment of a skill based on quiz performance.`,schema:`lssm_learning`,map:`skill_assessment`,fields:{id:n.id({description:`Unique assessment identifier`}),learnerId:n.foreignKey({description:`Learner`}),skillId:n.string({description:`Skill identifier`}),skillName:n.string({description:`Skill name`}),level:n.int({default:1,description:`Proficiency level (1-5)`}),score:n.int({default:0,description:`Assessment score (0-100)`}),confidence:n.decimal({default:.5,description:`Confidence in assessment`}),questionsAnswered:n.int({default:0,description:`Total questions answered`}),questionsCorrect:n.int({default:0,description:`Total correct`}),assessedAt:n.dateTime({description:`Last assessment time`}),createdAt:n.createdAt(),updatedAt:n.updatedAt(),learner:n.belongsTo(`Learner`,[`learnerId`],[`id`],{onDelete:`Cascade`})},indexes:[r.unique([`learnerId`,`skillId`],{name:`skill_assessment_unique`}),r.on([`learnerId`,`level`]),r.on([`skillId`])]}),f=[s,c,l,u,d],p=[i,a,o];export{o as AttemptStatusEnum,c as QuestionEntity,l as QuestionOptionEntity,i as QuestionTypeEnum,u as QuizAttemptEntity,s as QuizEntity,a as QuizStatusEnum,d as SkillAssessmentEntity,f as quizEntities,p as quizEnums};
package/dist/events.js ADDED
@@ -0,0 +1 @@
1
+ import{ScalarTypeEnum as e,defineSchemaModel as t}from"@lssm/lib.schema";import{defineEvent as n}from"@lssm/lib.contracts";const r=n({name:`course.published`,version:1,description:`A course has been published.`,payload:t({name:`CoursePublishedEventPayload`,description:`Payload when a course is published`,fields:{courseId:{type:e.String_unsecure(),isOptional:!1},title:{type:e.String_unsecure(),isOptional:!1},authorId:{type:e.String_unsecure(),isOptional:!1},publishedAt:{type:e.DateTime(),isOptional:!1}}})}),i=n({name:`enrollment.created`,version:1,description:`A learner has enrolled in a course.`,payload:t({name:`EnrollmentCreatedEventPayload`,description:`Payload when a learner enrolls in a course`,fields:{enrollmentId:{type:e.String_unsecure(),isOptional:!1},learnerId:{type:e.String_unsecure(),isOptional:!1},courseId:{type:e.String_unsecure(),isOptional:!1},enrolledAt:{type:e.DateTime(),isOptional:!1}}})}),a=n({name:`lesson.completed`,version:1,description:`A learner has completed a lesson.`,payload:t({name:`LessonCompletedEventPayload`,description:`Payload when a lesson is completed`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},lessonId:{type:e.String_unsecure(),isOptional:!1},courseId:{type:e.String_unsecure(),isOptional:!1},score:{type:e.Int_unsecure(),isOptional:!0},xpEarned:{type:e.Int_unsecure(),isOptional:!1},timeSpent:{type:e.Int_unsecure(),isOptional:!1},completedAt:{type:e.DateTime(),isOptional:!1}}})}),o=n({name:`course.completed`,version:1,description:`A learner has completed a course.`,payload:t({name:`CourseCompletedEventPayload`,description:`Payload when a course is completed`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},courseId:{type:e.String_unsecure(),isOptional:!1},enrollmentId:{type:e.String_unsecure(),isOptional:!1},score:{type:e.Int_unsecure(),isOptional:!0},xpEarned:{type:e.Int_unsecure(),isOptional:!1},certificateId:{type:e.String_unsecure(),isOptional:!0},completedAt:{type:e.DateTime(),isOptional:!1}}})}),s=n({name:`onboarding.started`,version:1,description:`A learner has started onboarding.`,payload:t({name:`OnboardingStartedEventPayload`,description:`Payload when onboarding starts`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},trackId:{type:e.String_unsecure(),isOptional:!1},productId:{type:e.String_unsecure(),isOptional:!1},startedAt:{type:e.DateTime(),isOptional:!1}}})}),c=n({name:`onboarding.step_completed`,version:1,description:`An onboarding step has been completed.`,payload:t({name:`OnboardingStepCompletedEventPayload`,description:`Payload when an onboarding step is completed`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},trackId:{type:e.String_unsecure(),isOptional:!1},stepId:{type:e.String_unsecure(),isOptional:!1},triggeringEvent:{type:e.String_unsecure(),isOptional:!0},xpEarned:{type:e.Int_unsecure(),isOptional:!1},completedAt:{type:e.DateTime(),isOptional:!1}}})}),l=n({name:`onboarding.completed`,version:1,description:`A learner has completed onboarding.`,payload:t({name:`OnboardingCompletedEventPayload`,description:`Payload when onboarding is completed`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},trackId:{type:e.String_unsecure(),isOptional:!1},productId:{type:e.String_unsecure(),isOptional:!1},xpEarned:{type:e.Int_unsecure(),isOptional:!1},completedAt:{type:e.DateTime(),isOptional:!1}}})}),u=n({name:`flashcard.reviewed`,version:1,description:`A flashcard has been reviewed.`,payload:t({name:`CardReviewedEventPayload`,description:`Payload when a flashcard is reviewed`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},cardId:{type:e.String_unsecure(),isOptional:!1},deckId:{type:e.String_unsecure(),isOptional:!1},rating:{type:e.String_unsecure(),isOptional:!1},responseTimeMs:{type:e.Int_unsecure(),isOptional:!0},reviewedAt:{type:e.DateTime(),isOptional:!1}}})}),d=n({name:`quiz.started`,version:1,description:`A quiz attempt has started.`,payload:t({name:`QuizStartedEventPayload`,description:`Payload when a quiz is started`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},quizId:{type:e.String_unsecure(),isOptional:!1},attemptId:{type:e.String_unsecure(),isOptional:!1},attemptNumber:{type:e.Int_unsecure(),isOptional:!1},startedAt:{type:e.DateTime(),isOptional:!1}}})}),f=n({name:`quiz.completed`,version:1,description:`A quiz attempt has been completed.`,payload:t({name:`QuizCompletedEventPayload`,description:`Payload when a quiz is completed`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},quizId:{type:e.String_unsecure(),isOptional:!1},attemptId:{type:e.String_unsecure(),isOptional:!1},score:{type:e.Int_unsecure(),isOptional:!1},percentageScore:{type:e.Int_unsecure(),isOptional:!1},passed:{type:e.Boolean(),isOptional:!1},xpEarned:{type:e.Int_unsecure(),isOptional:!1},timeSpent:{type:e.Int_unsecure(),isOptional:!1},completedAt:{type:e.DateTime(),isOptional:!1}}})}),p=n({name:`xp.earned`,version:1,description:`XP has been earned.`,payload:t({name:`XpEarnedEventPayload`,description:`Payload when XP is earned`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},amount:{type:e.Int_unsecure(),isOptional:!1},source:{type:e.String_unsecure(),isOptional:!1},sourceId:{type:e.String_unsecure(),isOptional:!0},totalXp:{type:e.Int_unsecure(),isOptional:!1},earnedAt:{type:e.DateTime(),isOptional:!1}}})}),m=n({name:`level.up`,version:1,description:`A learner has leveled up.`,payload:t({name:`LevelUpEventPayload`,description:`Payload when a learner levels up`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},previousLevel:{type:e.Int_unsecure(),isOptional:!1},newLevel:{type:e.Int_unsecure(),isOptional:!1},totalXp:{type:e.Int_unsecure(),isOptional:!1},leveledUpAt:{type:e.DateTime(),isOptional:!1}}})}),h=n({name:`streak.updated`,version:1,description:`A streak has been updated.`,payload:t({name:`StreakUpdatedEventPayload`,description:`Payload when a streak is updated`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},previousStreak:{type:e.Int_unsecure(),isOptional:!1},currentStreak:{type:e.Int_unsecure(),isOptional:!1},longestStreak:{type:e.Int_unsecure(),isOptional:!1},freezeUsed:{type:e.Boolean(),isOptional:!1},updatedAt:{type:e.DateTime(),isOptional:!1}}})}),g=n({name:`achievement.unlocked`,version:1,description:`An achievement has been unlocked.`,payload:t({name:`AchievementUnlockedEventPayload`,description:`Payload when an achievement is unlocked`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},achievementId:{type:e.String_unsecure(),isOptional:!1},achievementKey:{type:e.String_unsecure(),isOptional:!1},achievementName:{type:e.String_unsecure(),isOptional:!1},xpEarned:{type:e.Int_unsecure(),isOptional:!1},unlockedAt:{type:e.DateTime(),isOptional:!1}}})}),_=n({name:`daily_goal.completed`,version:1,description:`A daily goal has been completed.`,payload:t({name:`DailyGoalCompletedEventPayload`,description:`Payload when a daily goal is completed`,fields:{learnerId:{type:e.String_unsecure(),isOptional:!1},date:{type:e.String_unsecure(),isOptional:!1},targetXp:{type:e.Int_unsecure(),isOptional:!1},actualXp:{type:e.Int_unsecure(),isOptional:!1},completedAt:{type:e.DateTime(),isOptional:!1}}})}),v=n({name:`certificate.issued`,version:1,description:`A certificate has been issued.`,payload:t({name:`CertificateIssuedEventPayload`,description:`Payload when a certificate is issued`,fields:{certificateId:{type:e.String_unsecure(),isOptional:!1},learnerId:{type:e.String_unsecure(),isOptional:!1},courseId:{type:e.String_unsecure(),isOptional:!1},certificateNumber:{type:e.String_unsecure(),isOptional:!1},issuedAt:{type:e.DateTime(),isOptional:!1}}})}),y={CoursePublishedEvent:r,EnrollmentCreatedEvent:i,LessonCompletedEvent:a,CourseCompletedEvent:o,OnboardingStartedEvent:s,OnboardingStepCompletedEvent:c,OnboardingCompletedEvent:l,CardReviewedEvent:u,QuizStartedEvent:d,QuizCompletedEvent:f,XpEarnedEvent:p,LevelUpEvent:m,StreakUpdatedEvent:h,AchievementUnlockedEvent:g,DailyGoalCompletedEvent:_,CertificateIssuedEvent:v};export{g as AchievementUnlockedEvent,u as CardReviewedEvent,v as CertificateIssuedEvent,o as CourseCompletedEvent,r as CoursePublishedEvent,_ as DailyGoalCompletedEvent,i as EnrollmentCreatedEvent,y as LearningJourneyEvents,a as LessonCompletedEvent,m as LevelUpEvent,l as OnboardingCompletedEvent,s as OnboardingStartedEvent,c as OnboardingStepCompletedEvent,f as QuizCompletedEvent,d as QuizStartedEvent,h as StreakUpdatedEvent,p as XpEarnedEvent};
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ import{AchievementUnlockedEvent as e,CardReviewedEvent as t,CertificateIssuedEvent as n,CourseCompletedEvent as r,CoursePublishedEvent as i,DailyGoalCompletedEvent as a,EnrollmentCreatedEvent as o,LearningJourneyEvents as s,LessonCompletedEvent as c,LevelUpEvent as l,OnboardingCompletedEvent as u,OnboardingStartedEvent as d,OnboardingStepCompletedEvent as f,QuizCompletedEvent as p,QuizStartedEvent as m,StreakUpdatedEvent as h,XpEarnedEvent as g}from"./events.js";import{ContentTypeEnum as _,CourseDifficultyEnum as v,CourseEntity as y,CourseModuleEntity as b,CourseStatusEnum as x,LessonContentEntity as S,LessonEntity as C,LessonTypeEnum as w,courseEntities as T,courseEnums as E}from"./entities/course.js";import{CertificateEntity as D,EnrollmentEntity as O,EnrollmentStatusEnum as k,LearnerEntity as A,LessonProgressEntity as j,ModuleCompletionEntity as M,ProgressStatusEnum as N,learnerEntities as P,learnerEnums as F}from"./entities/learner.js";import{OnboardingProgressEntity as I,OnboardingStepCompletionEntity as L,OnboardingStepEntity as R,OnboardingStepStatusEnum as z,OnboardingTrackEntity as B,onboardingEntities as V,onboardingEnums as H}from"./entities/onboarding.js";import{CardEntity as U,CardRatingEnum as W,CardReviewEntity as G,CardScheduleEntity as K,DeckEntity as q,flashcardEntities as J,flashcardEnums as Y}from"./entities/flashcard.js";import{AttemptStatusEnum as X,QuestionEntity as Z,QuestionOptionEntity as Q,QuestionTypeEnum as $,QuizAttemptEntity as ee,QuizEntity as te,QuizStatusEnum as ne,SkillAssessmentEntity as re,quizEntities as ie,quizEnums as ae}from"./entities/quiz.js";import{AchievementEntity as oe,AchievementTypeEnum as se,DailyGoalEntity as ce,HeartEntity as le,LeaderboardEntryEntity as ue,LeaderboardPeriodEnum as de,LearnerAchievementEntity as fe,StreakEntity as pe,XPTransactionEntity as me,gamificationEntities as he,gamificationEnums as ge}from"./entities/gamification.js";import{LearnerProfileEntity as _e,LearningGapEntity as ve,LearningPathEntity as ye,LearningStyleEnum as be,RecommendationEntity as xe,RecommendationTypeEnum as Se,SkillMapEntity as Ce,aiEntities as we,aiEnums as Te}from"./entities/ai.js";import{learningJourneyEntities as Ee,learningJourneyEnums as De,learningJourneySchemaContribution as Oe}from"./entities/index.js";import{LEARNING_JOURNEY_OWNERS as ke}from"./contracts/shared.js";import{AchievementModel as Ae,CardModel as je,CompleteLessonInput as Me,CourseModel as Ne,DeckModel as Pe,EnrollInCourseInput as Fe,EnrollmentModel as Ie,GetDueCardsInput as Le,GetDueCardsOutput as Re,GetLearnerDashboardInput as ze,LearnerDashboardModel as Be,LearnerModel as Ve,ProgressModel as He,SubmitCardReviewInput as Ue,SuccessOutput as We}from"./contracts/models.js";import{CompleteLessonContract as Ge,EnrollInCourseContract as Ke,GetDueCardsContract as qe,GetLearnerDashboardContract as Je,SubmitCardReviewContract as Ye}from"./contracts/operations.js";import{GetOnboardingProgressContract as Xe,ListOnboardingTracksContract as Ze,OnboardingProgressModel as Qe,OnboardingStepModel as $e,OnboardingStepProgressModel as et,OnboardingTrackModel as tt,RecordOnboardingEventContract as nt}from"./contracts/onboarding.js";import"./contracts/index.js";import{DEFAULT_SRS_CONFIG as rt,SRSEngine as it,srsEngine as at}from"./engines/srs.js";import{DEFAULT_XP_CONFIG as ot,XPEngine as st,xpEngine as ct}from"./engines/xp.js";import{DEFAULT_STREAK_CONFIG as lt,StreakEngine as ut,streakEngine as dt}from"./engines/streak.js";import"./engines/index.js";import"./docs/index.js";export{oe as AchievementEntity,Ae as AchievementModel,se as AchievementTypeEnum,e as AchievementUnlockedEvent,X as AttemptStatusEnum,U as CardEntity,je as CardModel,W as CardRatingEnum,G as CardReviewEntity,t as CardReviewedEvent,K as CardScheduleEntity,D as CertificateEntity,n as CertificateIssuedEvent,Ge as CompleteLessonContract,Me as CompleteLessonInput,_ as ContentTypeEnum,r as CourseCompletedEvent,v as CourseDifficultyEnum,y as CourseEntity,Ne as CourseModel,b as CourseModuleEntity,i as CoursePublishedEvent,x as CourseStatusEnum,rt as DEFAULT_SRS_CONFIG,lt as DEFAULT_STREAK_CONFIG,ot as DEFAULT_XP_CONFIG,a as DailyGoalCompletedEvent,ce as DailyGoalEntity,q as DeckEntity,Pe as DeckModel,Ke as EnrollInCourseContract,Fe as EnrollInCourseInput,o as EnrollmentCreatedEvent,O as EnrollmentEntity,Ie as EnrollmentModel,k as EnrollmentStatusEnum,qe as GetDueCardsContract,Le as GetDueCardsInput,Re as GetDueCardsOutput,Je as GetLearnerDashboardContract,ze as GetLearnerDashboardInput,Xe as GetOnboardingProgressContract,le as HeartEntity,ke as LEARNING_JOURNEY_OWNERS,ue as LeaderboardEntryEntity,de as LeaderboardPeriodEnum,fe as LearnerAchievementEntity,Be as LearnerDashboardModel,A as LearnerEntity,Ve as LearnerModel,_e as LearnerProfileEntity,ve as LearningGapEntity,s as LearningJourneyEvents,ye as LearningPathEntity,be as LearningStyleEnum,c as LessonCompletedEvent,S as LessonContentEntity,C as LessonEntity,j as LessonProgressEntity,w as LessonTypeEnum,l as LevelUpEvent,Ze as ListOnboardingTracksContract,M as ModuleCompletionEntity,u as OnboardingCompletedEvent,I as OnboardingProgressEntity,Qe as OnboardingProgressModel,d as OnboardingStartedEvent,f as OnboardingStepCompletedEvent,L as OnboardingStepCompletionEntity,R as OnboardingStepEntity,$e as OnboardingStepModel,et as OnboardingStepProgressModel,z as OnboardingStepStatusEnum,B as OnboardingTrackEntity,tt as OnboardingTrackModel,He as ProgressModel,N as ProgressStatusEnum,Z as QuestionEntity,Q as QuestionOptionEntity,$ as QuestionTypeEnum,ee as QuizAttemptEntity,p as QuizCompletedEvent,te as QuizEntity,m as QuizStartedEvent,ne as QuizStatusEnum,xe as RecommendationEntity,Se as RecommendationTypeEnum,nt as RecordOnboardingEventContract,it as SRSEngine,re as SkillAssessmentEntity,Ce as SkillMapEntity,ut as StreakEngine,pe as StreakEntity,h as StreakUpdatedEvent,Ye as SubmitCardReviewContract,Ue as SubmitCardReviewInput,We as SuccessOutput,st as XPEngine,me as XPTransactionEntity,g as XpEarnedEvent,we as aiEntities,Te as aiEnums,T as courseEntities,E as courseEnums,J as flashcardEntities,Y as flashcardEnums,he as gamificationEntities,ge as gamificationEnums,P as learnerEntities,F as learnerEnums,Ee as learningJourneyEntities,De as learningJourneyEnums,Oe as learningJourneySchemaContribution,V as onboardingEntities,H as onboardingEnums,ie as quizEntities,ae as quizEnums,at as srsEngine,dt as streakEngine,ct as xpEngine};
File without changes
package/package.json ADDED
@@ -0,0 +1,87 @@
1
+ {
2
+ "name": "@lssm/module.learning-journey",
3
+ "version": "0.0.0-canary-20251212004227",
4
+ "description": "Comprehensive learning journey engine - onboarding, LMS, flashcards, gamification, and AI personalization",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "type": "module",
8
+ "scripts": {
9
+ "publish:pkg": "bun publish --tolerate-republish --ignore-scripts --verbose",
10
+ "build": "bun build:bundle && bun build:types",
11
+ "build:bundle": "tsdown",
12
+ "build:types": "tsc --noEmit",
13
+ "dev": "bun build:bundle --watch",
14
+ "clean": "rimraf dist .turbo",
15
+ "lint": "bun lint:fix",
16
+ "lint:fix": "eslint src --fix",
17
+ "lint:check": "eslint src"
18
+ },
19
+ "dependencies": {
20
+ "@lssm/lib.schema": "workspace:*",
21
+ "@lssm/lib.contracts": "workspace:*",
22
+ "zod": "^4.1.13"
23
+ },
24
+ "devDependencies": {
25
+ "@lssm/tool.typescript": "workspace:*",
26
+ "@lssm/tool.tsdown": "workspace:*",
27
+ "typescript": "^5.9.3"
28
+ },
29
+ "exports": {
30
+ ".": "./src/index.ts",
31
+ "./contracts": "./src/contracts/index.ts",
32
+ "./contracts/models": "./src/contracts/models.ts",
33
+ "./contracts/onboarding": "./src/contracts/onboarding.ts",
34
+ "./contracts/operations": "./src/contracts/operations.ts",
35
+ "./contracts/shared": "./src/contracts/shared.ts",
36
+ "./docs": "./src/docs/index.ts",
37
+ "./docs/learning-journey.docblock": "./src/docs/learning-journey.docblock.ts",
38
+ "./engines": "./src/engines/index.ts",
39
+ "./engines/srs": "./src/engines/srs.ts",
40
+ "./engines/streak": "./src/engines/streak.ts",
41
+ "./engines/xp": "./src/engines/xp.ts",
42
+ "./entities": "./src/entities/index.ts",
43
+ "./entities/ai": "./src/entities/ai.ts",
44
+ "./entities/course": "./src/entities/course.ts",
45
+ "./entities/flashcard": "./src/entities/flashcard.ts",
46
+ "./entities/gamification": "./src/entities/gamification.ts",
47
+ "./entities/learner": "./src/entities/learner.ts",
48
+ "./entities/onboarding": "./src/entities/onboarding.ts",
49
+ "./entities/quiz": "./src/entities/quiz.ts",
50
+ "./events": "./src/events.ts",
51
+ "./track-spec": "./src/track-spec.ts",
52
+ "./*": "./*"
53
+ },
54
+ "module": "./dist/index.js",
55
+ "files": [
56
+ "dist",
57
+ "README.md"
58
+ ],
59
+ "publishConfig": {
60
+ "access": "public",
61
+ "exports": {
62
+ ".": "./dist/index.js",
63
+ "./contracts": "./dist/contracts/index.js",
64
+ "./contracts/models": "./dist/contracts/models.js",
65
+ "./contracts/onboarding": "./dist/contracts/onboarding.js",
66
+ "./contracts/operations": "./dist/contracts/operations.js",
67
+ "./contracts/shared": "./dist/contracts/shared.js",
68
+ "./docs": "./dist/docs/index.js",
69
+ "./docs/learning-journey.docblock": "./dist/docs/learning-journey.docblock.js",
70
+ "./engines": "./dist/engines/index.js",
71
+ "./engines/srs": "./dist/engines/srs.js",
72
+ "./engines/streak": "./dist/engines/streak.js",
73
+ "./engines/xp": "./dist/engines/xp.js",
74
+ "./entities": "./dist/entities/index.js",
75
+ "./entities/ai": "./dist/entities/ai.js",
76
+ "./entities/course": "./dist/entities/course.js",
77
+ "./entities/flashcard": "./dist/entities/flashcard.js",
78
+ "./entities/gamification": "./dist/entities/gamification.js",
79
+ "./entities/learner": "./dist/entities/learner.js",
80
+ "./entities/onboarding": "./dist/entities/onboarding.js",
81
+ "./entities/quiz": "./dist/entities/quiz.js",
82
+ "./events": "./dist/events.js",
83
+ "./track-spec": "./dist/track-spec.js",
84
+ "./*": "./*"
85
+ }
86
+ }
87
+ }