#!/usr/bin/env bash # deploy_dashboard_api.sh — PROD dashboard_api bridge (fleetapi.rahamafresh.com). # Standalone Traefik-labelled bridge (NOT Coolify-managed): reuses the # webhook_receiver image + app network, bind-mounts the WIP API file. An env/CORS # change needs a container RECREATE (this script does that). # # Stage-2 least privilege: the request pool connects as the READ-ONLY dashboard_ro # role (DATABASE_URL), while the v_trips refresher keeps the privileged app role # (REFRESH_DATABASE_URL) — REFRESH needs write perms that dashboard_ro lacks. set -euo pipefail WH=$(docker ps --filter name=webhook_receiver --format "{{.Names}}" | head -1) IMG=$(docker inspect "$WH" --format "{{.Image}}") APPNET=$(docker inspect "$WH" --format '{{range $k,$v := .NetworkSettings.Networks}}{{$k}}{{end}}') echo "Reusing image $IMG on network $APPNET (from $WH)" mkdir -p /home/kianiadee/dashboard_api # Stage a fresh copy only if one was scp'd to ~; otherwise keep the existing mount. if [ -f /home/kianiadee/dashboard_api_rev.py ]; then mv -f /home/kianiadee/dashboard_api_rev.py /home/kianiadee/dashboard_api/dashboard_api_rev.py fi test -f /home/kianiadee/dashboard_api/dashboard_api_rev.py \ || { echo "ERROR: dashboard_api_rev.py missing in mount dir; scp it to ~ first"; exit 1; } # Reuse the webhook container's env, stripping runtime noise AND any inherited # DATABASE_URL + DASHBOARD_CORS_ORIGINS (both set explicitly below). docker inspect "$WH" --format '{{range .Config.Env}}{{println .}}{{end}}' \ | grep -vE '^(PATH=|HOSTNAME=|HOME=|PWD=|TERM=|SHLVL=|_=|LANG=|GPG_KEY=|PYTHON_VERSION=|PYTHON_PIP_VERSION=|PYTHONUNBUFFERED=|DATABASE_URL=|DASHBOARD_CORS_ORIGINS=)' \ > /home/kianiadee/dashboard_api/dapi.env echo 'DASHBOARD_CORS_ORIGINS=https://liveposition.rahamafresh.com,https://fleetintelligence.rahamafresh.com,https://fleetnow.rahamafresh.com,https://fleetops.rahamafresh.com' \ >> /home/kianiadee/dashboard_api/dapi.env # Split roles: REFRESH_DATABASE_URL = the inherited privileged URL (for the # refresher); DATABASE_URL = read-only dashboard_ro (for request handling). SRC_DB_URL=$(docker inspect "$WH" --format '{{range .Config.Env}}{{println .}}{{end}}' | sed -n 's/^DATABASE_URL=//p' | head -1) RO_PW=$(cat /home/kianiadee/.dashboard_ro.pw 2>/dev/null || true) [ -n "$SRC_DB_URL" ] || { echo "ERROR: DATABASE_URL not found in $WH env"; exit 1; } [ -n "$RO_PW" ] || { echo "ERROR: ~/.dashboard_ro.pw missing — run bootstrap_dashboard_ro.sh first"; exit 1; } HOSTPART="${SRC_DB_URL#*@}" { echo "REFRESH_DATABASE_URL=${SRC_DB_URL}" echo "DATABASE_URL=postgresql://dashboard_ro:${RO_PW}@${HOSTPART}" } >> /home/kianiadee/dashboard_api/dapi.env chmod 600 /home/kianiadee/dashboard_api/dapi.env docker rm -f dashboard_api 2>/dev/null || true docker run -d --name dashboard_api --restart unless-stopped \ --network "$APPNET" \ --env-file /home/kianiadee/dashboard_api/dapi.env \ -v /home/kianiadee/dashboard_api/dashboard_api_rev.py:/app/dashboard_api_rev.py:ro \ --label 'traefik.enable=true' \ --label 'traefik.docker.network=coolify' \ --label 'traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https' \ --label 'traefik.http.routers.http-0-fleetapi.entryPoints=http' \ --label 'traefik.http.routers.http-0-fleetapi.middlewares=redirect-to-https' \ --label 'traefik.http.routers.http-0-fleetapi.rule=Host(`fleetapi.rahamafresh.com`)' \ --label 'traefik.http.routers.https-0-fleetapi.entryPoints=https' \ --label 'traefik.http.routers.https-0-fleetapi.rule=Host(`fleetapi.rahamafresh.com`)' \ --label 'traefik.http.routers.https-0-fleetapi.tls=true' \ --label 'traefik.http.routers.https-0-fleetapi.tls.certresolver=letsencrypt' \ --label 'traefik.http.services.fleetapi.loadbalancer.server.port=8890' \ "$IMG" sh -c 'uvicorn dashboard_api_rev:app --host 0.0.0.0 --port 8890 --workers 2' docker network connect coolify dashboard_api 2>/dev/null || true sleep 8 echo "== container =="; docker ps --filter name=dashboard_api --format "{{.Names}} | {{.Status}}" echo "== CORS origins in effect =="; docker exec dashboard_api printenv DASHBOARD_CORS_ORIGINS echo "== request role (expect dashboard_ro) =="; docker exec dashboard_api sh -lc 'printenv DATABASE_URL | sed -E "s#://([^:]+):[^@]+@#://\1:@#"' echo "== refresh role set? =="; docker exec dashboard_api sh -lc 'printenv REFRESH_DATABASE_URL | sed -E "s#://([^:]+):[^@]+@#://\1:@#"' echo "== internal health =="; docker exec dashboard_api sh -lc 'curl -s http://localhost:8890/health' 2>&1 | head || true