# Deployment ## Docker The service ships with a `Dockerfile` based on `python:3.12-slim-bookworm` using [uv](https://astral.sh/uv/) for fast dependency installation. ### Configuration sources The application now supports two configuration sources: - environment variables - a YAML config file Load order: 1. per-request overrides 2. environment variables 3. YAML config file 4. built-in defaults Supported config file locations: - `config.yml` - `config.yaml` - `/config/config.yml` - `/config/config.yaml` You can also set an explicit config path with: ```bash export EMAIL_CLASSIFIER_CONFIG=/path/to/config.yml ``` Example `config.yml`: ```yaml llm: provider: anthropic base_url: https://api.minimax.io/anthropic api_key: your_api_key_here model: MiniMax-M2.7 temperature: 0.1 timeout_seconds: 60 max_retries: 3 ``` ### Building ```bash docker build -t email-classifier . ``` ### Running ```bash docker run -d --name email-classifier \ -p 7999:7999 \ -e EMAIL_CLASSIFIER_CONFIG=/config/config.yml \ -e EMAIL_CLASSIFIER_DB_PATH=/data/email_classifier.db \ -v /path/to/config.yml:/config/config.yml:ro \ -v /path/to/local/data:/data \ email-classifier ``` Mount a persistent volume for `/data` (or wherever `EMAIL_CLASSIFIER_DB_PATH` points) to preserve the dedupe database across container restarts. Environment variables still override file-based config, so you can keep most settings in YAML and override just one or two values at deploy time. ## Docker Compose example ```yaml services: email-classifier: image: your-registry.example.com/your-org/email-classifier:latest container_name: email-classifier ports: - "7999:7999" environment: EMAIL_CLASSIFIER_CONFIG: /config/config.yml EMAIL_CLASSIFIER_DB_PATH: /data/email_classifier.db # Optional overrides. Env vars win over YAML values. # LLM_MODEL: MiniMax-M2.7 # LLM_TIMEOUT_SECONDS: "90" volumes: - ./config.yml:/config/config.yml:ro - ./data:/data restart: unless-stopped # If your LLM backend runs on the Docker host, one option is: # extra_hosts: # - "host.docker.internal:host-gateway" ``` ### Compose notes - Mount the YAML config read-only into the container, typically at `/config/config.yml` - Mount a writable volume for `/data` so dedupe state survives restarts - Override specific values with environment variables when needed - If the LLM backend is another container on the same Compose network, use its service name in `base_url` - If the LLM backend runs on the host, use `host.docker.internal` or a host-gateway mapping where appropriate ## Building for a Remote Registry ```bash docker build -t \ your-registry.example.com/your-org/email-classifier:latest \ . docker push your-registry.example.com/your-org/email-classifier:latest ``` ## GitHub Actions CI/CD The repository includes a workflow at `.github/workflows/build-publish.yaml` that builds and pushes a Docker image on every push to `main`. ### Required Secrets Configure these in your GitHub/Gitea Actions secrets: | Secret | Description | |---|---| | `DOCKER_REGISTRY` | Registry hostname (e.g., `ghcr.io` or your custom registry) | | `DOCKER_USERNAME` | Registry username | | `DOCKER_PASSWORD` | Registry password or access token | The workflow tags the image as: - `:latest` — always points to the latest commit on `main` - `:` — the full git SHA of the triggering commit (useful for rollbacks) ### Deployment Considerations - **Network access** — The container needs to reach your LLM backend. If using Ollama or another service on the host, use `host.docker.internal` or an explicit host-gateway mapping. - **Dedupe persistence** — Mount a volume for the SQLite database to persist dedupe state across deploys. - **Port** — The container exposes port `7999`. Map it to any host port you prefer. - **Health check** — The service does not currently expose a dedicated `/health` endpoint. Use `GET /docs` as a liveness probe. ## Production Checklist - [ ] Provide either a YAML config file or the required `LLM_*` environment variables - [ ] Use HTTPS for remote `LLM_BASE_URL` values in production - [ ] Mount a persistent volume for `EMAIL_CLASSIFIER_DB_PATH` - [ ] Set appropriate resource limits (CPU/memory) on the container - [ ] Configure `LLM_MAX_RETRIES` and `LLM_TIMEOUT_SECONDS` to suit your LLM backend's reliability - [ ] Keep `LLM_TEMPERATURE` low for consistent classification results