#!/bin/sh # One image, several roles. Called as: entrypoint [args...] # # api uvicorn, behind the `web` nginx container # worker-sync lease-owned account sync supervisor (SPEC ยง6.3) # worker-jobs arq consumer (interactive + bulk queues) # worker-all both in one process (small installs; halves RAM use) # migrate core Alembic upgrade + per-plugin install; exits 0 when done # reindex rebuild the search index from Postgres # plugins `python -m app.plugins.cli ...` passthrough # shell /bin/sh (debugging) # # Any other argument is exec'd verbatim, so `docker compose run api python -c ...` # still works. set -eu : "${API_HOST:=0.0.0.0}" : "${API_PORT:=8000}" : "${API_WORKERS:=1}" # Plugins whose migrations are applied on every `migrate` run. Space-separated so # an operator can add a third-party plugin without editing the image. : "${ENABLED_PLUGINS:=calendar contacts labels filters}" cmd="${1:-api}" [ "$#" -gt 0 ] && shift || true run_migrations() { echo "[entrypoint] core schema: alembic upgrade head" alembic upgrade head for plugin in $ENABLED_PLUGINS; do echo "[entrypoint] plugin schema: $plugin" python -m app.plugins.cli install "$plugin" done echo "[entrypoint] migrations complete" } case "$cmd" in api) # --proxy-headers + --forwarded-allow-ips are what let the app see the # real scheme through nginx/DSM. Without them every request looks like # plain http and the session cookie loses its __Host- prefix and Secure # flag (app/identity/cookies.py:22). The allow-list is the internal # docker network only; this port is never published directly. exec uvicorn app.main:create_app \ --factory \ --host "$API_HOST" \ --port "$API_PORT" \ --workers "$API_WORKERS" \ --proxy-headers \ --forwarded-allow-ips "${FORWARDED_ALLOW_IPS:-*}" \ --no-server-header \ "$@" ;; worker-sync) WORKER_ROLE=sync exec python -m workers.run "$@" ;; worker-jobs) WORKER_ROLE=jobs exec python -m workers.run "$@" ;; worker-all) WORKER_ROLE=all exec python -m workers.run "$@" ;; migrate) run_migrations ;; reindex) exec python scripts/reindex_search.py "$@" ;; plugins) exec python -m app.plugins.cli "$@" ;; shell) exec /bin/sh "$@" ;; *) exec "$cmd" "$@" ;; esac