Architecture technique — Immbot AI
Pile retenue
| Couche | Choix | Justification |
|---|---|---|
| Framework | Next.js 15 (App Router) + React 19 + TypeScript strict | Full-stack unifié, streaming natif, RSC pour la vitesse |
| UI | Tailwind CSS v4 + composants maison de style shadcn/ui + animations CSS discrètes | Contrôle total de l'identité, thèmes clair/sombre/système |
| Rendu chat | react-markdown + remark-gfm + remark-math + rehype-katex | Markdown, tableaux, LaTeX |
| BD | SQLite via node:sqlite (natif Node 25, FTS5 vérifié avec remove_diacritics 2) |
Zéro dépendance native fragile, parfait pour un déploiement mono-nœud ; chemin PostgreSQL + pgvector documenté pour une montée en charge (docs/deployment.md) |
| Accès BD | Couche lib/db SQL typée (requêtes préparées) |
Simplicité, contrôle des index, FTS5 et blobs vecteurs sans friction ORM |
| Embeddings | Local : @huggingface/transformers, modèle Xenova/multilingual-e5-small (384 dims) |
OpenRouter n'offre pas d'endpoint d'embeddings ; local = gratuit, privé, hors-ligne, excellent en français |
| Recherche | Hybride : FTS5 (BM25) + cosinus vectoriel en mémoire + filtres de métadonnées + RRF | Corpus ~2-3k fragments → recherche en mémoire < 10 ms |
| LLM | OpenRouter (/api/v1/models + /api/v1/chat/completions, streaming SSE) |
Registre dynamique, multimodalité, coûts |
| Auth | Sessions serveur (cookie httpOnly + table sessions), bcryptjs, rate limiting | Voir security-model.md |
| Fichiers | Stockage local data/uploads/ (dev) ; interface compatible S3/MinIO documentée |
|
| Tests | Vitest (unitaires + intégration) |
Décisions documentées (hypothèses raisonnables adoptées) :
- SQLite plutôt que PostgreSQL en v1 : un seul professeur héberge la plateforme ;
node:sqliteen mode WAL supporte largement une cohorte de cours. Le schéma n'utilise rien d'exclusif à SQLite (migration Postgres documentée). pgvector devient utile au-delà de ~100k fragments — on en est loin. - Pas de Redis/file de tâches en v1 : l'ingestion (~30 documents LaTeX) prend quelques minutes et tourne comme script ou tâche serveur avec journal de progression en BD.
Structure du projet
immbot-ai/
├── app/ # Next.js App Router
│ ├── (public)/ # accueil, connexion, inscription
│ ├── (app)/ # chat, apprendre/*, bibliothèque, paramètres (auth requise)
│ ├── (admin)/admin/* # tableau de bord professeur
│ └── api/ # routes API (auth, chat SSE, rag, learning, admin, uploads)
├── components/ # UI (ui/ primitives, chat/, learning/, admin/)
├── lib/
│ ├── db/ # connexion node:sqlite, schéma, migrations, requêtes
│ ├── auth/ # sessions, mots de passe, permissions, rate-limit
│ ├── openrouter/ # registre de modèles, client streaming, coûts, presets
│ ├── rag/ # parseur LaTeX, chunker, embeddings, recherche hybride, citations
│ ├── learning/ # SM-2, maîtrise, quiz adaptatif, examens, plan d'étude, recommandations
│ ├── analytics/ # événements, agrégats anonymisés
│ └── security/ # validation, sanitisation
├── prompts/ # prompts système modulaires versionnés (fichiers .md)
├── scripts/ # setup, dev, build, seed-admin, ingest-courses, reindex, test, verify, backup
├── tests/ # vitest
├── evaluation/ # jeux de test RAG + rapport
├── docs/ # la présente documentation
├── data/ # immbot.db, uploads/, cache modèles (gitignoré)
└── public/ # logo SVG, actifsFlux principaux
Chat RAG (mode « Cours uniquement »)
- POST
/api/chat(auth + vérification d'accès au cours + budget). - Analyse de la question → détection du sujet ; embedding local de la requête.
- Recherche hybride dans l'espace du cours choisi : FTS5 (BM25) + cosinus, fusion RRF, filtres métadonnées, expansion aux fragments voisins, dédoublonnage → top-k équilibré.
- Construction du contexte : fragments numérotés
[S1]…[Sn]avec métadonnées (séance, diapositive) + prompt système assemblé (base + rag-grounding + citation-policy + cours + mode). - Appel OpenRouter en streaming, relayé au client en SSE ; le modèle cite
[S3]. - Post-validation : toute référence
[Sx]absente du contexte est neutralisée ; les citations valides sont résolues en objets cliquables (document, séance, diapositive, extrait). - Journalisation : jetons, coût, latence, fragments servis (pour l'évaluation RAG).
Ingestion
scripts/ingest-courses.ts (ou bouton admin) : scan des dossiers de cours → détection de type →
somme de contrôle (réingestion incrémentale) → parseur LaTeX (frames beamer numérotées en
diapositives, sections, boîtes sémantiques, équations, tableaux) → fragments structurés avec
métadonnées complètes → FTS5 + embeddings par lots → rapport (docs/ingestion-report.md + table
ingestion_runs).
Moteur de maîtrise
Chaque interaction évaluable (carte, question de quiz, item d'examen) émet un événement
(concept, correct, difficulté, autonomie, confiance) ; la maîtrise par concept est un score
composite à décroissance temporelle (voir learning-science-strategy.md), agrégé par thème et cours.
Performance
RSC par défaut, composants client uniquement où nécessaire (chat, cartes interactives) · embeddings et registre de modèles en cache mémoire avec TTL · requêtes préparées réutilisées · index SQL sur toutes les clés de recherche · streaming immédiat (TTFB < 1 s hors latence modèle).