diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f3867de --- /dev/null +++ b/.dockerignore @@ -0,0 +1,66 @@ +# Fichiers et répertoires à ignorer lors de la construction Docker + +# Dépendances +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Fichiers de développement +.env +.env.local +.env.development +.env.test + +# Fichiers de cache +.cache/ +.parcel-cache/ +.vite/ + +# Fichiers de construction +dist/ +build/ + +# Fichiers de logs +logs/ +*.log + +# Fichiers temporaires +tmp/ +temp/ + +# Fichiers de système +.DS_Store +Thumbs.db + +# Fichiers d'éditeur +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Fichiers de test +coverage/ +.nyc_output/ + +# Fichiers de sauvegarde +backups/ +*.backup + +# Fichiers Git +.git/ +.gitignore + +# Fichiers Docker +Dockerfile +.dockerignore +docker-compose*.yml + +# Fichiers de documentation +README.md +docs/ + +# Fichiers de configuration locale +.replit +replit.nix \ No newline at end of file diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..73d870f --- /dev/null +++ b/.env.example @@ -0,0 +1,20 @@ +# Configuration de l'environnement pour RegisFlow +# Copiez ce fichier en .env et modifiez les valeurs selon vos besoins + +# Configuration de la base de données +DATABASE_URL=postgresql://regisflow:regisflow2024@localhost:5432/regisflow +POSTGRES_PASSWORD=regisflow2024 + +# Configuration de l'application +NODE_ENV=production +PORT=5000 + +# Clé secrète pour les sessions (IMPORTANT: Changez cette valeur en production) +SESSION_SECRET=your-super-secret-session-key-change-in-production + +# Configuration du timezone +TZ=Europe/Paris + +# Configuration optionnelle pour les sauvegardes +BACKUP_RETENTION_DAYS=30 +MAX_BACKUP_COUNT=10 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ed8e2e8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,68 @@ +# Dockerfile multi-stage pour RegisFlow +FROM node:18-alpine AS builder + +# Installer les dépendances système nécessaires +RUN apk add --no-cache python3 make g++ + +# Créer le répertoire de l'application +WORKDIR /app + +# Copier les fichiers de dépendances +COPY package*.json ./ + +# Installer toutes les dépendances (dev + prod pour la build) +RUN npm ci + +# Copier le code source +COPY . . + +# Construire l'application +RUN npm run build + +# Stage de production +FROM node:18-alpine AS production + +# Installer les dépendances système pour la production +RUN apk add --no-cache dumb-init postgresql-client + +# Créer un utilisateur non-root +RUN addgroup -g 1001 -S nodejs +RUN adduser -S regisflow -u 1001 + +# Créer le répertoire de l'application +WORKDIR /app + +# Copier les fichiers de dépendances +COPY package*.json ./ + +# Installer seulement les dépendances de production +RUN npm ci --only=production && npm cache clean --force + +# Copier les fichiers construits depuis le stage builder +COPY --from=builder --chown=regisflow:nodejs /app/dist ./dist +COPY --from=builder --chown=regisflow:nodejs /app/server ./server +COPY --from=builder --chown=regisflow:nodejs /app/shared ./shared +COPY --from=builder --chown=regisflow:nodejs /app/drizzle.config.ts ./drizzle.config.ts + +# Copier le script d'entrée +COPY --chown=regisflow:nodejs docker-entrypoint.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/docker-entrypoint.sh + +# Créer les répertoires nécessaires +RUN mkdir -p /app/backups && chown regisflow:nodejs /app/backups + +# Changer vers l'utilisateur non-root +USER regisflow + +# Exposer le port +EXPOSE 5000 + +# Variables d'environnement par défaut +ENV NODE_ENV=production +ENV PORT=5000 + +# Utiliser dumb-init pour gérer les signaux +ENTRYPOINT ["dumb-init", "--"] + +# Démarrer l'application avec le script d'entrée +CMD ["docker-entrypoint.sh", "node", "dist/index.js"] \ No newline at end of file diff --git a/README_DOCKER.md b/README_DOCKER.md new file mode 100644 index 0000000..879a831 --- /dev/null +++ b/README_DOCKER.md @@ -0,0 +1,286 @@ +# RegisFlow - Déploiement Docker + +Ce guide vous explique comment déployer RegisFlow avec Docker et Docker Compose. + +## 🐳 Prérequis + +- Docker Engine 20.10 ou supérieur +- Docker Compose 2.0 ou supérieur +- Au minimum 1 GB de RAM libre +- Au minimum 2 GB d'espace disque libre + +## 🚀 Démarrage Rapide + +### 1. Préparer l'environnement + +```bash +# Cloner le projet +git clone +cd regisflow + +# Copier et configurer le fichier d'environnement +cp .env.example .env + +# Éditer le fichier .env avec vos paramètres +nano .env +``` + +### 2. Configurer les variables d'environnement + +Éditez le fichier `.env` : + +```env +# Configuration de la base de données +DATABASE_URL=postgresql://regisflow:votre_mot_de_passe@postgres:5432/regisflow +POSTGRES_PASSWORD=votre_mot_de_passe_securise + +# Configuration de l'application +NODE_ENV=production +PORT=5000 + +# Clé secrète pour les sessions (OBLIGATOIRE EN PRODUCTION) +SESSION_SECRET=votre-cle-secrete-super-longue-et-complexe + +# Configuration du timezone +TZ=Europe/Paris +``` + +### 3. Lancer l'application + +```bash +# Construire et démarrer tous les services +docker-compose up -d + +# Vérifier les logs +docker-compose logs -f + +# Accéder à l'application +# http://localhost (avec nginx) +# ou http://localhost:5000 (accès direct) +``` + +## 📋 Services Inclus + +### 1. PostgreSQL (Base de données) +- **Port**: 5432 +- **Database**: regisflow +- **Utilisateur**: regisflow +- **Données persistantes**: Volume `postgres_data` + +### 2. RegisFlow (Application) +- **Port**: 5000 +- **Dépendances**: PostgreSQL +- **Sauvegardes**: Volume `backup_data` +- **Health check**: `/health` + +### 3. Nginx (Reverse Proxy) +- **Port**: 80 (HTTP) +- **Port**: 443 (HTTPS - à configurer) +- **Compression**: Gzip activée +- **Cache**: Optimisé pour les assets statiques + +## 🔧 Commandes Utiles + +### Gestion des services + +```bash +# Démarrer les services +docker-compose up -d + +# Arrêter les services +docker-compose down + +# Redémarrer un service +docker-compose restart regisflow + +# Voir les logs +docker-compose logs -f regisflow + +# Voir le statut des services +docker-compose ps +``` + +### Gestion des données + +```bash +# Sauvegarder la base de données +docker-compose exec postgres pg_dump -U regisflow regisflow > backup.sql + +# Restaurer la base de données +docker-compose exec -T postgres psql -U regisflow regisflow < backup.sql + +# Accéder à la base de données +docker-compose exec postgres psql -U regisflow regisflow +``` + +### Maintenance + +```bash +# Mettre à jour l'application +docker-compose pull +docker-compose up -d --build + +# Nettoyer les images inutilisées +docker system prune -f + +# Voir l'utilisation des volumes +docker volume ls +docker volume inspect regisflow_postgres_data +``` + +## 🛡️ Sécurité + +### Configuration de production + +1. **Changez les mots de passe par défaut** : + - `POSTGRES_PASSWORD` + - `SESSION_SECRET` + +2. **Configurez HTTPS** : + - Obtenez un certificat SSL + - Modifiez `nginx.conf` pour le HTTPS + - Activez `secure: true` pour les cookies + +3. **Limitez l'accès réseau** : + - Utilisez un firewall + - Limitez l'accès aux ports nécessaires + +### Sauvegarde automatique + +L'application inclut un système de sauvegarde automatique : +- Sauvegarde toutes les 12 heures +- Conservation des 10 dernières sauvegardes +- Stockage dans le volume `backup_data` + +## 📊 Surveillance + +### Health Checks + +```bash +# Vérifier la santé de l'application +curl http://localhost:5000/health + +# Vérifier via Docker +docker-compose exec regisflow wget -qO- http://localhost:5000/health +``` + +### Métriques + +```bash +# Statistiques des conteneurs +docker stats + +# Utilisation des volumes +docker system df +``` + +## 🔧 Dépannage + +### Problèmes courants + +1. **L'application ne démarre pas** : + ```bash + # Vérifier les logs + docker-compose logs regisflow + + # Vérifier la base de données + docker-compose logs postgres + ``` + +2. **Erreur de connexion à la base** : + ```bash + # Vérifier que PostgreSQL est démarré + docker-compose ps postgres + + # Tester la connexion + docker-compose exec postgres pg_isready -U regisflow + ``` + +3. **Problème de permissions** : + ```bash + # Vérifier les permissions des volumes + docker-compose exec regisflow ls -la /app/backups + ``` + +### Réinitialisation complète + +```bash +# Arrêter tous les services +docker-compose down + +# Supprimer les volumes (ATTENTION: perte de données) +docker-compose down -v + +# Nettoyer les images +docker system prune -af + +# Redémarrer +docker-compose up -d +``` + +## 🔄 Mise à jour + +### Mise à jour de l'application + +```bash +# Récupérer les dernières modifications +git pull origin main + +# Reconstruire et redémarrer +docker-compose up -d --build + +# Vérifier les logs +docker-compose logs -f regisflow +``` + +### Migration de données + +L'application gère automatiquement les migrations de base de données au démarrage. + +## 📝 Configuration Avancée + +### Personnalisation de Nginx + +Éditez le fichier `nginx.conf` pour : +- Configurer SSL/TLS +- Ajouter des règles de sécurité +- Optimiser les performances + +### Variables d'environnement complètes + +```env +# Base de données +DATABASE_URL=postgresql://regisflow:password@postgres:5432/regisflow +POSTGRES_PASSWORD=password + +# Application +NODE_ENV=production +PORT=5000 +SESSION_SECRET=your-secret-key + +# Timezone +TZ=Europe/Paris + +# Sauvegardes (optionnel) +BACKUP_RETENTION_DAYS=30 +MAX_BACKUP_COUNT=10 + +# Logs (optionnel) +LOG_LEVEL=info +``` + +## 🆘 Support + +En cas de problème : + +1. Vérifiez les logs : `docker-compose logs` +2. Consultez la documentation +3. Vérifiez les issues sur GitHub +4. Contactez le support + +## 📚 Liens Utiles + +- [Documentation Docker](https://docs.docker.com/) +- [Documentation Docker Compose](https://docs.docker.com/compose/) +- [Documentation PostgreSQL](https://www.postgresql.org/docs/) +- [Documentation Nginx](https://nginx.org/en/docs/) \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7f5d3f8 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,76 @@ +version: '3.8' + +services: + # Base de données PostgreSQL + postgres: + image: postgres:15-alpine + container_name: regisflow-db + environment: + POSTGRES_DB: regisflow + POSTGRES_USER: regisflow + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-regisflow2024} + volumes: + - postgres_data:/var/lib/postgresql/data + - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro + ports: + - "5432:5432" + networks: + - regisflow-network + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "pg_isready -U regisflow -d regisflow"] + interval: 10s + timeout: 5s + retries: 5 + + # Application RegisFlow + regisflow: + build: . + container_name: regisflow-app + depends_on: + postgres: + condition: service_healthy + environment: + NODE_ENV: production + PORT: 5000 + DATABASE_URL: postgresql://regisflow:${POSTGRES_PASSWORD:-regisflow2024}@postgres:5432/regisflow + SESSION_SECRET: ${SESSION_SECRET:-your-super-secret-session-key-change-in-production} + TZ: Europe/Paris + volumes: + - backup_data:/app/backups + ports: + - "5000:5000" + networks: + - regisflow-network + restart: unless-stopped + healthcheck: + test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5000/health || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + + # Nginx reverse proxy (optionnel) + nginx: + image: nginx:alpine + container_name: regisflow-nginx + depends_on: + - regisflow + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + ports: + - "80:80" + - "443:443" + networks: + - regisflow-network + restart: unless-stopped + +volumes: + postgres_data: + driver: local + backup_data: + driver: local + +networks: + regisflow-network: + driver: bridge \ No newline at end of file diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..b5ef24b --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,25 @@ +#!/bin/sh +set -e + +# Script d'entrée pour le container RegisFlow +echo "🚀 Démarrage de RegisFlow..." + +# Attendre que la base de données soit prête +echo "📡 Attente de la base de données..." +until pg_isready -h postgres -p 5432 -U regisflow; do + echo "⏳ Base de données non prête, attente de 5 secondes..." + sleep 5 +done + +echo "✅ Base de données prête!" + +# Exécuter les migrations de base de données +echo "🔄 Exécution des migrations..." +npx drizzle-kit push:pg + +# Créer le répertoire des sauvegardes s'il n'existe pas +mkdir -p /app/backups + +# Démarrer l'application +echo "🎯 Démarrage de l'application RegisFlow..." +exec "$@" \ No newline at end of file diff --git a/init.sql b/init.sql new file mode 100644 index 0000000..c3cce53 --- /dev/null +++ b/init.sql @@ -0,0 +1,21 @@ +-- Script d'initialisation pour la base de données RegisFlow +-- Ce script sera exécuté automatiquement lors de la création du container PostgreSQL + +-- Créer les extensions nécessaires +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + +-- Créer la table des sessions (nécessaire pour express-session) +CREATE TABLE IF NOT EXISTS sessions ( + sid varchar NOT NULL COLLATE "default", + sess json NOT NULL, + expire timestamp(6) NOT NULL +); + +-- Créer un index sur la colonne d'expiration +CREATE INDEX IF NOT EXISTS "IDX_session_expire" ON sessions ("expire"); + +-- Créer la clé primaire pour la table des sessions +ALTER TABLE sessions ADD CONSTRAINT "session_pkey" PRIMARY KEY (sid) NOT DEFERRABLE INITIALLY IMMEDIATE; + +-- Créer un utilisateur pour l'application (optionnel, déjà créé par les variables d'environnement) +-- Les autres tables seront créées automatiquement par Drizzle lors du démarrage de l'application \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..7d8d7ba --- /dev/null +++ b/nginx.conf @@ -0,0 +1,79 @@ +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Configuration des logs + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + error_log /var/log/nginx/error.log warn; + + # Configuration générale + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + # Configuration de compression + gzip on; + gzip_vary on; + gzip_min_length 10240; + gzip_proxied expired no-cache no-store private must-revalidate auth; + gzip_types + text/plain + text/css + text/xml + text/javascript + application/javascript + application/xml+rss + application/json; + + # Configuration du serveur + server { + listen 80; + server_name localhost; + + # Limite de taille des fichiers + client_max_body_size 50M; + + # Configuration des headers de 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; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + + # Proxy vers l'application RegisFlow + location / { + proxy_pass http://regisflow:5000; + 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; + proxy_read_timeout 86400; + } + + # Configuration pour les fichiers statiques + location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ { + proxy_pass http://regisflow:5000; + expires 1y; + add_header Cache-Control "public, immutable"; + } + + # Health check + location /health { + proxy_pass http://regisflow:5000/health; + access_log off; + } + } +} \ No newline at end of file diff --git a/replit.md b/replit.md index 3389b57..83e2c75 100644 --- a/replit.md +++ b/replit.md @@ -122,6 +122,15 @@ Preferred communication style: Simple, everyday language. - **Sessions**: Secure session storage in PostgreSQL sessions table - **Environment Variables**: DATABASE_URL, SESSION_SECRET (optional) +### Docker Deployment +- **Container Strategy**: Multi-stage Docker build for optimized production images +- **Service Architecture**: Docker Compose with PostgreSQL, Nginx, and application containers +- **Database**: PostgreSQL 15 with persistent volumes and automated initialization +- **Reverse Proxy**: Nginx with compression, caching, and security headers +- **Health Monitoring**: Health checks for all services with automatic recovery +- **Volume Management**: Persistent storage for database and backup data +- **Environment**: Complete environment variable configuration with security templates + ### Security Configuration - **Password Hashing**: bcrypt with appropriate salt rounds - **Session Security**: HTTP-only cookies with configurable expiration @@ -191,4 +200,14 @@ Preferred communication style: Simple, everyday language. - ✅ Comprehensive statistics dashboard showing purge-eligible records - ✅ Regulatory compliance with French fireworks sales data retention requirements - ✅ Safety confirmation dialogs for manual purge operations -- ✅ Real-time monitoring of data retention status with visual indicators \ No newline at end of file +- ✅ Real-time monitoring of data retention status with visual indicators + +### Docker Configuration (January 9, 2025) +- ✅ Complete Docker setup with multi-stage build for production optimization +- ✅ Docker Compose configuration with PostgreSQL, Nginx, and application services +- ✅ Automated database initialization and migration scripts +- ✅ Health checks and proper container orchestration +- ✅ Production-ready configuration with security best practices +- ✅ Persistent volumes for database and backup data +- ✅ Environment variable configuration with .env.example template +- ✅ Comprehensive Docker documentation with deployment instructions \ No newline at end of file diff --git a/server/routes.ts b/server/routes.ts index df46ef0..b31f291 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -117,6 +117,16 @@ export async function registerRoutes(app: Express): Promise { } }); + // Health check endpoint for Docker + app.get('/health', (req, res) => { + res.status(200).json({ + status: 'healthy', + timestamp: new Date().toISOString(), + uptime: process.uptime(), + environment: process.env.NODE_ENV || 'development' + }); + }); + app.get('/api/auth/me', requireAuth, async (req, res) => { try { const user = await storage.getUser(req.session.userId!);