feat: add monitoring dashboard (Prometheus + Grafana + Umami + Admin)

Phase 1: Infrastructure
- Add docker/prometheus/prometheus.yml with scrape configs for all services
- Add docker/grafana/provisioning for auto-configured datasources
- Add docker/grafana/dashboards (system-overview, backends-docker)
- Update docker-compose.macmini.yml with monitoring services:
  - prometheus, grafana, node-exporter, cadvisor
  - postgres-exporter, redis-exporter, umami
- Add grafana.mana.how and analytics.mana.how to Caddyfile

Phase 2: Backend Metrics
- Create packages/shared-nestjs-metrics with:
  - MetricsModule (auto /metrics endpoint)
  - MetricsService (Counter, Histogram, Gauge helpers)
  - MetricsMiddleware (auto HTTP request tracking)

Phase 3: Umami Web Analytics
- Add Umami tracking scripts to all landing pages
- Add Umami tracking scripts to all web apps
- Create scripts/mac-mini/setup-umami-db.sh

Phase 4: Admin Dashboard (ManaCore Web)
- Add admin routes: /admin, /admin/users, /admin/system
- Create StatCard, QuickLinks, UserTable components
- Add Admin link to navigation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Till-JS 2026-01-23 15:31:39 +01:00
parent ad7a84feef
commit 6d86a08d63
36 changed files with 2779 additions and 559 deletions

View file

@ -378,6 +378,134 @@ services:
retries: 3
start_period: 40s
# ============================================
# Monitoring Stack
# ============================================
prometheus:
image: prom/prometheus:v2.51.0
container_name: manacore-prometheus
restart: always
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=30d'
- '--web.enable-lifecycle'
volumes:
- ./docker/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
ports:
- "9090:9090"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9090/-/healthy"]
interval: 30s
timeout: 10s
retries: 3
grafana:
image: grafana/grafana:10.4.1
container_name: manacore-grafana
restart: always
depends_on:
prometheus:
condition: service_healthy
environment:
GF_SECURITY_ADMIN_USER: admin
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
GF_USERS_ALLOW_SIGN_UP: false
GF_SERVER_ROOT_URL: https://grafana.mana.how
volumes:
- ./docker/grafana/provisioning:/etc/grafana/provisioning:ro
- ./docker/grafana/dashboards:/var/lib/grafana/dashboards:ro
- grafana_data:/var/lib/grafana
ports:
- "3100:3000"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
node-exporter:
image: prom/node-exporter:v1.7.0
container_name: manacore-node-exporter
restart: always
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--path.rootfs=/rootfs'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
ports:
- "9100:9100"
cadvisor:
image: gcr.io/cadvisor/cadvisor:v0.49.1
container_name: manacore-cadvisor
restart: always
privileged: true
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
ports:
- "8080:8080"
postgres-exporter:
image: prometheuscommunity/postgres-exporter:v0.15.0
container_name: manacore-postgres-exporter
restart: always
depends_on:
postgres:
condition: service_healthy
environment:
DATA_SOURCE_NAME: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/postgres?sslmode=disable
ports:
- "9187:9187"
redis-exporter:
image: oliver006/redis_exporter:v1.58.0
container_name: manacore-redis-exporter
restart: always
depends_on:
redis:
condition: service_healthy
environment:
REDIS_ADDR: redis://redis:6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123}
ports:
- "9121:9121"
# ============================================
# Web Analytics (Umami)
# ============================================
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
container_name: manacore-umami
restart: always
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-manacore123}@postgres:5432/umami
DATABASE_TYPE: postgresql
APP_SECRET: ${UMAMI_APP_SECRET:-change-me-umami-secret}
DISABLE_TELEMETRY: 1
ports:
- "3200:3000"
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/heartbeat"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# ============================================
# Volumes
# ============================================
@ -387,3 +515,7 @@ volumes:
name: manacore-postgres
redis_data:
name: manacore-redis
prometheus_data:
name: manacore-prometheus
grafana_data:
name: manacore-grafana