Installation
La pile complète tient dans un docker compose. Comptez quelques minutes, plus le premier téléchargement des modèles.
Prérequis#
- Docker et Docker Compose.
- Git avec Git LFS : images, vidéo de démonstration et polices sont stockées ainsi.
- Un accès Internet au premier démarrage : images Docker, et modèle d'embeddings téléchargé depuis Hugging Face (mis en cache ensuite).
- Hors Docker uniquement : Node 22+, Python 3.14+, uv et ffmpeg.
Aucun modèle de langage n'est requis pour démarrer. Catalogue, lecteur, progression, notes, documents et studio fonctionnent sans. Un point d'accès compatible OpenAI (LM Studio, Ollama, vLLM, ou un fournisseur distant) active ensuite résumés et assistant ; voir Brancher un modèle.
Ressources#
Ordres de grandeur mesurés sur une instance Docker avec le modèle d'embeddings par défaut, sans LLM local :
| Poste | Mesure | À savoir |
|---|---|---|
| Mémoire au repos | ≈ 2,3 Go | API et worker chargent chacun le modèle d'embeddings (≈ 1,1 Go) ; les autres services restent sous 50 Mo |
| Mémoire en transcription | + ≈ 1 Go par job | Modèle Whisper base ; davantage pour small ou medium. Limitez APP_WORKER_PREFETCH sur une petite machine |
| Image de l'API | ≈ 7 Go | PyTorch, Whisper, sentence-transformers ; partagée par api, worker et migrate |
| Autres images | ≈ 900 Mo | Front, PostgreSQL, RabbitMQ, Qdrant |
| GPU | non requis | Tout fonctionne sur processeur ; la transcription est simplement plus lente |
Une machine avec 8 Go de mémoire fait tourner la pile et une transcription à la fois. Un LLM local (LM Studio, Ollama) s'ajoute à ce budget, souvent de plusieurs Go selon le modèle.
Avec Docker Compose#
git lfs install # une fois par machine, avant le clone
git clone https://github.com/EdwinAlkins/e-learning.git
cd e-learning
cp .env.template .envgit lfs install (paquet git-lfs) avant le clone, vous
récupérez des fichiers pointeurs de quelques centaines d'octets à la place des images :
les icônes du front manquent et le build échoue. Sur un dépôt déjà cloné,
git lfs install && git lfs pull répare.
Dans .env, les valeurs à regarder en premier :
| Variable | Pourquoi |
|---|---|
APP_SECRET_KEY | Clé de signature des sessions, au moins 32 caractères : openssl rand -hex 32. Obligatoire : l'API refuse de démarrer avec changethis. |
APP_FIRST_ADMIN_EMAIL / APP_FIRST_ADMIN_PASSWORD | Premier compte administrateur, créé au premier démarrage. Obligatoire de changer le mot de passe d'exemple. |
VIDEOS_HOST_PATH | Dossier hôte des formations, monté sur /app/videos dans l'API et le worker. |
APP_OPENAI_BASE_URL | Modèle de langage pour les résumés et l'assistant. host.docker.internal désigne la machine hôte. |
NEXT_PUBLIC_API_URL | URL de l'API vue par le navigateur. Intégrée au build du front. |
docker compose up -d --build # à la racine du dépôt
docker compose pse-learning-api/ contient son propre docker-compose.yml,
réservé au développement de l'API : il ne démarre ni le front ni Qdrant.
Au démarrage, le service migrate applique les migrations Alembic
puis s'arrête ; l'API et le worker attendent qu'il ait réussi.
| Service | Rôle | Port |
|---|---|---|
front | Interface web | 3000 |
api | API REST et stream des médias | 8000 |
worker | Consomme les jobs : conversion, transcription, résumé, indexation | — |
migrate | Migrations, une fois | — |
postgres | Base de données | 5432 |
rabbitmq | File des jobs, console de gestion | 5672, 15672 |
qdrant | Base vectorielle de l'assistant | 6333 |
Ouvrez http://localhost:3000 et connectez-vous
avec APP_FIRST_ADMIN_EMAIL et APP_FIRST_ADMIN_PASSWORD.
Studio permet ensuite de créer une première formation, et
Studio → Comptes d'ouvrir des accès aux apprenants.
Si l'API redémarre en boucle, docker compose logs api indique la variable
à corriger : clé ou mot de passe d'exemple, ou "*" dans
APP_CORS_ORIGINS.
NEXT_PUBLIC_API_URL est figée au build
Next.js remplace la valeur dans le JavaScript livré au navigateur. Après l'avoir
changée : docker compose build front && docker compose up -d front.
Importer des vidéos existantes#
Rangez les médias sous VIDEOS_HOST_PATH en
Formation/Chapitre/fichier (détails dans
Studio et catalogue), puis réconciliez :
docker compose exec api e-learning-cli reconcile
docker compose exec api e-learning-cli list-videosOu, pour que la réconciliation tourne à chaque démarrage de l'API :
APP_RECONCILE_ON_STARTUP=true.
Hors Docker#
Utile pour développer. Les services d'infrastructure restent dans Docker :
docker compose up -d postgres rabbitmq qdrant
# API
cd e-learning-api
cp .env.template .env # URLs en localhost ; APP_DEBUG=true pour le dev
uv sync --group ai --group dev
uv run alembic upgrade head
uv run e-learning-api # http://localhost:8000
# Worker, dans un second terminal
uv run e-learning-worker
# Front, dans un troisième
cd ../e-learning-front
cp .env.template .env.local
npm ci
npm run dev # http://localhost:3000Avec APP_DEBUG=true, l'API accepte les secrets d'exemple (avec un
avertissement) et sert la documentation OpenAPI sur
/api-docs. Le compte admin
d'exemple est alors admin@example.com / changethis.
Exposer l'instance#
Chaque page et chaque route de l'API exigent une connexion, et le studio est réservé aux administrateurs. Avant une exposition sur Internet, trois points restent à régler.
- HTTPS obligatoire. Le cookie de session est marqué
Securedès que l'API n'est pas servie surlocalhost: en HTTP, le navigateur le refuse et la connexion web échoue. Les mots de passe transitent aussi dans la requête. - Secrets.
APP_SECRET_KEYd'au moins 32 caractères, mot de passe admin changé,APP_DEBUG=false. - Ports d'infrastructure. Le compose publie aussi PostgreSQL,
RabbitMQ (identifiants
guestpar défaut) et Qdrant sur toutes les interfaces. Retirez ces ports ou liez-les à la boucle locale, par exemple dans undocker-compose.override.yml(Compose 2.24+ pour!override) :
services:
postgres:
ports: !override
- "127.0.0.1:${POSTGRES_PORT}:5432"Un schéma simple : un seul domaine, le front à la racine et l'API sous
/api. Front et API restent ainsi sur le même site, ce qu'exige le cookie de
session. Exemple avec Caddy, qui obtient le certificat HTTPS tout seul :
learn.example.com {
handle_path /api/* {
reverse_proxy 127.0.0.1:8000
}
handle {
reverse_proxy 127.0.0.1:3000
}
}Et dans .env, avant de reconstruire le front :
NEXT_PUBLIC_API_URL=https://learn.example.com/api
APP_CORS_ORIGINS=["https://learn.example.com"]
APP_DEBUG=falseAjouter une protection en amont#
Les comptes intégrés suffisent pour la plupart des usages. Une couche en amont réduit encore la surface exposée :
| Option | Navigateur | Application mobile | Pour qui |
|---|---|---|---|
| Comptes intégrés seuls, en HTTPS | Oui | Oui | Le cas général |
| VPN : Tailscale, WireGuard | Oui | Oui | Rien n'est exposé publiquement |
| Proxy SSO devant l'instance : Authelia, Authentik, oauth2-proxy, Cloudflare Access | Oui | Non | Filtrer l'accès par des comptes existants ; la connexion Cladèse reste nécessaire ensuite |
L'application mobile appelle l'API directement et ne sait pas passer une page de connexion tierce : avec un proxy SSO, elle ne fonctionne qu'à travers un VPN. Cladèse ne se connecte pas lui-même à un fournisseur d'identité (SSO, OIDC).
Mettre à jour#
./scripts/backup.sh # d'abord
git pull
docker compose up -d --build # migrate applique les nouvelles migrationsDepuis une version sans comptes, lisez d'abord l'avertissement sur la migration 007 : elle supprime les progressions et notes des anciens identifiants anonymes.
Vérifier l'état : GET /health répond si le processus tourne,
GET /ready vérifie aussi la connexion à PostgreSQL.
Cladèse