@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.
Files changed (140) hide show
  1. package/dist/browser/contracts/index.js +578 -0
  2. package/dist/browser/contracts/models.js +193 -0
  3. package/dist/browser/contracts/onboarding.js +417 -0
  4. package/dist/browser/contracts/operations.js +326 -0
  5. package/dist/browser/contracts/shared.js +5 -0
  6. package/dist/browser/docs/index.js +124 -0
  7. package/dist/browser/docs/learning-journey.docblock.js +124 -0
  8. package/dist/browser/engines/index.js +526 -0
  9. package/dist/browser/engines/srs.js +198 -0
  10. package/dist/browser/engines/streak.js +159 -0
  11. package/dist/browser/engines/xp.js +171 -0
  12. package/dist/browser/entities/ai.js +343 -0
  13. package/dist/browser/entities/course.js +276 -0
  14. package/dist/browser/entities/flashcard.js +222 -0
  15. package/dist/browser/entities/gamification.js +340 -0
  16. package/dist/browser/entities/index.js +2136 -0
  17. package/dist/browser/entities/learner.js +329 -0
  18. package/dist/browser/entities/onboarding.js +301 -0
  19. package/dist/browser/entities/quiz.js +304 -0
  20. package/dist/browser/events.js +423 -0
  21. package/dist/browser/index.js +3833 -0
  22. package/dist/browser/learning-journey.capability.js +40 -0
  23. package/dist/browser/learning-journey.feature.js +56 -0
  24. package/dist/browser/track-spec.js +0 -0
  25. package/dist/contracts/index.d.ts +5 -5
  26. package/dist/contracts/index.d.ts.map +1 -0
  27. package/dist/contracts/index.js +578 -5
  28. package/dist/contracts/models.d.ts +426 -431
  29. package/dist/contracts/models.d.ts.map +1 -1
  30. package/dist/contracts/models.js +178 -372
  31. package/dist/contracts/onboarding.d.ts +621 -627
  32. package/dist/contracts/onboarding.d.ts.map +1 -1
  33. package/dist/contracts/onboarding.js +404 -388
  34. package/dist/contracts/operations.d.ts +243 -249
  35. package/dist/contracts/operations.d.ts.map +1 -1
  36. package/dist/contracts/operations.js +324 -148
  37. package/dist/contracts/shared.d.ts +1 -4
  38. package/dist/contracts/shared.d.ts.map +1 -1
  39. package/dist/contracts/shared.js +6 -6
  40. package/dist/docs/index.d.ts +2 -1
  41. package/dist/docs/index.d.ts.map +1 -0
  42. package/dist/docs/index.js +125 -1
  43. package/dist/docs/learning-journey.docblock.d.ts +2 -1
  44. package/dist/docs/learning-journey.docblock.d.ts.map +1 -0
  45. package/dist/docs/learning-journey.docblock.js +47 -58
  46. package/dist/engines/index.d.ts +4 -4
  47. package/dist/engines/index.d.ts.map +1 -0
  48. package/dist/engines/index.js +526 -4
  49. package/dist/engines/srs.d.ts +89 -92
  50. package/dist/engines/srs.d.ts.map +1 -1
  51. package/dist/engines/srs.js +197 -217
  52. package/dist/engines/streak.d.ts +84 -87
  53. package/dist/engines/streak.d.ts.map +1 -1
  54. package/dist/engines/streak.js +158 -192
  55. package/dist/engines/xp.d.ts +80 -83
  56. package/dist/engines/xp.d.ts.map +1 -1
  57. package/dist/engines/xp.js +170 -211
  58. package/dist/entities/ai.d.ts +199 -204
  59. package/dist/entities/ai.d.ts.map +1 -1
  60. package/dist/entities/ai.js +336 -368
  61. package/dist/entities/course.d.ts +149 -154
  62. package/dist/entities/course.d.ts.map +1 -1
  63. package/dist/entities/course.js +267 -306
  64. package/dist/entities/flashcard.d.ts +144 -149
  65. package/dist/entities/flashcard.d.ts.map +1 -1
  66. package/dist/entities/flashcard.js +217 -243
  67. package/dist/entities/gamification.d.ts +197 -202
  68. package/dist/entities/gamification.d.ts.map +1 -1
  69. package/dist/entities/gamification.js +331 -382
  70. package/dist/entities/index.d.ts +613 -618
  71. package/dist/entities/index.d.ts.map +1 -1
  72. package/dist/entities/index.js +2135 -43
  73. package/dist/entities/learner.d.ts +191 -196
  74. package/dist/entities/learner.d.ts.map +1 -1
  75. package/dist/entities/learner.js +322 -357
  76. package/dist/entities/onboarding.d.ts +164 -169
  77. package/dist/entities/onboarding.d.ts.map +1 -1
  78. package/dist/entities/onboarding.js +296 -301
  79. package/dist/entities/quiz.d.ts +184 -189
  80. package/dist/entities/quiz.d.ts.map +1 -1
  81. package/dist/entities/quiz.js +296 -361
  82. package/dist/events.d.ts +608 -614
  83. package/dist/events.d.ts.map +1 -1
  84. package/dist/events.js +421 -687
  85. package/dist/index.d.ts +8 -20
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.js +3834 -22
  88. package/dist/learning-journey.capability.d.ts +3 -8
  89. package/dist/learning-journey.capability.d.ts.map +1 -1
  90. package/dist/learning-journey.capability.js +41 -46
  91. package/dist/learning-journey.feature.d.ts +1 -6
  92. package/dist/learning-journey.feature.d.ts.map +1 -1
  93. package/dist/learning-journey.feature.js +55 -155
  94. package/dist/node/contracts/index.js +578 -0
  95. package/dist/node/contracts/models.js +193 -0
  96. package/dist/node/contracts/onboarding.js +417 -0
  97. package/dist/node/contracts/operations.js +326 -0
  98. package/dist/node/contracts/shared.js +5 -0
  99. package/dist/node/docs/index.js +124 -0
  100. package/dist/node/docs/learning-journey.docblock.js +124 -0
  101. package/dist/node/engines/index.js +526 -0
  102. package/dist/node/engines/srs.js +198 -0
  103. package/dist/node/engines/streak.js +159 -0
  104. package/dist/node/engines/xp.js +171 -0
  105. package/dist/node/entities/ai.js +343 -0
  106. package/dist/node/entities/course.js +276 -0
  107. package/dist/node/entities/flashcard.js +222 -0
  108. package/dist/node/entities/gamification.js +340 -0
  109. package/dist/node/entities/index.js +2136 -0
  110. package/dist/node/entities/learner.js +329 -0
  111. package/dist/node/entities/onboarding.js +301 -0
  112. package/dist/node/entities/quiz.js +304 -0
  113. package/dist/node/events.js +423 -0
  114. package/dist/node/index.js +3833 -0
  115. package/dist/node/learning-journey.capability.js +40 -0
  116. package/dist/node/learning-journey.feature.js +56 -0
  117. package/dist/node/track-spec.js +0 -0
  118. package/dist/track-spec.d.ts +115 -118
  119. package/dist/track-spec.d.ts.map +1 -1
  120. package/dist/track-spec.js +1 -0
  121. package/package.json +237 -60
  122. package/dist/contracts/models.js.map +0 -1
  123. package/dist/contracts/onboarding.js.map +0 -1
  124. package/dist/contracts/operations.js.map +0 -1
  125. package/dist/contracts/shared.js.map +0 -1
  126. package/dist/docs/learning-journey.docblock.js.map +0 -1
  127. package/dist/engines/srs.js.map +0 -1
  128. package/dist/engines/streak.js.map +0 -1
  129. package/dist/engines/xp.js.map +0 -1
  130. package/dist/entities/ai.js.map +0 -1
  131. package/dist/entities/course.js.map +0 -1
  132. package/dist/entities/flashcard.js.map +0 -1
  133. package/dist/entities/gamification.js.map +0 -1
  134. package/dist/entities/index.js.map +0 -1
  135. package/dist/entities/learner.js.map +0 -1
  136. package/dist/entities/onboarding.js.map +0 -1
  137. package/dist/entities/quiz.js.map +0 -1
  138. package/dist/events.js.map +0 -1
  139. package/dist/learning-journey.capability.js.map +0 -1
  140. package/dist/learning-journey.feature.js.map +0 -1
