Cladèse documentation

Architecture

Une API hexagonale en Python, deux clients, et un worker qui partage le même code métier.

Vue d'ensemble#

Tout tient dans un docker compose. Les requêtes HTTP restent courtes ; le travail lourd part dans une file RabbitMQ et un worker dédié s'en charge, sans bloquer l'interface.

Navigateur Application mobile API FastAPI PostgreSQL Dossier médias RabbitMQ Qdrant Worker front Next.js Flutter catalogue · studio progression · notes stream avec Range questions à l'assistant catalogue, notes, jobs VIDEOS_HOST_PATH jobs publiés après commit vecteurs du contenu ffmpeg · Whisper LLM · embeddings prefetch réglable Le LLM est n'importe quel point d'accès compatible OpenAI : LM Studio ou Ollama en local, ou un fournisseur distant.

L'API interroge aussi Qdrant et le modèle de langage pour répondre aux questions de l'assistant ; le worker, lui, écrit transcriptions et résumés dans le dossier médias et les statuts en base.

L'API : ports et adaptateurs#

Le paquet e_learning est découpé en quatre couches. Les dépendances vont uniquement vers l'intérieur, et c'est vérifié : import-linter échoue si une couche importe une couche plus externe, ou si le domaine importe FastAPI, SQLAlchemy ou Pydantic.

presentation infrastructure application domain API FastAPI CLI Click worker RabbitMQ composition des dépendances SQLAlchemy async catalogue disque ffmpeg, Whisper LLM, Qdrant aio-pika, config cas d'usage DTO ports techniques (stockage, médias, résumé, messagerie) entités, value objects (UUIDv7) exceptions métier ports des repositories aucun framework

L'API, la CLI et le worker sont trois adaptateurs primaires sur les mêmes cas d'usage : lancer une transcription depuis le navigateur ou depuis la ligne de commande exécute le même code.

Bounded contexts#

ContexteContenu
userCompte : email normalisé, empreinte argon2 du mot de passe, is_admin, is_active ; UserId UUIDv7
catalogFormation, Chapter, Video, Document, Job ; position en base, slugs disque stables
learningNote et Progress, rattachées à un utilisateur et à une vidéo
contentTranscription, résumé, conversion, indexation et questions RAG
usageJournal des tokens consommés par les appels au modèle de langage, par utilisateur

Authentification#

Cycle de vie d'un job#

  1. La requête HTTP crée un Job en base (queued) et passe le statut métier de la vidéo à processing.
  2. Après le commit, le message est publié sur l'exchange elearning_jobs (type direct, durable). Publier avant le commit exposerait le worker à un job qui n'existe pas encore.
  3. L'API répond 202 avec la vidéo et ses active_jobs.
  4. Le worker consomme (APP_WORKER_PREFETCH en parallèle), passe le job en running et met à jour progress et message.
  5. À la fin : succeeded ou failed, et le statut métier (transcription_status, summary_status, processing_status) passe à ready ou failed.
  6. Transcription et résumé réussis enchaînent un job rag_index_video.

Les clients n'ont pas de canal temps réel : ils interrogent la formation toutes les 3 secondes tant qu'un statut vaut processing. Les jobs terminés disparaissent de active_jobs ; les colonnes de statut restent la vérité métier.

Type de jobDéclenché par
media_conversionTéléversement d'un fichier autre que MP4 / MP3, ou POST /videos/{id}/conversion
transcriptionPOST /videos/{id}/transcription
summaryPOST /videos/{id}/summary/generate
rag_index_videoFin d'une transcription ou d'un résumé
rag_index_formationPOST /formations/{id}/index (bouton Réindexer)

Disque et base#

Le front#

RoutePage
/authConnexion ; seule page publique
/Catalogue
/formation/[formationId]Détail, assistant, chapitres
/player/[videoId]Lecteur, résumé, notes, documents
/studioListe des formations à éditer
/studio/formation/newCréation
/studio/formation/[id]Éditeur de formation
/studio/usersGestion des comptes
/usageConsommation IA du compte

Next.js 16 en App Router, mais toutes les pages sont des composants client : pas de rendu serveur en pratique. L'état vit dans des stores Zustand (auth, catalog, studio, player, theme) ; les appels passent par un client Axios unique (src/services/api.ts) qui envoie le cookie de session (withCredentials) et l'en-tête anti-CSRF X-Requested-With. SessionGate, dans le layout racine, redirige vers /auth sans session ; app/studio/layout.tsx renvoie un apprenant au catalogue. Un 401 efface la session, un 403 affiche « accès refusé » sans déconnecter. L'interface est entièrement en MUI 9 ; le lecteur vidéo est video.js et l'éditeur Markdown @uiw/react-md-editor. Le build Docker produit une sortie standalone, exécutée par un utilisateur non root.