@dzhechkov/keysarium 1.4.0 → 1.5.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 (79) hide show
  1. package/README.md +50 -3
  2. package/bin/cli.js +0 -0
  3. package/package.json +5 -3
  4. package/templates/.claude/commands/analyst-manual.md +38 -0
  5. package/templates/.claude/commands/casarium.md +55 -4
  6. package/templates/.claude/commands/feature-adr.md +8 -0
  7. package/templates/.claude/rules/trust-tiers.md +5 -0
  8. package/templates/.claude/shards/feature-adr.shard.md +64 -10
  9. package/templates/.claude/shards/phase-ai-factory.shard.md +109 -0
  10. package/templates/.claude/skills/ai-factory-mapper/README.md +90 -0
  11. package/templates/.claude/skills/ai-factory-mapper/SKILL.md +309 -0
  12. package/templates/.claude/skills/ai-factory-mapper/assets/report-template.md +123 -0
  13. package/templates/.claude/skills/ai-factory-mapper/references/catalog.md +230 -0
  14. package/templates/.claude/skills/ai-factory-mapper/references/coverage-formula.md +219 -0
  15. package/templates/.claude/skills/ai-factory-mapper/references/decomposition-checklist.md +183 -0
  16. package/templates/.claude/skills/ai-factory-mapper/references/pattern-library.md +312 -0
  17. package/templates/.claude/skills/ai-factory-mapper/scripts/build_docx_report.js +423 -0
  18. package/templates/.claude/skills/analyst-manual-full/SKILL.md +286 -0
  19. package/templates/.claude/skills/edu-site-generator/SKILL.md +254 -0
  20. package/templates/.claude/skills/edu-site-generator/examples/sample-course-structure.md +116 -0
  21. package/templates/.claude/skills/edu-site-generator/modules/00-content-analysis.md +84 -0
  22. package/templates/.claude/skills/edu-site-generator/modules/01-course-structure.md +75 -0
  23. package/templates/.claude/skills/edu-site-generator/modules/02-data-generation.md +186 -0
  24. package/templates/.claude/skills/edu-site-generator/modules/03-scaffold.md +249 -0
  25. package/templates/.claude/skills/edu-site-generator/modules/04-components.md +130 -0
  26. package/templates/.claude/skills/edu-site-generator/modules/05-gamification.md +163 -0
  27. package/templates/.claude/skills/edu-site-generator/modules/06-deploy.md +88 -0
  28. package/templates/.claude/skills/edu-site-generator/modules/07-verification.md +97 -0
  29. package/templates/.claude/skills/edu-site-generator/references/component-templates.md +436 -0
  30. package/templates/.claude/skills/edu-site-generator/references/data-schemas.md +164 -0
  31. package/templates/.claude/skills/edu-site-generator/references/exercise-catalog.md +110 -0
  32. package/templates/.claude/skills/edu-site-generator/references/tech-stack.md +69 -0
  33. package/templates/.claude/skills/feature-adr/SKILL.md +245 -59
  34. package/templates/.claude/skills/feature-adr/modules/03-adr.md +43 -0
  35. package/templates/.claude/skills/feature-adr/modules/03.5-ideation-swarm.md +180 -0
  36. package/templates/.claude/skills/feature-adr/modules/06-implementation-plan.md +56 -7
  37. package/templates/.claude/skills/feature-adr/modules/08-qe.md +87 -23
  38. package/templates/.claude/skills/feature-adr/modules/09-fleet-qe.md +305 -0
  39. package/templates/.claude/skills/feature-adr/references/agentic-qe/README.md +143 -0
  40. package/templates/.claude/skills/feature-adr/references/agentic-qe/brutal-honesty-review.md +240 -0
  41. package/templates/.claude/skills/feature-adr/references/agentic-qe/chaos-engineering-resilience.md +163 -0
  42. package/templates/.claude/skills/feature-adr/references/agentic-qe/code-goal-planner.md +446 -0
  43. package/templates/.claude/skills/feature-adr/references/agentic-qe/enterprise-integration-testing.md +111 -0
  44. package/templates/.claude/skills/feature-adr/references/agentic-qe/mutation-testing.md +236 -0
  45. package/templates/.claude/skills/feature-adr/references/agentic-qe/performance-testing.md +315 -0
  46. package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-ideation-swarm.md +126 -0
  47. package/templates/.claude/skills/feature-adr/references/agentic-qe/qcsd-production-swarm.md +108 -0
  48. package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-coverage-analysis.md +193 -0
  49. package/templates/.claude/skills/feature-adr/references/agentic-qe/qe-requirements-validation.md +254 -0
  50. package/templates/.claude/skills/feature-adr/references/agentic-qe/regression-testing.md +233 -0
  51. package/templates/.claude/skills/feature-adr/references/agentic-qe/risk-based-testing.md +212 -0
  52. package/templates/.claude/skills/feature-adr/references/agentic-qe/security-testing.md +311 -0
  53. package/templates/.claude/skills/feature-adr/references/agentic-qe/shift-left-testing.md +231 -0
  54. package/templates/.claude/skills/feature-adr/references/agentic-qe/tdd-london-chicago.md +249 -0
  55. package/templates/.claude/skills/transcript-site-generator/SKILL.md +287 -0
  56. package/templates/.claude/skills/transcript-site-generator/examples/sample-text-only-site.md +123 -0
  57. package/templates/.claude/skills/transcript-site-generator/examples/sample-transcript-site.md +134 -0
  58. package/templates/.claude/skills/transcript-site-generator/modules/00-input-analysis.md +132 -0
  59. package/templates/.claude/skills/transcript-site-generator/modules/01-content-parsing.md +117 -0
  60. package/templates/.claude/skills/transcript-site-generator/modules/02-site-generation.md +293 -0
  61. package/templates/.claude/skills/transcript-site-generator/modules/03-interactivity.md +406 -0
  62. package/templates/.claude/skills/transcript-site-generator/modules/04-deploy.md +130 -0
  63. package/templates/.claude/skills/transcript-site-generator/modules/05-verification.md +155 -0
  64. package/templates/.claude/skills/transcript-site-generator/references/component-catalog.md +86 -0
  65. package/templates/.claude/skills/transcript-site-generator/references/data-schemas.md +123 -0
  66. package/templates/.claude/skills/transcript-site-generator/references/tech-stack.md +132 -0
  67. package/templates/CLAUDE.md +9 -2
  68. package/templates/docs/edu-site-generator/01-deployment-guide.md +911 -0
  69. package/templates/docs/edu-site-generator/02-admin-guide.md +901 -0
  70. package/templates/docs/edu-site-generator/03-user-guide.md +1008 -0
  71. package/templates/docs/edu-site-generator/04-infrastructure-requirements.md +489 -0
  72. package/templates/docs/edu-site-generator/05-architecture.md +902 -0
  73. package/templates/docs/edu-site-generator/06-user-flows.md +759 -0
  74. package/templates/docs/transcript-site-generator/01-deployment-guide.md +1042 -0
  75. package/templates/docs/transcript-site-generator/02-admin-guide.md +918 -0
  76. package/templates/docs/transcript-site-generator/03-user-guide.md +925 -0
  77. package/templates/docs/transcript-site-generator/04-infrastructure-requirements.md +482 -0
  78. package/templates/docs/transcript-site-generator/05-architecture.md +1068 -0
  79. package/templates/docs/transcript-site-generator/06-user-flows.md +855 -0
