Files
alo-cluster/services/phaseflow.hcl
Petru Paler d195efdb0e Add phaseflow service
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 10:20:40 +00:00

121 lines
2.8 KiB
HCL

# ABOUTME: Nomad job for PhaseFlow - menstrual cycle tracking and training app.
# ABOUTME: Runs Next.js app with PocketBase sidecar for data persistence.
# Setup required before running:
# sudo mkdir -p /data/services/phaseflow/pb_data && sudo chown 1000:1000 /data/services/phaseflow /data/services/phaseflow/pb_data
# nomad var put secrets/phaseflow \
# resend_api_key="re_xxxx" \
# encryption_key="$(openssl rand -hex 16)" \
# cron_secret="$(openssl rand -hex 32)"
job "phaseflow" {
datacenters = ["alo"]
# Force re-pull of :latest images on each nomad run
meta {
uuid = uuidv4()
}
update {
max_parallel = 1
health_check = "checks"
min_healthy_time = "30s"
healthy_deadline = "5m"
progress_deadline = "10m"
auto_revert = true
}
group "app" {
network {
port "http" {
to = 3000
}
port "pocketbase" {
to = 8090
}
}
# PocketBase sidecar - starts first, provides database
task "pocketbase" {
driver = "docker"
user = "1000"
lifecycle {
hook = "prestart"
sidecar = true
}
config {
image = "ghcr.io/muchobien/pocketbase:latest"
ports = ["pocketbase"]
volumes = ["/data/services/phaseflow/pb_data:/pb_data"]
}
env {
PB_DATA_DIR = "/pb_data"
}
resources {
memory = 256
}
}
# Main Next.js application
task "app" {
driver = "docker"
user = "1000"
config {
image = "gitea.v.paler.net/alo/phaseflow:latest"
ports = ["http"]
force_pull = true
}
env {
NODE_ENV = "production"
POCKETBASE_URL = "http://localhost:8090"
APP_URL = "https://phaseflow.v.paler.net"
EMAIL_FROM = "phaseflow@paler.net"
}
# Secrets from Nomad variables
template {
destination = "secrets/env.env"
env = true
data = <<EOH
RESEND_API_KEY={{ with nomadVar "secrets/phaseflow" }}{{ .resend_api_key }}{{ end }}
ENCRYPTION_KEY={{ with nomadVar "secrets/phaseflow" }}{{ .encryption_key }}{{ end }}
CRON_SECRET={{ with nomadVar "secrets/phaseflow" }}{{ .cron_secret }}{{ end }}
EOH
}
resources {
memory = 512
}
service {
name = "phaseflow"
port = "http"
tags = [
"traefik.enable=true",
"traefik.http.routers.phaseflow.entryPoints=websecure",
"metrics",
]
check {
type = "http"
path = "/api/health"
interval = "10s"
timeout = "5s"
check_restart {
limit = 3
grace = "60s"
}
}
}
}
}
}