Fix: Remove hardcoded UUIDs and secrets from deploy scripts

- deploy.py: UUIDs from env vars or Coolify API lookup by name
- fast-deploy.sh: No hardcoded UUIDs, APP_DOMAIN from env
- docker-compose.yml: All secrets from env vars, no hardcoded values
- .env.example: All required vars documented
- Deleted obsolete fast-frontend-deploy.sh with hardcoded container name
This commit is contained in:
Agent Zero
2026-08-04 11:13:44 +02:00
parent e7edc46286
commit 7d3007b6c4
5 changed files with 633 additions and 359 deletions
+109 -44
View File
@@ -1,48 +1,94 @@
# LeoCRM v1.0 - Environment Variables Template # LeoCRM - Environment Variables Template
# Copy to .env and fill in real values.
# === REQUIRED === # === COOLIFY DEPLOYMENT (required for scripts/deploy.py) ===
DATABASE_URL=postgresql+asyncpg://crm_api:your_password@localhost:5432/crm_db # Coolify API token (required for deploy)
AUTH_DATABASE_URL=postgresql+asyncpg://crm_auth:your_password@localhost:5432/crm_db COOLIFY_API_TOKEN=
WORKER_DATABASE_URL=postgresql+asyncpg://crm_worker:your_password@localhost:5432/crm_db # Coolify base URL
MIGRATION_DATABASE_URL=postgresql+asyncpg://crm_migration:your_password@localhost:5432/crm_db COOLIFY_BASE_URL=https://server.media-on.de
REDIS_URL=redis://localhost:6379/0 # Application UUID (optional — resolved via API lookup by APP_NAME if absent)
COOLIFY_APP_UUID=
# Worker Service UUID (optional — resolved via API lookup by WORKER_NAME if absent)
COOLIFY_WORKER_UUID=
# Application name for API lookup
APP_NAME=leocrm-api
# Worker name for API lookup
WORKER_NAME=leocrm-worker
# App domain (required for deploy, used for health check and FQDN)
APP_DOMAIN=https://crm.media-on.de
# === REQUIRED for Docker/Production === # === COOLIFY INITIAL DEPLOY (only needed for --initial) ===
# Redis password (required in Docker) # Coolify project UUID
REDIS_PASSWORD=your_redis_password COOLIFY_PROJECT_UUID=
# Coolify server UUID
COOLIFY_SERVER_UUID=
# Coolify private key UUID (for Git deploy key)
COOLIFY_PRIVATE_KEY_UUID=
# Coolify environment name
COOLIFY_ENVIRONMENT=production
# === OPTIONAL (with defaults) === # === DATABASE (required) ===
# Single password for all DB roles (crm_user, crm_api, crm_auth, crm_worker, crm_migration)
DB_PASSWORD=
# Database name
POSTGRES_DB=crm_db
# Database user (superuser/owner)
POSTGRES_USER=crm_user
# Database host (container name in Docker network)
DB_HOST=crm-postgres
# Full database URLs (constructed from DB_PASSWORD/DB_HOST if not set explicitly)
DATABASE_URL=postgresql+asyncpg://crm_api:${DB_PASSWORD}@crm-postgres:5432/${POSTGRES_DB}
AUTH_DATABASE_URL=postgresql+asyncpg://crm_auth:${DB_PASSWORD}@crm-postgres:5432/${POSTGRES_DB}
WORKER_DATABASE_URL=postgresql+asyncpg://crm_worker:${DB_PASSWORD}@crm-postgres:5432/${POSTGRES_DB}
MIGRATION_DATABASE_URL=postgresql+asyncpg://crm_migration:${DB_PASSWORD}@crm-postgres:5432/${POSTGRES_DB}
# === REDIS (required) ===
REDIS_PASSWORD=
REDIS_HOST=crm-redis
REDIS_URL=redis://:${REDIS_PASSWORD}@crm-redis:6379/0
# === SECURITY (required) ===
# Secret key for signing, sessions (use a secure random string >= 32 chars)
SECRET_KEY=
# === SSH VERIFICATION (optional, deploy.py verification only) ===
SSH_KEY=/a0/usr/workdir/.ssh/coolify-01-root
SERVER_IP=46.225.91.159
# Login test credentials (optional, for deploy verification)
LOGIN_EMAIL=
LOGIN_PASSWORD=
# === APPLICATION ===
# Environment: development | production | testing # Environment: development | production | testing
ENVIRONMENT=development ENVIRONMENT=production
# Log level: DEBUG | INFO | WARNING | ERROR # Log level: DEBUG | INFO | WARNING | ERROR
LOG_LEVEL=INFO LOG_LEVEL=INFO
# Database pool
DB_POOL_SIZE=10
DB_MAX_OVERFLOW=20
DB_ECHO=false
# Session settings
SESSION_TTL_SECONDS=28800
SESSION_COOKIE_NAME=leocrm_session
SESSION_COOKIE_SECURE=false
SESSION_COOKIE_SAMESITE=strict
SESSION_COOKIE_HTTPONLY=true
# Password hashing
BCRYPT_ROUNDS=12
PASSWORD_RESET_EXPIRY_HOURS=1
# CORS allowed origins (comma-separated, NO wildcards) # CORS allowed origins (comma-separated, NO wildcards)
CORS_ORIGINS=http://localhost:5173,http://localhost:3000 CORS_ORIGINS=https://crm.media-on.de
# Frontend URL
FRONTEND_URL=https://crm.media-on.de
# Session cookie secure (true in production)
SESSION_COOKIE_SECURE=true
# Secret Key (for signing, sessions — use a secure random string ≥32 chars in prod) # === DOCKER COMPOSE (optional overrides) ===
SECRET_KEY=change-me-in-production-use-a-secure-random-string # Container names
POSTGRES_CONTAINER_NAME=crm-postgres
REDIS_CONTAINER_NAME=crm-redis
APP_CONTAINER_NAME=crm-app
WORKER_CONTAINER_NAME=crm-worker
# Volume names
PGDATA_VOLUME_NAME=crm_pgdata
REDISDATA_VOLUME_NAME=crm_redisdata
STORAGE_VOLUME_NAME=crm_storage
# Network names
CRM_NETWORK_NAME=crm-net
COOLIFY_NETWORK_NAME=coolify
# Traefik host
APP_HOST=crm.media-on.de
APP_PORT=8000
# Storage (file uploads, DMS) # === STORAGE ===
STORAGE_PATH=/tmp STORAGE_PATH=/data/storage
# Storage backend: local (default) or s3 # Storage backend: local (default) or s3
STORAGE_BACKEND=local STORAGE_BACKEND=local
# S3-compatible storage (when STORAGE_BACKEND=s3) # S3-compatible storage (when STORAGE_BACKEND=s3)
@@ -53,15 +99,15 @@ S3_SECRET_KEY=
S3_REGION=us-east-1 S3_REGION=us-east-1
S3_SECURE=true S3_SECURE=true
# SMTP / Email # === SMTP / EMAIL ===
SMTP_HOST=localhost SMTP_HOST=localhost
SMTP_PORT=587 SMTP_PORT=587
SMTP_USERNAME= SMTP_USER=
SMTP_PASSWORD= SMTP_PASSWORD=
SMTP_FROM_EMAIL=noreply@leocrm.local SMTP_FROM=no-reply@localhost
SMTP_USE_TLS=true SMTP_TLS=true
# Rate limiting # === RATE LIMITING ===
RATE_LIMIT_LOGIN_MAX=5 RATE_LIMIT_LOGIN_MAX=5
RATE_LIMIT_LOGIN_WINDOW=900 RATE_LIMIT_LOGIN_WINDOW=900
RATE_LIMIT_RESET_MAX=3 RATE_LIMIT_RESET_MAX=3
@@ -71,10 +117,29 @@ RATE_LIMIT_RESET_CONFIRM_WINDOW=3600
RATE_LIMIT_GENERAL_MAX=60 RATE_LIMIT_GENERAL_MAX=60
RATE_LIMIT_GENERAL_WINDOW=60 RATE_LIMIT_GENERAL_WINDOW=60
# === AI / Search === # === DATABASE POOL ===
# Ollama Cloud API Key (für LiteLLM) DB_POOL_SIZE=10
DB_MAX_OVERFLOW=20
DB_ECHO=false
# === SESSION ===
SESSION_TTL_SECONDS=28800
SESSION_COOKIE_NAME=leocrm_session
SESSION_COOKIE_SAMESITE=strict
SESSION_COOKIE_HTTPONLY=true
# === PASSWORD HASHING ===
BCRYPT_ROUNDS=12
PASSWORD_RESET_EXPIRY_HOURS=1
# === AI / SEARCH ===
# Ollama Cloud API Key (for LiteLLM)
API_KEY_OLLAMA_CLOUD= API_KEY_OLLAMA_CLOUD=
# Embedding Modell (default: ollama/nomic-embed-text) # Embedding model (default: ollama/nomic-embed-text)
SEARCH_EMBEDDING_MODEL=ollama/nomic-embed-text SEARCH_EMBEDDING_MODEL=ollama/nomic-embed-text
# LLM Modell für Query Understanding (default: ollama/deepseek-v4) # LLM model for query understanding (default: ollama/deepseek-v4)
SEARCH_LLM_MODEL=ollama/deepseek-v4 SEARCH_LLM_MODEL=ollama/deepseek-v4
# === GIT (for initial deployment) ===
API_GIT_REPO=https://forgejo.media-on.de/Leopoldadmin/leocrm.git
API_GIT_BRANCH=main
+27 -25
View File
@@ -14,10 +14,12 @@
# - RLS policy enforcement # - RLS policy enforcement
# - Health & domain verification # - Health & domain verification
# #
# No hardcoded secrets, UUIDs, or domains — everything from environment.
#
# Usage (local testing): # Usage (local testing):
# cp .env.docker.example .env.docker # cp .env.example .env
# $EDITOR .env.docker # fill SECRET_KEY, POSTGRES_PASSWORD, ... # $EDITOR .env # fill SECRET_KEY, DB_PASSWORD, REDIS_PASSWORD, ...
# docker compose --env-file .env.docker up --build # docker compose up --build
# curl http://localhost:8000/api/v1/health # curl http://localhost:8000/api/v1/health
# ============================================================================= # =============================================================================
@@ -25,11 +27,11 @@ services:
# ── PostgreSQL 16 with pgvector ───────────────────────────────────── # ── PostgreSQL 16 with pgvector ─────────────────────────────────────
postgres: postgres:
image: pgvector/pgvector:pg16 image: pgvector/pgvector:pg16
container_name: crm-postgres container_name: ${POSTGRES_CONTAINER_NAME:-crm-postgres}
restart: unless-stopped restart: unless-stopped
environment: environment:
POSTGRES_USER: ${POSTGRES_USER:-crm_user} POSTGRES_USER: ${POSTGRES_USER:-crm_user}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required} POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD is required}
POSTGRES_DB: ${POSTGRES_DB:-crm_db} POSTGRES_DB: ${POSTGRES_DB:-crm_db}
PGDATA: /var/lib/postgresql/data/pgdata PGDATA: /var/lib/postgresql/data/pgdata
volumes: volumes:
@@ -53,7 +55,7 @@ services:
# ── Redis 7 (sessions, rate limiting, ARQ queue) ──────────────────── # ── Redis 7 (sessions, rate limiting, ARQ queue) ────────────────────
redis: redis:
image: redis:7-alpine image: redis:7-alpine
container_name: crm-redis container_name: ${REDIS_CONTAINER_NAME:-crm-redis}
restart: unless-stopped restart: unless-stopped
command: redis-server --requirepass ${REDIS_PASSWORD:?REDIS_PASSWORD is required} command: redis-server --requirepass ${REDIS_PASSWORD:?REDIS_PASSWORD is required}
volumes: volumes:
@@ -73,15 +75,15 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: crm-app container_name: ${APP_CONTAINER_NAME:-crm-app}
restart: unless-stopped restart: unless-stopped
labels: labels:
- traefik.enable=true - traefik.enable=true
- traefik.http.routers.crm.rule=Host(`crm.media-on.de`) - traefik.http.routers.crm.rule=Host(`${APP_HOST:-crm.media-on.de}`)
- traefik.http.routers.crm.entryPoints=http,https - traefik.http.routers.crm.entryPoints=http,https
- traefik.http.routers.crm.tls=true - traefik.http.routers.crm.tls=true
- traefik.http.routers.crm.tls.certresolver=letsencrypt - traefik.http.routers.crm.tls.certresolver=letsencrypt
- traefik.http.services.crm.loadbalancer.server.port=8000 - traefik.http.services.crm.loadbalancer.server.port=${APP_PORT:-8000}
networks: networks:
- crm-net - crm-net
- coolify - coolify
@@ -92,15 +94,15 @@ services:
condition: service_healthy condition: service_healthy
environment: environment:
# API uses crm_api (NOSUPERUSER, NOBYPASSRLS) — RLS enforced # API uses crm_api (NOSUPERUSER, NOBYPASSRLS) — RLS enforced
DATABASE_URL: ${DATABASE_URL:?DATABASE_URL is required} DATABASE_URL: ${DATABASE_URL:-postgresql+asyncpg://crm_api:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
# Auth uses crm_auth (NOSUPERUSER, NOBYPASSRLS) — identity tables only # Auth uses crm_auth (NOSUPERUSER, NOBYPASSRLS) — identity tables only
AUTH_DATABASE_URL: ${AUTH_DATABASE_URL:-postgresql+asyncpg://crm_auth:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}} AUTH_DATABASE_URL: ${AUTH_DATABASE_URL:-postgresql+asyncpg://crm_auth:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
# Migration/DDL uses crm_migration (owner, NOBYPASSRLS) # Migration/DDL uses crm_migration (owner, NOBYPASSRLS)
MIGRATION_DATABASE_URL: ${MIGRATION_DATABASE_URL:-postgresql+asyncpg://crm_migration:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}} MIGRATION_DATABASE_URL: ${MIGRATION_DATABASE_URL:-postgresql+asyncpg://crm_migration:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
REDIS_URL: ${REDIS_URL:-redis://:${REDIS_PASSWORD}@redis:6379/0} REDIS_URL: ${REDIS_URL:-redis://:${REDIS_PASSWORD}@redis:6379/0}
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY is required (min 32 chars)} SECRET_KEY: ${SECRET_KEY:?SECRET_KEY is required (min 32 chars)}
CORS_ORIGINS: ${CORS_ORIGINS:-https://crm.media-on.de} CORS_ORIGINS: ${CORS_ORIGINS:-${APP_DOMAIN:-http://localhost:8000}}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:8000} FRONTEND_URL: ${FRONTEND_URL:-${APP_DOMAIN:-http://localhost:8000}}
ENVIRONMENT: ${ENVIRONMENT:-production} ENVIRONMENT: ${ENVIRONMENT:-production}
LOG_LEVEL: ${LOG_LEVEL:-INFO} LOG_LEVEL: ${LOG_LEVEL:-INFO}
SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-true} SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-true}
@@ -125,7 +127,7 @@ services:
volumes: volumes:
- storage:/data/storage - storage:/data/storage
healthcheck: healthcheck:
test: ["CMD", "curl", "-fsS", "http://localhost:8000/api/v1/health"] test: ["CMD", "curl", "-fsS", "http://localhost:${APP_PORT:-8000}/api/v1/health"]
interval: 30s interval: 30s
timeout: 10s timeout: 10s
retries: 3 retries: 3
@@ -141,7 +143,7 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile dockerfile: Dockerfile
container_name: crm-worker container_name: ${WORKER_CONTAINER_NAME:-crm-worker}
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
postgres: postgres:
@@ -162,12 +164,12 @@ services:
cpus: "1.0" cpus: "1.0"
environment: environment:
# Worker uses crm_worker (NOSUPERUSER, NOBYPASSRLS) — RLS enforced # Worker uses crm_worker (NOSUPERUSER, NOBYPASSRLS) — RLS enforced
DATABASE_URL: ${WORKER_DATABASE_URL:-${DATABASE_URL:?DATABASE_URL is required}} DATABASE_URL: ${WORKER_DATABASE_URL:-postgresql+asyncpg://crm_worker:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
WORKER_DATABASE_URL: ${WORKER_DATABASE_URL:-postgresql+asyncpg://crm_worker:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}} WORKER_DATABASE_URL: ${WORKER_DATABASE_URL:-postgresql+asyncpg://crm_worker:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
MIGRATION_DATABASE_URL: ${MIGRATION_DATABASE_URL:-postgresql+asyncpg://crm_migration:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}} MIGRATION_DATABASE_URL: ${MIGRATION_DATABASE_URL:-postgresql+asyncpg://crm_migration:${DB_PASSWORD}@postgres:5432/${POSTGRES_DB:-crm_db}}
REDIS_URL: ${REDIS_URL:-redis://:${REDIS_PASSWORD}@redis:6379/0} REDIS_URL: ${REDIS_URL:-redis://:${REDIS_PASSWORD}@redis:6379/0}
SECRET_KEY: ${SECRET_KEY:?SECRET_KEY is required (min 32 chars)} SECRET_KEY: ${SECRET_KEY:?SECRET_KEY is required (min 32 chars)}
FRONTEND_URL: ${FRONTEND_URL:-http://localhost:8000} FRONTEND_URL: ${FRONTEND_URL:-${APP_DOMAIN:-http://localhost:8000}}
ENVIRONMENT: ${ENVIRONMENT:-production} ENVIRONMENT: ${ENVIRONMENT:-production}
LOG_LEVEL: ${LOG_LEVEL:-INFO} LOG_LEVEL: ${LOG_LEVEL:-INFO}
SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-true} SESSION_COOKIE_SECURE: ${SESSION_COOKIE_SECURE:-true}
@@ -191,16 +193,16 @@ services:
volumes: volumes:
pgdata: pgdata:
name: crm_pgdata name: ${PGDATA_VOLUME_NAME:-crm_pgdata}
redisdata: redisdata:
name: crm_redisdata name: ${REDISDATA_VOLUME_NAME:-crm_redisdata}
storage: storage:
name: crm_storage name: ${STORAGE_VOLUME_NAME:-crm_storage}
networks: networks:
crm-net: crm-net:
name: crm-net name: ${CRM_NETWORK_NAME:-crm-net}
driver: bridge driver: bridge
coolify: coolify:
name: coolify name: ${COOLIFY_NETWORK_NAME:-coolify}
external: true external: true
+414 -246
View File
File diff suppressed because it is too large Load Diff
+78 -11
View File
@@ -4,36 +4,103 @@
# bash scripts/fast-deploy.sh frontend # Frontend-only: build + copy (~20s) # bash scripts/fast-deploy.sh frontend # Frontend-only: build + copy (~20s)
# bash scripts/fast-deploy.sh full # Full: Coolify rebuild (~2min) # bash scripts/fast-deploy.sh full # Full: Coolify rebuild (~2min)
# Default: frontend # Default: frontend
#
# Environment variables:
# COOLIFY_API_TOKEN — Coolify API token (required for full deploy)
# COOLIFY_BASE_URL — Coolify base URL (default: https://server.media-on.de)
# COOLIFY_APP_UUID — Application UUID (optional, resolved via API if absent)
# APP_NAME — Application name for API lookup (default: leocrm-api)
# APP_DOMAIN — App domain (required for full deploy, e.g. https://crm.media-on.de)
# SSH_KEY — SSH key path (default: /a0/usr/workdir/.ssh/coolify-01-root)
# SERVER_IP — Server IP (default: 46.225.91.159)
set -euo pipefail set -euo pipefail
SERVER="root@46.225.91.159"
SSH_KEY="${SSH_KEY:-/a0/usr/workdir/.ssh/coolify-01-root}" SSH_KEY="${SSH_KEY:-/a0/usr/workdir/.ssh/coolify-01-root}"
SERVER_IP="${SERVER_IP:-46.225.91.159}"
SERVER="root@${SERVER_IP}"
SSH_OPTS="-o StrictHostKeyChecking=no -i $SSH_KEY" SSH_OPTS="-o StrictHostKeyChecking=no -i $SSH_KEY"
MODE="${1:-frontend}" MODE="${1:-frontend}"
cd /a0/usr/workdir/leocrm-fix # Resolve repo root from script location
cd "$(dirname "$0")/.."
REPO_ROOT="$(pwd)"
# ─── Helper: Resolve app UUID via Coolify API ────────────────────────
resolve_app_uuid() {
local token="${COOLIFY_API_TOKEN:-}"
local base_url="${COOLIFY_BASE_URL:-https://server.media-on.de}"
local app_name="${APP_NAME:-leocrm-api}"
if [ -z "$token" ]; then
echo "ERROR: COOLIFY_API_TOKEN not set" >&2
return 1
fi
curl -sS -H "Authorization: Bearer $token" \
"${base_url}/api/v1/applications" \
| python3 -c "
import sys, json
apps = json.load(sys.stdin)
for app in apps:
if app.get('name') == '${app_name}':
print(app.get('uuid', ''))
break
" 2>/dev/null
}
# ─── Full Deploy ─────────────────────────────────────────────────────
if [ "$MODE" = "full" ]; then if [ "$MODE" = "full" ]; then
echo "[Full Deploy] Triggering Coolify rebuild..." echo "[Full Deploy] Triggering Coolify rebuild..."
COOLIFY_API_TOKEN="${COOLIFY_API_TOKEN:-}" \
COOLIFY_APP_UUID='stvabl4vaqru7jclx4ittzr3' \ if [ -z "${COOLIFY_API_TOKEN:-}" ]; then
COOLIFY_BASE_URL='https://server.media-on.de' \ echo "ERROR: COOLIFY_API_TOKEN not set" >&2
exit 1
fi
if [ -z "${APP_DOMAIN:-}" ]; then
echo "ERROR: APP_DOMAIN not set (e.g. https://crm.media-on.de)" >&2
exit 1
fi
COOLIFY_API_TOKEN="$COOLIFY_API_TOKEN" \
COOLIFY_BASE_URL="${COOLIFY_BASE_URL:-https://server.media-on.de}" \
COOLIFY_APP_UUID="${COOLIFY_APP_UUID:-}" \
COOLIFY_WORKER_UUID="${COOLIFY_WORKER_UUID:-}" \
APP_NAME="${APP_NAME:-leocrm-api}" \
WORKER_NAME="${WORKER_NAME:-leocrm-worker}" \
APP_DOMAIN="$APP_DOMAIN" \
SSH_KEY="$SSH_KEY" \ SSH_KEY="$SSH_KEY" \
SERVER_IP='46.225.91.159' \ SERVER_IP="$SERVER_IP" \
/opt/venv/bin/python scripts/deploy.py /opt/venv/bin/python "$REPO_ROOT/scripts/deploy.py"
exit 0 exit 0
fi fi
# Frontend-only fast deploy # ─── Frontend-only Fast Deploy ──────────────────────────────────────
# Resolve app UUID
APP_UUID="${COOLIFY_APP_UUID:-}"
if [ -z "$APP_UUID" ]; then
if [ -z "${COOLIFY_API_TOKEN:-}" ]; then
echo "ERROR: COOLIFY_APP_UUID or COOLIFY_API_TOKEN must be set" >&2
exit 1
fi
echo "[1/6] Resolving app UUID via Coolify API..."
APP_UUID="$(resolve_app_uuid)"
if [ -z "$APP_UUID" ]; then
echo "ERROR: Could not resolve app UUID" >&2
exit 1
fi
echo " App UUID: $APP_UUID"
fi
echo "[1/5] Building frontend..." echo "[1/5] Building frontend..."
cd frontend cd "$REPO_ROOT/frontend"
npm run build 2>&1 | tail -3 npm run build 2>&1 | tail -3
echo "[2/5] Finding container..." echo "[2/5] Finding container..."
CONTAINER=$(ssh $SSH_OPTS $SERVER 'docker ps --format "{{.Names}}" | grep "^stvabl4vaqru7jclx4ittzr3-" | head -1') CONTAINER=$(ssh $SSH_OPTS $SERVER "docker ps --format '{{.Names}}' | grep '^${APP_UUID}-' | head -1")
if [ -z "$CONTAINER" ]; then if [ -z "$CONTAINER" ]; then
echo "ERROR: Could not find app container" echo "ERROR: Could not find app container with prefix ${APP_UUID}-" >&2
exit 1 exit 1
fi fi
echo " Container: $CONTAINER" echo " Container: $CONTAINER"
-28
View File
@@ -1,28 +0,0 @@
#!/usr/bin/env bash
# Fast frontend-only deploy: build locally, copy to container, restart.
# Usage: bash scripts/fast-frontend-deploy.sh
# Skips Coolify rebuild entirely. ~20s total instead of ~2min.
set -euo pipefail
CONTAINER="stvabl4vaqru7jclx4ittzr3-153149570355"
SERVER="root@46.225.91.159"
SSH_KEY="${SSH_KEY:-/a0/usr/workdir/.ssh/coolify-01-root}"
SSH_OPTS="-o StrictHostKeyChecking=no -i $SSH_KEY"
echo "[1/4] Building frontend..."
cd /a0/usr/workdir/leocrm-fix/frontend
npm run build 2>&1 | tail -3
echo "[2/4] Packaging & uploading..."
tar czf /tmp/frontend-dist.tar.gz -C dist .
scp $SSH_OPTS /tmp/frontend-dist.tar.gz $SERVER:/tmp/frontend-dist.tar.gz
echo "[3/4] Copying into container..."
ssh $SSH_OPTS $SERVER "docker cp /tmp/frontend-dist.tar.gz $CONTAINER:/tmp/ && docker exec $CONTAINER sh -c 'cd /app/frontend/dist && tar xzf /tmp/frontend-dist.tar.gz --overwrite && rm /tmp/frontend-dist.tar.gz' && rm /tmp/frontend-dist.tar.gz"
echo "[4/4] Restarting container (clears service worker cache)..."
ssh $SSH_OPTS $SERVER "docker restart $CONTAINER" 2>/dev/null || true
sleep 3
echo "✅ Fast deploy done (~20s). Container restarted."