@@ -0,0 +1,436 @@
1
+ # Component Templates Reference
2
+
3
+ Code templates for all components. Use these as the basis when generating components in Step 4.
4
+
5
+ ## Layout Components
6
+
7
+ ### SectionLayout.jsx
8
+ ```jsx
9
+ import { useAppStore } from '../../store/useAppStore'
10
+
11
+ export default function SectionLayout({ id, icon, title, description, theory, children }) {
12
+ const completed = useAppStore((s) => s.completedSections[id])
13
+ const score = useAppStore((s) => s.sectionScores[id])
14
+
15
+ return (
16
+ <section id={`section-${id}`} className="py-12 border-t border-border">
17
+ <div className="max-w-3xl mx-auto px-4">
18
+ <div className="flex items-start gap-3 mb-4">
19
+ <span className="text-2xl">{icon}</span>
20
+ <div className="flex-1">
21
+ <h2 className="text-xl font-bold text-text">{title}</h2>
22
+ <p className="text-text-muted text-sm mt-1">{description}</p>
23
+ </div>
24
+ {completed && (
25
+ <span className="px-3 py-1 bg-success-500/10 text-success-600 dark:text-success-400 text-xs font-medium rounded-full">
26
+ {score}%
27
+ </span>
28
+ )}
29
+ </div>
30
+
31
+ {theory && (
32
+ <div className="mb-8 text-text-secondary text-sm leading-relaxed whitespace-pre-line">
33
+ {theory}
34
+ </div>
35
+ )}
36
+
37
+ {!completed && children}
38
+ {completed && (
39
+ <p className="text-sm text-success-600 dark:text-success-400 font-medium">
40
+ Section completed with {score}% score
41
+ </p>
42
+ )}
43
+ </div>
44
+ </section>
45
+ )
46
+ }
47
+ ```
48
+
49
+ ### Header.jsx
50
+ ```jsx
51
+ import { useAppStore } from '../../store/useAppStore'
52
+ import { useProgress } from '../../hooks/useProgress'
53
+
54
+ export default function Header() {
55
+ const { percentage, totalScore } = useProgress()
56
+ const toggleNav = useAppStore((s) => s.toggleNav)
57
+ const darkMode = useAppStore((s) => s.darkMode)
58
+ const toggleDarkMode = useAppStore((s) => s.toggleDarkMode)
59
+
60
+ return (
61
+ <header className="sticky top-0 z-50 bg-card/80 backdrop-blur-sm border-b border-border">
62
+ <div className="max-w-6xl mx-auto px-4 h-14 flex items-center justify-between">
63
+ <div className="flex items-center gap-3">
64
+ <button onClick={toggleNav} className="md:hidden p-2">
65
+ {/* hamburger icon */}
66
+ </button>
67
+ <a href="#/" className="font-bold text-text no-underline">
68
+ {/* Course title */}
69
+ </a>
70
+ </div>
71
+ <div className="flex items-center gap-4">
72
+ <span className="text-sm text-text-muted">{totalScore} pts</span>
73
+ <span className="text-sm text-text-muted">{percentage}%</span>
74
+ <button onClick={toggleDarkMode}>
75
+ {/* sun/moon icon */}
76
+ </button>
77
+ <a href="#/final-test" className="px-3 py-1.5 bg-primary-500 text-white text-sm rounded-lg">
78
+ Final Test
79
+ </a>
80
+ </div>
81
+ </div>
82
+ </header>
83
+ )
84
+ }
85
+ ```
86
+
87
+ ### Navigation.jsx
88
+
89
+ **CRITICAL:** Use `scrollIntoView()` via buttons, NOT `<a href="#section-...">`:
90
+ ```jsx
91
+ function scrollTo(id) {
92
+ document.getElementById(`section-${id}`)?.scrollIntoView({ behavior: 'smooth' })
93
+ // Close nav on mobile
94
+ setNavOpen(false)
95
+ }
96
+
97
+ // Render:
98
+ <button onClick={() => scrollTo(section.id)}>
99
+ {section.icon} {section.shortTitle}
100
+ </button>
101
+ ```
102
+
103
+ ### Flashcard.jsx
104
+ ```jsx
105
+ import { useState } from 'react'
106
+
107
+ export default function Flashcard({ cards, onComplete }) {
108
+ // Toggle state: tracks which side is showing (true = back, false = front)
109
+ const [flipped, setFlipped] = useState({})
110
+ // Viewed state: tracks which cards have been seen at least once (for completion)
111
+ const [viewed, setViewed] = useState({})
112
+
113
+ function handleFlip(index) {
114
+ // Toggle the card back and forth
115
+ setFlipped(prev => ({ ...prev, [index]: !prev[index] }))
116
+
117
+ // Track first-time views for completion scoring
118
+ if (!viewed[index]) {
119
+ const nextViewed = { ...viewed, [index]: true }
120
+ setViewed(nextViewed)
121
+ if (Object.keys(nextViewed).length === cards.length) {
122
+ onComplete(100)
123
+ }
124
+ }
125
+ }
126
+
127
+ return (
128
+ <div className="grid gap-4 sm:grid-cols-2">
129
+ {cards.map((card, i) => (
130
+ <button
131
+ key={i}
132
+ onClick={() => handleFlip(i)}
133
+ onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); handleFlip(i) } }}
134
+ aria-label={flipped[i] ? 'Flip card to front' : 'Flip card to back'}
135
+ className={`p-6 rounded-xl border-2 min-h-[120px] transition-all duration-300 text-left cursor-pointer ${
136
+ flipped[i]
137
+ ? 'border-primary-500 bg-primary-50 dark:bg-primary-900/20'
138
+ : 'border-border hover:border-primary-400'
139
+ }`}
140
+ >
141
+ <p className={`text-sm ${flipped[i] ? 'text-primary-700 dark:text-primary-300' : 'text-text font-medium'}`}>
142
+ {flipped[i] ? card.back : card.front}
143
+ </p>
144
+ <p className="text-xs text-text-muted mt-2">
145
+ {viewed[i] ? '✓ Viewed — click to flip' : 'Click to flip'}
146
+ </p>
147
+ </button>
148
+ ))}
149
+ </div>
150
+ )
151
+ }
152
+ ```
153
+
154
+ ### CommandBuilder.jsx
155
+ ```jsx
156
+ import { useState } from 'react'
157
+
158
+ export default function CommandBuilder({ instruction, parts, correctCommand, hints, onComplete }) {
159
+ const [built, setBuilt] = useState([])
160
+ const [checked, setChecked] = useState(false)
161
+ const [correct, setCorrect] = useState(false)
162
+ const [hintIndex, setHintIndex] = useState(0)
163
+
164
+ const availableParts = parts.filter((_, i) => !built.includes(i))
165
+ const builtCommand = built.map((i) => parts[i]).join('')
166
+
167
+ function handleAdd(index) {
168
+ if (checked) return
169
+ setBuilt([...built, index])
170
+ }
171
+
172
+ function handleRemove(pos) {
173
+ if (checked) return
174
+ setBuilt(built.filter((_, i) => i !== pos))
175
+ }
176
+
177
+ function handleCheck() {
178
+ if (builtCommand === correctCommand) {
179
+ setCorrect(true)
180
+ setChecked(true)
181
+ onComplete(100)
182
+ } else {
183
+ setHintIndex((i) => Math.min(i + 1, hints.length - 1))
184
+ }
185
+ }
186
+
187
+ function handleReset() {
188
+ setBuilt([])
189
+ setChecked(false)
190
+ setCorrect(false)
191
+ }
192
+
193
+ return (
194
+ <div className="space-y-4">
195
+ <p className="text-sm text-text-secondary">{instruction}</p>
196
+
197
+ <div className="bg-bg-secondary rounded-lg p-3 font-mono text-sm min-h-[44px]">
198
+ <span className="text-text-muted">$ </span>
199
+ {built.map((partIndex, pos) => (
200
+ <button key={pos} onClick={() => handleRemove(pos)}
201
+ className="text-primary-600 dark:text-primary-400 hover:line-through">
202
+ {parts[partIndex]}
203
+ </button>
204
+ ))}
205
+ {built.length === 0 && <span className="text-text-muted">click parts below...</span>}
206
+ </div>
207
+
208
+ <div className="flex flex-wrap gap-2">
209
+ {availableParts.map((part, i) => {
210
+ const originalIndex = parts.indexOf(part)
211
+ return (
212
+ <button key={i} onClick={() => handleAdd(originalIndex)}
213
+ className="px-3 py-1.5 bg-card border border-border rounded-lg text-sm hover:border-primary-400">
214
+ {part}
215
+ </button>
216
+ )
217
+ })}
218
+ </div>
219
+
220
+ {hintIndex > 0 && !correct && (
221
+ <p className="text-sm text-amber-600 dark:text-amber-400 bg-amber-50 dark:bg-amber-900/20 rounded-lg p-3">
222
+ {hints[hintIndex - 1]}
223
+ </p>
224
+ )}
225
+
226
+ {correct && (
227
+ <p className="text-sm text-success-600 dark:text-success-400 bg-success-500/10 rounded-lg p-3">
228
+ Correct!
229
+ </p>
230
+ )}
231
+
232
+ <div className="flex gap-2">
233
+ {!checked && built.length > 0 && (
234
+ <button onClick={handleCheck}
235
+ className="px-6 py-2 bg-primary-500 text-white rounded-lg hover:bg-primary-600">
236
+ Check
237
+ </button>
238
+ )}
239
+ {built.length > 0 && !correct && (
240
+ <button onClick={handleReset}
241
+ className="px-6 py-2 border border-border text-text-secondary rounded-lg hover:bg-bg-hover">
242
+ Reset
243
+ </button>
244
+ )}
245
+ </div>
246
+ </div>
247
+ )
248
+ }
249
+ ```
250
+
251
+ ### App.jsx Template
252
+ ```jsx
253
+ import { HashRouter, Routes, Route } from 'react-router-dom'
254
+ import Header from './components/layout/Header'
255
+ import Footer from './components/layout/Footer'
256
+ import ProgressBar from './components/layout/ProgressBar'
257
+ import Toast from './components/common/Toast'
258
+ import HomePage from './pages/HomePage'
259
+ import FinalTestPage from './pages/FinalTestPage'
260
+ import { useAchievements } from './hooks/useAchievements'
261
+
262
+ function AppContent() {
263
+ useAchievements()
264
+ return (
265
+ <div className="min-h-screen flex flex-col bg-surface">
266
+ <Header />
267
+ <ProgressBar />
268
+ <div className="flex-1">
269
+ <Routes>
270
+ <Route path="/" element={<HomePage />} />
271
+ <Route path="/final-test" element={<FinalTestPage />} />
272
+ </Routes>
273
+ </div>
274
+ <Footer />
275
+ <Toast />
276
+ </div>
277
+ )
278
+ }
279
+
280
+ export default function App() {
281
+ return (
282
+ <HashRouter>
283
+ <AppContent />
284
+ </HashRouter>
285
+ )
286
+ }
287
+ ```
288
+
289
+ ### Toast.jsx Template
290
+ ```jsx
291
+ import { useEffect } from 'react'
292
+ import { useAppStore } from '../../store/useAppStore'
293
+
294
+ export default function Toast() {
295
+ const toast = useAppStore((s) => s.toast)
296
+ const clearToast = useAppStore((s) => s.clearToast)
297
+
298
+ useEffect(() => {
299
+ if (toast) {
300
+ const timer = setTimeout(clearToast, 4000)
301
+ return () => clearTimeout(timer)
302
+ }
303
+ }, [toast])
304
+
305
+ if (!toast) return null
306
+
307
+ return (
308
+ <div className="fixed top-20 right-4 z-50 animate-fade-in-up">
309
+ <div className="bg-card border border-border rounded-xl shadow-lg p-4 max-w-sm">
310
+ <div className="flex items-start gap-3">
311
+ <span className="text-2xl">{toast.icon}</span>
312
+ <div>
313
+ <p className="font-semibold text-text text-sm">{toast.title}</p>
314
+ <p className="text-xs text-text-muted mt-1">{toast.description}</p>
315
+ </div>
316
+ </div>
317
+ </div>
318
+ </div>
319
+ )
320
+ }
321
+ ```
322
+
323
+ ## Interactive Components
324
+
325
+ ### Quiz.jsx — CRITICAL SCORING PATTERN
326
+ ```jsx
327
+ // handleSelect increments correctCount
328
+ function handleSelect(index) {
329
+ if (selected !== null) return
330
+ setSelected(index)
331
+ if (index === question.correctAnswer) {
332
+ setCorrectCount((c) => c + 1) // Already counted here
333
+ }
334
+ }
335
+
336
+ // handleNext uses correctCount DIRECTLY (no +1 compensation)
337
+ function handleNext() {
338
+ if (currentIndex < questions.length - 1) {
339
+ setCurrentIndex((i) => i + 1)
340
+ setSelected(null)
341
+ } else {
342
+ setFinished(true)
343
+ const score = Math.round((correctCount / questions.length) * 100) // NOT correctCount + 1
344
+ onComplete(score)
345
+ }
346
+ }
347
+
348
+ // Finished view also uses correctCount directly
349
+ if (finished) {
350
+ const finalCorrect = correctCount // NOT correctCount + (selected === ...)
351
+ // ...
352
+ }
353
+ ```
354
+
355
+ ### ScenarioGame.jsx — SAME SCORING PATTERN
356
+ ```jsx
357
+ // handleSelect increments score
358
+ function handleSelect(option) {
359
+ if (selectedOption) return
360
+ setSelectedOption(option)
361
+ if (option.result === 'positive') {
362
+ setScore((s) => s + 1) // Already counted here
363
+ }
364
+ }
365
+
366
+ // handleNext uses score DIRECTLY
367
+ function handleNext() {
368
+ // ...
369
+ setFinished(true)
370
+ const finalScore = score // NOT score + (selectedOption?.result === 'positive' ? 1 : 0)
371
+ const percentage = Math.round((finalScore / steps.length) * 100)
372
+ onComplete(percentage)
373
+ }
374
+ ```
375
+
376
+ ### DragOrder.jsx — Shuffle Pattern
377
+ ```jsx
378
+ // Fisher-Yates shuffle on mount
379
+ const [items, setItems] = useState(() => {
380
+ const shuffled = [...initialItems]
381
+ for (let i = shuffled.length - 1; i > 0; i--) {
382
+ const j = Math.floor(Math.random() * (i + 1));
383
+ [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]
384
+ }
385
+ return shuffled
386
+ })
387
+ ```
388
+
389
+ ### MatchingExercise.jsx — Shuffle Right Side
390
+ ```jsx
391
+ const [shuffledRight] = useState(() => {
392
+ const arr = items.map(i => i.right)
393
+ // Fisher-Yates shuffle
394
+ for (let i = arr.length - 1; i > 0; i--) {
395
+ const j = Math.floor(Math.random() * (i + 1));
396
+ [arr[i], arr[j]] = [arr[j], arr[i]]
397
+ }
398
+ return arr
399
+ })
400
+ ```
401
+
402
+ ## Section Component Template
403
+
404
+ ```jsx
405
+ import SectionLayout from '../layout/SectionLayout'
406
+ import Quiz from '../interactive/Quiz' // or appropriate component
407
+ import { useAppStore } from '../../store/useAppStore'
408
+ import { SECTIONS } from '../../data/sections'
409
+ import { quizQuestions } from '../../data/quizQuestions' // or exercises
410
+
411
+ const section = SECTIONS[0] // adjust index
412
+
413
+ export default function Section1() {
414
+ const markComplete = useAppStore((s) => s.markSectionComplete)
415
+
416
+ return (
417
+ <SectionLayout {...section} theory={section.theory}>
418
+ <Quiz
419
+ questions={quizQuestions[section.id]}
420
+ onComplete={(score) => markComplete(section.id, score)}
421
+ />
422
+ </SectionLayout>
423
+ )
424
+ }
425
+ ```
426
+
427
+ ## Component-to-Data Mapping
428
+
429
+ | Component | Data Source | Props |
430
+ |-----------|-----------|-------|
431
+ | Quiz | `quizQuestions[sectionId]` | `questions, onComplete` |
432
+ | Flashcard | `flashcardData[sectionId]` | `cards, onComplete` |
433
+ | MatchingExercise | `matchingData[sectionId]` | `items, onComplete` |
434
+ | DragOrder | `dragOrderData[sectionId]` or `orderingData[sectionId]` | `instruction, items, correctOrder, onComplete` |
435
+ | CommandBuilder | `commandBuilderData[sectionId]` | `instruction, parts, correctCommand, hints, onComplete` |
436
+ | ScenarioGame | `simulationData[sectionId]` or `scenarioData[sectionId]` | `title, scenario, steps, onComplete` |
@@ -0,0 +1,164 @@
1
+ # Data Schemas Reference
2
+
3
+ All data files live in `src/data/`. Content is data-driven — never hardcode text in components.
4
+
5
+ ## sections.js
6
+
7
+ ```typescript
8
+ // Section definition
9
+ interface Section {
10
+ id: string // kebab-case, unique, 2-4 words
11
+ order: number // 1-based sequential
12
+ title: string // "N. Full Title" (with order prefix)
13
+ shortTitle: string // 2-3 words for sidebar
14
+ description: string // One-line summary
15
+ icon: string // Single emoji
16
+ interactiveType: InteractiveType
17
+ theory: string // Multi-paragraph, use \n\n for breaks, **bold** for emphasis
18
+ }
19
+
20
+ type InteractiveType =
21
+ | 'quiz' // -> Quiz.jsx
22
+ | 'flashcards' // -> Flashcard.jsx
23
+ | 'matching' // -> MatchingExercise.jsx
24
+ | 'drag-and-drop' // -> DragOrder.jsx
25
+ | 'ordering' // -> DragOrder.jsx (alias)
26
+ | 'builder' // -> CommandBuilder.jsx
27
+ | 'simulation' // -> ScenarioGame.jsx
28
+ | 'scenario' // -> ScenarioGame.jsx (alias)
29
+
30
+ // Exports
31
+ export const SECTIONS: Section[]
32
+ export const TOTAL_SECTIONS: number // = SECTIONS.length
33
+ ```
34
+
35
+ ## quizQuestions.js
36
+
37
+ ```typescript
38
+ // Per-section quiz questions
39
+ interface QuizQuestion {
40
+ id: string // unique, e.g. "section-id-q1"
41
+ question: string // The question text
42
+ options: string[] // 4 options (array of 4 strings)
43
+ correctAnswer: number // Index (0-3) of the correct option
44
+ explanation: string // Why the correct answer is correct
45
+ }
46
+
47
+ // Final test question (one per section)
48
+ interface FinalTestQuestion {
49
+ id: string // unique, e.g. "final-section-id"
50
+ sectionId: string // Must match a section.id
51
+ question: string
52
+ options: string[] // 4 options
53
+ correctAnswer: number // Index (0-3)
54
+ }
55
+
56
+ // Exports
57
+ export const quizQuestions: Record<string, QuizQuestion[]>
58
+ export const finalTestQuestions: FinalTestQuestion[]
59
+ ```
60
+
61
+ ## exercises.js
62
+
63
+ ```typescript
64
+ // Flashcard data
65
+ interface FlashcardItem {
66
+ front: string // Question/term side
67
+ back: string // Answer/definition side
68
+ }
69
+ export const flashcardData: Record<string, FlashcardItem[]>
70
+ // 4-8 cards per section
71
+
72
+ // Matching data
73
+ interface MatchingItem {
74
+ left: string // Left side (stays in order)
75
+ right: string // Right side (shuffled)
76
+ }
77
+ export const matchingData: Record<string, MatchingItem[]>
78
+ // 4-6 pairs per section
79
+
80
+ // Drag order data
81
+ interface DragOrderItem {
82
+ id: string // Unique within this exercise
83
+ label: string // Display text
84
+ }
85
+ interface DragOrderExercise {
86
+ instruction: string // What to arrange
87
+ items: DragOrderItem[] // Items to order
88
+ correctOrder: string[] // Array of item IDs in correct order
89
+ }
90
+ export const dragOrderData: Record<string, DragOrderExercise>
91
+ export const orderingData: Record<string, DragOrderExercise> // alias
92
+
93
+ // Command builder data
94
+ interface CommandBuilderExercise {
95
+ instruction: string // What command to build
96
+ parts: string[] // Command parts (including spaces)
97
+ correctCommand: string // Expected assembled command
98
+ hints: string[] // Progressive hints
99
+ }
100
+ export const commandBuilderData: Record<string, CommandBuilderExercise>
101
+
102
+ // Scenario/Simulation data
103
+ interface ScenarioOption {
104
+ id: string // e.g. 'a', 'b', 'c'
105
+ text: string // Option display text
106
+ result: 'positive' | 'neutral' | 'negative'
107
+ feedback: string // Feedback after selection
108
+ }
109
+ interface ScenarioStep {
110
+ id: string // e.g. 'step1'
111
+ description: string // Situation description
112
+ options: ScenarioOption[] // 2-3 options
113
+ }
114
+ interface ScenarioExercise {
115
+ title: string
116
+ scenario: string // Context/setup text
117
+ steps: ScenarioStep[] // 3-5 steps
118
+ }
119
+ export const simulationData: Record<string, ScenarioExercise>
120
+ export const scenarioData: Record<string, ScenarioExercise> // alias
121
+
122
+ // FAQ data
123
+ interface FAQItem {
124
+ question: string
125
+ answer: string
126
+ }
127
+ export const faqData: FAQItem[]
128
+ // 5-8 items about the course topic
129
+ ```
130
+
131
+ ## achievements.js
132
+
133
+ ```typescript
134
+ interface Achievement {
135
+ id: string // unique kebab-case
136
+ title: string // Display name (localized)
137
+ description: string // What was accomplished
138
+ icon: string // Single emoji
139
+ condition: (state: StoreState) => boolean // Unlock condition
140
+ }
141
+
142
+ // StoreState shape:
143
+ interface StoreState {
144
+ completedSections: Record<string, boolean>
145
+ sectionScores: Record<string, number>
146
+ finalTestScore: number | null
147
+ }
148
+
149
+ export const ACHIEVEMENTS: Achievement[]
150
+ ```
151
+
152
+ ### Standard Achievement Set
153
+
154
+ Every course should include these base achievements:
155
+
156
+ | ID | Condition | Description |
157
+ |----|-----------|-------------|
158
+ | `first-step` | 1+ section completed | Starting the journey |
159
+ | `halfway` | N/2+ sections completed | Halfway through |
160
+ | `perfectionist` | Any section with score 100 | Perfect score |
161
+ | `full-course` | All N sections completed | Course complete |
162
+ | `test-passed` | Final test score >= 70 | Test passed |
163
+
164
+ Plus 3-5 topic-specific achievements based on section groupings.
@@ -0,0 +1,110 @@
1
+ # Exercise Type Catalog
2
+
3
+ ## 6 Interactive Exercise Types
4
+
5
+ ### 1. Quiz (`interactiveType: 'quiz'`)
6
+
7
+ **Best for:** Factual knowledge, best practices, conceptual understanding
8
+ **Content type:** Statements that can be verified as true/false or selected from options
9
+
10
+ **When to use:**
11
+ - Testing recall of facts, definitions, rules
12
+ - Multiple valid-looking answers exist (good distractors)
13
+ - Explanations add learning value
14
+
15
+ **Data needed:** 2-4 questions with 4 options each, correct answer index, explanation
16
+
17
+ **UX:** Step through questions one at a time, immediate feedback per question, final score.
18
+
19
+ ---
20
+
21
+ ### 2. Flashcards (`interactiveType: 'flashcards'`)
22
+
23
+ **Best for:** Vocabulary, definitions, term-concept pairs
24
+ **Content type:** Two-sided information (question/answer, term/definition)
25
+
26
+ **When to use:**
27
+ - Memorization is the goal
28
+ - Content is naturally paired (term <-> definition)
29
+ - Self-paced review is valuable
30
+
31
+ **Data needed:** 4-8 front/back card pairs
32
+
33
+ **UX:** Click/tap to toggle — cards flip back and forth freely. Tracks which cards have been viewed at least once. 100% completion on viewing all. Keyboard accessible (Enter/Space).
34
+
35
+ ---
36
+
37
+ ### 3. Matching Exercise (`interactiveType: 'matching'`)
38
+
39
+ **Best for:** Associations, mappings, relationships
40
+ **Content type:** Items that belong together in pairs
41
+
42
+ **When to use:**
43
+ - Concepts map to descriptions, tools to purposes, causes to effects
44
+ - Visual connection reinforces learning
45
+ - 4-6 distinct pairs available
46
+
47
+ **Data needed:** 4-6 left/right pairs
48
+
49
+ **UX:** Left column fixed, right column shuffled. Click left then right to match. Green on correct, shake on wrong.
50
+
51
+ ---
52
+
53
+ ### 4. Drag-to-Order (`interactiveType: 'drag-and-drop'` or `'ordering'`)
54
+
55
+ **Best for:** Sequential processes, priority ordering, step-by-step procedures
56
+ **Content type:** Items with a definitive correct order
57
+
58
+ **When to use:**
59
+ - Steps in a process must be in specific sequence
60
+ - Priority or importance ordering matters
61
+ - Understanding workflow/pipeline order
62
+
63
+ **Data needed:** 4-8 items with IDs, labels, and correct order array
64
+
65
+ **UX:** Drag items to reorder, "Check" button to verify, retry on wrong. Uses @dnd-kit.
66
+
67
+ ---
68
+
69
+ ### 5. Command Builder (`interactiveType: 'builder'`)
70
+
71
+ **Best for:** CLI commands, API calls, code syntax
72
+ **Content type:** Structured text that must be assembled correctly
73
+
74
+ **When to use:**
75
+ - Teaching command-line tools or API usage
76
+ - Syntax matters (order of flags, arguments)
77
+ - Progressive hints guide the learner
78
+
79
+ **Data needed:** Command parts array, correct assembled command, hints array
80
+
81
+ **UX:** Click parts to build command (shown as terminal-style), check button, progressive hints on failure.
82
+
83
+ ---
84
+
85
+ ### 6. Scenario Game (`interactiveType: 'simulation'` or `'scenario'`)
86
+
87
+ **Best for:** Decision-making, workflows, applied knowledge
88
+ **Content type:** Multi-step situations requiring judgment
89
+
90
+ **When to use:**
91
+ - Teaching decision-making in real-world contexts
92
+ - Multiple valid approaches with different outcomes
93
+ - Feedback on choices is more valuable than binary right/wrong
94
+
95
+ **Data needed:** Scenario description, 3-5 steps each with 2-3 options (positive/neutral/negative)
96
+
97
+ **UX:** Read scenario, step through decisions, see feedback per choice, final score = positive choices / total steps.
98
+
99
+ ---
100
+
101
+ ## Exercise Distribution Guidelines
102
+
103
+ | Section Count | Recommended Mix |
104
+ |---------------|----------------|
105
+ | 3-5 | 1 quiz, 1 flashcard, 1 matching/drag |
106
+ | 6-9 | 2 quiz, 1 flashcard, 1 matching, 1 drag, 1 scenario |
107
+ | 10-15 | 3 quiz, 2 flashcard, 2 matching, 2 drag, 1 builder, 2 scenario |
108
+ | 16-20 | Balanced across all 6 types |
109
+
110
+ **Rule:** Never have 3+ consecutive sections with the same exercise type.