# NVR Docker Compose Configuration
#
# Base compose file — works standalone for production (pulls images from registry)
# and with dev overlay for local builds.
#
# Production:  docker compose up -d                          (uses .env COMPOSE_FILE)
# Development: docker compose -f docker-compose.yml -f docker-compose.dev.yml build
# See also:    docker-compose.dev.yml, docker-compose.prod.yml
#
# All services use network_mode: host - they share the host's network stack.
# This means all services communicate via 127.0.0.1, identical to bare-metal.
# No port mappings are needed; services bind directly to host ports.
#
# =============================================================================
# VOLUME STRATEGY
# =============================================================================
# Persistent state uses two mount types:
#
#   Bind mounts (./data/):
#     ./data/config:/data     - dvs.conf, rda-db markers (all services)
#     ./data/db_data           - MariaDB data (db service)
#
#   Named volume:
#     seed:/seed              - device-id seed file (engine, backend, connector)
#                               Needs named volume for consistent inode semantics
#                               across platforms (key.c XOR-encrypts with inode)
#
# dvs.conf, rda-db markers, and the database all live on bind mounts so they
# share the same lifecycle. `docker compose down -v` only removes the seed
# volume (regenerated by make-seed). Deleting ./data/ removes all state for
# a clean fresh install.
# =============================================================================
#
# =============================================================================
# VIDEOSTORE CONFIGURATION
# =============================================================================
# VideoStores are storage locations for video recording. The entire /videostore
# parent directory is mounted into containers, so new VideoStores (subdirs)
# are visible immediately — no container restart needed.
#
# VideoStore volumes are defined in the overlay files:
#   - docker-compose.dev.yml:  ./data/videostore:/videostore (directories)
#   - docker-compose.prod.yml: /videostore:/videostore:slave (physical drives)
#
# In production, rda-backend mounts physical drives into the host's mount
# namespace via nsenter. The 'slave' propagation carries host mounts into
# all containers.
# =============================================================================

name: dividia-nvr

volumes:
  seed:
    name: dividia-nvr-seed  # device-id seed file (inode-sensitive, needs consistent filesystem)

services:

  db:
    image: mariadb:10.5
    restart: always
    network_mode: host
    environment:
      MYSQL_ROOT_PASSWORD: lynn1094
      MYSQL_DATABASE: dtech
    volumes:
      - "./data/db_data:/var/lib/mysql"
    # No ports needed - host networking exposes 3306 directly
    healthcheck:
      test: ["CMD", "mariadb", "-u", "root", "-plynn1094", "-e", "SELECT 1"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
      start_interval: 2s

  backend:
    image: ${REGISTRY:-docker.io}/dividia/nvr-backend:${CHANNEL:-dev}
    network_mode: host
    depends_on:
      db:
        condition: service_healthy
    restart: always
    volumes:
      - "./data/config:/data"
      - "seed:/seed"
      - "/var/run/docker.sock:/var/run/docker.sock"
      - "./data/rdafw.d:/etc/rdafw.d"
      - "./data/dhcp:/etc/dhcp"
      - "./data/ntp:/etc/ntp"
    healthcheck:
      test: ["CMD", "curl", "-so", "/dev/null", "http://127.0.0.1:43204/"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
      start_interval: 2s
    cap_add:
      - SYS_TIME

  engine:
    image: ${REGISTRY:-docker.io}/dividia/nvr-engine:${CHANNEL:-dev}
    network_mode: host
    depends_on:
      db:
        condition: service_healthy
      backend:
        condition: service_healthy
    restart: always
    volumes:
      - "./data/config:/data"
      - "seed:/seed"
    healthcheck:
      test: ["CMD-SHELL", "bash -c '</dev/tcp/127.0.0.1/43209' || grep -q sleep /proc/1/cmdline 2>/dev/null"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 15s

  connector:
    image: ${REGISTRY:-docker.io}/dividia/nvr-connector:${CHANNEL:-dev}
    network_mode: host
    depends_on:
      db:
        condition: service_healthy
      backend:
        condition: service_healthy
      engine:
        condition: service_started
    restart: always
    volumes:
      - "./data/config:/data"
      - "seed:/seed"
    healthcheck:
      test: ["CMD-SHELL", "grep -rlq recorder.pyc /proc/[0-9]*/cmdline 2>/dev/null"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  playback:
    image: ${REGISTRY:-docker.io}/dividia/nvr-playback:${CHANNEL:-dev}
    network_mode: host
    depends_on:
      db:
        condition: service_healthy
      backend:
        condition: service_healthy
    restart: always
    volumes:
      - "./data/config:/data"
    healthcheck:
      test: ["CMD-SHELL", "bash -c '</dev/tcp/127.0.0.1/43203'"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s

  viewer:
    image: ${REGISTRY:-docker.io}/dividia/nvr-viewer:${CHANNEL:-dev}
    network_mode: host
    depends_on:
      db:
        condition: service_healthy
      backend:
        condition: service_healthy
    restart: always
    volumes:
      - "./data/config:/data"
    healthcheck:
      test: ["CMD-SHELL", "bash -c '</dev/tcp/127.0.0.1/80'"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
