feat: add runtime configuration for Caddy-based SPA containerization

Introduced `config.json` runtime configuration fetch mechanism to support the "Build Once, Deploy Everywhere" pattern. Replaced NGINX with Caddy for SPA deployment, enabling SPA routing, security headers, and static asset management. Updated Gradle and Kotlin/JS build configurations to align with the new runtime environment. Enhanced Dockerfile and health checks for optimized CI/CD workflows and improved SPA delivery.
This commit is contained in:
2026-02-02 16:19:20 +01:00
parent 86d8d780f5
commit 11c597f147
17 changed files with 327 additions and 193 deletions
@@ -2,8 +2,6 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget
/**
* Dieses Modul kapselt die gesamte UI und Logik für das Ping-Feature.
* Es kennt seine eigenen technischen Abhängigkeiten (Ktor, Coroutines)
* und den UI-Baukasten (common-ui), aber es kennt keine anderen Features.
*/
plugins {
alias(libs.plugins.kotlinMultiplatform)
@@ -16,45 +14,23 @@ group = "at.mocode.clients"
version = "1.0.0"
kotlin {
// Toolchain is now handled centrally in the root build.gradle.kts
jvm()
js {
binaries.library()
browser {
testTask {
enabled = false
}
testTask { enabled = false }
}
}
// Wasm vorerst deaktiviert
/*
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
}
*/
sourceSets {
commonMain.dependencies {
// Contract from backend
implementation(projects.contracts.pingApi)
// UI Kit (Design System)
implementation(projects.frontend.core.designSystem)
// Generic Delta-Sync core
implementation(projects.frontend.core.sync)
// Local DB (SQLDelight)
implementation(projects.frontend.core.localDb)
implementation(libs.sqldelight.coroutines) // Explicitly add coroutines extension for async driver support
implementation(libs.sqldelight.coroutines)
implementation(projects.frontend.core.domain)
// Shared sync contract base (Syncable)
implementation(projects.core.coreDomain)
// Compose dependencies
implementation(compose.foundation)
implementation(compose.runtime)
implementation(compose.material3)
@@ -62,12 +38,10 @@ kotlin {
implementation(compose.components.resources)
implementation(compose.materialIconsExtended)
// Bundles (Cleaned up dependencies)
implementation(libs.bundles.kmp.common) // Coroutines, Serialization, DateTime
implementation(libs.bundles.ktor.client.common) // Ktor Client (Core, Auth, JSON, Logging)
implementation(libs.bundles.compose.common) // ViewModel & Lifecycle
implementation(libs.bundles.kmp.common)
implementation(libs.bundles.ktor.client.common)
implementation(libs.bundles.compose.common)
// DI (Koin) for resolving apiClient from container
implementation(libs.koin.core)
}
@@ -78,7 +52,7 @@ kotlin {
}
jvmTest.dependencies {
implementation(libs.mockk) // MockK only for JVM tests
implementation(libs.mockk)
implementation(projects.platform.platformTesting)
implementation(libs.bundles.testing.jvm)
}
@@ -90,22 +64,9 @@ kotlin {
jsMain.dependencies {
implementation(libs.ktor.client.js)
}
/*
val wasmJsMain = getByName("wasmJsMain")
wasmJsMain.dependencies {
implementation(libs.ktor.client.js) // WASM verwendet JS-Client [cite: 7]
// Compose für shared UI components für WASM
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material3)
}
*/
}
}
// KMP Compile-Optionen
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
compilerOptions {
jvmTarget.set(JvmTarget.JVM_25)
@@ -132,8 +132,8 @@ class TestPingApiClient : PingApi {
return handleRequest(securePingResponse)
}
override suspend fun syncPings(lastSyncTimestamp: Long): List<PingEvent> {
syncPingsCalledWith = lastSyncTimestamp
override suspend fun syncPings(since: Long): List<PingEvent> {
syncPingsCalledWith = since
callCount++
if (simulateDelay) {