FigJam Diagram: Digital Signage — Multi-Service Kiosk Platform (expires 2026-04-13)
Multi-service digital signage system powering Raspberry Pi kiosks around the house. Aggregates calendar, weather, chores, Home Assistant sensor data, and device state into a single dashboard display.
| Internal URL | https://ds.k3s.internal.strommen.systems |
| Namespace | digital-signage |
| Auth | Authentik forwardAuth (internal URL) |
| MQTT LB | 192.168.20.203:1883 (MetalLB LoadBalancer for kiosk LAN access) |
| PSS | baseline (enforced via kubernetes/core/pod-security-standards.yaml) |
| Images | harbor.../production/digital-signage-*:sha-c4515673 (7 APIs + frontend) |
| Service | Port | Purpose |
|---|---|---|
ds-frontend |
80 | nginx SPA serving the display dashboard |
ds-calendar-api |
5560 | Calendar event aggregation (Google Calendar optional) |
ds-weather-api |
5561 | Weather data (OpenWeatherMap optional) |
ds-quotes-api |
5562 | Quote rotation |
ds-chores-api |
5563 | Chore schedule management |
ds-ha-proxy |
5564 | Home Assistant sensor/device proxy |
ds-settings-api |
5565 | Layout config, user settings, display profiles (also handles /api/users and /api/layouts routes) |
ds-device-manager |
5566 | Kiosk device state, MQTT publisher |
mosquitto |
1883 | MQTT broker for kiosk device management |
All services use the same Harbor image SHA (sha-c4515673), strategy: Recreate, and Prometheus ServiceMonitors at /metrics.
ds-ha-proxy bridges the display system to Home Assistant. It calls the HA REST API at http://home-assistant.home-assistant:8123 using a long-lived token from the ha-access-token secret. This surfaces sensor data (lights, switches, climate sensors) directly on the kiosk display.
mosquitto runs as a Deployment with a 1Gi Longhorn PVC for persistence. It's exposed as a MetalLB LoadBalancer service at 192.168.20.203:1883 so Raspberry Pi kiosks can connect from the LAN without going through Traefik.
The ds-device-manager service publishes device state changes to MQTT topics that kiosks subscribe to.
Security note: Mosquitto is configured with
allow_anonymous true. This is intentional — Raspberry Pi kiosks on the home LAN connect without authentication. MQTT traffic is LAN-only; the broker is not exposed externally.
| Secret | Keys | Purpose |
|---|---|---|
postgres-credentials |
POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, DATABASE_URL |
Database access (all APIs) |
ha-access-token |
HA_ACCESS_TOKEN |
Home Assistant long-lived token |
google-calendar-credentials |
GOOGLE_CALENDAR_CREDENTIALS |
Optional Google Calendar integration (optional: true in manifest) |
api-keys |
OPENWEATHERMAP_API_KEY |
Optional weather data (optional: true in manifest) |
postgres-backup-aws-credentials |
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY |
S3 backup access (from Terraform k3s-backups IAM user) |
Bootstrap:
PW="$(openssl rand -base64 32)"
kubectl create secret generic postgres-credentials --namespace digital-signage \
--from-literal=POSTGRES_USER=digitalsignage \
--from-literal=POSTGRES_PASSWORD="${PW}" \
--from-literal=POSTGRES_DB=digitalsignage \
--from-literal=DATABASE_URL="postgresql://digitalsignage:${PW}@postgres:5432/digitalsignage"
kubectl create secret generic ha-access-token --namespace digital-signage \
--from-literal=HA_ACCESS_TOKEN=<long-lived-HA-token>
# AWS credentials from Terraform output
kubectl create secret generic postgres-backup-aws-credentials --namespace digital-signage \
--from-literal=AWS_ACCESS_KEY_ID=$(terraform -chdir=terraform/environments/aws output -raw k3s_backups_access_key_id) \
--from-literal=AWS_SECRET_ACCESS_KEY=$(terraform -chdir=terraform/environments/aws output -raw k3s_backups_secret_access_key)
# Optional: Google Calendar and weather API keys
kubectl create secret generic google-calendar-credentials --namespace digital-signage \
--from-literal=GOOGLE_CALENDAR_CREDENTIALS='<oauth2-json>'
kubectl create secret generic api-keys --namespace digital-signage \
--from-literal=OPENWEATHERMAP_API_KEY=<owm-api-key>
| Volume | Type | Size | Purpose |
|---|---|---|---|
postgres-data |
Longhorn RWO | 2Gi | PostgreSQL app data |
mosquitto-data |
Longhorn RWO | 1Gi | MQTT broker persistence |
All 7 API microservices expose Prometheus metrics via pod annotations and individual ServiceMonitors (30s scrape interval, /metrics path). There is a dedicated Grafana dashboard in kubernetes/apps/digital-signage/grafana-dashboard.yaml.
CronJob schedule: daily at 3:35 AM UTC → s3://k3s-homelab-backups-855878721457/postgres-backups/digital-signage/
Retention: 7 days.
Note: The backup image
harbor.../production/postgres-backup:latestuses:latesttag — this is a known policy violation. Should be promoted to a SHA-pinned tag.
Kubernetes Ingress resource (ingressClassName: traefik) with path-based routing:
/api/calendar → ds-calendar-api:5560/api/weather → ds-weather-api:5561/api/quotes → ds-quotes-api:5562/api/chores → ds-chores-api:5563/api/ha → ds-ha-proxy:5564/api/settings, /api/users, /api/layouts → ds-settings-api:5565/api/devices → ds-device-manager:5566/ → ds-frontend:80 (catch-all)Auth middleware: public-ingress-authentik-forward-auth@kubernetescrd
kubernetes/apps/digital-signage/
digital-signage.yaml — Namespace, PostgreSQL StatefulSet, Mosquitto Deployment,
7 API Deployments + ds-frontend, Services,
Ingress (path-based), ServiceMonitors
grafana-dashboard.yaml — Pre-provisioned Grafana dashboard ConfigMap
postgres-backup-cronjob.yaml — Daily PostgreSQL backup to S3 (3:35 AM UTC)
kubernetes/core/pod-security-standards.yaml
— baseline PSS enforcement for digital-signage namespace