Skip to content

Services

Rod Christiansen edited this page Oct 8, 2026 · 2 revisions

Services

Everything docker-compose.yml defines. The Compose project name is reportmate, so containers are named reportmate-<service>-1 and the network is reportmate_reportmate.

Service table

Service Image Published ports Volumes Depends on Purpose
postgres postgres:16-alpine none postgres_data:/var/lib/postgresql/data, ./schema/init.sql:/docker-entrypoint-initdb.d/01-init.sql:ro — Stores devices, events, and one table per client module
api ghcr.io/reportmate/reportmate-api:${REPORTMATE_TAG:-latest} 8000:8000 none postgres (condition: service_healthy) FastAPI ingest and query backend; the only service that talks to Postgres
web ghcr.io/reportmate/web:${REPORTMATE_TAG:-latest} 3000:3000 none api (start order only) Next.js dashboard; reads the API over the internal network at http://api:8000

All three set restart: unless-stopped and join the single user-defined bridge network reportmate.

Notes on each service

postgres

Initialised with database reportmate, user reportmate, and password DB_PASSWORD. It is the only service with a healthcheck:

pg_isready -U reportmate -d reportmate

Run every 10s, 5s timeout, 5 retries. api blocks until this passes.

The port is deliberately not published. Postgres is reachable only from other containers on the reportmate network, at postgres:5432. To use psql from the host, exec into the container rather than publishing 5432.

schema/init.sql is mounted read-only into the standard Postgres init directory, so it runs only when the data directory is empty — that is, on the very first start, or after docker compose down -v. It creates the device and event tables, one table per client module (applications, displays, hardware, identity, installs, inventory, management, network, printers, profiles, security, system), the business-unit and machine-group tables, app_settings, supporting indexes including GIN indexes on each module's JSONB payload, and updated_at triggers. It also adds the archived / archived_at soft-delete columns to devices.

The file is consolidated from the terraform-azurerm-reportmate migrations, so this repo and the Terraform modules provision the same shape.

api

Talks to Postgres over DATABASE_URL, which the Compose file assembles from DB_PASSWORD. DB_SSL is pinned to "false" because the in-network Postgres container has no TLS.

Health endpoints are under /api/v1/: health, health/live, and health/ready. The image also carries its own container healthcheck against /api/v1/health, though the Compose file does not depend on it.

CORS_ORIGINS is set from PUBLIC_URL, so the only browser origin allowed cross-origin access to the API is the one you declare. The bundled dashboard does not need it, because it reaches the API server-side.

Port 8000 is published on the host because endpoints post to it directly.

web

The browser only talks to the dashboard's own same-origin routes (/api/... on port 3000); those route handlers call the API at API_BASE_URL=http://api:8000, which stays inside the Compose network. NEXT_PUBLIC_API_BASE_URL is set from PUBLIC_API_URL but is read only as a fallback when API_BASE_URL is empty. It shares API_INTERNAL_SECRET with the API to authenticate its own server-side requests, and holds NEXTAUTH_SECRET for session signing.

depends_on: [api] here is ordering only — there is no condition attached, so web can start before the API is answering requests. Expect the first few dashboard loads after up to show API errors until the API is ready.

What is not here

There is no reverse proxy, no TLS terminator, no backup job, no log shipper, and no separate migration container in this Compose file. See TLS and Reverse Proxy and Backup and Restore for what that means for you.

Clone this wiki locally