mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-12 01:37:40 +02:00
7 files changed
+411
-32
No files matched your search
@@ -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
|
||||
+5
-3
@@ -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"]
|
||||
@@ -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;
|
||||
+196
@@ -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'
|
||||
@@ -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
|
||||
|
||||
Regular → Executable
+89
-27
@@ -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 "$@"
|
||||
Executable → Regular
+2
-2
@@ -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
|
||||
|
||||
Reference in new issue
Block a user