@contractspec/module.learning-journey 1.57.0 → 1.58.0
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/dist/browser/contracts/index.js +578 -0
- package/dist/browser/contracts/models.js +193 -0
- package/dist/browser/contracts/onboarding.js +417 -0
- package/dist/browser/contracts/operations.js +326 -0
- package/dist/browser/contracts/shared.js +5 -0
- package/dist/browser/docs/index.js +124 -0
- package/dist/browser/docs/learning-journey.docblock.js +124 -0
- package/dist/browser/engines/index.js +526 -0
- package/dist/browser/engines/srs.js +198 -0
- package/dist/browser/engines/streak.js +159 -0
- package/dist/browser/engines/xp.js +171 -0
- package/dist/browser/entities/ai.js +343 -0
- package/dist/browser/entities/course.js +276 -0
- package/dist/browser/entities/flashcard.js +222 -0
- package/dist/browser/entities/gamification.js +340 -0
- package/dist/browser/entities/index.js +2136 -0
- package/dist/browser/entities/learner.js +329 -0
- package/dist/browser/entities/onboarding.js +301 -0
- package/dist/browser/entities/quiz.js +304 -0
- package/dist/browser/events.js +423 -0
- package/dist/browser/index.js +3833 -0
- package/dist/browser/learning-journey.capability.js +40 -0
- package/dist/browser/learning-journey.feature.js +56 -0
- package/dist/browser/track-spec.js +0 -0
- package/dist/contracts/index.d.ts +5 -5
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +578 -5
- package/dist/contracts/models.d.ts +426 -431
- package/dist/contracts/models.d.ts.map +1 -1
- package/dist/contracts/models.js +178 -372
- package/dist/contracts/onboarding.d.ts +621 -627
- package/dist/contracts/onboarding.d.ts.map +1 -1
- package/dist/contracts/onboarding.js +404 -388
- package/dist/contracts/operations.d.ts +243 -249
- package/dist/contracts/operations.d.ts.map +1 -1
- package/dist/contracts/operations.js +324 -148
- package/dist/contracts/shared.d.ts +1 -4
- package/dist/contracts/shared.d.ts.map +1 -1
- package/dist/contracts/shared.js +6 -6
- package/dist/docs/index.d.ts +2 -1
- package/dist/docs/index.d.ts.map +1 -0
- package/dist/docs/index.js +125 -1
- package/dist/docs/learning-journey.docblock.d.ts +2 -1
- package/dist/docs/learning-journey.docblock.d.ts.map +1 -0
- package/dist/docs/learning-journey.docblock.js +47 -58
- package/dist/engines/index.d.ts +4 -4
- package/dist/engines/index.d.ts.map +1 -0
- package/dist/engines/index.js +526 -4
- package/dist/engines/srs.d.ts +89 -92
- package/dist/engines/srs.d.ts.map +1 -1
- package/dist/engines/srs.js +197 -217
- package/dist/engines/streak.d.ts +84 -87
- package/dist/engines/streak.d.ts.map +1 -1
- package/dist/engines/streak.js +158 -192
- package/dist/engines/xp.d.ts +80 -83
- package/dist/engines/xp.d.ts.map +1 -1
- package/dist/engines/xp.js +170 -211
- package/dist/entities/ai.d.ts +199 -204
- package/dist/entities/ai.d.ts.map +1 -1
- package/dist/entities/ai.js +336 -368
- package/dist/entities/course.d.ts +149 -154
- package/dist/entities/course.d.ts.map +1 -1
- package/dist/entities/course.js +267 -306
- package/dist/entities/flashcard.d.ts +144 -149
- package/dist/entities/flashcard.d.ts.map +1 -1
- package/dist/entities/flashcard.js +217 -243
- package/dist/entities/gamification.d.ts +197 -202
- package/dist/entities/gamification.d.ts.map +1 -1
- package/dist/entities/gamification.js +331 -382
- package/dist/entities/index.d.ts +613 -618
- package/dist/entities/index.d.ts.map +1 -1
- package/dist/entities/index.js +2135 -43
- package/dist/entities/learner.d.ts +191 -196
- package/dist/entities/learner.d.ts.map +1 -1
- package/dist/entities/learner.js +322 -357
- package/dist/entities/onboarding.d.ts +164 -169
- package/dist/entities/onboarding.d.ts.map +1 -1
- package/dist/entities/onboarding.js +296 -301
- package/dist/entities/quiz.d.ts +184 -189
- package/dist/entities/quiz.d.ts.map +1 -1
- package/dist/entities/quiz.js +296 -361
- package/dist/events.d.ts +608 -614
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +421 -687
- package/dist/index.d.ts +8 -20
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3834 -22
- package/dist/learning-journey.capability.d.ts +3 -8
- package/dist/learning-journey.capability.d.ts.map +1 -1
- package/dist/learning-journey.capability.js +41 -46
- package/dist/learning-journey.feature.d.ts +1 -6
- package/dist/learning-journey.feature.d.ts.map +1 -1
- package/dist/learning-journey.feature.js +55 -155
- package/dist/node/contracts/index.js +578 -0
- package/dist/node/contracts/models.js +193 -0
- package/dist/node/contracts/onboarding.js +417 -0
- package/dist/node/contracts/operations.js +326 -0
- package/dist/node/contracts/shared.js +5 -0
- package/dist/node/docs/index.js +124 -0
- package/dist/node/docs/learning-journey.docblock.js +124 -0
- package/dist/node/engines/index.js +526 -0
- package/dist/node/engines/srs.js +198 -0
- package/dist/node/engines/streak.js +159 -0
- package/dist/node/engines/xp.js +171 -0
- package/dist/node/entities/ai.js +343 -0
- package/dist/node/entities/course.js +276 -0
- package/dist/node/entities/flashcard.js +222 -0
- package/dist/node/entities/gamification.js +340 -0
- package/dist/node/entities/index.js +2136 -0
- package/dist/node/entities/learner.js +329 -0
- package/dist/node/entities/onboarding.js +301 -0
- package/dist/node/entities/quiz.js +304 -0
- package/dist/node/events.js +423 -0
- package/dist/node/index.js +3833 -0
- package/dist/node/learning-journey.capability.js +40 -0
- package/dist/node/learning-journey.feature.js +56 -0
- package/dist/node/track-spec.js +0 -0
- package/dist/track-spec.d.ts +115 -118
- package/dist/track-spec.d.ts.map +1 -1
- package/dist/track-spec.js +1 -0
- package/package.json +237 -60
- package/dist/contracts/models.js.map +0 -1
- package/dist/contracts/onboarding.js.map +0 -1
- package/dist/contracts/operations.js.map +0 -1
- package/dist/contracts/shared.js.map +0 -1
- package/dist/docs/learning-journey.docblock.js.map +0 -1
- package/dist/engines/srs.js.map +0 -1
- package/dist/engines/streak.js.map +0 -1
- package/dist/engines/xp.js.map +0 -1
- package/dist/entities/ai.js.map +0 -1
- package/dist/entities/course.js.map +0 -1
- package/dist/entities/flashcard.js.map +0 -1
- package/dist/entities/gamification.js.map +0 -1
- package/dist/entities/index.js.map +0 -1
- package/dist/entities/learner.js.map +0 -1
- package/dist/entities/onboarding.js.map +0 -1
- package/dist/entities/quiz.js.map +0 -1
- package/dist/events.js.map +0 -1
- package/dist/learning-journey.capability.js.map +0 -1
- package/dist/learning-journey.feature.js.map +0 -1
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
// src/entities/learner.ts
|
|
2
|
+
import {
|
|
3
|
+
defineEntity,
|
|
4
|
+
defineEntityEnum,
|
|
5
|
+
field,
|
|
6
|
+
index
|
|
7
|
+
} from "@contractspec/lib.schema";
|
|
8
|
+
var EnrollmentStatusEnum = defineEntityEnum({
|
|
9
|
+
name: "EnrollmentStatus",
|
|
10
|
+
values: [
|
|
11
|
+
"ENROLLED",
|
|
12
|
+
"IN_PROGRESS",
|
|
13
|
+
"COMPLETED",
|
|
14
|
+
"DROPPED",
|
|
15
|
+
"EXPIRED"
|
|
16
|
+
],
|
|
17
|
+
schema: "lssm_learning",
|
|
18
|
+
description: "Status of a course enrollment."
|
|
19
|
+
});
|
|
20
|
+
var ProgressStatusEnum = defineEntityEnum({
|
|
21
|
+
name: "ProgressStatus",
|
|
22
|
+
values: ["NOT_STARTED", "IN_PROGRESS", "COMPLETED", "SKIPPED"],
|
|
23
|
+
schema: "lssm_learning",
|
|
24
|
+
description: "Status of lesson progress."
|
|
25
|
+
});
|
|
26
|
+
var LearnerEntity = defineEntity({
|
|
27
|
+
name: "Learner",
|
|
28
|
+
description: "A learner profile.",
|
|
29
|
+
schema: "lssm_learning",
|
|
30
|
+
map: "learner",
|
|
31
|
+
fields: {
|
|
32
|
+
id: field.id({ description: "Unique learner identifier" }),
|
|
33
|
+
userId: field.string({ isUnique: true, description: "Associated user ID" }),
|
|
34
|
+
displayName: field.string({
|
|
35
|
+
isOptional: true,
|
|
36
|
+
description: "Display name"
|
|
37
|
+
}),
|
|
38
|
+
avatarUrl: field.string({ isOptional: true, description: "Avatar URL" }),
|
|
39
|
+
bio: field.string({ isOptional: true, description: "Short bio" }),
|
|
40
|
+
level: field.int({ default: 1, description: "Current level" }),
|
|
41
|
+
totalXp: field.int({ default: 0, description: "Total XP earned" }),
|
|
42
|
+
currentStreak: field.int({
|
|
43
|
+
default: 0,
|
|
44
|
+
description: "Current streak days"
|
|
45
|
+
}),
|
|
46
|
+
longestStreak: field.int({
|
|
47
|
+
default: 0,
|
|
48
|
+
description: "Longest streak ever"
|
|
49
|
+
}),
|
|
50
|
+
lastActivityAt: field.dateTime({
|
|
51
|
+
isOptional: true,
|
|
52
|
+
description: "Last learning activity"
|
|
53
|
+
}),
|
|
54
|
+
timezone: field.string({
|
|
55
|
+
default: '"UTC"',
|
|
56
|
+
description: "Learner timezone"
|
|
57
|
+
}),
|
|
58
|
+
dailyGoalXp: field.int({ default: 50, description: "Daily XP goal" }),
|
|
59
|
+
reminderEnabled: field.boolean({
|
|
60
|
+
default: true,
|
|
61
|
+
description: "Enable reminders"
|
|
62
|
+
}),
|
|
63
|
+
reminderTime: field.string({
|
|
64
|
+
isOptional: true,
|
|
65
|
+
description: "Preferred reminder time"
|
|
66
|
+
}),
|
|
67
|
+
orgId: field.string({
|
|
68
|
+
isOptional: true,
|
|
69
|
+
description: "Organization scope"
|
|
70
|
+
}),
|
|
71
|
+
metadata: field.json({
|
|
72
|
+
isOptional: true,
|
|
73
|
+
description: "Additional metadata"
|
|
74
|
+
}),
|
|
75
|
+
createdAt: field.createdAt(),
|
|
76
|
+
updatedAt: field.updatedAt(),
|
|
77
|
+
enrollments: field.hasMany("Enrollment"),
|
|
78
|
+
lessonProgress: field.hasMany("LessonProgress"),
|
|
79
|
+
achievements: field.hasMany("LearnerAchievement"),
|
|
80
|
+
decks: field.hasMany("Deck"),
|
|
81
|
+
profile: field.hasOne("LearnerProfile")
|
|
82
|
+
},
|
|
83
|
+
indexes: [
|
|
84
|
+
index.on(["orgId"]),
|
|
85
|
+
index.on(["totalXp"]),
|
|
86
|
+
index.on(["level"]),
|
|
87
|
+
index.on(["currentStreak"])
|
|
88
|
+
]
|
|
89
|
+
});
|
|
90
|
+
var EnrollmentEntity = defineEntity({
|
|
91
|
+
name: "Enrollment",
|
|
92
|
+
description: "A learner enrollment in a course.",
|
|
93
|
+
schema: "lssm_learning",
|
|
94
|
+
map: "enrollment",
|
|
95
|
+
fields: {
|
|
96
|
+
id: field.id({ description: "Unique enrollment identifier" }),
|
|
97
|
+
learnerId: field.foreignKey({ description: "Enrolled learner" }),
|
|
98
|
+
courseId: field.foreignKey({ description: "Enrolled course" }),
|
|
99
|
+
status: field.enum("EnrollmentStatus", {
|
|
100
|
+
default: "ENROLLED",
|
|
101
|
+
description: "Enrollment status"
|
|
102
|
+
}),
|
|
103
|
+
progress: field.int({
|
|
104
|
+
default: 0,
|
|
105
|
+
description: "Completion percentage (0-100)"
|
|
106
|
+
}),
|
|
107
|
+
completedLessons: field.int({
|
|
108
|
+
default: 0,
|
|
109
|
+
description: "Number of completed lessons"
|
|
110
|
+
}),
|
|
111
|
+
totalLessons: field.int({
|
|
112
|
+
default: 0,
|
|
113
|
+
description: "Total lessons in course"
|
|
114
|
+
}),
|
|
115
|
+
xpEarned: field.int({
|
|
116
|
+
default: 0,
|
|
117
|
+
description: "XP earned in this course"
|
|
118
|
+
}),
|
|
119
|
+
startedAt: field.dateTime({
|
|
120
|
+
isOptional: true,
|
|
121
|
+
description: "When learner started"
|
|
122
|
+
}),
|
|
123
|
+
completedAt: field.dateTime({
|
|
124
|
+
isOptional: true,
|
|
125
|
+
description: "When learner completed"
|
|
126
|
+
}),
|
|
127
|
+
lastAccessedAt: field.dateTime({
|
|
128
|
+
isOptional: true,
|
|
129
|
+
description: "Last access time"
|
|
130
|
+
}),
|
|
131
|
+
certificateId: field.string({
|
|
132
|
+
isOptional: true,
|
|
133
|
+
description: "Issued certificate ID"
|
|
134
|
+
}),
|
|
135
|
+
metadata: field.json({
|
|
136
|
+
isOptional: true,
|
|
137
|
+
description: "Additional metadata"
|
|
138
|
+
}),
|
|
139
|
+
createdAt: field.createdAt(),
|
|
140
|
+
updatedAt: field.updatedAt(),
|
|
141
|
+
learner: field.belongsTo("Learner", ["learnerId"], ["id"], {
|
|
142
|
+
onDelete: "Cascade"
|
|
143
|
+
}),
|
|
144
|
+
course: field.belongsTo("Course", ["courseId"], ["id"], {
|
|
145
|
+
onDelete: "Cascade"
|
|
146
|
+
})
|
|
147
|
+
},
|
|
148
|
+
indexes: [
|
|
149
|
+
index.unique(["learnerId", "courseId"], { name: "enrollment_unique" }),
|
|
150
|
+
index.on(["learnerId", "status"]),
|
|
151
|
+
index.on(["courseId", "status"])
|
|
152
|
+
],
|
|
153
|
+
enums: [EnrollmentStatusEnum]
|
|
154
|
+
});
|
|
155
|
+
var LessonProgressEntity = defineEntity({
|
|
156
|
+
name: "LessonProgress",
|
|
157
|
+
description: "Progress tracking for a lesson.",
|
|
158
|
+
schema: "lssm_learning",
|
|
159
|
+
map: "lesson_progress",
|
|
160
|
+
fields: {
|
|
161
|
+
id: field.id({ description: "Unique progress identifier" }),
|
|
162
|
+
learnerId: field.foreignKey({ description: "Learner" }),
|
|
163
|
+
lessonId: field.foreignKey({ description: "Lesson" }),
|
|
164
|
+
status: field.enum("ProgressStatus", {
|
|
165
|
+
default: "NOT_STARTED",
|
|
166
|
+
description: "Progress status"
|
|
167
|
+
}),
|
|
168
|
+
progress: field.int({
|
|
169
|
+
default: 0,
|
|
170
|
+
description: "Completion percentage (0-100)"
|
|
171
|
+
}),
|
|
172
|
+
score: field.int({
|
|
173
|
+
isOptional: true,
|
|
174
|
+
description: "Score achieved (for quizzes)"
|
|
175
|
+
}),
|
|
176
|
+
attempts: field.int({ default: 0, description: "Number of attempts" }),
|
|
177
|
+
bestScore: field.int({
|
|
178
|
+
isOptional: true,
|
|
179
|
+
description: "Best score across attempts"
|
|
180
|
+
}),
|
|
181
|
+
timeSpent: field.int({ default: 0, description: "Time spent in seconds" }),
|
|
182
|
+
xpEarned: field.int({
|
|
183
|
+
default: 0,
|
|
184
|
+
description: "XP earned from this lesson"
|
|
185
|
+
}),
|
|
186
|
+
startedAt: field.dateTime({
|
|
187
|
+
isOptional: true,
|
|
188
|
+
description: "When started"
|
|
189
|
+
}),
|
|
190
|
+
completedAt: field.dateTime({
|
|
191
|
+
isOptional: true,
|
|
192
|
+
description: "When completed"
|
|
193
|
+
}),
|
|
194
|
+
lastAccessedAt: field.dateTime({
|
|
195
|
+
isOptional: true,
|
|
196
|
+
description: "Last access time"
|
|
197
|
+
}),
|
|
198
|
+
bookmarks: field.json({
|
|
199
|
+
isOptional: true,
|
|
200
|
+
description: "Content bookmarks"
|
|
201
|
+
}),
|
|
202
|
+
notes: field.string({ isOptional: true, description: "Learner notes" }),
|
|
203
|
+
createdAt: field.createdAt(),
|
|
204
|
+
updatedAt: field.updatedAt(),
|
|
205
|
+
learner: field.belongsTo("Learner", ["learnerId"], ["id"], {
|
|
206
|
+
onDelete: "Cascade"
|
|
207
|
+
}),
|
|
208
|
+
lesson: field.belongsTo("Lesson", ["lessonId"], ["id"], {
|
|
209
|
+
onDelete: "Cascade"
|
|
210
|
+
})
|
|
211
|
+
},
|
|
212
|
+
indexes: [
|
|
213
|
+
index.unique(["learnerId", "lessonId"], { name: "lesson_progress_unique" }),
|
|
214
|
+
index.on(["learnerId", "status"]),
|
|
215
|
+
index.on(["lessonId"])
|
|
216
|
+
],
|
|
217
|
+
enums: [ProgressStatusEnum]
|
|
218
|
+
});
|
|
219
|
+
var ModuleCompletionEntity = defineEntity({
|
|
220
|
+
name: "ModuleCompletion",
|
|
221
|
+
description: "Module completion record.",
|
|
222
|
+
schema: "lssm_learning",
|
|
223
|
+
map: "module_completion",
|
|
224
|
+
fields: {
|
|
225
|
+
id: field.id({ description: "Unique completion identifier" }),
|
|
226
|
+
learnerId: field.foreignKey({ description: "Learner" }),
|
|
227
|
+
moduleId: field.foreignKey({ description: "Module" }),
|
|
228
|
+
score: field.int({ isOptional: true, description: "Average score" }),
|
|
229
|
+
xpEarned: field.int({ default: 0, description: "XP earned" }),
|
|
230
|
+
timeSpent: field.int({ default: 0, description: "Time spent in seconds" }),
|
|
231
|
+
completedAt: field.dateTime({ description: "When completed" }),
|
|
232
|
+
createdAt: field.createdAt(),
|
|
233
|
+
learner: field.belongsTo("Learner", ["learnerId"], ["id"], {
|
|
234
|
+
onDelete: "Cascade"
|
|
235
|
+
}),
|
|
236
|
+
module: field.belongsTo("CourseModule", ["moduleId"], ["id"], {
|
|
237
|
+
onDelete: "Cascade"
|
|
238
|
+
})
|
|
239
|
+
},
|
|
240
|
+
indexes: [
|
|
241
|
+
index.unique(["learnerId", "moduleId"], {
|
|
242
|
+
name: "module_completion_unique"
|
|
243
|
+
}),
|
|
244
|
+
index.on(["learnerId", "completedAt"])
|
|
245
|
+
]
|
|
246
|
+
});
|
|
247
|
+
var CertificateEntity = defineEntity({
|
|
248
|
+
name: "Certificate",
|
|
249
|
+
description: "Course completion certificate.",
|
|
250
|
+
schema: "lssm_learning",
|
|
251
|
+
map: "certificate",
|
|
252
|
+
fields: {
|
|
253
|
+
id: field.id({ description: "Unique certificate identifier" }),
|
|
254
|
+
learnerId: field.foreignKey({ description: "Certificate holder" }),
|
|
255
|
+
courseId: field.foreignKey({ description: "Completed course" }),
|
|
256
|
+
enrollmentId: field.foreignKey({ description: "Associated enrollment" }),
|
|
257
|
+
certificateNumber: field.string({
|
|
258
|
+
isUnique: true,
|
|
259
|
+
description: "Unique certificate number"
|
|
260
|
+
}),
|
|
261
|
+
title: field.string({ description: "Certificate title" }),
|
|
262
|
+
description: field.string({
|
|
263
|
+
isOptional: true,
|
|
264
|
+
description: "Certificate description"
|
|
265
|
+
}),
|
|
266
|
+
score: field.int({ isOptional: true, description: "Final score" }),
|
|
267
|
+
grade: field.string({ isOptional: true, description: "Grade awarded" }),
|
|
268
|
+
issuedAt: field.dateTime({ description: "When issued" }),
|
|
269
|
+
validUntil: field.dateTime({
|
|
270
|
+
isOptional: true,
|
|
271
|
+
description: "Expiration date"
|
|
272
|
+
}),
|
|
273
|
+
verificationUrl: field.string({
|
|
274
|
+
isOptional: true,
|
|
275
|
+
description: "Verification URL"
|
|
276
|
+
}),
|
|
277
|
+
credentialHash: field.string({
|
|
278
|
+
isOptional: true,
|
|
279
|
+
description: "Credential hash for verification"
|
|
280
|
+
}),
|
|
281
|
+
isRevoked: field.boolean({
|
|
282
|
+
default: false,
|
|
283
|
+
description: "Whether certificate is revoked"
|
|
284
|
+
}),
|
|
285
|
+
revokedAt: field.dateTime({
|
|
286
|
+
isOptional: true,
|
|
287
|
+
description: "When revoked"
|
|
288
|
+
}),
|
|
289
|
+
revokedReason: field.string({
|
|
290
|
+
isOptional: true,
|
|
291
|
+
description: "Revocation reason"
|
|
292
|
+
}),
|
|
293
|
+
metadata: field.json({
|
|
294
|
+
isOptional: true,
|
|
295
|
+
description: "Additional metadata"
|
|
296
|
+
}),
|
|
297
|
+
createdAt: field.createdAt(),
|
|
298
|
+
learner: field.belongsTo("Learner", ["learnerId"], ["id"], {
|
|
299
|
+
onDelete: "Cascade"
|
|
300
|
+
}),
|
|
301
|
+
course: field.belongsTo("Course", ["courseId"], ["id"], {
|
|
302
|
+
onDelete: "Cascade"
|
|
303
|
+
})
|
|
304
|
+
},
|
|
305
|
+
indexes: [
|
|
306
|
+
index.on(["learnerId"]),
|
|
307
|
+
index.on(["courseId"]),
|
|
308
|
+
index.on(["issuedAt"])
|
|
309
|
+
]
|
|
310
|
+
});
|
|
311
|
+
var learnerEntities = [
|
|
312
|
+
LearnerEntity,
|
|
313
|
+
EnrollmentEntity,
|
|
314
|
+
LessonProgressEntity,
|
|
315
|
+
ModuleCompletionEntity,
|
|
316
|
+
CertificateEntity
|
|
317
|
+
];
|
|
318
|
+
var learnerEnums = [EnrollmentStatusEnum, ProgressStatusEnum];
|
|
319
|
+
export {
|
|
320
|
+
learnerEnums,
|
|
321
|
+
learnerEntities,
|
|
322
|
+
ProgressStatusEnum,
|
|
323
|
+
ModuleCompletionEntity,
|
|
324
|
+
LessonProgressEntity,
|
|
325
|
+
LearnerEntity,
|
|
326
|
+
EnrollmentStatusEnum,
|
|
327
|
+
EnrollmentEntity,
|
|
328
|
+
CertificateEntity
|
|
329
|
+
};
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
// src/entities/onboarding.ts
|
|
2
|
+
import {
|
|
3
|
+
defineEntity,
|
|
4
|
+
defineEntityEnum,
|
|
5
|
+
field,
|
|
6
|
+
index
|
|
7
|
+
} from "@contractspec/lib.schema";
|
|
8
|
+
var OnboardingStepStatusEnum = defineEntityEnum({
|
|
9
|
+
name: "OnboardingStepStatus",
|
|
10
|
+
values: ["PENDING", "IN_PROGRESS", "COMPLETED", "SKIPPED"],
|
|
11
|
+
schema: "lssm_learning",
|
|
12
|
+
description: "Status of an onboarding step."
|
|
13
|
+
});
|
|
14
|
+
var OnboardingTrackEntity = defineEntity({
|
|
15
|
+
name: "OnboardingTrack",
|
|
16
|
+
description: "An onboarding track for a product.",
|
|
17
|
+
schema: "lssm_learning",
|
|
18
|
+
map: "onboarding_track",
|
|
19
|
+
fields: {
|
|
20
|
+
id: field.id({ description: "Unique track identifier" }),
|
|
21
|
+
productId: field.string({ description: "Product this track is for" }),
|
|
22
|
+
name: field.string({ description: "Track name" }),
|
|
23
|
+
description: field.string({
|
|
24
|
+
isOptional: true,
|
|
25
|
+
description: "Track description"
|
|
26
|
+
}),
|
|
27
|
+
targetUserSegment: field.string({
|
|
28
|
+
isOptional: true,
|
|
29
|
+
description: "Target user segment"
|
|
30
|
+
}),
|
|
31
|
+
targetRole: field.string({
|
|
32
|
+
isOptional: true,
|
|
33
|
+
description: "Target user role"
|
|
34
|
+
}),
|
|
35
|
+
welcomeTitle: field.string({
|
|
36
|
+
isOptional: true,
|
|
37
|
+
description: "Welcome message title"
|
|
38
|
+
}),
|
|
39
|
+
welcomeMessage: field.string({
|
|
40
|
+
isOptional: true,
|
|
41
|
+
description: "Welcome message"
|
|
42
|
+
}),
|
|
43
|
+
completionTitle: field.string({
|
|
44
|
+
isOptional: true,
|
|
45
|
+
description: "Completion message title"
|
|
46
|
+
}),
|
|
47
|
+
completionMessage: field.string({
|
|
48
|
+
isOptional: true,
|
|
49
|
+
description: "Completion message"
|
|
50
|
+
}),
|
|
51
|
+
isActive: field.boolean({
|
|
52
|
+
default: true,
|
|
53
|
+
description: "Whether track is active"
|
|
54
|
+
}),
|
|
55
|
+
isRequired: field.boolean({
|
|
56
|
+
default: false,
|
|
57
|
+
description: "Whether track is required"
|
|
58
|
+
}),
|
|
59
|
+
canSkip: field.boolean({
|
|
60
|
+
default: true,
|
|
61
|
+
description: "Whether steps can be skipped"
|
|
62
|
+
}),
|
|
63
|
+
totalXp: field.int({
|
|
64
|
+
default: 100,
|
|
65
|
+
description: "Total XP for completing track"
|
|
66
|
+
}),
|
|
67
|
+
completionXpBonus: field.int({
|
|
68
|
+
isOptional: true,
|
|
69
|
+
description: "Bonus XP for completing track"
|
|
70
|
+
}),
|
|
71
|
+
completionBadgeKey: field.string({
|
|
72
|
+
isOptional: true,
|
|
73
|
+
description: "Badge awarded on completion"
|
|
74
|
+
}),
|
|
75
|
+
streakHoursWindow: field.int({
|
|
76
|
+
isOptional: true,
|
|
77
|
+
description: "Hours window to finish for streak bonus"
|
|
78
|
+
}),
|
|
79
|
+
streakBonusXp: field.int({
|
|
80
|
+
isOptional: true,
|
|
81
|
+
description: "Bonus XP if completed within streak window"
|
|
82
|
+
}),
|
|
83
|
+
orgId: field.string({
|
|
84
|
+
isOptional: true,
|
|
85
|
+
description: "Organization scope"
|
|
86
|
+
}),
|
|
87
|
+
metadata: field.json({
|
|
88
|
+
isOptional: true,
|
|
89
|
+
description: "Additional metadata"
|
|
90
|
+
}),
|
|
91
|
+
createdAt: field.createdAt(),
|
|
92
|
+
updatedAt: field.updatedAt(),
|
|
93
|
+
steps: field.hasMany("OnboardingStep"),
|
|
94
|
+
progress: field.hasMany("OnboardingProgress")
|
|
95
|
+
},
|
|
96
|
+
indexes: [
|
|
97
|
+
index.on(["productId", "isActive"]),
|
|
98
|
+
index.on(["orgId"]),
|
|
99
|
+
index.unique(["productId", "targetUserSegment", "targetRole"], {
|
|
100
|
+
name: "onboarding_track_target"
|
|
101
|
+
})
|
|
102
|
+
]
|
|
103
|
+
});
|
|
104
|
+
var OnboardingStepEntity = defineEntity({
|
|
105
|
+
name: "OnboardingStep",
|
|
106
|
+
description: "A step in an onboarding track.",
|
|
107
|
+
schema: "lssm_learning",
|
|
108
|
+
map: "onboarding_step",
|
|
109
|
+
fields: {
|
|
110
|
+
id: field.id({ description: "Unique step identifier" }),
|
|
111
|
+
trackId: field.foreignKey({ description: "Parent track" }),
|
|
112
|
+
title: field.string({ description: "Step title" }),
|
|
113
|
+
description: field.string({
|
|
114
|
+
isOptional: true,
|
|
115
|
+
description: "Step description"
|
|
116
|
+
}),
|
|
117
|
+
instructions: field.string({
|
|
118
|
+
isOptional: true,
|
|
119
|
+
description: "How to complete the step"
|
|
120
|
+
}),
|
|
121
|
+
helpUrl: field.string({
|
|
122
|
+
isOptional: true,
|
|
123
|
+
description: "Link to help documentation"
|
|
124
|
+
}),
|
|
125
|
+
order: field.int({ default: 0, description: "Display order" }),
|
|
126
|
+
triggerEvent: field.string({
|
|
127
|
+
isOptional: true,
|
|
128
|
+
description: "Event that triggers step start"
|
|
129
|
+
}),
|
|
130
|
+
completionEvent: field.string({
|
|
131
|
+
description: "Event that completes the step"
|
|
132
|
+
}),
|
|
133
|
+
completionEventVersion: field.int({
|
|
134
|
+
isOptional: true,
|
|
135
|
+
description: "Version of the completion event"
|
|
136
|
+
}),
|
|
137
|
+
completionSourceModule: field.string({
|
|
138
|
+
isOptional: true,
|
|
139
|
+
description: "Module emitting the completion event"
|
|
140
|
+
}),
|
|
141
|
+
completionEventFilter: field.json({
|
|
142
|
+
isOptional: true,
|
|
143
|
+
description: "Filter for completion event"
|
|
144
|
+
}),
|
|
145
|
+
actionUrl: field.string({
|
|
146
|
+
isOptional: true,
|
|
147
|
+
description: "URL to navigate to complete"
|
|
148
|
+
}),
|
|
149
|
+
actionLabel: field.string({
|
|
150
|
+
isOptional: true,
|
|
151
|
+
description: "Action button label"
|
|
152
|
+
}),
|
|
153
|
+
highlightSelector: field.string({
|
|
154
|
+
isOptional: true,
|
|
155
|
+
description: "CSS selector to highlight"
|
|
156
|
+
}),
|
|
157
|
+
tooltipPosition: field.string({
|
|
158
|
+
isOptional: true,
|
|
159
|
+
description: "Tooltip position"
|
|
160
|
+
}),
|
|
161
|
+
xpReward: field.int({ default: 10, description: "XP for completing step" }),
|
|
162
|
+
isRequired: field.boolean({
|
|
163
|
+
default: true,
|
|
164
|
+
description: "Whether step is required"
|
|
165
|
+
}),
|
|
166
|
+
canSkip: field.boolean({
|
|
167
|
+
default: true,
|
|
168
|
+
description: "Whether step can be skipped"
|
|
169
|
+
}),
|
|
170
|
+
metadata: field.json({
|
|
171
|
+
isOptional: true,
|
|
172
|
+
description: "Additional metadata"
|
|
173
|
+
}),
|
|
174
|
+
createdAt: field.createdAt(),
|
|
175
|
+
updatedAt: field.updatedAt(),
|
|
176
|
+
track: field.belongsTo("OnboardingTrack", ["trackId"], ["id"], {
|
|
177
|
+
onDelete: "Cascade"
|
|
178
|
+
})
|
|
179
|
+
},
|
|
180
|
+
indexes: [index.on(["trackId", "order"]), index.on(["completionEvent"])]
|
|
181
|
+
});
|
|
182
|
+
var OnboardingProgressEntity = defineEntity({
|
|
183
|
+
name: "OnboardingProgress",
|
|
184
|
+
description: "Tracks user progress through an onboarding track.",
|
|
185
|
+
schema: "lssm_learning",
|
|
186
|
+
map: "onboarding_progress",
|
|
187
|
+
fields: {
|
|
188
|
+
id: field.id({ description: "Unique progress identifier" }),
|
|
189
|
+
learnerId: field.foreignKey({ description: "Learner" }),
|
|
190
|
+
trackId: field.foreignKey({ description: "Onboarding track" }),
|
|
191
|
+
currentStepId: field.string({
|
|
192
|
+
isOptional: true,
|
|
193
|
+
description: "Current step ID"
|
|
194
|
+
}),
|
|
195
|
+
completedSteps: field.json({
|
|
196
|
+
default: "[]",
|
|
197
|
+
description: "Array of completed step IDs"
|
|
198
|
+
}),
|
|
199
|
+
skippedSteps: field.json({
|
|
200
|
+
default: "[]",
|
|
201
|
+
description: "Array of skipped step IDs"
|
|
202
|
+
}),
|
|
203
|
+
progress: field.int({
|
|
204
|
+
default: 0,
|
|
205
|
+
description: "Completion percentage (0-100)"
|
|
206
|
+
}),
|
|
207
|
+
isCompleted: field.boolean({
|
|
208
|
+
default: false,
|
|
209
|
+
description: "Whether track is completed"
|
|
210
|
+
}),
|
|
211
|
+
xpEarned: field.int({ default: 0, description: "XP earned from track" }),
|
|
212
|
+
startedAt: field.dateTime({ description: "When user started" }),
|
|
213
|
+
completedAt: field.dateTime({
|
|
214
|
+
isOptional: true,
|
|
215
|
+
description: "When user completed"
|
|
216
|
+
}),
|
|
217
|
+
lastActivityAt: field.dateTime({
|
|
218
|
+
isOptional: true,
|
|
219
|
+
description: "Last activity"
|
|
220
|
+
}),
|
|
221
|
+
isDismissed: field.boolean({
|
|
222
|
+
default: false,
|
|
223
|
+
description: "Whether user dismissed onboarding"
|
|
224
|
+
}),
|
|
225
|
+
dismissedAt: field.dateTime({
|
|
226
|
+
isOptional: true,
|
|
227
|
+
description: "When dismissed"
|
|
228
|
+
}),
|
|
229
|
+
metadata: field.json({
|
|
230
|
+
isOptional: true,
|
|
231
|
+
description: "Additional metadata"
|
|
232
|
+
}),
|
|
233
|
+
createdAt: field.createdAt(),
|
|
234
|
+
updatedAt: field.updatedAt(),
|
|
235
|
+
learner: field.belongsTo("Learner", ["learnerId"], ["id"], {
|
|
236
|
+
onDelete: "Cascade"
|
|
237
|
+
}),
|
|
238
|
+
track: field.belongsTo("OnboardingTrack", ["trackId"], ["id"], {
|
|
239
|
+
onDelete: "Cascade"
|
|
240
|
+
})
|
|
241
|
+
},
|
|
242
|
+
indexes: [
|
|
243
|
+
index.unique(["learnerId", "trackId"], {
|
|
244
|
+
name: "onboarding_progress_unique"
|
|
245
|
+
}),
|
|
246
|
+
index.on(["learnerId", "isCompleted"]),
|
|
247
|
+
index.on(["trackId"])
|
|
248
|
+
],
|
|
249
|
+
enums: [OnboardingStepStatusEnum]
|
|
250
|
+
});
|
|
251
|
+
var OnboardingStepCompletionEntity = defineEntity({
|
|
252
|
+
name: "OnboardingStepCompletion",
|
|
253
|
+
description: "Individual step completion record.",
|
|
254
|
+
schema: "lssm_learning",
|
|
255
|
+
map: "onboarding_step_completion",
|
|
256
|
+
fields: {
|
|
257
|
+
id: field.id({ description: "Unique completion identifier" }),
|
|
258
|
+
progressId: field.foreignKey({ description: "Parent progress record" }),
|
|
259
|
+
stepId: field.foreignKey({ description: "Completed step" }),
|
|
260
|
+
status: field.enum("OnboardingStepStatus", {
|
|
261
|
+
description: "Completion status"
|
|
262
|
+
}),
|
|
263
|
+
xpEarned: field.int({ default: 0, description: "XP earned" }),
|
|
264
|
+
triggeringEvent: field.string({
|
|
265
|
+
isOptional: true,
|
|
266
|
+
description: "Event that triggered completion"
|
|
267
|
+
}),
|
|
268
|
+
eventPayload: field.json({
|
|
269
|
+
isOptional: true,
|
|
270
|
+
description: "Event payload"
|
|
271
|
+
}),
|
|
272
|
+
completedAt: field.dateTime({ description: "When completed" }),
|
|
273
|
+
createdAt: field.createdAt(),
|
|
274
|
+
progress: field.belongsTo("OnboardingProgress", ["progressId"], ["id"], {
|
|
275
|
+
onDelete: "Cascade"
|
|
276
|
+
}),
|
|
277
|
+
step: field.belongsTo("OnboardingStep", ["stepId"], ["id"], {
|
|
278
|
+
onDelete: "Cascade"
|
|
279
|
+
})
|
|
280
|
+
},
|
|
281
|
+
indexes: [
|
|
282
|
+
index.unique(["progressId", "stepId"], { name: "step_completion_unique" }),
|
|
283
|
+
index.on(["completedAt"])
|
|
284
|
+
]
|
|
285
|
+
});
|
|
286
|
+
var onboardingEntities = [
|
|
287
|
+
OnboardingTrackEntity,
|
|
288
|
+
OnboardingStepEntity,
|
|
289
|
+
OnboardingProgressEntity,
|
|
290
|
+
OnboardingStepCompletionEntity
|
|
291
|
+
];
|
|
292
|
+
var onboardingEnums = [OnboardingStepStatusEnum];
|
|
293
|
+
export {
|
|
294
|
+
onboardingEnums,
|
|
295
|
+
onboardingEntities,
|
|
296
|
+
OnboardingTrackEntity,
|
|
297
|
+
OnboardingStepStatusEnum,
|
|
298
|
+
OnboardingStepEntity,
|
|
299
|
+
OnboardingStepCompletionEntity,
|
|
300
|
+
OnboardingProgressEntity
|
|
301
|
+
};
|