diff --git a/.env b/.env index 09737202..2299b8ad 100644 --- a/.env +++ b/.env @@ -60,7 +60,8 @@ KC_ADMIN_PASSWORD=kc-password KC_DB=postgres KC_DB_SCHEMA=keycloak KC_DB_PASSWORD=meldestelle -# Lokal: localhost | Server: echte IP oder Domain (z.B. 10.0.0.50:8180 oder auth.meldestelle.at) +# Lokal: localhost | Server: echte IP oder Domain (z.B. 10.0.0.50 oder auth.meldestelle.at) +# WICHTIG: Nur den Hostnamen angeben, OHNE Port (Keycloak 26.x hostname v2) KC_HOSTNAME=localhost # false = kein Hostname-Strict-Check (empfohlen für Entwicklung und HTTP-only Server) KC_HOSTNAME_STRICT=false @@ -70,6 +71,7 @@ KC_MANAGEMENT_PORT=9000:9000 # --- KEYCLOAK TOKEN VALIDATION --- # Public Issuer URI (must match the token issuer from browser/postman) +# Lokal: http://localhost:8180 | Produktion: http://10.0.0.50:8180 SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=http://localhost:8180/realms/meldestelle # Internal JWK Set URI (for service-to-service communication within Docker) SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI=http://keycloak:8080/realms/meldestelle/protocol/openid-connect/certs @@ -144,6 +146,7 @@ PING_CONSUL_PREFER_IP=true CADDY_VERSION=2.11-alpine WEB_APP_PORT=4000:4000 WEB_BUILD_PROFILE=dev +# Lokal: http://localhost:8081 | Produktion: http://10.0.0.50:8081 WEB_APP_API_URL=http://localhost:8081 # --- DESKTOP-APP --- diff --git a/docs/01_Architecture/Minisforum-MS-R1/SSoT_Konfigurations-Masterplan_Zora.md b/docs/01_Architecture/Minisforum-MS-R1/SSoT_Konfigurations-Masterplan_Zora.md index 34b3312a..5d643c29 100644 --- a/docs/01_Architecture/Minisforum-MS-R1/SSoT_Konfigurations-Masterplan_Zora.md +++ b/docs/01_Architecture/Minisforum-MS-R1/SSoT_Konfigurations-Masterplan_Zora.md @@ -7,13 +7,13 @@ owner: DevOps Engineer ## 1. System-Umgebung (Infrastruktur) -| Parameter | Wert | Erklärung | -|:-----------------------|:----------------|:-------------------------------------------------------------| -| **Architektur** | `linux/arm64` | Native Architektur von Zora (CIX P1 / CP8180). | -| **Hypervisor** | Proxmox VE 8.4.10 | `pve.mo-code.at` — Web-UI: `https://pve.mo-code.at:8006` | -| **Proxmox-Node-IP** | `10.0.0.20` | SSH: `ssh root@10.0.0.20` | -| **Netz-Bridge** | `vmbr0` | Alle VMs und Container im Subnetz `10.0.0.0/24` | -| **Gateway (Router)** | `10.0.0.138` | Standard-Gateway für alle VMs/Container | +| Parameter | Wert | Erklärung | +|:---------------------|:------------------|:---------------------------------------------------------| +| **Architektur** | `linux/arm64` | Native Architektur von Zora (CIX P1 / CP8180). | +| **Hypervisor** | Proxmox VE 8.4.10 | `pve.mo-code.at` — Web-UI: `https://pve.mo-code.at:8006` | +| **Proxmox-Node-IP** | `10.0.0.20` | SSH: `ssh root@10.0.0.20` | +| **Netz-Bridge** | `vmbr0` | Alle VMs und Container im Subnetz `10.0.0.0/24` | +| **Gateway (Router)** | `10.0.0.138` | Standard-Gateway für alle VMs/Container | ### VM & Container Übersicht @@ -30,77 +30,77 @@ owner: DevOps Engineer ### Detaillierte Ressourcen-Konfiguration #### CT 100 — pangolin-client (LXC) -| Parameter | Wert | -|:-----------------|:---------------------------------------| -| **OS** | Ubuntu, arm64 | -| **CPU** | 4 Cores (cpulimit=4) | -| **RAM** | 512 MiB + 512 MiB Swap | -| **Disk** | 8 GB (`local:100/vm-100-disk-0.raw`) | -| **Netzwerk** | eth0 → vmbr0, IP `10.0.0.21/24`, GW `10.0.0.138`, Firewall: Yes | -| **Typ** | Unprivileged, nesting=1 | -| **Autostart** | Ja — order=1, up=30 | +| Parameter | Wert | +|:--------------|:----------------------------------------------------------------| +| **OS** | Ubuntu, arm64 | +| **CPU** | 4 Cores (cpulimit=4) | +| **RAM** | 512 MiB + 512 MiB Swap | +| **Disk** | 8 GB (`local:100/vm-100-disk-0.raw`) | +| **Netzwerk** | eth0 → vmbr0, IP `10.0.0.21/24`, GW `10.0.0.138`, Firewall: Yes | +| **Typ** | Unprivileged, nesting=1 | +| **Autostart** | Ja — order=1, up=30 | #### CT 101 — gitea (LXC) -| Parameter | Wert | -|:-----------------|:---------------------------------------| -| **OS** | Ubuntu, arm64 | -| **CPU** | 4 Cores | -| **RAM** | 1.00 GiB + 512 MiB Swap | -| **Disk** | 20 GB (`local:101/vm-101-disk-0.raw`) | -| **Netzwerk** | eth0 → vmbr0, IP `10.0.0.22/24`, GW `10.0.0.138`, Firewall: Yes | -| **Typ** | Unprivileged, nesting=1 | -| **Autostart** | Ja — order=2, up=30 | +| Parameter | Wert | +|:--------------|:----------------------------------------------------------------| +| **OS** | Ubuntu, arm64 | +| **CPU** | 4 Cores | +| **RAM** | 1.00 GiB + 512 MiB Swap | +| **Disk** | 20 GB (`local:101/vm-101-disk-0.raw`) | +| **Netzwerk** | eth0 → vmbr0, IP `10.0.0.22/24`, GW `10.0.0.138`, Firewall: Yes | +| **Typ** | Unprivileged, nesting=1 | +| **Autostart** | Ja — order=2, up=30 | #### CT 103 — immich (LXC) -| Parameter | Wert | -|:-----------------|:---------------------------------------| -| **OS** | Ubuntu, arm64 | -| **CPU** | 8 Cores | -| **RAM** | 10.00 GiB + 512 MiB Swap | -| **Root Disk** | 200 GB (`local:103/vm-103-disk-0.raw`) | -| **Mount Point** | mp0: `/mnt/immich_gross` → `/mnt/fotos` (Foto-Bibliothek) | -| **Netzwerk** | eth0 → vmbr0, IP `10.0.0.24/24`, GW `10.0.0.138`, Firewall: Yes | -| **Typ** | Unprivileged, nesting=1, keyctl=1, fuse=1 | -| **Autostart** | Ja — order=3, up=30 | +| Parameter | Wert | +|:----------------|:----------------------------------------------------------------| +| **OS** | Ubuntu, arm64 | +| **CPU** | 8 Cores | +| **RAM** | 10.00 GiB + 512 MiB Swap | +| **Root Disk** | 200 GB (`local:103/vm-103-disk-0.raw`) | +| **Mount Point** | mp0: `/mnt/immich_gross` → `/mnt/fotos` (Foto-Bibliothek) | +| **Netzwerk** | eth0 → vmbr0, IP `10.0.0.24/24`, GW `10.0.0.138`, Firewall: Yes | +| **Typ** | Unprivileged, nesting=1, keyctl=1, fuse=1 | +| **Autostart** | Ja — order=3, up=30 | #### CT 120 — ai-stack (LXC) -| Parameter | Wert | -|:-----------------|:---------------------------------------| -| **OS** | Ubuntu 24.04, arm64 | -| **CPU** | 10 Cores (cpulimit=10, cpuunits=1024) | -| **RAM** | 48.00 GiB + 4.00 GiB Swap | -| **Disk** | 200 GB (`local:120/vm-120-disk-0.raw`) | -| **Netzwerk** | eth0 → vmbr0, IP `10.0.0.60/24`, GW `10.0.0.138`, Firewall: Yes | -| **Typ** | Unprivileged, nesting=1, keyctl=1 | -| **Autostart** | Nein | -| **Dienste** | Ollama :11434, Open WebUI :3001 | +| Parameter | Wert | +|:--------------|:----------------------------------------------------------------| +| **OS** | Ubuntu 24.04, arm64 | +| **CPU** | 10 Cores (cpulimit=10, cpuunits=1024) | +| **RAM** | 48.00 GiB + 4.00 GiB Swap | +| **Disk** | 200 GB (`local:120/vm-120-disk-0.raw`) | +| **Netzwerk** | eth0 → vmbr0, IP `10.0.0.60/24`, GW `10.0.0.138`, Firewall: Yes | +| **Typ** | Unprivileged, nesting=1, keyctl=1 | +| **Autostart** | Nein | +| **Dienste** | Ollama :11434, Open WebUI :3001 | #### VM 110 — meldestelle-host (QEMU/KVM) -| Parameter | Wert | -|:-----------------|:-----------------------------------------------------------------| -| **BIOS** | OVMF (UEFI) | -| **Machine** | virt (ARM64, aarch64) | -| **CPU** | 8 Cores (1 Socket, host-type, numa=1) | -| **RAM** | 16.00 GiB (balloon=0, kein Dynamic Memory) | -| **Disk** | 150 GB SSD (`local:110/vm-110-disk-1.qcow2`, aio=io_uring, iothread=1, ssd=1) | -| **EFI Disk** | `local:110/vm-110-disk-0.qcow2`, efitype=4m, 64 MB | -| **Netzwerk** | virtio, bridge=vmbr0, Firewall: Yes | -| **SCSI** | VirtIO SCSI single | -| **Autostart** | Nein (order=any) | -| **QEMU Agent** | Enabled | -| **Dienste** | Docker App-Stack (API :8081, Keycloak :8180, Prometheus :9090, Grafana :3000) | +| Parameter | Wert | +|:---------------|:------------------------------------------------------------------------------| +| **BIOS** | OVMF (UEFI) | +| **Machine** | virt (ARM64, aarch64) | +| **CPU** | 8 Cores (1 Socket, host-type, numa=1) | +| **RAM** | 16.00 GiB (balloon=0, kein Dynamic Memory) | +| **Disk** | 150 GB SSD (`local:110/vm-110-disk-1.qcow2`, aio=io_uring, iothread=1, ssd=1) | +| **EFI Disk** | `local:110/vm-110-disk-0.qcow2`, efitype=4m, 64 MB | +| **Netzwerk** | virtio, bridge=vmbr0, Firewall: Yes | +| **SCSI** | VirtIO SCSI single | +| **Autostart** | Nein (order=any) | +| **QEMU Agent** | Enabled | +| **Dienste** | Docker App-Stack (API :8081, Keycloak :8180, Prometheus :9090, Grafana :3000) | #### VM 102 — gitea-runner (QEMU/KVM) -| Parameter | Wert | -|:-----------------|:-----------------------------------------------------------------| -| **BIOS** | OVMF (UEFI) | -| **Machine** | virt (ARM64) | -| **CPU** | 8 Cores (1 Socket, host-type, numa=1) | -| **RAM** | 16.00 GiB (balloon=0, kein Dynamic Memory) | -| **Disk** | 50 GB SSD (`local:102/vm-102-disk-1.qcow2`, aio=io_uring, iothread=1) | -| **EFI Disk** | `local:102/vm-102-disk-0.qcow2`, efitype=4m, 64 MB | -| **Netzwerk** | virtio, bridge=vmbr0, Firewall: Yes | -| **SCSI** | VirtIO SCSI single | +| Parameter | Wert | +|:-------------|:----------------------------------------------------------------------| +| **BIOS** | OVMF (UEFI) | +| **Machine** | virt (ARM64) | +| **CPU** | 8 Cores (1 Socket, host-type, numa=1) | +| **RAM** | 16.00 GiB (balloon=0, kein Dynamic Memory) | +| **Disk** | 50 GB SSD (`local:102/vm-102-disk-1.qcow2`, aio=io_uring, iothread=1) | +| **EFI Disk** | `local:102/vm-102-disk-0.qcow2`, efitype=4m, 64 MB | +| **Netzwerk** | virtio, bridge=vmbr0, Firewall: Yes | +| **SCSI** | VirtIO SCSI single | ## 2. Mail-Relay (SSoT Identity) @@ -112,13 +112,13 @@ Diese Daten müssen in der Spring Boot `application.yml` oder `.env` abgeglichen ## 3. Docker-Image Checkliste (ARM64 Kompatibilität) -| Dienst | Empfohlenes Image | Status | -|:---------------|:-------------------------------------------|:-----------------------------------------------| -| **Datenbank** | `postgres:16-alpine` | ARM64 Support: Ja | -| **Cache** | `valkey/valkey:9-alpine` | ARM64 Support: Ja (Besserer Support als Redis) | -| **Identity** | `quay.io/keycloak/keycloak:26.4` | ARM64 Support: Ja (Offiziell) | -| **Monitoring** | `prom/prometheus:v3.7.3` | ARM64 Support: Ja | -| **Dashboards** | `grafana/grafana:12.3` | ARM64 Support: Ja | +| Dienst | Empfohlenes Image | Status | +|:---------------|:-----------------------------------|:------------------------------| +| **Datenbank** | `postgres:16-alpine` | ARM64 Support: Ja | +| **Cache** | `valkey/valkey:9-alpine` | ARM64 Support: Ja | +| **Identity** | `quay.io/keycloak/keycloak:26.5.5` | ARM64 Support: Ja (Offiziell) | +| **Monitoring** | `prom/prometheus:v3.7.3` | ARM64 Support: Ja | +| **Dashboards** | `grafana/grafana:12.3` | ARM64 Support: Ja | ## 4. Backend & Gateway (Spring Boot) diff --git a/docs/90_Reports/Infrastructure_Status_Report_01-2026.md b/docs/90_Reports/Infrastructure_Status_Report_01-2026.md index 61c5a5a7..142bd1e9 100644 --- a/docs/90_Reports/Infrastructure_Status_Report_01-2026.md +++ b/docs/90_Reports/Infrastructure_Status_Report_01-2026.md @@ -24,14 +24,14 @@ Die Integrationstests des `ping-service` gegen die Docker-Umgebung waren erfolgr ## 2. Komponenten-Status -| Service | Status | Port (Host) | Bemerkung | -| :--- | :--- | :--- | :--- | -| **PostgreSQL** | ✅ Healthy | `5432` | Keycloak-Schema & `ping-service` DB (`pingdb`) aktiv. | -| **Redis** | ✅ Healthy | `6379` | Cache für Services bereit. | -| **Keycloak** | ✅ Running | `8180` | Realm `meldestelle` aktiv. JWT-Validierung durch Backend erfolgreich. | -| **Consul** | ✅ Healthy | `8500` | Service Discovery funktioniert. | -| **Zipkin** | ✅ Running | `9411` | Tracing-Server bereit. | -| **Mailpit** | ✅ Running | `8025` | SMTP-Mock bereit. | +| Service | Status | Port (Host) | Bemerkung | +|:---------------|:----------|:------------|:----------------------------------------------------------------------| +| **PostgreSQL** | ✅ Healthy | `5432` | Keycloak-Schema & `ping-service` DB (`pingdb`) aktiv. | +| **Redis** | ✅ Healthy | `6379` | Cache für Services bereit. | +| **Keycloak** | ✅ Running | `8180` | Realm `meldestelle` aktiv. JWT-Validierung durch Backend erfolgreich. | +| **Consul** | ✅ Healthy | `8500` | Service Discovery funktioniert. | +| **Zipkin** | ✅ Running | `9411` | Tracing-Server bereit. | +| **Mailpit** | ✅ Running | `8025` | SMTP-Mock bereit. | ## 3. Durchgeführte Maßnahmen (DevOps) diff --git a/docs/99_Journal/2026-03-06_Session_Log_Zora_Konfiguration.md b/docs/99_Journal/2026-03-06_Session_Log_Zora_Konfiguration.md index c0500d2c..213c58f2 100644 --- a/docs/99_Journal/2026-03-06_Session_Log_Zora_Konfiguration.md +++ b/docs/99_Journal/2026-03-06_Session_Log_Zora_Konfiguration.md @@ -15,35 +15,35 @@ erfassen und ein vollständiges, ausführbares Konfigurationsrunbook erstellen. ## Erkenntnisse aus User-Feedback ### VM 102 (Gitea-Runner — `10.0.0.23`) -| Punkt | Status | Detail | -|:---|:---|:---| -| `daemon.json` | ✅ OK | `insecure-registries: ["10.0.0.22:3000"]` gesetzt und verifiziert | -| `gitea-runner.service` | ❌ FEHLT | Binary (`act_runner`) nie installiert — Service existiert nicht | +| Punkt | Status | Detail | +|:-----------------------|:--------|:------------------------------------------------------------------| +| `daemon.json` | ✅ OK | `insecure-registries: ["10.0.0.22:3000"]` gesetzt und verifiziert | +| `gitea-runner.service` | ❌ FEHLT | Binary (`act_runner`) nie installiert — Service existiert nicht | **Root Cause:** Der Gitea Actions Runner wurde bisher nur als Prozess gestartet (oder gar nicht), nie als systemd-Service mit Binary aus den offiziellen `act_runner`-Releases eingerichtet. ### Gitea CT 101 (`10.0.0.22`) -| Punkt | Status | -|:---|:---| -| Registry-Packages (4x Images) | ✅ Vorhanden (Screenshot bestätigt) | -| Org-Secrets `REGISTRY_USER` + `REGISTRY_TOKEN` | ✅ Gesetzt (Screenshot bestätigt) | +| Punkt | Status | +|:-----------------------------------------------|:-----------------------------------| +| Registry-Packages (4x Images) | ✅ Vorhanden (Screenshot bestätigt) | +| Org-Secrets `REGISTRY_USER` + `REGISTRY_TOKEN` | ✅ Gesetzt (Screenshot bestätigt) | ### VM 110 (Meldestelle-Host — `10.0.0.50`) -| Punkt | Status | Detail | -|:---|:---|:---| -| `.env` befüllt | ⚠️ Teilweise | Echte Werte für Ports/Hostnamen OK, aber Passwörter sind noch Placeholder | -| `backup.sh` / `deploy.sh` | ✅ Vorhanden | Scripts korrekt implementiert | -| Stack gestartet | ❌ Offen | Erst nach Passwort-Fix starten | +| Punkt | Status | Detail | +|:--------------------------|:-------------|:--------------------------------------------------------------------------| +| `.env` befüllt | ⚠️ Teilweise | Echte Werte für Ports/Hostnamen OK, aber Passwörter sind noch Placeholder | +| `backup.sh` / `deploy.sh` | ✅ Vorhanden | Scripts korrekt implementiert | +| Stack gestartet | ❌ Offen | Erst nach Passwort-Fix starten | **Kritisch:** `.env` enthält `pg-password`, `kc-password`, `gf-password` — **vor Stack-Start ersetzen!** ### Workflow `.gitea/workflows/docker-publish.yaml` -| Punkt | Status | -|:---|:---| -| `docker/login-action@v3` | ✅ Aktiv | +| Punkt | Status | +|:---------------------------------------|:-----------------| +| `docker/login-action@v3` | ✅ Aktiv | | Alter Workaround (config.json manuell) | ✅ Auskommentiert | -| `max-parallel: 1` (OOM-Schutz) | ✅ Gesetzt | +| `max-parallel: 1` (OOM-Schutz) | ✅ Gesetzt | --- diff --git a/docs/99_Journal/2026-03-07_Session_Log_TechStack_Zusammenfassung.md b/docs/99_Journal/2026-03-07_Session_Log_TechStack_Zusammenfassung.md index 458e3e9a..52664f6c 100644 --- a/docs/99_Journal/2026-03-07_Session_Log_TechStack_Zusammenfassung.md +++ b/docs/99_Journal/2026-03-07_Session_Log_TechStack_Zusammenfassung.md @@ -22,8 +22,8 @@ für die Auswahl und Konfiguration eines Self-Hosted AI-Modells (Ollama auf Zora ## Erstellte Dokumente -| Datei | Inhalt | -|:------|:-------| +| Datei | Inhalt | +|:-----------------------------------------------------------------|:---------------------------------| | `docs/01_Architecture/Meldestelle_Tech_Stack_Zusammenfassung.md` | Vollständige Tech-Stack-Referenz | --- diff --git a/docs/99_Journal/2026-03-07_Session_Log_Zora_Hardware_Zusammenfassung.md b/docs/99_Journal/2026-03-07_Session_Log_Zora_Hardware_Zusammenfassung.md index c2a83e61..9dcdea64 100644 --- a/docs/99_Journal/2026-03-07_Session_Log_Zora_Hardware_Zusammenfassung.md +++ b/docs/99_Journal/2026-03-07_Session_Log_Zora_Hardware_Zusammenfassung.md @@ -13,9 +13,9 @@ von Zora (Minisforum MS-R1) als Basis für weitere Self-Hosted AI Recherchen. ## Durchgeführte Änderungen -| Datei | Aktion | Beschreibung | -|:------|:-------|:-------------| -| `docs/01_Architecture/Minisforum-MS-R1/Zora_Hardware_Zusammenfassung.md` | NEU | Vollständige Hardware-Referenz (CPU, GPU, NPU, RAM, Ports, Proxmox-Konfiguration, VMs/LXCs, Netzwerk, AI-Potenzial) | +| Datei | Aktion | Beschreibung | +|:-------------------------------------------------------------------------|:-------|:--------------------------------------------------------------------------------------------------------------------| +| `docs/01_Architecture/Minisforum-MS-R1/Zora_Hardware_Zusammenfassung.md` | NEU | Vollständige Hardware-Referenz (CPU, GPU, NPU, RAM, Ports, Proxmox-Konfiguration, VMs/LXCs, Netzwerk, AI-Potenzial) | ## Inhalt der Zusammenfassung diff --git a/frontend/core/auth/src/commonMain/kotlin/at/mocode/frontend/core/auth/data/AuthApiClient.kt b/frontend/core/auth/src/commonMain/kotlin/at/mocode/frontend/core/auth/data/AuthApiClient.kt index 64cdfeaf..7402d7cb 100644 --- a/frontend/core/auth/src/commonMain/kotlin/at/mocode/frontend/core/auth/data/AuthApiClient.kt +++ b/frontend/core/auth/src/commonMain/kotlin/at/mocode/frontend/core/auth/data/AuthApiClient.kt @@ -1,6 +1,7 @@ package at.mocode.frontend.core.auth.data import at.mocode.frontend.core.domain.AppConstants +import at.mocode.frontend.core.network.PlatformConfig import io.ktor.client.* import io.ktor.client.call.* import io.ktor.client.request.forms.* @@ -24,8 +25,8 @@ data class LoginResponse( */ class AuthApiClient( private val httpClient: HttpClient, - // Keycloak Basis-URL (z. B. http://localhost:8180) - private val keycloakBaseUrl: String = AppConstants.KEYCLOAK_URL, + // Keycloak Basis-URL — wird zur Laufzeit via PlatformConfig aufgelöst (SSoT: .env / globalThis.KEYCLOAK_URL) + private val keycloakBaseUrl: String = PlatformConfig.resolveKeycloakUrl(), // Realm-Name in Keycloak private val realm: String = AppConstants.KEYCLOAK_REALM, // Client-ID (Public Client empfohlen für Frontend-Flows) diff --git a/frontend/core/network/src/commonMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.kt b/frontend/core/network/src/commonMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.kt index 76a50dc6..1accbe25 100644 --- a/frontend/core/network/src/commonMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.kt +++ b/frontend/core/network/src/commonMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.kt @@ -1,6 +1,6 @@ package at.mocode.frontend.core.network - @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") expect object PlatformConfig { fun resolveApiBaseUrl(): String + fun resolveKeycloakUrl(): String } diff --git a/frontend/core/network/src/jsMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.js.kt b/frontend/core/network/src/jsMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.js.kt index a6e647fb..bc38db4f 100644 --- a/frontend/core/network/src/jsMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.js.kt +++ b/frontend/core/network/src/jsMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.js.kt @@ -36,4 +36,36 @@ actual object PlatformConfig { console.log("[PlatformConfig] Fallback API_BASE_URL: $fallbackUrl") return fallbackUrl } + + actual fun resolveKeycloakUrl(): String { + // 1) Prefer a global JS variable injected by index.html at runtime + val global = + js("typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {}))") + val fromGlobal = try { + (global.KEYCLOAK_URL as? String)?.trim().orEmpty() + } catch (_: dynamic) { + "" + } + if (fromGlobal.isNotEmpty()) { + console.log("[PlatformConfig] Resolved KEYCLOAK_URL from global: $fromGlobal") + return fromGlobal.removeSuffix("/") + } + + // 2) Derive from window.location.hostname with default Keycloak port + val hostname = try { + window.location.hostname + } catch (_: dynamic) { + null + } + if (!hostname.isNullOrBlank()) { + val resolvedUrl = "http://$hostname:8180" + console.log("[PlatformConfig] Resolved KEYCLOAK_URL from window.location.hostname: $resolvedUrl") + return resolvedUrl + } + + // 3) Fallback for local development + val fallbackUrl = "http://localhost:8180" + console.log("[PlatformConfig] Fallback KEYCLOAK_URL: $fallbackUrl") + return fallbackUrl + } } diff --git a/frontend/core/network/src/jvmMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.jvm.kt b/frontend/core/network/src/jvmMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.jvm.kt index 5e60397f..31f96f82 100644 --- a/frontend/core/network/src/jvmMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.jvm.kt +++ b/frontend/core/network/src/jvmMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.jvm.kt @@ -9,4 +9,10 @@ actual object PlatformConfig { // Fallback default to the local gateway return "http://localhost:8081" } + + actual fun resolveKeycloakUrl(): String { + val env = System.getenv("KEYCLOAK_URL")?.trim().orEmpty() + if (env.isNotEmpty()) return env.removeSuffix("/") + return "http://localhost:8180" + } } diff --git a/frontend/core/network/src/wasmJsMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.wasmJs.kt b/frontend/core/network/src/wasmJsMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.wasmJs.kt index 7fbf8d31..0023612e 100644 --- a/frontend/core/network/src/wasmJsMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.wasmJs.kt +++ b/frontend/core/network/src/wasmJsMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.wasmJs.kt @@ -4,6 +4,14 @@ import kotlinx.browser.window @Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") actual object PlatformConfig { + actual fun resolveKeycloakUrl(): String { + val fromGlobal = getGlobalKeycloakUrl() + if (fromGlobal.isNotEmpty()) return fromGlobal.removeSuffix("/") + val hostname = getWindowHostname() + if (hostname.isNotEmpty()) return "http://$hostname:8180" + return "http://localhost:8180" + } + actual fun resolveApiBaseUrl(): String { // 1) Prefer a global JS variable (can be injected by index.html or nginx) val fromGlobal = getGlobalApiBaseUrl() @@ -36,3 +44,20 @@ private fun getGlobalApiBaseUrl(): String = js( })() """ ) + +private fun getGlobalKeycloakUrl(): String = js( + """ + (function() { + var global = typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); + return (global.KEYCLOAK_URL && typeof global.KEYCLOAK_URL === 'string') ? global.KEYCLOAK_URL : ""; + })() +""" +) + +private fun getWindowHostname(): String = js( + """ + (function() { + try { return window.location.hostname || ""; } catch(e) { return ""; } + })() +""" +) diff --git a/frontend/shells/meldestelle-portal/src/jsMain/resources/index.html b/frontend/shells/meldestelle-portal/src/jsMain/resources/index.html index ffcf32a2..0641bc83 100644 --- a/frontend/shells/meldestelle-portal/src/jsMain/resources/index.html +++ b/frontend/shells/meldestelle-portal/src/jsMain/resources/index.html @@ -12,23 +12,32 @@