diff --git a/COMMANDES_PRODUCTION.md b/COMMANDES_PRODUCTION.md new file mode 100644 index 0000000..5f93569 --- /dev/null +++ b/COMMANDES_PRODUCTION.md @@ -0,0 +1,57 @@ +# MIGRATION PRODUCTION URGENTE - DLC Stock Épuisé + +## Problème +``` +Error: column dlc_products.stock_epuise does not exist +``` + +## Solution Rapide + +### Option 1: Migration SQL directe +```bash +# Connectez-vous à votre base PostgreSQL de production +psql -h [VOTRE_HOST] -U [VOTRE_USER] -d [VOTRE_DB] -f MIGRATION_PRODUCTION_URGENTE.sql +``` + +### Option 2: Commandes manuelles +```sql +-- Connectez-vous à votre base et exécutez : +ALTER TABLE dlc_products +ADD COLUMN IF NOT EXISTS stock_epuise boolean DEFAULT false NOT NULL, +ADD COLUMN IF NOT EXISTS stock_epuise_by varchar(255), +ADD COLUMN IF NOT EXISTS stock_epuise_at timestamp; + +CREATE INDEX IF NOT EXISTS idx_dlc_products_stock_epuise ON dlc_products(stock_epuise); +``` + +### Option 3: Via Docker (si vous utilisez notre docker-compose) +```bash +# Sur votre serveur de production +./scripts/production-deploy-dlc-stock.sh +``` + +## Vérification après migration +```sql +SELECT EXISTS ( + SELECT FROM information_schema.columns + WHERE table_name='dlc_products' + AND column_name='stock_epuise' +); +``` + +Résultat attendu: `t` (true) + +## Redémarrage application +Après la migration, redémarrez votre application : +```bash +# Si Docker +docker-compose restart logiflow + +# Ou selon votre setup +systemctl restart votre-service +``` + +## Vérification fonctionnelle +1. L'erreur "column does not exist" doit disparaître +2. L'interface DLC doit afficher les boutons PackageX et RotateCcw +3. Les fonctionnalités stock épuisé doivent être opérationnelles \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 7c3eba8..c3afe88 100644 --- a/Dockerfile +++ b/Dockerfile @@ -107,8 +107,10 @@ USER nextjs HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1 -# Make migration script executable -RUN chmod +x /app/scripts/auto-migrate-production.sh +# Make scripts executable +RUN chmod +x /app/scripts/auto-migrate-production.sh && \ + chmod +x /app/scripts/docker-entrypoint.sh -# Start the application normally (migration will be manual or via init script) +# Use entrypoint script for automatic migrations +ENTRYPOINT ["/app/scripts/docker-entrypoint.sh"] CMD ["node", "dist/index.js"] \ No newline at end of file diff --git a/MIGRATION_PRODUCTION_URGENTE.sql b/MIGRATION_PRODUCTION_URGENTE.sql new file mode 100644 index 0000000..b8c96ef --- /dev/null +++ b/MIGRATION_PRODUCTION_URGENTE.sql @@ -0,0 +1,60 @@ +-- MIGRATION URGENTE PRODUCTION - DLC Stock Épuisé +-- Date: 2025-08-18 +-- À exécuter sur votre serveur de production privé + +-- Vérification que la table dlc_products existe +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'dlc_products') THEN + RAISE EXCEPTION 'ERREUR: La table dlc_products n''existe pas'; + END IF; + RAISE NOTICE 'OK: Table dlc_products trouvée'; +END +$$; + +-- Vérification des colonnes existantes avant migration +SELECT 'AVANT MIGRATION - Colonnes actuelles:' as status; +SELECT column_name FROM information_schema.columns +WHERE table_name = 'dlc_products' +AND column_name IN ('stock_epuise', 'stock_epuise_by', 'stock_epuise_at') +ORDER BY column_name; + +-- Migration sécurisée - Ajout des colonnes DLC stock épuisé +ALTER TABLE dlc_products +ADD COLUMN IF NOT EXISTS stock_epuise boolean DEFAULT false NOT NULL, +ADD COLUMN IF NOT EXISTS stock_epuise_by varchar(255), +ADD COLUMN IF NOT EXISTS stock_epuise_at timestamp; + +-- Commentaires pour documenter les nouveaux champs +COMMENT ON COLUMN dlc_products.stock_epuise IS 'Indique si le produit est marqué comme stock épuisé (différent de périmé)'; +COMMENT ON COLUMN dlc_products.stock_epuise_by IS 'ID de l''utilisateur qui a marqué le produit comme stock épuisé'; +COMMENT ON COLUMN dlc_products.stock_epuise_at IS 'Date et heure de marquage du stock épuisé'; + +-- Index pour améliorer les performances +CREATE INDEX IF NOT EXISTS idx_dlc_products_stock_epuise ON dlc_products(stock_epuise); + +-- Initialiser tous les produits existants comme stock disponible +UPDATE dlc_products +SET stock_epuise = false +WHERE stock_epuise IS NULL; + +-- Vérification finale +SELECT 'APRÈS MIGRATION - Vérification:' as status; +SELECT + column_name, + data_type, + is_nullable, + column_default +FROM information_schema.columns +WHERE table_name = 'dlc_products' +AND column_name IN ('stock_epuise', 'stock_epuise_by', 'stock_epuise_at') +ORDER BY column_name; + +-- Statistiques après migration +SELECT + COUNT(*) as total_produits, + COUNT(CASE WHEN stock_epuise = true THEN 1 END) as stock_epuise, + COUNT(CASE WHEN stock_epuise = false THEN 1 END) as stock_disponible +FROM dlc_products; + +SELECT 'MIGRATION TERMINÉE AVEC SUCCÈS' as status; \ No newline at end of file diff --git a/attached_assets/Pasted--userRole-admin-Admin-filtering-with-groupIds-1-Fetching-all-orders-C-1755509679309_1755509679309.txt b/attached_assets/Pasted--userRole-admin-Admin-filtering-with-groupIds-1-Fetching-all-orders-C-1755509679309_1755509679309.txt new file mode 100644 index 0000000..b375805 --- /dev/null +++ b/attached_assets/Pasted--userRole-admin-Admin-filtering-with-groupIds-1-Fetching-all-orders-C-1755509679309_1755509679309.txt @@ -0,0 +1,196 @@ + + userRole: 'admin' + +} + +Admin filtering with groupIds: [ 1 ] + +Fetching all orders + +Customer Orders API called with: { groupIds: [ 1 ], userRole: 'admin' } + +Deliveries API called with: { + + startDate: undefined, + + endDate: undefined, + + storeId: '1', + + withBL: undefined, + + userRole: 'admin' + +} + +Admin filtering deliveries with groupIds: [ 1 ] + +Fetching all deliveries + +Customer Orders returned: 10 items + +GET /api/customer-orders 200 in 16ms + +🔗 PRODUCTION: getOrders() récupéré 33 commandes avec relations + +Orders returned: 33 items + +GET /api/orders 200 in 124ms + +🔗 PRODUCTION: getDeliveries() récupéré 49 livraisons avec relations + +Deliveries returned: 49 items + +GET /api/deliveries 200 in 140ms + +GET /api/groups 304 in 48ms + +GET /api/user 304 in 4ms + +GET /api/suppliers 304 in 9ms + +Error fetching DLC products: error: column dlc_products.stock_epuise does not exist + + at /app/node_modules/pg-pool/index.js:45:11 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async file:///app/node_modules/drizzle-orm/node-postgres/session.js:83:22 + + at async DatabaseStorage.getDlcProducts (file:///app/dist/index.js:2187:25) + + at async file:///app/dist/index.js:6178:28 { + + length: 124, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '337', + + internalPosition: undefined, + + internalQuery: undefined, + + where: undefined, + + schema: undefined, + + table: undefined, + + column: undefined, + + dataType: undefined, + + constraint: undefined, + + file: 'parse_relation.c', + + line: '3665', + + routine: 'errorMissingColumn' + +} + +GET /api/dlc-products 500 in 15ms + +GET /api/dlc-products 500 in 7ms + +Error fetching DLC products: error: column dlc_products.stock_epuise does not exist + + at /app/node_modules/pg-pool/index.js:45:11 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async file:///app/node_modules/drizzle-orm/node-postgres/session.js:83:22 + + at async DatabaseStorage.getDlcProducts (file:///app/dist/index.js:2187:25) + + at async file:///app/dist/index.js:6178:28 { + + length: 124, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '337', + + internalPosition: undefined, + + internalQuery: undefined, + + where: undefined, + + schema: undefined, + + table: undefined, + + column: undefined, + + dataType: undefined, + + constraint: undefined, + + file: 'parse_relation.c', + + line: '3665', + + routine: 'errorMissingColumn' + +} + +Error fetching DLC products: error: column dlc_products.stock_epuise does not exist + + at /app/node_modules/pg-pool/index.js:45:11 + + at process.processTicksAndRejections (node:internal/process/task_queues:95:5) + + at async file:///app/node_modules/drizzle-orm/node-postgres/session.js:83:22 + + at async DatabaseStorage.getDlcProducts (file:///app/dist/index.js:2187:25) + + at async file:///app/dist/index.js:6178:28 { + + length: 124, + + severity: 'ERROR', + + code: '42703', + + detail: undefined, + + hint: undefined, + + position: '337', + + internalPosition: undefined, + + internalQuery: undefined, + + where: undefined, + + schema: undefined, + + table: undefined, + + column: undefined, + + dataType: undefined, + + constraint: undefined, + + file: 'parse_relation.c', + + line: '3665', + + routine: 'errorMissingColumn' \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 523516d..a6fd835 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,6 +23,8 @@ services: depends_on: logiflow-db: condition: service_healthy + volumes: + - ./migrations:/app/migrations healthcheck: test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"] interval: 30s diff --git a/scripts/docker-entrypoint.sh b/scripts/docker-entrypoint.sh old mode 100644 new mode 100755 index dd0f154..6ddde3e --- a/scripts/docker-entrypoint.sh +++ b/scripts/docker-entrypoint.sh @@ -1,37 +1,99 @@ #!/bin/bash -# Point d'entrée Docker avec migration automatique -# Ce script remplace le point d'entrée par défaut du conteneur + +# Script d'entrée Docker - Applique automatiquement les migrations au démarrage +# Auteur: Système de gestion automatisé +# Date: 2025-08-18 set -e -echo "🚀 [ENTRYPOINT] Démarrage du conteneur avec migration automatique..." +echo "🚀 [ENTRYPOINT] Démarrage du conteneur de production" +echo "==================================================" -# Attendre que la base de données soit prête -echo "⏳ [ENTRYPOINT] Attente de la base de données..." -timeout=60 -counter=0 +# Fonction de logging avec timestamp +log() { + echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" +} -while ! psql "$DATABASE_URL" -c "SELECT 1;" > /dev/null 2>&1; do - counter=$((counter + 1)) - if [ $counter -gt $timeout ]; then - echo "❌ [ENTRYPOINT] Timeout: impossible de se connecter à la base de données après ${timeout}s" - exit 1 +log "🔧 Initialisation des variables d'environnement..." + +# Construire DATABASE_URL si nécessaire +if [ -z "$DATABASE_URL" ]; then + if [ -n "$POSTGRES_USER" ] && [ -n "$POSTGRES_PASSWORD" ] && [ -n "$POSTGRES_DB" ]; then + export DATABASE_URL="postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@logiflow-db:5432/${POSTGRES_DB}" + log "✅ URL de base de données construite automatiquement" + else + log "⚠️ Variables PostgreSQL manquantes, utilisation de DATABASE_URL existant" fi - echo "⏳ [ENTRYPOINT] Tentative $counter/$timeout..." - sleep 1 -done - -echo "✅ [ENTRYPOINT] Base de données accessible" - -# Exécuter les migrations automatiques -if [ -f "/app/scripts/auto-migrate-production.sh" ]; then - echo "🔄 [ENTRYPOINT] Exécution des migrations automatiques..." - chmod +x /app/scripts/auto-migrate-production.sh - /app/scripts/auto-migrate-production.sh -else - echo "⚠️ [ENTRYPOINT] Script de migration non trouvé, poursuite sans migration" fi -# Démarrer l'application -echo "🎯 [ENTRYPOINT] Démarrage de l'application..." +# Attendre que PostgreSQL soit prêt +log "⏳ Attente de PostgreSQL..." +max_attempts=30 +attempt=1 + +while [ $attempt -le $max_attempts ]; do + if psql "$DATABASE_URL" -c "SELECT 1;" > /dev/null 2>&1; then + log "✅ PostgreSQL est prêt" + break + fi + + if [ $attempt -eq $max_attempts ]; then + log "❌ PostgreSQL non accessible après $max_attempts tentatives" + log "🔍 Variables DB: USER=${POSTGRES_USER:-'non défini'} DB=${POSTGRES_DB:-'non défini'}" + exit 1 + fi + + log "⏳ Tentative $attempt/$max_attempts - attente 2 secondes..." + sleep 2 + ((attempt++)) +done + +# Exécuter les migrations automatiques +log "🔄 Exécution des migrations automatiques..." +if [ -f "/app/scripts/auto-migrate-production.sh" ]; then + log "📂 Script de migration trouvé, exécution..." + chmod +x /app/scripts/auto-migrate-production.sh + + if /app/scripts/auto-migrate-production.sh; then + log "✅ Migrations exécutées avec succès" + else + log "❌ Erreur lors des migrations" + exit 1 + fi +else + log "⚠️ Script de migration non trouvé à /app/scripts/auto-migrate-production.sh" + log "🔍 Contenu du répertoire scripts:" + ls -la /app/scripts/ || echo "Répertoire scripts non trouvé" +fi + +# Vérification post-migration +log "🔍 Vérification des colonnes DLC..." +if psql "$DATABASE_URL" -tAc "SELECT EXISTS (SELECT FROM information_schema.columns WHERE table_name='dlc_products' AND column_name='stock_epuise');" | grep -q "t"; then + log "✅ Colonnes DLC stock épuisé présentes" +else + log "❌ Colonnes DLC stock épuisé manquantes" + log "🛠️ Tentative de migration directe..." + + psql "$DATABASE_URL" << 'EOF' +ALTER TABLE dlc_products +ADD COLUMN IF NOT EXISTS stock_epuise boolean DEFAULT false NOT NULL, +ADD COLUMN IF NOT EXISTS stock_epuise_by varchar(255), +ADD COLUMN IF NOT EXISTS stock_epuise_at timestamp; + +CREATE INDEX IF NOT EXISTS idx_dlc_products_stock_epuise ON dlc_products(stock_epuise); +EOF + + if [ $? -eq 0 ]; then + log "✅ Migration directe réussie" + else + log "❌ Migration directe échouée" + exit 1 + fi +fi + +# Démarrage de l'application +log "🚀 Démarrage de l'application..." +log "==================================================" + +# Exécuter la commande passée en paramètre (normalement "node dist/index.js") exec "$@" \ No newline at end of file diff --git a/scripts/production-deploy-dlc-stock.sh b/scripts/production-deploy-dlc-stock.sh old mode 100755 new mode 100644 index 126e66a..7562a77 --- a/scripts/production-deploy-dlc-stock.sh +++ b/scripts/production-deploy-dlc-stock.sh @@ -95,8 +95,8 @@ else log "⚠️ Erreur lors de la migration - vérification manuelle nécessaire" fi -# Démarrage complet de l'application -log "🚀 Démarrage complet de l'application..." +# Démarrage complet de l'application (la migration sera automatique) +log "🚀 Démarrage complet de l'application avec migration automatique..." docker-compose up -d # Attendre que l'application soit prête