Set up database initialization process using SQL scripts and Drizzle ORM

Adds init.sql and init-db.sh for database initialization, and enhances Docker setup.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: dec54137-d5a2-4406-8ad4-5f2f9fb110bf
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/0715008c-7244-40f4-befc-26c014852236/438ba2d5-c119-4a74-9474-438eed8b3141.jpg
This commit is contained in:
michaelschal committed 2025-07-11 16:01:42 +00:00
1 parent 9cc28ddc93
commit 77d77ab658
5 files changed
+357 -4

No files matched your search

+1
View File
@@ -47,6 +47,7 @@ COPY --from=builder --chown=regisflow:nodejs /build/shared ./shared
COPY --from=builder --chown=regisflow:nodejs /build/server/prod-start.js ./server/
COPY --from=builder --chown=regisflow:nodejs /build/drizzle.config.ts ./
COPY --from=builder --chown=regisflow:nodejs /build/node_modules ./node_modules
COPY --from=builder --chown=regisflow:nodejs /build/init.sql ./
# Copier les assets client au bon endroit pour serveStatic
COPY --from=builder --chown=regisflow:nodejs /build/dist/public ./public
+16 -1
View File
@@ -40,9 +40,13 @@ MAX_BACKUP_COUNT=20
### 3. Déploiement immédiat
```bash
# Démarrer l'application
# Option A: Démarrer avec Docker Compose
docker-compose up -d --build
# Option B: Utiliser le script automatisé
chmod +x deploy-production.sh
./deploy-production.sh
# Vérifier le fonctionnement
curl http://localhost:5000/health
@@ -50,6 +54,17 @@ curl http://localhost:5000/health
docker-compose logs -f regisflow
```
### 3.1 Initialisation manuelle de la base (si nécessaire)
```bash
# Si les tables ne se créent pas automatiquement
chmod +x init-db.sh
./init-db.sh
# Ou avec une DATABASE_URL spécifique
./init-db.sh "postgresql://regisflow:password@localhost:5433/regisflow"
```
### 4. Accès initial
- **URL** : http://votre-serveur:5000
+18 -3
View File
@@ -27,11 +27,26 @@ mkdir -p /app/backups /app/logs
# Créer les tables de la base de données
echo "📦 Création des tables de la base de données..."
# Méthode 1: Utiliser Drizzle Kit (recommandé)
if npx drizzle-kit push --config=./drizzle.config.ts; then
echo "✅ Tables créées avec succès"
echo "✅ Tables créées avec succès via Drizzle"
else
echo "❌ Erreur lors de la création des tables"
exit 1
echo "⚠️ Drizzle Kit failed, essai avec init.sql..."
# Méthode 2: Fallback avec init.sql si Drizzle échoue
if [ -f "/app/init.sql" ]; then
export PGPASSWORD="$POSTGRES_PASSWORD"
if psql -h regisflow-db -p 5432 -U regisflow -d regisflow -f /app/init.sql; then
echo "✅ Tables créées avec succès via init.sql"
else
echo "❌ Erreur lors de la création des tables"
exit 1
fi
else
echo "❌ Aucune méthode d'initialisation disponible"
exit 1
fi
fi
echo "✅ Base de données configurée"
Executable
+151
View File
@@ -0,0 +1,151 @@
#!/bin/bash
# Script d'initialisation de la base de données RegisFlow
# Usage: ./init-db.sh [DATABASE_URL]
set -e
# Configuration par défaut
DEFAULT_DB_HOST="localhost"
DEFAULT_DB_PORT="5433"
DEFAULT_DB_NAME="regisflow"
DEFAULT_DB_USER="regisflow"
DEFAULT_DB_PASSWORD="RegisFlow2024!PostgreSQL"
# Couleurs pour les messages
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${BLUE}ℹ️ $1${NC}"
}
log_success() {
echo -e "${GREEN}✅ $1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
log_error() {
echo -e "${RED}❌ $1${NC}"
}
# Fonction pour extraire les informations de DATABASE_URL
parse_database_url() {
local url="$1"
# Extraire les composants de l'URL PostgreSQL
if [[ $url =~ postgresql://([^:]+):([^@]+)@([^:]+):([^/]+)/(.+) ]]; then
DB_USER="${BASH_REMATCH[1]}"
DB_PASSWORD="${BASH_REMATCH[2]}"
DB_HOST="${BASH_REMATCH[3]}"
DB_PORT="${BASH_REMATCH[4]}"
DB_NAME="${BASH_REMATCH[5]}"
else
log_error "Format DATABASE_URL invalide. Utilisez: postgresql://user:password@host:port/database"
exit 1
fi
}
# Déterminer la configuration de la base de données
if [ -n "$1" ]; then
log_info "Utilisation de DATABASE_URL fournie: $1"
parse_database_url "$1"
elif [ -n "$DATABASE_URL" ]; then
log_info "Utilisation de DATABASE_URL depuis l'environnement"
parse_database_url "$DATABASE_URL"
else
log_info "Utilisation de la configuration par défaut"
DB_HOST="$DEFAULT_DB_HOST"
DB_PORT="$DEFAULT_DB_PORT"
DB_NAME="$DEFAULT_DB_NAME"
DB_USER="$DEFAULT_DB_USER"
DB_PASSWORD="$DEFAULT_DB_PASSWORD"
fi
log_info "Configuration de la base de données:"
log_info " Host: $DB_HOST"
log_info " Port: $DB_PORT"
log_info " Database: $DB_NAME"
log_info " User: $DB_USER"
# Vérifier que psql est installé
if ! command -v psql &> /dev/null; then
log_error "psql n'est pas installé. Installez PostgreSQL client."
exit 1
fi
# Vérifier la connexion à PostgreSQL
log_info "Test de connexion à PostgreSQL..."
export PGPASSWORD="$DB_PASSWORD"
if ! psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -c "\q" 2>/dev/null; then
log_error "Impossible de se connecter à PostgreSQL"
log_info "Vérifiez que PostgreSQL est démarré et accessible"
log_info "Commande de test: psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME"
exit 1
fi
log_success "Connexion PostgreSQL réussie"
# Exécuter le script d'initialisation
log_info "Exécution du script d'initialisation..."
if [ -f "init.sql" ]; then
if psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -f init.sql; then
log_success "Script d'initialisation exécuté avec succès"
else
log_error "Erreur lors de l'exécution du script d'initialisation"
exit 1
fi
else
log_error "Fichier init.sql non trouvé"
exit 1
fi
# Vérifier que les tables ont été créées
log_info "Vérification des tables créées..."
TABLES=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT tablename FROM pg_tables WHERE schemaname='public';" | tr -d ' ' | grep -v '^$')
if echo "$TABLES" | grep -q "users\|stores\|sales\|sessions"; then
log_success "Tables principales créées:"
echo "$TABLES" | while read -r table; do
if [ -n "$table" ]; then
log_info " - $table"
fi
done
else
log_error "Les tables principales n'ont pas été créées correctement"
exit 1
fi
# Vérifier l'utilisateur admin
log_info "Vérification de l'utilisateur administrateur..."
ADMIN_COUNT=$(psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -t -c "SELECT COUNT(*) FROM users WHERE username='admin';" | tr -d ' ')
if [ "$ADMIN_COUNT" = "1" ]; then
log_success "Utilisateur admin créé avec succès"
else
log_warning "Problème avec la création de l'utilisateur admin"
fi
# Afficher le résumé
echo ""
log_success "🎉 Initialisation de la base de données terminée!"
echo "======================================================"
log_info "Base de données: $DB_NAME sur $DB_HOST:$DB_PORT"
log_info "Utilisateur administrateur:"
log_info " - Username: admin"
log_info " - Password: admin123"
log_warning "IMPORTANT: Changez le mot de passe admin après la première connexion!"
echo ""
# Nettoyer les variables d'environnement
unset PGPASSWORD
log_success "Prêt pour le déploiement!"
+171
View File
@@ -0,0 +1,171 @@
-- Script d'initialisation PostgreSQL pour RegisFlow
-- Ce script crée toutes les tables nécessaires et les données de base
-- Configuration initiale
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;
-- Création de la base de données (si elle n'existe pas déjà)
-- CREATE DATABASE regisflow WITH ENCODING 'UTF8' LC_COLLATE='fr_FR.UTF-8' LC_CTYPE='fr_FR.UTF-8';
-- Extension pour les UUID si nécessaire
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Table des sessions (pour l'authentification)
CREATE TABLE IF NOT EXISTS sessions (
sid VARCHAR PRIMARY KEY,
sess JSONB NOT NULL,
expire TIMESTAMP NOT NULL
);
-- Index sur la date d'expiration des sessions
CREATE INDEX IF NOT EXISTS "IDX_session_expire" ON sessions (expire);
-- Table des magasins
CREATE TABLE IF NOT EXISTS stores (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
address TEXT,
phone VARCHAR(20),
email VARCHAR(255),
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Table des utilisateurs avec authentification
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE,
first_name VARCHAR(100),
last_name VARCHAR(100),
role VARCHAR(20) NOT NULL DEFAULT 'employee',
store_id INTEGER REFERENCES stores(id),
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Table des ventes
CREATE TABLE IF NOT EXISTS sales (
id SERIAL PRIMARY KEY,
store_id INTEGER REFERENCES stores(id) NOT NULL,
user_id INTEGER REFERENCES users(id) NOT NULL,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- Informations vendeur
vendeur VARCHAR(255) NOT NULL,
-- Informations produit
type_article VARCHAR(255) NOT NULL,
categorie VARCHAR(2) NOT NULL,
quantite INTEGER NOT NULL,
gencode VARCHAR(13) NOT NULL,
-- Informations client
nom VARCHAR(255) NOT NULL,
prenom VARCHAR(255) NOT NULL,
date_naissance VARCHAR(10) NOT NULL,
lieu_naissance VARCHAR(255),
mode_paiement VARCHAR(50) NOT NULL DEFAULT 'Espèce',
-- Informations pièce d'identité
type_identite VARCHAR(100) NOT NULL,
numero_identite VARCHAR(100) NOT NULL,
autorite_delivrance VARCHAR(255),
date_delivrance VARCHAR(10) NOT NULL,
-- Photos (Base64)
photo_recto TEXT,
photo_verso TEXT
);
-- Index pour optimiser les recherches
CREATE INDEX IF NOT EXISTS idx_sales_store_id ON sales(store_id);
CREATE INDEX IF NOT EXISTS idx_sales_user_id ON sales(user_id);
CREATE INDEX IF NOT EXISTS idx_sales_timestamp ON sales(timestamp);
CREATE INDEX IF NOT EXISTS idx_sales_nom ON sales(nom);
CREATE INDEX IF NOT EXISTS idx_sales_prenom ON sales(prenom);
CREATE INDEX IF NOT EXISTS idx_sales_gencode ON sales(gencode);
-- Relations et contraintes
ALTER TABLE users ADD CONSTRAINT chk_user_role
CHECK (role IN ('admin', 'manager', 'employee'));
ALTER TABLE sales ADD CONSTRAINT chk_sales_categorie
CHECK (categorie IN ('F2', 'F3'));
-- Trigger pour mettre à jour updated_at automatiquement
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_stores_updated_at
BEFORE UPDATE ON stores
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_users_updated_at
BEFORE UPDATE ON users
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
-- Insertion des données de base
-- Magasin par défaut
INSERT INTO stores (id, name, address, phone, email)
VALUES (1, 'Magasin Principal', '', '', '')
ON CONFLICT (id) DO NOTHING;
-- Utilisateur administrateur par défaut
-- Mot de passe: admin123 (hashé avec bcrypt)
INSERT INTO users (id, username, password, email, first_name, last_name, role, store_id)
VALUES (1, 'admin', '$2a$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', 'admin@regisflow.com', 'Admin', 'RegisFlow', 'admin', 1)
ON CONFLICT (username) DO NOTHING;
-- Séquences pour l'auto-increment
SELECT setval('stores_id_seq', (SELECT COALESCE(MAX(id), 1) FROM stores));
SELECT setval('users_id_seq', (SELECT COALESCE(MAX(id), 1) FROM users));
SELECT setval('sales_id_seq', (SELECT COALESCE(MAX(id), 1) FROM sales));
-- Permissions et sécurité
GRANT CONNECT ON DATABASE regisflow TO regisflow;
GRANT USAGE ON SCHEMA public TO regisflow;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO regisflow;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO regisflow;
-- Vue pour les statistiques (optionnelle)
CREATE OR REPLACE VIEW sales_stats AS
SELECT
s.store_id,
st.name as store_name,
COUNT(*) as total_sales,
DATE_TRUNC('month', s.timestamp) as month_year,
s.categorie,
COUNT(*) as category_count
FROM sales s
LEFT JOIN stores st ON s.store_id = st.id
GROUP BY s.store_id, st.name, DATE_TRUNC('month', s.timestamp), s.categorie
ORDER BY month_year DESC;
-- Commentaires pour la documentation
COMMENT ON TABLE sessions IS 'Table des sessions utilisateur pour l''authentification';
COMMENT ON TABLE stores IS 'Table des magasins/points de vente';
COMMENT ON TABLE users IS 'Table des utilisateurs avec rôles et authentification';
COMMENT ON TABLE sales IS 'Table principale des ventes de feux d''artifice';
COMMENT ON COLUMN sales.categorie IS 'Catégorie F2 ou F3 selon la réglementation française';
COMMENT ON COLUMN sales.photo_recto IS 'Photo recto de la pièce d''identité (Base64)';
COMMENT ON COLUMN sales.photo_verso IS 'Photo verso de la pièce d''identité (Base64)';
-- Affichage des informations de fin
\echo 'Base de données RegisFlow initialisée avec succès!'
\echo 'Utilisateur admin créé: username=admin, password=admin123'
\echo 'Magasin par défaut créé: Magasin Principal'