#!/bin/bash # ============================================ # Wordly.art - Configuration Wizard # ============================================ # Script interactif pour configurer le .env # Lancer sur le serveur: bash scripts/setup-env.sh # ============================================ set -e # Couleurs RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' ENV_FILE=".env" echo "" echo -e "${CYAN}${BOLD}=========================================${NC}" echo -e "${CYAN}${BOLD} Wordly.art - Configuration Wizard${NC}" echo -e "${CYAN}${BOLD}=========================================${NC}" echo "" # Verifier qu'on est dans le bon dossier if [ ! -f "docker-compose.yml" ]; then echo -e "${RED}Erreur: lance ce script depuis la racine du projet (cd /opt/wordly)${NC}" echo "Usage: bash scripts/setup-env.sh" exit 1 fi # Fonction pour demander une valeur avec defaut ask() { local prompt="$1" local default="$2" local varname="$3" local required="$4" if [ -n "$default" ]; then echo -ne "${YELLOW}${prompt}${NC} [${default}]: " else echo -ne "${YELLOW}${prompt}${NC}: " fi read -r answer answer="${answer:-$default}" if [ "$required" = "true" ] && [ -z "$answer" ]; then echo -e "${RED}Cette valeur est obligatoire!${NC}" ask "$prompt" "$default" "$varname" "$required" return fi eval "$varname=\"\$answer\"" } # Fonction pour demander un mot de passe cache ask_password() { local prompt="$1" local varname="$2" echo -ne "${YELLOW}${prompt}${NC}: " read -rs answer echo "" eval "$varname=\"\$answer\"" } # Fonction pour generer un secret generate_secret() { python3 -c "import secrets; print(secrets.token_urlsafe(64))" 2>/dev/null || \ openssl rand -base64 48 | tr -d '\n' } generate_hex() { python3 -c "import secrets; print(secrets.token_hex(32))" 2>/dev/null || \ openssl rand -hex 32 } generate_password() { python3 -c "import secrets; print(secrets.token_urlsafe(32))" 2>/dev/null || \ openssl rand -base64 24 | tr -d '\n' } # =========================================== # ETAPE 1 : Domaine # =========================================== echo -e "${BOLD}--- Domaine & DNS ---${NC}" echo "" ask "Nom de domaine" "wordly.art" DOMAIN true # =========================================== # ETAPE 2 : Base de donnees # =========================================== echo "" echo -e "${BOLD}--- Base de donnees PostgreSQL ---${NC}" echo "" ask "Utilisateur PostgreSQL" "translate" POSTGRES_USER true POSTGRES_PASSWORD=$(generate_password) echo -e " ${GREEN}Mot de passe genere automatiquement${NC}" # =========================================== # ETAPE 3 : Admin # =========================================== echo "" echo -e "${BOLD}--- Compte Administrateur ---${NC}" echo "" ask "Nom d'utilisateur admin" "admin" ADMIN_USERNAME true ask_password "Mot de passe admin (cache)" ADMIN_PASSWORD if [ -z "$ADMIN_PASSWORD" ]; then echo -e "${RED}Le mot de passe admin est obligatoire!${NC}" ask_password "Mot de passe admin (cache)" ADMIN_PASSWORD fi echo "" ask_password "Confirmer le mot de passe" ADMIN_PASSWORD_CONFIRM if [ "$ADMIN_PASSWORD" != "$ADMIN_PASSWORD_CONFIRM" ]; then echo -e "${RED}Les mots de passe ne correspondent pas!${NC}" exit 1 fi echo -e " ${GREEN}Mot de passe confirme${NC}" # Generer le hash bcrypt echo -e " ${CYAN}Generation du hash bcrypt...${NC}" if command -v docker &> /dev/null; then ADMIN_PASSWORD_HASH=$(docker run --rm python:3.12-slim bash -c \ "pip install 'passlib[bcrypt]' bcrypt > /dev/null 2>&1 && \ python3 -c \"from passlib.context import CryptContext; \ print(CryptContext(schemes=['bcrypt']).hash('${ADMIN_PASSWORD}'))\"" 2>/dev/null) fi if [ -z "$ADMIN_PASSWORD_HASH" ]; then echo -e " ${YELLOW}Impossible de generer le hash bcrypt automatiquement.${NC}" echo -e " ${YELLOW}Tu devras le generer manuellement plus tard.${NC}" ADMIN_PASSWORD_HASH="CHANGE_WITH_BCRYPT_HASH" else echo -e " ${GREEN}Hash bcrypt genere${NC}" fi # =========================================== # ETAPE 4 : Secrets # =========================================== echo "" echo -e "${BOLD}--- Secrets de securite ---${NC}" echo -e " ${CYAN}Generation automatique des secrets...${NC}" JWT_SECRET_KEY=$(generate_secret) ADMIN_TOKEN_SECRET=$(generate_hex) echo -e " ${GREEN}JWT_SECRET_KEY genere${NC}" echo -e " ${GREEN}ADMIN_TOKEN_SECRET genere${NC}" # =========================================== # ETAPE 5 : Services de traduction # =========================================== echo "" echo -e "${BOLD}--- Services de traduction ---${NC}" echo "" echo "Quel service de traduction par defaut ?" echo " 1) ollama (local, gratuit)" echo " 2) google (API payante)" echo " 3) deepl (API payante, haute qualite)" echo " 4) openai (GPT, payant)" echo " 5) openrouter (multi-modeles, payant)" ask "Choix (1-5)" "1" TRANSLATION_CHOICE case "$TRANSLATION_CHOICE" in 1) TRANSLATION_SERVICE="ollama" ;; 2) TRANSLATION_SERVICE="google" ;; 3) TRANSLATION_SERVICE="deepl" ;; 4) TRANSLATION_SERVICE="openai" ;; 5) TRANSLATION_SERVICE="openrouter" ;; *) TRANSLATION_SERVICE="ollama" ;; esac DEEPL_API_KEY="" OPENAI_API_KEY="" OPENROUTER_API_KEY="" if [ "$TRANSLATION_SERVICE" = "ollama" ]; then ask "URL Ollama" "http://ollama:11434" OLLAMA_BASE_URL ask "Modele Ollama" "llama3" OLLAMA_MODEL fi if [ "$TRANSLATION_SERVICE" = "deepl" ] || [ "$TRANSLATION_SERVICE" = "all" ]; then ask "Cle API DeepL (laisser vide si pas maintenant)" "" DEEPL_API_KEY fi if [ "$TRANSLATION_SERVICE" = "openai" ] || [ "$TRANSLATION_SERVICE" = "all" ]; then ask "Cle API OpenAI (laisser vide si pas maintenant)" "" OPENAI_API_KEY fi if [ "$TRANSLATION_SERVICE" = "openrouter" ] || [ "$TRANSLATION_SERVICE" = "all" ]; then ask "Cle API OpenRouter (laisser vide si pas maintenant)" "" OPENROUTER_API_KEY fi # =========================================== # ETAPE 6 : Monitoring # =========================================== echo "" echo -e "${BOLD}--- Monitoring Grafana ---${NC}" echo "" ask "Utilisateur Grafana" "admin" GRAFANA_USER true GRAFANA_PASSWORD=$(generate_password) echo -e " ${GREEN}Mot de passe Grafana genere: ${GRAFANA_PASSWORD}${NC}" # =========================================== # ETAPE 7 : Stripe (optionnel) # =========================================== echo "" echo -e "${BOLD}--- Paiements Stripe (optionnel) ---${NC}" echo "" ask "Configurer Stripe maintenant ? (oui/non)" "non" SETUP_STRIPE STRIPE_SECRET_KEY="" STRIPE_WEBHOOK_SECRET="" STRIPE_STARTER_PRICE_ID="" STRIPE_PRO_PRICE_ID="" STRIPE_BUSINESS_PRICE_ID="" if [ "$SETUP_STRIPE" = "oui" ]; then ask "Cle secrete Stripe (sk_live_...)" "" STRIPE_SECRET_KEY ask "Webhook secret (whsec_...)" "" STRIPE_WEBHOOK_SECRET ask "Price ID Starter" "" STRIPE_STARTER_PRICE_ID ask "Price ID Pro" "" STRIPE_PRO_PRICE_ID ask "Price ID Business" "" STRIPE_BUSINESS_PRICE_ID fi # =========================================== # RESUME # =========================================== echo "" echo -e "${CYAN}${BOLD}=========================================${NC}" echo -e "${CYAN}${BOLD} Resume de la configuration${NC}" echo -e "${CYAN}${BOLD}=========================================${NC}" echo "" echo -e " Domaine: ${BOLD}${DOMAIN}${NC}" echo -e " Traduction: ${BOLD}${TRANSLATION_SERVICE}${NC}" echo -e " DB User: ${BOLD}${POSTGRES_USER}${NC}" echo -e " Admin: ${BOLD}${ADMIN_USERNAME}${NC}" echo -e " Admin hash: ${BOLD}${ADMIN_PASSWORD_HASH:0:20}...${NC}" echo -e " JWT Secret: ${BOLD}${JWT_SECRET_KEY:0:20}...${NC}" echo -e " Admin Token: ${BOLD}${ADMIN_TOKEN_SECRET:0:20}...${NC}" echo -e " Grafana: ${BOLD}${GRAFANA_USER} / ${GRAFANA_PASSWORD}${NC}" echo "" if [ -n "$STRIPE_SECRET_KEY" ]; then echo -e " Stripe: ${GREEN}Configure${NC}" else echo -e " Stripe: ${YELLOW}Non configure${NC}" fi echo "" # Confirmation ask "Cette configuration est correcte ? (oui/non)" "oui" CONFIRM if [ "$CONFIRM" != "oui" ]; then echo "Annule. Relance le script pour recommencer." exit 0 fi # =========================================== # GENERATION DU FICHIER .env # =========================================== echo "" echo -e "${CYAN}Generation du fichier .env...${NC}" cat > "$ENV_FILE" < "$INFO_FILE" <