#!/bin/bash set -euo pipefail echo "═══════════════════════════════════════════════════════" echo " Mosaic Stack - Interactive Setup Wizard" echo "═══════════════════════════════════════════════════════" echo "" # Backup existing .env if it exists if [ -f .env ]; then BACKUP=".env.bak.$(date +%Y%m%d_%H%M%S)" cp .env "$BACKUP" echo "✓ Backed up existing .env to $BACKUP" echo "" fi # Start with .env.example as base if [ ! -f .env ]; then cp .env.example .env fi # Helper function to update or add env var update_env() { local key=$1 local value=$2 if grep -q "^$key=" .env; then sed -i "s|^$key=.*|$key=$value|" .env else echo "$key=$value" >> .env fi } echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Domain Configuration" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" read -p "Web domain [app.mosaicstack.dev]: " WEB_DOMAIN WEB_DOMAIN=${WEB_DOMAIN:-app.mosaicstack.dev} update_env "MOSAIC_WEB_DOMAIN" "$WEB_DOMAIN" read -p "API domain [api.mosaicstack.dev]: " API_DOMAIN API_DOMAIN=${API_DOMAIN:-api.mosaicstack.dev} update_env "MOSAIC_API_DOMAIN" "$API_DOMAIN" # Update NEXT_PUBLIC_API_URL to use the configured domain update_env "NEXT_PUBLIC_API_URL" "https://$API_DOMAIN" update_env "MOSAIC_BASE_URL" "https://$WEB_DOMAIN" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Authentication Configuration" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" read -p "Authentik OIDC Issuer URL: " OIDC_ISSUER if [ -n "$OIDC_ISSUER" ]; then update_env "OIDC_ISSUER" "$OIDC_ISSUER" fi read -p "OIDC Client ID: " OIDC_CLIENT_ID if [ -n "$OIDC_CLIENT_ID" ]; then update_env "OIDC_CLIENT_ID" "$OIDC_CLIENT_ID" fi read -sp "OIDC Client Secret: " OIDC_CLIENT_SECRET echo "" if [ -n "$OIDC_CLIENT_SECRET" ]; then update_env "OIDC_CLIENT_SECRET" "$OIDC_CLIENT_SECRET" fi # Auto-set redirect URI REDIRECT_URI="https://${API_DOMAIN}/auth/callback/authentik" update_env "OIDC_REDIRECT_URI" "$REDIRECT_URI" echo "✓ Set redirect URI to: $REDIRECT_URI" echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " AI Provider Configuration" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "Choose AI provider for orchestrator agents:" echo " 1) Ollama (local or remote) - Recommended for self-hosted" echo " 2) Claude API (requires API key)" echo " 3) OpenAI API (requires API key)" echo " 4) Skip (configure manually later)" echo "" read -p "Select [1]: " AI_CHOICE AI_CHOICE=${AI_CHOICE:-1} case $AI_CHOICE in 1) echo "" read -p "Ollama endpoint [http://localhost:11434]: " OLLAMA_ENDPOINT OLLAMA_ENDPOINT=${OLLAMA_ENDPOINT:-http://localhost:11434} update_env "OLLAMA_ENDPOINT" "$OLLAMA_ENDPOINT" update_env "OLLAMA_MODE" "remote" read -p "Ollama model for orchestrator [llama3.1:latest]: " OLLAMA_MODEL OLLAMA_MODEL=${OLLAMA_MODEL:-llama3.1:latest} update_env "OLLAMA_MODEL" "$OLLAMA_MODEL" update_env "AI_PROVIDER" "ollama" echo "✓ Configured Ollama at $OLLAMA_ENDPOINT" echo " Note: Claude API key is NOT required for Ollama mode" ;; 2) echo "" read -sp "Claude API Key: " CLAUDE_API_KEY echo "" if [ -n "$CLAUDE_API_KEY" ]; then update_env "CLAUDE_API_KEY" "$CLAUDE_API_KEY" update_env "AI_PROVIDER" "claude" echo "✓ Configured Claude API" fi ;; 3) echo "" read -sp "OpenAI API Key: " OPENAI_API_KEY echo "" if [ -n "$OPENAI_API_KEY" ]; then update_env "OPENAI_API_KEY" "$OPENAI_API_KEY" update_env "AI_PROVIDER" "openai" echo "✓ Configured OpenAI API" fi ;; 4) echo "✓ Skipping AI provider configuration" update_env "AI_PROVIDER" "ollama" echo " Defaulting to Ollama (configure OLLAMA_ENDPOINT in .env)" ;; esac echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Security Configuration" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" # Generate secrets if not present or contain REPLACE echo "Generating security secrets..." if ! grep -q "^JWT_SECRET=" .env || grep -q "REPLACE" .env; then JWT_SECRET=$(openssl rand -base64 32) update_env "JWT_SECRET" "$JWT_SECRET" echo "✓ Generated JWT_SECRET" fi if ! grep -q "^ENCRYPTION_KEY=" .env || grep -q "REPLACE" .env; then ENCRYPTION_KEY=$(openssl rand -hex 32) update_env "ENCRYPTION_KEY" "$ENCRYPTION_KEY" echo "✓ Generated ENCRYPTION_KEY" fi if ! grep -q "^BETTER_AUTH_SECRET=" .env || grep -q "REPLACE" .env; then BETTER_AUTH_SECRET=$(openssl rand -base64 32) update_env "BETTER_AUTH_SECRET" "$BETTER_AUTH_SECRET" echo "✓ Generated BETTER_AUTH_SECRET" fi echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Database Configuration" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" if ! grep -q "^POSTGRES_PASSWORD=" .env || grep -q "REPLACE" .env; then echo "Generate new PostgreSQL password? (recommended for new installations)" read -p "[y/N]: " GEN_DB_PASS if [[ $GEN_DB_PASS =~ ^[Yy]$ ]]; then POSTGRES_PASSWORD=$(openssl rand -base64 24) update_env "POSTGRES_PASSWORD" "$POSTGRES_PASSWORD" # Update DATABASE_URL update_env "DATABASE_URL" "postgresql://mosaic:${POSTGRES_PASSWORD}@postgres:5432/mosaic" echo "✓ Generated PostgreSQL password" else echo "✓ Keeping existing PostgreSQL password" fi else echo "✓ Using existing PostgreSQL password" fi echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo " Traefik Configuration" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "Use external Traefik instance? [Y/n]: " read -p "" USE_EXTERNAL_TRAEFIK USE_EXTERNAL_TRAEFIK=${USE_EXTERNAL_TRAEFIK:-Y} if [[ $USE_EXTERNAL_TRAEFIK =~ ^[Yy]$ ]]; then update_env "TRAEFIK_MODE" "upstream" update_env "TRAEFIK_NETWORK" "traefik-public" echo "✓ Configured for upstream Traefik" else update_env "TRAEFIK_MODE" "bundled" echo "✓ Configured for bundled Traefik" fi echo "" echo "═══════════════════════════════════════════════════════" echo " Configuration Complete!" echo "═══════════════════════════════════════════════════════" echo "" echo "Configuration saved to .env" echo "" echo "Next steps:" echo " 1. Review .env file: nano .env" echo " 2. Deploy stack:" if [ -f deploy-swarm.sh ]; then echo " ./deploy-swarm.sh mosaic" else echo " docker compose up -d" fi echo "" echo "Services will be available at:" echo " Web: https://$WEB_DOMAIN" echo " API: https://$API_DOMAIN" echo ""