#!/usr/bin/env bash # Docker entrypoint for CrowdSight production image. # # Runs database migrations to head BEFORE starting any service, so that the # backend (gunicorn) and the durable worker never query tables that do not # exist yet (fixes worker crash-loop: "no such table: jobs"). # # - Require DATABASE_URL to be set (fail fast with a clear message). # - Run `alembic upgrade head` (idempotent; no-ops when already at head). # - Then exec supervisord to run nginx + backend + worker. set -euo pipefail cd /app/backend if [[ -z "${DATABASE_URL:-}" ]]; then echo "[entrypoint] FATAL: DATABASE_URL is not set. Refusing to start." >&2 exit 1 fi # If DATABASE_URL points at Postgres, fail fast with a clear message if the # psycopg driver is missing (instead of a confusing SQLAlchemy # NoSuchModuleError inside alembic). if [[ "$DATABASE_URL" == postgres* ]]; then if ! uv run --frozen python -c "import psycopg" 2>/dev/null; then echo "[entrypoint] FATAL: DATABASE_URL is PostgreSQL but the psycopg driver is not installed in this image. Rebuild the image so 'uv sync' installs psycopg[binary]." >&2 exit 1 fi fi echo "[entrypoint] Running database migrations (alembic upgrade head)..." uv run --frozen alembic upgrade head echo "[entrypoint] Migrations complete." # Idempotent first-admin bootstrap. Only runs when ADMIN_EMAIL and # ADMIN_PASSWORD are provided; it creates/updates a super_admin user and org # (never overwrites an existing password). Optional in the image so a deployed # container can self-provision its first super_admin on startup. if [[ -n "${ADMIN_EMAIL:-}" && -n "${ADMIN_PASSWORD:-}" ]]; then echo "[entrypoint] Bootstrapping first super_admin (${ADMIN_EMAIL})..." uv run --frozen python scripts/bootstrap_super_admin.py \ --email "${ADMIN_EMAIL}" --password "${ADMIN_PASSWORD}" \ --org "${ADMIN_ORG_NAME:-Acme}" --slug "${ADMIN_ORG_SLUG:-}" echo "[entrypoint] super_admin bootstrap complete." else echo "[entrypoint] ADMIN_EMAIL/ADMIN_PASSWORD not set; skipping auto bootstrap." fi echo "[entrypoint] Starting supervisord (nginx + backend + worker)..." exec /usr/bin/supervisord -n