feat: Infrastructure multi-tenant avec isolation par sous-domaine

Une application SaaS éducative nécessite une séparation stricte des données
entre établissements scolaires. L'architecture multi-tenant par sous-domaine
(ecole-alpha.classeo.local) permet cette isolation tout en utilisant une
base de code unique.

Le choix d'une résolution basée sur les sous-domaines plutôt que sur des
headers ou tokens facilite le routage au niveau infrastructure (reverse proxy)
et offre une UX plus naturelle où chaque école accède à "son" URL dédiée.
This commit is contained in:
2026-01-30 23:34:10 +01:00
parent 6da5996340
commit 1fd256346a
71 changed files with 14390 additions and 37 deletions

94
scripts/check-tenants.sh Executable file
View File

@@ -0,0 +1,94 @@
#!/bin/bash
# =============================================================================
# Vérifie que les tenants de dev répondent correctement
# Usage: ./scripts/check-tenants.sh
# =============================================================================
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
TENANTS=("ecole-alpha" "ecole-beta")
BASE_DOMAIN="classeo.local"
API_PORT="18000"
FRONTEND_PORT="5174"
echo "🔍 Vérification des tenants de développement..."
echo ""
# Vérifier /etc/hosts
echo "📋 Vérification de /etc/hosts..."
MISSING_HOSTS=()
for tenant in "${TENANTS[@]}"; do
if ! grep -q "${tenant}.${BASE_DOMAIN}" /etc/hosts 2>/dev/null; then
MISSING_HOSTS+=("${tenant}.${BASE_DOMAIN}")
fi
done
if [ ${#MISSING_HOSTS[@]} -ne 0 ]; then
echo -e "${YELLOW}⚠️ Entrées manquantes dans /etc/hosts:${NC}"
echo ""
echo " Ajoutez cette ligne à /etc/hosts :"
echo -e "${YELLOW} 127.0.0.1 classeo.local ${MISSING_HOSTS[*]}${NC}"
echo ""
echo " Commande :"
echo " sudo sh -c 'echo \"127.0.0.1 classeo.local ${MISSING_HOSTS[*]}\" >> /etc/hosts'"
echo ""
exit 1
fi
echo -e "${GREEN}✓ /etc/hosts configuré correctement${NC}"
echo ""
# Vérifier que les containers tournent
echo "🐳 Vérification des containers..."
if ! docker compose ps --status running | grep -q "classeo_php"; then
echo -e "${RED}✗ Container PHP non démarré. Lancez 'make up'${NC}"
exit 1
fi
if ! docker compose ps --status running | grep -q "classeo_frontend"; then
echo -e "${RED}✗ Container Frontend non démarré. Lancez 'make up'${NC}"
exit 1
fi
echo -e "${GREEN}✓ Containers démarrés${NC}"
echo ""
# Vérifier les endpoints
echo "🌐 Vérification des endpoints..."
ERRORS=0
for tenant in "${TENANTS[@]}"; do
# API
API_URL="http://${tenant}.${BASE_DOMAIN}:${API_PORT}/api/docs"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$API_URL" 2>/dev/null || echo "000")
if [ "$HTTP_CODE" = "200" ]; then
echo -e "${GREEN}✓ API ${tenant}: ${API_URL}${NC}"
else
echo -e "${RED}✗ API ${tenant}: ${API_URL} (HTTP ${HTTP_CODE})${NC}"
ERRORS=$((ERRORS + 1))
fi
# Frontend
FRONTEND_URL="http://${tenant}.${BASE_DOMAIN}:${FRONTEND_PORT}/"
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$FRONTEND_URL" 2>/dev/null || echo "000")
if [ "$HTTP_CODE" = "200" ]; then
echo -e "${GREEN}✓ Front ${tenant}: ${FRONTEND_URL}${NC}"
else
echo -e "${RED}✗ Front ${tenant}: ${FRONTEND_URL} (HTTP ${HTTP_CODE})${NC}"
ERRORS=$((ERRORS + 1))
fi
done
echo ""
if [ $ERRORS -ne 0 ]; then
echo -e "${RED}${ERRORS} erreur(s) détectée(s)${NC}"
exit 1
fi
echo -e "${GREEN}✅ Tous les tenants répondent correctement !${NC}"