# Deployment ## Production Readiness Before a real deployment, treat `.env.example` as local-development only. Create a separate `.env` for production and replace all placeholder values. Required production changes: - set `DJANGO_DEBUG=false`; - set a strong random `DJANGO_SECRET_KEY`; - set `DJANGO_ALLOWED_HOSTS` to the real public hostnames only; - set `DJANGO_CSRF_TRUSTED_ORIGINS` to the real public HTTPS origins; - set `SITE_BASE_URL` to the real public HTTPS base URL used for confirmation emails and QR/check-in links; - replace the console email backend with real SMTP settings and a valid sender address; - publish only nginx and terminate HTTPS at nginx or a trusted upstream reverse proxy; - keep `collectstatic --noinput` in the deployment flow before `up -d`; - persist the PostgreSQL named volume and configure tested backups before accepting bookings; - create the first admin account explicitly with `python manage.py createsuperuser`. Reverse proxy and HTTPS notes: - the current nginx template listens on plain HTTP port `80` only and must be adapted for production TLS; - if TLS is terminated by another reverse proxy, forward the public host and scheme correctly so generated links remain accurate; - keep `SITE_BASE_URL`, `DJANGO_ALLOWED_HOSTS`, and `DJANGO_CSRF_TRUSTED_ORIGINS` aligned with the final public URL. AzioneLab should deploy with a simple Docker Compose topology: - `nginx`: public reverse proxy and static frontend server; - `frontend`: Angular build source or build stage for static assets; - `backend`: Django 5.2 LTS application served by gunicorn; - `postgres`: PostgreSQL database. Only nginx should expose public ports. The backend and database should stay on the internal Compose network. The initial Compose setup is located at `infra/docker/compose.yml`. ## Services ### nginx Responsibilities: - listen on public HTTP and HTTPS ports; - serve built Angular files; - proxy `/api/` and `/admin/` requests to the backend; - serve static and media files according to the selected storage layout; - apply request size and timeout limits appropriate for booking and admin usage. Public ports: - `80` for HTTP; - `443` for HTTPS in production. ### frontend The frontend is an Angular application using Angular Material. Deployment options: - build the Angular app in a Docker build stage and copy static files into the nginx image; - or run a one-shot build container that writes static files to a shared volume consumed by nginx. The first option is preferred for a simple production deployment because nginx can serve immutable built assets without a long-running Node process. At the infrastructure placeholder stage, the `frontend` service serves a static placeholder page with nginx. The Angular build will replace this placeholder later. ### backend The backend is a Django application served by gunicorn. Responsibilities: - REST API; - Django admin; - booking, confirmation, QR generation, and check-in logic; - transactional capacity validation; - email sending. The backend should run database migrations before or during deployment through an explicit operational command, not as hidden startup magic unless that choice is documented later. The `backend` service runs gunicorn against the Django WSGI application. The current backend is an initial skeleton with Django admin, Django REST Framework, CORS configuration, the `shows`, `bookings`, and `checkins` apps, and a health endpoint. ### postgres PostgreSQL is the only database service. Responsibilities: - persistent application data; - reservation and check-in state; - transactional capacity enforcement. Use a named Docker volume for database data. ## Networks Recommended Compose networks: - `public`: nginx-facing network when needed; - `internal`: private network for nginx, backend, and db communication. The database should not be published to the host in production. ## Volumes Recommended volumes: - `postgres_data`: PostgreSQL data directory; - `media`: uploaded show images and generated QR assets if stored on disk; - `static`: collected Django static files if served by nginx from a shared volume. Generated QR codes may also be generated on demand instead of stored as files. If stored, they must not reveal personal data and access must remain controlled. ## Configuration Copy `.env.example` to `.env` and replace all placeholder values before running or deploying the stack. `.env.example` is intentionally local-dev oriented. Do not use it unchanged for production. Required backend configuration: - `DJANGO_SECRET_KEY`; - `DJANGO_ALLOWED_HOSTS`; - `DJANGO_CSRF_TRUSTED_ORIGINS`; - `DJANGO_DEBUG=false`; - `CORS_ALLOWED_ORIGINS`; - `SITE_BASE_URL`; - `TIME_ZONE`; - `DATABASE_URL` or equivalent database settings; - email host, port, username, password, TLS settings, and sender address; - public site URL used to build confirmation and QR verification links. Local Docker convention: - use nginx as the public entrypoint at `http://localhost`; - set `SITE_BASE_URL=http://localhost`; - keep `DJANGO_CSRF_TRUSTED_ORIGINS` and browser-facing `CORS_ALLOWED_ORIGINS` aligned with that public URL; - if you publish nginx on a different port, update `SITE_BASE_URL` and trusted origins to the same host and port. - local/debug reservation email sends also log the confirmation URL so browser testing can continue even if SMTP is missing or fails. Required database configuration: - database name; - database user; - database password; - data volume path. Required nginx configuration: - upstream backend service name and port; - static frontend root; - proxy rules for `/api/` and `/admin/`; - media root for `/media/` if uploaded assets are served by nginx from a shared volume; - TLS certificate paths for production. Secrets must be provided through deployment-managed environment variables, Docker secrets, or another secret manager. Do not commit real secret values. ## Example Request Routing ```text Visitor browser -> nginx -> Angular static files -> /api/ requests proxied to backend:gunicorn -> /admin/ requests proxied to backend:gunicorn Backend -> PostgreSQL -> SMTP provider ``` ## Deployment Commands The exact commands will be finalized when application code and Compose files are added. Expected production-style flow: ```bash docker compose --env-file .env -f infra/docker/compose.yml build docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py migrate docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py collectstatic --noinput docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py createsuperuser docker compose --env-file .env -f infra/docker/compose.yml up -d ``` Expected validation commands: ```bash docker compose --env-file .env.example -f infra/docker/compose.yml config docker compose --env-file .env.example -f infra/docker/compose.yml run --rm --build backend python manage.py test docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py check --deploy docker compose --env-file .env -f infra/docker/compose.yml run --rm backend python manage.py test ``` The canonical repository check for the current stage is: ```bash docker compose --env-file .env.example -f infra/docker/compose.yml config docker compose --env-file .env.example -f infra/docker/compose.yml run --rm --build backend python manage.py test ``` ## Rollback Rollback should be designed around immutable images and database backups. Basic rollback steps: 1. identify the previous known-good image tags or Git commit; 2. stop the current Compose stack; 3. deploy the previous image tags or commit; 4. restore the database from backup only if a migration or data change requires it; 5. run smoke checks for public pages, booking creation, confirmation, and check-in. Database rollback needs special care once migrations exist. Down migrations or backup restore procedures should be documented before production use. ## Operational Notes - Configure database backups before accepting real bookings. - Back up the shared media volume together with the database if staff uploads show images. - Monitor backend errors, email delivery failures, and check-in failures. - Keep container images explicitly versioned; do not use `latest` tags. - Keep the system small until operational needs justify additional services.