(fix) Konfiguration-Setup Umbau zu SCS

This commit is contained in:
stefan
2025-07-19 14:13:51 +02:00
parent b3f8624aa9
commit e38ab27fbe
18 changed files with 655 additions and 121 deletions
@@ -0,0 +1,187 @@
package at.mocode.shared.config
import at.mocode.shared.database.DatabaseConfig
import java.io.File
import java.util.Properties
/**
* Zentrale Konfigurationsverwaltung für die Anwendung.
* Lädt Konfigurationen aus verschiedenen Quellen (Umgebungsvariablen, Property-Dateien).
*/
object AppConfig {
// Aktuelle Umgebung
val environment: AppEnvironment = AppEnvironment.current()
// Anwendungs-Informationen
val appInfo = AppInfoConfig()
// Server-Konfiguration
val server = ServerConfig()
// Sicherheits-Konfiguration
val security = SecurityConfig()
// Logging-Konfiguration
val logging = LoggingConfig()
// Datenbank-Konfiguration (wird nach dem Laden der Properties initialisiert)
val database: DatabaseConfig
init {
// Lade Umgebungsspezifische Properties
val props = loadProperties()
// Konfiguriere Komponenten mit Properties
appInfo.configure(props)
server.configure(props)
security.configure(props)
logging.configure(props)
// Datenbank-Konfiguration mit Properties initialisieren
database = DatabaseConfig.fromEnv(props)
// Log Konfigurationsinformationen
if (!AppEnvironment.isProduction()) {
println("=== Anwendungskonfiguration ===")
println("Umgebung: $environment")
println("App: ${appInfo.name} v${appInfo.version}")
println("Server: Port ${server.port}, ${server.workers} Worker")
println("Datenbank: ${database.jdbcUrl}")
println("===============================\n")
}
}
/**
* Lädt die Properties für die aktuelle Umgebung.
*/
private fun loadProperties(): Properties {
val props = Properties()
// Lade Basis-Properties
loadPropertiesFile("application.properties", props)
// Lade umgebungsspezifische Properties
val envFile = when (environment) {
AppEnvironment.DEVELOPMENT -> "application-dev.properties"
AppEnvironment.TEST -> "application-test.properties"
AppEnvironment.STAGING -> "application-staging.properties"
AppEnvironment.PRODUCTION -> "application-prod.properties"
}
loadPropertiesFile(envFile, props)
return props
}
/**
* Lädt eine Property-Datei, wenn sie existiert.
*/
private fun loadPropertiesFile(filename: String, props: Properties) {
val resourceStream = javaClass.classLoader.getResourceAsStream(filename)
if (resourceStream != null) {
props.load(resourceStream)
resourceStream.close()
} else {
// Versuche aus dem Dateisystem zu laden
val file = File("config/$filename")
if (file.exists()) {
file.inputStream().use { props.load(it) }
}
}
}
/**
* Gibt den Wert einer Property zurück, wobei die Priorität wie folgt ist:
* 1. Umgebungsvariable
* 2. Property aus Datei
* 3. Standardwert
*/
fun getProperty(key: String, defaultValue: String? = null): String? {
val envKey = key.replace('.', '_').uppercase()
return System.getenv(envKey) ?: defaultValue
}
}
/**
* Konfiguration für Anwendungsinformationen.
*/
class AppInfoConfig {
var name: String = "Meldestelle"
var version: String = "1.0.0"
var description: String = "Pferdesport Meldestelle System"
fun configure(props: Properties) {
name = props.getProperty("app.name", name)
version = props.getProperty("app.version", version)
description = props.getProperty("app.description", description)
}
}
/**
* Konfiguration für den Server.
*/
class ServerConfig {
var port: Int = System.getenv("API_PORT")?.toIntOrNull() ?: 8081
var host: String = System.getenv("API_HOST") ?: "0.0.0.0"
var workers: Int = Runtime.getRuntime().availableProcessors()
var cors: CorsConfig = CorsConfig()
fun configure(props: Properties) {
port = props.getProperty("server.port")?.toIntOrNull() ?: port
host = props.getProperty("server.host") ?: host
workers = props.getProperty("server.workers")?.toIntOrNull() ?: workers
// CORS Konfiguration
cors.enabled = props.getProperty("server.cors.enabled")?.toBoolean() ?: cors.enabled
props.getProperty("server.cors.allowedOrigins")?.split(",")?.map { it.trim() }?.let {
cors.allowedOrigins = it
}
}
class CorsConfig {
var enabled: Boolean = true
var allowedOrigins: List<String> = listOf("*")
}
}
/**
* Konfiguration für die Sicherheit.
*/
class SecurityConfig {
var jwt = JwtConfig()
fun configure(props: Properties) {
// JWT Konfiguration
jwt.secret = System.getenv("JWT_SECRET") ?: props.getProperty("security.jwt.secret") ?: jwt.secret
jwt.issuer = System.getenv("JWT_ISSUER") ?: props.getProperty("security.jwt.issuer") ?: jwt.issuer
jwt.audience = System.getenv("JWT_AUDIENCE") ?: props.getProperty("security.jwt.audience") ?: jwt.audience
jwt.realm = System.getenv("JWT_REALM") ?: props.getProperty("security.jwt.realm") ?: jwt.realm
props.getProperty("security.jwt.expirationInMinutes")?.toLongOrNull()?.let {
jwt.expirationInMinutes = it
}
}
class JwtConfig {
var secret: String = "default-jwt-secret-key-please-change-in-production"
var issuer: String = "meldestelle-api"
var audience: String = "meldestelle-clients"
var realm: String = "meldestelle"
var expirationInMinutes: Long = 60 * 24 // 24 Stunden
}
}
/**
* Konfiguration für das Logging.
*/
class LoggingConfig {
var level: String = if (AppEnvironment.isProduction()) "INFO" else "DEBUG"
var logRequests: Boolean = true
var logResponses: Boolean = !AppEnvironment.isProduction()
fun configure(props: Properties) {
level = props.getProperty("logging.level") ?: level
logRequests = props.getProperty("logging.requests")?.toBoolean() ?: logRequests
logResponses = props.getProperty("logging.responses")?.toBoolean() ?: logResponses
}
}
@@ -0,0 +1,48 @@
package at.mocode.shared.config
/**
* Aufzählung der verschiedenen Anwendungsumgebungen.
*/
enum class AppEnvironment {
DEVELOPMENT, // Lokale Entwicklungsumgebung
TEST, // Testumgebung (CI/CD, Integrationstests)
STAGING, // Vorabproduktionsumgebung
PRODUCTION; // Produktionsumgebung
companion object {
/**
* Ermittelt die aktuelle Umgebung basierend auf der APP_ENV Umgebungsvariable.
*
* @return Die aktuelle Umgebung (Standardmäßig DEVELOPMENT wenn nicht definiert)
*/
fun current(): AppEnvironment {
val envName = System.getenv("APP_ENV")?.uppercase() ?: "DEVELOPMENT"
return try {
valueOf(envName)
} catch (e: IllegalArgumentException) {
println("Warnung: Unbekannte Umgebung '$envName', verwende DEVELOPMENT")
DEVELOPMENT
}
}
/**
* Prüft, ob die aktuelle Umgebung die Entwicklungsumgebung ist.
*/
fun isDevelopment() = current() == DEVELOPMENT
/**
* Prüft, ob die aktuelle Umgebung die Testumgebung ist.
*/
fun isTest() = current() == TEST
/**
* Prüft, ob die aktuelle Umgebung die Staging-Umgebung ist.
*/
fun isStaging() = current() == STAGING
/**
* Prüft, ob die aktuelle Umgebung die Produktionsumgebung ist.
*/
fun isProduction() = current() == PRODUCTION
}
}
@@ -1,32 +1,45 @@
package at.mocode.shared.database
import java.util.Properties
/**
* Konfiguration für die Datenbankverbindung.
* Parameter werden aus Umgebungsvariablen gelesen oder Standardwerte verwendet.
* Parameter werden aus Umgebungsvariablen oder Property-Dateien gelesen.
*/
data class DatabaseConfig(
val jdbcUrl: String,
val username: String,
val password: String,
val driverClassName: String = "org.postgresql.Driver",
val maxPoolSize: Int = 10
val maxPoolSize: Int = 10,
val autoMigrate: Boolean = true
) {
companion object {
/**
* Erstellt eine Datenbank-Konfiguration aus Umgebungsvariablen.
* Erstellt eine Datenbank-Konfiguration aus Umgebungsvariablen und Properties.
* Wenn keine Umgebungsvariablen gefunden werden, werden Standardwerte für die Entwicklung verwendet.
*/
fun fromEnv(): DatabaseConfig {
val host = System.getenv("DB_HOST") ?: "localhost"
val port = System.getenv("DB_PORT") ?: "5432"
val database = System.getenv("DB_NAME") ?: "meldestelle_db"
val username = System.getenv("DB_USER") ?: "meldestelle_user"
val password = System.getenv("DB_PASSWORD") ?: "secure_password_change_me"
fun fromEnv(props: Properties = Properties()): DatabaseConfig {
// Priorität: Umgebungsvariablen > Properties > Standardwerte
val host = System.getenv("DB_HOST") ?: props.getProperty("database.host") ?: "localhost"
val port = System.getenv("DB_PORT") ?: props.getProperty("database.port") ?: "5432"
val database = System.getenv("DB_NAME") ?: props.getProperty("database.name") ?: "meldestelle_db"
val username = System.getenv("DB_USER") ?: props.getProperty("database.username") ?: "meldestelle_user"
val password = System.getenv("DB_PASSWORD") ?: props.getProperty("database.password") ?: "secure_password_change_me"
val maxPoolSize = System.getenv("DB_MAX_POOL_SIZE")?.toIntOrNull()
?: props.getProperty("database.maxPoolSize")?.toIntOrNull()
?: 10
val autoMigrate = System.getenv("DB_AUTO_MIGRATE")?.toBoolean()
?: props.getProperty("database.autoMigrate")?.toBoolean()
?: true
return DatabaseConfig(
jdbcUrl = "jdbc:postgresql://$host:$port/$database",
username = username,
password = password
password = password,
driverClassName = "org.postgresql.Driver",
maxPoolSize = maxPoolSize,
autoMigrate = autoMigrate
)
}
}