# Bus Manager A Django-based bus coordination and management system. Handles transport scheduling, traveller management, location tracking, coordinator workflows, and optional SMS (Telstra) and SSO (Azure AD) integrations. --- ## Stack | Component | Technology | |-----------|-----------| | Web framework | Django 6 + Gunicorn | | Database | PostgreSQL 16 | | Auth (optional) | Azure AD SSO via MSAL | | SMS (optional) | Telstra Messaging API | | Scheduling | django-crontab (nightly coordinator check) | | Container runtime | Docker + Docker Compose | --- ## Deployment ### Prerequisites - Docker and Docker Compose installed on the host - A reverse proxy (e.g. Nginx Proxy Manager) to front the app ### 1. Clone the repository ```bash git clone https://gitea.hideawaygaming.com.au/jessikitty/bus-manager.git cd bus-manager ``` ### 2. Configure environment ```bash cp .env.example .env ``` Edit `.env` and set at minimum: | Variable | Description | |----------|-------------| | `SECRET_KEY` | Long random string — generate with `python -c "import secrets; print(secrets.token_urlsafe(50))"` | | `SQL_PASSWORD` | Postgres password (picked up by both the `db` and `web` containers) | | `ALLOWED_HOSTS` | Space-separated list of hostnames the app will be served from (e.g. `busmanager.yourdomain.com`) | | `APP_PORT` | Host port Gunicorn will be exposed on (default: `8000`) | Optional variables for email, Azure SSO, and Telstra SMS are documented in `.env.example`. ### 3. Build and start ```bash docker compose up -d --build ``` On first start the `web` container will: 1. Wait for Postgres to pass its healthcheck 2. Run `manage.py migrate` to initialise the database schema 3. Run `manage.py collectstatic` to gather static assets 4. Register the nightly cron job via `manage.py crontab add` 5. Start Gunicorn on port `8000` ### 4. Create a superuser ```bash docker compose exec web python manage.py createsuperuser ``` ### 5. Reverse proxy (Nginx Proxy Manager) Create a new proxy host in NPM pointing to: ``` http://: ``` Enable SSL via Let's Encrypt as usual. No special headers required — Gunicorn handles WSGI directly. --- ## Updating ```bash git pull docker compose up -d --build ``` Migrations run automatically on startup, so schema changes are applied without manual intervention. --- ## Useful commands | Task | Command | |------|---------| | View logs | `docker compose logs -f web` | | Open Django shell | `docker compose exec web python manage.py shell` | | Run migrations manually | `docker compose exec web python manage.py migrate` | | Check crontab | `docker compose exec web python manage.py crontab show` | | Restart app only | `docker compose restart web` | | Stop everything | `docker compose down` | | Stop and wipe database | `docker compose down -v` ⚠️ destructive | --- ## Environment variables reference | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `SECRET_KEY` | ✅ | — | Django secret key | | `DEBUG` | | `False` | Enable Django debug mode | | `ALLOWED_HOSTS` | ✅ | `localhost` | Space-separated allowed hostnames | | `SQL_DATABASE` | | `busmanager` | Postgres database name | | `SQL_USER` | | `busmanager` | Postgres username | | `SQL_PASSWORD` | ✅ | — | Postgres password | | `APP_PORT` | | `8000` | Host port for Gunicorn | | `GUNICORN_WORKERS` | | `3` | Number of Gunicorn worker processes | | `GUNICORN_TIMEOUT` | | `120` | Gunicorn worker timeout (seconds) | | `EMAIL_HOST` | | — | SMTP relay hostname | | `EMAIL_PORT` | | `25` | SMTP relay port | | `AZURE_CLIENT_ID` | | — | Azure app client ID (enables SSO) | | `AZURE_CLIENT_SECRET` | | — | Azure app client secret | | `AZURE_REDIRECT_URI` | | — | Azure OAuth redirect URI | | `AZURE_AUTHORITY` | | — | Azure authority URL | | `TELSTRA_CLIENT_ID` | | — | Telstra API client ID (enables SMS) | | `TELSTRA_CLIENT_SECRET` | | — | Telstra API client secret | --- ## Data persistence Two named Docker volumes are created automatically: - `postgres_data` — PostgreSQL data directory - `static_files` — collected Django static assets These survive `docker compose down` and are only removed with `docker compose down -v`.