@@ -0,0 +1,326 @@
1
+ // src/contracts/shared.ts
2
+ var LEARNING_JOURNEY_OWNERS = ["modules.learning-journey"];
3
+
4
+ // src/contracts/models.ts
5
+ import { ScalarTypeEnum, defineSchemaModel } from "@contractspec/lib.schema";
6
+ var CourseModel = defineSchemaModel({
7
+ name: "Course",
8
+ description: "A learning course",
9
+ fields: {
10
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
11
+ title: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
12
+ slug: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
13
+ description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
14
+ difficulty: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
15
+ status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
16
+ estimatedDuration: {
17
+ type: ScalarTypeEnum.Int_unsecure(),
18
+ isOptional: true
19
+ },
20
+ thumbnailUrl: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
21
+ createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
22
+ }
23
+ });
24
+ var LearnerModel = defineSchemaModel({
25
+ name: "Learner",
26
+ description: "A learner profile",
27
+ fields: {
28
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
29
+ userId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
30
+ displayName: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
31
+ level: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
32
+ totalXp: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
33
+ currentStreak: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
34
+ longestStreak: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
35
+ createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
36
+ }
37
+ });
38
+ var EnrollmentModel = defineSchemaModel({
39
+ name: "Enrollment",
40
+ description: "A course enrollment",
41
+ fields: {
42
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
43
+ learnerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
44
+ courseId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
45
+ status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
46
+ progress: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
47
+ startedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true },
48
+ completedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true }
49
+ }
50
+ });
51
+ var ProgressModel = defineSchemaModel({
52
+ name: "LessonProgress",
53
+ description: "Lesson progress",
54
+ fields: {
55
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
56
+ learnerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
57
+ lessonId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
58
+ status: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
59
+ progress: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
60
+ score: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
61
+ timeSpent: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
62
+ completedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true }
63
+ }
64
+ });
65
+ var DeckModel = defineSchemaModel({
66
+ name: "Deck",
67
+ description: "A flashcard deck",
68
+ fields: {
69
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
70
+ title: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
71
+ description: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
72
+ cardCount: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
73
+ isPublic: { type: ScalarTypeEnum.Boolean(), isOptional: false },
74
+ createdAt: { type: ScalarTypeEnum.DateTime(), isOptional: false }
75
+ }
76
+ });
77
+ var CardModel = defineSchemaModel({
78
+ name: "Card",
79
+ description: "A flashcard",
80
+ fields: {
81
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
82
+ deckId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
83
+ front: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
84
+ back: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
85
+ hints: { type: ScalarTypeEnum.JSON(), isOptional: true },
86
+ isDue: { type: ScalarTypeEnum.Boolean(), isOptional: false },
87
+ nextReviewAt: { type: ScalarTypeEnum.DateTime(), isOptional: true }
88
+ }
89
+ });
90
+ var AchievementModel = defineSchemaModel({
91
+ name: "Achievement",
92
+ description: "An achievement",
93
+ fields: {
94
+ id: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
95
+ key: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
96
+ name: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
97
+ description: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
98
+ icon: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
99
+ xpReward: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
100
+ unlockedAt: { type: ScalarTypeEnum.DateTime(), isOptional: true }
101
+ }
102
+ });
103
+ var EnrollInCourseInput = defineSchemaModel({
104
+ name: "EnrollInCourseInput",
105
+ description: "Input for enrolling in a course",
106
+ fields: {
107
+ courseId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false }
108
+ }
109
+ });
110
+ var CompleteLessonInput = defineSchemaModel({
111
+ name: "CompleteLessonInput",
112
+ description: "Input for completing a lesson",
113
+ fields: {
114
+ lessonId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
115
+ score: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true },
116
+ timeSpent: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false }
117
+ }
118
+ });
119
+ var SubmitCardReviewInput = defineSchemaModel({
120
+ name: "SubmitCardReviewInput",
121
+ description: "Input for submitting a card review",
122
+ fields: {
123
+ cardId: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
124
+ rating: { type: ScalarTypeEnum.String_unsecure(), isOptional: false },
125
+ responseTimeMs: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true }
126
+ }
127
+ });
128
+ var GetDueCardsInput = defineSchemaModel({
129
+ name: "GetDueCardsInput",
130
+ description: "Input for getting due cards",
131
+ fields: {
132
+ deckId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true },
133
+ limit: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true }
134
+ }
135
+ });
136
+ var GetDueCardsOutput = defineSchemaModel({
137
+ name: "GetDueCardsOutput",
138
+ description: "Output for getting due cards",
139
+ fields: {
140
+ cards: { type: CardModel, isArray: true, isOptional: false },
141
+ total: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false }
142
+ }
143
+ });
144
+ var GetLearnerDashboardInput = defineSchemaModel({
145
+ name: "GetLearnerDashboardInput",
146
+ description: "Input for getting learner dashboard",
147
+ fields: {
148
+ learnerId: { type: ScalarTypeEnum.String_unsecure(), isOptional: true }
149
+ }
150
+ });
151
+ var LearnerDashboardModel = defineSchemaModel({
152
+ name: "LearnerDashboard",
153
+ description: "Learner dashboard data",
154
+ fields: {
155
+ learner: { type: LearnerModel, isOptional: false },
156
+ currentStreak: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
157
+ dailyXpGoal: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
158
+ dailyXpProgress: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false },
159
+ activeEnrollments: {
160
+ type: EnrollmentModel,
161
+ isArray: true,
162
+ isOptional: false
163
+ },
164
+ recentAchievements: {
165
+ type: AchievementModel,
166
+ isArray: true,
167
+ isOptional: false
168
+ },
169
+ dueCardCount: { type: ScalarTypeEnum.Int_unsecure(), isOptional: false }
170
+ }
171
+ });
172
+ var SuccessOutput = defineSchemaModel({
173
+ name: "SuccessOutput",
174
+ description: "Generic success output",
175
+ fields: {
176
+ success: { type: ScalarTypeEnum.Boolean(), isOptional: false },
177
+ xpEarned: { type: ScalarTypeEnum.Int_unsecure(), isOptional: true }
178
+ }
179
+ });
180
+
181
+ // src/contracts/operations.ts
182
+ import { defineCommand, defineQuery } from "@contractspec/lib.contracts";
183
+ var EnrollInCourseContract = defineCommand({
184
+ meta: {
185
+ key: "learning.enroll",
186
+ version: "1.0.0",
187
+ stability: "stable",
188
+ owners: [...LEARNING_JOURNEY_OWNERS],
189
+ tags: ["learning", "enrollment"],
190
+ description: "Enroll in a course.",
191
+ goal: "Start learning a new course.",
192
+ context: "Called when a learner wants to start a course."
193
+ },
194
+ io: {
195
+ input: EnrollInCourseInput,
196
+ output: EnrollmentModel,
197
+ errors: {
198
+ COURSE_NOT_FOUND: {
199
+ description: "Course does not exist",
200
+ http: 404,
201
+ gqlCode: "COURSE_NOT_FOUND",
202
+ when: "Course ID is invalid"
203
+ },
204
+ ALREADY_ENROLLED: {
205
+ description: "Already enrolled in course",
206
+ http: 409,
207
+ gqlCode: "ALREADY_ENROLLED",
208
+ when: "Learner is already enrolled"
209
+ }
210
+ }
211
+ },
212
+ policy: {
213
+ auth: "user"
214
+ }
215
+ });
216
+ var CompleteLessonContract = defineCommand({
217
+ meta: {
218
+ key: "learning.completeLesson",
219
+ version: "1.0.0",
220
+ stability: "stable",
221
+ owners: [...LEARNING_JOURNEY_OWNERS],
222
+ tags: ["learning", "progress"],
223
+ description: "Mark a lesson as completed.",
224
+ goal: "Record lesson completion and earn XP.",
225
+ context: "Called when a learner finishes a lesson."
226
+ },
227
+ io: {
228
+ input: CompleteLessonInput,
229
+ output: SuccessOutput,
230
+ errors: {
231
+ LESSON_NOT_FOUND: {
232
+ description: "Lesson does not exist",
233
+ http: 404,
234
+ gqlCode: "LESSON_NOT_FOUND",
235
+ when: "Lesson ID is invalid"
236
+ },
237
+ NOT_ENROLLED: {
238
+ description: "Not enrolled in course",
239
+ http: 403,
240
+ gqlCode: "NOT_ENROLLED",
241
+ when: "Learner is not enrolled in the course"
242
+ }
243
+ }
244
+ },
245
+ policy: {
246
+ auth: "user"
247
+ }
248
+ });
249
+ var SubmitCardReviewContract = defineCommand({
250
+ meta: {
251
+ key: "learning.submitCardReview",
252
+ version: "1.0.0",
253
+ stability: "stable",
254
+ owners: [...LEARNING_JOURNEY_OWNERS],
255
+ tags: ["learning", "flashcards"],
256
+ description: "Submit a flashcard review.",
257
+ goal: "Record review and update SRS schedule.",
258
+ context: "Called when reviewing flashcards."
259
+ },
260
+ io: {
261
+ input: SubmitCardReviewInput,
262
+ output: SuccessOutput,
263
+ errors: {
264
+ CARD_NOT_FOUND: {
265
+ description: "Card does not exist",
266
+ http: 404,
267
+ gqlCode: "CARD_NOT_FOUND",
268
+ when: "Card ID is invalid"
269
+ },
270
+ INVALID_RATING: {
271
+ description: "Invalid rating",
272
+ http: 400,
273
+ gqlCode: "INVALID_RATING",
274
+ when: "Rating must be AGAIN, HARD, GOOD, or EASY"
275
+ }
276
+ }
277
+ },
278
+ policy: {
279
+ auth: "user"
280
+ }
281
+ });
282
+ var GetDueCardsContract = defineQuery({
283
+ meta: {
284
+ key: "learning.getDueCards",
285
+ version: "1.0.0",
286
+ stability: "stable",
287
+ owners: [...LEARNING_JOURNEY_OWNERS],
288
+ tags: ["learning", "flashcards"],
289
+ description: "Get flashcards due for review.",
290
+ goal: "Get the next batch of cards to review.",
291
+ context: "Called when starting a review session."
292
+ },
293
+ io: {
294
+ input: GetDueCardsInput,
295
+ output: GetDueCardsOutput
296
+ },
297
+ policy: {
298
+ auth: "user"
299
+ }
300
+ });
301
+ var GetLearnerDashboardContract = defineQuery({
302
+ meta: {
303
+ key: "learning.getDashboard",
304
+ version: "1.0.0",
305
+ stability: "stable",
306
+ owners: [...LEARNING_JOURNEY_OWNERS],
307
+ tags: ["learning", "dashboard"],
308
+ description: "Get learner dashboard data.",
309
+ goal: "Display learner progress and stats.",
310
+ context: "Called when viewing the learning dashboard."
311
+ },
312
+ io: {
313
+ input: GetLearnerDashboardInput,
314
+ output: LearnerDashboardModel
315
+ },
316
+ policy: {
317
+ auth: "user"
318
+ }
319
+ });
320
+ export {
321
+ SubmitCardReviewContract,
322
+ GetLearnerDashboardContract,
323
+ GetDueCardsContract,
324
+ EnrollInCourseContract,
325
+ CompleteLessonContract
326
+ };
@@ -0,0 +1,5 @@
1
+ // src/contracts/shared.ts
2
+ var LEARNING_JOURNEY_OWNERS = ["modules.learning-journey"];
3
+ export {
4
+ LEARNING_JOURNEY_OWNERS
5
+ };
@@ -0,0 +1,124 @@
1
+ // src/docs/learning-journey.docblock.ts
2
+ import { registerDocBlocks } from "@contractspec/lib.contracts/docs";
3
+ var learningJourneyDocBlocks = [
4
+ {
5
+ id: "docs.learning-journey.engine",
6
+ title: "Learning Journey Engine",
7
+ summary: "Tracks learners, tracks/modules/steps, progress, quizzes, streaks, XP, and AI coaching hooks for product-integrated onboarding.",
8
+ kind: "reference",
9
+ visibility: "public",
10
+ route: "/docs/learning-journey/engine",
11
+ tags: ["learning", "onboarding", "journey", "education"],
12
+ body: `## Capabilities
13
+
14
+ - **Entities**: Learner, Track, Module, Step, Progress, Quiz, Flashcard, AI Coach, Gamification (XP, streaks, badges).
15
+ - **Contracts**: enroll/resume/advance steps, complete quizzes, record streaks, assign XP, fetch progress dashboards, onboarding list/progress/recordEvent.
16
+ - **Engines**: spaced-repetition (SRS), streak calculator, XP progression.
17
+ - **Events**: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded, onboarding.started/completed/step_completed.
18
+
19
+ ## Completion conditions
20
+ - Event-based: name/version/source + payload filter
21
+ - Count-based: require N events (optional time window)
22
+ - Time-bounded: must complete within a window; steps can unlock by day/hour
23
+ - SRS mastery: complete when cards/skills hit mastery thresholds (with required counts)
24
+
25
+ ## Usage
26
+
27
+ 1) Compose schema
28
+ - Include \`learningJourneySchemaContribution\` (entities export) in composition.
29
+
30
+ 2) Register contracts/events
31
+ - Import from \`@contractspec/module.learning-journey\` into your spec registry.
32
+
33
+ 3) Bind to product actions
34
+ - Tie \`Step\` completion conditions to domain events (e.g., deal.created, agent.run.completed, drill.session.completed).
35
+ - Trigger notifications via Notification Center and audits on completion.
36
+
37
+ 4) Gamification
38
+ - Use \`XP\` and \`Streak\` engines to update learner stats; emit analytics for UI.
39
+
40
+ ## Example
41
+
42
+ ${"```"}ts
43
+ import { learningJourneyEntities } from '@contractspec/module.learning-journey';
44
+ import { StreakEngine } from '@contractspec/module.learning-journey/engines';
45
+
46
+ const streak = new StreakEngine({ graceDays: 1 });
47
+ const updated = streak.compute({ lastActiveAt: new Date(), today: new Date() });
48
+ ${"```"},
49
+
50
+ ## Guardrails
51
+
52
+ - Keep steps bound to real product events, not just button clicks.
53
+ - Avoid storing PII in content; keep org/user scoping for multi-tenant isolation.
54
+ - Emit analytics and audit logs for completions; respect \`prefers-reduced-motion\` in UIs consuming these specs.
55
+ - Track completion bonuses: \`completionXpBonus\`, \`completionBadgeKey\`, optional \`streakHoursWindow\` + \`streakBonusXp\`.
56
+ `
57
+ },
58
+ {
59
+ id: "docs.learning-journey.goal",
60
+ title: "Learning Journey — Goal",
61
+ summary: "Why the learning journey engine exists and the outcomes it targets.",
62
+ kind: "goal",
63
+ visibility: "public",
64
+ route: "/docs/learning-journey/goal",
65
+ tags: ["learning", "goal"],
66
+ body: `## Why it matters
67
+ - Provides a regenerable onboarding/education engine tied to product signals.
68
+ - Keeps tracks, steps, quizzes, and gamification consistent across surfaces.
69
+
70
+ ## Business/Product goal
71
+ - Drive activation and retention with measurable progress, SRS, and streaks.
72
+ - Allow product teams to adjust journeys safely via specs.
73
+
74
+ ## Success criteria
75
+ - Journey changes regenerate UI/API/events without drift.
76
+ - Analytics/audit hooks exist for completions and streaks.`
77
+ },
78
+ {
79
+ id: "docs.learning-journey.usage",
80
+ title: "Learning Journey — Usage",
81
+ summary: "How to compose, bind, and regenerate journeys safely.",
82
+ kind: "usage",
83
+ visibility: "public",
84
+ route: "/docs/learning-journey/usage",
85
+ tags: ["learning", "usage"],
86
+ body: `## Setup
87
+ 1) Include \`learningJourneyEntities\` in schema composition.
88
+ 2) Register contracts/events from \`@contractspec/module.learning-journey\`.
89
+ 3) Bind steps to real product events (e.g., deal.created, run.completed).
90
+
91
+ ## Extend & regenerate
92
+ 1) Update track/module/step definitions or quiz schemas in spec.
93
+ 2) Regenerate to sync UI/API/events; mark PII paths where needed.
94
+ 3) Use Feature Flags to trial new tracks or streak rules.
95
+
96
+ ## Guardrails
97
+ - Avoid hardcoded progression; keep engines declarative.
98
+ - Emit analytics/audit for completions; respect user locale/accessibility in presentations.
99
+ - Keep content free of PII; scope learners by org/tenant.`
100
+ },
101
+ {
102
+ id: "docs.learning-journey.constraints",
103
+ title: "Learning Journey — Constraints & Safety",
104
+ summary: "Internal guardrails for progression, telemetry, and regeneration semantics.",
105
+ kind: "reference",
106
+ visibility: "internal",
107
+ route: "/docs/learning-journey/constraints",
108
+ tags: ["learning", "constraints", "internal"],
109
+ body: `## Constraints
110
+ - Progression (tracks/modules/steps) and engines (SRS, streaks, XP) must stay declarative in spec.
111
+ - Events to emit: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded.
112
+ - Regeneration should not change scoring/streak rules without explicit spec change.
113
+
114
+ ## PII & Telemetry
115
+ - Mark PII (learner identifiers) and redact in presentations; keep telemetry aggregated when possible.
116
+ - Respect accessibility (prefers-reduced-motion) in UIs consuming these specs.
117
+
118
+ ## Verification
119
+ - Add fixtures for streak/XP rule changes and quiz scoring.
120
+ - Ensure Notifications/Audit wiring persists for completions; analytics emitted for progress.
121
+ - Use Feature Flags to trial new tracks or reward rules; default safe/off.`
122
+ }
123
+ ];
124
+ registerDocBlocks(learningJourneyDocBlocks);
@@ -0,0 +1,124 @@
1
+ // src/docs/learning-journey.docblock.ts
2
+ import { registerDocBlocks } from "@contractspec/lib.contracts/docs";
3
+ var learningJourneyDocBlocks = [
4
+ {
5
+ id: "docs.learning-journey.engine",
6
+ title: "Learning Journey Engine",
7
+ summary: "Tracks learners, tracks/modules/steps, progress, quizzes, streaks, XP, and AI coaching hooks for product-integrated onboarding.",
8
+ kind: "reference",
9
+ visibility: "public",
10
+ route: "/docs/learning-journey/engine",
11
+ tags: ["learning", "onboarding", "journey", "education"],
12
+ body: `## Capabilities
13
+
14
+ - **Entities**: Learner, Track, Module, Step, Progress, Quiz, Flashcard, AI Coach, Gamification (XP, streaks, badges).
15
+ - **Contracts**: enroll/resume/advance steps, complete quizzes, record streaks, assign XP, fetch progress dashboards, onboarding list/progress/recordEvent.
16
+ - **Engines**: spaced-repetition (SRS), streak calculator, XP progression.
17
+ - **Events**: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded, onboarding.started/completed/step_completed.
18
+
19
+ ## Completion conditions
20
+ - Event-based: name/version/source + payload filter
21
+ - Count-based: require N events (optional time window)
22
+ - Time-bounded: must complete within a window; steps can unlock by day/hour
23
+ - SRS mastery: complete when cards/skills hit mastery thresholds (with required counts)
24
+
25
+ ## Usage
26
+
27
+ 1) Compose schema
28
+ - Include \`learningJourneySchemaContribution\` (entities export) in composition.
29
+
30
+ 2) Register contracts/events
31
+ - Import from \`@contractspec/module.learning-journey\` into your spec registry.
32
+
33
+ 3) Bind to product actions
34
+ - Tie \`Step\` completion conditions to domain events (e.g., deal.created, agent.run.completed, drill.session.completed).
35
+ - Trigger notifications via Notification Center and audits on completion.
36
+
37
+ 4) Gamification
38
+ - Use \`XP\` and \`Streak\` engines to update learner stats; emit analytics for UI.
39
+
40
+ ## Example
41
+
42
+ ${"```"}ts
43
+ import { learningJourneyEntities } from '@contractspec/module.learning-journey';
44
+ import { StreakEngine } from '@contractspec/module.learning-journey/engines';
45
+
46
+ const streak = new StreakEngine({ graceDays: 1 });
47
+ const updated = streak.compute({ lastActiveAt: new Date(), today: new Date() });
48
+ ${"```"},
49
+
50
+ ## Guardrails
51
+
52
+ - Keep steps bound to real product events, not just button clicks.
53
+ - Avoid storing PII in content; keep org/user scoping for multi-tenant isolation.
54
+ - Emit analytics and audit logs for completions; respect \`prefers-reduced-motion\` in UIs consuming these specs.
55
+ - Track completion bonuses: \`completionXpBonus\`, \`completionBadgeKey\`, optional \`streakHoursWindow\` + \`streakBonusXp\`.
56
+ `
57
+ },
58
+ {
59
+ id: "docs.learning-journey.goal",
60
+ title: "Learning Journey — Goal",
61
+ summary: "Why the learning journey engine exists and the outcomes it targets.",
62
+ kind: "goal",
63
+ visibility: "public",
64
+ route: "/docs/learning-journey/goal",
65
+ tags: ["learning", "goal"],
66
+ body: `## Why it matters
67
+ - Provides a regenerable onboarding/education engine tied to product signals.
68
+ - Keeps tracks, steps, quizzes, and gamification consistent across surfaces.
69
+
70
+ ## Business/Product goal
71
+ - Drive activation and retention with measurable progress, SRS, and streaks.
72
+ - Allow product teams to adjust journeys safely via specs.
73
+
74
+ ## Success criteria
75
+ - Journey changes regenerate UI/API/events without drift.
76
+ - Analytics/audit hooks exist for completions and streaks.`
77
+ },
78
+ {
79
+ id: "docs.learning-journey.usage",
80
+ title: "Learning Journey — Usage",
81
+ summary: "How to compose, bind, and regenerate journeys safely.",
82
+ kind: "usage",
83
+ visibility: "public",
84
+ route: "/docs/learning-journey/usage",
85
+ tags: ["learning", "usage"],
86
+ body: `## Setup
87
+ 1) Include \`learningJourneyEntities\` in schema composition.
88
+ 2) Register contracts/events from \`@contractspec/module.learning-journey\`.
89
+ 3) Bind steps to real product events (e.g., deal.created, run.completed).
90
+
91
+ ## Extend & regenerate
92
+ 1) Update track/module/step definitions or quiz schemas in spec.
93
+ 2) Regenerate to sync UI/API/events; mark PII paths where needed.
94
+ 3) Use Feature Flags to trial new tracks or streak rules.
95
+
96
+ ## Guardrails
97
+ - Avoid hardcoded progression; keep engines declarative.
98
+ - Emit analytics/audit for completions; respect user locale/accessibility in presentations.
99
+ - Keep content free of PII; scope learners by org/tenant.`
100
+ },
101
+ {
102
+ id: "docs.learning-journey.constraints",
103
+ title: "Learning Journey — Constraints & Safety",
104
+ summary: "Internal guardrails for progression, telemetry, and regeneration semantics.",
105
+ kind: "reference",
106
+ visibility: "internal",
107
+ route: "/docs/learning-journey/constraints",
108
+ tags: ["learning", "constraints", "internal"],
109
+ body: `## Constraints
110
+ - Progression (tracks/modules/steps) and engines (SRS, streaks, XP) must stay declarative in spec.
111
+ - Events to emit: learner.enrolled, step.completed, quiz.scored, streak.reset, xp.awarded.
112
+ - Regeneration should not change scoring/streak rules without explicit spec change.
113
+
114
+ ## PII & Telemetry
115
+ - Mark PII (learner identifiers) and redact in presentations; keep telemetry aggregated when possible.
116
+ - Respect accessibility (prefers-reduced-motion) in UIs consuming these specs.
117
+
118
+ ## Verification
119
+ - Add fixtures for streak/XP rule changes and quiz scoring.
120
+ - Ensure Notifications/Audit wiring persists for completions; analytics emitted for progress.
121
+ - Use Feature Flags to trial new tracks or reward rules; default safe/off.`
122
+ }
123
+ ];
124
+ registerDocBlocks(learningJourneyDocBlocks);