# TNAF Production Deployment Checklist

## Required Environment

Set these before starting Django with `TNAFAPI_DEBUG=False`:

- `TNAFAPI_SECRET_KEY`: long random Django secret.
- `TNAFAPI_ALLOWED_HOSTS`: comma-separated production hosts.
- `TNAFAPI_CORS_ALLOWED_ORIGINS`: comma-separated frontend origins.
- `TNAFAPI_CSRF_TRUSTED_ORIGINS`: comma-separated HTTPS frontend/admin origins.
- `TNAFAPI_ENABLE_DOCS=False` unless API docs are intentionally public or access-controlled by your proxy.
- `TNAFAPI_SERVE_STATIC=False` and `TNAFAPI_SERVE_MEDIA=False`; serve these through the web server/proxy in production.
- `TNAFAPI_DB_NAME`, `TNAFAPI_DB_USER`, `TNAFAPI_DB_PASSWORD`, `TNAFAPI_DB_HOST`, `TNAFAPI_DB_PORT`.
- `TNAFAPI_SILENCED_SYSTEM_CHECKS=models.W036` if you stay on MariaDB and accept that `django-allauth`'s conditional unique email constraint is not enforced by the database.
- `PAYSTACK_SECRET_KEY`: live Paystack secret.
- `PAYSTACK_DEMO_MODE=False`.
- `FRONTEND_BASE_URL` and `PAYSTACK_CALLBACK_URL`.

Recommended HTTPS settings:

- `TNAFAPI_SECURE_SSL_REDIRECT=True`
- `TNAFAPI_SESSION_COOKIE_SECURE=True`
- `TNAFAPI_CSRF_COOKIE_SECURE=True`
- `TNAFAPI_SECURE_HSTS_SECONDS=31536000`
- `TNAFAPI_SECURE_HSTS_INCLUDE_SUBDOMAINS=True`
- `TNAFAPI_SECURE_HSTS_PRELOAD=True` only after confirming all subdomains are HTTPS-only.

Only enable secure cookies and HSTS when the frontend/admin are served over HTTPS. On plain HTTP local development, secure cookies will not be sent by the browser.

Set these for the PHP admin:

- `TNAF_ENV=production`
- `TNAF_API_URL`
- `TNAF_API_USER`
- `TNAF_API_PWD`
- `TNAF_API_TOKEN`
- `TNAF_LEGACY_SECRET`
- `TNAF_CRYPT_KEY`

The Django user attached to `TNAF_API_TOKEN` must be staff/admin because legacy admin endpoints now require admin permissions.

Set these for the React frontend:

- `VITE_PAYSTACK_PUBLIC_KEY`
- `VITE_API_URL`

## Verification Commands

```bash
tnafapi/venv/bin/python tnafapi/manage.py check --deploy
tnafapi/venv/bin/python tnafapi/manage.py migrate --check
npm --prefix frontend run build
find tnaf -path 'tnaf/plugins' -prune -o -path 'tnaf/vendor' -prune -o -path 'tnaf/dist' -prune -o -name '*.php' -print0 | xargs -0 -n1 php -l
```

## Safe API Update on Existing Server Data

Before running new migrations on a server that already has data, take a database backup. Then run migrations normally; Django migrations alter schema and keep existing rows unless a migration explicitly deletes data.

Example for frontend served at `http://50.6.202.74` and API served at `http://50.6.202.74:8800`:

```bash
export TNAFAPI_ALLOWED_HOSTS=50.6.202.74,localhost,127.0.0.1
export FRONTEND_BASE_URL=http://50.6.202.74
export PAYSTACK_CALLBACK_URL=http://50.6.202.74/payment/callback
export TNAFAPI_CORS_ALLOWED_ORIGINS=http://50.6.202.74,http://50.6.202.74:8800,http://localhost:5173,http://thenewafricafilms.com
export TNAFAPI_CSRF_TRUSTED_ORIGINS=http://50.6.202.74,http://50.6.202.74:8800,http://localhost:5173,http://thenewafricafilms.com

tnafapi/venv/bin/python tnafapi/manage.py migrate
tnafapi/venv/bin/python tnafapi/manage.py collectstatic --noinput
```

Genre and React admin menu seed data are included in the Django migration history. Running `migrate` on a fresh deployment creates the default rows if they are missing. Existing rows are kept and are not deleted or overwritten.

The seed commands are still available if you need to repair missing data manually:

- `seed_react_admin_menu` uses stable menu codes and does not delete menu rows.
- `seed_genres` creates missing default genres and skips existing genres by default. Use `seed_genres --update` only when you want to refresh the default names/descriptions.

## Operational Notes

- Rotate all API tokens and passwords that were previously hardcoded.
- Legacy PHP admin authentication uses `/tnaf/legacy-login/` and `/tnaf/legacy-change-password/` so password hashes are verified server-side and are not exposed through user list/detail API responses.
- Django exposes `/health/` for deployment health checks.
- Keep `.env`, media uploads, logs, virtualenvs, and frontend build artifacts out of version control.
- Run Django behind a production WSGI/ASGI server such as Gunicorn, with HTTPS termination at the reverse proxy.
- Configure the web server to serve Django static files from `tnafapi/staticfiles/` after `collectstatic`.
- Configure protected media delivery carefully; streaming endpoints issue signed URLs and should stay behind HTTPS.
