# 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:sqlite` en 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, actifs ``` ## Flux principaux ### Chat RAG (mode « Cours uniquement ») 1. POST `/api/chat` (auth + vérification d'accès au cours + budget). 2. Analyse de la question → détection du sujet ; embedding local de la requête. 3. 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é. 4. 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). 5. Appel OpenRouter en streaming, relayé au client en SSE ; le modèle cite `[S3]`. 6. 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). 7. 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).