Files
training-software/README.md
Paperclip CTO 3c2cbb6e39
All checks were successful
CI / lint (push) Successful in 13s
CI / test (push) Successful in 24s
CI / build-container (push) Successful in 6s
Apply FRONTEND_API_BASE_URL across compose profiles
2026-05-19 13:32:22 +02:00

217 lines
5.6 KiB
Markdown

# Training Software
This repository contains a Django-based training platform backend plus a static customer portal frontend.
## Features for customer environment setup
- Per-customer organization profile with configurable license user limits (`20`, `50`, `100`, `1000`)
- Per-customer branding via company name and logo URL
- Static frontend that can be hosted on Nginx and configured with the backend API domain at deploy time
- CI pipeline for tests, linting, and container build
## Production deployment with nginx
`docker-compose.prod.yml` starts the full stack in one command:
- **nginx** — public-facing web server on port 80; serves the frontend SPA and
Django static files directly; proxies all backend routes to gunicorn
- **web** — Django/gunicorn (prod settings, 4 workers)
- **celery** / **celery-beat** — background task workers
- **db** — PostgreSQL 16
- **redis** — Redis 7
### 1. Prerequisites
- Docker Engine 24+ with Compose v2
### 2. Environment variables
```bash
cp .env.example .env
```
Edit `.env` and set at minimum:
| Variable | Notes |
|---|---|
| `DJANGO_SECRET_KEY` | Long random string |
| `DJANGO_ALLOWED_HOSTS` | Comma-separated hostnames, e.g. `training.example.com` |
| `DB_PASSWORD` | PostgreSQL password |
| `SECURE_SSL_REDIRECT` | Set `false` for HTTP-only; set `true` (or omit) when TLS is terminated at nginx or an upstream proxy |
### 3. Start the stack
```bash
docker compose -f docker-compose.prod.yml up -d --build
```
### 4. Run migrations and create admin user
```bash
docker compose -f docker-compose.prod.yml exec web python manage.py migrate
docker compose -f docker-compose.prod.yml exec web python manage.py createsuperuser
```
### 5. Verify health
```bash
curl http://<host>/healthz/
```
### HTTPS
To enable HTTPS, add `ssl_certificate` and `ssl_certificate_key` directives to
`nginx/nginx.conf` and expose port 443 in `docker-compose.prod.yml`, or place a
TLS-terminating reverse proxy (Traefik, Caddy, etc.) in front and set
`SECURE_SSL_REDIRECT=true`.
## Production deployment with dedicated frontend container
Use `docker-compose.proxy.yml` if you want your external nginx to be only a
reverse proxy while this stack runs its own frontend container.
### 1. Start the stack
```bash
cp .env.example .env
docker compose -f docker-compose.proxy.yml up -d --build
docker compose -f docker-compose.proxy.yml exec web python manage.py migrate
docker compose -f docker-compose.proxy.yml exec web python manage.py createsuperuser
```
By default, the frontend container is exposed on `http://localhost:8080`.
Set `FRONTEND_PORT` in `.env.proxy` if needed.
### 2. External nginx reverse-proxy example
```nginx
server {
listen 80;
server_name training.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
```
---
## Local development
### 1. Prerequisites
- Python 3.12
- PostgreSQL 16+
- Redis 7+
- Docker (recommended for containerised dev)
### 2. Environment variables
Create environment variables based on `.env.example`.
Required minimum values:
- `DJANGO_SECRET_KEY`
- `DJANGO_ALLOWED_HOSTS`
- `DATABASE_URL`
- `REDIS_URL`
- `DJANGO_SETTINGS_MODULE` (use `config.settings.local` for dev)
### 3. Build and run with Docker Compose
```bash
docker compose up -d --build
```
### 4. Run migrations
```bash
docker compose exec web python manage.py migrate
```
### 5. Verify health
```bash
curl http://localhost:8000/healthz/
```
### Local frontend in Docker (optional)
`docker-compose.yml` also includes a `frontend` service on `http://localhost:8080`.
Set `FRONTEND_API_BASE_URL` in `.env` to point the frontend to your backend API, for example:
```bash
FRONTEND_API_BASE_URL=http://localhost:8000
```
The same variable is supported by `docker-compose.proxy.yml` and `docker-compose.prod.yml`.
## Organization profile API (license + branding)
Admin-only endpoint (requires admin role):
- `GET /api/v1/accounts/organizations/{org_id}/profile/`
- `PATCH /api/v1/accounts/organizations/{org_id}/profile/`
### Fields
| Field | Type | Description |
|-------|------|-------------|
| `company_name` | string | Customer company name shown in the UI |
| `license_user_limit` | integer | Maximum number of active users — any positive integer (e.g. 20, 50, 100, 250, 1000) |
| `brand_logo_url` | string (URL) | URL of the customer's logo, displayed in the frontend header |
### Setting the license limit
`license_user_limit` accepts **any positive integer** — there are no fixed tiers. Set it to exactly the number of users your customer has licensed:
```bash
curl -X PATCH https://api.example.com/api/v1/accounts/organizations/<org_id>/profile/ \
-H "Authorization: Bearer <admin-token>" \
-H "Content-Type: application/json" \
-d '{
"company_name": "Acme Corp",
"license_user_limit": 250,
"brand_logo_url": "https://cdn.example.com/acme-logo.svg"
}'
```
Common values: 20 · 50 · 100 · 250 · 500 · 1000 — but any number works.
## Frontend deployment on Nginx
The static frontend is under `frontend/public`.
### 1. Set backend API domain
Edit `frontend/public/config.js` and set:
```js
window.APP_CONFIG = {
API_BASE_URL: "https://api.example.com"
};
```
### 2. Serve via Nginx
Use `frontend/nginx.conf` as a reference server config and copy the `frontend/public` files to your Nginx web root.
## CI for Gitea
Gitea Actions workflow file:
- `.gitea/workflows/ci.yml`
It runs:
- Ruff lint
- Django test suite
- Docker image build