1

Vision & Contraintes

Plateforme permettant à des enseignants de créer des parcours pédagogiques collaboratifs entre deux groupes. Chaque parcours est une séquence de cards où la progression d'un groupe conditionne le déblocage des étapes de l'autre groupe.

Deux modes

ModeDescriptionGroupes
Collaboratif2 groupes liés, déblocage inter-dépendantA ⇄ B
Solo1 groupe, déblocage par validation prof ou verrou gamifiéA seul

Contraintes non négociables

🔒

100 % gratuit · Self-hosted VPS IONOS · Un seul déploiement (multi-tenant) · IA via Ollama existant · Mobile-first élèves · Builder desktop-only profs

2

Stack technique

CoucheChoixJustification
FrontendVue 3 + ViteRéactivité builder drag & drop + temps réel
BaaSPocketBase (SQLite WAL)Auth, API, Realtime WebSocket, 1 container, zéro config
IAOllama mistral:7bFrançais, gratuit, déjà en prod sur le VPS
Reverse proxyNginx 1.24 + Let's EncryptDéjà en place, sous-domaines illimités
ConteneurisationDocker ComposeCohérent avec les autres projets du VPS
BuildVite → fichiers statiquesPas de Node.js en prod

Sous-domaines

duneclassealautre.portailemfe.fr
→
Site vitrine
app.duneclassealautre.portailemfe.fr
→
SaaS (Vue 3 + PocketBase)
ressources.duneclassealautre.portailemfe.fr
→
Guides & tutoriels enseignants
3

Modèle de données

ℹ️

Toutes les tables PocketBase. Isolation multi-tenant via org_id. Règle : listRule: @request.auth.org_id = org_id

organizations

id, name, slug (unique), country, plan (free|pro), created

users (Auth PocketBase)

id, email (nullable), role (eleve|prof|responsable),
org_id, group_id, display_name, avatar

groups

id, project_id, org_id, name, level,
city, country,
join_code (4-8 car., personnalisable, unique par projet),
linked_group_id (nullable)

city + country affichés dans l'UI élève. join_code personnalisable (ex : "6EME2") + QR code.

projects

id, org_id, title, description,
mode (solo|collaborative), status (draft|active|archived),
template_id (nullable), created_by, created

cards

id, project_id, group_id, org_id,
title, instructions,
type (ressource|tache|production|feedback|debat|echange),
position, fields (JSON), unlock_type, unlock_config (JSON),
unlock_requires_card_id (nullable), locked_by_default
⚠️

Une card de type ressource peut avoir fields: [] — pas de formulaire, juste un bouton "Marquer comme lu".

card_drafts

id, card_id, group_id, org_id, content (JSON), updated_at

Brouillon côté serveur, sauvegardé toutes les 10 s. Supprimé à la soumission finale.

card_completions

id, card_id, group_id, org_id,
completed_at, validated_by_teacher (bool),
validated_at, validator_id, teacher_feedback,
submitted_by (texte libre, optionnel),
content (JSON)

templates

id, title, description, subject, level_a, level_b,
duration_weeks, tags (JSON), use_count,
published_by_org_id, is_public, cards_snapshot (JSON), created
4

Types de champs élève (v1)

TypeCléDescriptionOptions
Texte courttext1 ligneplaceholder, max_chars
Texte longtextareaParagraphemin_words, max_words
NombrenumberNumériquemin, max, unit
Photo caméraphotoOuvre la caméra directement (attribut capture)max_size
FichierfileSélecteur de fichiers (docs, images existantes)accept, max_size
AudioaudioEnregistrement micro (MediaRecorder API)max_duration_sec
Lien URLlinkURL validéeallowed_domains
Lien vidéovideo_linkYouTube / Drive / Vimeo—
Choix uniqueradioQCMoptions (array)
Cases à cocherchecklistMulti-sélectionitems (array)
ÉtoilesratingNote 1 à Nmax, labels
CurseursliderValeur entre min et maxmin, max, step

Prévus en v2 : dessin libre, annotation image, vidéo, texte à trous, carte, QR scan, vote de groupe.

5

Types de verrous

🔐

Sécurité : toute vérification se fait côté serveur via hook PocketBase. Les valeurs attendues ne transitent jamais vers le client JS.

auto
Toujours visible dès que la card précédente est complétée
—
teacher
Prof valide manuellement. 1ère card : affichée immédiatement.
—
group
L'autre groupe soumet sa card liée. Affiche "En attente de [Groupe B]..." avec indicateur temps réel.
unlock_requires_card_id
code
Élève saisit un code exact
value, hint (opt.)
enigme
Élève répond à une question libre
question, answer, hint, case_sensitive
quiz
Élève répond correctement à un QCM
question, options[], correct
6

Builder

🖥️

Desktop uniquement. Autosave debounce 1,5 s. Pas de undo/redo en v1.

Couleurs et icônes par type

📄
Ressource
Gris bleu · lecture seule possible
✅
Tâche
Vert · action à réaliser
✏️
Production
Orange · création originale
💬
Feedback
Violet · retour sur travail
⚡
Débat
Rouge · argumentation
🔄
Échange
Teal · inter-groupes

