## Summary - Standalone Django 6 shortener: Bearer `/api/links/` (create/list/detail/disable) and public `GET /<code>` 302 - Host split, target-host allowlist, named rotatable tokens; `short_url` from `PUBLIC_SHORT_URL` - Landing page, DEBUG-only `/debug/` mint form, Django admin - Docker/compose (host **8005**), Gitea CI like monica_site (PR tests, beta on merge, prod button) - Caller contract in `API.md` Closes #1. Infra follow-up: [server-infra#22](ai_ml_operations/server-infra#22). ## Test plan - [ ] `cd site && uv run python manage.py test` - [ ] `docker compose up --build` → http://127.0.0.1:8005/ - [ ] `POST /api/links/` with `Bearer monica:dev-only-token` → 201 - [ ] `GET /<code>` → 302 to allowlisted https URL - [ ] No Bearer → 401; non-allowlisted host → 400 - [ ] `/debug/` only when `DEBUG=true` Reviewed-on: #2
57 lines
1.3 KiB
Bash
57 lines
1.3 KiB
Bash
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
cd /app/site
|
|
|
|
wait_for_database() {
|
|
if [[ -z "${DATABASE_URL:-}" && -z "${DB_HOST:-}" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
echo "Waiting for database..."
|
|
for _ in $(seq 1 30); do
|
|
if uv run python - <<'PY'
|
|
import os
|
|
import sys
|
|
|
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shortener.settings")
|
|
|
|
import django
|
|
from django.db import connections
|
|
from django.db.utils import OperationalError
|
|
|
|
django.setup()
|
|
|
|
try:
|
|
connections["default"].ensure_connection()
|
|
except OperationalError:
|
|
sys.exit(1)
|
|
PY
|
|
then
|
|
echo "Database is ready."
|
|
return 0
|
|
fi
|
|
sleep 2
|
|
done
|
|
|
|
echo "Database did not become ready in time." >&2
|
|
exit 1
|
|
}
|
|
|
|
wait_for_database
|
|
|
|
uv run python manage.py migrate --noinput
|
|
|
|
# Local compose defaults to DJANGO_ENV=dev: runserver + source bind-mount → hot reload.
|
|
# Prod/beta images keep gunicorn (no file watch).
|
|
if [[ "${DJANGO_ENV:-}" == "dev" || "${DJANGO_USE_RUNSERVER:-}" == "true" ]]; then
|
|
echo "Starting Django runserver (auto-reload on)."
|
|
exec uv run python manage.py runserver "${GUNICORN_BIND:-0.0.0.0:8000}"
|
|
fi
|
|
|
|
uv run python manage.py collectstatic --noinput
|
|
|
|
exec uv run gunicorn shortener.wsgi:application \
|
|
--bind "${GUNICORN_BIND:-0.0.0.0:8000}" \
|
|
--workers "${GUNICORN_WORKERS:-2}"
|