job "frigate" {
  # Pin to N150 LattePanda nodes - Intel UHD iGPU for OpenVINO-accelerated detection.
  # hardware.graphics (intel-compute-runtime) is deployed to these nodes via configuration.nix.
  constraint {
    attribute = "${node.class}"
    value     = "latte-panda-n150"
  }

  group "frigate" {
    count = 1

    network {
      port "http" {
        to = 5000
      }
    }

    # Prestart: restore Frigate's SQLite DB from the Litestream file replica on the CIFS share.
    # Runs to completion before the frigate task starts. Safe on first boot (-if-replica-exists
    # is a no-op when no replica exists yet).
    task "litestream-restore" {
      lifecycle {
        hook    = "prestart"
        sidecar = false
      }

      driver = "docker"

      config {
        image   = "litestream/litestream:0.5.9"
        command = "restore"
        args    = ["-if-replica-exists", "-config", "/local/litestream.yml", "/alloc/data/frigate.db"]
      }

      # Litestream config: replicate to /config/frigate.db.litestream/ on the CIFS share.
      # Litestream writes its own segment format - no SQLite advisory locking involved.
      # Frigate must be configured with database.path: /alloc/data/frigate.db in config.yml.
      template {
        data        = <<EOH
dbs:
  - path: /alloc/data/frigate.db
    replicas:
      - url: file:///config/frigate.db.litestream
EOH
        destination = "local/litestream.yml"
      }

      volume_mount {
        volume      = "unraid_appdata_frigate"
        destination = "/config"
        read_only   = false
      }

      resources {
        cpu        = 100
        memory     = 64
        memory_max = 256
      }
    }

    # Sidecar: continuously stream WAL changes from /alloc/data/frigate.db to the CIFS replica.
    # Runs alongside frigate for the lifetime of the allocation.
    task "litestream-replicate" {
      lifecycle {
        hook    = "poststart"
        sidecar = true
      }

      driver = "docker"

      config {
        image   = "litestream/litestream:0.5"
        command = "replicate"
        args    = ["-config", "/local/litestream.yml"]
      }

      template {
        data        = <<EOH
dbs:
  - path: /alloc/data/frigate.db
    replicas:
      - url: file:///config/frigate.db.litestream
EOH
        destination = "local/litestream.yml"
      }

      volume_mount {
        volume      = "unraid_appdata_frigate"
        destination = "/config"
        read_only   = false
      }

      resources {
        cpu        = 100
        memory     = 64
        memory_max = 256
      }
    }

    task "frigate" {
      driver = "docker"

      config {
        image      = "ghcr.io/blakeblackshear/frigate:0.17.1"
        ports      = ["http"]
        privileged = true

        # Shared memory for inter-process frame buffers (frigate forks detector processes).
        shm_size = 268435456 # 256 MiB

        # Large tmpfs for decoded frame cache - avoids wearing out any storage.
        mounts = [
          {
            type     = "tmpfs"
            target   = "/tmp/cache"
            readonly = false
            tmpfs_options = {
              size = 1000000000 # 1 GiB in bytes
            }
          }
        ]

        # Intel iGPU render node - Frigate's bundled OpenVINO runtime auto-detects
        # GPU device and uses it for object detection without any extra env vars.
        # Requires hardware.graphics.enable = true on the NixOS node (N150 nodes).
        devices = [
          {
            host_path      = "/dev/dri/renderD128"
            container_path = "/dev/dri/renderD128"
          }
        ]
      }

      # RTSP password injected from Nomad variables (sourced from sops secrets).
      # Reference in config.yml as: {FRIGATE_RTSP_PASSWORD}
      template {
        data        = <<EOH
FRIGATE_RTSP_PASSWORD="{{ with nomadVar "nomad/jobs/frigate" }}{{ .rtsp_password }}{{ end }}"
EOH
        destination = "secrets/frigate.env"
        env         = true
      }

      service {
        name = "frigate"
        port = "http"

        tags = [
          "traefik.enable=true",
          "traefik.http.routers.frigate.middlewares=auth@file",
          "traefik.http.routers.frigate-token.rule=Host(`n7gdph5cuh7bd1cakbq8s099rvrv3qhs-frigate.othrayte.one`)",
        ]

        check {
          name     = "alive"
          type     = "http"
          path     = "/api/version"
          port     = "http"
          interval = "10s"
          timeout  = "5s"
        }
      }

      env {
        TZ = "Australia/Melbourne"
      }

      # config.yml lives here (read from CIFS). SQLite DB is at /alloc/data/frigate.db
      # (local NVMe, managed by Litestream). Requires in config.yml:
      #   database:
      #     path: /alloc/data/frigate.db
      volume_mount {
        volume      = "unraid_appdata_frigate"
        destination = "/config"
        read_only   = false
      }

      # Recordings, clips, and exports.
      volume_mount {
        volume      = "unraid_media_frigate"
        destination = "/media/frigate"
        read_only   = false
      }

      resources {
        # GPU handles inference; CPU manages stream ingestion, motion detection, and recording.
        cpu    = 2000
        memory = 2048
      }
    }

    volume "unraid_appdata_frigate" {
      type            = "csi"
      read_only       = false
      source          = "unraid_appdata_frigate"
      access_mode     = "single-node-writer"
      attachment_mode = "file-system"

      mount_options {
        mount_flags = ["nobrl", "uid=0", "gid=0"]
      }
    }

    volume "unraid_media_frigate" {
      type            = "csi"
      read_only       = false
      source          = "unraid_media_frigate"
      access_mode     = "single-node-writer"
      attachment_mode = "file-system"

      mount_options {
        mount_flags = ["nobrl", "uid=0", "gid=0"]
      }
    }
  }
}
