Types primaires
1. slides
Présentation avec éléments riches.
{
"slides": [
{
"id": "uuid",
"layout": "title_content" | "two_column" | "image_focus" | "code_demo",
"elements": [
{ "type": "heading", "text": "...", "style": {} },
{ "type": "paragraph", "text": "..." },
{ "type": "image", "mediaAssetId": "uuid" },
{ "type": "list", "items": ["..."], "ordered": true },
{ "type": "code", "language": "python", "code": "..." },
{ "type": "callout", "variant": "info|warning|tip", "text": "..." }
]
}
],
"speakerNotes": { "slide-uuid": "Notes..." }
}
Viewer : components/lesson-viewer/slide-viewer.tsx (navigation au clavier, plein écran, notes du présentateur).
2. video
{
"source": "youtube" | "vimeo" | "upload",
"embedUrl": "https://...",
"videoUrl": "...",
"mediaAssetId": "uuid"
}
Prend en charge la vitesse de lecture, les sous-titres, le contrôle de la lecture automatique. Transcription automatique via Whisper lorsque mediaAssetId est présent.
3. pdf_viewer
{
"mediaAssetId": "uuid",
"storageUrl": "...",
"initialPage": 1
}
Viewer avec react-pdf, navigation, zoom, recherche en texte intégral.
4. rich_text
{
"html": "<h1>...</h1><p>...</p>"
}
Éditeur : Tiptap avec extensions (tableaux, blocs de code avec coloration syntaxique, images, liens, couleur, typographie, math). HTML assaini côté serveur avec sanitizeHtml().
5. quiz
{
"questions": [
{ "type": "multiple_choice", "question": "...", "options": ["A","B","C","D"],
"correctIndex": 0, "explanation": "...", "concepts": ["concept-id"] },
{ "type": "true_false", "question": "...", "correctIndex": 0 },
{ "type": "fill_blank", "question": "...", "blanks": [{"answer": "..."}] },
{ "type": "matching", "pairs": [{"left": "...", "right": "..."}] },
{ "type": "ordering", "items": ["..."] },
{ "type": "numeric", "answer": 42, "tolerance": 0.1 },
{ "type": "short_answer", "acceptedAnswers": ["..."] },
{ "type": "essay", "prompt": "..." }
],
"passingScore": 70,
"configuration": {
"maxAttempts": 3,
"timeLimitMinutes": 30,
"shuffleQuestions": true,
"shuffleOptions": true,
"accessCode": "...",
"scoringPolicy": "highest" | "latest" | "average",
"reviewMode": "after_submit" | "after_due_date" | "never"
}
}
Détails sur Quiz Engine.
6. assignment
{
"instructions": "...",
"dueDate": "2026-06-15",
"maxScore": 100,
"submissionType": "text" | "file" | "both",
"rubricId": "uuid"
}
Les soumissions sont stockées dans le bucket privé submissions/{tenantId}/{courseId}/{lessonId}/{userId}/ (règle critique 122).
7. live_class
{
"liveClassId": "uuid"
}
L'entité LiveClass dispose d'un fournisseur (BBB/Zoom/Teams/Meet), d'une URL de connexion et d'une URL d'enregistrement. Détails sur les classes en direct.
8. external_link
{
"url": "https://...",
"description": "...",
"openInNewTab": true
}
Sous-types interactifs
Lorsque lesson.subtype !== null, un viewer interactif dédié est rendu :
interactive_video
Vidéo avec checkpoints (questions obligatoires avant de continuer).
{
"videoUrl": "...",
"checkpoints": [
{ "timestampSec": 120, "question": { ... } }
]
}
drag_drop
{
"items": [{ "id": "1", "label": "Mitose" }],
"targets": [{ "id": "a", "label": "Division cellulaire", "acceptedItemIds": ["1"] }]
}
fill_blanks
{
"text": "La capitale de la France est {{0}} et se trouve sur le continent {{1}}.",
"blanks": [
{ "id": 0, "acceptedAnswers": ["Paris"] },
{ "id": 1, "acceptedAnswers": ["Europe", "européen"] }
]
}
flashcard_set
{
"cards": [
{ "id": "1", "front": "Quel est le théorème de Pythagore ?", "back": "a² + b² = c²" }
],
"srsEnabled": true
}
Algorithme SRS SM-2 modifié. Planifie les révisions dans StudentFlashcardReview.
timeline
{
"events": [
{ "date": "1500", "title": "Découverte du Brésil", "description": "..." }
]
}
Frise chronologique interactive avec zoom.
branching_scenario
Arbre de décision pour les simulations (ex : cas clinique, dilemme éthique, négociation).
{
"rootNodeId": "n1",
"nodes": {
"n1": {
"text": "Vous êtes médecin et recevez un patient souffrant de douleurs thoraciques...",
"choices": [
{ "text": "Demander un ECG", "nextNodeId": "n2" },
{ "text": "Hospitaliser immédiatement", "nextNodeId": "n3" }
]
}
}
}
Éditeurs (Lesson Builder)
Chaque type dispose d'un éditeur visuel dédié dans components/lesson-builder/ :
- slides →
slides-editor.tsx(réordonnancement dnd-kit, éléments drag-drop) - rich_text →
rich-text-editor.tsx(Tiptap) - quiz →
quiz-editor.tsx(avec sélecteur de banque de questions + boîte de dialogue d'enregistrement) - assignment →
assignment-editor.tsx(sélecteur de rubrique, date d'échéance) - video →
video-editor.tsx(sélection de source + intégration) - pdf →
pdf-editor.tsx(upload + sélecteur de médias) - live_class →
live-class-editor.tsx(sélection du fournisseur + planification) - external_link →
external-link-editor.tsx - sous-types interactifs → éditeurs dédiés dans
components/interactive/
Limitations
- Quiz de type essay sans correction automatique native — l'administrateur peut activer la correction par LLM (coût supplémentaire)
- Les sous-types interactifs ne migrent pas vers H5P — format propriétaire Studeia
- Branching_scenario profondeur maximale 10 niveaux — protection contre les boucles infinies