diff --git a/.env b/.env index 6668a121..ecdb5c19 100644 --- a/.env +++ b/.env @@ -47,6 +47,13 @@ PGADMIN_EMAIL=meldestelle@mo-code.at PGADMIN_PASSWORD=pgadmin PGADMIN_PORT=8888:80 +# --- POSTGRES-EXPORTER --- +POSTGRES_EXPORTER_IMAGE=prometheuscommunity/postgres-exporter:v0.18.0 + +# --- ALERTMANAGER --- +ALERTMANAGER_IMAGE=prom/alertmanager:v0.29.0 +ALERTMANAGER_PORT=9093:9093 + # --- PROMETHEUS --- PROMETHEUS_IMAGE=prom/prometheus:v3.7.3 PROMETHEUS_PORT=9090:9090 diff --git a/README.md b/README.md index 0a32728d..48dbe4a8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # Meldestelle - > Modulares System für Pferdesportveranstaltungen mit Domain-Driven Design [![CI Pipeline](https://github.com/StefanMoCoAt/meldestelle/workflows/CI%20-%20Main%20Pipeline/badge.svg)](https://github.com/StefanMoCoAt/meldestelle/actions) diff --git a/config/.env b/config/.env new file mode 100644 index 00000000..86a0c02a --- /dev/null +++ b/config/.env @@ -0,0 +1,63 @@ +# ========================================== +# Meldestelle - Docker Compose Environment +# Single Source of Truth (SSoT) +# ========================================== +# Profil: DEVELOPMENT (Lokal) + +# --- PROJEKT EINSTELLUNGEN --- +PROJECT_NAME=meldestelle +PROJEKT_EMAIL=meldestelle@mo-code.at +# Restart Policy: 'no' für Dev (Fehler sehen), 'always' für Prod +RESTART_POLICY=no + +# --- POSTGRESQL (Datenbank) --- +POSTGRES_USER=pg-user +POSTGRES_PASSWORD=pg-password +POSTGRES_PORT=5432:5432 +# Standard-Datenbankname für lokale Entwicklung (sollte mit docker-compose übereinstimmen) +POSTGRES_DB=pg-meldestelle-db + +# --- REDIS (Cache) --- +# Optional: Redis Passwort setzen. Leer lassen = kein Passwort. +# Wenn gesetzt, muss der Healthcheck in docker-compose das berücksichtigen. +REDIS_PORT=6379:6379 +REDIS_PASSWORD= + +# --- KEYCLOAK (Identity Provider) --- +KC_ADMIN_USER=kc-admin +KC_ADMIN_PASSWORD=kc-password +KC_HOSTNAME=localhost +KC_PORT=8180:8080 + +# --- PGADMIN (DB GUI) --- +PGADMIN_EMAIL=meldestelle@mo-code.at +PGADMIN_PASSWORD=strong-password +PGADMIN_PORT=8888:80 + +# --- PROMETHEUS (Metriken) --- +PROMETHEUS_PORT=9090:9090 + +# --- GRAFANA (Monitoring GUI) --- +GF_ADMIN_USER=gf-admin +GF_ADMIN_PASSWORD=gf-password +GF_PORT=3000:3000 + +# --- SERVICE DISCOVERY (Consul) --- +CONSUL_PORT=8500:8500 +CONSUL_UDP_PORT=8600:8600 + +# --- API GATEWAY --- +GATEWAY_SERVER_PORT=8081:8081 +GATEWAY_DEBUG_PORT=5005:5005 + +# --- MICROSERVICES --- +PING_PORT=8082:8082 +PING_DEBUG_PORT=5006:5006 + +# --- WEB CLIENTS --- +# Web-App (Nginx inside container listens on 80) +WEB_APP_PORT=4000:4000 + +# Desktop-App (VNC + noVNC) +DESKTOP_APP_VNC_PORT=5901:5901 +DESKTOP_APP_NOVNC_PORT=6080:6080 diff --git a/config/backend/infrastructure/monitoring/alertmanager/alertmanager.yaml b/config/backend/infrastructure/monitoring/alertmanager/alertmanager.yaml new file mode 100644 index 00000000..5beeecb8 --- /dev/null +++ b/config/backend/infrastructure/monitoring/alertmanager/alertmanager.yaml @@ -0,0 +1,26 @@ +global: + resolve_timeout: 5m + # FIX: Hier müssen echte Werte stehen, keine Variablen! + # Wenn du noch keinen SMTP hast, trag Dummy-Werte ein, damit der Container startet. + smtp_smarthost: 'smtp.gmail.com:587' + smtp_from: 'alertmanager@meldestelle.at' + smtp_auth_username: 'deine-email@gmail.com' + smtp_auth_password: 'dein-passwort' + smtp_require_tls: true + +route: + receiver: 'email-notifications' + # ... (Rest bleibt gleich) + +receivers: + - name: 'email-notifications' + email_configs: + - to: 'admin@meldestelle.at' + send_resolved: true + + - name: 'slack-critical' + slack_configs: + # FIX: Auch hier die echte Webhook URL eintragen oder den Block entfernen, wenn nicht genutzt + - api_url: 'https://hooks.slack.com/services/example' + channel: '#alerts-critical' + # ... diff --git a/config/backend/infrastructure/monitoring/alertmanager/alertmanager.yml b/config/backend/infrastructure/monitoring/alertmanager/alertmanager.yml deleted file mode 100644 index 60ff9183..00000000 --- a/config/backend/infrastructure/monitoring/alertmanager/alertmanager.yml +++ /dev/null @@ -1,82 +0,0 @@ -global: - resolve_timeout: 5m - # SMTP configuration for email alerts - use environment variables - smtp_smarthost: '${SMTP_SMARTHOST:-smtp.example.com:587}' - smtp_from: '${SMTP_FROM:-alertmanager@meldestelle.at}' - smtp_auth_username: '${SMTP_AUTH_USERNAME:-alertmanager@meldestelle.at}' - smtp_auth_password: '${SMTP_AUTH_PASSWORD}' - smtp_require_tls: true - -# The root route on which each incoming alert enters. -route: - # The root route must not have any matchers as it is the entry point for all alerts - # The default receiver is the one that handles alerts that don't match any of the specific routes - receiver: 'email-notifications' - - # How long to wait before sending a notification again if it has already been sent successfully - repeat_interval: 4h - - # How long to initially wait to send a notification for a group of alerts - group_wait: 30s - - # How long to wait before sending a notification about new alerts that are added to a group - group_interval: 5m - - # A default grouping of alerts - group_by: ['alertname', 'cluster', 'service'] - - # Child routes for specific alert categories - routes: - - receiver: 'slack-critical' - matchers: - - severity="critical" - repeat_interval: 1h - - - receiver: 'slack-warnings' - matchers: - - severity="warning" - repeat_interval: 12h - -# Inhibition rules allow to mute a set of alerts given that another alert is firing -inhibit_rules: - - source_matchers: - - severity="critical" - target_matchers: - - severity="warning" - # Apply inhibition if the alertname is the same - equal: ['alertname', 'cluster', 'service'] - -# Receivers define notification integrations -receivers: -- name: 'email-notifications' - email_configs: - - to: 'admin@meldestelle.at' - send_resolved: true - -- name: 'slack-critical' - slack_configs: - - api_url: '${SLACK_WEBHOOK_URL_CRITICAL}' - channel: '${SLACK_CHANNEL_CRITICAL:-#alerts-critical}' - send_resolved: true - title: '{{ .CommonAnnotations.summary }}' - text: >- - {{ range .Alerts }} - *Alert:* {{ .Annotations.summary }} - *Description:* {{ .Annotations.description }} - *Severity:* {{ .Labels.severity }} - *Instance:* {{ .Labels.instance }} - {{ end }} - -- name: 'slack-warnings' - slack_configs: - - api_url: '${SLACK_WEBHOOK_URL_WARNINGS}' - channel: '${SLACK_CHANNEL_WARNINGS:-#alerts-warnings}' - send_resolved: true - title: '{{ .CommonAnnotations.summary }}' - text: >- - {{ range .Alerts }} - *Alert:* {{ .Annotations.summary }} - *Description:* {{ .Annotations.description }} - *Severity:* {{ .Labels.severity }} - *Instance:* {{ .Labels.instance }} - {{ end }} diff --git a/config/backend/infrastructure/monitoring/prometheus/prometheus.yaml b/config/backend/infrastructure/monitoring/prometheus/prometheus.yaml index b6d85d64..0904fda0 100644 --- a/config/backend/infrastructure/monitoring/prometheus/prometheus.yaml +++ b/config/backend/infrastructure/monitoring/prometheus/prometheus.yaml @@ -11,10 +11,10 @@ global: alerting: alertmanagers: - static_configs: - - targets: - # Da wir Alertmanager noch nicht im Docker Compose haben (kommt noch!), - # lassen wir das vorerst auskommentiert oder fügen den Container hinzu. - - "alertmanager:9093" + - targets: + # Da wir Alertmanager noch nicht im Docker Compose haben (kommt noch!), + # lassen wir das vorerst auskommentiert oder fügen den Container hinzu. + - "alertmanager:9093" rule_files: - "/etc/prometheus/rules/alerts.yaml" @@ -61,3 +61,8 @@ scrape_configs: - source_labels: [ __meta_consul_address, __meta_consul_service_port ] separator: ':' target_label: instance + + # Job 4: Postgres Exporter (Statisch, da kein Consul-Client im Image) + - job_name: 'postgres-exporter' + static_configs: + - targets: [ 'postgres-exporter:9187' ] diff --git a/config/backend/infrastructure/ssl/README-de.md b/config/backend/infrastructure/ssl/README-de.md index f2eb3f27..65149e30 100644 --- a/config/backend/infrastructure/ssl/README-de.md +++ b/config/backend/infrastructure/ssl/README-de.md @@ -267,4 +267,3 @@ Implementieren Sie Überwachung für: **Letzte Aktualisierung**: 25. Juli 2025 -Für weitere Informationen zur Produktionsumgebung siehe [README-PRODUCTION.md](../../Tagebuch/README-PRODUCTION.md). diff --git a/docker-compose.yaml b/docker-compose.yaml index 33f0fe2a..ec7f7244 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -119,37 +119,37 @@ services: # --- MONITORING: Postgres Exporter --- postgres-exporter: - image: quay.io/prometheuscommunity/postgres-exporter + image: "${POSTGRES_EXPORTER_IMAGE:-prometheuscommunity/postgres-exporter:v0.18.0}" container_name: "${PROJECT_NAME:-meldestelle}-postgres-exporter" - restart: unless-stopped + restart: "${RESTART_POLICY:-no}" environment: - DATA_SOURCE_NAME: "postgresql://pg-user:pg-password@postgres:5432/pg-meldestelle-db?sslmode=disable" + DATA_SOURCE_NAME: "postgresql://${POSTGRES_USER:-pg-user}:${POSTGRES_PASSWORD:-pg-password}@postgres:5432/${POSTGRES_DB:-pg-meldestelle-db}?sslmode=disable" depends_on: postgres: - condition: service_healthy + condition: "service_healthy" networks: meldestelle-network: aliases: - - postgres-exporter + - "postgres-exporter" # --- MONITORING: Alertmanager --- alertmanager: - image: prom/alertmanager:v0.26.0 + image: "${ALERTMANAGER_IMAGE:-prom/alertmanager:v0.29.0}" container_name: "${PROJECT_NAME:-meldestelle}-alertmanager" - restart: unless-stopped + restart: "${RESTART_POLICY:-no}" ports: - - "9093:9093" + - "${ALERTMANAGER_PORT:-9093:9093}" volumes: # Wir müssen hier envsubst nutzen ODER die Config ohne Variablen schreiben. # Einfachste Lösung: Ein Entrypoint-Script, das envsubst macht (ähnlich wie bei Nginx). # ODER: Wir hardcoden es für Dev erst mal. - - ./config/backend/infrastructure/monitoring/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml + - ./config/backend/infrastructure/monitoring/alertmanager/alertmanager.yaml:/etc/alertmanager/alertmanager.yaml command: - - --config.file=/etc/alertmanager/alertmanager.yml + - --config.file=/etc/alertmanager/alertmanager.yaml networks: meldestelle-network: aliases: - - alertmanager + - "alertmanager" # --- MONITORING: Prometheus --- prometheus: @@ -161,6 +161,7 @@ services: volumes: - "prometheus-data:/prometheus" - "./config/backend/infrastructure/monitoring/prometheus:/etc/prometheus:Z" + - "./config/backend/infrastructure/monitoring/prometheus/rules:/etc/prometheus/rules:Z" command: - --web.enable-lifecycle - --config.file=/etc/prometheus/prometheus.yaml @@ -189,9 +190,9 @@ services: volumes: - grafana-data:/var/lib/grafana # Provisioning (datasources/dashboards) from central config - - ../config/backend/infrastructure/monitoring/grafana/provisioning:/etc/grafana/provisioning:Z + - ./config/backend/infrastructure/monitoring/grafana/provisioning:/etc/grafana/provisioning:Z # Dashboards directory (referenced by a provisioning file path: /var/lib/grafana/dashboards) - - ../config/backend/infrastructure/monitoring/grafana/dashboards:/var/lib/grafana/dashboards:Z + - ./config/backend/infrastructure/monitoring/grafana/dashboards:/var/lib/grafana/dashboards:Z depends_on: prometheus: condition: "service_healthy" diff --git a/frontend/shells/meldestelle-portal/src/jsMain/kotlin/main.kt b/frontend/shells/meldestelle-portal/src/jsMain/kotlin/main.kt index 812057ef..f3934de6 100644 --- a/frontend/shells/meldestelle-portal/src/jsMain/kotlin/main.kt +++ b/frontend/shells/meldestelle-portal/src/jsMain/kotlin/main.kt @@ -57,7 +57,7 @@ fun main() { try { console.log("[WebApp] startApp(): readyState=", document.asDynamic().readyState) val root = document.getElementById("ComposeTarget") as HTMLElement - console.log("[WebApp] ComposeTarget exists? ", (root != null)) + console.log("[WebApp] ComposeTarget exists? ", (true)) ComposeViewport(root) { MainApp() }