Canvas

Header : titre · toggle mode · autosave · "Aperçu élève" · "Publier"
Mode collaboratif : 2 lanes côte à côte, flèches SVG (teal A→B, violet B→A, pointillés)
Mode solo : 1 lane centrée

Join code + QR

Code personnalisable (ex: "6EME2", 4–8 caractères). Bouton "QR Code" → projeter ou imprimer, scan = connexion directe.

Aperçu élève

Panneau simulant la vue du groupe A ou B — cards verrouillées/déverrouillées selon config. Lecture seule.

7

Expérience élève

Connexion

Nom du groupe + code. N appareils simultanés sur le même groupe — chaque élève ouvre l'app sur son téléphone. Soumission partagée en temps réel via WebSocket.

Vue parcours

  • Header : nom du projet + groupe + ville/pays + progression X/N
  • Statuts : ✅ validé · ✏️ en cours · 🔒 verrouillé · 🎁 code · 🧩 énigme · ⏳ en attente

Remplir une card

  • Brouillon sauvegardé en card_drafts toutes les 10 s
  • Au moment de soumettre : champ optionnel "Qui envoie ?" → submitted_by

Comportement offline

À la reconnexion, Vue 3 recharge la liste via REST — les déblocages apparaissent naturellement. Aucune donnée perdue.

Fin de parcours

Écran de célébration (confetti, logo, "Bravo — parcours terminé !") quand toutes les cards sont validées. Le prof reçoit une notification Realtime.

8

Dashboard prof

Vue "classe vivante"

Bandeau temps réel : "Groupe A — 3 appareils connectés · dernière activité il y a 2 min". Basé sur PocketBase Realtime.

Actions disponibles

  • Lire toutes les productions (texte, fichiers, audio)
  • Valider / refuser + commentaire optionnel
  • Débloquer manuellement une card (override)
  • Message broadcast à un groupe
  • Voir le submitted_by de chaque soumission
  • Retour dans le builder
9

Multi-tenant

Isolation logique via org_id. Une seule URL app.duneclassealautre.portailemfe.fr.

Onboarding

  1. Prof s'inscrit → organisation créée automatiquement, il devient responsable
  2. Invite collègues via lien d'invitation (token, 7 jours) → rejoignent avec role: prof

Rôles

RôleCrée des projetsVoit tous les projets de l'orgGère les membres
eleve✗✗✗
prof✓✗✗
responsable✓✓ (lecture)✓
10

Intégration Ollama

🤖

Jamais d'appel direct depuis le client. Tout passe par hooks PocketBase → ollama.portailemfe.fr (mistral:7b, CPU-only, 5–15 s)

DéclencheurUsage
"Générer instructions" dans le builderRédiger les instructions d'une card depuis titre + type
Publication d'un templateSuggérer titre, description, tags
Validation d'une complétion texteGénérer un brouillon de feedback (toujours modifiable)

Gestion des erreurs

  • Timeout hook : 30 s max
  • Si indisponible : résultat vide + message "Génération indisponible — réessayez"
  • Le feedback IA n'est jamais affiché directement aux élèves
11

Hors scope v1

FonctionnalitéRaison du report
Auth individuelle élèveSession groupe suffisante en v1
Undo/redo builderAutosave suffit
Drag inter-lanes / flèches dragDropdown suffit
Enregistrement vidéoLien vidéo suffit
Dessin libre / annotation imagev2
Statistiques avancéesv2
Marketplace template ouverteModération admin d'abord
App mobile nativePWA suffisant pour v1
Export PDFv2
Intégration LMSv2
12

Architecture de déploiement

VPS IONOS (87.106.196.43)
└── Nginx
    ├── duneclassealautre.portailemfe.fr      → vitrine
    ├── app.duneclassealautre.portailemfe.fr  → Vue 3 + PocketBase :8090
    ├── ressources.duneclassealautre.portailemfe.fr → guides enseignants
    └── ollama.portailemfe.fr                 → (existant)

~/duneclasse/docker-compose.yml
  pocketbase:
    image: ghcr.io/muchobien/pocketbase:latest
    ports: ["127.0.0.1:8090:8090"]
    volumes: [/var/www/duneclasse_pb_data:/pb_data]

Sauvegarde : ~/backup_vps.sh (couvre SQLite via volume)
13

Décisions architecturales clés

DécisionChoix retenuAlternative écartée
Schéma dynamiqueJSON fields dans chaque cardTables SQL dynamiques par projet
RealtimePocketBase WebSocket natifPolling ou Socket.io séparé
Auth élèveN appareils / même groupe, localStorageComptes individuels (v2)
Vérification verrousHook PocketBase serveurVérification client JS
Templatescards_snapshot JSONClonage de rows DB
IAOllama hook serveur, timeout 30s + fallbackAPI payante
Scale v1PocketBase SQLite WALPostgreSQL (migration path v2)
BrouillonTable card_drafts côté serveurlocalStorage seul
Identité groupecity + country affichésGroupes anonymes
Join codePersonnalisable + QR codeCode fixe non modifiable
Fin de parcoursÉcran célébration confettiRetour silencieux
Couleurs typesIcône + couleur par typeTout identique