Skip to content

C4 Level 2 — Containers

Goal: zoom into support-bot and show the deployable units (processes / containers / pods), the technologies they use, and how they communicate.

Diagram

Hold "Alt" / "Option" to enable pan & zoom
flowchart TB
    U(["Ziggo customer<br/>(browser / mobile)"])

    subgraph CLUSTER["support-bot (single Docker Compose stack<br/>or EKS namespace)"]
        API["FastAPI service<br/>:8080 → :8000<br/>Python 3.11 / uvicorn<br/>support_bot.composition.api_app:create_app"]

        ING["ingestion Job<br/>one-shot CLI<br/>python -m support_bot.composition.ingestion_main<br/>(docker compose --profile ingest)"]

        CHR["Chroma vector store<br/>:8000<br/>chromadb/chroma:1.5.9<br/>persistent volume: chroma_data"]
    end

    subgraph SECRETS["Secret store"]
        OAI_KEY[("OPENAI_API_KEY")]
    end

    U -->|"POST /ask<br/>{question}"| API
    API -->|"chat.completions.create<br/>embeddings.create"| OAI(["OpenAI API"])
    API -->|"chromadb.HttpClient<br/>:8000"| CHR

    ING -->|"requests.get<br/>(scraping)"| SRC(["ziggo.nl/internet<br/>operator-configurable"])
    ING -->|"chat.completions.create<br/>(semantic page analyser)"| OAI
    ING -->|"chromadb.HttpClient<br/>upsert"| CHR

    OAI_KEY -.->|"env_file (.env)<br/>or Secret mount"| API
    OAI_KEY -.->|"env_file (.env)<br/>or Secret mount"| ING

Container inventory

Container Technology Lifecycle Image Purpose
FastAPI service Python 3.11 + FastAPI 0.115 + uvicorn Long-running, scaled by HPA on CPU support-bot-api (built from docker/api.Dockerfile) Receives POST /ask, runs the LangGraph workflow, returns JSON.
ingestion Job Python 3.11 (same image, different entrypoint) One-shot per source change; runs as Helm post-install / post-upgrade hook or docker compose --profile ingest support-bot-api (same image, different CMD) Scrapes → cleans → analyses → chunks → embeds → upserts into Chroma.
Chroma chromadb/chroma:1.5.9 (Debian-based slim image) Long-running; single replica, StatefulSet on EKS Upstream Docker image, pinned Stores embeddings + metadata; serves chromadb.HttpClient over HTTP.

Communication paths

From To Protocol Notes
Customer browser FastAPI service HTTPS (HTTP/1.1) POST /ask with JSON body. CORS is not configured by default.
FastAPI service OpenAI API HTTPS (api.openai.com:443) httpx auto-instrumented; structured output mode for the page analyser; chat completions for the answerer.
FastAPI service Chroma HTTP (cleartext inside the cluster) chromadb.HttpClient over :8000; per-request Authorization header when CHROMA_AUTH_TOKEN is set.
ingestion Job Source web page HTTPS requests.get with timeout + retries; raises SourcePageUnreachable on failure.
ingestion Job OpenAI API HTTPS Same as FastAPI service.
ingestion Job Chroma HTTP Same as FastAPI service.

Storage

Container Storage Type Retention
FastAPI service None Stateless. Replicas can be killed without data loss.
ingestion Job None during the run; uses the lock file at <LOCK_DIR>/<request_id>.lock File system Lock file is try/finally-released.
Chroma chroma_data:/chroma/chroma (Docker volume) / PVC chroma-data (Helm, gp3 50 Gi, persistentVolumeReclaimPolicy: Retain) Persistent Survives pod restarts; survives helm uninstall (operator-controlled at the StorageClass level).

Resource sizing (Helm values)

Component requests.cpu requests.memory limits.cpu limits.memory Scaling
API pod 100m 256 MiB 1000m 1 GiB 2–4 replicas, HPA on CPU 60%
Chroma pod 50m 128 MiB 500m 512 MiB 1 replica, vertical scale only
Ingestion Job 200m 512 MiB 1000m 2 GiB One-shot

Where to look in the code

Concern File
FastAPI entrypoint + uvicorn wiring src/support_bot/composition/api_app.py
Ingestion entrypoint (CLI) src/support_bot/composition/ingestion_main.py
Docker Compose deploy/docker-compose.yml
Helm chart deploy/helm/support-bot/
Helm chart values deploy/helm/support-bot/values.yaml, values-dev.yaml, values-prod.yaml
Dockerfile (multi-stage, non-root) docker/api.Dockerfile