diff --git a/.env.docker b/.env.docker index 3104229..ccd2af1 100644 --- a/.env.docker +++ b/.env.docker @@ -1,17 +1,26 @@ -# Configuration pour Docker - COPIEZ CE FICHIER EN .env ET MODIFIEZ -# IMPORTANT: Générez une clé SECRET_KEY unique et sécurisée ! +# Configuration Docker pour Notytex v2 +# COPIEZ CE FICHIER EN .env ET MODIFIEZ LES VALEURS -# Clé secrète Flask (OBLIGATOIRE - minimum 32 caractères) -# Générez une nouvelle clé avec: python -c "import secrets; print(secrets.token_hex(32))" -SECRET_KEY=CHANGEZ-MOI-cle-secrete-unique-minimum-32-caracteres-obligatoire-docker +# ⚠️ IMPORTANT: Générez une clé SECRET_KEY unique et sécurisée ! +# Commande: python -c "import secrets; print(secrets.token_hex(32))" +SECRET_KEY=CHANGEZ-MOI-cle-secrete-unique-minimum-32-caracteres-obligatoire -# Base de données (stockée dans le volume ./instance) -DATABASE_URL=sqlite:///instance/school_management.db +# Base de données (stockée dans le volume ./data) +DATABASE_URL=sqlite+aiosqlite:////data/school_management.db -# Configuration production -FLASK_ENV=production -DEBUG=false +# CORS - Ajustez selon vos domaines +CORS_ORIGINS=["http://localhost","http://localhost:80","https://votre-domaine.com"] + +# Logging LOG_LEVEL=INFO -# Configuration optionnelle -WTF_CSRF_TIME_LIMIT=3600 \ No newline at end of file +# Email (optionnel - pour l'envoi de bilans) +# SMTP_HOST=smtp.gmail.com +# SMTP_PORT=587 +# SMTP_USERNAME=votre-email@gmail.com +# SMTP_PASSWORD=votre-mot-de-passe-app +# EMAIL_FROM=votre-email@gmail.com +# SMTP_USE_TLS=true + +# Configuration production +DEBUG=false diff --git a/.gitignore b/.gitignore index c85d6c3..aa94ba9 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,10 @@ logs/ .coverage htmlcov/ +# Docker data +data/ +!data/.gitkeep + # Flask legacy instance/ .webassets-cache \ No newline at end of file diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..755ee3b --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,423 @@ +# 🐳 Déploiement Docker - Notytex v2 + +Guide complet pour déployer Notytex avec Docker et Docker Compose. + +--- + +## 🚀 Démarrage Rapide + +### Prérequis + +- Docker 20.10+ +- Docker Compose 2.0+ + +### Installation en 3 commandes + +```bash +# 1. Configurer l'environnement +cp .env.docker .env +# Éditez .env et changez SECRET_KEY ! + +# 2. Créer le répertoire de données +mkdir -p data +cp school_management.db data/ + +# 3. Démarrer les services +docker-compose up -d +``` + +**Accès :** +- Frontend : http://localhost +- API : http://localhost:8000 +- Documentation API : http://localhost:8000/api/v2/docs + +--- + +## 📂 Architecture Docker + +``` +┌─────────────────────────────────────────────────┐ +│ Nginx:80 │ +│ (Frontend Vue.js) │ +└────────────────┬────────────────────────────────┘ + │ + │ Proxy /api → backend:8000 + │ +┌────────────────▼────────────────────────────────┐ +│ FastAPI:8000 │ +│ (Backend Python) │ +└────────────────┬────────────────────────────────┘ + │ + │ SQLite + │ +┌────────────────▼────────────────────────────────┐ +│ Volume: ./data │ +│ (Base de données SQLite) │ +└─────────────────────────────────────────────────┘ +``` + +--- + +## 🔧 Configuration + +### Variables d'Environnement + +Éditez le fichier `.env` : + +```bash +# Clé secrète (OBLIGATOIRE - générez-en une nouvelle !) +SECRET_KEY=votre-cle-secrete-unique-min-32-chars + +# Base de données +DATABASE_URL=sqlite+aiosqlite:////data/school_management.db + +# CORS (ajoutez vos domaines) +CORS_ORIGINS=["http://localhost","https://votre-domaine.com"] + +# Email (optionnel) +SMTP_HOST=smtp.gmail.com +SMTP_PORT=587 +SMTP_USERNAME=votre-email@gmail.com +SMTP_PASSWORD=votre-mot-de-passe-app +EMAIL_FROM=votre-email@gmail.com +``` + +### Générer une SECRET_KEY + +```bash +python -c "import secrets; print(secrets.token_hex(32))" +``` + +--- + +## 🛠️ Commandes Docker + +### Démarrage + +```bash +# Démarrer en arrière-plan +docker-compose up -d + +# Voir les logs +docker-compose logs -f + +# Logs d'un service spécifique +docker-compose logs -f backend +docker-compose logs -f frontend +``` + +### Arrêt + +```bash +# Arrêter les services +docker-compose stop + +# Arrêter et supprimer les conteneurs +docker-compose down + +# Arrêter et supprimer tout (conteneurs + volumes) +docker-compose down -v +``` + +### Rebuild + +```bash +# Rebuild après modification du code +docker-compose build + +# Rebuild et redémarrage +docker-compose up -d --build + +# Rebuild un service spécifique +docker-compose build backend +docker-compose up -d backend +``` + +### Inspection + +```bash +# Statut des services +docker-compose ps + +# Santé des services +docker-compose ps -a + +# Entrer dans un conteneur +docker-compose exec backend sh +docker-compose exec frontend sh +``` + +--- + +## 🗄️ Gestion de la Base de Données + +### Backup + +```bash +# Créer un backup +docker-compose exec backend sh -c "cp /data/school_management.db /data/backup_$(date +%Y%m%d_%H%M%S).db" + +# Ou depuis l'hôte +cp data/school_management.db data/backup_$(date +%Y%m%d_%H%M%S).db +``` + +### Restauration + +```bash +# Restaurer depuis un backup +docker-compose stop backend +cp data/backup_YYYYMMDD_HHMMSS.db data/school_management.db +docker-compose start backend +``` + +### Migration depuis v1 + +```bash +# Si vous avez une base v1 Flask +cp instance/school_management.db data/school_management.db +docker-compose restart backend +``` + +--- + +## 🔍 Healthcheck + +Les services incluent des healthchecks automatiques : + +```bash +# Vérifier la santé du backend +curl http://localhost:8000/api/v2/health + +# Vérifier la santé du frontend +curl http://localhost/ + +# Voir le statut Docker +docker-compose ps +``` + +**Réponse attendue du backend :** +```json +{ + "status": "healthy", + "database": "connected", + "tables": 12, + "classes": 5, + "students": 155 +} +``` + +--- + +## 🚨 Dépannage + +### Le backend ne démarre pas + +```bash +# Voir les logs +docker-compose logs backend + +# Vérifier la configuration +docker-compose exec backend env | grep DATABASE_URL + +# Recréer le conteneur +docker-compose up -d --force-recreate backend +``` + +### Le frontend ne charge pas + +```bash +# Vérifier Nginx +docker-compose logs frontend + +# Tester la connectivité au backend +docker-compose exec frontend curl http://backend:8000/api/v2/health + +# Rebuild le frontend +docker-compose build frontend +docker-compose up -d frontend +``` + +### Problème de permissions (base de données) + +```bash +# Ajuster les permissions +chmod 666 data/school_management.db +chmod 755 data/ +``` + +### Les changements de code ne sont pas pris en compte + +```bash +# Rebuild complet +docker-compose down +docker-compose build --no-cache +docker-compose up -d +``` + +--- + +## 🌐 Déploiement Production + +### Configuration Nginx (hôte) + +Si vous utilisez Nginx sur l'hôte pour le reverse proxy : + +```nginx +server { + listen 80; + server_name notytex.example.com; + + location / { + proxy_pass http://localhost:80; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +### HTTPS avec Let's Encrypt + +```bash +# Installer certbot +sudo apt install certbot python3-certbot-nginx + +# Obtenir un certificat +sudo certbot --nginx -d notytex.example.com + +# Renouvellement automatique est configuré +``` + +### Systemd Service + +Créez `/etc/systemd/system/notytex.service` : + +```ini +[Unit] +Description=Notytex Docker Compose +Requires=docker.service +After=docker.service + +[Service] +Type=oneshot +RemainAfterExit=yes +WorkingDirectory=/path/to/notytex +ExecStart=/usr/bin/docker-compose up -d +ExecStop=/usr/bin/docker-compose down + +[Install] +WantedBy=multi-user.target +``` + +Activer : +```bash +sudo systemctl enable notytex +sudo systemctl start notytex +``` + +--- + +## 📊 Monitoring + +### Logs centralisés + +```bash +# Tous les logs en temps réel +docker-compose logs -f + +# Logs des dernières 24h +docker-compose logs --since 24h + +# Recherche dans les logs +docker-compose logs | grep ERROR +``` + +### Métriques Docker + +```bash +# Utilisation ressources +docker stats + +# Espace disque +docker system df + +# Nettoyage +docker system prune -a +``` + +--- + +## 🔐 Sécurité + +### Checklist Production + +- [ ] Changer `SECRET_KEY` (unique et aléatoire) +- [ ] Configurer CORS avec vos domaines réels +- [ ] Utiliser HTTPS en production +- [ ] Limiter les ports exposés (firewall) +- [ ] Mettre en place des backups automatiques +- [ ] Configurer des alertes monitoring +- [ ] Restreindre les permissions fichiers +- [ ] Mettre à jour régulièrement les images Docker + +### Mise à jour des images de base + +```bash +# Pull les dernières images +docker-compose pull + +# Rebuild avec nouvelles images +docker-compose up -d --build +``` + +--- + +## 📦 Multi-environnements + +### Développement + +```bash +# Utiliser docker-compose.dev.yml +docker-compose -f docker-compose.yml -f docker-compose.dev.yml up +``` + +### Production + +```bash +# Utiliser docker-compose.prod.yml +docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d +``` + +--- + +## 🎯 Performances + +### Optimisations + +1. **Build multi-stage** : Réduit la taille des images +2. **Cache des dépendances** : Accélère les rebuilds +3. **Gzip Nginx** : Compression des assets +4. **Cache statique** : Headers cache 1 an pour JS/CSS +5. **Healthchecks** : Détection automatique des problèmes + +### Ressources recommandées + +- **Backend** : 512MB RAM, 0.5 CPU +- **Frontend** : 256MB RAM, 0.25 CPU +- **Total** : ~1GB RAM, 1 CPU pour 50 utilisateurs + +--- + +## 📞 Support + +En cas de problème : + +1. Vérifiez les logs : `docker-compose logs` +2. Testez les healthchecks +3. Consultez la documentation : `README.md` +4. Vérifiez les issues GitHub + +--- + +**Développé avec ❤️ pour simplifier le déploiement de Notytex** diff --git a/README.md b/README.md index 63d0e17..27f1cb2 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,21 @@ npm run dev - **Documentation API** : http://localhost:8000/api/v2/docs - **ReDoc** : http://localhost:8000/api/v2/redoc +### **Déploiement avec Docker** 🐳 + +```bash +# Configuration +cp .env.docker .env +# Éditez .env et changez SECRET_KEY + +# Démarrage +docker-compose up -d + +# Accès: http://localhost +``` + +📖 **Documentation complète** : [`DOCKER.md`](DOCKER.md) + --- ## 🏗️ **Architecture Technique** diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..726ea92 --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,34 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python + +# Virtual environments +.venv/ +venv/ +env/ +ENV/ + +# Tests +.pytest_cache/ +.coverage +htmlcov/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# Environment +.env +.env.local + +# Documentation +docs/ + +# Git +.git/ +.gitignore diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..f129979 --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,29 @@ +# Dockerfile pour Backend FastAPI +FROM python:3.11-slim + +# Variables d'environnement +ENV PYTHONUNBUFFERED=1 \ + PYTHONDONTWRITEBYTECODE=1 \ + PIP_NO_CACHE_DIR=1 \ + PIP_DISABLE_PIP_VERSION_CHECK=1 + +# Installer uv +RUN pip install uv + +# Créer répertoire de travail +WORKDIR /app + +# Copier les fichiers de dépendances +COPY pyproject.toml uv.lock ./ + +# Installer les dépendances +RUN uv sync --frozen + +# Copier le code source +COPY . . + +# Exposer le port +EXPOSE 8000 + +# Commande de démarrage +CMD ["uv", "run", "python", "-m", "uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..985c2f8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,55 @@ +version: '3.8' + +services: + # Backend FastAPI + backend: + build: + context: ./backend + dockerfile: Dockerfile + container_name: notytex-backend + restart: unless-stopped + ports: + - "8000:8000" + environment: + - DATABASE_URL=sqlite+aiosqlite:////data/school_management.db + - SECRET_KEY=${SECRET_KEY:-change-me-in-production-min-32-chars} + - CORS_ORIGINS=["http://localhost","http://localhost:80","http://localhost:3000"] + - LOG_LEVEL=INFO + volumes: + - ./data:/data + - ./backend:/app + networks: + - notytex-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000/api/v2/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # Frontend Vue.js + Nginx + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + container_name: notytex-frontend + restart: unless-stopped + ports: + - "80:80" + depends_on: + - backend + networks: + - notytex-network + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost/"] + interval: 30s + timeout: 10s + retries: 3 + +networks: + notytex-network: + driver: bridge + +volumes: + data: + driver: local diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..21229a4 --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,29 @@ +# Node +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Build +dist/ +.vite/ + +# Environment +.env.local +.env.*.local + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# Tests +coverage/ + +# Git +.git/ +.gitignore + +# Logs +*.log diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..7f1e7b9 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,32 @@ +# Dockerfile pour Frontend Vue.js +# Stage 1: Build +FROM node:18-alpine AS builder + +WORKDIR /app + +# Copier package.json et package-lock.json +COPY package*.json ./ + +# Installer les dépendances +RUN npm ci + +# Copier le code source +COPY . . + +# Build de production +RUN npm run build + +# Stage 2: Production avec Nginx +FROM nginx:alpine + +# Copier le build depuis le stage précédent +COPY --from=builder /app/dist /usr/share/nginx/html + +# Copier la configuration Nginx +COPY nginx.conf /etc/nginx/conf.d/default.conf + +# Exposer le port +EXPOSE 80 + +# Commande de démarrage +CMD ["nginx", "-g", "daemon off;"] diff --git a/frontend/nginx.conf b/frontend/nginx.conf new file mode 100644 index 0000000..bf1d412 --- /dev/null +++ b/frontend/nginx.conf @@ -0,0 +1,41 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + + # Gzip compression + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/json application/javascript; + + # SPA routing - toutes les routes vers index.html + location / { + try_files $uri $uri/ /index.html; + } + + # Proxy API vers le backend + location /api/ { + proxy_pass http://backend:8000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + } + + # Cache pour les assets statiques + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Sécurité + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; +}