Universal Tracking Appendix D40

Appendix D

1 min read Section 40 of 42

Appendix D - Deployment Blueprint

Compose skeleton

services:
  postgres:
    image: postgis/postgis:pin-a-reviewed-version
    restart: unless-stopped
    environment:
      POSTGRES_DB: tracking
      POSTGRES_USER_FILE: /run/secrets/postgres_user
      POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./postgres/init:/docker-entrypoint-initdb.d:ro
    secrets:
      - postgres_user
      - postgres_password
    networks: [data]

  api-a:
    image: registry.example/tracking-platform:${TRACKING_VERSION}
    command: ["api"]
    env_file: [./config/common.env, ./config/api.env]
    secrets: [database_url, token_signing_key]
    depends_on: [postgres]
    networks: [edge, data]

  api-b:
    extends: api-a

  worker:
    image: registry.example/tracking-platform:${TRACKING_VERSION}
    command: ["worker"]
    env_file: [./config/common.env, ./config/worker.env]
    secrets: [database_url]
    depends_on: [postgres]
    networks: [data]

  scheduler:
    image: registry.example/tracking-platform:${TRACKING_VERSION}
    command: ["scheduler"]
    env_file: [./config/common.env]
    secrets: [database_url]
    depends_on: [postgres]
    networks: [data]

  gps-gateway:
    image: registry.example/tracking-platform:${TRACKING_VERSION}
    command: ["gps-gateway"]
    env_file: [./config/common.env, ./config/gateway.env]
    secrets: [database_url]
    depends_on: [postgres]
    networks: [edge, data]

  nginx:
    image: nginx:pin-a-reviewed-version
    ports:
      - "443:443"
      - "5001:5001"
    volumes:
      - ./nginx:/etc/nginx:ro
      - ./tls:/etc/nginx/tls:ro
      - dashboard-static:/srv/dashboard:ro
    depends_on: [api-a, api-b, gps-gateway]
    networks: [edge]

networks:
  edge:
  data:
    internal: true

volumes:
  postgres-data:
  dashboard-static:

secrets:
  postgres_user:
    file: ./secrets/postgres_user
  postgres_password:
    file: ./secrets/postgres_password
  database_url:
    file: ./secrets/database_url
  token_signing_key:
    file: ./secrets/token_signing_key

The exact image tags must be pinned to reviewed versions or digests. Do not publish the database port. extends support and production tooling should be verified in the selected Compose implementation.

Deployment sequence

preflight configuration and disk space
verify backup and WAL archive health
pull immutable image by digest
run migration plan and compatible migrations
start new API instances
run readiness and smoke tests
switch or expand Nginx upstreams
drain old API instances
replace workers and scheduler
replace GPS gateway carefully
verify ingest, realtime, jobs, and alerts
record release evidence

Rollback

Application rollback is safe only while the schema remains backward compatible. A release plan states:

  • previous image digest;
  • minimum compatible migration version;
  • whether new writes can be read by old code;
  • whether workers must be paused;
  • how to drain active WebSockets;
  • how to verify restored service;
  • when database PITR is the only option.

Aleksandar Popovic · Copyright © 2026 Aleksandar Popovic · All rights reserved. Licensing and attribution