From 95fe3e0573e700f223dbe404eb832f78e40f869f Mon Sep 17 00:00:00 2001 From: StefanMo <61204035+StefanMoCoAt@users.noreply.github.com> Date: Wed, 3 Dec 2025 12:03:40 +0100 Subject: [PATCH] chore(ci): Align GH Workflows with Docker SSoT, new paths; minimal SSoT guard; staticAnalysis (#23) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(MP-21): snapshot pre-refactor state (Epic 1) * chore(MP-22): scaffold new repo structure, relocate Docker Compose, move frontend/backend modules, update Makefile; add docs mapping and env template * MP-22 Epic 2: Erfolgreich umgesetzt und verifiziert * MP-23 Epic 3: Gradle/Build Governance zentralisieren * MP-23 Epic 3: Gradle/Build Governance zentralisieren * chore(devops)!: Docker-SSoT (.env) konsolidiert, Compose-Mounts ergänzt, Makefile entfernt - ENV Single Source of Truth - docker/.env.example neu (inkl. REDIS_PASSWORD, Ports, Build-Overrides) - config/.env(.example) als DEPRECATED markiert (Verweis auf docker/.env[.example]) - Docker Compose vereinheitlicht (docker/docker-compose.yaml) - Postgres: zentralen postgresql.conf mounten (../config/postgres/postgresql.conf) und Start mit -c config_file=/etc/postgresql/postgresql.conf - Redis: zentralen redis.conf mounten (../config/redis/redis.conf) und Start via "redis-server … ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}" - Web-Nginx: ../config/nginx/nginx.prod.conf → /etc/nginx/nginx.conf (ro) - Monitoring: Prometheus/Grafana nutzen ../config/monitoring/* als SSoT - Frontend/DI/Network (MP-23 Grundlage) - :frontend:core:network Modul mit Koin `apiClient` (Ktor + JSON/Retry/Timeout/Logging) - Plattform-Basis-URL-Auflösung (JVM: ENV API_BASE_URL; JS: globalThis.API_BASE_URL / Same-Origin) - Web index.html setzt API_BASE_URL (Query `?apiBaseUrl=…` > Same-Origin > Fallback) - Build/Gradle & Module-Refs - settings.gradle.kts: neue Frontend-/Backend-Pfade bereits inkludiert - Features/Shell: Abhängigkeiten auf :frontend:shared / :frontend:core:* angepasst - Ping-API-Refs auf :backend:services:ping:ping-api vereinheitlicht - Dockerfiles angepasst - backend/infrastructure/gateway/Dockerfile → Tasks/Pfade auf :backend:gateway - backend/services/ping/Dockerfile → Tasks/Pfade auf :backend:services:ping:ping-service - Static Analysis / Guards - config/detekt/detekt.yml hinzugefügt - Leichter Arch-Guard (Frontend) gegen manuelle Authorization-Header vorbereitet - Doku - docs/ARCHITECTURE.md (Struktur, Mapping, Next Steps) ergänzt - docs/adr/README.md angelegt BREAKING CHANGES: - Makefile komplett entfernt (bitte direkt `docker compose` verwenden) - ENV-Quelle ist jetzt docker/.env (statt config/.env oder Root) - Compose-Datei unter docker/docker-compose.yaml (nicht mehr compose.yaml im Repo-Root) Verifikation (lokal): - ENV anlegen: `cp docker/.env.example docker/.env` (Werte anpassen) - Compose prüfen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml config` - Infrastruktur: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle up -d postgres redis keycloak web-app` - Services bauen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle build api-gateway ping-service --no-cache --progress=plain` Refs: MP-22 (Epic 2), MP-23 (Epic 3) * chore(devops)!: Docker-SSoT (.env) konsolidiert, Compose-Mounts ergänzt, Makefile entfernt - ENV Single Source of Truth - docker/.env.example neu (inkl. REDIS_PASSWORD, Ports, Build-Overrides) - config/.env(.example) als DEPRECATED markiert (Verweis auf docker/.env[.example]) - Docker Compose vereinheitlicht (docker/docker-compose.yaml) - Postgres: zentralen postgresql.conf mounten (../config/postgres/postgresql.conf) und Start mit -c config_file=/etc/postgresql/postgresql.conf - Redis: zentralen redis.conf mounten (../config/redis/redis.conf) und Start via "redis-server … ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}" - Web-Nginx: ../config/nginx/nginx.prod.conf → /etc/nginx/nginx.conf (ro) - Monitoring: Prometheus/Grafana nutzen ../config/monitoring/* als SSoT - Frontend/DI/Network (MP-23 Grundlage) - :frontend:core:network Modul mit Koin `apiClient` (Ktor + JSON/Retry/Timeout/Logging) - Plattform-Basis-URL-Auflösung (JVM: ENV API_BASE_URL; JS: globalThis.API_BASE_URL / Same-Origin) - Web index.html setzt API_BASE_URL (Query `?apiBaseUrl=…` > Same-Origin > Fallback) - Build/Gradle & Module-Refs - settings.gradle.kts: neue Frontend-/Backend-Pfade bereits inkludiert - Features/Shell: Abhängigkeiten auf :frontend:shared / :frontend:core:* angepasst - Ping-API-Refs auf :backend:services:ping:ping-api vereinheitlicht - Dockerfiles angepasst - backend/infrastructure/gateway/Dockerfile → Tasks/Pfade auf :backend:gateway - backend/services/ping/Dockerfile → Tasks/Pfade auf :backend:services:ping:ping-service - Static Analysis / Guards - config/detekt/detekt.yml hinzugefügt - Leichter Arch-Guard (Frontend) gegen manuelle Authorization-Header vorbereitet - Doku - docs/ARCHITECTURE.md (Struktur, Mapping, Next Steps) ergänzt - docs/adr/README.md angelegt BREAKING CHANGES: - Makefile komplett entfernt (bitte direkt `docker compose` verwenden) - ENV-Quelle ist jetzt docker/.env (statt config/.env oder Root) - Compose-Datei unter docker/docker-compose.yaml (nicht mehr compose.yaml im Repo-Root) Verifikation (lokal): - ENV anlegen: `cp docker/.env.example docker/.env` (Werte anpassen) - Compose prüfen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml config` - Infrastruktur: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle up -d postgres redis keycloak web-app` - Services bauen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle build api-gateway ping-service --no-cache --progress=plain` Refs: MP-22 (Epic 2), MP-23 (Epic 3) * chore(devops)!: Docker-SSoT (.env) konsolidiert, Compose-Mounts ergänzt, Makefile entfernt - ENV Single Source of Truth - docker/.env.example neu (inkl. REDIS_PASSWORD, Ports, Build-Overrides) - config/.env(.example) als DEPRECATED markiert (Verweis auf docker/.env[.example]) - Docker Compose vereinheitlicht (docker/docker-compose.yaml) - Postgres: zentralen postgresql.conf mounten (../config/postgres/postgresql.conf) und Start mit -c config_file=/etc/postgresql/postgresql.conf - Redis: zentralen redis.conf mounten (../config/redis/redis.conf) und Start via "redis-server … ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}" - Web-Nginx: ../config/nginx/nginx.prod.conf → /etc/nginx/nginx.conf (ro) - Monitoring: Prometheus/Grafana nutzen ../config/monitoring/* als SSoT - Frontend/DI/Network (MP-23 Grundlage) - :frontend:core:network Modul mit Koin `apiClient` (Ktor + JSON/Retry/Timeout/Logging) - Plattform-Basis-URL-Auflösung (JVM: ENV API_BASE_URL; JS: globalThis.API_BASE_URL / Same-Origin) - Web index.html setzt API_BASE_URL (Query `?apiBaseUrl=…` > Same-Origin > Fallback) - Build/Gradle & Module-Refs - settings.gradle.kts: neue Frontend-/Backend-Pfade bereits inkludiert - Features/Shell: Abhängigkeiten auf :frontend:shared / :frontend:core:* angepasst - Ping-API-Refs auf :backend:services:ping:ping-api vereinheitlicht - Dockerfiles angepasst - backend/infrastructure/gateway/Dockerfile → Tasks/Pfade auf :backend:gateway - backend/services/ping/Dockerfile → Tasks/Pfade auf :backend:services:ping:ping-service - Static Analysis / Guards - config/detekt/detekt.yml hinzugefügt - Leichter Arch-Guard (Frontend) gegen manuelle Authorization-Header vorbereitet - Doku - docs/ARCHITECTURE.md (Struktur, Mapping, Next Steps) ergänzt - docs/adr/README.md angelegt BREAKING CHANGES: - Makefile komplett entfernt (bitte direkt `docker compose` verwenden) - ENV-Quelle ist jetzt docker/.env (statt config/.env oder Root) - Compose-Datei unter docker/docker-compose.yaml (nicht mehr compose.yaml im Repo-Root) Verifikation (lokal): - ENV anlegen: `cp docker/.env.example docker/.env` (Werte anpassen) - Compose prüfen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml config` - Infrastruktur: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle up -d postgres redis keycloak web-app` - Services bauen: `docker compose --env-file docker/.env -f docker/docker-compose.yaml -p meldestelle build api-gateway ping-service --no-cache --progress=plain` Refs: MP-22 (Epic 2), MP-23 (Epic 3) * chore(ci): Workflows an Docker-SSoT & neue Struktur angepasst, minimaler SSoT-Guard - ssot-guard.yml: Option B (minimal) → `docker compose -f docker/docker-compose.yaml config` als Lint - integration-tests.yml: `./gradlew staticAnalysis` vor Integrationstests - docs-kdoc-sync.yml: Dokka-Task Fallback (dokkaGfmAll || dokkaGfm), YouTrack-Sync nur wenn Script vorhanden - deploy-proxmox.yml: Compose-Pfade auf docker/docker-compose.yaml + `--env-file docker/.env`; Build/Test Schritte vereinheitlicht - ci-main.yml: SSoT-Skripte per `if: hashFiles(...)` guarded, Compose-Lint Fallback; OpenAPI‑Pfad → backend/gateway; ADR‑Pfade → docs/adr/**; `staticAnalysis` in Build integriert - youtrack-sync.yml: unverändert (funktional) Refs: MP-22, MP-23 * chore(ci): Workflows an Docker-SSoT & neue Struktur angepasst, minimaler SSoT-Guard - ssot-guard.yml: Option B (minimal) → `docker compose -f docker/docker-compose.yaml config` als Lint - integration-tests.yml: `./gradlew staticAnalysis` vor Integrationstests - docs-kdoc-sync.yml: Dokka-Task Fallback (dokkaGfmAll || dokkaGfm), YouTrack-Sync nur wenn Script vorhanden - deploy-proxmox.yml: Compose-Pfade auf docker/docker-compose.yaml + `--env-file docker/.env`; Build/Test Schritte vereinheitlicht - ci-main.yml: SSoT-Skripte per `if: hashFiles(...)` guarded, Compose-Lint Fallback; OpenAPI‑Pfad → backend/gateway; ADR‑Pfade → docs/adr/**; `staticAnalysis` in Build integriert - youtrack-sync.yml: unverändert (funktional) Refs: MP-22, MP-23 * fix(ci): create .env from example before validating compose config * fix(ci): update ssot-guard filename (.yaml) and sync workflow state * fixing * fix(webpack): correct sql.js fallback configuration for webpack 5 --- .dockerignore | 2 +- .env.template | 60 -- .github/workflows/ci-main.yml | 26 +- .github/workflows/deploy-proxmox.yml | 33 +- .github/workflows/docs-kdoc-sync.yml | 6 +- .github/workflows/integration-tests.yml | 5 +- .github/workflows/ssot-guard.yml | 220 +---- .github/workflows/youtrack-sync.yml | 2 +- .gitignore | 2 +- ...er-guideline-v3.0.1-archived-2025-09-15.md | 40 +- .../docker/docker-development.md | 10 +- .../docker/docker-monitoring.md | 2 +- .../docker/docker-production.md | 2 +- .../technology-guides/web-app-guideline.md | 4 +- README.md | 11 +- _backup_chaos/.env.template | 195 ----- _backup_chaos/.env~origin_main | 207 ----- _backup_chaos/README.md | 1 - _backup_chaos/Schlachtplan.md | 443 ---------- _backup_chaos/build-args/clients.env | 20 - _backup_chaos/build-args/global.env | 26 - _backup_chaos/build-args/infrastructure.env | 22 - _backup_chaos/build-args/services.env | 14 - _backup_chaos/compose.yaml | 12 - _backup_chaos/docker-compose.clients.yml | 54 -- _backup_chaos/docker-compose.services.yml | 80 -- _backup_chaos/docker-compose.yml | 162 ---- _backup_chaos/events/README.md | 1 - _backup_chaos/masterdata/README.md | 1 - _backup_chaos/members/README.md | 1 - _backup_chaos/secrets/README.md | 15 - .../secrets/grafana_admin_password.txt | 1 - _backup_chaos/secrets/grafana_admin_user.txt | 1 - _backup_chaos/secrets/jwt_secret.txt | 1 - .../secrets/keycloak_admin_password.txt | 1 - .../secrets/keycloak_auth_client_secret.txt | 1 - .../secrets/keycloak_client_secret.txt | 1 - .../secrets/metrics_auth_password.txt | 1 - .../secrets/metrics_auth_username.txt | 1 - _backup_chaos/secrets/postgres_password.txt | 1 - _backup_chaos/secrets/postgres_user.txt | 1 - _backup_chaos/secrets/redis_password.txt | 1 - _backup_chaos/secrets/setup-secrets.sh | 345 -------- _backup_chaos/secrets/vnc_password.txt | 1 - _backup_chaos/versions.toml.bak | 192 ---- backend/README.md | 7 - backend/gateway/gateway/CONFIGURATION.md | 733 ---------------- .../gateway/gateway/README-INFRA-GATEWAY.md | 442 ---------- .../cache/cache-api/build.gradle.kts | 0 .../cache/api/CacheConfiguration.kt | 0 .../infrastructure/cache/api/CacheEntry.kt | 0 .../cache/api/CacheSerializer.kt | 0 .../cache/api/ConnectionStatus.kt | 0 .../cache/api/DistributedCache.kt | 0 .../cache/api/DistributedCacheExtensions.kt | 0 .../cache/redis-cache/build.gradle.kts | 2 +- .../cache/redis/JacksonCacheSerializer.kt | 0 .../cache/redis/RedisConfiguration.kt | 0 .../cache/redis/RedisDistributedCache.kt | 0 .../RedisDistributedCacheConfigurationTest.kt | 0 .../RedisDistributedCacheEdgeCasesTest.kt | 0 .../RedisDistributedCacheIntegrationTest.kt | 0 .../RedisDistributedCachePerformanceTest.kt | 0 .../RedisDistributedCacheResilienceTest.kt | 0 .../cache/redis/RedisDistributedCacheTest.kt | 0 .../src/test/resources/logback-test.xml | 0 .../event-store-api/build.gradle.kts | 0 .../eventstore/api/EventSerializer.kt | 0 .../eventstore/api/EventStore.kt | 0 .../redis-event-store/build.gradle.kts | 6 +- .../eventstore/redis/EventStoreMetrics.kt | 0 .../redis/JacksonEventSerializer.kt | 0 .../eventstore/redis/RedisEventConsumer.kt | 0 .../eventstore/redis/RedisEventStore.kt | 0 .../redis/RedisEventStoreConfiguration.kt | 0 .../redis/JacksonEventSerializerTest.kt | 0 .../RedisCacheAndEventStoreIntegrationTest.kt | 0 .../redis/RedisEventConsumerResilienceTest.kt | 0 .../redis/RedisEventStoreConfigurationTest.kt | 0 .../redis/RedisEventStoreErrorHandlingTest.kt | 0 .../redis/RedisEventStoreIntegrationTest.kt | 0 .../redis/RedisEventStoreStreamTest.kt | 0 .../eventstore/redis/RedisEventStoreTest.kt | 0 .../eventstore/redis/RedisIntegrationTest.kt | 0 .../infrastructure/gateway/Dockerfile | 10 +- .../gateway/build.gradle.kts | 2 +- .../gateway/docs/index.html | 0 .../gateway/GatewayApplication.kt | 0 .../gateway/config/GatewayConfig.kt | 0 .../gateway/controller/FallbackController.kt | 0 .../gateway/health/GatewayHealthIndicator.kt | 0 .../gateway/metrics/GatewayMetricsConfig.kt | 0 .../gateway/security/SecurityConfig.kt | 0 .../main/resources/application-keycloak.yml | 0 .../src/main/resources/application.conf | 0 .../src/main/resources/application.yml | 0 .../src/main/resources/logback-spring.xml | 0 .../gateway/src/main/resources/logback.xml | 0 .../main/resources/openapi/documentation.yaml | 0 .../src/main/resources/static/docs/index.html | 0 .../postman/Meldestelle_API_Collection.json | 0 .../gateway/FallbackControllerTests.kt | 0 .../gateway/GatewayApplicationTests.kt | 0 .../gateway/GatewayFiltersTests.kt | 0 .../gateway/GatewayRoutingTests.kt | 0 .../gateway/GatewaySecurityTests.kt | 0 .../gateway/KeycloakGatewayIntegrationTest.kt | 0 .../gateway/config/TestSecurityConfig.kt | 0 .../src/test/resources/application-dev.yml | 0 .../application-keycloak-integration-test.yml | 0 .../src/test/resources/application-test.yml | 0 .../src/test/resources/logback-test.xml | 0 .../resources/test-init-keycloak-schema.sql | 2 +- .../messaging-client/build.gradle.kts | 2 +- .../messaging/client/EventConsumer.kt | 0 .../messaging/client/EventPublisher.kt | 0 .../messaging/client/KafkaEventConsumer.kt | 0 .../messaging/client/KafkaEventPublisher.kt | 0 .../messaging/client/MessagingError.kt | 0 .../messaging/client/ReactiveKafkaConfig.kt | 0 .../client/KafkaEventConsumerCacheTest.kt | 0 .../client/KafkaEventPublisherErrorTest.kt | 0 .../messaging/client/KafkaIntegrationTest.kt | 0 .../messaging/client/KafkaSecurityTest.kt | 0 .../messaging-config/build.gradle.kts | 0 .../messaging/config/KafkaConfig.kt | 0 .../messaging/config/KafkaConfigTest.kt | 0 .../monitoring-client/build.gradle.kts | 0 .../MonitoringClientAutoConfiguration.kt | 0 ...ot.autoconfigure.AutoConfiguration.imports | 0 .../resources/monitoring-defaults.properties | 0 .../monitoring-server/build.gradle.kts | 0 .../monitoring/MonitoringServerApplication.kt | 0 .../src/main/resources/application.properties | 0 .../MonitoringServerApplicationTest.kt | 0 .../src/test/resources/logback-test.xml | 0 .../services/events}/Dockerfile | 0 .../events/events-api/build.gradle.kts | 0 .../api/rest/VeranstaltungController.kt | 0 .../events/events-common/build.gradle.kts | 0 .../usecase/CreateVeranstaltungUseCase.kt | 0 .../usecase/DeleteVeranstaltungUseCase.kt | 0 .../usecase/GetVeranstaltungUseCase.kt | 0 .../usecase/UpdateVeranstaltungUseCase.kt | 0 .../events/events-domain/build.gradle.kts | 0 .../at/mocode/events/EventManagement.kt | 0 .../events/domain/model/Veranstaltung.kt | 0 .../repository/VeranstaltungRepository.kt | 0 .../events-infrastructure/build.gradle.kts | 0 .../VeranstaltungRepositoryImpl.kt | 0 .../persistence/VeranstaltungTable.kt | 0 .../events/events-service/build.gradle.kts | 0 .../service/EventsServiceApplication.kt | 0 .../config/EventsDatabaseConfiguration.kt | 0 .../src/test/resources/logback-test.xml | 0 .../services/horses}/Dockerfile | 0 .../horses/horses-api/build.gradle.kts | 0 .../mocode/horses/api/rest/HorseController.kt | 0 .../horses/horses-common/build.gradle.kts | 0 .../application/usecase/CreateHorseUseCase.kt | 0 .../application/usecase/DeleteHorseUseCase.kt | 0 .../application/usecase/GetHorseUseCase.kt | 0 .../TransactionalCreateHorseUseCase.kt | 0 .../application/usecase/UpdateHorseUseCase.kt | 0 .../horses/horses-domain/build.gradle.kts | 0 .../at/mocode/horses/domain/model/DomPferd.kt | 0 .../domain/repository/HorseRepository.kt | 0 .../horses-infrastructure/build.gradle.kts | 0 .../persistence/HorseRepositoryImpl.kt | 0 .../infrastructure/persistence/HorseTable.kt | 0 .../horses/horses-service/build.gradle.kts | 0 .../service/HorsesServiceApplication.kt | 0 .../config/ApplicationConfiguration.kt | 0 .../service/config/DatabaseConfiguration.kt | 0 .../HorseServiceIntegrationTest.kt | 0 .../integration/TransactionContextTest.kt | 0 .../integration/TransactionalContextTest.kt | 0 .../src/test/resources/logback-test.xml | 0 .../services/masterdata}/Dockerfile | 0 .../masterdata-api/build.gradle.kts | 0 .../at/mocode/masterdata/api/StatusPages.kt | 0 .../api/rest/AltersklasseController.kt | 0 .../api/rest/BundeslandController.kt | 0 .../masterdata/api/rest/CountryController.kt | 0 .../masterdata/api/rest/PlatzController.kt | 0 .../masterdata-common/build.gradle.kts | 0 .../usecase/CreateAltersklasseUseCase.kt | 0 .../usecase/CreateBundeslandUseCase.kt | 0 .../usecase/CreateCountryUseCase.kt | 0 .../application/usecase/CreatePlatzUseCase.kt | 0 .../usecase/GetAltersklasseUseCase.kt | 0 .../usecase/GetBundeslandUseCase.kt | 0 .../application/usecase/GetCountryUseCase.kt | 0 .../application/usecase/GetPlatzUseCase.kt | 0 .../masterdata-domain/build.gradle.kts | 0 .../domain/model/AltersklasseDefinition.kt | 0 .../domain/model/BundeslandDefinition.kt | 0 .../masterdata/domain/model/LandDefinition.kt | 0 .../mocode/masterdata/domain/model/Platz.kt | 0 .../repository/AltersklasseRepository.kt | 0 .../domain/repository/BundeslandRepository.kt | 0 .../domain/repository/LandRepository.kt | 0 .../domain/repository/PlatzRepository.kt | 0 .../build.gradle.kts | 0 .../persistence/AltersklasseRepositoryImpl.kt | 0 .../persistence/AltersklasseTable.kt | 0 .../persistence/BundeslandRepositoryImpl.kt | 0 .../persistence/BundeslandTable.kt | 0 .../persistence/LandRepositoryImpl.kt | 0 .../infrastructure/persistence/LandTable.kt | 0 .../persistence/PlatzRepositoryImpl.kt | 0 .../infrastructure/persistence/PlatzTable.kt | 0 .../masterdata-service/build.gradle.kts | 0 .../service/MasterdataServiceApplication.kt | 0 .../service/config/MasterdataConfiguration.kt | 0 .../config/MasterdataDatabaseConfiguration.kt | 0 .../db/migration/V001__Create_Land_Table.sql | 0 .../V002__Create_Bundesland_Table.sql | 0 .../V003__Create_Altersklasse_Table.sql | 0 .../db/migration/V004__Create_Platz_Table.sql | 0 .../migration/V1__Create_Initial_Tables.sql | 2 +- .../src/test/resources/logback-test.xml | 0 .../services/members}/Dockerfile | 0 .../services/ping}/Dockerfile | 26 +- .../ping/ping-service/build.gradle.kts | 4 +- .../registry/oeps-importer/build.gradle.kts | 0 .../registry/registry-api/build.gradle.kts | 0 .../registry/registry-domain/build.gradle.kts | 0 .../registry-service/build.gradle.kts | 0 .../domain/repository/PingRepository.kt | 8 - config/.env | 8 + config/.env.dev | 190 ---- config/.env.example | 7 + config/.env.prod | 164 ---- config/.env.staging | 164 ---- config/.env.template | 178 ---- config/.env.test | 163 ---- config/README.md | 269 ------ config/detekt/detekt.yml | 52 ++ config/postgres/postgresql.conf | 2 +- .env => docker/.env | 10 +- docker/.env.example | 49 ++ docker/compose.hardcoded.yaml | 153 ++++ .../core}/keycloak/Dockerfile | 0 ...lients.yml => docker-compose.clients.yaml} | 0 ...vices.yml => docker-compose.services.yaml} | 0 ...docker-compose.yml => docker-compose.yaml} | 36 +- .../frontends}/desktop-app/Dockerfile | 0 .../frontends}/desktop-app/entrypoint.sh | 0 .../frontends}/desktop-app/health-check.sh | 0 .../frontends}/desktop-app/supervisord.conf | 0 .../frontends}/web-app/Dockerfile | 0 .../frontends}/web-app/downloads/index.html | 0 .../frontends}/web-app/nginx.conf | 0 .../monitoring}/Dockerfile | 0 .../kotlin-multiplatform-web.Dockerfile | 0 .../templates/spring-boot-service.Dockerfile | 0 ...AntwortenOffenerFragenArchitekturReview.md | 9 +- .../MultiplatformApp_Ktor_SQLDelight_Doku.pdf | Bin 0 -> 2317813 bytes docs/how-to/start-local.md | 91 -- domains/events/README-EVENTS.md | 473 ---------- domains/horses/README-HORSES.md | 561 ------------ domains/masterdata/README-MASTERDATA.md | 361 -------- frontend/core/design-system/build.gradle.kts | 4 +- frontend/core/local-db/build.gradle.kts | 51 ++ .../frontend/core/localdb/DatabaseProvider.kt | 21 + .../frontend/core/localdb/MeldestelleDb.sq | 10 + .../core/localdb/DatabaseProvider.js.kt | 25 + .../core/localdb/DatabaseProvider.jvm.kt | 20 + frontend/core/navigation/build.gradle.kts | 2 - frontend/core/network/build.gradle.kts | 70 ++ .../frontend/core/network/NetworkConfig.kt | 17 + .../frontend/core/network/NetworkModule.kt | 75 ++ .../frontend/core/network/PlatformConfig.kt | 5 + .../core/network/PlatformConfig.js.kt | 29 + .../core/network/PlatformConfig.jvm.kt | 11 + .../features/auth-feature/build.gradle.kts | 126 +++ .../clients/authfeature/AuthApiClient.kt | 2 +- .../clients/authfeature/AuthTokenManager.kt | 0 .../authfeature/AuthenticatedHttpClient.kt | 2 +- .../mocode/clients/authfeature/LoginScreen.kt | 0 .../clients/authfeature/LoginViewModel.kt | 2 +- .../authfeature/oauth/AuthCallbackParams.kt | 0 .../clients/authfeature/oauth/OAuthPkce.kt | 2 +- .../authfeature/oauth/AuthCallbackParamsJs.kt | 0 .../clients/authfeature/oauth/OAuthPkceJs.kt | 2 +- .../oauth/AuthCallbackParamsJvm.kt | 0 .../clients/authfeature/oauth/OAuthPkceJvm.kt | 2 +- .../members-feature}/build.gradle.kts | 2 +- .../features}/ping-feature/build.gradle.kts | 8 +- .../clients/pingfeature/PingApiClient.kt | 2 +- .../clients/pingfeature/PingApiFactory.kt | 14 + .../clients/pingfeature/PingApiKoinClient.kt | 29 + .../mocode/clients/pingfeature/PingScreen.kt | 0 .../clients/pingfeature/PingViewModel.kt | 0 .../pingfeature/api/ReitsportTestApi.kt | 0 .../clients/pingfeature/model/AuthEnums.kt | 0 .../model/ReitsportDomainModels.kt | 0 .../pingfeature/model/ReitsportRoles.kt | 0 .../clients/pingfeature/PingApiClientTest.kt | 0 .../clients/pingfeature/PingViewModelTest.kt | 0 .../clients/pingfeature/TestPingApiClient.kt | 0 {clients => frontend}/shared/build.gradle.kts | 3 +- .../kotlin/at/mocode/shared/.gitkeep | 0 .../at/mocode}/shared/core/AppConfig.kt | 2 +- .../at/mocode}/shared/core/AppConstants.kt | 2 +- .../data/repository/PingRepositoryImpl.kt | 8 +- .../at/mocode}/shared/di/NetworkModule.kt | 4 +- .../at/mocode}/shared/di/SharedModule.kt | 4 +- .../mocode}/shared/domain/model/ApiModels.kt | 24 +- .../domain/repository/PingRepository.kt | 8 + .../shared/navigation/DeepLinkHandler.kt | 194 ++++ .../shared/navigation/NavigationManager.kt | 178 ++++ .../navigation/NavigationPersistence.kt | 75 ++ .../mocode/shared/network/HttpClientConfig.kt | 27 + .../mocode/shared/network/NetworkException.kt | 172 ++++ .../at/mocode/shared/network/NetworkUtils.kt | 221 +++++ .../mocode/shared/network/RepositoryResult.kt | 18 + .../shared/presentation/actions/AppAction.kt | 37 + .../shared/presentation/state/AppState.kt | 55 ++ .../shared/presentation/store/AppStore.kt | 156 ++++ .../kotlin/at/mocode/shared/network/TimeJs.kt | 5 + .../at/mocode/shared/network/TimeJvm.kt | 3 + .../meldestelle-portal/build.gradle.kts | 13 +- .../src/commonMain/kotlin/MainApp.kt | 2 +- .../src/jsMain/kotlin/main.kt | 25 +- .../src/jvmMain/kotlin/main.kt | 2 +- .../webpack.config.d/sqljs-fix.js | 9 + .../webpack.config.d/webpack.config.js | 8 +- gradle.properties | 6 + gradle/libs.versions.toml | 17 +- infrastructure/README-INFRASTRUCTURE.md | 582 ------------ infrastructure/cache/README-INFRA-CACHE.md | 135 --- infrastructure/cache/redis-cache/README.md | 173 ---- .../event-store/README-INFRA-EVENT-STORE.md | 624 ------------- .../event-store/redis-event-store/README.md | 280 ------ .../messaging/README-INFRA-MESSAGING.md | 733 ---------------- .../monitoring/README-INFRA-MONITORING.md | 112 --- kotlin-js-store/yarn.lock | 10 + logs/gateway.log | 82 -- logs/troubleshooting/compose-config.txt | 371 -------- logs/troubleshooting/compose-ps.txt | 3 - logs/troubleshooting/keycloak.log | 1 - logs/troubleshooting/postgres.log | 74 -- scripts/config-sync.sh | 614 ------------- scripts/docker-build.sh | 251 ------ scripts/docker-versions-update.sh | 298 ------- scripts/generate-build-env.sh | 69 -- scripts/generate-compose-files.sh | 531 ----------- scripts/git-hooks/pre-commit-ssot | 76 -- scripts/maintenance/prune-docs.sh | 78 -- scripts/setup-keycloak.sh | 98 --- scripts/smoke/prometheus_smoke.sh | 27 - scripts/smoke/zipkin_smoke.sh | 30 - scripts/test/integration-test.sh | 432 --------- scripts/test/test-monitoring.sh | 505 ----------- scripts/test/test_database_initialization.sh | 650 -------------- scripts/test/test_gateway.sh | 374 -------- scripts/troubleshooting/keycloak_repro.sh | 59 -- .../logs/troubleshooting/compose-config.txt | 2 - scripts/utils/common.sh | 462 ---------- scripts/validate-docker-consistency.sh | 826 ------------------ scripts/validation/validate-docs.sh | 266 ------ scripts/validation/validate-env.sh | 226 ----- settings.gradle.kts | 146 ++-- 365 files changed, 2283 insertions(+), 15142 deletions(-) delete mode 100644 .env.template delete mode 100644 _backup_chaos/.env.template delete mode 100644 _backup_chaos/.env~origin_main delete mode 100644 _backup_chaos/README.md delete mode 100644 _backup_chaos/Schlachtplan.md delete mode 100644 _backup_chaos/build-args/clients.env delete mode 100644 _backup_chaos/build-args/global.env delete mode 100644 _backup_chaos/build-args/infrastructure.env delete mode 100644 _backup_chaos/build-args/services.env delete mode 100644 _backup_chaos/compose.yaml delete mode 100644 _backup_chaos/docker-compose.clients.yml delete mode 100644 _backup_chaos/docker-compose.services.yml delete mode 100644 _backup_chaos/docker-compose.yml delete mode 100644 _backup_chaos/events/README.md delete mode 100644 _backup_chaos/masterdata/README.md delete mode 100644 _backup_chaos/members/README.md delete mode 100644 _backup_chaos/secrets/README.md delete mode 100644 _backup_chaos/secrets/grafana_admin_password.txt delete mode 100644 _backup_chaos/secrets/grafana_admin_user.txt delete mode 100644 _backup_chaos/secrets/jwt_secret.txt delete mode 100644 _backup_chaos/secrets/keycloak_admin_password.txt delete mode 100644 _backup_chaos/secrets/keycloak_auth_client_secret.txt delete mode 100644 _backup_chaos/secrets/keycloak_client_secret.txt delete mode 100644 _backup_chaos/secrets/metrics_auth_password.txt delete mode 100644 _backup_chaos/secrets/metrics_auth_username.txt delete mode 100644 _backup_chaos/secrets/postgres_password.txt delete mode 100644 _backup_chaos/secrets/postgres_user.txt delete mode 100644 _backup_chaos/secrets/redis_password.txt delete mode 100755 _backup_chaos/secrets/setup-secrets.sh delete mode 100644 _backup_chaos/secrets/vnc_password.txt delete mode 100644 _backup_chaos/versions.toml.bak delete mode 100644 backend/README.md delete mode 100644 backend/gateway/gateway/CONFIGURATION.md delete mode 100644 backend/gateway/gateway/README-INFRA-GATEWAY.md rename {infrastructure => backend/infrastructure}/cache/cache-api/build.gradle.kts (100%) rename {infrastructure => backend/infrastructure}/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheConfiguration.kt (100%) rename {infrastructure => backend/infrastructure}/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheEntry.kt (100%) rename {infrastructure => backend/infrastructure}/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheSerializer.kt (100%) rename {infrastructure => backend/infrastructure}/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/ConnectionStatus.kt (100%) rename {infrastructure => backend/infrastructure}/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCache.kt (100%) rename {infrastructure => backend/infrastructure}/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCacheExtensions.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/build.gradle.kts (95%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/JacksonCacheSerializer.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisConfiguration.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCache.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheConfigurationTest.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheEdgeCasesTest.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheIntegrationTest.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCachePerformanceTest.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheResilienceTest.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheTest.kt (100%) rename {infrastructure => backend/infrastructure}/cache/redis-cache/src/test/resources/logback-test.xml (100%) rename {infrastructure => backend/infrastructure}/event-store/event-store-api/build.gradle.kts (100%) rename {infrastructure => backend/infrastructure}/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventSerializer.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventStore.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/build.gradle.kts (92%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/EventStoreMetrics.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializer.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumer.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStore.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfiguration.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializerTest.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisCacheAndEventStoreIntegrationTest.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumerResilienceTest.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfigurationTest.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreErrorHandlingTest.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreIntegrationTest.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreStreamTest.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreTest.kt (100%) rename {infrastructure => backend/infrastructure}/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisIntegrationTest.kt (100%) rename {dockerfiles => backend}/infrastructure/gateway/Dockerfile (97%) rename backend/{ => infrastructure}/gateway/build.gradle.kts (96%) rename backend/{ => infrastructure}/gateway/docs/index.html (100%) rename backend/{ => infrastructure}/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/GatewayApplication.kt (100%) rename backend/{ => infrastructure}/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/config/GatewayConfig.kt (100%) rename backend/{ => infrastructure}/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/controller/FallbackController.kt (100%) rename backend/{ => infrastructure}/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/health/GatewayHealthIndicator.kt (100%) rename backend/{ => infrastructure}/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/metrics/GatewayMetricsConfig.kt (100%) rename backend/{ => infrastructure}/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/security/SecurityConfig.kt (100%) rename backend/{ => infrastructure}/gateway/src/main/resources/application-keycloak.yml (100%) rename backend/{ => infrastructure}/gateway/src/main/resources/application.conf (100%) rename backend/{ => infrastructure}/gateway/src/main/resources/application.yml (100%) rename backend/{ => infrastructure}/gateway/src/main/resources/logback-spring.xml (100%) rename backend/{ => infrastructure}/gateway/src/main/resources/logback.xml (100%) rename backend/{ => infrastructure}/gateway/src/main/resources/openapi/documentation.yaml (100%) rename backend/{ => infrastructure}/gateway/src/main/resources/static/docs/index.html (100%) rename backend/{ => infrastructure}/gateway/src/main/resources/static/docs/postman/Meldestelle_API_Collection.json (100%) rename backend/{ => infrastructure}/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/FallbackControllerTests.kt (100%) rename backend/{ => infrastructure}/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayApplicationTests.kt (100%) rename backend/{ => infrastructure}/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayFiltersTests.kt (100%) rename backend/{ => infrastructure}/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayRoutingTests.kt (100%) rename backend/{ => infrastructure}/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewaySecurityTests.kt (100%) rename backend/{ => infrastructure}/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/KeycloakGatewayIntegrationTest.kt (100%) rename backend/{ => infrastructure}/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/config/TestSecurityConfig.kt (100%) rename backend/{ => infrastructure}/gateway/src/test/resources/application-dev.yml (100%) rename backend/{ => infrastructure}/gateway/src/test/resources/application-keycloak-integration-test.yml (100%) rename backend/{ => infrastructure}/gateway/src/test/resources/application-test.yml (100%) rename backend/{ => infrastructure}/gateway/src/test/resources/logback-test.xml (100%) rename backend/{ => infrastructure}/gateway/src/test/resources/test-init-keycloak-schema.sql (91%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/build.gradle.kts (93%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventConsumer.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventPublisher.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumer.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisher.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/MessagingError.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/ReactiveKafkaConfig.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumerCacheTest.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisherErrorTest.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaIntegrationTest.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaSecurityTest.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-config/build.gradle.kts (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-config/src/main/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfig.kt (100%) rename {infrastructure => backend/infrastructure}/messaging/messaging-config/src/test/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfigTest.kt (100%) rename {infrastructure => backend/infrastructure}/monitoring/monitoring-client/build.gradle.kts (100%) rename {infrastructure => backend/infrastructure}/monitoring/monitoring-client/src/main/kotlin/at/mocode/infrastructure/monitoring/client/MonitoringClientAutoConfiguration.kt (100%) rename {infrastructure => backend/infrastructure}/monitoring/monitoring-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (100%) rename {infrastructure => backend/infrastructure}/monitoring/monitoring-client/src/main/resources/monitoring-defaults.properties (100%) rename {infrastructure => backend/infrastructure}/monitoring/monitoring-server/build.gradle.kts (100%) rename {infrastructure => backend/infrastructure}/monitoring/monitoring-server/src/main/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplication.kt (100%) rename {infrastructure => backend/infrastructure}/monitoring/monitoring-server/src/main/resources/application.properties (100%) rename {infrastructure => backend/infrastructure}/monitoring/monitoring-server/src/test/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplicationTest.kt (100%) rename {domains/events/events-service => backend/infrastructure/monitoring/monitoring-server}/src/test/resources/logback-test.xml (100%) rename {dockerfiles/domains/events-service => backend/services/events}/Dockerfile (100%) rename {domains => backend/services}/events/events-api/build.gradle.kts (100%) rename {domains => backend/services}/events/events-api/src/main/kotlin/at/mocode/events/api/rest/VeranstaltungController.kt (100%) rename {domains => backend/services}/events/events-common/build.gradle.kts (100%) rename {domains => backend/services}/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/CreateVeranstaltungUseCase.kt (100%) rename {domains => backend/services}/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/DeleteVeranstaltungUseCase.kt (100%) rename {domains => backend/services}/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/GetVeranstaltungUseCase.kt (100%) rename {domains => backend/services}/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/UpdateVeranstaltungUseCase.kt (100%) rename {domains => backend/services}/events/events-domain/build.gradle.kts (100%) rename {domains => backend/services}/events/events-domain/src/main/kotlin/at/mocode/events/EventManagement.kt (100%) rename {domains => backend/services}/events/events-domain/src/main/kotlin/at/mocode/events/domain/model/Veranstaltung.kt (100%) rename {domains => backend/services}/events/events-domain/src/main/kotlin/at/mocode/events/domain/repository/VeranstaltungRepository.kt (100%) rename {domains => backend/services}/events/events-infrastructure/build.gradle.kts (100%) rename {domains => backend/services}/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungRepositoryImpl.kt (100%) rename {domains => backend/services}/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungTable.kt (100%) rename {domains => backend/services}/events/events-service/build.gradle.kts (100%) rename {domains => backend/services}/events/events-service/src/main/kotlin/at/mocode/events/service/EventsServiceApplication.kt (100%) rename {domains => backend/services}/events/events-service/src/main/kotlin/at/mocode/events/service/config/EventsDatabaseConfiguration.kt (100%) rename {domains/horses/horses-service => backend/services/events/events-service}/src/test/resources/logback-test.xml (100%) rename {dockerfiles/domains/horses-service => backend/services/horses}/Dockerfile (100%) rename {domains => backend/services}/horses/horses-api/build.gradle.kts (100%) rename {domains => backend/services}/horses/horses-api/src/main/kotlin/at/mocode/horses/api/rest/HorseController.kt (100%) rename {domains => backend/services}/horses/horses-common/build.gradle.kts (100%) rename {domains => backend/services}/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/CreateHorseUseCase.kt (100%) rename {domains => backend/services}/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/DeleteHorseUseCase.kt (100%) rename {domains => backend/services}/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/GetHorseUseCase.kt (100%) rename {domains => backend/services}/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/TransactionalCreateHorseUseCase.kt (100%) rename {domains => backend/services}/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/UpdateHorseUseCase.kt (100%) rename {domains => backend/services}/horses/horses-domain/build.gradle.kts (100%) rename {domains => backend/services}/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/model/DomPferd.kt (100%) rename {domains => backend/services}/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/repository/HorseRepository.kt (100%) rename {domains => backend/services}/horses/horses-infrastructure/build.gradle.kts (100%) rename {domains => backend/services}/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseRepositoryImpl.kt (100%) rename {domains => backend/services}/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseTable.kt (100%) rename {domains => backend/services}/horses/horses-service/build.gradle.kts (100%) rename {domains => backend/services}/horses/horses-service/src/main/kotlin/at/mocode/horses/service/HorsesServiceApplication.kt (100%) rename {domains => backend/services}/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/ApplicationConfiguration.kt (100%) rename {domains => backend/services}/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/DatabaseConfiguration.kt (100%) rename {domains => backend/services}/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/HorseServiceIntegrationTest.kt (100%) rename {domains => backend/services}/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionContextTest.kt (100%) rename {domains => backend/services}/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionalContextTest.kt (100%) rename {domains/masterdata/masterdata-service => backend/services/horses/horses-service}/src/test/resources/logback-test.xml (100%) rename {dockerfiles/domains/masterdata-service => backend/services/masterdata}/Dockerfile (100%) rename {domains => backend/services}/masterdata/masterdata-api/build.gradle.kts (100%) rename {domains => backend/services}/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/StatusPages.kt (100%) rename {domains => backend/services}/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/AltersklasseController.kt (100%) rename {domains => backend/services}/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/BundeslandController.kt (100%) rename {domains => backend/services}/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/CountryController.kt (100%) rename {domains => backend/services}/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/PlatzController.kt (100%) rename {domains => backend/services}/masterdata/masterdata-common/build.gradle.kts (100%) rename {domains => backend/services}/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateAltersklasseUseCase.kt (100%) rename {domains => backend/services}/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateBundeslandUseCase.kt (100%) rename {domains => backend/services}/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateCountryUseCase.kt (100%) rename {domains => backend/services}/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreatePlatzUseCase.kt (100%) rename {domains => backend/services}/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetAltersklasseUseCase.kt (100%) rename {domains => backend/services}/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetBundeslandUseCase.kt (100%) rename {domains => backend/services}/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetCountryUseCase.kt (100%) rename {domains => backend/services}/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetPlatzUseCase.kt (100%) rename {domains => backend/services}/masterdata/masterdata-domain/build.gradle.kts (100%) rename {domains => backend/services}/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/AltersklasseDefinition.kt (100%) rename {domains => backend/services}/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/BundeslandDefinition.kt (100%) rename {domains => backend/services}/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/LandDefinition.kt (100%) rename {domains => backend/services}/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/Platz.kt (100%) rename {domains => backend/services}/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/AltersklasseRepository.kt (100%) rename {domains => backend/services}/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/BundeslandRepository.kt (100%) rename {domains => backend/services}/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/LandRepository.kt (100%) rename {domains => backend/services}/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/PlatzRepository.kt (100%) rename {domains => backend/services}/masterdata/masterdata-infrastructure/build.gradle.kts (100%) rename {domains => backend/services}/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseRepositoryImpl.kt (100%) rename {domains => backend/services}/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseTable.kt (100%) rename {domains => backend/services}/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandRepositoryImpl.kt (100%) rename {domains => backend/services}/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandTable.kt (100%) rename {domains => backend/services}/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandRepositoryImpl.kt (100%) rename {domains => backend/services}/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandTable.kt (100%) rename {domains => backend/services}/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzRepositoryImpl.kt (100%) rename {domains => backend/services}/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzTable.kt (100%) rename {domains => backend/services}/masterdata/masterdata-service/build.gradle.kts (100%) rename {domains => backend/services}/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/MasterdataServiceApplication.kt (100%) rename {domains => backend/services}/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataConfiguration.kt (100%) rename {domains => backend/services}/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataDatabaseConfiguration.kt (100%) rename {domains => backend/services}/masterdata/masterdata-service/src/main/resources/db/migration/V001__Create_Land_Table.sql (100%) rename {domains => backend/services}/masterdata/masterdata-service/src/main/resources/db/migration/V002__Create_Bundesland_Table.sql (100%) rename {domains => backend/services}/masterdata/masterdata-service/src/main/resources/db/migration/V003__Create_Altersklasse_Table.sql (100%) rename {domains => backend/services}/masterdata/masterdata-service/src/main/resources/db/migration/V004__Create_Platz_Table.sql (100%) rename {domains => backend/services}/masterdata/masterdata-service/src/main/resources/db/migration/V1__Create_Initial_Tables.sql (96%) rename {infrastructure/monitoring/monitoring-server => backend/services/masterdata/masterdata-service}/src/test/resources/logback-test.xml (100%) rename {dockerfiles/domains/members-service => backend/services/members}/Dockerfile (100%) rename {dockerfiles/services/ping-service => backend/services/ping}/Dockerfile (89%) rename {domains => backend/services}/registry/oeps-importer/build.gradle.kts (100%) rename {domains => backend/services}/registry/registry-api/build.gradle.kts (100%) rename {domains => backend/services}/registry/registry-domain/build.gradle.kts (100%) rename {domains => backend/services}/registry/registry-service/build.gradle.kts (100%) delete mode 100644 clients/shared/src/commonMain/kotlin/at/mocode/clients/shared/domain/repository/PingRepository.kt create mode 100644 config/.env delete mode 100644 config/.env.dev create mode 100644 config/.env.example delete mode 100644 config/.env.prod delete mode 100644 config/.env.staging delete mode 100644 config/.env.template delete mode 100644 config/.env.test delete mode 100644 config/README.md create mode 100644 config/detekt/detekt.yml rename .env => docker/.env (86%) create mode 100644 docker/compose.hardcoded.yaml rename {dockerfiles/infrastructure => docker/core}/keycloak/Dockerfile (100%) rename docker/{docker-compose.clients.yml => docker-compose.clients.yaml} (100%) rename docker/{docker-compose.services.yml => docker-compose.services.yaml} (100%) rename docker/{docker-compose.yml => docker-compose.yaml} (84%) rename {dockerfiles/clients => docker/frontends}/desktop-app/Dockerfile (100%) rename {dockerfiles/clients => docker/frontends}/desktop-app/entrypoint.sh (100%) rename {dockerfiles/clients => docker/frontends}/desktop-app/health-check.sh (100%) rename {dockerfiles/clients => docker/frontends}/desktop-app/supervisord.conf (100%) rename {dockerfiles/clients => docker/frontends}/web-app/Dockerfile (100%) rename {dockerfiles/clients => docker/frontends}/web-app/downloads/index.html (100%) rename {dockerfiles/clients => docker/frontends}/web-app/nginx.conf (100%) rename {dockerfiles/infrastructure/monitoring-server => docker/monitoring}/Dockerfile (100%) rename {dockerfiles => docker}/templates/kotlin-multiplatform-web.Dockerfile (100%) rename {dockerfiles => docker}/templates/spring-boot-service.Dockerfile (100%) create mode 100644 docs/clients/visionen/MultiplatformApp_Ktor_SQLDelight_Doku.pdf delete mode 100644 docs/how-to/start-local.md delete mode 100644 domains/events/README-EVENTS.md delete mode 100644 domains/horses/README-HORSES.md delete mode 100644 domains/masterdata/README-MASTERDATA.md create mode 100644 frontend/core/local-db/build.gradle.kts create mode 100644 frontend/core/local-db/src/commonMain/kotlin/at/mocode/frontend/core/localdb/DatabaseProvider.kt create mode 100644 frontend/core/local-db/src/commonMain/sqldelight/at/mocode/frontend/core/localdb/MeldestelleDb.sq create mode 100644 frontend/core/local-db/src/jsMain/kotlin/at/mocode/frontend/core/localdb/DatabaseProvider.js.kt create mode 100644 frontend/core/local-db/src/jvmMain/kotlin/at/mocode/frontend/core/localdb/DatabaseProvider.jvm.kt create mode 100644 frontend/core/network/build.gradle.kts create mode 100644 frontend/core/network/src/commonMain/kotlin/at/mocode/frontend/core/network/NetworkConfig.kt create mode 100644 frontend/core/network/src/commonMain/kotlin/at/mocode/frontend/core/network/NetworkModule.kt create mode 100644 frontend/core/network/src/commonMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.kt create mode 100644 frontend/core/network/src/jsMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.js.kt create mode 100644 frontend/core/network/src/jvmMain/kotlin/at/mocode/frontend/core/network/PlatformConfig.jvm.kt create mode 100644 frontend/features/auth-feature/build.gradle.kts rename {clients => frontend/features}/auth-feature/src/commonMain/kotlin/at/mocode/clients/authfeature/AuthApiClient.kt (99%) rename {clients => frontend/features}/auth-feature/src/commonMain/kotlin/at/mocode/clients/authfeature/AuthTokenManager.kt (100%) rename {clients => frontend/features}/auth-feature/src/commonMain/kotlin/at/mocode/clients/authfeature/AuthenticatedHttpClient.kt (96%) rename {clients => frontend/features}/auth-feature/src/commonMain/kotlin/at/mocode/clients/authfeature/LoginScreen.kt (100%) rename {clients => frontend/features}/auth-feature/src/commonMain/kotlin/at/mocode/clients/authfeature/LoginViewModel.kt (98%) rename {clients => frontend/features}/auth-feature/src/commonMain/kotlin/at/mocode/clients/authfeature/oauth/AuthCallbackParams.kt (100%) rename {clients => frontend/features}/auth-feature/src/commonMain/kotlin/at/mocode/clients/authfeature/oauth/OAuthPkce.kt (94%) rename {clients => frontend/features}/auth-feature/src/jsMain/kotlin/at/mocode/clients/authfeature/oauth/AuthCallbackParamsJs.kt (100%) rename {clients => frontend/features}/auth-feature/src/jsMain/kotlin/at/mocode/clients/authfeature/oauth/OAuthPkceJs.kt (98%) rename {clients => frontend/features}/auth-feature/src/jvmMain/kotlin/at/mocode/clients/authfeature/oauth/AuthCallbackParamsJvm.kt (100%) rename {clients => frontend/features}/auth-feature/src/jvmMain/kotlin/at/mocode/clients/authfeature/oauth/OAuthPkceJvm.kt (97%) rename {clients/auth-feature => frontend/features/members-feature}/build.gradle.kts (98%) rename {clients => frontend/features}/ping-feature/build.gradle.kts (92%) rename {clients => frontend/features}/ping-feature/src/commonMain/kotlin/at/mocode/clients/pingfeature/PingApiClient.kt (95%) create mode 100644 frontend/features/ping-feature/src/commonMain/kotlin/at/mocode/clients/pingfeature/PingApiFactory.kt create mode 100644 frontend/features/ping-feature/src/commonMain/kotlin/at/mocode/clients/pingfeature/PingApiKoinClient.kt rename {clients => frontend/features}/ping-feature/src/commonMain/kotlin/at/mocode/clients/pingfeature/PingScreen.kt (100%) rename {clients => frontend/features}/ping-feature/src/commonMain/kotlin/at/mocode/clients/pingfeature/PingViewModel.kt (100%) rename {clients => frontend/features}/ping-feature/src/commonMain/kotlin/at/mocode/clients/pingfeature/api/ReitsportTestApi.kt (100%) rename {clients => frontend/features}/ping-feature/src/commonMain/kotlin/at/mocode/clients/pingfeature/model/AuthEnums.kt (100%) rename {clients => frontend/features}/ping-feature/src/commonMain/kotlin/at/mocode/clients/pingfeature/model/ReitsportDomainModels.kt (100%) rename {clients => frontend/features}/ping-feature/src/commonMain/kotlin/at/mocode/clients/pingfeature/model/ReitsportRoles.kt (100%) rename {clients => frontend/features}/ping-feature/src/commonTest/kotlin/at/mocode/clients/pingfeature/PingApiClientTest.kt (100%) rename {clients => frontend/features}/ping-feature/src/commonTest/kotlin/at/mocode/clients/pingfeature/PingViewModelTest.kt (100%) rename {clients => frontend/features}/ping-feature/src/commonTest/kotlin/at/mocode/clients/pingfeature/TestPingApiClient.kt (100%) rename {clients => frontend}/shared/build.gradle.kts (97%) create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/.gitkeep rename {clients/shared/src/commonMain/kotlin/at/mocode/clients => frontend/shared/src/commonMain/kotlin/at/mocode}/shared/core/AppConfig.kt (84%) rename {clients/shared/src/commonMain/kotlin/at/mocode/clients => frontend/shared/src/commonMain/kotlin/at/mocode}/shared/core/AppConstants.kt (97%) rename {clients/shared/src/commonMain/kotlin/at/mocode/clients => frontend/shared/src/commonMain/kotlin/at/mocode}/shared/data/repository/PingRepositoryImpl.kt (76%) rename {clients/shared/src/commonMain/kotlin/at/mocode/clients => frontend/shared/src/commonMain/kotlin/at/mocode}/shared/di/NetworkModule.kt (92%) rename {clients/shared/src/commonMain/kotlin/at/mocode/clients => frontend/shared/src/commonMain/kotlin/at/mocode}/shared/di/SharedModule.kt (90%) rename {clients/shared/src/commonMain/kotlin/at/mocode/clients => frontend/shared/src/commonMain/kotlin/at/mocode}/shared/domain/model/ApiModels.kt (56%) create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/domain/repository/PingRepository.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/navigation/DeepLinkHandler.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/navigation/NavigationManager.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/navigation/NavigationPersistence.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/network/HttpClientConfig.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/network/NetworkException.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/network/NetworkUtils.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/network/RepositoryResult.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/presentation/actions/AppAction.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/presentation/state/AppState.kt create mode 100644 frontend/shared/src/commonMain/kotlin/at/mocode/shared/presentation/store/AppStore.kt create mode 100644 frontend/shared/src/jsMain/kotlin/at/mocode/shared/network/TimeJs.kt create mode 100644 frontend/shared/src/jvmMain/kotlin/at/mocode/shared/network/TimeJvm.kt create mode 100644 frontend/shells/meldestelle-portal/webpack.config.d/sqljs-fix.js delete mode 100644 infrastructure/README-INFRASTRUCTURE.md delete mode 100644 infrastructure/cache/README-INFRA-CACHE.md delete mode 100644 infrastructure/cache/redis-cache/README.md delete mode 100644 infrastructure/event-store/README-INFRA-EVENT-STORE.md delete mode 100644 infrastructure/event-store/redis-event-store/README.md delete mode 100644 infrastructure/messaging/README-INFRA-MESSAGING.md delete mode 100644 infrastructure/monitoring/README-INFRA-MONITORING.md delete mode 100644 logs/gateway.log delete mode 100644 logs/troubleshooting/compose-config.txt delete mode 100644 logs/troubleshooting/compose-ps.txt delete mode 100644 logs/troubleshooting/keycloak.log delete mode 100644 logs/troubleshooting/postgres.log delete mode 100755 scripts/config-sync.sh delete mode 100755 scripts/docker-build.sh delete mode 100755 scripts/docker-versions-update.sh delete mode 100644 scripts/generate-build-env.sh delete mode 100755 scripts/generate-compose-files.sh delete mode 100644 scripts/git-hooks/pre-commit-ssot delete mode 100755 scripts/maintenance/prune-docs.sh delete mode 100755 scripts/setup-keycloak.sh delete mode 100644 scripts/smoke/prometheus_smoke.sh delete mode 100644 scripts/smoke/zipkin_smoke.sh delete mode 100755 scripts/test/integration-test.sh delete mode 100755 scripts/test/test-monitoring.sh delete mode 100755 scripts/test/test_database_initialization.sh delete mode 100755 scripts/test/test_gateway.sh delete mode 100644 scripts/troubleshooting/keycloak_repro.sh delete mode 100644 scripts/troubleshooting/logs/troubleshooting/compose-config.txt delete mode 100755 scripts/utils/common.sh delete mode 100755 scripts/validate-docker-consistency.sh delete mode 100755 scripts/validation/validate-docs.sh delete mode 100755 scripts/validation/validate-env.sh diff --git a/.dockerignore b/.dockerignore index f973e99e..c78e54e3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -70,7 +70,7 @@ Thumbs.db # =================================================================== # Environment and Configuration files # =================================================================== -.env +config/.env .env.local .env.*.local **/.env diff --git a/.env.template b/.env.template deleted file mode 100644 index fde1d32b..00000000 --- a/.env.template +++ /dev/null @@ -1,60 +0,0 @@ -# ==================================================== -# Meldestelle - Environment - Template Configuration -# ==================================================== -# Profil: DEVELOPMENT (Development) - -# --- PROJEKT EINSTELLUNGEN --- -# .env.template - Vorlage für Server/Kollegen -COMPOSE_PROJECT_NAME=meldestelle -# Restart Policy: 'no' für Dev (Fehler sehen), 'always' für Prod -RESTART_POLICY=always - -# --- POSTGRESQL (Datenbank) --- -POSTGRES_USER=pg-user -POSTGRES_PASSWORD= -POSTGRES_DB=meldestelle -# Port Mapping: Host:Container. -# Prod: 127.0.0.1:5432 (nur localhost) oder leer lassen -POSTGRES_PORT=5432:5432 - -# --- REDIS (Cache) --- -# Prod: 127.0.0.1:6379 oder leer lassen -REDIS_PORT=6379:6379 - -# --- KEYCLOAK (Identity Provider) --- -# Admin Login für die Konsole -KC_ADMIN_USER=kc-admin -KC_ADMIN_PASSWORD= -# Hostname (Wichtig für Redirects) -KC_HOSTNAME=localhost -# Port Mapping -KC_PORT=8180:8080 - -# --- PGADMIN (DB GUI) --- -PGADMIN_EMAIL=user@domain.com -PGADMIN_PASSWORD= -PGADMIN_PORT=8888:80 - -# --- GRAFANA (Monitoring GUI) --- -GF_ADMIN_USER=gf-admin -GF_ADMIN_PASSWORD= -GF_PORT=3000:3000 - -# --- PROMETHEUS (Metriken) --- -PROMETHEUS_PORT=9090:9090 - -# --- SERVICE DISCOVERY (Consul) --- -CONSUL_PORT=8500:8500 - -# --- API GATEWAY --- -# Der Port, der nach außen für Clients (Web App) offen ist -GATEWAY_PORT=8081 -# Debug Port für IntelliJ (Remote JVM Debug) -GATEWAY_DEBUG_PORT=5005 - -# --- CLIENT APPLICATIONS --- -# Web-App (Kotlin/JS, kein WASM) -WEB_APP_PORT=4000:4000 -# Desktop-App (VNC/noVNC) -DESKTOP_APP_VNC_PORT=5901:5901 -DESKTOP_APP_NOVNC_PORT=6080:6080 diff --git a/.github/workflows/ci-main.yml b/.github/workflows/ci-main.yml index 7068fce3..034e7f44 100644 --- a/.github/workflows/ci-main.yml +++ b/.github/workflows/ci-main.yml @@ -21,19 +21,25 @@ jobs: name: Docker SSoT Validation runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Validate Docker SSoT (compat mode) + if: ${{ hashFiles('scripts/docker-versions-update.sh') != '' && hashFiles('scripts/generate-compose-files.sh') != '' && hashFiles('scripts/validate-docker-consistency.sh') != '' }} run: | bash scripts/docker-versions-update.sh sync bash scripts/generate-compose-files.sh all development bash scripts/validate-docker-consistency.sh all - name: Validate Docker SSoT (envless mode) + if: ${{ hashFiles('scripts/generate-compose-files.sh') != '' && hashFiles('scripts/validate-docker-consistency.sh') != '' }} run: | DOCKER_SSOT_MODE=envless bash scripts/generate-compose-files.sh all development DOCKER_SSOT_MODE=envless bash scripts/validate-docker-consistency.sh all + - name: Lint docker-compose (fallback) + if: ${{ hashFiles('scripts/validate-docker-consistency.sh') == '' }} + run: docker compose -f docker/docker-compose.yaml config + # ======================================== # 2. OpenAPI Validation (nur Lint) # ======================================== @@ -41,10 +47,10 @@ jobs: name: Validate OpenAPI Specs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: '20' @@ -53,7 +59,7 @@ jobs: - name: Validate OpenAPI run: | - spectral lint infrastructure/gateway/src/main/resources/openapi/documentation.yaml \ + spectral lint backend/gateway/src/main/resources/openapi/documentation.yaml \ --ruleset .spectral.yaml \ --fail-severity error @@ -64,22 +70,22 @@ jobs: name: Validate Essential Docs runs-on: ubuntu-latest steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Lint Critical Markdown - uses: DavidAnson/markdownlint-cli2-action@v20 + uses: DavidAnson/markdownlint-cli2-action@v21 with: globs: | README.md docs/README.md - docs/architecture/adr/**/*.md + docs/adr/**/*.md docs/how-to/start-local.md - name: Check Links in ADRs uses: gaurav-nelson/github-action-markdown-link-check@v1 with: config-file: '.github/markdown-link-check.json' - folder-path: 'docs/architecture/adr/' + folder-path: 'docs/adr/' use-quiet-mode: 'yes' # ======================================== @@ -91,7 +97,7 @@ jobs: needs: [ docker-ssot, validate-openapi, validate-docs ] steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Setup JDK 21 uses: actions/setup-java@v5 @@ -101,7 +107,7 @@ jobs: cache: gradle - name: Build - run: ./gradlew build -x test + run: ./gradlew staticAnalysis build -x test - name: Test run: ./gradlew test diff --git a/.github/workflows/deploy-proxmox.yml b/.github/workflows/deploy-proxmox.yml index da7888d6..590e4d0a 100644 --- a/.github/workflows/deploy-proxmox.yml +++ b/.github/workflows/deploy-proxmox.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Set up JDK 21 uses: actions/setup-java@v5 @@ -48,11 +48,14 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew - - name: Build Client (Test Compilation) - run: ./gradlew :client:compileCommonMainKotlinMetadata --no-daemon + - name: Static Analysis + run: ./gradlew staticAnalysis --no-daemon || true - - name: Run Client Tests - run: ./gradlew :client:test --no-daemon || true # Allow failure for now + - name: Build (all) + run: ./gradlew build -x test --no-daemon + + - name: Test (all) + run: ./gradlew test --no-daemon || true # Allow failure for now # =================================================================== # Deploy to Proxmox (nur bei main branch) @@ -64,7 +67,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup SSH Key uses: webfactory/ssh-agent@v0.8.0 @@ -98,7 +101,7 @@ jobs: # Stop existing services echo "🛑 Stopping existing services..." - docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml down || true + docker compose --env-file docker/.env -f docker/docker-compose.yaml down || true # Clean up old images (optional) echo "🧹 Cleaning up old images..." @@ -106,13 +109,11 @@ jobs: # Build new images echo "🏗️ Building new images..." - docker compose -f docker-compose.yml build - docker compose -f docker-compose.services.yml build - docker compose -f docker-compose.clients.yml build + docker compose --env-file docker/.env -f docker/docker-compose.yaml build # Start infrastructure first echo "🚀 Starting infrastructure..." - docker compose -f docker-compose.yml up -d + docker compose --env-file docker/.env -f docker/docker-compose.yaml up -d # Wait for infrastructure to be ready echo "⏳ Waiting for infrastructure..." @@ -120,7 +121,8 @@ jobs: # Start services echo "🚀 Starting services..." - docker compose -f docker-compose.yml -f docker-compose.services.yml up -d + # Start services (already included in main compose file) + docker compose --env-file docker/.env -f docker/docker-compose.yaml up -d # Wait for services to be ready echo "⏳ Waiting for services..." @@ -128,7 +130,8 @@ jobs: # Start clients echo "🚀 Starting clients..." - docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml up -d + # Start clients (already included in main compose file) + docker compose --env-file docker/.env -f docker/docker-compose.yaml up -d # Health check echo "🏥 Running health checks..." @@ -136,11 +139,11 @@ jobs: # Check service status echo "📊 Service Status:" - docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml ps + docker compose --env-file docker/.env -f docker/docker-compose.yaml ps # Check logs for errors echo "📋 Recent logs:" - docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml logs --tail=50 + docker compose --env-file docker/.env -f docker/docker-compose.yaml logs --tail=50 echo "✅ Deployment completed successfully!" ENDSSH diff --git a/.github/workflows/docs-kdoc-sync.yml b/.github/workflows/docs-kdoc-sync.yml index 76275cd9..7772f1d4 100644 --- a/.github/workflows/docs-kdoc-sync.yml +++ b/.github/workflows/docs-kdoc-sync.yml @@ -26,7 +26,7 @@ jobs: contents: read steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Setup JDK 21 uses: actions/setup-java@v5 @@ -38,7 +38,8 @@ jobs: uses: gradle/actions/setup-gradle@v5 - name: Build Dokka (GFM) - run: ./gradlew --no-daemon dokkaGfmAll + run: | + ./gradlew --no-daemon dokkaGfmAll || ./gradlew --no-daemon dokkaGfm - name: Python deps for YouTrack sync run: | @@ -46,6 +47,7 @@ jobs: pip install requests pyyaml - name: Sync KDoc Markdown to YouTrack KB + if: ${{ hashFiles('.junie/scripts/youtrack-sync-kb.py') != '' }} env: YT_URL: ${{ secrets.YT_URL }} YT_TOKEN: ${{ secrets.YT_TOKEN }} diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index d66fc62b..e078f3b7 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -93,7 +93,7 @@ jobs: --health-start-period 10s steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 - name: Set up JDK 21 uses: actions/setup-java@v5 @@ -197,6 +197,9 @@ jobs: - name: Grant execute permission for gradlew run: chmod +x gradlew + - name: Static Analysis + run: ./gradlew staticAnalysis --no-daemon + - name: Run integration tests run: ./gradlew integrationTest --no-daemon --parallel env: diff --git a/.github/workflows/ssot-guard.yml b/.github/workflows/ssot-guard.yml index 2dfcf972..09ffc8e4 100644 --- a/.github/workflows/ssot-guard.yml +++ b/.github/workflows/ssot-guard.yml @@ -1,225 +1,25 @@ -name: Docker SSoT Guard - -permissions: - contents: read - -concurrency: - group: ssot-guard-${{ github.ref }} - cancel-in-progress: true +name: Docker SSoT Guard (Minimal) on: push: - branches: [ main ] paths: - 'docker/**' - - 'dockerfiles/**' - - 'docker-compose*.yml*' - - 'scripts/**' - '.github/workflows/ssot-guard.yml' pull_request: paths: - 'docker/**' - - 'dockerfiles/**' - - 'docker-compose*.yml*' - - 'scripts/**' - '.github/workflows/ssot-guard.yml' jobs: - ssot-guard: + check-compose-config: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v5 - with: - fetch-depth: 0 + - uses: actions/checkout@v4 + + # FIX: .env aus Example erstellen, damit Variablen da sind + - name: Create .env context + run: cp docker/.env.example docker/.env - - name: Show environment - run: | - bash --version - docker --version || true - compose_ver=$(docker compose version 2>/dev/null || true); echo "docker compose: $compose_ver" - - - name: Sync versions to env files - run: bash scripts/docker-versions-update.sh sync - - - name: Generate docker-compose files (all) - run: bash scripts/generate-compose-files.sh all development - - - name: Validate Docker SSoT consistency - run: bash scripts/validate-docker-consistency.sh all - - - name: Build vs Runtime variable guards - run: | - set -euo pipefail - echo "[Guard] Prüfe, dass keine Laufzeit-Variablen in Build-Args-Dateien vorkommen..." - RUNTIME_KEYS_REGEX='^(GATEWAY_HOST|GATEWAY_PORT|WEB_APP_PORT|NODE_ENV|CONSUL_(HOST|PORT|ENABLED)|DB_(HOST|PORT|NAME|USER|USERNAME|PASSWORD)|POSTGRES_DB|REDIS_PORT|KEYCLOAK_PORT|PING_SERVICE_PORT|MEMBERS_SERVICE_PORT|HORSES_SERVICE_PORT|EVENTS_SERVICE_PORT|MASTERDATA_SERVICE_PORT|AUTH_SERVICE_PORT|MONITORING_SERVER_PORT|PROMETHEUS_PORT|GRAFANA_PORT|JWT_ISSUER|JWT_AUDIENCE)$' - FAIL=0 - shopt -s nullglob - for f in docker/build-args/*.env config/build/*.env; do - [ -f "$f" ] || continue - BAD=$(grep -E '^[A-Z0-9_]+=' "$f" | cut -d= -f1 | grep -E "$RUNTIME_KEYS_REGEX" || true) - if [ -n "$BAD" ]; then - echo "Fehler: Laufzeit-Variablen in Build-Args Datei $f gefunden:"; echo "$BAD"; FAIL=1 - fi - done - shopt -u nullglob - if [ $FAIL -ne 0 ]; then - echo "Build vs Runtime Trennung verletzt."; exit 1; fi - - echo "[Guard] Prüfe, dass keine Build-/Versions-Variablen in Runtime-Env vorkommen..." - BUILD_KEYS_REGEX='^(GRADLE_VERSION|JAVA_VERSION|VERSION|APP_VERSION|[A-Z]+_IMAGE_TAG)$' - shopt -s nullglob - for f in config/env/.env .env.template; do - [ -f "$f" ] || continue - BAD=$(grep -E '^[A-Z0-9_]+=' "$f" | cut -d= -f1 | grep -E "$BUILD_KEYS_REGEX" || true) - if [ -n "$BAD" ]; then - echo "Fehler: Build-/Versions-Variablen in Runtime-Env $f gefunden:"; echo "$BAD"; FAIL=1 - fi - done - shopt -u nullglob - if [ $FAIL -ne 0 ]; then - echo "Build-/Runtime-Mischung in Runtime-Env."; exit 1; fi - - - name: Check versions.toml vs global.env consistency - run: | - set -euo pipefail - TOML=docker/versions.toml - GLOBAL=docker/build-args/global.env - [ -f "$TOML" ] || { echo "Missing $TOML"; exit 1; } - [ -f "$GLOBAL" ] || { echo "Missing $GLOBAL"; exit 1; } - - get_toml_ver(){ awk -F'=' -v key="$1" '/^\[versions\]/{in_vers=1; next} /^\[/{in_vers=0} in_vers && gsub(/^[ \t]+|[ \t]+$/,"",$1) && $1==key {gsub(/[ "\t]/,"",$2); print $2; exit}' "$TOML"; } - mapfile -t checks < <(printf "%s\n" \ - "GRADLE_VERSION:versions.gradle" \ - "JAVA_VERSION:versions.java" \ - "VERSION:versions.app-version" \ - "PROMETHEUS_IMAGE_TAG:versions.prometheus" \ - "GRAFANA_IMAGE_TAG:versions.grafana" \ - "KEYCLOAK_IMAGE_TAG:versions.keycloak" \ - "POSTGRES_IMAGE_TAG:versions.postgres" \ - "REDIS_IMAGE_TAG:versions.redis" \ - "CONSUL_IMAGE_TAG:versions.consul" \ - "ZOOKEEPER_IMAGE_TAG:versions.zookeeper" \ - "KAFKA_IMAGE_TAG:versions.kafka") - - FAIL=0 - for entry in "${checks[@]}"; do - var=${entry%%:*}; path=${entry##*:} - key=${path#*.} - case "$var" in - GRADLE_VERSION) expected=$(get_toml_ver gradle) ;; - JAVA_VERSION) expected=$(get_toml_ver java) ;; - VERSION) expected=$(get_toml_ver app-version) ;; - PROMETHEUS_IMAGE_TAG) expected=$(get_toml_ver prometheus) ;; - GRAFANA_IMAGE_TAG) expected=$(get_toml_ver grafana) ;; - KEYCLOAK_IMAGE_TAG) expected=$(get_toml_ver keycloak) ;; - POSTGRES_IMAGE_TAG) expected=$(get_toml_ver postgres) ;; - REDIS_IMAGE_TAG) expected=$(get_toml_ver redis) ;; - CONSUL_IMAGE_TAG) expected=$(get_toml_ver consul) ;; - ZOOKEEPER_IMAGE_TAG) expected=$(get_toml_ver zookeeper) ;; - KAFKA_IMAGE_TAG) expected=$(get_toml_ver kafka) ;; - esac - actual=$(grep -E "^${var}=" "$GLOBAL" | head -n1 | cut -d= -f2-) - if [ -z "$actual" ] || [ "$actual" != "$expected" ]; then - echo "Versions-Drift: $var global.env='$actual' != versions.toml('$expected')"; FAIL=1 - fi - done - if [ $FAIL -ne 0 ]; then - echo "Versions SSoT-Drift erkannt."; exit 1; fi - - - name: Check drift of generated artifacts (ignore timestamps) - run: | - set -euo pipefail - # Gather modified files after sync+generate - CHANGED=$(git diff --name-only) - if [ -z "$CHANGED" ]; then - echo "No drift detected." - exit 0 - fi - echo "Changed files:" $CHANGED - fail=0 - for f in $CHANGED; do - # Inspect actual content changes but ignore volatile timestamp/comment lines - # Ignore lines starting with + or - that are exactly the timestamp markers we generate - DIFF_FILTERED=$(git diff --unified=0 -- "$f" \ - | awk 'BEGIN{show=0} { \ - if ($0 ~ /^\+\+\+|^---|^@@/) { next } \ - if ($0 ~ /^[+-]# (Generated:|Last updated:)/) { next } \ - if ($0 ~ /^[+-]#\s*Generated from docker\/versions.toml/) { next } \ - if ($0 ~ /^[+-]#\s*Environment:/) { next } \ - if ($0 ~ /^[+-]#\s*Source:/) { next } \ - if ($0 ~ /^[+-]$/) { next } \ - if ($0 ~ /^[+-]/) { print $0 } \ - }') - if [ -n "$DIFF_FILTERED" ]; then - echo "SSoT drift detected in $f:"; - echo "$DIFF_FILTERED"; - fail=1; - fi - done - if [ $fail -ne 0 ]; then - echo "\nERROR: Generated artifacts differ from repository (beyond timestamps)." - echo "Run:" - echo " bash scripts/docker-versions-update.sh sync" - echo " bash scripts/generate-compose-files.sh all" - echo "and commit the changes." - exit 1 - fi - echo "No SSoT drift (ignoring timestamps)." - - - ssot-guard-envless: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v5 - with: - fetch-depth: 0 - - - name: Show environment - run: | - bash --version - docker --version || true - compose_ver=$(docker compose version 2>/dev/null || true); echo "docker compose: $compose_ver" - - - name: Generate docker-compose files (all) - run: bash scripts/generate-compose-files.sh all development - - - name: Validate Docker SSoT consistency (envless) - run: DOCKER_SSOT_MODE=envless bash scripts/validate-docker-consistency.sh all - - - name: Check drift of generated artifacts (ignore timestamps) - run: | - set -euo pipefail - CHANGED=$(git diff --name-only) - if [ -z "$CHANGED" ]; then - echo "No drift detected." - exit 0 - fi - echo "Changed files:" $CHANGED - fail=0 - for f in $CHANGED; do - DIFF_FILTERED=$(git diff --unified=0 -- "$f" \ - | awk 'BEGIN{show=0} { \ - if ($0 ~ /^\+\+\+|^---|^@@/) { next } \ - if ($0 ~ /^[+-]# (Generated:|Last updated:)/) { next } \ - if ($0 ~ /^[+-]#\s*Generated from docker\/versions.toml/) { next } \ - if ($0 ~ /^[+-]#\s*Environment:/) { next } \ - if ($0 ~ /^[+-]#\s*Source:/) { next } \ - if ($0 ~ /^[+-]$/) { next } \ - if ($0 ~ /^[+-]/) { print $0 } \ - }') - if [ -n "$DIFF_FILTERED" ]; then - echo "SSoT drift detected in $f:"; - echo "$DIFF_FILTERED"; - fail=1; - fi - done - if [ $fail -ne 0 ]; then - echo "\nERROR: Generated artifacts differ from repository (beyond timestamps)." - echo "Run:" - echo " DOCKER_SSOT_MODE=envless bash scripts/generate-compose-files.sh all" - echo "and commit the changes." - exit 1 - fi - echo "No SSoT drift (ignoring timestamps)." + # FIX: .yaml Extension nutzen (SSoT) + - name: Validate Docker Compose Config + run: docker compose --env-file docker/.env -f docker/docker-compose.yaml config diff --git a/.github/workflows/youtrack-sync.yml b/.github/workflows/youtrack-sync.yml index 5f88806a..e4507b4f 100644 --- a/.github/workflows/youtrack-sync.yml +++ b/.github/workflows/youtrack-sync.yml @@ -23,7 +23,7 @@ jobs: steps: # WICHTIG: Checkout ist notwendig, damit "git log" funktioniert - name: Checkout Code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 # Notwendig, um die Commit-Historie für "git log" zu laden diff --git a/.gitignore b/.gitignore index 5eaa1d53..e4d2cb84 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,7 @@ logs/ # Kotlin/Java *.class -.env +config/.env # Generated diagrams build/diagrams/ diff --git a/.junie/guidelines/_archived/docker-guideline-v3.0.1-archived-2025-09-15.md b/.junie/guidelines/_archived/docker-guideline-v3.0.1-archived-2025-09-15.md index 00444547..63ca23cc 100644 --- a/.junie/guidelines/_archived/docker-guideline-v3.0.1-archived-2025-09-15.md +++ b/.junie/guidelines/_archived/docker-guideline-v3.0.1-archived-2025-09-15.md @@ -108,7 +108,7 @@ graph TB ```bash # Massive Redundanz über 100+ Dateien verteilt: gradle.properties: services.port.ping=8082 -docker-compose.services.yml: SERVER_PORT: ${PING_SERVICE_PORT:-8082} +docker-compose.services.yaml: SERVER_PORT: ${PING_SERVICE_PORT:-8082} dockerfiles/services/ping: EXPOSE 8082 scripts/test/integration: ping-service:8082 config/monitoring/prometheus: - targets: ['ping-service:8082'] @@ -258,7 +258,7 @@ ping-service = 8092 # Geändert von 8082 # Ergebnis: 38+ Dateien automatisch aktualisiert: # ✓ gradle.properties: services.port.ping=8092 -# ✓ docker-compose.services.yml: SERVER_PORT: ${PING_SERVICE_PORT:-8092} +# ✓ docker-compose.services.yaml: SERVER_PORT: ${PING_SERVICE_PORT:-8092} # ✓ dockerfiles/services/ping-service/Dockerfile: EXPOSE 8092 # ✓ scripts/test/integration-test.sh: ping-service:8092 # ✓ config/monitoring/prometheus.dev.yml: - targets: ['ping-service:8092'] @@ -355,7 +355,7 @@ future-service = 8099 # Nach Synchronisation automatisch in: # - gradle.properties -# - docker-compose.yml +# - docker-compose.yaml # - Monitoring-Konfiguration # - Test-Scripts # - Environment-Files @@ -387,7 +387,7 @@ future-service = 8099 ```bash # ❌ FALSCH - Nie mehr manuelle Port-Änderungen -vim docker-compose.yml # Änderungen gehen verloren! +vim docker-compose.yaml # Änderungen gehen verloren! # ✅ RICHTIG - Zentrale Änderung + Synchronisation vim config/central.toml @@ -914,7 +914,7 @@ test-containers = true ```bash # Development mit Hot-Reload und Debug export DOCKER_ENVIRONMENT=development -docker-compose -f docker-compose.yml -f docker-compose.dev.yml up -d +docker-compose -f docker-compose.yaml -f docker-compose.dev.yml up -d ``` #### Production Environment @@ -1162,9 +1162,9 @@ jobs: }, "docker.composeCommand": "docker-compose", "docker.composeFiles": [ - "docker-compose.yml", - "docker-compose.services.yml", - "docker-compose.clients.yml" + "docker-compose.yaml", + "docker-compose.services.yaml", + "docker-compose.clients.yaml" ] } ``` @@ -1713,20 +1713,20 @@ Unsere Compose-Dateien sind modular organisiert für verschiedene Einsatzszenari ```bash # Alle Services einschließlich Clients docker-compose \ - -f docker-compose.yml \ - -f docker-compose.services.yml \ - -f docker-compose.clients.yml \ + -f docker-compose.yaml \ + -f docker-compose.services.yaml \ + -f docker-compose.clients.yaml \ up -d # Nur Infrastructure für Backend-Entwicklung -docker-compose -f docker-compose.yml up -d postgres redis kafka consul zipkin +docker-compose -f docker-compose.yaml up -d postgres redis kafka consul zipkin # Mit Debug-Unterstützung für Service-Entwicklung DEBUG=true SPRING_PROFILES_ACTIVE=docker \ -docker-compose -f docker-compose.yml -f docker-compose.services.yml up -d +docker-compose -f docker-compose.yaml -f docker-compose.services.yaml up -d # Mit Live-Reload für Frontend-Entwicklung -docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d +docker-compose -f docker-compose.yaml -f docker-compose.override.yml up -d ``` #### 🔧 Erweiterte Umgebungskonfiguration @@ -1734,7 +1734,7 @@ docker-compose -f docker-compose.yml -f docker-compose.override.yml up -d **Beispiel für Auth-Server Konfiguration:** ```yaml -# Erweiterte Environment-Variablen aus docker-compose.services.yml +# Erweiterte Environment-Variablen aus docker-compose.services.yaml auth-server: environment: # Spring Boot Configuration @@ -1788,7 +1788,7 @@ auth-server: # Production - Optimiert und sicher docker-compose \ -f docker-compose.prod.yml \ - -f docker-compose.services.yml \ + -f docker-compose.services.yaml \ up -d # Mit spezifischen Environment-Variablen @@ -1801,11 +1801,11 @@ docker-compose -f docker-compose.prod.yml up -d ```bash # Nur notwendige Services für Tests -docker-compose -f docker-compose.yml up -d postgres redis +docker-compose -f docker-compose.yaml up -d postgres redis ./gradlew test # End-to-End Tests -docker-compose -f docker-compose.yml -f docker-compose.services.yml up -d +docker-compose -f docker-compose.yaml -f docker-compose.services.yaml up -d ./gradlew :client:web-app:jsTest ``` @@ -1909,7 +1909,7 @@ services: ```bash # Service im Debug-Modus starten -docker-compose -f docker-compose.yml up -d ping-service +docker-compose -f docker-compose.yaml up -d ping-service docker-compose exec ping-service sh # Logs in Echtzeit verfolgen @@ -2080,7 +2080,7 @@ labels: ```bash # Centralized logging mit ELK Stack (optional) -docker-compose -f docker-compose.yml -f docker-compose.logging.yml up -d +docker-compose -f docker-compose.yaml -f docker-compose.logging.yml up -d # Log-Parsing für strukturierte Logs docker-compose logs --follow --tail=100 api-gateway | jq -r '.message' diff --git a/.junie/guidelines/technology-guides/docker/docker-development.md b/.junie/guidelines/technology-guides/docker/docker-development.md index d8bcf254..33715817 100644 --- a/.junie/guidelines/technology-guides/docker/docker-development.md +++ b/.junie/guidelines/technology-guides/docker/docker-development.md @@ -53,7 +53,7 @@ make full-logs # Alle Logs in Echtzeit Befehle für die lokale Entwicklungsumgebung: ```bash -make dev-up # Startet Entwicklungsumgebung (docker-compose.yml) +make dev-up # Startet Entwicklungsumgebung (docker-compose.yaml) make dev-down # Stoppt Entwicklungsumgebung make dev-restart # Neustart Entwicklungsumgebung make dev-logs # Zeigt alle Development-Logs @@ -634,16 +634,16 @@ Das Projekt verwendet mehrere Compose-Files: ```bash # Nur Infrastruktur -docker compose -f docker-compose.yml up -d +docker compose -f docker-compose.yaml up -d # Infrastruktur + Services -docker compose -f docker-compose.yml -f docker-compose.services.yml up -d +docker compose -f docker-compose.yaml -f docker-compose.services.yaml up -d # Infrastruktur + Clients -docker compose -f docker-compose.yml -f docker-compose.clients.yml up -d +docker compose -f docker-compose.yaml -f docker-compose.clients.yaml up -d # Alles -docker compose -f docker-compose.yml -f docker-compose.services.yml -f docker-compose.clients.yml up -d +docker compose -f docker-compose.yaml -f docker-compose.services.yaml -f docker-compose.clients.yaml up -d # ⚠️ Tipp: Verwende stattdessen die Makefile-Befehle! ``` diff --git a/.junie/guidelines/technology-guides/docker/docker-monitoring.md b/.junie/guidelines/technology-guides/docker/docker-monitoring.md index ad09609e..71fc9e68 100644 --- a/.junie/guidelines/technology-guides/docker/docker-monitoring.md +++ b/.junie/guidelines/technology-guides/docker/docker-monitoring.md @@ -58,7 +58,7 @@ labels: ```bash # Centralized logging mit ELK Stack (optional) -docker-compose -f docker-compose.yml -f docker-compose.logging.yml up -d +docker-compose -f docker-compose.yaml -f docker-compose.logging.yml up -d # Log-Parsing für strukturierte Logs docker-compose logs --follow --tail=100 api-gateway | jq -r '.message' diff --git a/.junie/guidelines/technology-guides/docker/docker-production.md b/.junie/guidelines/technology-guides/docker/docker-production.md index 16ffc145..1ddc2bf0 100644 --- a/.junie/guidelines/technology-guides/docker/docker-production.md +++ b/.junie/guidelines/technology-guides/docker/docker-production.md @@ -186,7 +186,7 @@ source .env.production certbot certificates # 3. Services mit Production-Konfiguration starten -docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d +docker-compose -f docker-compose.yaml -f docker-compose.prod.yml up -d # 4. Health-Checks durchführen curl -f https://api.meldestelle.at/actuator/health diff --git a/.junie/guidelines/technology-guides/web-app-guideline.md b/.junie/guidelines/technology-guides/web-app-guideline.md index 0c6271c4..1fa7f83c 100644 --- a/.junie/guidelines/technology-guides/web-app-guideline.md +++ b/.junie/guidelines/technology-guides/web-app-guideline.md @@ -146,8 +146,8 @@ Das Docker-Setup ist spezifisch für die Web-Entwicklung konfiguriert (wie in `R ```shell script # Startet die Web-App mit Hot-Reload -docker-compose -f docker-compose.yml \ --f docker-compose.clients.yml up -d web-app +docker-compose -f docker-compose.yaml \ +-f docker-compose.clients.yaml up -d web-app ``` Der Dienst ist dann unter dem in der `docker-compose.clients.yml` konfigurierten Port (z.B. Port `3000`) erreichbar. diff --git a/README.md b/README.md index 9f619549..0a32728d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # 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) @@ -26,7 +27,7 @@ cp -n .env.template config/env/.env 2>/dev/null || true # DOCKER_SSOT_MODE=envless bash scripts/generate-compose-files.sh all development # 4) Infrastruktur starten -docker compose -f docker-compose.yml up -d +docker compose -f docker-compose.yaml up -d # 5) Services starten (Beispiel) ./gradlew :members:members-service:bootRun @@ -259,10 +260,10 @@ bash scripts/generate-compose-files.sh all development && \ ```bash # Nur Infrastruktur -# Wenn eine handgeschriebene docker-compose.yml existiert: -docker compose -f docker-compose.yml up -d +# Wenn eine handgeschriebene docker-compose.yaml existiert: +docker compose -f docker-compose.yaml up -d # Falls Compose-Files generiert werden: -docker compose -f docker-compose.services.yml up -d +docker compose -f docker-compose.services.yaml up -d # Services via Gradle a) Einzeldienst @@ -304,7 +305,7 @@ b) Falls unterstützt: alle (oder Aggregator) #### Nur Infrastruktur (Postgres, Redis, Kafka, Keycloak) ```bash - docker compose -f docker-compose.yml up -d + docker compose -f docker-compose.yaml up -d ``` #### Services über Gradle diff --git a/_backup_chaos/.env.template b/_backup_chaos/.env.template deleted file mode 100644 index a5ccc91a..00000000 --- a/_backup_chaos/.env.template +++ /dev/null @@ -1,195 +0,0 @@ -# =================================================================== -# Environment Configuration Template - Meldestelle Project -# =================================================================== -# Copy this file to config/env/.env and customize the values for your environment -# Security Note: Never commit .env files containing production secrets! -# =================================================================== - -# =================================================================== -# Runtime Configuration (Single Source for runtime values) -# Hinweis: Build-/Image-Versionen werden ausschließlich in docker/versions.toml -# und docker/build-args/global.env gepflegt. Keine Build-/Versionseinträge hier. -# =================================================================== - -# Anwendung -APP_NAME=Meldestelle - -# Profile -SPRING_PROFILES_ACTIVE=docker,keycloak - -# =================================================================== -# Infrastructure Services - Port Configuration -# =================================================================== -# Database -POSTGRES_DB=meldestelle -# Note: Username and password are now managed via Docker secrets - -# Redis Cache -REDIS_PORT=6379 - -# Keycloak Authentication -KEYCLOAK_PORT=8180 -KEYCLOAK_LOG_LEVEL=INFO - -# Service Discovery -CONSUL_HOST=consul -CONSUL_PORT=8500 -CONSUL_ENABLED=true - -# Messaging -ZOOKEEPER_CLIENT_PORT=2181 -KAFKA_PORT=9092 -KAFKA_BROKER_ID=1 -KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 - -# Monitoring -PROMETHEUS_PORT=9090 -GRAFANA_PORT=3000 - -# =================================================================== -# Application Services - Port Configuration -# =================================================================== -# API Gateway -GATEWAY_HOST=api-gateway -GATEWAY_PORT=8081 - -# Microservices -PING_SERVICE_PORT=8082 -MEMBERS_SERVICE_PORT=8083 -HORSES_SERVICE_PORT=8084 -EVENTS_SERVICE_PORT=8085 -MASTERDATA_SERVICE_PORT=8086 -AUTH_SERVICE_PORT=8087 -MONITORING_SERVER_PORT=8088 - -# =================================================================== -# Client Applications - Port Configuration -# =================================================================== -# Web Application -WEB_APP_PORT=4000 -WEB_APP_DOMAIN=localhost -NODE_ENV=production - -# Nginx Configuration -NGINX_WORKER_PROCESSES=auto -NGINX_WORKER_CONNECTIONS=1024 - -# Desktop Application -DESKTOP_VNC_WEB_PORT=6080 -DESKTOP_VNC_PORT=5901 -DESKTOP_APP_DOMAIN=localhost - -# =================================================================== -# Security Configuration -# =================================================================== -# JWT Configuration -JWT_ISSUER=meldestelle-auth-server -JWT_AUDIENCE=meldestelle-services - -# Note: JWT_SECRET is now managed via Docker secrets -# Generate with: openssl rand -hex 32 - -# Keycloak Configuration -KEYCLOAK_REALM=meldestelle -KEYCLOAK_CLIENT_ID=api-gateway - -# Note: All passwords and secrets are now managed via Docker secrets -# Run: ./docker/secrets/setup-secrets.sh to generate secure secrets - -# =================================================================== -# Data Storage Configuration -# =================================================================== -# Data directory for persistent volumes -# Default: ./data (relative to project root) -# Production: /var/lib/meldestelle or dedicated mount point -DATA_PATH=./data - -# Volume configuration -# These directories will be created under DATA_PATH: -# - postgres/ (PostgreSQL data) -# - redis/ (Redis data) -# - prometheus/ (Prometheus metrics) -# - grafana/ (Grafana dashboards) -# - keycloak/ (Keycloak data) -# - consul/ (Consul data) -# - monitoring/ (Custom monitoring data) -# - desktop-app/ (Desktop application data) - -# =================================================================== -# Development and Testing -# =================================================================== -# Enable debug mode for Java applications -DEBUG=false - -# Enable Wasm compilation for client applications -ENABLE_WASM=false - -# =================================================================== -# Production Deployment Settings -# =================================================================== -# Container resource limits (configured in docker-compose files) -# These are documented here for reference: - -# Infrastructure Services Resource Limits: -# - postgres: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - redis: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) -# - keycloak: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM) -# - consul: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM) -# - kafka: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - zookeeper: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) -# - prometheus: 1 CPU, 2GB RAM (reserved: 0.25 CPU, 512MB RAM) -# - grafana: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) -# - api-gateway: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM) - -# Microservices Resource Limits: -# - ping-service: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) -# - members-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - horses-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - events-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - masterdata-service: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - auth-server: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM) - -# Client Applications Resource Limits: -# - web-app: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM) -# - desktop-app: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - monitoring-server: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) - -# =================================================================== -# Security Notes -# =================================================================== -# 1. All passwords and secrets are managed via Docker secrets -# 2. Run ./docker/secrets/setup-secrets.sh to generate secure credentials -# 3. Containers run as non-root users where possible -# 4. Security options: no-new-privileges enabled for all services -# 5. Networks are isolated with custom subnet (172.20.0.0/16) -# 6. Volumes have proper permissions and are mounted read-only where appropriate -# 7. Health checks are configured for all services -# 8. Resource limits prevent resource exhaustion attacks - -# =================================================================== -# Usage Instructions -# =================================================================== -# 1. Copy this file: mkdir -p config/env && cp .env.template config/env/.env -# 2. Customize values in config/env/.env for your environment -# 3. Generate secrets: ./docker/secrets/setup-secrets.sh --all -# 4. Create data directories: mkdir -p ./data/{postgres,redis,prometheus,grafana,keycloak,consul} -# 5. Deploy infrastructure: docker compose -f docker-compose.yml up -d -# 6. Deploy services: docker compose -f docker-compose.services.yml up -d -# 7. Deploy clients: docker compose -f docker-compose.clients.yml up -d - -# =================================================================== -# Monitoring and Logging -# =================================================================== -# Access URLs (when running with default ports): -# - Grafana Dashboard: http://localhost:3000 (admin credentials in secrets) -# - Prometheus Metrics: http://localhost:9090 -# - Consul UI: http://localhost:8500 -# - Keycloak Admin: http://localhost:8180/admin (admin credentials in secrets) -# - API Gateway: http://localhost:8081 -# - Web Application: http://localhost:4000 -# - Desktop VNC: http://localhost:6080 - -# Log locations (inside containers): -# - Application logs: /app/logs/ -# - Nginx logs: /var/log/nginx/ -# - System logs: journalctl -u docker diff --git a/_backup_chaos/.env~origin_main b/_backup_chaos/.env~origin_main deleted file mode 100644 index 9ea6101f..00000000 --- a/_backup_chaos/.env~origin_main +++ /dev/null @@ -1,207 +0,0 @@ -# =================================================================== -# Environment Configuration Template - Meldestelle Project -# =================================================================== -# Copy this file to .env and customize the values for your environment -# Security Note: Never commit .env files containing production secrets! -# =================================================================== - -# =================================================================== -# Build Configuration -# =================================================================== -# Docker image versions -DOCKER_GRADLE_VERSION=9.1.0 -DOCKER_JAVA_VERSION=21 -DOCKER_KEYCLOAK_VERSION=26.4.0 -DOCKER_PROMETHEUS_VERSION=v2.54.1 -DOCKER_GRAFANA_VERSION=11.3.0 - -# Application version -DOCKER_APP_VERSION=1.0.0 -APP_VERSION=1.0.0 -APP_NAME=Meldestelle - -# Build metadata -BUILD_DATE=2025-11-11 -# BUILD_DATE will be auto-generated if not set - -# Spring profiles for services -SPRING_PROFILES_ACTIVE=docker,keycloak -DOCKER_SPRING_PROFILES_DEFAULT=default -DOCKER_SPRING_PROFILES_DOCKER=docker - -# =================================================================== -# Infrastructure Services - Port Configuration -# =================================================================== -# Database -POSTGRES_DB=meldestelle -# Note: Username and password are now managed via Docker secrets - -# Redis Cache -REDIS_PORT=6379 - -# Keycloak Authentication -KEYCLOAK_PORT=8180 -KEYCLOAK_LOG_LEVEL=INFO - -# Service Discovery -CONSUL_HOST=consul -CONSUL_PORT=8500 -CONSUL_ENABLED=true - -# Messaging -ZOOKEEPER_CLIENT_PORT=2181 -KAFKA_PORT=9092 -KAFKA_BROKER_ID=1 -KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 - -# Monitoring -PROMETHEUS_PORT=9090 -GRAFANA_PORT=3000 - -# =================================================================== -# Application Services - Port Configuration -# =================================================================== -# API Gateway -GATEWAY_HOST=api-gateway -GATEWAY_PORT=8081 - -# Microservices -PING_SERVICE_PORT=8082 -MEMBERS_SERVICE_PORT=8083 -HORSES_SERVICE_PORT=8084 -EVENTS_SERVICE_PORT=8085 -MASTERDATA_SERVICE_PORT=8086 -AUTH_SERVICE_PORT=8087 -MONITORING_SERVER_PORT=8088 - -# =================================================================== -# Client Applications - Port Configuration -# =================================================================== -# Web Application -WEB_APP_PORT=4000 -WEB_APP_DOMAIN=localhost -NODE_ENV=production - -# Nginx Configuration -NGINX_WORKER_PROCESSES=auto -NGINX_WORKER_CONNECTIONS=1024 - -# Desktop Application -DESKTOP_VNC_WEB_PORT=6080 -DESKTOP_VNC_PORT=5901 -DESKTOP_APP_DOMAIN=localhost - -# =================================================================== -# Security Configuration -# =================================================================== -# JWT Configuration -JWT_ISSUER=meldestelle-auth-server -JWT_AUDIENCE=meldestelle-services - -# Note: JWT_SECRET is now managed via Docker secrets -# Generate with: openssl rand -hex 32 - -# Keycloak Configuration -KEYCLOAK_REALM=meldestelle -KEYCLOAK_CLIENT_ID=api-gateway - -# Note: All passwords and secrets are now managed via Docker secrets -# Run: ./docker/secrets/setup-secrets.sh to generate secure secrets - -# =================================================================== -# Data Storage Configuration -# =================================================================== -# Data directory for persistent volumes -# Default: ./data (relative to project root) -# Production: /var/lib/meldestelle or dedicated mount point -DATA_PATH=./data - -# Volume configuration -# These directories will be created under DATA_PATH: -# - postgres/ (PostgreSQL data) -# - redis/ (Redis data) -# - prometheus/ (Prometheus metrics) -# - grafana/ (Grafana dashboards) -# - keycloak/ (Keycloak data) -# - consul/ (Consul data) -# - monitoring/ (Custom monitoring data) -# - desktop-app/ (Desktop application data) - -# =================================================================== -# Development and Testing -# =================================================================== -# Enable debug mode for Java applications -DEBUG=false - -# Enable Wasm compilation for client applications -ENABLE_WASM=false - -# =================================================================== -# Production Deployment Settings -# =================================================================== -# Container resource limits (configured in docker-compose files) -# These are documented here for reference: - -# Infrastructure Services Resource Limits: -# - postgres: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - redis: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) -# - keycloak: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM) -# - consul: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM) -# - kafka: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - zookeeper: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) -# - prometheus: 1 CPU, 2GB RAM (reserved: 0.25 CPU, 512MB RAM) -# - grafana: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) -# - api-gateway: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 1GB RAM) - -# Microservices Resource Limits: -# - ping-service: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) -# - members-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - horses-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - events-service: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - masterdata-service: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - auth-server: 1.5 CPU, 1.5GB RAM (reserved: 0.5 CPU, 512MB RAM) - -# Client Applications Resource Limits: -# - web-app: 1 CPU, 512MB RAM (reserved: 0.25 CPU, 128MB RAM) -# - desktop-app: 2 CPU, 2GB RAM (reserved: 0.5 CPU, 512MB RAM) -# - monitoring-server: 1 CPU, 1GB RAM (reserved: 0.25 CPU, 256MB RAM) - -# =================================================================== -# Security Notes -# =================================================================== -# 1. All passwords and secrets are managed via Docker secrets -# 2. Run ./docker/secrets/setup-secrets.sh to generate secure credentials -# 3. Containers run as non-root users where possible -# 4. Security options: no-new-privileges enabled for all services -# 5. Networks are isolated with custom subnet (172.20.0.0/16) -# 6. Volumes have proper permissions and are mounted read-only where appropriate -# 7. Health checks are configured for all services -# 8. Resource limits prevent resource exhaustion attacks - -# =================================================================== -# Usage Instructions -# =================================================================== -# 1. Copy this file: cp .env.template .env -# 2. Customize values in .env for your environment -# 3. Generate secrets: ./docker/secrets/setup-secrets.sh --all -# 4. Create data directories: mkdir -p ./data/{postgres,redis,prometheus,grafana,keycloak,consul} -# 5. Deploy infrastructure: docker-compose -f docker-compose.yml.optimized up -d -# 6. Deploy services: docker-compose -f docker-compose.yml.optimized -f docker-compose.services.yml.optimized up -d -# 7. Deploy clients: docker-compose -f docker-compose.yml.optimized -f docker-compose.services.yml.optimized -f docker-compose.clients.yml.optimized up -d - -# =================================================================== -# Monitoring and Logging -# =================================================================== -# Access URLs (when running with default ports): -# - Grafana Dashboard: http://localhost:3000 (admin credentials in secrets) -# - Prometheus Metrics: http://localhost:9090 -# - Consul UI: http://localhost:8500 -# - Keycloak Admin: http://localhost:8180/admin (admin credentials in secrets) -# - API Gateway: http://localhost:8081 -# - Web Application: http://localhost:4000 -# - Desktop VNC: http://localhost:6080 - -# Log locations (inside containers): -# - Application logs: /app/logs/ -# - Nginx logs: /var/log/nginx/ -# - System logs: journalctl -u docker diff --git a/_backup_chaos/README.md b/_backup_chaos/README.md deleted file mode 100644 index b2588a09..00000000 --- a/_backup_chaos/README.md +++ /dev/null @@ -1 +0,0 @@ -# Horses Module\n\nThis is a minimal placeholder README to satisfy documentation validation. See docs/index.md for project docs diff --git a/_backup_chaos/Schlachtplan.md b/_backup_chaos/Schlachtplan.md deleted file mode 100644 index fe0fc29f..00000000 --- a/_backup_chaos/Schlachtplan.md +++ /dev/null @@ -1,443 +0,0 @@ -### Schlachtplan für das 'infrastructure'-Modul - -Basierend auf der Analyse des aktuellen Zustands (Stand: 11. Oktober 2025) habe ich einen strukturierten Aktionsplan -erstellt. Die letzte größere Aktualisierung war im Juli 2025, seitdem gab es signifikante Änderungen am Gateway-Modul. - ---- - -### 🔴 Phase 1: SOFORT (Diese Woche) - -#### 1.1 Gateway-Tests reparieren (Höchste Priorität) - -**Problem:** Tests sind komplett defekt - nur ~47% funktionieren noch (25/53 Tests). - -**Aktionen:** - -- ❌ **Löschen:** `JwtAuthenticationTests.kt` - testet nicht-existierende Custom-Filter -- ✅ **Behalten:** `FallbackControllerTests.kt`, `GatewayApplicationTests.kt` -- ✏️ **Überarbeiten:** `GatewayRoutingTests.kt`, `GatewaySecurityTests.kt`, `GatewayFiltersTests.kt` - - Option A: Tests mit MockJWT-Tokens ausstatten (siehe `TestSecurityConfig.kt`) - - Option B: Tests auf Public Paths verlegen (`/actuator/**`, `/fallback/**`) - - Option C: Security in Tests deaktivieren - -**Warum jetzt:** Tests geben keine Sicherheit mehr – blockiert Entwicklung. - -**Zeitaufwand:** 4–6 Stunden - ---- - -#### 1.2 Gateway-Build-Datei bereinigen - -**Problem:** Duplizierte Dependency in `gateway/build.gradle.kts` (Zeile 33-34). - -**Aktion:** - -```kotlin -// ENTFERNEN: Zeile 34 -implementation(project(":infrastructure:event-store:redis-event-store")) // ← Duplikat! -``` - -**Zeitaufwand:** 5 Minuten - ---- - -### 🟡 Phase 2: KURZFRISTIG (Nächste 2 Wochen) - -#### 2.1 Dependency-Versionen aktualisieren - -**Problem:** Versionen von Juli 2025 – teilweise veraltet. - -**Zu prüfen und aktualisieren:** - -| Dependency | Aktuell | Latest (Okt 2025) | Priorität | -|-------------------|----------|-------------------|-----------| -| Spring Boot | 3.5.5 | 3.5.x | Mittel | -| Spring Cloud | 2025.0.0 | 2025.0.x | Mittel | -| Kotlin | 2.2.20 | 2.2.x | Niedrig | -| Keycloak | 26.0.7 | 26.x.x | Hoch | -| Testcontainers | 1.21.3 | 1.21.x | Niedrig | -| PostgresQL Driver | 42.7.7 | 42.7.x | Niedrig | - -**Aktion:** - -1. `gradle/libs.versions.toml` aktualisieren -2. Tests nach jedem Update ausführen -3. Breaking Changes dokumentieren - -**Zeitaufwand:** 1–2 Tage (mit Testing) - ---- - -#### 2.2 Docker-Images aktualisieren - -**Problem:** Einige Docker-Images sind möglicherweise veraltet. - -**Zu prüfen:** - -```yaml -# docker-compose.yml -postgres: 16-alpine # ✅ Aktuell (neueste: 16.x) -redis: 7-alpine # ✅ Aktuell -keycloak: 26.4.0 # ⚠️ Prüfen auf 26.x updates -consul: 1.15 # ⚠️ Prüfen (neueste: 1.20+) -kafka: 7.4.0 # ⚠️ Prüfen (neueste: 7.8+) -prometheus: v2.54.1 # ⚠️ Prüfen -grafana: 11.3.0 # ✅ Wahrscheinlich aktuell -``` - -**Aktion:** - -1. Versions-Check durchführen -2. Schrittweise aktualisieren (einzeln testen!) -3. `.env`-Datei mit Versions-Variablen anlegen - -**Zeitaufwand:** 3–4 Stunden - ---- - -#### 2.3 Monitoring-Modul vervollständigen - -**Problem:** Nur 3 Kotlin-Files – deutlich unter implementiert im Vergleich zur Dokumentation. - -**Dokumentiert, aber fehlt:** - -- Distributed Tracing (Zipkin) - Docker-Container fehlt! -- Custom Metrics Implementation -- Health Check Aggregation -- Alerting Rules Implementation - -**Aktion:** - -1. Zipkin zu `docker-compose.yml` hinzufügen -2. Tracing-Integration in Gateway testen -3. Custom Metrics-Library erstellen -4. Prometheus Alerting Rules konfigurieren - -**Zeitaufwand:** 2–3 Tage - ---- - -### 🟢 Phase 3: MITTELFRISTIG (Nächste 4–6 Wochen) - -#### 3.1 Dokumentation aktualisieren - -**Problem:** README von Juli 2025 – nicht mehr aktuell. - -**Zu aktualisieren:** - -**`README-INFRASTRUCTURE.md`:** - -- Zeile 552: "Letzte Aktualisierung: 25. Juli 2025" → Oktober 2025 -- Security-Sektion: OAuth2 Resource Server statt Custom JWT Filter -- Keycloak Version: 23.0 → 26.4.0 -- Kafka Version: 7.5.0 → 7.4.0 (Downgrade dokumentieren!) -- Monitoring: Zipkin-Konfiguration ergänzen - -**Neue Sections hinzufügen:** - -- #### Bekannte Limitierungen - -- #### Migration Notes (Juli → Oktober 2025) - -- #### Troubleshooting erweitern - -**Zeitaufwand:** 1 Tag - ---- - -#### 3.2 Auth-Module überarbeiten - -**Problem:** Vermutlich veraltet - Custom JWT vs. OAuth2 Resource Server Diskrepanz. - -**Zu klären:** - -- Werden `auth-client` und `auth-server` noch verwendet? -- Redundanz mit Gateway's OAuth2 Resource Server? -- Keycloak-Integration vereinheitlichen - -**Aktion:** - -1. Abhängigkeiten zu auth-Modulen analysieren -2. Entscheiden: Refactoring oder Deprecation -3. Wenn deprecated: Migration Path dokumentieren - -**Zeitaufwand:** 3–5 Tage - ---- - -#### 3.3 Cache-Module modernisieren - -**Problem:** Redis 7 ist aktuell, aber Implementation-Patterns könnten veraltet sein. - -**Zu prüfen:** - -- Multi-Level Caching tatsächlich implementiert? -- Cache Statistics vorhanden? -- TTL Management korrekt? -- Integration mit Spring Cache Abstraction? - -**Aktion:** - -1. Cache-Tests erweitern -2. Performance-Metriken hinzufügen -3. Cache-Warming Strategy implementieren - -**Zeitaufwand:** 2–3 Tage - ---- - -#### 3.4 Event-Store Performance-Optimierung - -**Problem:** Redis-basiert - für Production ggf. nicht optimal. - -**Zu evaluieren:** - -- Ist Redis der richtige Event Store für Production? -- Alternative: PostgresQL mit Event Store Pattern? -- Snapshot-Strategie tatsächlich implementiert? - -**Aktion:** - -1. Performance-Tests durchführen -2. Event Store Benchmark (Redis vs. PostgresQL) -3. Dokumentation aktualisieren mit Pros/Cons - -**Zeitaufwand:** 1 Woche - ---- - -### 🔵 Phase 4: LANGFRISTIG (Nächste 2–3 Monate) - -#### 4.1 Service Mesh evaluieren - -**Dokumentiert in "Zukünftige Erweiterungen"** – noch nicht implementiert. - -**Optionen:** - -- Istio (komplex, feature-reich) -- Linkerd (leichtgewichtig) -- Consul Connect (bereits Consul vorhanden!) - -**Empfehlung:** Start mit Consul Connect - minimaler Overhead. - -**Zeitaufwand:** 2–3 Wochen - ---- - -#### 4.2 OpenTelemetry statt Zipkin - -**Problem:** Zipkin ist veraltet – OpenTelemetry ist der moderne Standard. - -**Migration Path:** - -1. OpenTelemetry Collector aufsetzen -2. Spring Boot Auto-Instrumentation aktivieren -3. Zipkin als Backend behalten (kompatibel!) -4. Schrittweise migrieren - -**Zeitaufwand:** 1–2 Wochen - ---- - -#### 4.3 Security Hardening - -**Aktuelle Gaps:** - -- JWT Token Rotation nicht implementiert -- Rate Limiting nur dokumentiert, nicht konfiguriert -- Audit Logging fehlt -- HTTPS/TLS noch nicht erzwungen - -**Aktion:** - -1. Rate Limiting im Gateway aktivieren -2. Audit Log Framework implementieren -3. TLS für Service-zu-Service-Kommunikation -4. Security Scan mit OWASP Dependency Check - -**Zeitaufwand:** 2–3 Wochen - ---- - -#### 4.4 Infrastructure as Code (IaC) - -**Problem:** Nur Docker Compose – für Production nicht ausreichend. - -**Zu erstellen:** - -- Kubernetes Manifests (aktualisieren - Zeile 393+) -- Helm Charts (aktualisieren – Zeile 420+) -- Terraform für Cloud-Ressourcen -- CI/CD Pipelines - -**Zeitaufwand:** 4–6 Wochen - ---- - -### 📊 Priorisierung-Matrix - -| Phase | Aufgabe | Dringlichkeit | Aufwand | Impact | -|-------|---------------|---------------|---------|---------| -| 1 | Gateway-Tests | 🔴 Sehr hoch | 4-6h | Hoch | -| 1 | Build-Datei | 🔴 Sehr hoch | 5min | Niedrig | -| 2 | Dependencies | 🟡 Hoch | 1-2d | Mittel | -| 2 | Docker-Images | 🟡 Hoch | 3-4h | Mittel | -| 2 | Monitoring | 🟡 Mittel | 2-3d | Hoch | -| 3 | Dokumentation | 🟢 Mittel | 1d | Mittel | -| 3 | Auth-Module | 🟢 Mittel | 3-5d | Hoch | -| 3 | Cache | 🟢 Niedrig | 2-3d | Mittel | -| 3 | Event-Store | 🟢 Niedrig | 1w | Mittel | -| 4 | Service Mesh | 🔵 Niedrig | 2-3w | Hoch | -| 4 | OpenTelemetry | 🔵 Niedrig | 1-2w | Mittel | -| 4 | Security | 🔵 Mittel | 2-3w | Hoch | -| 4 | IaC | 🔵 Niedrig | 4-6w | Hoch | - ---- - -### 🎯 Empfohlene Reihenfolge - -#### Woche 1-2 - -1. Gateway-Tests reparieren -2. Build-Datei bereinigen -3. Dependencies aktualisieren - -#### Woche 3-4 - -4. Docker-Images aktualisieren -5. Monitoring vervollständigen -6. Dokumentation aktualisieren - -#### Woche 5-8 - -7. Auth-Module evaluieren/refactored -8. Cache-Module modernisieren -9. Event-Store Performance-Tests - -#### Monat 3-4 - -10. Security Hardening -11. OpenTelemetry Migration -12. Service Mesh Evaluation - -#### Monat 5-6 - -13. Infrastructure as Code -14. Production Readiness Assessment - ---- - -### 🛠️ Tooling-Empfehlungen - -**Für Dependency-Management:** - -- Renovate Bot oder Dependabot für automatische Updates -- `./gradlew dependencyUpdates` Plugin verwenden - -**Für Security:** - -- OWASP Dependency Check -- Trivy für Container-Scanning -- SonarQube für Code-Qualität - -**Für Monitoring:** - -- Grafana Dashboards aus Community importieren -- Prometheus Alertmanager konfigurieren - ---- - -### 📝 Nächste Schritte - -1. **Jetzt sofort:** Gateway-Tests fixen (blockiert alles andere) -2. **Diese Woche:** Dependencies updaten und testen -3. **Nächste Woche:** Sprint Planning für Phase 2 -4. **Monatlich:** Review des Fortschritts und Repriorisierung - ---- - -### ⚠️ Risiken & Abhängigkeiten - -**Kritische Pfade:** - -- Gateway-Tests müssen ZUERST behoben werden -- Dependency-Updates können Breaking Changes haben -- Auth-Refactoring könnte alle Services betreffen - -**Externe Abhängigkeiten:** - -- Keycloak Breaking Changes bei Major Updates -- Spring Boot/Cloud Release Schedule beachten -- Kubernetes Cluster für IaC-Phase benötigt - ---- - -**Geschätzter Gesamtaufwand:** 6–8 Wochen (bei 1 Vollzeit-Entwickler) - -**Empfohlener Start:** Sofort mit Phase 1, dann iterativ durch die Phasen - ---- - -### Documentations-Sprachbereinigung (2025-10-22) - -Im Zuge der Vereinheitlichung auf ausschließlich deutschsprachige Dokumentation wurden folgende Dateien entfernt: - -Gelöschte ADRs (englische Varianten): - -- docs/architecture/adr/0000-adr-template.md -- docs/architecture/adr/0001-modular-architecture.md -- docs/architecture/adr/0002-domain-driven-design.md -- docs/architecture/adr/0003-microservices-architecture.md -- docs/architecture/adr/0004-event-driven-communication.md -- docs/architecture/adr/0005-polyglot-persistence.md -- docs/architecture/adr/0006-authentication-authorization-keycloak.md -- docs/architecture/adr/0007-api-gateway-pattern.md -- docs/architecture/adr/0008-multiplatform-client-applications.md - -Gelöschte C4-Diagramme (englische Varianten): - -- docs/architecture/c4/01-context.puml -- docs/architecture/c4/02-container.puml -- docs/architecture/c4/03-component-events-service.puml - -Hinweis: - -- Alle verbleibenden ADRs und C4-Diagramme sind in deutscher Sprache vorhanden (Suffix-de) und verlinkt. -- Weitere Doku-Dateien in docs/ sind deutsch (Front-Matter/Sprachindizien geprüft). - ---- - -## CI‑Stabilisierung Keycloak (2025‑10‑25) - -Hintergrund: In GitHub Actions startete Keycloak zeitweise nicht zuverlässig. Ziel: Integrationstests stabilisieren, -ohne produktive Architektur zu ändern. - -Änderungen: - -- Integration‑Workflow (`.github/workflows/integration-tests.yml`) auf Matrixbetrieb umgestellt: - - `keycloak_db=postgres` (produktnäher, mit externer Postgres‑DB) - - `keycloak_db=dev-file` (Dateibackend, ohne Postgres; stabiler im CI) -- Robuste Startlogik: - - Aktives Warten auf Postgres (nur in `postgres`‑Variante) - - Keycloak‑Start per `docker run … start-dev` (26.4.2) mit `KC_HEALTH_ENABLED=true` - - Health‑Checks gegen `/`, `/health`, `/q/health`, `/health/ready`, Admin‑Konsole - - Ausführliche Log‑Ausgabe bei Fehlern (Keycloak & Postgres) -- Fail‑fast deaktiviert; beide Matrix‑Jobs laufen unabhängig. - -Nutzung/Operative Hinweise: - -- In PRs beide Matrix‑Runs beachten; bei Flakes in `postgres` sichert `dev-file` die Tests ab. -- Logs bei Fehlschlag: Step „Dump service logs (Keycloak, Postgres)“ am Jobende öffnen. -- Produktiv bleibt Postgres maßgeblich (siehe `docker-compose.yml`). - -ADR‑Konsistenz: - -- ADR‑0006 (Keycloak) bleibt gültig und unverändert; die `dev-file`‑Variante betrifft ausschließlich CI‑Tests. - -Next Steps (optional): - -- Falls `postgres` im CI dauerhaft flakey: Required Checks vorübergehend auf `dev-file` begrenzen. -- Langfristig: Ursachenanalyse für Postgres‑Variante (Runner‑Leistung/Timeouts/Schema‑Setup) und Re‑Enable als Required - Check nach Stabilisierung. - ---- diff --git a/_backup_chaos/build-args/clients.env b/_backup_chaos/build-args/clients.env deleted file mode 100644 index 20217c8a..00000000 --- a/_backup_chaos/build-args/clients.env +++ /dev/null @@ -1,20 +0,0 @@ -# =================================================================== -# Clients Docker Build Arguments - dockerfiles/clients/* -# Source: docker/versions.toml [categories.clients] -# Last updated: 2025-11-18 14:30:11 UTC -# =================================================================== - -# --- Include Global Arguments --- -# Source global.env for GRADLE_VERSION, JAVA_VERSION, VERSION - -# --- Client-Specific Build Tools --- -NODE_VERSION=22.21.0 -NGINX_VERSION=1.28.0-alpine - -# --- Client Build Configuration --- -CLIENT_PATH=client -CLIENT_MODULE=client -CLIENT_NAME=meldestelle-client - -# Note: Runtime/Dev values moved to config/env/.env -# Keep this file strictly for build-time values only. diff --git a/_backup_chaos/build-args/global.env b/_backup_chaos/build-args/global.env deleted file mode 100644 index bc1f9e65..00000000 --- a/_backup_chaos/build-args/global.env +++ /dev/null @@ -1,26 +0,0 @@ -# =================================================================== -# Global Docker Build Arguments - Used by all categories -# Source: docker/versions.toml -# Last updated: 2025-11-18 15:44:00 UTC -# =================================================================== - -# --- Build Tools --- -GRADLE_VERSION=9.1.0 -JAVA_VERSION=21 - -# --- Build Metadata --- -VERSION=1.0.0 - -# --- Monitoring & Infrastructure Services (image tags) --- -PROMETHEUS_IMAGE_TAG=v2.54.1 -GRAFANA_IMAGE_TAG=11.3.0 -KEYCLOAK_IMAGE_TAG=26.4.2 - -# --- Datastore Images (image tags) --- -POSTGRES_IMAGE_TAG=16-alpine -REDIS_IMAGE_TAG=7-alpine - -# --- Additional Infrastructure Images (image tags) --- -CONSUL_IMAGE_TAG=1.15 -ZOOKEEPER_IMAGE_TAG=7.4.0 -KAFKA_IMAGE_TAG=7.4.0 diff --git a/_backup_chaos/build-args/infrastructure.env b/_backup_chaos/build-args/infrastructure.env deleted file mode 100644 index e4815383..00000000 --- a/_backup_chaos/build-args/infrastructure.env +++ /dev/null @@ -1,22 +0,0 @@ -# =================================================================== -# Infrastructure Docker Build Arguments - dockerfiles/infrastructure/* -# Source: docker/versions.toml [categories.infrastructure] -# Last updated: 2025-11-18 14:30:11 UTC -# =================================================================== - -# --- Include Global Arguments --- -# Source global.env for GRADLE_VERSION, JAVA_VERSION, VERSION - -# --- API Gateway Specific --- -GATEWAY_SERVICE_PATH=infrastructure/gateway -GATEWAY_SERVICE_NAME=api-gateway - -# --- Auth Server Specific --- -AUTH_SERVER_PATH=infrastructure/auth/auth-server -AUTH_SERVER_SERVICE_NAME=auth-server - -# --- Monitoring Server Specific --- -MONITORING_SERVER_PATH=infrastructure/monitoring/monitoring-server -MONITORING_SERVER_SERVICE_NAME=monitoring-server - -# Note: Runtime profiles/ports/dependencies moved to config/env/.env diff --git a/_backup_chaos/build-args/services.env b/_backup_chaos/build-args/services.env deleted file mode 100644 index bb61096a..00000000 --- a/_backup_chaos/build-args/services.env +++ /dev/null @@ -1,14 +0,0 @@ -# =================================================================== -# Services Docker Build Arguments - dockerfiles/services/* -# Source: docker/versions.toml [categories.services] -# Last updated: 2025-11-18 14:30:11 UTC -# =================================================================== - -# --- Include Global Arguments --- -# Source global.env for GRADLE_VERSION, JAVA_VERSION, VERSION - -# --- Service-Specific Arguments --- -SERVICE_PATH=. -SERVICE_NAME=spring-boot-service - -# Note: Runtime profiles/ports moved to config/env/.env diff --git a/_backup_chaos/compose.yaml b/_backup_chaos/compose.yaml deleted file mode 100644 index 770d83c0..00000000 --- a/_backup_chaos/compose.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# Zentrale Einstiegsdatei für Docker Compose -name: meldestelle-system - -include: - - path: docker-compose.yml # Infra (Postgres, Redis, Keycloak...) - - path: docker-compose.services.yml # Gateway & Microservices - - path: docker-compose.clients.yml # Web App - -# Hier definieren wir das Netzwerk zentral, damit alle includes es nutzen können -networks: - meldestelle-network: - driver: bridge diff --git a/_backup_chaos/docker-compose.clients.yml b/_backup_chaos/docker-compose.clients.yml deleted file mode 100644 index cff30daa..00000000 --- a/_backup_chaos/docker-compose.clients.yml +++ /dev/null @@ -1,54 +0,0 @@ -# =================================================================== -# Docker Compose - Client Applications -# Generated from docker/versions.toml -# Environment: development -# Generated: 2025-11-18 19:43:46 UTC -# =================================================================== - -services: - # =================================================================== - # Web Application (Compose for Web) - # =================================================================== - web-app: - profiles: ["ui", "frontend"] - build: - context: .. - dockerfile: ../dockerfiles/clients/web-app/Dockerfile - args: - # Global build arguments (centralized DOCKER_* variables) - GRADLE_VERSION: ${DOCKER_GRADLE_VERSION} - JAVA_VERSION: ${DOCKER_JAVA_VERSION} - BUILD_DATE: ${BUILD_DATE} - VERSION: ${DOCKER_APP_VERSION} - # Client-specific arguments (centralized DOCKER_* variables) - NODE_VERSION: ${DOCKER_NODE_VERSION} - NGINX_VERSION: ${DOCKER_NGINX_VERSION} - # Application-specific arguments - CLIENT_PATH: client - CLIENT_MODULE: client - CLIENT_NAME: meldestelle-web-app - container_name: meldestelle-web-app - environment: - NODE_ENV: ${NODE_ENV:-dev} - API_BASE_URL: http://api-gateway:${GATEWAY_PORT:-8081} - WS_URL: ws://api-gateway:${GATEWAY_PORT:-8081}/ws - APP_TITLE: ${APP_NAME:-Meldestelle} - APP_VERSION: ${APP_VERSION:-1.0.0} - ports: - - "4000:4000" - networks: - - meldestelle-network - healthcheck: - test: ["CMD", "curl", "--fail", "http://localhost:4000/health"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 40s - restart: unless-stopped - -# =================================================================== -# Networks (shared network from main compose file) -# =================================================================== -networks: - meldestelle-network: - driver: bridge diff --git a/_backup_chaos/docker-compose.services.yml b/_backup_chaos/docker-compose.services.yml deleted file mode 100644 index 241c30e2..00000000 --- a/_backup_chaos/docker-compose.services.yml +++ /dev/null @@ -1,80 +0,0 @@ -# =================================================================== -# Docker Compose - Application Services -# Generated from docker/versions.toml -# Environment: development -# Generated: 2025-11-18 19:43:46 UTC -# =================================================================== - -services: - profiles: ["app", "backend"] - ping-service: - build: - context: .. - dockerfile: ../dockerfiles/services/ping-service/Dockerfile - args: - # Global build arguments (centralized DOCKER_* variables) - GRADLE_VERSION: ${DOCKER_GRADLE_VERSION} - JAVA_VERSION: ${DOCKER_JAVA_VERSION} - BUILD_DATE: ${BUILD_DATE} - VERSION: ${DOCKER_APP_VERSION} - # Service-specific arguments (centralized DOCKER_* variables) - SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DOCKER} - container_name: meldestelle-ping-service - environment: - SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev} - SERVER_PORT: ${PING_SERVICE_PORT:-8082} - DEBUG: ${DEBUG:-true} - LOGGING_LEVEL_ROOT: ${LOGGING_LEVEL_ROOT:-DEBUG} - JVM_DEBUG_PORT: 5005 - ports: - - "${PING_SERVICE_PORT:-8082}:8082" - - "5005:5005" # Debug-Port - networks: - - meldestelle-network - healthcheck: - test: ["CMD", "curl", "--fail", "http://localhost:8082/actuator/health/readiness"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 40s - restart: unless-stopped - - api-gateway: - profiles: ["infra", "gateway"] - build: - context: .. - dockerfile: ../dockerfiles/infrastructure/gateway/Dockerfile - args: - # Global build arguments (centralized DOCKER_* variables) - GRADLE_VERSION: ${DOCKER_GRADLE_VERSION} - JAVA_VERSION: ${DOCKER_JAVA_VERSION} - BUILD_DATE: ${BUILD_DATE} - VERSION: ${DOCKER_APP_VERSION} - # Infrastructure-specific arguments (centralized DOCKER_* variables) - SPRING_PROFILES_ACTIVE: ${DOCKER_SPRING_PROFILES_DEFAULT} - container_name: meldestelle-api-gateway - environment: - SPRING_PROFILES_ACTIVE: ${SPRING_PROFILES_ACTIVE:-dev} - SERVER_PORT: ${API_GATEWAY_PORT:-8081} - DEBUG: ${DEBUG:-true} - LOGGING_LEVEL_ROOT: ${LOGGING_LEVEL_ROOT:-DEBUG} - JVM_DEBUG_PORT: 5005 - ports: - - "${API_GATEWAY_PORT:-8081}:8081" - - "5005:5005" # Debug-Port - networks: - - meldestelle-network - healthcheck: - test: ["CMD", "curl", "--fail", "http://localhost:8081/actuator/health/readiness"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 40s - restart: unless-stopped - -# =================================================================== -# Networks (shared network from main compose file) -# =================================================================== -networks: - meldestelle-network: - driver: bridge diff --git a/_backup_chaos/docker-compose.yml b/_backup_chaos/docker-compose.yml deleted file mode 100644 index b2fafb94..00000000 --- a/_backup_chaos/docker-compose.yml +++ /dev/null @@ -1,162 +0,0 @@ -# =================================================================== -# Docker Compose - Infrastructure Services -# Generated from docker/versions.toml -# Environment: development -# Generated: 2025-11-18 19:43:46 UTC -# =================================================================== - -services: - # =================================================================== - # Database - # =================================================================== - postgres: - profiles: ["core", "backend"] - image: postgres:${DOCKER_POSTGRES_VERSION:-16-alpine} - container_name: meldestelle-postgres - environment: - POSTGRES_USER: ${POSTGRES_USER:-meldestelle} - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-meldestelle} - POSTGRES_DB: ${POSTGRES_DB:-meldestelle} - ports: - - "5432:5432" - volumes: - - postgres-data:/var/lib/postgresql/data - - ./docker/services/postgres:/docker-entrypoint-initdb.d - networks: - - meldestelle-network - healthcheck: - test: ["CMD-SHELL", "pg_isready -U meldestelle -d meldestelle"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 40s - restart: unless-stopped - - # =================================================================== - # Cache - # =================================================================== - redis: - profiles: ["core", "backend"] - image: redis:${DOCKER_REDIS_VERSION:-7-alpine} - container_name: meldestelle-redis - ports: - - "${REDIS_PORT:-6379}:6379" - volumes: - - redis-data:/data - command: redis-server --appendonly yes - networks: - - meldestelle-network - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 40s - restart: unless-stopped - - # =================================================================== - # Authentication - # =================================================================== - keycloak: - profiles: ["auth", "security"] - image: quay.io/keycloak/keycloak:${DOCKER_KEYCLOAK_VERSION:-26.4.2} - container_name: meldestelle-keycloak - environment: - KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN:-admin} - KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin} - KC_DB: postgres - KC_DB_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB:-meldestelle} - KC_DB_USERNAME: ${POSTGRES_USER:-meldestelle} - KC_DB_PASSWORD: ${POSTGRES_PASSWORD:-meldestelle} - ports: - - "8180:8080" - depends_on: - postgres: - condition: service_healthy - volumes: - - ./docker/services/keycloak:/opt/keycloak/data/import - command: start-dev --import-realm - networks: - - meldestelle-network - healthcheck: - test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 40s - restart: unless-stopped - - # =================================================================== - # Monitoring - # =================================================================== - prometheus: - profiles: ["monitoring"] - image: prom/prometheus:${DOCKER_PROMETHEUS_VERSION:-v2.54.1} - container_name: meldestelle-prometheus - ports: - - "${PROMETHEUS_PORT:-9090}:9090" - volumes: - - prometheus-data:/prometheus - - ./docker/monitoring/prometheus:/etc/prometheus:ro - command: - - '--config.file=/etc/prometheus/prometheus.yml' - - '--storage.tsdb.path=/prometheus' - - '--web.console.libraries=/etc/prometheus/console_libraries' - - '--web.console.templates=/etc/prometheus/consoles' - - '--storage.tsdb.retention.time=200h' - - '--web.enable-lifecycle' - networks: - - meldestelle-network - healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:9090/-/healthy"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 40s - restart: unless-stopped - - grafana: - profiles: ["monitoring"] - image: grafana/grafana:${DOCKER_GRAFANA_VERSION:-11.3.0} - container_name: meldestelle-grafana - environment: - GF_SECURITY_ADMIN_USER: ${GF_SECURITY_ADMIN_USER:-admin} - GF_SECURITY_ADMIN_PASSWORD: ${GF_SECURITY_ADMIN_PASSWORD:-admin} - GF_USERS_ALLOW_SIGN_UP: ${GF_USERS_ALLOW_SIGN_UP:-false} - GF_INSTALL_PLUGINS: grafana-piechart-panel - ports: - - "${GRAFANA_PORT:-3000}:3000" - volumes: - - grafana-data:/var/lib/grafana - - ./docker/monitoring/grafana:/etc/grafana/provisioning:ro - depends_on: - - prometheus - networks: - - meldestelle-network - healthcheck: - test: ["CMD", "curl", "--fail", "http://localhost:3000/api/health"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 40s - restart: unless-stopped - -# =================================================================== -# Volumes -# =================================================================== -volumes: - postgres-data: - driver: local - redis-data: - driver: local - prometheus-data: - driver: local - grafana-data: - driver: local - -# =================================================================== -# Networks -# =================================================================== -networks: - meldestelle-network: - driver: bridge diff --git a/_backup_chaos/events/README.md b/_backup_chaos/events/README.md deleted file mode 100644 index fe671c3d..00000000 --- a/_backup_chaos/events/README.md +++ /dev/null @@ -1 +0,0 @@ -# Events Module\n\nThis is a minimal placeholder README to satisfy documentation validation. See docs/index.md for project docs diff --git a/_backup_chaos/masterdata/README.md b/_backup_chaos/masterdata/README.md deleted file mode 100644 index 2cac59a4..00000000 --- a/_backup_chaos/masterdata/README.md +++ /dev/null @@ -1 +0,0 @@ -# Masterdata Module\n\nThis is a minimal placeholder README to satisfy documentation validation. See docs/index.md for project docs diff --git a/_backup_chaos/members/README.md b/_backup_chaos/members/README.md deleted file mode 100644 index 0e336b79..00000000 --- a/_backup_chaos/members/README.md +++ /dev/null @@ -1 +0,0 @@ -# Members Module\n\nThis is a minimal placeholder README to satisfy documentation validation. See docs/index.md for project docs diff --git a/_backup_chaos/secrets/README.md b/_backup_chaos/secrets/README.md deleted file mode 100644 index d50a04ac..00000000 --- a/_backup_chaos/secrets/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Docker Secrets (Development vs. Production) - -In der lokalen Entwicklung werden keine Docker-Secrets erzwungen. - -- Verwende für sensible Werte stattdessen die Datei `config/env/.env.local` (ist gitignored). -- Die Dateien in diesem Ordner sind lediglich Platzhalter und enthalten KEINE echten Geheimnisse. -- Für ein Deployment in Produktion kannst du diese Dateien mit echten Werten befüllen oder einen sicheren Secret-Store (Docker/K8s) verwenden. - -Hinweise: -- Postgres-User/Passwort haben in der lokalen Entwicklung Standard/Fallback-Werte via `docker-compose.yml` (Environment mit Defaults). -- Die optimierten Compose-Dateien (`*.optimized`) können weiterhin Docker-Secrets verwenden – diese sind für Prod gedacht. - -Schnellstart lokal (ohne Secrets): -- Passe `config/env/.env` und optional `config/env/.env.local` an -- Starte mit: `docker compose -f docker-compose.yml -f docker-compose.services.yml up` diff --git a/_backup_chaos/secrets/grafana_admin_password.txt b/_backup_chaos/secrets/grafana_admin_password.txt deleted file mode 100644 index e37f4acd..00000000 --- a/_backup_chaos/secrets/grafana_admin_password.txt +++ /dev/null @@ -1 +0,0 @@ -TiB6FRRYW4gjM7xie17mKtTYFOp \ No newline at end of file diff --git a/_backup_chaos/secrets/grafana_admin_user.txt b/_backup_chaos/secrets/grafana_admin_user.txt deleted file mode 100644 index f77b0040..00000000 --- a/_backup_chaos/secrets/grafana_admin_user.txt +++ /dev/null @@ -1 +0,0 @@ -admin \ No newline at end of file diff --git a/_backup_chaos/secrets/jwt_secret.txt b/_backup_chaos/secrets/jwt_secret.txt deleted file mode 100644 index 6c466b67..00000000 --- a/_backup_chaos/secrets/jwt_secret.txt +++ /dev/null @@ -1 +0,0 @@ -ba960b899f72d5ed192b5597d7f4b5b8853d9d641a2dc23c6b1a4b692b20211c \ No newline at end of file diff --git a/_backup_chaos/secrets/keycloak_admin_password.txt b/_backup_chaos/secrets/keycloak_admin_password.txt deleted file mode 100644 index d85823d0..00000000 --- a/_backup_chaos/secrets/keycloak_admin_password.txt +++ /dev/null @@ -1 +0,0 @@ -XASb7AzVy7G5fEKulE1mNPTy2Sw6pHi \ No newline at end of file diff --git a/_backup_chaos/secrets/keycloak_auth_client_secret.txt b/_backup_chaos/secrets/keycloak_auth_client_secret.txt deleted file mode 100644 index 24b090bc..00000000 --- a/_backup_chaos/secrets/keycloak_auth_client_secret.txt +++ /dev/null @@ -1 +0,0 @@ -s8N3r59JwS0lFsJobKWFJXh9qvdbHgcC6S3fYXYdXFM6eMKkRMtQbxHo0NJKFJC \ No newline at end of file diff --git a/_backup_chaos/secrets/keycloak_client_secret.txt b/_backup_chaos/secrets/keycloak_client_secret.txt deleted file mode 100644 index 9f2f28b1..00000000 --- a/_backup_chaos/secrets/keycloak_client_secret.txt +++ /dev/null @@ -1 +0,0 @@ -lRo7W15UNy60EFRlvk1XP99MmgrgK2Z97QK9btl9ZPVIVzWcY81Bebp9hpB \ No newline at end of file diff --git a/_backup_chaos/secrets/metrics_auth_password.txt b/_backup_chaos/secrets/metrics_auth_password.txt deleted file mode 100644 index 73e896b2..00000000 --- a/_backup_chaos/secrets/metrics_auth_password.txt +++ /dev/null @@ -1 +0,0 @@ -pON4NxxsKPWseVg1gw5PyLNN4YYrj8h \ No newline at end of file diff --git a/_backup_chaos/secrets/metrics_auth_username.txt b/_backup_chaos/secrets/metrics_auth_username.txt deleted file mode 100644 index 6f8aca1a..00000000 --- a/_backup_chaos/secrets/metrics_auth_username.txt +++ /dev/null @@ -1 +0,0 @@ -metrics \ No newline at end of file diff --git a/_backup_chaos/secrets/postgres_password.txt b/_backup_chaos/secrets/postgres_password.txt deleted file mode 100644 index a9a6cd11..00000000 --- a/_backup_chaos/secrets/postgres_password.txt +++ /dev/null @@ -1 +0,0 @@ -CHANGE_ME_LOCAL_DEV diff --git a/_backup_chaos/secrets/postgres_user.txt b/_backup_chaos/secrets/postgres_user.txt deleted file mode 100644 index 81559440..00000000 --- a/_backup_chaos/secrets/postgres_user.txt +++ /dev/null @@ -1 +0,0 @@ -meldestelle \ No newline at end of file diff --git a/_backup_chaos/secrets/redis_password.txt b/_backup_chaos/secrets/redis_password.txt deleted file mode 100644 index eaab894a..00000000 --- a/_backup_chaos/secrets/redis_password.txt +++ /dev/null @@ -1 +0,0 @@ -p701HhKOnZJ4zbY9dGRvyH9kQTKcsUm \ No newline at end of file diff --git a/_backup_chaos/secrets/setup-secrets.sh b/_backup_chaos/secrets/setup-secrets.sh deleted file mode 100755 index 919f0a3e..00000000 --- a/_backup_chaos/secrets/setup-secrets.sh +++ /dev/null @@ -1,345 +0,0 @@ -#!/bin/bash - -# =================================================================== -# Docker Secrets Setup Script - Meldestelle Project -# =================================================================== -# This script generates secure secrets for all Docker services -# Security Features: -# - Generates cryptographically secure random passwords -# - Creates JWT secrets with proper length for HMAC512 -# - Sets appropriate file permissions (600) for security -# - Provides backup functionality -# - Validates secret file creation -# =================================================================== - -set -euo pipefail - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Script directory -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -SECRETS_DIR="${SCRIPT_DIR}" - -# Logging function -log() { - echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" -} - -warn() { - echo -e "${YELLOW}[WARNING] $1${NC}" -} - -error() { - echo -e "${RED}[ERROR] $1${NC}" - exit 1 -} - -# Function to generate secure random password -generate_password() { - local length=${1:-32} - openssl rand -base64 $((length * 3 / 4)) | tr -d "=+/" | cut -c1-${length} -} - -# Function to generate JWT secret (64 characters for HMAC512) -generate_jwt_secret() { - openssl rand -hex 32 -} - -# Function to create secret file with proper permissions -create_secret_file() { - local filename="$1" - local content="$2" - local filepath="${SECRETS_DIR}/${filename}" - - # Check if file already exists - if [[ -f "$filepath" ]]; then - warn "Secret file $filename already exists. Use --force to overwrite." - return 1 - fi - - # Create the secret file - echo -n "$content" > "$filepath" - chmod 600 "$filepath" - - log "Created secret file: $filename" - return 0 -} - -# Function to backup existing secrets -backup_secrets() { - local backup_dir="${SECRETS_DIR}/backup_$(date +%Y%m%d_%H%M%S)" - - if find "$SECRETS_DIR" -name "*.txt" -type f | grep -q .; then - log "Creating backup of existing secrets..." - mkdir -p "$backup_dir" - find "$SECRETS_DIR" -name "*.txt" -type f -exec cp {} "$backup_dir/" \; - log "Backup created in: $backup_dir" - fi -} - -# Function to validate secret file -validate_secret_file() { - local filepath="$1" - local min_length="$2" - - if [[ ! -f "$filepath" ]]; then - error "Secret file does not exist: $filepath" - fi - - local content_length=$(wc -c < "$filepath") - if [[ $content_length -lt $min_length ]]; then - error "Secret file $filepath is too short (${content_length} < ${min_length})" - fi - - local permissions=$(stat -c %a "$filepath") - if [[ "$permissions" != "600" ]]; then - warn "Secret file $filepath has incorrect permissions: $permissions (should be 600)" - chmod 600 "$filepath" - fi -} - -# Function to generate all secrets -generate_all_secrets() { - local force_overwrite=${1:-false} - - log "Starting secret generation for Meldestelle Docker infrastructure..." - - # Create backup if not forcing overwrite - if [[ "$force_overwrite" != "true" ]]; then - backup_secrets - fi - - # Database secrets - log "Generating database secrets..." - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/postgres_user.txt" ]]; then - create_secret_file "postgres_user.txt" "meldestelle" - fi - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/postgres_password.txt" ]]; then - create_secret_file "postgres_password.txt" "$(generate_password 32)" - fi - - # Redis secrets - log "Generating Redis secrets..." - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/redis_password.txt" ]]; then - create_secret_file "redis_password.txt" "$(generate_password 32)" - fi - - # Keycloak secrets - log "Generating Keycloak secrets..." - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/keycloak_admin_password.txt" ]]; then - create_secret_file "keycloak_admin_password.txt" "$(generate_password 32)" - fi - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/keycloak_client_secret.txt" ]]; then - create_secret_file "keycloak_client_secret.txt" "$(generate_password 64)" - fi - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/keycloak_auth_client_secret.txt" ]]; then - create_secret_file "keycloak_auth_client_secret.txt" "$(generate_password 64)" - fi - - # Grafana secrets - log "Generating Grafana secrets..." - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/grafana_admin_user.txt" ]]; then - create_secret_file "grafana_admin_user.txt" "admin" - fi - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/grafana_admin_password.txt" ]]; then - create_secret_file "grafana_admin_password.txt" "$(generate_password 32)" - fi - - # JWT secrets - log "Generating JWT secrets..." - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/jwt_secret.txt" ]]; then - create_secret_file "jwt_secret.txt" "$(generate_jwt_secret)" - fi - - # VNC secrets (for desktop app) - log "Generating VNC secrets..." - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/vnc_password.txt" ]]; then - create_secret_file "vnc_password.txt" "$(generate_password 16)" - fi - - # Monitoring secrets - log "Generating monitoring secrets..." - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/metrics_auth_username.txt" ]]; then - create_secret_file "metrics_auth_username.txt" "metrics" - fi - if [[ "$force_overwrite" == "true" ]] || ! [[ -f "${SECRETS_DIR}/metrics_auth_password.txt" ]]; then - create_secret_file "metrics_auth_password.txt" "$(generate_password 32)" - fi - - log "Secret generation completed successfully!" -} - -# Function to validate all secrets -validate_all_secrets() { - log "Validating all secret files..." - - # Define expected secrets with minimum lengths - declare -A secrets=( - ["postgres_user.txt"]=8 - ["postgres_password.txt"]=16 - ["redis_password.txt"]=16 - ["keycloak_admin_password.txt"]=16 - ["keycloak_client_secret.txt"]=32 - ["keycloak_auth_client_secret.txt"]=32 - ["grafana_admin_user.txt"]=4 - ["grafana_admin_password.txt"]=16 - ["jwt_secret.txt"]=64 - ["vnc_password.txt"]=8 - ["metrics_auth_username.txt"]=4 - ["metrics_auth_password.txt"]=16 - ) - - local all_valid=true - for secret_file in "${!secrets[@]}"; do - local filepath="${SECRETS_DIR}/${secret_file}" - local min_length=${secrets[$secret_file]} - - if validate_secret_file "$filepath" "$min_length" 2>/dev/null; then - log "✓ $secret_file is valid" - else - error "✗ $secret_file is invalid or missing" - all_valid=false - fi - done - - if [[ "$all_valid" == "true" ]]; then - log "All secret files are valid and properly secured!" - else - error "Some secret files are invalid. Please regenerate secrets." - fi -} - -# Function to create Docker secrets -create_docker_secrets() { - log "Creating Docker secrets..." - - # Get the project name (directory name) - local project_name=$(basename "$(dirname "$(dirname "$SCRIPT_DIR")")") - - # Define secrets to create - declare -A docker_secrets=( - ["postgres_user"]="postgres_user.txt" - ["postgres_password"]="postgres_password.txt" - ["redis_password"]="redis_password.txt" - ["keycloak_admin_password"]="keycloak_admin_password.txt" - ["keycloak_client_secret"]="keycloak_client_secret.txt" - ["grafana_admin_user"]="grafana_admin_user.txt" - ["grafana_admin_password"]="grafana_admin_password.txt" - ["jwt_secret"]="jwt_secret.txt" - ) - - for secret_name in "${!docker_secrets[@]}"; do - local secret_file="${docker_secrets[$secret_name]}" - local filepath="${SECRETS_DIR}/${secret_file}" - local docker_secret_name="${project_name}_${secret_name}" - - # Check if Docker secret already exists - if docker secret ls --format "{{.Name}}" | grep -q "^${docker_secret_name}$"; then - warn "Docker secret $docker_secret_name already exists" - else - # Create Docker secret - if docker secret create "$docker_secret_name" "$filepath"; then - log "Created Docker secret: $docker_secret_name" - else - error "Failed to create Docker secret: $docker_secret_name" - fi - fi - done -} - -# Function to show usage -show_usage() { - echo "Usage: $0 [OPTIONS]" - echo "" - echo "Options:" - echo " --help Show this help message" - echo " --generate Generate all secret files (default)" - echo " --force Force overwrite existing secret files" - echo " --validate Validate existing secret files" - echo " --docker-secrets Create Docker secrets from files" - echo " --all Generate files, validate, and create Docker secrets" - echo "" - echo "Examples:" - echo " $0 # Generate secrets (skip existing files)" - echo " $0 --force # Generate secrets (overwrite existing files)" - echo " $0 --validate # Validate existing secret files" - echo " $0 --all # Complete setup (generate, validate, docker secrets)" -} - -# Main execution -main() { - local action="generate" - local force_overwrite=false - - # Check dependencies - if ! command -v openssl &> /dev/null; then - error "openssl is required but not installed" - fi - - # Parse command line arguments - while [[ $# -gt 0 ]]; do - case $1 in - --help) - show_usage - exit 0 - ;; - --generate) - action="generate" - shift - ;; - --force) - force_overwrite=true - shift - ;; - --validate) - action="validate" - shift - ;; - --docker-secrets) - action="docker-secrets" - shift - ;; - --all) - action="all" - shift - ;; - *) - error "Unknown option: $1" - ;; - esac - done - - # Ensure secrets directory exists - mkdir -p "$SECRETS_DIR" - - # Execute requested action - case $action in - "generate") - generate_all_secrets "$force_overwrite" - ;; - "validate") - validate_all_secrets - ;; - "docker-secrets") - create_docker_secrets - ;; - "all") - generate_all_secrets "$force_overwrite" - validate_all_secrets - create_docker_secrets - ;; - *) - error "Invalid action: $action" - ;; - esac - - log "Operation completed successfully!" -} - -# Run main function with all arguments -main "$@" diff --git a/_backup_chaos/secrets/vnc_password.txt b/_backup_chaos/secrets/vnc_password.txt deleted file mode 100644 index 3fbc6e46..00000000 --- a/_backup_chaos/secrets/vnc_password.txt +++ /dev/null @@ -1 +0,0 @@ -nrscAXfIoOKTAEt \ No newline at end of file diff --git a/_backup_chaos/versions.toml.bak b/_backup_chaos/versions.toml.bak deleted file mode 100644 index 30d81e3d..00000000 --- a/_backup_chaos/versions.toml.bak +++ /dev/null @@ -1,192 +0,0 @@ -# =================================================================== -# Docker Versions Catalog - Single Source of Truth -# Analogous to gradle/libs.versions.toml for centralized version management -# =================================================================== -# Last updated: 2025-09-13 -# Eliminates version redundancy across 12+ Dockerfiles - -[versions] -# --- Build Tools --- -gradle = "9.1.0" -java = "21" -node = "22.21.0" - -# --- Base Images --- -nginx = "1.25-alpine" -alpine = "3.19" -eclipse-temurin-jdk = "21-jdk-alpine" -eclipse-temurin-jre = "21-jre-alpine" - -# --- Monitoring & Infrastructure Services --- -prometheus = "v2.54.1" -grafana = "11.3.0" -keycloak = "26.0.7" - -# --- Spring Configuration --- -spring-profiles-default = "default" -spring-profiles-docker = "docker" -spring-profiles-prod = "prod" - -# --- Application Versions --- -app-version = "1.0.0" - -# --- Zentrale Port-Verwaltung --- -# Single Source of Truth für alle Service-Ports - -[service-ports] -# --- Infrastructure Services --- -api-gateway = 8081 -auth-server = 8087 -monitoring-server = 8088 - -# --- Application Services --- -ping-service = 8082 -members-service = 8083 -horses-service = 8084 -events-service = 8085 -masterdata-service = 8086 - -# --- External Services --- -postgres = 5432 -redis = 6379 -keycloak = 8180 -consul = 8500 -zookeeper = 2181 -kafka = 9092 - -# --- Monitoring Stack --- -prometheus = 9090 -grafana = 3000 - -# --- Client Applications --- -web-app = 4000 -desktop-app-vnc = 5901 -desktop-app-novnc = 6080 - -[port-ranges] -# --- Port-Range-Definitionen für automatische Port-Zuweisung --- -infrastructure = "8081-8088" -services = "8082-8099" -monitoring = "9090-9099" -clients = "4000-4099" -vnc = "5901-5999" -debug = "5005-5009" - -# --- Reserved Port Ranges --- -system-reserved = "0-1023" -ephemeral = "32768-65535" - -[build-args] -# --- Global Build Arguments (used across all categories) --- -global = [ - "GRADLE_VERSION", - "JAVA_VERSION", - "BUILD_DATE", - "VERSION" -] - -# --- Spring Boot Services (dockerfiles/services/* and infrastructure/*) --- -spring-services = [ - "SPRING_PROFILES_ACTIVE", - "SERVICE_PATH", - "SERVICE_NAME", - "SERVICE_PORT" -] - -# --- Kotlin/JS Web Clients (dockerfiles/clients/*) --- -web-clients = [ - "NODE_VERSION", - "NGINX_VERSION", - "CLIENT_PATH", - "CLIENT_MODULE", - "CLIENT_NAME" -] - -[categories] -# --- Services Configuration --- -[categories.services] -default-spring-profile = "docker" -default-port-start = 8082 -services = [ - "ping-service", - "members-service", - "horses-service", - "events-service", - "masterdata-service" -] - -# --- Infrastructure Configuration --- -[categories.infrastructure] -default-spring-profile = "default" -services = [ - "gateway", - "auth-server", - "monitoring-server" -] - -# --- Client Applications Configuration --- -[categories.clients] -default-node-version = "20.11.0" -default-nginx-version = "1.25-alpine" -clients = [ - "web-app", - "desktop-app" -] - -[environment-mapping] -# --- Environment Variable Names for Docker Compose --- -# Maps internal version names to environment variable names -gradle-version = "DOCKER_GRADLE_VERSION" -java-version = "DOCKER_JAVA_VERSION" -node-version = "DOCKER_NODE_VERSION" -nginx-version = "DOCKER_NGINX_VERSION" -prometheus-version = "DOCKER_PROMETHEUS_VERSION" -grafana-version = "DOCKER_GRAFANA_VERSION" -keycloak-version = "DOCKER_KEYCLOAK_VERSION" -spring-profiles-default = "DOCKER_SPRING_PROFILES_DEFAULT" -spring-profiles-docker = "DOCKER_SPRING_PROFILES_DOCKER" -app-version = "DOCKER_APP_VERSION" - -[environments] -# --- Environment-spezifische Konfigurationen --- -# Zentrale Verwaltung für dev/test/prod Umgebungen - -[environments.development] -spring-profiles = "dev" -debug-enabled = true -log-level = "DEBUG" -health-check-interval = "30s" -health-check-timeout = "5s" -health-check-retries = 3 -health-check-start-period = "40s" -resource-limits = false -jvm-debug-port = 5005 -hot-reload = true - -[environments.production] -spring-profiles = "prod" -debug-enabled = false -log-level = "INFO" -health-check-interval = "15s" -health-check-timeout = "3s" -health-check-retries = 3 -health-check-start-period = "30s" -resource-limits = true -jvm-debug-port = false -hot-reload = false -security-headers = true -tls-enabled = true - -[environments.testing] -spring-profiles = "test" -debug-enabled = true -log-level = "DEBUG" -health-check-interval = "10s" -health-check-timeout = "5s" -health-check-retries = 2 -health-check-start-period = "20s" -resource-limits = false -jvm-debug-port = 5005 -hot-reload = false -ephemeral-storage = true -test-containers = true diff --git a/backend/README.md b/backend/README.md deleted file mode 100644 index 1e834ba3..00000000 --- a/backend/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Backend - -Domänenspezifische Services und Gateway. - -- gateway: API Gateway/Auth/Routing -- discovery: Service Registry/Discovery (optional) -- services: Microservices, pro Domäne ein Service diff --git a/backend/gateway/gateway/CONFIGURATION.md b/backend/gateway/gateway/CONFIGURATION.md deleted file mode 100644 index 62373426..00000000 --- a/backend/gateway/gateway/CONFIGURATION.md +++ /dev/null @@ -1,733 +0,0 @@ -# Gateway Configuration Documentation - -## Überblick - -Dieses Dokument beschreibt alle zentralen Konfigurationseigenschaften für das API Gateway. Die Konfiguration erfolgt über die `application.yml` Datei und kann durch Umgebungsvariablen überschrieben werden. - -## Table of Contents - -- [Server Configuration](#server-configuration) -- [Spring Application](#spring-application) -- [Consul Service Discovery](#consul-service-discovery) -- [Spring Cloud Gateway](#spring-cloud-gateway) -- [Circuit Breaker (Resilience4j)](#circuit-breaker-resilience4j) -- [Management & Monitoring](#management--monitoring) -- [Security](#security) -- [Logging](#logging) - ---- - -## Server Configuration - -### server.port - -- **Typ**: Integer -- **Default**: 8081 -- **Environment Variable**: `GATEWAY_PORT` -- **Beschreibung**: Port, auf dem das Gateway läuft - -### server.netty.connection-timeout - -- **Typ**: Duration -- **Default**: 5s -- **Beschreibung**: Timeout für initiale TCP-Verbindungen - -### server.netty.idle-timeout - -- **Typ**: Duration -- **Default**: 15s -- **Beschreibung**: Timeout für inaktive Verbindungen - -**Beispiel:** - -```yaml -server: - port: 8081 - netty: - connection-timeout: 5s - idle-timeout: 15s -``` - ---- - -## Spring Application - -### spring.application.name - -- **Typ**: String -- **Default**: api-gateway -- **Beschreibung**: Name der Anwendung, wird in Consul und Logs verwendet - -### spring.profiles.active - -- **Typ**: String -- **Default**: dev -- **Environment Variable**: `SPRING_PROFILES_ACTIVE` -- **Beschreibung**: Aktives Spring-Profil (dev, test, prod) -- **Mögliche Werte**: dev, test, staging, prod - -### spring.security.user.name / password - -- **Typ**: String -- **Default**: admin / admin -- **Environment Variables**: `GATEWAY_ADMIN_USER`, `GATEWAY_ADMIN_PASSWORD` -- **Beschreibung**: Basic Auth für administrative Endpunkte -- **⚠️ Wichtig**: In Produktion durch sichere Werte ersetzen! - -**Beispiel:** - -```yaml -spring: - application: - name: api-gateway - profiles: - active: ${SPRING_PROFILES_ACTIVE:dev} - security: - user: - name: ${GATEWAY_ADMIN_USER:admin} - password: ${GATEWAY_ADMIN_PASSWORD:admin} -``` - ---- - -## Consul Service Discovery - -### spring.cloud.consul.host - -- **Typ**: String -- **Default**: localhost -- **Environment Variable**: `CONSUL_HOST` -- **Beschreibung**: Hostname des Consul-Servers - -### spring.cloud.consul.port - -- **Typ**: Integer -- **Default**: 8500 -- **Environment Variable**: `CONSUL_PORT` -- **Beschreibung**: Port des Consul-Servers - -### spring.cloud.consul.enabled - -- **Typ**: Boolean -- **Default**: true -- **Environment Variable**: `CONSUL_ENABLED` -- **Beschreibung**: Aktiviert/Deaktiviert Consul Integration - -### spring.cloud.consul.discovery.enabled - -- **Typ**: Boolean -- **Default**: true -- **Environment Variable**: `CONSUL_ENABLED` -- **Beschreibung**: Aktiviert Service Discovery - -### spring.cloud.consul.discovery.register - -- **Typ**: Boolean -- **Default**: true -- **Environment Variable**: `CONSUL_ENABLED` -- **Beschreibung**: Registriert das Gateway in Consul - -### spring.cloud.consul.discovery.health-check-path - -- **Typ**: String -- **Default**: /actuator/health -- **Beschreibung**: Pfad für Consul Health Checks - -### spring.cloud.consul.discovery.health-check-interval - -- **Typ**: Duration -- **Default**: 10s -- **Beschreibung**: Intervall für Health Checks - -### spring.cloud.consul.discovery.instance-id - -- **Typ**: String -- **Default**: ${spring.application.name}-${server.port}-${random.uuid} -- **Beschreibung**: Eindeutige Instanz-ID für Service Discovery - -**Beispiel:** - -```yaml -spring: - cloud: - consul: - host: ${CONSUL_HOST:localhost} - port: ${CONSUL_PORT:8500} - enabled: ${CONSUL_ENABLED:true} - discovery: - enabled: ${CONSUL_ENABLED:true} - register: ${CONSUL_ENABLED:true} - health-check-path: /actuator/health - health-check-interval: 10s - instance-id: ${spring.application.name}-${server.port}-${random.uuid} -``` - ---- - -## Spring Cloud Gateway - -### Verbindungskonfiguration - -#### spring.cloud.gateway.server.webflux.httpclient.connect-timeout - -- **Typ**: Integer (Millisekunden) -- **Default**: 5000 -- **Beschreibung**: Timeout für Backend-Verbindungen - -#### spring.cloud.gateway.server.webflux.httpclient.response-timeout - -- **Typ**: Duration -- **Default**: 30s -- **Beschreibung**: Timeout für Backend-Responses - -#### spring.cloud.gateway.server.webflux.httpclient.pool.max-idle-time - -- **Typ**: Duration -- **Default**: 15s -- **Beschreibung**: Max. Idle-Zeit für Verbindungen im Pool - -#### spring.cloud.gateway.server.webflux.httpclient.pool.max-life-time - -- **Typ**: Duration -- **Default**: 60s -- **Beschreibung**: Max. Lebensdauer einer Verbindung - -**Beispiel:** - -```yaml -spring: - cloud: - gateway: - server: - webflux: - httpclient: - connect-timeout: 5000 - response-timeout: 30s - pool: - max-idle-time: 15s - max-life-time: 60s -``` - -### Default Filters - -Diese Filter werden auf **alle** Routen angewendet: - -1. **DedupeResponseHeader**: Entfernt doppelte CORS-Header -2. **CircuitBreaker**: Default Circuit Breaker mit Fallback -3. **Retry**: Automatische Wiederholung bei Fehlern -4. **Security Headers**: X-Content-Type-Options, X-Frame-Options, X-XSS-Protection, etc. -5. **Cache-Control**: No-cache Header für alle Responses - -**Beispiel:** - -```yaml -spring: - cloud: - gateway: - default-filters: - - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin - - name: CircuitBreaker - args: - name: defaultCircuitBreaker - fallbackUri: forward:/fallback - - name: Retry - args: - retries: 3 - statuses: BAD_GATEWAY,GATEWAY_TIMEOUT - methods: GET,POST,PUT,DELETE - backoff: - firstBackoff: 50ms - maxBackoff: 500ms - factor: 2 -``` - -### Routes - -Das Gateway definiert folgende Service-Routen: - -#### 1. Members Service Route - -- **Path**: `/api/members/**` -- **Service**: members-service (via Consul) -- **Circuit Breaker**: membersCircuitBreaker -- **Fallback**: /fallback/members - -#### 2. Horses Service Route - -- **Path**: `/api/horses/**` -- **Service**: horses-service (via Consul) -- **Circuit Breaker**: horsesCircuitBreaker -- **Fallback**: /fallback/horses - -#### 3. Events Service Route - -- **Path**: `/api/events/**` -- **Service**: events-service (via Consul) -- **Circuit Breaker**: eventsCircuitBreaker -- **Fallback**: /fallback/events - -#### 4. Masterdata Service Route - -- **Path**: `/api/masterdata/**` -- **Service**: masterdata-service (via Consul) -- **Circuit Breaker**: masterdataCircuitBreaker -- **Fallback**: /fallback/masterdata - -#### 5. Auth Service Route - -- **Path**: `/api/auth/**` -- **Service**: auth-service (via Consul) -- **Circuit Breaker**: authCircuitBreaker -- **Fallback**: /fallback/auth - -#### 6. Ping Service Route - -- **Path**: `/api/ping/**` -- **Service**: ping-service (via Consul) -- **No Circuit Breaker**: Optional service - -**Beispiel einer Route:** - -```yaml -spring: - cloud: - gateway: - routes: - - id: members-service-route - uri: lb://members-service # lb = Load Balanced via Consul - predicates: - - Path=/api/members/** - filters: - - StripPrefix=1 # Entfernt /api vom Pfad - - name: CircuitBreaker - args: - name: membersCircuitBreaker - fallbackUri: forward:/fallback/members -``` - ---- - -## Circuit Breaker (Resilience4j) - -### Default Konfiguration - -#### resilience4j.circuitbreaker.configs.default.registerHealthIndicator - -- **Typ**: Boolean -- **Default**: true -- **Beschreibung**: Registriert Circuit Breaker im Health Endpoint - -#### resilience4j.circuitbreaker.configs.default.slidingWindowSize - -- **Typ**: Integer -- **Default**: 100 -- **Beschreibung**: Größe des Sliding Window für Fehlerrate-Berechnung - -#### resilience4j.circuitbreaker.configs.default.minimumNumberOfCalls - -- **Typ**: Integer -- **Default**: 20 -- **Beschreibung**: Mindestanzahl an Calls bevor Circuit Breaker aktiviert wird - -#### resilience4j.circuitbreaker.configs.default.permittedNumberOfCallsInHalfOpenState - -- **Typ**: Integer -- **Default**: 3 -- **Beschreibung**: Anzahl Test-Calls im Half-Open State - -#### resilience4j.circuitbreaker.configs.default.waitDurationInOpenState - -- **Typ**: Duration -- **Default**: 5s -- **Beschreibung**: Wartezeit bevor von Open zu Half-Open gewechselt wird - -#### resilience4j.circuitbreaker.configs.default.failureRateThreshold - -- **Typ**: Integer (Prozent) -- **Default**: 50 -- **Beschreibung**: Fehlerrate-Schwelle für Circuit Breaker Aktivierung - -### Service-spezifische Circuit Breaker - -Jeder Service hat einen eigenen Circuit Breaker mit angepasster Konfiguration: - -| Service | Sliding Window | Failure Threshold | Besonderheit | -|---------|---------------|-------------------|--------------| -| members-service | 50 | 50% | Standard | -| horses-service | 50 | 50% | Standard | -| events-service | 75 | 50% | Größeres Window | -| masterdata-service | 30 | 50% | Kleineres Window | -| auth-service | 20 | 30% | Sensitiverer Threshold | - -**Beispiel:** - -```yaml -resilience4j: - circuitbreaker: - instances: - authCircuitBreaker: - baseConfig: default - slidingWindowSize: 20 - failureRateThreshold: 30 # Auth ist kritisch -> niedrigerer Threshold -``` - ---- - -## Management & Monitoring - -### Exposed Endpoints - -#### management.endpoints.web.exposure.include - -- **Typ**: Comma-separated String -- **Default**: health,info,metrics,prometheus,gateway,circuitbreakers -- **Beschreibung**: Öffentlich verfügbare Actuator Endpoints - -**Verfügbare Endpoints:** - -- `/actuator/health` - Service Health Status -- `/actuator/info` - Service Informationen -- `/actuator/metrics` - Micrometer Metriken -- `/actuator/prometheus` - Prometheus Scrape Endpoint -- `/actuator/gateway` - Gateway Routes & Filters -- `/actuator/circuitbreakers` - Circuit Breaker Status - -### Health Endpoint - -#### management.endpoint.health.show-details - -- **Typ**: String -- **Default**: always -- **Mögliche Werte**: never, when-authorized, always -- **Beschreibung**: Zeigt detaillierte Health-Informationen - -#### management.endpoint.health.show-components - -- **Typ**: Boolean -- **Default**: always -- **Beschreibung**: Zeigt Health-Komponenten - -#### management.endpoint.health.probes.enabled - -- **Typ**: Boolean -- **Default**: true -- **Beschreibung**: Aktiviert Kubernetes Liveness/Readiness Probes - -### Metrics - -#### management.metrics.tags - -- **Beschreibung**: Globale Tags für alle Metriken -- **Standard Tags**: - - application: ${spring.application.name} - - environment: ${spring.profiles.active} - - instance: ${spring.cloud.consul.discovery.instance-id} - - service: gateway - - component: infrastructure - - gateway: api-gateway - -#### management.metrics.distribution.percentiles-histogram.http.server.requests - -- **Typ**: Boolean -- **Default**: true -- **Beschreibung**: Aktiviert Histogram für Request-Zeiten - -#### management.metrics.distribution.percentiles.http.server.requests - -- **Typ**: Array[Double] -- **Default**: [0.5, 0.90, 0.95, 0.99] -- **Beschreibung**: Percentile-Werte für Request-Zeiten - -### Tracing - -#### management.tracing.enabled - -- **Typ**: Boolean -- **Default**: false -- **Environment Variable**: `TRACING_ENABLED` -- **Beschreibung**: Aktiviert Distributed Tracing - -#### management.tracing.sampling.probability - -- **Typ**: Double (0.0 - 1.0) -- **Default**: 1.0 -- **Environment Variable**: `TRACING_SAMPLING_PROBABILITY` -- **Beschreibung**: Sampling-Rate für Traces (1.0 = 100%) - -#### management.zipkin.tracing.endpoint - -- **Typ**: URL -- **Default**: -- **Environment Variable**: `ZIPKIN_TRACING_ENDPOINT` -- **Beschreibung**: Zipkin Server URL - -**Beispiel:** - -```yaml -management: - endpoints: - web: - exposure: - include: health,info,metrics,prometheus,gateway,circuitbreakers - endpoint: - health: - show-details: always - probes: - enabled: true - tracing: - enabled: ${TRACING_ENABLED:false} - sampling: - probability: ${TRACING_SAMPLING_PROBABILITY:1.0} - zipkin: - tracing: - endpoint: ${ZIPKIN_TRACING_ENDPOINT:http://localhost:9411/api/v2/spans} -``` - ---- - -## Security - -Die Security-Konfiguration erfolgt über Custom Properties unter `gateway.security`: - -### gateway.security.publicPaths - -- **Typ**: Array[String] -- **Default**: ["/", "/fallback/**", "/actuator/**", "/webjars/**", "/v3/api-docs/**", "/api/auth/**"] -- **Beschreibung**: Pfade, die ohne Authentifizierung zugänglich sind - -### gateway.security.cors.allowedOriginPatterns - -- **Typ**: Array[String] -- **Default**: ["http://localhost:[*]", "https://*.meldestelle.at"] -- **Beschreibung**: Erlaubte Origin-Patterns für CORS - -### gateway.security.cors.allowedMethods - -- **Typ**: Array[String] -- **Default**: ["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"] -- **Beschreibung**: Erlaubte HTTP-Methoden - -### gateway.security.cors.allowedHeaders - -- **Typ**: Array[String] -- **Default**: ["*"] -- **Beschreibung**: Erlaubte Request-Headers - -### gateway.security.cors.exposedHeaders - -- **Typ**: Array[String] -- **Default**: ["X-Correlation-ID", "X-RateLimit-Limit", "X-RateLimit-Remaining"] -- **Beschreibung**: Headers die an Client exponiert werden - -### gateway.security.cors.allowCredentials - -- **Typ**: Boolean -- **Default**: true -- **Beschreibung**: Erlaubt Credentials (Cookies, Auth-Header) - -### gateway.security.cors.maxAge - -- **Typ**: Duration -- **Default**: 1h -- **Beschreibung**: Cache-Zeit für CORS Preflight-Requests - -**Beispiel:** - -```yaml -gateway: - security: - publicPaths: - - "/" - - "/actuator/**" - - "/api/auth/**" - cors: - allowedOriginPatterns: - - "http://localhost:[*]" - - "https://*.meldestelle.at" - allowedMethods: - - GET - - POST - - PUT - - DELETE - allowCredentials: true - maxAge: 1h -``` - -### JWT Configuration - -#### spring.security.oauth2.resourceserver.jwt.jwk-set-uri - -- **Typ**: URL -- **Environment Variable**: `KEYCLOAK_JWK_SET_URI` -- **Beschreibung**: Keycloak JWK Set URI für JWT-Validierung -- **Beispiel**: - ---- - -## Logging - -### logging.level - -- **Beschreibung**: Log-Level für verschiedene Pakete - -**Standard Log-Levels:** - -- `org.springframework.cloud.gateway`: INFO -- `org.springframework.cloud.loadbalancer`: DEBUG -- `org.springframework.cloud.consul`: INFO -- `at.mocode.infrastructure.gateway`: DEBUG -- `io.github.resilience4j`: INFO -- `reactor.netty.http.client`: INFO -- `org.springframework.security`: WARN -- `org.springframework.web`: INFO - -### logging.pattern.console - -- **Beschreibung**: Console-Log-Pattern mit Farben und Correlation-ID - -### logging.pattern.file - -- **Beschreibung**: File-Log-Pattern ohne Farben - -### logging.file.name - -- **Typ**: String -- **Default**: infrastructure/gateway/logs/gateway.log -- **Beschreibung**: Log-Datei Pfad - -### logging.logback.rollingpolicy - -- **clean-history-on-start**: true -- **max-file-size**: 100MB -- **total-size-cap**: 1GB -- **max-history**: 30 (Tage) - -**Beispiel:** - -```yaml -logging: - level: - at.mocode.infrastructure.gateway: DEBUG - org.springframework.cloud.gateway: INFO - file: - name: infrastructure/gateway/logs/gateway.log - logback: - rollingpolicy: - max-file-size: 100MB - max-history: 30 -``` - ---- - -## Umgebungsvariablen Übersicht - -### Kritische Variablen für Produktion - -| Variable | Beschreibung | Default | -|----------|--------------|---------| -| `GATEWAY_PORT` | Gateway Port | 8081 | -| `CONSUL_HOST` | Consul Server | localhost | -| `CONSUL_PORT` | Consul Port | 8500 | -| `CONSUL_ENABLED` | Consul Aktivieren | true | -| `GATEWAY_ADMIN_USER` | Admin Username | admin | -| `GATEWAY_ADMIN_PASSWORD` | Admin Password | admin | -| `KEYCLOAK_JWK_SET_URI` | Keycloak JWK URI | ... | -| `TRACING_ENABLED` | Tracing aktivieren | false | -| `ZIPKIN_TRACING_ENDPOINT` | Zipkin Server | ... | -| `SPRING_PROFILES_ACTIVE` | Spring Profil | dev | - ---- - -## Profile-spezifische Konfiguration - -Das Gateway unterstützt verschiedene Spring Profile: - -### dev (Development) - -- Detailliertes Logging -- Alle Monitoring-Endpunkte verfügbar -- Tracing optional - -### test - -- Reduziertes Logging -- Test-spezifische Timeouts -- In-Memory Services optional - -### prod (Production) - -- Production-ready Logging -- Sichere Credentials erforderlich -- Tracing empfohlen -- Rate Limiting aktiviert - -**Beispiel für profile-spezifische Datei:** - -```yaml -# application-prod.yml -spring: - security: - user: - name: ${GATEWAY_ADMIN_USER} # Muss gesetzt sein! - password: ${GATEWAY_ADMIN_PASSWORD} # Muss gesetzt sein! - -management: - tracing: - enabled: true - sampling: - probability: 0.1 # 10% Sampling in Production - -logging: - level: - at.mocode.infrastructure.gateway: INFO # Weniger Logs -``` - ---- - -## Best Practices - -1. **Umgebungsvariablen verwenden**: Nie Credentials in application.yml hardcoden -2. **Profile nutzen**: Separate Konfigurationen für dev/test/prod -3. **Health Checks aktivieren**: Für Consul und Kubernetes -4. **Tracing in Production**: Mindestens 10% Sampling -5. **Monitoring exportieren**: Prometheus-Endpunkt für Grafana -6. **Circuit Breaker tunen**: An Service-Charakteristiken anpassen -7. **CORS restriktiv**: Nur benötigte Origins erlauben -8. **Log Rotation**: Verhindert volle Festplatten - ---- - -## Troubleshooting - -### Gateway startet nicht - -- ✅ Prüfen: Consul erreichbar? -- ✅ Prüfen: Port 8081 frei? -- ✅ Prüfen: Keycloak erreichbar? (Optional) - -### Service nicht erreichbar - -- ✅ Prüfen: Service in Consul registriert? -- ✅ Prüfen: Circuit Breaker offen? -- ✅ Prüfen: Health Check erfolgreich? - -### CORS-Fehler - -- ✅ Prüfen: Origin in allowedOriginPatterns? -- ✅ Prüfen: Methode in allowedMethods? -- ✅ Prüfen: allowCredentials korrekt? - -### Hohe Latenz - -- ✅ Prüfen: response-timeout zu hoch? -- ✅ Prüfen: Backend-Services langsam? -- ✅ Prüfen: Connection Pool ausgeschöpft? - ---- - -## Weitere Ressourcen - -- [Gateway README](README-INFRA-GATEWAY.md) -- [Spring Cloud Gateway Dokumentation](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/) -- [Resilience4j Dokumentation](https://resilience4j.readme.io/) -- [Consul Dokumentation](https://www.consul.io/docs) diff --git a/backend/gateway/gateway/README-INFRA-GATEWAY.md b/backend/gateway/gateway/README-INFRA-GATEWAY.md deleted file mode 100644 index b6515d39..00000000 --- a/backend/gateway/gateway/README-INFRA-GATEWAY.md +++ /dev/null @@ -1,442 +0,0 @@ -# Infrastructure/Gateway Module - Comprehensive Documentation - -## Überblick - -Das API-Gateway ist der zentrale und einzige öffentliche Einstiegspunkt für alle Anfragen von externen Clients (z.B. Web-Anwendung, Desktop-Anwendung, mobile Apps) an das Meldestelle-System. Es fungiert als "Pförtner" für die gesamte Microservice-Landschaft und wurde zu einem vollwertigen, produktionstauglichen API Gateway mit modernen Best Practices erweitert. - -**Wichtiger Grundsatz**: Kein externer Client sollte jemals direkt mit einem internen Microservice kommunizieren. Alle Anfragen laufen über das Gateway. - -## Architektur und Technologie - -Das Gateway ist als eigenständiger Spring Boot Service implementiert und nutzt Spring Cloud Gateway als technologische Grundlage. Spring Cloud Gateway ist ein reaktives, nicht-blockierendes Framework, das sich nahtlos in das Spring-Ökosystem integriert. - -### Technologie-Stack - -- **Spring Boot 3.x** - Moderne Spring Boot Anwendung -- **Spring Cloud Gateway** - Reaktives Gateway Framework -- **Spring WebFlux** - Reaktive Web-Programmierung mit Netty -- **Resilience4j** - Circuit Breaker Pattern Implementation -- **Consul** - Service Discovery und Health Checks -- **Micrometer + Prometheus** - Umfassende Metriken und Monitoring -- **JWT** - Token-basierte Authentifizierung -- **Reactive Streams** - Non-blocking I/O für optimale Performance - -## Hauptverantwortlichkeiten - -Das Gateway handhabt alle Cross-Cutting Concerns (übergreifende Belange), die für mehrere oder alle Microservices gelten und entlastet damit die Fach-Services von technischen Aufgaben. - -### 1. Dynamisches Routing - -- **Service Discovery Integration**: Vollständige Consul Integration für automatische Service-Erkennung -- **Load Balancing**: Intelligente Lastverteilung zwischen Service-Instanzen -- **Health-basiertes Routing**: Weiterleitung nur an gesunde Service-Instanzen - -**Verfügbare Routen**: - -- `/api/members/**` → members-service -- `/api/horses/**` → horses-service -- `/api/events/**` → events-service -- `/api/masterdata/**` → masterdata-service -- `/api/auth/**` → auth-service -- `/api/ping/**` → ping-service - -### 2. Sicherheit und Authentifizierung - -- **JWT Security Enforcement**: Validierung von Bearer Tokens für alle geschützten Endpunkte -- **Public Path Exemptions**: Konfigurierbare öffentliche Pfade (`/`, `/health`, `/actuator/**`, `/api/auth/login`) -- **User Context Injection**: Automatische Weiterleitung von User-ID und Rolle an Backend Services -- **Standardisierte Fehlerbehandlung**: Strukturierte 401 Unauthorized Responses - -### 3. Rate Limiting - -- **Intelligentes Rate Limiting** basierend auf User-Typ: - - **Anonymous Users**: 50 Anfragen pro Minute - - **Authenticated Users**: 200 Anfragen pro Minute - - **Admin Users**: 500 Anfragen pro Minute -- **IP-basierte Limits**: Schutz vor DDoS-Attacken -- **Custom Headers**: X-RateLimit-* Header für Client-Information - -### 4. Circuit Breaker und Resilienz - -- **Service-spezifische Circuit Breaker**: Resilience4j Integration für jeden Backend Service -- **Fallback Mechanismen**: Benutzerfreundliche Fehlermeldungen bei Service-Ausfällen -- **Retry Logic**: Automatische Wiederholungen bei transienten Fehlern -- **Graceful Degradation**: Systembetrieb auch bei partiellen Service-Ausfällen - -### 5. Monitoring und Observability - -Das Gateway implementiert umfassende Observability durch eine vollständig integrierte Micrometer-basierte Metriken-Architektur. - -#### Automatische Metriken-Erfassung (GatewayMetricsConfig) - -- **Request Duration Tracking**: Automatische Messung aller Request-Response Zyklen - - Metric: `gateway_request_duration` (Timer) - - Tags: method, path, status, status_series - - Percentile-basierte Auswertung (P50, P90, P95, P99) -- **Error Rate Monitoring**: Detailliertes Error-Tracking für 4xx/5xx Responses - - Metric: `gateway_errors_total` (Counter) - - Tags: method, path, status, status_series, error_type - - Unterscheidung zwischen client_error und server_error -- **Request Volume Tracking**: Vollständige Request-Volumen Überwachung - - Metric: `gateway_requests_total` (Counter) - - Tags: method, path für detaillierte Analyse -- **Circuit Breaker Events**: Monitoring von Resilience-Pattern Events - - Metric: `gateway_circuit_breaker_events_total` (Counter) - - Integration mit Resilience4j Circuit Breaker Status - -#### Intelligente Pfad-Normalisierung - -- **Kardinalitäts-Kontrolle**: Automatische Normalisierung von dynamischen Pfaden - - `/api/horses/123` → `/api/horses/{id}` - - UUID-Pattern → `/{uuid}` - - Sehr lange Pfade werden gekürzt (100+ Zeichen) - -#### Health Monitoring Integration - -- **Downstream Service Health**: Umfassende Überwachung aller Backend Services - - Kritische Services: Members, Horses, Events, Masterdata, Auth - - Optionale Services: Ping Service - - Circuit Breaker Status Integration -- **Distributed Tracing**: Korrelations-ID basiertes Request-Tracking -- **Strukturierte Logs**: JSON-Format für maschinelle Auswertung - -#### Prometheus Export - -- **Automatischer Export**: Alle Metriken werden automatisch an Prometheus exportiert -- **Common Tags**: Alle Metriken erhalten automatisch Service- und Component-Tags -- **Filter-Optimierung**: Rauschen-reduzierende Metrik-Filter für interne Spring/Netty Metriken - -### 6. CORS-Management - -- **Produktionstaugliche CORS-Konfiguration**: - - Erlaubte Origins: `https://*.meldestelle.at`, `http://localhost:*` - - Alle HTTP-Methoden (GET, POST, PUT, DELETE, PATCH, OPTIONS) - - Credential-Support für authentifizierte Anfragen - -## Implementierte Optimierungen - -### Gateway-Konfiguration (application.yml) - -✅ **Vollständige Service-Routen**: Routing für alle Business Services -✅ **Circuit Breaker Integration**: Service-spezifische Resilience4j Konfigurationen -✅ **Connection Pooling**: Optimierte HTTP-Client-Konfiguration -✅ **Security Headers**: Umfassende Sicherheits-Header (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection) -✅ **Enhanced Logging**: Strukturierte Logs mit Korrelations-IDs und Performance-Daten - -### Health Monitoring (GatewayHealthIndicator.kt) - -✅ **Downstream Service Monitoring**: Überwachung aller kritischen Services -✅ **Service Discovery Integration**: Consul-basierte Service-Erkennung -✅ **Test-Environment Handling**: Graceful Degradation in Test-Umgebungen -✅ **Detailliertes Error Reporting**: Umfassende Statusinformationen - -### Build-Optimierungen (build.gradle.kts) - -✅ **SINGLE SOURCE OF TRUTH**: Alle Dependencies über libs.versions.toml -✅ **Build Info Generation**: Automatische Build-Metadaten -✅ **Modern Kotlin Compiler**: Optimierte Compiler-Einstellungen -✅ **Dependency Optimization**: Bereinigung redundanter Dependencies - -### Docker-Optimierungen (Dockerfile) - -✅ **Multi-Stage Build**: Spring Boot Layer-Extraktion für 90%+ besseres Caching -✅ **Security Hardening**: Non-root User, Security Updates -✅ **OCI Compliance**: Vollständige Container-Metadaten -✅ **Production-Ready**: Optimierte JVM-Settings für Container-Umgebung - -### Metriken-Integration (GatewayMetricsConfig.kt) - -✅ **Comprehensive Micrometer Integration**: Vollständige Metriken-Erfassung mit automatischem Prometheus Export -✅ **Request/Response Time Tracking**: Detaillierte Performance-Metriken mit Percentile-Auswertung -✅ **Error Rate Monitoring**: Intelligente Fehler-Klassifikation und -Tracking -✅ **Path Normalization**: Kardinalitäts-kontrolle für dynamische API-Pfade -✅ **Circuit Breaker Metrics**: Integration mit Resilience4j Event-Tracking -✅ **Custom Business Metrics**: Erweiterbare Metrik-Architektur für fachliche KPIs - -### Dokumentation - -✅ **OpenAPI 3.0.3 Spezifikation**: Vollständige API-Dokumentation mit Members Service -✅ **Interactive Swagger UI**: Modern dokumentierte API-Endpunkte -✅ **Static HTML Documentation**: Responsive, moderne Dokumentations-Website -✅ **Health Monitoring Integration**: Real-time Status-Informationen - -## Performance und Reliability - -### Netty Server Optimierungen - -- **Connection Timeouts**: 5 Sekunden für optimale Responsiveness -- **Idle Timeout**: 15 Sekunden für effiziente Resource-Nutzung -- **Elastic Connection Pool**: Automatische Skalierung basierend auf Load - -### Circuit Breaker Konfiguration - -- **Sliding Window**: 100 Anfragen für Default, service-spezifische Anpassungen -- **Failure Rate Threshold**: 50% für Standard-Services, 30% für Auth-Service -- **Half-Open State**: 3 Test-Anfragen für Service-Recovery - -### JVM Optimierungen (Container) - -```bash -JAVA_OPTS="-server -Xmx512m -Xms256m -XX:+UseG1GC - -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0" -``` - -## API Gateway Request Flow - -Ein typischer Anfrage-Flow: - -1. **Client Request**: `https://api.meldestelle.at/api/members/123` -2. **Gateway Empfang**: Anfrage wird vom Spring Cloud Gateway empfangen -3. **Filter-Pipeline**: - - **Security Filter**: JWT-Validierung - - **Rate Limiting Filter**: Anfrage-Limits prüfen - - **Correlation Filter**: Trace-ID generieren - - **Logging Filter**: Request-Details erfassen -4. **Service Discovery**: Consul-Abfrage für verfügbare `members-service` Instanzen -5. **Load Balancing**: Intelligente Auswahl einer gesunden Instanz -6. **Circuit Breaker**: Überwachung der Service-Verfügbarkeit -7. **Request Forwarding**: Weiterleitung an Backend Service -8. **Response Processing**: Antwort-Verarbeitung und Header-Enrichment -9. **Client Response**: Strukturierte Antwort an Client - -## Monitoring und Health Checks - -### Actuator Endpunkte - -- `/actuator/health` - Umfassender Health Status aller Services -- `/actuator/metrics` - Prometheus-kompatible Metriken -- `/actuator/info` - Anwendungs- und Build-Informationen -- `/actuator/gateway` - Gateway-spezifische Routing-Informationen -- `/actuator/circuitbreakers` - Circuit Breaker Status - -### Key Performance Indicators (KPIs) - -#### Automatisch erfasste Metriken - -- **Request Throughput**: `gateway_requests_total` - Anfragen pro Sekunde nach Method/Path -- **Response Times**: `gateway_request_duration` - P50, P90, P95, P99 Percentile nach Status -- **Error Rates**: `gateway_errors_total` - 4xx/5xx Response Codes mit Error-Type Klassifikation -- **Circuit Breaker Events**: `gateway_circuit_breaker_events_total` - Resilience Pattern Aktivierungen -- **Service Availability**: Upstream Service Health via Health Indicators - -#### Verfügbare Metric Tags für detaillierte Analyse - -- **method**: HTTP-Method (GET, POST, PUT, DELETE, etc.) -- **path**: Normalisierter API-Pfad (z.B. `/api/horses/{id}`) -- **status**: HTTP-Status-Code (200, 404, 500, etc.) -- **status_series**: Status-Gruppe (2xx, 3xx, 4xx, 5xx) -- **error_type**: Fehler-Klassifikation (client_error, server_error) -- **service**: Automatisches "gateway" Tag -- **component**: Automatisches "infrastructure" Tag - -#### Prometheus Query Beispiele - -```promql -# Request Rate pro Endpunkt -rate(gateway_requests_total[5m]) - -# 95. Percentile Response Time -histogram_quantile(0.95, rate(gateway_request_duration_bucket[5m])) - -# Error Rate nach Service -rate(gateway_errors_total[5m]) / rate(gateway_requests_total[5m]) - -# Circuit Breaker Aktivierungen -increase(gateway_circuit_breaker_events_total[1h]) -``` - -## Security Features - -### JWT Authentication - -- **Bearer Token Validation**: Automatische JWT-Verifikation -- **Role Extraction**: User-Rolle für Backend Services verfügbar -- **Token Refresh**: Unterstützung für Token-Erneuerung -- **Public Endpoints**: Konfigurierbare Ausnahmen für öffentliche APIs - -### Security Headers - -```yaml -X-Content-Type-Options: nosniff -X-Frame-Options: DENY -X-XSS-Protection: 1; mode=block -Referrer-Policy: strict-origin-when-cross-origin -Cache-Control: no-cache, no-store, must-revalidate -``` - -## Development und Testing - -### Local Development - -**WICHTIG:** Alle Befehle müssen aus dem Projekt-Root-Verzeichnis (`/home/stefan/WsMeldestelle/Meldestelle`) ausgeführt werden. - -```bash -# Sicherstellen, dass Sie im richtigen Verzeichnis sind -cd /home/stefan/WsMeldestelle/Meldestelle - -# Gateway starten -./gradlew :infrastructure:gateway:bootRun - -# Mit Docker -docker build -t meldestelle/gateway:latest -f infrastructure/gateway/Dockerfile . -docker run -p 8081:8081 meldestelle/gateway:latest -``` - -📖 **Detaillierte Startup-Anleitung:** Siehe `GATEWAY-STARTUP-GUIDE.md` im Projekt-Root für vollständige Befehle und Fehlerbehebung. - -### Testing - -```bash -# Unit Tests -./gradlew :infrastructure:gateway:test - -# Integration Tests (mit Testcontainers) -./gradlew :infrastructure:gateway:integrationTest -``` - -## Konfiguration - -### Environment Variables - -```bash -SPRING_PROFILES_ACTIVE=prod -CONSUL_HOST=consul.meldestelle.at -CONSUL_PORT=8500 -GATEWAY_ADMIN_USER=admin -GATEWAY_ADMIN_PASSWORD=secure-password -``` - -### Profile-spezifische Konfiguration - -- **dev**: Entwicklungsumgebung mit Debug-Logging -- **test**: Test-Umgebung mit Mock Services -- **prod**: Produktionsumgebung mit allen Security Features - -## Deployment - -### Docker Deployment - -```bash -# Multi-stage Build mit Layer Caching -docker build -t meldestelle/gateway:1.0.0 \ - -f infrastructure/gateway/Dockerfile . - -# Container starten -docker run -d \ - --name gateway \ - -p 8081:8081 \ - -e SPRING_PROFILES_ACTIVE=prod \ - -e CONSUL_HOST=consul \ - meldestelle/gateway:1.0.0 -``` - -### Kubernetes Deployment - -```yaml -apiVersion: apps/v1 -kind: Deployment -metadata: - name: api-gateway -spec: - replicas: 3 - selector: - matchLabels: - app: api-gateway - template: - spec: - containers: - - name: gateway - image: meldestelle/gateway:1.0.0 - ports: - - containerPort: 8081 - livenessProbe: - httpGet: - path: /actuator/health - port: 8081 - initialDelaySeconds: 90 - periodSeconds: 30 -``` - -## Troubleshooting - -### Häufige Probleme - -**Service Discovery Issues** - -- Consul Connectivity prüfen -- Service Registration Status überprüfen -- DNS Resolution testen - -**Circuit Breaker Activation** - -- Service Health Status prüfen -- Failure Rate Threshold analysieren -- Manual Circuit Breaker Reset über Actuator - -**Performance Issues** - -- Connection Pool Metrics analysieren -- JVM Heap Usage monitoring -- Request Rate Limiting überprüfen - -**Metriken und Monitoring Issues** - -- Prometheus Scraping Endpunkt prüfen: `/actuator/prometheus` -- Metrics Registry Status überprüfen: `/actuator/metrics` -- GatewayMetricsWebFilter Aktivierung validieren -- Metric Tags auf Kardinalitäts-Explosion prüfen -- Path Normalization bei unerwarteten Metric-Namen - -### Logging und Debugging - -```bash -# Logs mit Korrelations-IDs -docker logs gateway | grep "correlationId" - -# Circuit Breaker Status -curl http://localhost:8081/actuator/circuitbreakers - -# Health Details -curl http://localhost:8081/actuator/health -``` - -## Zukünftige Erweiterungen - -### Geplante Features - -- **OAuth2/OIDC Integration**: Erweiterte Authentifizierung -- **GraphQL Gateway**: Unified GraphQL Interface -- **Caching Layer**: Redis-basiertes Response Caching -- **Request/Response Transformation**: Dynamic Content Modification - -### Performance Optimierungen - -- **HTTP/2 Support**: Moderne Protocol-Unterstützung -- **Connection Pooling Tuning**: Erweiterte Pool-Konfiguration -- **Reactive Streams Optimization**: Backpressure Handling - -## Dokumentation und Ressourcen - -### API Dokumentation - -- **Swagger UI**: `/swagger` - Interactive API Documentation -- **OpenAPI Spec**: `/openapi` - Machine-readable API Specification -- **Static Documentation**: `/docs` - Comprehensive Documentation Hub - -### Monitoring Dashboards - -- **Health Status**: `/actuator/health` - Real-time Service Health -- **Metrics**: `/actuator/metrics` - Prometheus Metrics -- **Gateway Routes**: `/actuator/gateway/routes` - Active Route Information - ---- - -**Letzte Aktualisierung**: 14. August 2025 - -**Version**: 1.1.0 - -**Maintainer**: Meldestelle Development Team - ---- - -Diese Dokumentation wurde umfassend aktualisiert und um die neue Micrometer Metrics Integration (GatewayMetricsConfig.kt) erweitert. Sie dokumentiert alle implementierten Optimierungen einschließlich der vollständigen Observability-Architektur mit automatischer Request/Response Zeit Messung, Error Rate Tracking und Custom Business Metrics. diff --git a/infrastructure/cache/cache-api/build.gradle.kts b/backend/infrastructure/cache/cache-api/build.gradle.kts similarity index 100% rename from infrastructure/cache/cache-api/build.gradle.kts rename to backend/infrastructure/cache/cache-api/build.gradle.kts diff --git a/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheConfiguration.kt b/backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheConfiguration.kt similarity index 100% rename from infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheConfiguration.kt rename to backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheConfiguration.kt diff --git a/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheEntry.kt b/backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheEntry.kt similarity index 100% rename from infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheEntry.kt rename to backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheEntry.kt diff --git a/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheSerializer.kt b/backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheSerializer.kt similarity index 100% rename from infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheSerializer.kt rename to backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/CacheSerializer.kt diff --git a/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/ConnectionStatus.kt b/backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/ConnectionStatus.kt similarity index 100% rename from infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/ConnectionStatus.kt rename to backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/ConnectionStatus.kt diff --git a/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCache.kt b/backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCache.kt similarity index 100% rename from infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCache.kt rename to backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCache.kt diff --git a/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCacheExtensions.kt b/backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCacheExtensions.kt similarity index 100% rename from infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCacheExtensions.kt rename to backend/infrastructure/cache/cache-api/src/main/kotlin/at/mocode/infrastructure/cache/api/DistributedCacheExtensions.kt diff --git a/infrastructure/cache/redis-cache/build.gradle.kts b/backend/infrastructure/cache/redis-cache/build.gradle.kts similarity index 95% rename from infrastructure/cache/redis-cache/build.gradle.kts rename to backend/infrastructure/cache/redis-cache/build.gradle.kts index fd0b6a79..5e4ce942 100644 --- a/infrastructure/cache/redis-cache/build.gradle.kts +++ b/backend/infrastructure/cache/redis-cache/build.gradle.kts @@ -27,7 +27,7 @@ dependencies { // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen. api(platform(projects.platform.platformBom)) // Implementiert die provider-agnostische Caching-API. - implementation(projects.infrastructure.cache.cacheApi) + implementation(projects.backend.infrastructure.cache.cacheApi) // OPTIMIERUNG: Verwendung des `redis-cache`-Bundles aus libs.versions.toml. // Dieses Bundle enthält Spring Data Redis, Lettuce und Jackson-Module. implementation(libs.bundles.redis.cache) diff --git a/infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/JacksonCacheSerializer.kt b/backend/infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/JacksonCacheSerializer.kt similarity index 100% rename from infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/JacksonCacheSerializer.kt rename to backend/infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/JacksonCacheSerializer.kt diff --git a/infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisConfiguration.kt b/backend/infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisConfiguration.kt similarity index 100% rename from infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisConfiguration.kt rename to backend/infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisConfiguration.kt diff --git a/infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCache.kt b/backend/infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCache.kt similarity index 100% rename from infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCache.kt rename to backend/infrastructure/cache/redis-cache/src/main/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCache.kt diff --git a/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheConfigurationTest.kt b/backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheConfigurationTest.kt similarity index 100% rename from infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheConfigurationTest.kt rename to backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheConfigurationTest.kt diff --git a/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheEdgeCasesTest.kt b/backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheEdgeCasesTest.kt similarity index 100% rename from infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheEdgeCasesTest.kt rename to backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheEdgeCasesTest.kt diff --git a/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheIntegrationTest.kt b/backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheIntegrationTest.kt similarity index 100% rename from infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheIntegrationTest.kt rename to backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheIntegrationTest.kt diff --git a/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCachePerformanceTest.kt b/backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCachePerformanceTest.kt similarity index 100% rename from infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCachePerformanceTest.kt rename to backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCachePerformanceTest.kt diff --git a/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheResilienceTest.kt b/backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheResilienceTest.kt similarity index 100% rename from infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheResilienceTest.kt rename to backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheResilienceTest.kt diff --git a/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheTest.kt b/backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheTest.kt similarity index 100% rename from infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheTest.kt rename to backend/infrastructure/cache/redis-cache/src/test/kotlin/at/mocode/infrastructure/cache/redis/RedisDistributedCacheTest.kt diff --git a/infrastructure/cache/redis-cache/src/test/resources/logback-test.xml b/backend/infrastructure/cache/redis-cache/src/test/resources/logback-test.xml similarity index 100% rename from infrastructure/cache/redis-cache/src/test/resources/logback-test.xml rename to backend/infrastructure/cache/redis-cache/src/test/resources/logback-test.xml diff --git a/infrastructure/event-store/event-store-api/build.gradle.kts b/backend/infrastructure/event-store/event-store-api/build.gradle.kts similarity index 100% rename from infrastructure/event-store/event-store-api/build.gradle.kts rename to backend/infrastructure/event-store/event-store-api/build.gradle.kts diff --git a/infrastructure/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventSerializer.kt b/backend/infrastructure/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventSerializer.kt similarity index 100% rename from infrastructure/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventSerializer.kt rename to backend/infrastructure/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventSerializer.kt diff --git a/infrastructure/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventStore.kt b/backend/infrastructure/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventStore.kt similarity index 100% rename from infrastructure/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventStore.kt rename to backend/infrastructure/event-store/event-store-api/src/main/kotlin/at/mocode/infrastructure/eventstore/api/EventStore.kt diff --git a/infrastructure/event-store/redis-event-store/build.gradle.kts b/backend/infrastructure/event-store/redis-event-store/build.gradle.kts similarity index 92% rename from infrastructure/event-store/redis-event-store/build.gradle.kts rename to backend/infrastructure/event-store/redis-event-store/build.gradle.kts index ec039819..03204c29 100644 --- a/infrastructure/event-store/redis-event-store/build.gradle.kts +++ b/backend/infrastructure/event-store/redis-event-store/build.gradle.kts @@ -22,7 +22,7 @@ dependencies { // Stellt sicher, dass alle Versionen aus der zentralen BOM kommen implementation(platform(projects.platform.platformBom)) // Implementiert die provider-agnostische Event-Store-API - api(projects.infrastructure.eventStore.eventStoreApi) + api(projects.backend.infrastructure.eventStore.eventStoreApi) // Benötigt Zugriff auf Core-Module für Domänen-Events und Utilities implementation(projects.core.coreDomain) implementation(projects.core.coreUtils) @@ -43,8 +43,8 @@ dependencies { testImplementation(libs.kotlinx.serialization.json) testImplementation(libs.reactor.test) // Für Integration Tests mit beiden Redis-Modulen - testImplementation(projects.infrastructure.cache.cacheApi) - testImplementation(projects.infrastructure.cache.redisCache) + testImplementation(projects.backend.infrastructure.cache.cacheApi) + testImplementation(projects.backend.infrastructure.cache.redisCache) } // === Task Configuration === diff --git a/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/EventStoreMetrics.kt b/backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/EventStoreMetrics.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/EventStoreMetrics.kt rename to backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/EventStoreMetrics.kt diff --git a/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializer.kt b/backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializer.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializer.kt rename to backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializer.kt diff --git a/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumer.kt b/backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumer.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumer.kt rename to backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumer.kt diff --git a/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStore.kt b/backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStore.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStore.kt rename to backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStore.kt diff --git a/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfiguration.kt b/backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfiguration.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfiguration.kt rename to backend/infrastructure/event-store/redis-event-store/src/main/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfiguration.kt diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializerTest.kt b/backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializerTest.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializerTest.kt rename to backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/JacksonEventSerializerTest.kt diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisCacheAndEventStoreIntegrationTest.kt b/backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisCacheAndEventStoreIntegrationTest.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisCacheAndEventStoreIntegrationTest.kt rename to backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisCacheAndEventStoreIntegrationTest.kt diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumerResilienceTest.kt b/backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumerResilienceTest.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumerResilienceTest.kt rename to backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventConsumerResilienceTest.kt diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfigurationTest.kt b/backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfigurationTest.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfigurationTest.kt rename to backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreConfigurationTest.kt diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreErrorHandlingTest.kt b/backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreErrorHandlingTest.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreErrorHandlingTest.kt rename to backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreErrorHandlingTest.kt diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreIntegrationTest.kt b/backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreIntegrationTest.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreIntegrationTest.kt rename to backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreIntegrationTest.kt diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreStreamTest.kt b/backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreStreamTest.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreStreamTest.kt rename to backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreStreamTest.kt diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreTest.kt b/backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreTest.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreTest.kt rename to backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisEventStoreTest.kt diff --git a/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisIntegrationTest.kt b/backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisIntegrationTest.kt similarity index 100% rename from infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisIntegrationTest.kt rename to backend/infrastructure/event-store/redis-event-store/src/test/kotlin/at/mocode/infrastructure/eventstore/redis/RedisIntegrationTest.kt diff --git a/dockerfiles/infrastructure/gateway/Dockerfile b/backend/infrastructure/gateway/Dockerfile similarity index 97% rename from dockerfiles/infrastructure/gateway/Dockerfile rename to backend/infrastructure/gateway/Dockerfile index 736b558b..b78b0449 100644 --- a/dockerfiles/infrastructure/gateway/Dockerfile +++ b/backend/infrastructure/gateway/Dockerfile @@ -23,8 +23,8 @@ ARG VERSION FROM gradle:${GRADLE_VERSION}-jdk${JAVA_VERSION}-alpine AS builder # Re-declare build arguments for this stage -ARG BUILD_DATE ARG VERSION +ARG BUILD_DATE LABEL stage=builder LABEL service="api-gateway" @@ -57,6 +57,7 @@ RUN chmod +x gradlew COPY platform/ platform/ COPY core/ core/ +# Copy infrastructure directories (required by settings.gradle.kts) # Copy infrastructure directories (required by settings.gradle.kts) COPY infrastructure/ infrastructure/ @@ -65,6 +66,7 @@ COPY domains/ domains/ # Copy services directories (required by settings.gradle.kts) COPY services/ services/ +COPY backend/ backend/ # Copy client directories (required by settings.gradle.kts) COPY clients/ clients/ @@ -78,16 +80,16 @@ COPY build.gradle.kts ./ # Download and cache dependencies with BuildKit cache mount (removed deprecated flag) RUN --mount=type=cache,target=/home/gradle/.gradle/caches \ --mount=type=cache,target=/home/gradle/.gradle/wrapper \ - ./gradlew :infrastructure:gateway:dependencies --info + ./gradlew :backend:gateway:dependencies --info # Build the application with optimizations and build cache (removed deprecated flag) RUN --mount=type=cache,target=/home/gradle/.gradle/caches \ --mount=type=cache,target=/home/gradle/.gradle/wrapper \ - ./gradlew :infrastructure:gateway:bootJar --info + ./gradlew :backend:gateway:bootJar --info # Extract JAR layers for better caching in runtime stage RUN mkdir -p build/dependency && \ - (cd build/dependency; java -Djarmode=layertools -jar /workspace/infrastructure/gateway/build/libs/*.jar extract) + (cd build/dependency; java -Djarmode=layertools -jar /workspace/backend/gateway/build/libs/*.jar extract) # =================================================================== # Runtime Stage diff --git a/backend/gateway/build.gradle.kts b/backend/infrastructure/gateway/build.gradle.kts similarity index 96% rename from backend/gateway/build.gradle.kts rename to backend/infrastructure/gateway/build.gradle.kts index 1ff18a52..74c656a9 100644 --- a/backend/gateway/build.gradle.kts +++ b/backend/infrastructure/gateway/build.gradle.kts @@ -19,7 +19,7 @@ dependencies { // === Core Dependencies === implementation(projects.core.coreUtils) implementation(projects.platform.platformDependencies) - implementation(projects.infrastructure.monitoring.monitoringClient) + implementation(projects.backend.infrastructure.monitoring.monitoringClient) // === GATEWAY-SPEZIFISCHE ABHÄNGIGKEITEN === implementation(libs.bundles.spring.cloud.gateway) diff --git a/backend/gateway/docs/index.html b/backend/infrastructure/gateway/docs/index.html similarity index 100% rename from backend/gateway/docs/index.html rename to backend/infrastructure/gateway/docs/index.html diff --git a/backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/GatewayApplication.kt b/backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/GatewayApplication.kt similarity index 100% rename from backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/GatewayApplication.kt rename to backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/GatewayApplication.kt diff --git a/backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/config/GatewayConfig.kt b/backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/config/GatewayConfig.kt similarity index 100% rename from backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/config/GatewayConfig.kt rename to backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/config/GatewayConfig.kt diff --git a/backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/controller/FallbackController.kt b/backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/controller/FallbackController.kt similarity index 100% rename from backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/controller/FallbackController.kt rename to backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/controller/FallbackController.kt diff --git a/backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/health/GatewayHealthIndicator.kt b/backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/health/GatewayHealthIndicator.kt similarity index 100% rename from backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/health/GatewayHealthIndicator.kt rename to backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/health/GatewayHealthIndicator.kt diff --git a/backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/metrics/GatewayMetricsConfig.kt b/backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/metrics/GatewayMetricsConfig.kt similarity index 100% rename from backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/metrics/GatewayMetricsConfig.kt rename to backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/metrics/GatewayMetricsConfig.kt diff --git a/backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/security/SecurityConfig.kt b/backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/security/SecurityConfig.kt similarity index 100% rename from backend/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/security/SecurityConfig.kt rename to backend/infrastructure/gateway/src/main/kotlin/at/mocode/infrastructure/gateway/security/SecurityConfig.kt diff --git a/backend/gateway/src/main/resources/application-keycloak.yml b/backend/infrastructure/gateway/src/main/resources/application-keycloak.yml similarity index 100% rename from backend/gateway/src/main/resources/application-keycloak.yml rename to backend/infrastructure/gateway/src/main/resources/application-keycloak.yml diff --git a/backend/gateway/src/main/resources/application.conf b/backend/infrastructure/gateway/src/main/resources/application.conf similarity index 100% rename from backend/gateway/src/main/resources/application.conf rename to backend/infrastructure/gateway/src/main/resources/application.conf diff --git a/backend/gateway/src/main/resources/application.yml b/backend/infrastructure/gateway/src/main/resources/application.yml similarity index 100% rename from backend/gateway/src/main/resources/application.yml rename to backend/infrastructure/gateway/src/main/resources/application.yml diff --git a/backend/gateway/src/main/resources/logback-spring.xml b/backend/infrastructure/gateway/src/main/resources/logback-spring.xml similarity index 100% rename from backend/gateway/src/main/resources/logback-spring.xml rename to backend/infrastructure/gateway/src/main/resources/logback-spring.xml diff --git a/backend/gateway/src/main/resources/logback.xml b/backend/infrastructure/gateway/src/main/resources/logback.xml similarity index 100% rename from backend/gateway/src/main/resources/logback.xml rename to backend/infrastructure/gateway/src/main/resources/logback.xml diff --git a/backend/gateway/src/main/resources/openapi/documentation.yaml b/backend/infrastructure/gateway/src/main/resources/openapi/documentation.yaml similarity index 100% rename from backend/gateway/src/main/resources/openapi/documentation.yaml rename to backend/infrastructure/gateway/src/main/resources/openapi/documentation.yaml diff --git a/backend/gateway/src/main/resources/static/docs/index.html b/backend/infrastructure/gateway/src/main/resources/static/docs/index.html similarity index 100% rename from backend/gateway/src/main/resources/static/docs/index.html rename to backend/infrastructure/gateway/src/main/resources/static/docs/index.html diff --git a/backend/gateway/src/main/resources/static/docs/postman/Meldestelle_API_Collection.json b/backend/infrastructure/gateway/src/main/resources/static/docs/postman/Meldestelle_API_Collection.json similarity index 100% rename from backend/gateway/src/main/resources/static/docs/postman/Meldestelle_API_Collection.json rename to backend/infrastructure/gateway/src/main/resources/static/docs/postman/Meldestelle_API_Collection.json diff --git a/backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/FallbackControllerTests.kt b/backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/FallbackControllerTests.kt similarity index 100% rename from backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/FallbackControllerTests.kt rename to backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/FallbackControllerTests.kt diff --git a/backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayApplicationTests.kt b/backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayApplicationTests.kt similarity index 100% rename from backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayApplicationTests.kt rename to backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayApplicationTests.kt diff --git a/backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayFiltersTests.kt b/backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayFiltersTests.kt similarity index 100% rename from backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayFiltersTests.kt rename to backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayFiltersTests.kt diff --git a/backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayRoutingTests.kt b/backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayRoutingTests.kt similarity index 100% rename from backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayRoutingTests.kt rename to backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewayRoutingTests.kt diff --git a/backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewaySecurityTests.kt b/backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewaySecurityTests.kt similarity index 100% rename from backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewaySecurityTests.kt rename to backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/GatewaySecurityTests.kt diff --git a/backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/KeycloakGatewayIntegrationTest.kt b/backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/KeycloakGatewayIntegrationTest.kt similarity index 100% rename from backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/KeycloakGatewayIntegrationTest.kt rename to backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/KeycloakGatewayIntegrationTest.kt diff --git a/backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/config/TestSecurityConfig.kt b/backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/config/TestSecurityConfig.kt similarity index 100% rename from backend/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/config/TestSecurityConfig.kt rename to backend/infrastructure/gateway/src/test/kotlin/at/mocode/infrastructure/gateway/config/TestSecurityConfig.kt diff --git a/backend/gateway/src/test/resources/application-dev.yml b/backend/infrastructure/gateway/src/test/resources/application-dev.yml similarity index 100% rename from backend/gateway/src/test/resources/application-dev.yml rename to backend/infrastructure/gateway/src/test/resources/application-dev.yml diff --git a/backend/gateway/src/test/resources/application-keycloak-integration-test.yml b/backend/infrastructure/gateway/src/test/resources/application-keycloak-integration-test.yml similarity index 100% rename from backend/gateway/src/test/resources/application-keycloak-integration-test.yml rename to backend/infrastructure/gateway/src/test/resources/application-keycloak-integration-test.yml diff --git a/backend/gateway/src/test/resources/application-test.yml b/backend/infrastructure/gateway/src/test/resources/application-test.yml similarity index 100% rename from backend/gateway/src/test/resources/application-test.yml rename to backend/infrastructure/gateway/src/test/resources/application-test.yml diff --git a/backend/gateway/src/test/resources/logback-test.xml b/backend/infrastructure/gateway/src/test/resources/logback-test.xml similarity index 100% rename from backend/gateway/src/test/resources/logback-test.xml rename to backend/infrastructure/gateway/src/test/resources/logback-test.xml diff --git a/backend/gateway/src/test/resources/test-init-keycloak-schema.sql b/backend/infrastructure/gateway/src/test/resources/test-init-keycloak-schema.sql similarity index 91% rename from backend/gateway/src/test/resources/test-init-keycloak-schema.sql rename to backend/infrastructure/gateway/src/test/resources/test-init-keycloak-schema.sql index 6287cefb..bd6767a0 100644 --- a/backend/gateway/src/test/resources/test-init-keycloak-schema.sql +++ b/backend/infrastructure/gateway/src/test/resources/test-init-keycloak-schema.sql @@ -1,4 +1,4 @@ --- Testcontainers init script for Keycloak schema +-- Testcontainers an init script for Keycloak schema -- Creates the schema and basic privileges for the test DB user CREATE SCHEMA IF NOT EXISTS keycloak; diff --git a/infrastructure/messaging/messaging-client/build.gradle.kts b/backend/infrastructure/messaging/messaging-client/build.gradle.kts similarity index 93% rename from infrastructure/messaging/messaging-client/build.gradle.kts rename to backend/infrastructure/messaging/messaging-client/build.gradle.kts index 5495f2a0..a9f53660 100644 --- a/infrastructure/messaging/messaging-client/build.gradle.kts +++ b/backend/infrastructure/messaging/messaging-client/build.gradle.kts @@ -23,7 +23,7 @@ dependencies { // Stellt gemeinsame Abhängigkeiten bereit. implementation(projects.platform.platformDependencies) // Baut auf der zentralen Kafka-Konfiguration auf und erbt deren Abhängigkeiten. - implementation(projects.infrastructure.messaging.messagingConfig) + implementation(projects.backend.infrastructure.messaging.messagingConfig) // Fügt die reaktive Kafka-Implementierung hinzu (Project Reactor). implementation(libs.reactor.kafka) // Stellt alle Test-Abhängigkeiten gebündelt bereit. diff --git a/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventConsumer.kt b/backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventConsumer.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventConsumer.kt rename to backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventConsumer.kt diff --git a/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventPublisher.kt b/backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventPublisher.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventPublisher.kt rename to backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/EventPublisher.kt diff --git a/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumer.kt b/backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumer.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumer.kt rename to backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumer.kt diff --git a/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisher.kt b/backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisher.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisher.kt rename to backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisher.kt diff --git a/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/MessagingError.kt b/backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/MessagingError.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/MessagingError.kt rename to backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/MessagingError.kt diff --git a/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/ReactiveKafkaConfig.kt b/backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/ReactiveKafkaConfig.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/ReactiveKafkaConfig.kt rename to backend/infrastructure/messaging/messaging-client/src/main/kotlin/at/mocode/infrastructure/messaging/client/ReactiveKafkaConfig.kt diff --git a/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumerCacheTest.kt b/backend/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumerCacheTest.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumerCacheTest.kt rename to backend/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventConsumerCacheTest.kt diff --git a/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisherErrorTest.kt b/backend/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisherErrorTest.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisherErrorTest.kt rename to backend/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaEventPublisherErrorTest.kt diff --git a/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaIntegrationTest.kt b/backend/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaIntegrationTest.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaIntegrationTest.kt rename to backend/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaIntegrationTest.kt diff --git a/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaSecurityTest.kt b/backend/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaSecurityTest.kt similarity index 100% rename from infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaSecurityTest.kt rename to backend/infrastructure/messaging/messaging-client/src/test/kotlin/at/mocode/infrastructure/messaging/client/KafkaSecurityTest.kt diff --git a/infrastructure/messaging/messaging-config/build.gradle.kts b/backend/infrastructure/messaging/messaging-config/build.gradle.kts similarity index 100% rename from infrastructure/messaging/messaging-config/build.gradle.kts rename to backend/infrastructure/messaging/messaging-config/build.gradle.kts diff --git a/infrastructure/messaging/messaging-config/src/main/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfig.kt b/backend/infrastructure/messaging/messaging-config/src/main/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfig.kt similarity index 100% rename from infrastructure/messaging/messaging-config/src/main/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfig.kt rename to backend/infrastructure/messaging/messaging-config/src/main/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfig.kt diff --git a/infrastructure/messaging/messaging-config/src/test/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfigTest.kt b/backend/infrastructure/messaging/messaging-config/src/test/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfigTest.kt similarity index 100% rename from infrastructure/messaging/messaging-config/src/test/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfigTest.kt rename to backend/infrastructure/messaging/messaging-config/src/test/kotlin/at/mocode/infrastructure/messaging/config/KafkaConfigTest.kt diff --git a/infrastructure/monitoring/monitoring-client/build.gradle.kts b/backend/infrastructure/monitoring/monitoring-client/build.gradle.kts similarity index 100% rename from infrastructure/monitoring/monitoring-client/build.gradle.kts rename to backend/infrastructure/monitoring/monitoring-client/build.gradle.kts diff --git a/infrastructure/monitoring/monitoring-client/src/main/kotlin/at/mocode/infrastructure/monitoring/client/MonitoringClientAutoConfiguration.kt b/backend/infrastructure/monitoring/monitoring-client/src/main/kotlin/at/mocode/infrastructure/monitoring/client/MonitoringClientAutoConfiguration.kt similarity index 100% rename from infrastructure/monitoring/monitoring-client/src/main/kotlin/at/mocode/infrastructure/monitoring/client/MonitoringClientAutoConfiguration.kt rename to backend/infrastructure/monitoring/monitoring-client/src/main/kotlin/at/mocode/infrastructure/monitoring/client/MonitoringClientAutoConfiguration.kt diff --git a/infrastructure/monitoring/monitoring-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/backend/infrastructure/monitoring/monitoring-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports similarity index 100% rename from infrastructure/monitoring/monitoring-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports rename to backend/infrastructure/monitoring/monitoring-client/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/infrastructure/monitoring/monitoring-client/src/main/resources/monitoring-defaults.properties b/backend/infrastructure/monitoring/monitoring-client/src/main/resources/monitoring-defaults.properties similarity index 100% rename from infrastructure/monitoring/monitoring-client/src/main/resources/monitoring-defaults.properties rename to backend/infrastructure/monitoring/monitoring-client/src/main/resources/monitoring-defaults.properties diff --git a/infrastructure/monitoring/monitoring-server/build.gradle.kts b/backend/infrastructure/monitoring/monitoring-server/build.gradle.kts similarity index 100% rename from infrastructure/monitoring/monitoring-server/build.gradle.kts rename to backend/infrastructure/monitoring/monitoring-server/build.gradle.kts diff --git a/infrastructure/monitoring/monitoring-server/src/main/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplication.kt b/backend/infrastructure/monitoring/monitoring-server/src/main/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplication.kt similarity index 100% rename from infrastructure/monitoring/monitoring-server/src/main/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplication.kt rename to backend/infrastructure/monitoring/monitoring-server/src/main/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplication.kt diff --git a/infrastructure/monitoring/monitoring-server/src/main/resources/application.properties b/backend/infrastructure/monitoring/monitoring-server/src/main/resources/application.properties similarity index 100% rename from infrastructure/monitoring/monitoring-server/src/main/resources/application.properties rename to backend/infrastructure/monitoring/monitoring-server/src/main/resources/application.properties diff --git a/infrastructure/monitoring/monitoring-server/src/test/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplicationTest.kt b/backend/infrastructure/monitoring/monitoring-server/src/test/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplicationTest.kt similarity index 100% rename from infrastructure/monitoring/monitoring-server/src/test/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplicationTest.kt rename to backend/infrastructure/monitoring/monitoring-server/src/test/kotlin/at/mocode/infrastructure/monitoring/MonitoringServerApplicationTest.kt diff --git a/domains/events/events-service/src/test/resources/logback-test.xml b/backend/infrastructure/monitoring/monitoring-server/src/test/resources/logback-test.xml similarity index 100% rename from domains/events/events-service/src/test/resources/logback-test.xml rename to backend/infrastructure/monitoring/monitoring-server/src/test/resources/logback-test.xml diff --git a/dockerfiles/domains/events-service/Dockerfile b/backend/services/events/Dockerfile similarity index 100% rename from dockerfiles/domains/events-service/Dockerfile rename to backend/services/events/Dockerfile diff --git a/domains/events/events-api/build.gradle.kts b/backend/services/events/events-api/build.gradle.kts similarity index 100% rename from domains/events/events-api/build.gradle.kts rename to backend/services/events/events-api/build.gradle.kts diff --git a/domains/events/events-api/src/main/kotlin/at/mocode/events/api/rest/VeranstaltungController.kt b/backend/services/events/events-api/src/main/kotlin/at/mocode/events/api/rest/VeranstaltungController.kt similarity index 100% rename from domains/events/events-api/src/main/kotlin/at/mocode/events/api/rest/VeranstaltungController.kt rename to backend/services/events/events-api/src/main/kotlin/at/mocode/events/api/rest/VeranstaltungController.kt diff --git a/domains/events/events-common/build.gradle.kts b/backend/services/events/events-common/build.gradle.kts similarity index 100% rename from domains/events/events-common/build.gradle.kts rename to backend/services/events/events-common/build.gradle.kts diff --git a/domains/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/CreateVeranstaltungUseCase.kt b/backend/services/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/CreateVeranstaltungUseCase.kt similarity index 100% rename from domains/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/CreateVeranstaltungUseCase.kt rename to backend/services/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/CreateVeranstaltungUseCase.kt diff --git a/domains/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/DeleteVeranstaltungUseCase.kt b/backend/services/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/DeleteVeranstaltungUseCase.kt similarity index 100% rename from domains/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/DeleteVeranstaltungUseCase.kt rename to backend/services/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/DeleteVeranstaltungUseCase.kt diff --git a/domains/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/GetVeranstaltungUseCase.kt b/backend/services/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/GetVeranstaltungUseCase.kt similarity index 100% rename from domains/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/GetVeranstaltungUseCase.kt rename to backend/services/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/GetVeranstaltungUseCase.kt diff --git a/domains/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/UpdateVeranstaltungUseCase.kt b/backend/services/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/UpdateVeranstaltungUseCase.kt similarity index 100% rename from domains/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/UpdateVeranstaltungUseCase.kt rename to backend/services/events/events-common/src/main/kotlin/at/mocode/events/application/usecase/UpdateVeranstaltungUseCase.kt diff --git a/domains/events/events-domain/build.gradle.kts b/backend/services/events/events-domain/build.gradle.kts similarity index 100% rename from domains/events/events-domain/build.gradle.kts rename to backend/services/events/events-domain/build.gradle.kts diff --git a/domains/events/events-domain/src/main/kotlin/at/mocode/events/EventManagement.kt b/backend/services/events/events-domain/src/main/kotlin/at/mocode/events/EventManagement.kt similarity index 100% rename from domains/events/events-domain/src/main/kotlin/at/mocode/events/EventManagement.kt rename to backend/services/events/events-domain/src/main/kotlin/at/mocode/events/EventManagement.kt diff --git a/domains/events/events-domain/src/main/kotlin/at/mocode/events/domain/model/Veranstaltung.kt b/backend/services/events/events-domain/src/main/kotlin/at/mocode/events/domain/model/Veranstaltung.kt similarity index 100% rename from domains/events/events-domain/src/main/kotlin/at/mocode/events/domain/model/Veranstaltung.kt rename to backend/services/events/events-domain/src/main/kotlin/at/mocode/events/domain/model/Veranstaltung.kt diff --git a/domains/events/events-domain/src/main/kotlin/at/mocode/events/domain/repository/VeranstaltungRepository.kt b/backend/services/events/events-domain/src/main/kotlin/at/mocode/events/domain/repository/VeranstaltungRepository.kt similarity index 100% rename from domains/events/events-domain/src/main/kotlin/at/mocode/events/domain/repository/VeranstaltungRepository.kt rename to backend/services/events/events-domain/src/main/kotlin/at/mocode/events/domain/repository/VeranstaltungRepository.kt diff --git a/domains/events/events-infrastructure/build.gradle.kts b/backend/services/events/events-infrastructure/build.gradle.kts similarity index 100% rename from domains/events/events-infrastructure/build.gradle.kts rename to backend/services/events/events-infrastructure/build.gradle.kts diff --git a/domains/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungRepositoryImpl.kt b/backend/services/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungRepositoryImpl.kt similarity index 100% rename from domains/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungRepositoryImpl.kt rename to backend/services/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungRepositoryImpl.kt diff --git a/domains/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungTable.kt b/backend/services/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungTable.kt similarity index 100% rename from domains/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungTable.kt rename to backend/services/events/events-infrastructure/src/main/kotlin/at/mocode/events/infrastructure/persistence/VeranstaltungTable.kt diff --git a/domains/events/events-service/build.gradle.kts b/backend/services/events/events-service/build.gradle.kts similarity index 100% rename from domains/events/events-service/build.gradle.kts rename to backend/services/events/events-service/build.gradle.kts diff --git a/domains/events/events-service/src/main/kotlin/at/mocode/events/service/EventsServiceApplication.kt b/backend/services/events/events-service/src/main/kotlin/at/mocode/events/service/EventsServiceApplication.kt similarity index 100% rename from domains/events/events-service/src/main/kotlin/at/mocode/events/service/EventsServiceApplication.kt rename to backend/services/events/events-service/src/main/kotlin/at/mocode/events/service/EventsServiceApplication.kt diff --git a/domains/events/events-service/src/main/kotlin/at/mocode/events/service/config/EventsDatabaseConfiguration.kt b/backend/services/events/events-service/src/main/kotlin/at/mocode/events/service/config/EventsDatabaseConfiguration.kt similarity index 100% rename from domains/events/events-service/src/main/kotlin/at/mocode/events/service/config/EventsDatabaseConfiguration.kt rename to backend/services/events/events-service/src/main/kotlin/at/mocode/events/service/config/EventsDatabaseConfiguration.kt diff --git a/domains/horses/horses-service/src/test/resources/logback-test.xml b/backend/services/events/events-service/src/test/resources/logback-test.xml similarity index 100% rename from domains/horses/horses-service/src/test/resources/logback-test.xml rename to backend/services/events/events-service/src/test/resources/logback-test.xml diff --git a/dockerfiles/domains/horses-service/Dockerfile b/backend/services/horses/Dockerfile similarity index 100% rename from dockerfiles/domains/horses-service/Dockerfile rename to backend/services/horses/Dockerfile diff --git a/domains/horses/horses-api/build.gradle.kts b/backend/services/horses/horses-api/build.gradle.kts similarity index 100% rename from domains/horses/horses-api/build.gradle.kts rename to backend/services/horses/horses-api/build.gradle.kts diff --git a/domains/horses/horses-api/src/main/kotlin/at/mocode/horses/api/rest/HorseController.kt b/backend/services/horses/horses-api/src/main/kotlin/at/mocode/horses/api/rest/HorseController.kt similarity index 100% rename from domains/horses/horses-api/src/main/kotlin/at/mocode/horses/api/rest/HorseController.kt rename to backend/services/horses/horses-api/src/main/kotlin/at/mocode/horses/api/rest/HorseController.kt diff --git a/domains/horses/horses-common/build.gradle.kts b/backend/services/horses/horses-common/build.gradle.kts similarity index 100% rename from domains/horses/horses-common/build.gradle.kts rename to backend/services/horses/horses-common/build.gradle.kts diff --git a/domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/CreateHorseUseCase.kt b/backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/CreateHorseUseCase.kt similarity index 100% rename from domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/CreateHorseUseCase.kt rename to backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/CreateHorseUseCase.kt diff --git a/domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/DeleteHorseUseCase.kt b/backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/DeleteHorseUseCase.kt similarity index 100% rename from domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/DeleteHorseUseCase.kt rename to backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/DeleteHorseUseCase.kt diff --git a/domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/GetHorseUseCase.kt b/backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/GetHorseUseCase.kt similarity index 100% rename from domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/GetHorseUseCase.kt rename to backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/GetHorseUseCase.kt diff --git a/domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/TransactionalCreateHorseUseCase.kt b/backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/TransactionalCreateHorseUseCase.kt similarity index 100% rename from domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/TransactionalCreateHorseUseCase.kt rename to backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/TransactionalCreateHorseUseCase.kt diff --git a/domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/UpdateHorseUseCase.kt b/backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/UpdateHorseUseCase.kt similarity index 100% rename from domains/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/UpdateHorseUseCase.kt rename to backend/services/horses/horses-common/src/main/kotlin/at/mocode/horses/application/usecase/UpdateHorseUseCase.kt diff --git a/domains/horses/horses-domain/build.gradle.kts b/backend/services/horses/horses-domain/build.gradle.kts similarity index 100% rename from domains/horses/horses-domain/build.gradle.kts rename to backend/services/horses/horses-domain/build.gradle.kts diff --git a/domains/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/model/DomPferd.kt b/backend/services/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/model/DomPferd.kt similarity index 100% rename from domains/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/model/DomPferd.kt rename to backend/services/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/model/DomPferd.kt diff --git a/domains/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/repository/HorseRepository.kt b/backend/services/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/repository/HorseRepository.kt similarity index 100% rename from domains/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/repository/HorseRepository.kt rename to backend/services/horses/horses-domain/src/main/kotlin/at/mocode/horses/domain/repository/HorseRepository.kt diff --git a/domains/horses/horses-infrastructure/build.gradle.kts b/backend/services/horses/horses-infrastructure/build.gradle.kts similarity index 100% rename from domains/horses/horses-infrastructure/build.gradle.kts rename to backend/services/horses/horses-infrastructure/build.gradle.kts diff --git a/domains/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseRepositoryImpl.kt b/backend/services/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseRepositoryImpl.kt similarity index 100% rename from domains/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseRepositoryImpl.kt rename to backend/services/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseRepositoryImpl.kt diff --git a/domains/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseTable.kt b/backend/services/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseTable.kt similarity index 100% rename from domains/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseTable.kt rename to backend/services/horses/horses-infrastructure/src/main/kotlin/at/mocode/horses/infrastructure/persistence/HorseTable.kt diff --git a/domains/horses/horses-service/build.gradle.kts b/backend/services/horses/horses-service/build.gradle.kts similarity index 100% rename from domains/horses/horses-service/build.gradle.kts rename to backend/services/horses/horses-service/build.gradle.kts diff --git a/domains/horses/horses-service/src/main/kotlin/at/mocode/horses/service/HorsesServiceApplication.kt b/backend/services/horses/horses-service/src/main/kotlin/at/mocode/horses/service/HorsesServiceApplication.kt similarity index 100% rename from domains/horses/horses-service/src/main/kotlin/at/mocode/horses/service/HorsesServiceApplication.kt rename to backend/services/horses/horses-service/src/main/kotlin/at/mocode/horses/service/HorsesServiceApplication.kt diff --git a/domains/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/ApplicationConfiguration.kt b/backend/services/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/ApplicationConfiguration.kt similarity index 100% rename from domains/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/ApplicationConfiguration.kt rename to backend/services/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/ApplicationConfiguration.kt diff --git a/domains/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/DatabaseConfiguration.kt b/backend/services/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/DatabaseConfiguration.kt similarity index 100% rename from domains/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/DatabaseConfiguration.kt rename to backend/services/horses/horses-service/src/main/kotlin/at/mocode/horses/service/config/DatabaseConfiguration.kt diff --git a/domains/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/HorseServiceIntegrationTest.kt b/backend/services/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/HorseServiceIntegrationTest.kt similarity index 100% rename from domains/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/HorseServiceIntegrationTest.kt rename to backend/services/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/HorseServiceIntegrationTest.kt diff --git a/domains/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionContextTest.kt b/backend/services/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionContextTest.kt similarity index 100% rename from domains/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionContextTest.kt rename to backend/services/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionContextTest.kt diff --git a/domains/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionalContextTest.kt b/backend/services/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionalContextTest.kt similarity index 100% rename from domains/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionalContextTest.kt rename to backend/services/horses/horses-service/src/test/kotlin/at/mocode/horses/service/integration/TransactionalContextTest.kt diff --git a/domains/masterdata/masterdata-service/src/test/resources/logback-test.xml b/backend/services/horses/horses-service/src/test/resources/logback-test.xml similarity index 100% rename from domains/masterdata/masterdata-service/src/test/resources/logback-test.xml rename to backend/services/horses/horses-service/src/test/resources/logback-test.xml diff --git a/dockerfiles/domains/masterdata-service/Dockerfile b/backend/services/masterdata/Dockerfile similarity index 100% rename from dockerfiles/domains/masterdata-service/Dockerfile rename to backend/services/masterdata/Dockerfile diff --git a/domains/masterdata/masterdata-api/build.gradle.kts b/backend/services/masterdata/masterdata-api/build.gradle.kts similarity index 100% rename from domains/masterdata/masterdata-api/build.gradle.kts rename to backend/services/masterdata/masterdata-api/build.gradle.kts diff --git a/domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/StatusPages.kt b/backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/StatusPages.kt similarity index 100% rename from domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/StatusPages.kt rename to backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/StatusPages.kt diff --git a/domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/AltersklasseController.kt b/backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/AltersklasseController.kt similarity index 100% rename from domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/AltersklasseController.kt rename to backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/AltersklasseController.kt diff --git a/domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/BundeslandController.kt b/backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/BundeslandController.kt similarity index 100% rename from domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/BundeslandController.kt rename to backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/BundeslandController.kt diff --git a/domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/CountryController.kt b/backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/CountryController.kt similarity index 100% rename from domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/CountryController.kt rename to backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/CountryController.kt diff --git a/domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/PlatzController.kt b/backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/PlatzController.kt similarity index 100% rename from domains/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/PlatzController.kt rename to backend/services/masterdata/masterdata-api/src/main/kotlin/at/mocode/masterdata/api/rest/PlatzController.kt diff --git a/domains/masterdata/masterdata-common/build.gradle.kts b/backend/services/masterdata/masterdata-common/build.gradle.kts similarity index 100% rename from domains/masterdata/masterdata-common/build.gradle.kts rename to backend/services/masterdata/masterdata-common/build.gradle.kts diff --git a/domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateAltersklasseUseCase.kt b/backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateAltersklasseUseCase.kt similarity index 100% rename from domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateAltersklasseUseCase.kt rename to backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateAltersklasseUseCase.kt diff --git a/domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateBundeslandUseCase.kt b/backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateBundeslandUseCase.kt similarity index 100% rename from domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateBundeslandUseCase.kt rename to backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateBundeslandUseCase.kt diff --git a/domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateCountryUseCase.kt b/backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateCountryUseCase.kt similarity index 100% rename from domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateCountryUseCase.kt rename to backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreateCountryUseCase.kt diff --git a/domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreatePlatzUseCase.kt b/backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreatePlatzUseCase.kt similarity index 100% rename from domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreatePlatzUseCase.kt rename to backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/CreatePlatzUseCase.kt diff --git a/domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetAltersklasseUseCase.kt b/backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetAltersklasseUseCase.kt similarity index 100% rename from domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetAltersklasseUseCase.kt rename to backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetAltersklasseUseCase.kt diff --git a/domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetBundeslandUseCase.kt b/backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetBundeslandUseCase.kt similarity index 100% rename from domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetBundeslandUseCase.kt rename to backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetBundeslandUseCase.kt diff --git a/domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetCountryUseCase.kt b/backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetCountryUseCase.kt similarity index 100% rename from domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetCountryUseCase.kt rename to backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetCountryUseCase.kt diff --git a/domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetPlatzUseCase.kt b/backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetPlatzUseCase.kt similarity index 100% rename from domains/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetPlatzUseCase.kt rename to backend/services/masterdata/masterdata-common/src/main/kotlin/at/mocode/masterdata/application/usecase/GetPlatzUseCase.kt diff --git a/domains/masterdata/masterdata-domain/build.gradle.kts b/backend/services/masterdata/masterdata-domain/build.gradle.kts similarity index 100% rename from domains/masterdata/masterdata-domain/build.gradle.kts rename to backend/services/masterdata/masterdata-domain/build.gradle.kts diff --git a/domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/AltersklasseDefinition.kt b/backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/AltersklasseDefinition.kt similarity index 100% rename from domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/AltersklasseDefinition.kt rename to backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/AltersklasseDefinition.kt diff --git a/domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/BundeslandDefinition.kt b/backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/BundeslandDefinition.kt similarity index 100% rename from domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/BundeslandDefinition.kt rename to backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/BundeslandDefinition.kt diff --git a/domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/LandDefinition.kt b/backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/LandDefinition.kt similarity index 100% rename from domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/LandDefinition.kt rename to backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/LandDefinition.kt diff --git a/domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/Platz.kt b/backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/Platz.kt similarity index 100% rename from domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/Platz.kt rename to backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/model/Platz.kt diff --git a/domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/AltersklasseRepository.kt b/backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/AltersklasseRepository.kt similarity index 100% rename from domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/AltersklasseRepository.kt rename to backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/AltersklasseRepository.kt diff --git a/domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/BundeslandRepository.kt b/backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/BundeslandRepository.kt similarity index 100% rename from domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/BundeslandRepository.kt rename to backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/BundeslandRepository.kt diff --git a/domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/LandRepository.kt b/backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/LandRepository.kt similarity index 100% rename from domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/LandRepository.kt rename to backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/LandRepository.kt diff --git a/domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/PlatzRepository.kt b/backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/PlatzRepository.kt similarity index 100% rename from domains/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/PlatzRepository.kt rename to backend/services/masterdata/masterdata-domain/src/main/kotlin/at/mocode/masterdata/domain/repository/PlatzRepository.kt diff --git a/domains/masterdata/masterdata-infrastructure/build.gradle.kts b/backend/services/masterdata/masterdata-infrastructure/build.gradle.kts similarity index 100% rename from domains/masterdata/masterdata-infrastructure/build.gradle.kts rename to backend/services/masterdata/masterdata-infrastructure/build.gradle.kts diff --git a/domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseRepositoryImpl.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseRepositoryImpl.kt similarity index 100% rename from domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseRepositoryImpl.kt rename to backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseRepositoryImpl.kt diff --git a/domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseTable.kt similarity index 100% rename from domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseTable.kt rename to backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/AltersklasseTable.kt diff --git a/domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandRepositoryImpl.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandRepositoryImpl.kt similarity index 100% rename from domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandRepositoryImpl.kt rename to backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandRepositoryImpl.kt diff --git a/domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandTable.kt similarity index 100% rename from domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandTable.kt rename to backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/BundeslandTable.kt diff --git a/domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandRepositoryImpl.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandRepositoryImpl.kt similarity index 100% rename from domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandRepositoryImpl.kt rename to backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandRepositoryImpl.kt diff --git a/domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandTable.kt similarity index 100% rename from domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandTable.kt rename to backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/LandTable.kt diff --git a/domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzRepositoryImpl.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzRepositoryImpl.kt similarity index 100% rename from domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzRepositoryImpl.kt rename to backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzRepositoryImpl.kt diff --git a/domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzTable.kt b/backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzTable.kt similarity index 100% rename from domains/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzTable.kt rename to backend/services/masterdata/masterdata-infrastructure/src/main/kotlin/at/mocode/masterdata/infrastructure/persistence/PlatzTable.kt diff --git a/domains/masterdata/masterdata-service/build.gradle.kts b/backend/services/masterdata/masterdata-service/build.gradle.kts similarity index 100% rename from domains/masterdata/masterdata-service/build.gradle.kts rename to backend/services/masterdata/masterdata-service/build.gradle.kts diff --git a/domains/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/MasterdataServiceApplication.kt b/backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/MasterdataServiceApplication.kt similarity index 100% rename from domains/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/MasterdataServiceApplication.kt rename to backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/MasterdataServiceApplication.kt diff --git a/domains/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataConfiguration.kt b/backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataConfiguration.kt similarity index 100% rename from domains/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataConfiguration.kt rename to backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataConfiguration.kt diff --git a/domains/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataDatabaseConfiguration.kt b/backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataDatabaseConfiguration.kt similarity index 100% rename from domains/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataDatabaseConfiguration.kt rename to backend/services/masterdata/masterdata-service/src/main/kotlin/at/mocode/masterdata/service/config/MasterdataDatabaseConfiguration.kt diff --git a/domains/masterdata/masterdata-service/src/main/resources/db/migration/V001__Create_Land_Table.sql b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V001__Create_Land_Table.sql similarity index 100% rename from domains/masterdata/masterdata-service/src/main/resources/db/migration/V001__Create_Land_Table.sql rename to backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V001__Create_Land_Table.sql diff --git a/domains/masterdata/masterdata-service/src/main/resources/db/migration/V002__Create_Bundesland_Table.sql b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V002__Create_Bundesland_Table.sql similarity index 100% rename from domains/masterdata/masterdata-service/src/main/resources/db/migration/V002__Create_Bundesland_Table.sql rename to backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V002__Create_Bundesland_Table.sql diff --git a/domains/masterdata/masterdata-service/src/main/resources/db/migration/V003__Create_Altersklasse_Table.sql b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V003__Create_Altersklasse_Table.sql similarity index 100% rename from domains/masterdata/masterdata-service/src/main/resources/db/migration/V003__Create_Altersklasse_Table.sql rename to backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V003__Create_Altersklasse_Table.sql diff --git a/domains/masterdata/masterdata-service/src/main/resources/db/migration/V004__Create_Platz_Table.sql b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V004__Create_Platz_Table.sql similarity index 100% rename from domains/masterdata/masterdata-service/src/main/resources/db/migration/V004__Create_Platz_Table.sql rename to backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V004__Create_Platz_Table.sql diff --git a/domains/masterdata/masterdata-service/src/main/resources/db/migration/V1__Create_Initial_Tables.sql b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V1__Create_Initial_Tables.sql similarity index 96% rename from domains/masterdata/masterdata-service/src/main/resources/db/migration/V1__Create_Initial_Tables.sql rename to backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V1__Create_Initial_Tables.sql index 7c330d15..9ade97d1 100644 --- a/domains/masterdata/masterdata-service/src/main/resources/db/migration/V1__Create_Initial_Tables.sql +++ b/backend/services/masterdata/masterdata-service/src/main/resources/db/migration/V1__Create_Initial_Tables.sql @@ -30,4 +30,4 @@ CREATE TABLE IF NOT EXISTS dom_person ( updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP ); --- Weitere Tabellen können hier hinzugefügt werden... +-- Weitere Tabellen können hier hinzugefügt werden ... diff --git a/infrastructure/monitoring/monitoring-server/src/test/resources/logback-test.xml b/backend/services/masterdata/masterdata-service/src/test/resources/logback-test.xml similarity index 100% rename from infrastructure/monitoring/monitoring-server/src/test/resources/logback-test.xml rename to backend/services/masterdata/masterdata-service/src/test/resources/logback-test.xml diff --git a/dockerfiles/domains/members-service/Dockerfile b/backend/services/members/Dockerfile similarity index 100% rename from dockerfiles/domains/members-service/Dockerfile rename to backend/services/members/Dockerfile diff --git a/dockerfiles/services/ping-service/Dockerfile b/backend/services/ping/Dockerfile similarity index 89% rename from dockerfiles/services/ping-service/Dockerfile rename to backend/services/ping/Dockerfile index 8a012d29..5da5050e 100644 --- a/dockerfiles/services/ping-service/Dockerfile +++ b/backend/services/ping/Dockerfile @@ -51,20 +51,14 @@ RUN chmod +x gradlew # Copy platform dependencies (changes less frequently) COPY platform/ platform/ -# Copy client directories (required by settings.gradle.kts) -COPY clients/ clients/ +# Copy frontend/client directories (required by settings.gradle.kts) +COPY frontend/ frontend/ # Copy core directories (required by settings.gradle.kts) COPY core/ core/ -# Copy infrastructure directories (required by settings.gradle.kts) -COPY infrastructure/ infrastructure/ - -# Copy domains directory (required by settings.gradle.kts) -COPY domains/ domains/ - -# Copy services directories (required by settings.gradle.kts) -COPY services/ services/ +# Copy backend (includes services and infrastructure in new structure) +COPY backend/ backend/ # Copy docs directory (required by settings.gradle.kts) COPY docs/ docs/ @@ -72,19 +66,19 @@ COPY docs/ docs/ # Copy root build configuration COPY build.gradle.kts ./ -# Copy ping modules (changes most frequently) -COPY services/ping/ping-api/ services/ping/ping-api/ -COPY services/ping/ping-service/ services/ping/ping-service/ +# Copy ping modules (changes most frequently) for both legacy and new structure +COPY backend/services/ping/ping-api/ backend/services/ping/ping-api/ +COPY backend/services/ping/ping-service/ backend/services/ping/ping-service/ # Download and cache dependencies in a separate layer with build cache RUN --mount=type=cache,target=/home/gradle/.gradle/caches \ --mount=type=cache,target=/home/gradle/.gradle/wrapper \ - ./gradlew :services:ping:ping-service:dependencies --no-daemon --info + ./gradlew :backend:services:ping:ping-service:dependencies --no-daemon --info # Build the application with optimizations and build cache RUN --mount=type=cache,target=/home/gradle/.gradle/caches \ --mount=type=cache,target=/home/gradle/.gradle/wrapper \ - ./gradlew :services:ping:ping-service:bootJar --no-daemon --info + ./gradlew :backend:services:ping:ping-service:bootJar --no-daemon --info # =================================================================== # Runtime stage: optimized JRE image for production @@ -138,7 +132,7 @@ RUN apk update && \ # Copy the built JAR from builder stage with proper ownership COPY --from=builder --chown=${APP_USER}:${APP_GROUP} \ - /workspace/services/ping/ping-service/build/libs/*.jar app.jar + /workspace/backend/services/ping/ping-service/build/libs/*.jar app.jar # Switch to non-root user USER ${APP_USER} diff --git a/backend/services/ping/ping-service/build.gradle.kts b/backend/services/ping/ping-service/build.gradle.kts index 1476ac67..290226c5 100644 --- a/backend/services/ping/ping-service/build.gradle.kts +++ b/backend/services/ping/ping-service/build.gradle.kts @@ -19,8 +19,8 @@ dependencies { // Platform und Core Dependencies implementation(projects.platform.platformDependencies) - implementation(project(":backend:services:ping:ping-api")) - implementation(projects.infrastructure.monitoring.monitoringClient) + implementation(projects.backend.services.ping.pingApi) + implementation(projects.backend.infrastructure.monitoring.monitoringClient) // Spring Boot Service Complete Bundle // Provides: web, validation, actuator, security, oauth2-client, oauth2-resource-server, diff --git a/domains/registry/oeps-importer/build.gradle.kts b/backend/services/registry/oeps-importer/build.gradle.kts similarity index 100% rename from domains/registry/oeps-importer/build.gradle.kts rename to backend/services/registry/oeps-importer/build.gradle.kts diff --git a/domains/registry/registry-api/build.gradle.kts b/backend/services/registry/registry-api/build.gradle.kts similarity index 100% rename from domains/registry/registry-api/build.gradle.kts rename to backend/services/registry/registry-api/build.gradle.kts diff --git a/domains/registry/registry-domain/build.gradle.kts b/backend/services/registry/registry-domain/build.gradle.kts similarity index 100% rename from domains/registry/registry-domain/build.gradle.kts rename to backend/services/registry/registry-domain/build.gradle.kts diff --git a/domains/registry/registry-service/build.gradle.kts b/backend/services/registry/registry-service/build.gradle.kts similarity index 100% rename from domains/registry/registry-service/build.gradle.kts rename to backend/services/registry/registry-service/build.gradle.kts diff --git a/clients/shared/src/commonMain/kotlin/at/mocode/clients/shared/domain/repository/PingRepository.kt b/clients/shared/src/commonMain/kotlin/at/mocode/clients/shared/domain/repository/PingRepository.kt deleted file mode 100644 index 89672780..00000000 --- a/clients/shared/src/commonMain/kotlin/at/mocode/clients/shared/domain/repository/PingRepository.kt +++ /dev/null @@ -1,8 +0,0 @@ -package at.mocode.clients.shared.domain.repository - -import at.mocode.clients.shared.domain.model.PingData -import at.mocode.clients.shared.domain.model.Resource - -interface PingRepository { - suspend fun checkSystemStatus(): Resource -} diff --git a/config/.env b/config/.env new file mode 100644 index 00000000..2d7b3215 --- /dev/null +++ b/config/.env @@ -0,0 +1,8 @@ +# DEPRECATED – Single Source of Truth moved to docker/.env +# +# This file is no longer used by Docker Compose or any build scripts. +# Please configure environment variables in: +# docker/.env (create from docker/.env.example) +# +# Reason: Avoid duplicated/conflicting configuration files. +# Monitoring, Postgres, Redis, Keycloak, Gateway etc. read values from docker/.env. diff --git a/config/.env.dev b/config/.env.dev deleted file mode 100644 index 5ea2991f..00000000 --- a/config/.env.dev +++ /dev/null @@ -1,190 +0,0 @@ -# ============================================================================= -# Meldestelle - Development Environment Configuration -# ============================================================================= -# Development-specific environment variables -# ============================================================================= - -# ============================================================================= -# 1. APPLICATION CONFIGURATION -# ============================================================================= -APP_NAME=Meldestelle -APP_VERSION=1.0.0 -APP_DESCRIPTION='Pferdesport Meldestelle System' -APP_ENVIRONMENT=development -APP_HOST=0.0.0.0 - -# Development-specific settings -DEBUG_MODE=true -DEV_HOT_RELOAD=true - -# ============================================================================= -# 2. PORT MANAGEMENT -# ============================================================================= -# Gateway Ports -GATEWAY_PORT=8081 -GATEWAY_ADMIN_PORT=8080 - -# Service Ports -PING_SERVICE_PORT=8082 -MEMBERS_SERVICE_PORT=8083 -HORSES_SERVICE_PORT=8084 -EVENTS_SERVICE_PORT=8085 -MASTERDATA_SERVICE_PORT=8086 -AUTH_SERVICE_PORT=8087 - -# Client Application Ports -WEB_APP_PORT=4000 -DESKTOP_VNC_PORT=5901 -DESKTOP_WEB_VNC_PORT=6080 - -# Infrastructure Ports -CONSUL_PORT=8500 -REDIS_PORT=6379 -KAFKA_PORT=9092 -PROMETHEUS_PORT=9090 -GRAFANA_PORT=3000 - -# ============================================================================= -# 3. DATABASE CONFIGURATION -# ============================================================================= -DB_HOST=localhost -DB_PORT=5432 -DB_NAME=meldestelle -DB_USER=meldestelle -DB_PASSWORD=meldestelle -DB_MAX_POOL_SIZE=10 -DB_MIN_POOL_SIZE=5 -DB_AUTO_MIGRATE=true - -POSTGRES_USER=meldestelle -POSTGRES_PASSWORD=meldestelle -POSTGRES_DB=meldestelle -POSTGRES_EXTERNAL_PORT=5432 - -# ============================================================================= -# 4. REDIS CONFIGURATION -# ============================================================================= -REDIS_EVENT_STORE_HOST=localhost -REDIS_EVENT_STORE_PORT=6379 -REDIS_EVENT_STORE_PASSWORD= -REDIS_EVENT_STORE_DATABASE=0 -REDIS_EVENT_STORE_CONNECTION_TIMEOUT=2000 -REDIS_EVENT_STORE_READ_TIMEOUT=2000 -REDIS_EVENT_STORE_USE_POOLING=true -REDIS_EVENT_STORE_MAX_POOL_SIZE=8 -REDIS_EVENT_STORE_MIN_POOL_SIZE=2 - -REDIS_CACHE_HOST=localhost -REDIS_CACHE_PORT=6379 -REDIS_CACHE_PASSWORD= -REDIS_CACHE_DATABASE=1 - -REDIS_EXTERNAL_PORT=6379 -REDIS_PASSWORD= - -# ============================================================================= -# 5. SECURITY CONFIGURATION -# ============================================================================= -JWT_SECRET=meldestelle-jwt-secret-key-for-development-change-in-production -JWT_ISSUER=meldestelle-api -JWT_AUDIENCE=meldestelle-clients -JWT_REALM=meldestelle -API_KEY=meldestelle-api-key-for-development - -# ============================================================================= -# 6. KEYCLOAK CONFIGURATION -# ============================================================================= -KC_BOOTSTRAP_ADMIN_USERNAME=admin -KC_BOOTSTRAP_ADMIN_PASSWORD=admin -KC_DB=postgres -KC_DB_URL=jdbc:postgresql://postgres:5432/meldestelle -KC_DB_SCHEMA=keycloak -KC_DB_USERNAME=meldestelle -KC_DB_PASSWORD=meldestelle -KC_HOSTNAME=localhost - -# ============================================================================= -# 7. SERVICE DISCOVERY -# ============================================================================= -CONSUL_HOST=consul -CONSUL_ENABLED=true -SERVICE_DISCOVERY_ENABLED=true -SERVICE_DISCOVERY_REGISTER_SERVICES=true -SERVICE_DISCOVERY_HEALTH_CHECK_PATH=/health -SERVICE_DISCOVERY_HEALTH_CHECK_INTERVAL=10 - -# ============================================================================= -# 8. MESSAGING (Kafka) -# ============================================================================= -ZOOKEEPER_CLIENT_PORT=2181 -KAFKA_BROKER_ID=1 -KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 -KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 -KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT -KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT -KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 - -# ============================================================================= -# 9. MONITORING -# ============================================================================= -GF_SECURITY_ADMIN_USER=meldestelle -GF_SECURITY_ADMIN_PASSWORD=meldestelle -GF_USERS_ALLOW_SIGN_UP=false - -METRICS_AUTH_USERNAME=admin -METRICS_AUTH_PASSWORD=metrics - -GRAFANA_HOSTNAME=grafana.meldestelle.local -PROMETHEUS_HOSTNAME=prometheus.meldestelle.local - -# ============================================================================= -# 10. LOGGING CONFIGURATION -# ============================================================================= -LOGGING_LEVEL=DEBUG -LOGGING_REQUESTS=true -LOGGING_RESPONSES=true -LOGGING_REQUEST_HEADERS=true -LOGGING_REQUEST_BODY=true -LOGGING_RESPONSE_HEADERS=true -LOGGING_RESPONSE_BODY=true -LOGGING_STRUCTURED=true -LOGGING_CORRELATION_ID=true -LOGGING_REQUEST_ID_HEADER=X-Request-ID - -# ============================================================================= -# 11. CORS AND RATE LIMITING -# ============================================================================= -SERVER_CORS_ENABLED=true -SERVER_CORS_ALLOWED_ORIGINS=* -RATELIMIT_ENABLED=true -RATELIMIT_GLOBAL_LIMIT=100 -RATELIMIT_GLOBAL_PERIOD_MINUTES=1 -RATELIMIT_INCLUDE_HEADERS=true - -# ============================================================================= -# 12. DOCKER BUILD ARGUMENTS -# ============================================================================= -# Centralized Docker build arguments for compose files -# These mirror the values from docker/build-args/ for standalone compose usage -DOCKER_GRADLE_VERSION=9.0.0 -DOCKER_JAVA_VERSION=21 -DOCKER_NODE_VERSION=20.11.0 -DOCKER_NGINX_VERSION=1.25-alpine -DOCKER_APP_VERSION=1.0.0 -BUILD_DATE=2025-09-13T23:32:00Z - -# Monitoring & Infrastructure versions -DOCKER_PROMETHEUS_VERSION=v2.54.1 -DOCKER_GRAFANA_VERSION=11.3.0 -DOCKER_KEYCLOAK_VERSION=26.4.0 - -# Spring profiles for Docker builds -DOCKER_SPRING_PROFILES_DEFAULT=default -DOCKER_SPRING_PROFILES_DOCKER=docker - -# ============================================================================= -# 13. SPRING PROFILES AND GATEWAY -# ============================================================================= -SPRING_PROFILES_ACTIVE=dev -GATEWAY_ADMIN_USER=admin -GATEWAY_ADMIN_PASSWORD=admin diff --git a/config/.env.example b/config/.env.example new file mode 100644 index 00000000..bbf53b5f --- /dev/null +++ b/config/.env.example @@ -0,0 +1,7 @@ +# DEPRECATED – Single Source of Truth moved to docker/.env.example +# +# This file is no longer used by Docker Compose or any build scripts. +# Please use and copy from: +# docker/.env.example → docker/.env +# +# Reason: Avoid duplicated/conflicting configuration files. diff --git a/config/.env.prod b/config/.env.prod deleted file mode 100644 index 6dc55366..00000000 --- a/config/.env.prod +++ /dev/null @@ -1,164 +0,0 @@ -# ============================================================================= -# Meldestelle - Production Environment Configuration -# ============================================================================= -# Production-specific environment variables -# IMPORTANT: Change all CHANGE_ME values before deployment! -# ============================================================================= - -# ============================================================================= -# 1. APPLICATION CONFIGURATION -# ============================================================================= -APP_NAME=Meldestelle -APP_VERSION=1.0.0 -APP_DESCRIPTION='Pferdesport Meldestelle System' -APP_ENVIRONMENT=production -APP_HOST=0.0.0.0 - -# Production settings -DEBUG_MODE=false -DEV_HOT_RELOAD=false - -# ============================================================================= -# 2. PORT MANAGEMENT -# ============================================================================= -# Gateway Ports -GATEWAY_PORT=8081 -GATEWAY_ADMIN_PORT=8080 - -# Service Ports -PING_SERVICE_PORT=8082 -MEMBERS_SERVICE_PORT=8083 -HORSES_SERVICE_PORT=8084 -EVENTS_SERVICE_PORT=8085 -MASTERDATA_SERVICE_PORT=8086 -AUTH_SERVICE_PORT=8087 - -# Infrastructure Ports -CONSUL_PORT=8500 -REDIS_PORT=6379 -KAFKA_PORT=9092 -PROMETHEUS_PORT=9090 -GRAFANA_PORT=3000 - -# ============================================================================= -# 3. DATABASE CONFIGURATION -# ============================================================================= -DB_HOST=postgres -DB_PORT=5432 -DB_NAME=meldestelle_prod -DB_USER=meldestelle_prod -DB_PASSWORD=CHANGE_ME_STRONG_DB_PASSWORD_HERE -DB_MAX_POOL_SIZE=20 -DB_MIN_POOL_SIZE=10 -DB_AUTO_MIGRATE=false - -POSTGRES_USER=meldestelle_prod -POSTGRES_PASSWORD=CHANGE_ME_STRONG_DB_PASSWORD_HERE -POSTGRES_DB=meldestelle_prod -POSTGRES_EXTERNAL_PORT=5432 - -# ============================================================================= -# 4. REDIS CONFIGURATION -# ============================================================================= -REDIS_EVENT_STORE_HOST=redis -REDIS_EVENT_STORE_PORT=6379 -REDIS_EVENT_STORE_PASSWORD=CHANGE_ME_STRONG_REDIS_PASSWORD_HERE -REDIS_EVENT_STORE_DATABASE=0 -REDIS_EVENT_STORE_CONNECTION_TIMEOUT=5000 -REDIS_EVENT_STORE_READ_TIMEOUT=5000 -REDIS_EVENT_STORE_USE_POOLING=true -REDIS_EVENT_STORE_MAX_POOL_SIZE=20 -REDIS_EVENT_STORE_MIN_POOL_SIZE=5 - -REDIS_CACHE_HOST=redis -REDIS_CACHE_PORT=6379 -REDIS_CACHE_PASSWORD=CHANGE_ME_STRONG_REDIS_PASSWORD_HERE -REDIS_CACHE_DATABASE=1 - -REDIS_EXTERNAL_PORT=6379 -REDIS_PASSWORD=CHANGE_ME_STRONG_REDIS_PASSWORD_HERE - -# ============================================================================= -# 5. SECURITY CONFIGURATION -# ============================================================================= -JWT_SECRET=CHANGE_ME_STRONG_JWT_SECRET_AT_LEAST_256_BITS_HERE -JWT_ISSUER=meldestelle-api-prod -JWT_AUDIENCE=meldestelle-clients-prod -JWT_REALM=meldestelle-prod -API_KEY=CHANGE_ME_STRONG_API_KEY_HERE - -# ============================================================================= -# 6. KEYCLOAK CONFIGURATION -# ============================================================================= -KEYCLOAK_ADMIN=CHANGE_ME_ADMIN_USERNAME -KEYCLOAK_ADMIN_PASSWORD=CHANGE_ME_STRONG_ADMIN_PASSWORD_HERE -KC_DB=postgres -KC_DB_URL=jdbc:postgresql://postgres:5432/keycloak_prod -KC_DB_USERNAME=keycloak_prod -KC_DB_PASSWORD=CHANGE_ME_STRONG_KEYCLOAK_DB_PASSWORD_HERE -KC_HOSTNAME=auth.yourdomain.com - -# ============================================================================= -# 7. SERVICE DISCOVERY -# ============================================================================= -CONSUL_HOST=consul -CONSUL_ENABLED=true -SERVICE_DISCOVERY_ENABLED=true -SERVICE_DISCOVERY_REGISTER_SERVICES=true -SERVICE_DISCOVERY_HEALTH_CHECK_PATH=/health -SERVICE_DISCOVERY_HEALTH_CHECK_INTERVAL=30 - -# ============================================================================= -# 8. MESSAGING (Kafka) -# ============================================================================= -ZOOKEEPER_CLIENT_PORT=2181 -KAFKA_BROKER_ID=1 -KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 -KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 -KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT -KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT -KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 - -# ============================================================================= -# 9. MONITORING -# ============================================================================= -GF_SECURITY_ADMIN_USER=CHANGE_ME_GRAFANA_ADMIN_USERNAME -GF_SECURITY_ADMIN_PASSWORD=CHANGE_ME_STRONG_GRAFANA_PASSWORD_HERE -GF_USERS_ALLOW_SIGN_UP=false - -METRICS_AUTH_USERNAME=CHANGE_ME_METRICS_USERNAME -METRICS_AUTH_PASSWORD=CHANGE_ME_STRONG_METRICS_PASSWORD_HERE - -GRAFANA_HOSTNAME=monitoring.yourdomain.com -PROMETHEUS_HOSTNAME=metrics.yourdomain.com - -# ============================================================================= -# 10. LOGGING CONFIGURATION -# ============================================================================= -LOGGING_LEVEL=INFO -LOGGING_REQUESTS=false -LOGGING_RESPONSES=false -LOGGING_REQUEST_HEADERS=false -LOGGING_REQUEST_BODY=false -LOGGING_RESPONSE_HEADERS=false -LOGGING_RESPONSE_BODY=false -LOGGING_STRUCTURED=true -LOGGING_CORRELATION_ID=true -LOGGING_REQUEST_ID_HEADER=X-Request-ID - -# ============================================================================= -# 11. CORS AND RATE LIMITING -# ============================================================================= -SERVER_CORS_ENABLED=true -SERVER_CORS_ALLOWED_ORIGINS=https://yourdomain.com,https://www.yourdomain.com -RATELIMIT_ENABLED=true -RATELIMIT_GLOBAL_LIMIT=1000 -RATELIMIT_GLOBAL_PERIOD_MINUTES=1 -RATELIMIT_INCLUDE_HEADERS=true - -# ============================================================================= -# 12. SPRING PROFILES AND GATEWAY -# ============================================================================= -SPRING_PROFILES_ACTIVE=prod -GATEWAY_ADMIN_USER=CHANGE_ME_GATEWAY_ADMIN_USERNAME -GATEWAY_ADMIN_PASSWORD=CHANGE_ME_STRONG_GATEWAY_ADMIN_PASSWORD_HERE diff --git a/config/.env.staging b/config/.env.staging deleted file mode 100644 index 024fd97c..00000000 --- a/config/.env.staging +++ /dev/null @@ -1,164 +0,0 @@ -# ============================================================================= -# Meldestelle - Staging Environment Configuration -# ============================================================================= -# Staging-specific environment variables (production-like but for testing) -# ============================================================================= - -# ============================================================================= -# 1. APPLICATION CONFIGURATION -# ============================================================================= -APP_NAME=Meldestelle -APP_VERSION=1.0.0 -APP_DESCRIPTION='Pferdesport Meldestelle System' -APP_ENVIRONMENT=staging -APP_HOST=0.0.0.0 - -# Staging settings (production-like but with some debugging) -DEBUG_MODE=false -DEV_HOT_RELOAD=false - -# ============================================================================= -# 2. PORT MANAGEMENT -# ============================================================================= -# Gateway Ports -GATEWAY_PORT=8081 -GATEWAY_ADMIN_PORT=8080 - -# Service Ports -PING_SERVICE_PORT=8082 -MEMBERS_SERVICE_PORT=8083 -HORSES_SERVICE_PORT=8084 -EVENTS_SERVICE_PORT=8085 -MASTERDATA_SERVICE_PORT=8086 -AUTH_SERVICE_PORT=8087 - -# Infrastructure Ports -CONSUL_PORT=8500 -REDIS_PORT=6379 -KAFKA_PORT=9092 -PROMETHEUS_PORT=9090 -GRAFANA_PORT=3000 - -# ============================================================================= -# 3. DATABASE CONFIGURATION -# ============================================================================= -DB_HOST=postgres -DB_PORT=5432 -DB_NAME=meldestelle_staging -DB_USER=meldestelle_staging -DB_PASSWORD=staging_password_change_me -DB_MAX_POOL_SIZE=15 -DB_MIN_POOL_SIZE=5 -DB_AUTO_MIGRATE=true - -POSTGRES_USER=meldestelle_staging -POSTGRES_PASSWORD=staging_password_change_me -POSTGRES_DB=meldestelle_staging -POSTGRES_EXTERNAL_PORT=5432 - -# ============================================================================= -# 4. REDIS CONFIGURATION -# ============================================================================= -REDIS_EVENT_STORE_HOST=redis -REDIS_EVENT_STORE_PORT=6379 -REDIS_EVENT_STORE_PASSWORD=staging_redis_password -REDIS_EVENT_STORE_DATABASE=0 -REDIS_EVENT_STORE_CONNECTION_TIMEOUT=3000 -REDIS_EVENT_STORE_READ_TIMEOUT=3000 -REDIS_EVENT_STORE_USE_POOLING=true -REDIS_EVENT_STORE_MAX_POOL_SIZE=15 -REDIS_EVENT_STORE_MIN_POOL_SIZE=3 - -REDIS_CACHE_HOST=redis -REDIS_CACHE_PORT=6379 -REDIS_CACHE_PASSWORD=staging_redis_password -REDIS_CACHE_DATABASE=1 - -REDIS_EXTERNAL_PORT=6379 -REDIS_PASSWORD=staging_redis_password - -# ============================================================================= -# 5. SECURITY CONFIGURATION -# ============================================================================= -JWT_SECRET=staging-jwt-secret-key-not-for-production-use -JWT_ISSUER=meldestelle-api-staging -JWT_AUDIENCE=meldestelle-clients-staging -JWT_REALM=meldestelle-staging -API_KEY=staging-api-key-change-me - -# ============================================================================= -# 6. KEYCLOAK CONFIGURATION -# ============================================================================= -KEYCLOAK_ADMIN=admin -KEYCLOAK_ADMIN_PASSWORD=admin -KC_DB=postgres -KC_DB_URL=jdbc:postgresql://postgres:5432/meldestelle_staging -KC_DB_SCHEMA=keycloak -KC_DB_USERNAME=meldestelle_staging -KC_DB_PASSWORD=staging_password_change_me -KC_HOSTNAME=localhost - -# ============================================================================= -# 7. SERVICE DISCOVERY -# ============================================================================= -CONSUL_HOST=consul -CONSUL_ENABLED=true -SERVICE_DISCOVERY_ENABLED=true -SERVICE_DISCOVERY_REGISTER_SERVICES=true -SERVICE_DISCOVERY_HEALTH_CHECK_PATH=/health -SERVICE_DISCOVERY_HEALTH_CHECK_INTERVAL=15 - -# ============================================================================= -# 8. MESSAGING (Kafka) -# ============================================================================= -ZOOKEEPER_CLIENT_PORT=2181 -KAFKA_BROKER_ID=1 -KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 -KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 -KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT -KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT -KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 - -# ============================================================================= -# 9. MONITORING -# ============================================================================= -GF_SECURITY_ADMIN_USER=staging_admin -GF_SECURITY_ADMIN_PASSWORD=staging_grafana_password -GF_USERS_ALLOW_SIGN_UP=false - -METRICS_AUTH_USERNAME=staging_metrics -METRICS_AUTH_PASSWORD=staging_metrics_password - -GRAFANA_HOSTNAME=grafana-staging.meldestelle.local -PROMETHEUS_HOSTNAME=prometheus-staging.meldestelle.local - -# ============================================================================= -# 10. LOGGING CONFIGURATION -# ============================================================================= -LOGGING_LEVEL=INFO -LOGGING_REQUESTS=true -LOGGING_RESPONSES=false -LOGGING_REQUEST_HEADERS=false -LOGGING_REQUEST_BODY=false -LOGGING_RESPONSE_HEADERS=false -LOGGING_RESPONSE_BODY=false -LOGGING_STRUCTURED=true -LOGGING_CORRELATION_ID=true -LOGGING_REQUEST_ID_HEADER=X-Request-ID - -# ============================================================================= -# 11. CORS AND RATE LIMITING -# ============================================================================= -SERVER_CORS_ENABLED=true -SERVER_CORS_ALLOWED_ORIGINS=https://staging.meldestelle.local,https://app-staging.meldestelle.local -RATELIMIT_ENABLED=true -RATELIMIT_GLOBAL_LIMIT=500 -RATELIMIT_GLOBAL_PERIOD_MINUTES=1 -RATELIMIT_INCLUDE_HEADERS=true - -# ============================================================================= -# 12. SPRING PROFILES AND GATEWAY -# ============================================================================= -SPRING_PROFILES_ACTIVE=staging -GATEWAY_ADMIN_USER=staging_gateway_admin -GATEWAY_ADMIN_PASSWORD=staging_gateway_password diff --git a/config/.env.template b/config/.env.template deleted file mode 100644 index dc6f7b81..00000000 --- a/config/.env.template +++ /dev/null @@ -1,178 +0,0 @@ -# ============================================================================= -# Meldestelle - Umgebungsvariablen Vorlage -# ============================================================================= -# Dies ist die SINGLE SOURCE OF TRUTH für alle Umgebungsvariablen. -# Kopieren Sie zu .env.dev, .env.prod, .env.staging oder .env.test und anpassen. -# -# ⚠️ SICHERHEITSWARNUNG: -# - Niemals Produktions-Secrets in die Versionskontrolle committen -# - JWT_SECRET in der Produktion ändern -# - Starke Passwörter für Produktionsumgebungen verwenden -# - API-Schlüssel regelmäßig rotieren -# ============================================================================= - -# ============================================================================= -# 1. ANWENDUNGSKONFIGURATION -# ============================================================================= -APP_NAME=Meldestelle -APP_VERSION=1.0.0 -APP_DESCRIPTION='Pferdesport Meldestelle System' -APP_ENVIRONMENT=development -APP_HOST=0.0.0.0 - -# Entwicklungsspezifische Einstellungen -DEBUG_MODE=true -DEV_HOT_RELOAD=true - -# ============================================================================= -# 2. PORT-VERWALTUNG - SINGLE SOURCE OF TRUTH -# ============================================================================= -# Gateway Ports -GATEWAY_PORT=8081 -GATEWAY_ADMIN_PORT=8080 - -# Service Ports (eindeutige Zuteilung) -PING_SERVICE_PORT=8082 -MEMBERS_SERVICE_PORT=8083 -HORSES_SERVICE_PORT=8084 -EVENTS_SERVICE_PORT=8085 -MASTERDATA_SERVICE_PORT=8086 -AUTH_SERVICE_PORT=8087 - -# Infrastruktur Ports -CONSUL_PORT=8500 -REDIS_PORT=6379 -KAFKA_PORT=9092 -PROMETHEUS_PORT=9090 -GRAFANA_PORT=3000 - -# ============================================================================= -# 3. DATENBANK-KONFIGURATION (PostgreSQL) -# ============================================================================= -# Anwendungs-Datenbankeinstellungen -DB_HOST=localhost -DB_PORT=5432 -DB_NAME=meldestelle -DB_USER=meldestelle -DB_PASSWORD=meldestelle -DB_MAX_POOL_SIZE=10 -DB_MIN_POOL_SIZE=5 -DB_AUTO_MIGRATE=true - -# Docker PostgreSQL Container-Einstellungen -POSTGRES_USER=meldestelle -POSTGRES_PASSWORD=meldestelle -POSTGRES_DB=meldestelle -POSTGRES_EXTERNAL_PORT=5432 - -# ============================================================================= -# 4. REDIS-KONFIGURATION -# ============================================================================= -# Event Store Konfiguration -REDIS_EVENT_STORE_HOST=localhost -REDIS_EVENT_STORE_PORT=6379 -REDIS_EVENT_STORE_PASSWORD= -REDIS_EVENT_STORE_DATABASE=0 -REDIS_EVENT_STORE_CONNECTION_TIMEOUT=2000 -REDIS_EVENT_STORE_READ_TIMEOUT=2000 -REDIS_EVENT_STORE_USE_POOLING=true -REDIS_EVENT_STORE_MAX_POOL_SIZE=8 -REDIS_EVENT_STORE_MIN_POOL_SIZE=2 - -# Cache-Konfiguration -REDIS_CACHE_HOST=localhost -REDIS_CACHE_PORT=6379 -REDIS_CACHE_PASSWORD= -REDIS_CACHE_DATABASE=1 - -# Redis Docker-Einstellungen -REDIS_EXTERNAL_PORT=6379 -REDIS_PASSWORD= - -# ============================================================================= -# 5. SICHERHEITSKONFIGURATION -# ============================================================================= -JWT_SECRET=meldestelle-jwt-secret-key-for-development-change-in-production -JWT_ISSUER=meldestelle-api -JWT_AUDIENCE=meldestelle-clients -JWT_REALM=meldestelle -API_KEY=meldestelle-api-key-for-development - -# ============================================================================= -# 6. KEYCLOAK CONFIGURATION -# ============================================================================= -KEYCLOAK_ADMIN=admin -KEYCLOAK_ADMIN_PASSWORD=admin -KC_DB=postgres -KC_DB_URL=jdbc:postgresql://postgres:5432/keycloak -KC_DB_USERNAME=meldestelle -KC_DB_PASSWORD=meldestelle -KC_HOSTNAME=auth.meldestelle.local - -# ============================================================================= -# 7. SERVICE DISCOVERY (Consul) -# ============================================================================= -CONSUL_HOST=consul -CONSUL_ENABLED=true -SERVICE_DISCOVERY_ENABLED=true -SERVICE_DISCOVERY_REGISTER_SERVICES=true -SERVICE_DISCOVERY_HEALTH_CHECK_PATH=/health -SERVICE_DISCOVERY_HEALTH_CHECK_INTERVAL=10 - -# ============================================================================= -# 8. MESSAGING (Kafka) -# ============================================================================= -ZOOKEEPER_CLIENT_PORT=2181 -KAFKA_BROKER_ID=1 -KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 -KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 -KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT -KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT -KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 - -# ============================================================================= -# 9. MONITORING -# ============================================================================= -# Grafana Configuration -GF_SECURITY_ADMIN_USER=admin -GF_SECURITY_ADMIN_PASSWORD=admin -GF_USERS_ALLOW_SIGN_UP=false - -# Metrics Authentication -METRICS_AUTH_USERNAME=admin -METRICS_AUTH_PASSWORD=metrics - -# Monitoring hostnames -GRAFANA_HOSTNAME=grafana.meldestelle.local -PROMETHEUS_HOSTNAME=prometheus.meldestelle.local - -# ============================================================================= -# 10. LOGGING CONFIGURATION -# ============================================================================= -LOGGING_LEVEL=DEBUG -LOGGING_REQUESTS=true -LOGGING_RESPONSES=true -LOGGING_REQUEST_HEADERS=true -LOGGING_REQUEST_BODY=true -LOGGING_RESPONSE_HEADERS=true -LOGGING_RESPONSE_BODY=true -LOGGING_STRUCTURED=true -LOGGING_CORRELATION_ID=true -LOGGING_REQUEST_ID_HEADER=X-Request-ID - -# ============================================================================= -# 11. CORS AND RATE LIMITING -# ============================================================================= -SERVER_CORS_ENABLED=true -SERVER_CORS_ALLOWED_ORIGINS=* -RATELIMIT_ENABLED=true -RATELIMIT_GLOBAL_LIMIT=100 -RATELIMIT_GLOBAL_PERIOD_MINUTES=1 -RATELIMIT_INCLUDE_HEADERS=true - -# ============================================================================= -# 12. SPRING PROFILES AND GATEWAY -# ============================================================================= -SPRING_PROFILES_ACTIVE=dev -GATEWAY_ADMIN_USER=admin -GATEWAY_ADMIN_PASSWORD=admin diff --git a/config/.env.test b/config/.env.test deleted file mode 100644 index c1186e42..00000000 --- a/config/.env.test +++ /dev/null @@ -1,163 +0,0 @@ -# ============================================================================= -# Meldestelle - Test Environment Configuration -# ============================================================================= -# Test-specific environment variables (optimized for automated testing) -# ============================================================================= - -# ============================================================================= -# 1. APPLICATION CONFIGURATION -# ============================================================================= -APP_NAME=Meldestelle -APP_VERSION=1.0.0 -APP_DESCRIPTION='Pferdesport Meldestelle System' -APP_ENVIRONMENT=test -APP_HOST=localhost - -# Test settings (fast and minimal for CI/CD) -DEBUG_MODE=true -DEV_HOT_RELOAD=false - -# ============================================================================= -# 2. PORT MANAGEMENT -# ============================================================================= -# Gateway Ports (use different ports to avoid conflicts during parallel testing) -GATEWAY_PORT=9081 -GATEWAY_ADMIN_PORT=9080 - -# Service Ports -PING_SERVICE_PORT=9082 -MEMBERS_SERVICE_PORT=9083 -HORSES_SERVICE_PORT=9084 -EVENTS_SERVICE_PORT=9085 -MASTERDATA_SERVICE_PORT=9086 -AUTH_SERVICE_PORT=9087 - -# Infrastructure Ports -CONSUL_PORT=9500 -REDIS_PORT=9379 -KAFKA_PORT=9092 -PROMETHEUS_PORT=9090 -GRAFANA_PORT=9000 - -# ============================================================================= -# 3. DATABASE CONFIGURATION -# ============================================================================= -DB_HOST=localhost -DB_PORT=5433 -DB_NAME=meldestelle_test -DB_USER=meldestelle_test -DB_PASSWORD=test_password -DB_MAX_POOL_SIZE=5 -DB_MIN_POOL_SIZE=1 -DB_AUTO_MIGRATE=true - -POSTGRES_USER=meldestelle_test -POSTGRES_PASSWORD=test_password -POSTGRES_DB=meldestelle_test -POSTGRES_EXTERNAL_PORT=5433 - -# ============================================================================= -# 4. REDIS CONFIGURATION -# ============================================================================= -REDIS_EVENT_STORE_HOST=localhost -REDIS_EVENT_STORE_PORT=9379 -REDIS_EVENT_STORE_PASSWORD= -REDIS_EVENT_STORE_DATABASE=0 -REDIS_EVENT_STORE_CONNECTION_TIMEOUT=1000 -REDIS_EVENT_STORE_READ_TIMEOUT=1000 -REDIS_EVENT_STORE_USE_POOLING=true -REDIS_EVENT_STORE_MAX_POOL_SIZE=3 -REDIS_EVENT_STORE_MIN_POOL_SIZE=1 - -REDIS_CACHE_HOST=localhost -REDIS_CACHE_PORT=9379 -REDIS_CACHE_PASSWORD= -REDIS_CACHE_DATABASE=1 - -REDIS_EXTERNAL_PORT=9379 -REDIS_PASSWORD= - -# ============================================================================= -# 5. SECURITY CONFIGURATION -# ============================================================================= -JWT_SECRET=test-jwt-secret-key-for-testing-only -JWT_ISSUER=meldestelle-api-test -JWT_AUDIENCE=meldestelle-clients-test -JWT_REALM=meldestelle-test -API_KEY=test-api-key - -# ============================================================================= -# 6. KEYCLOAK CONFIGURATION -# ============================================================================= -KEYCLOAK_ADMIN=test_admin -KEYCLOAK_ADMIN_PASSWORD=test_password -KC_DB=postgres -KC_DB_URL=jdbc:postgresql://localhost:5433/keycloak_test -KC_DB_USERNAME=keycloak_test -KC_DB_PASSWORD=test_password -KC_HOSTNAME=localhost - -# ============================================================================= -# 7. SERVICE DISCOVERY -# ============================================================================= -CONSUL_HOST=localhost -CONSUL_ENABLED=false -SERVICE_DISCOVERY_ENABLED=false -SERVICE_DISCOVERY_REGISTER_SERVICES=false -SERVICE_DISCOVERY_HEALTH_CHECK_PATH=/health -SERVICE_DISCOVERY_HEALTH_CHECK_INTERVAL=5 - -# ============================================================================= -# 8. MESSAGING (Kafka) -# ============================================================================= -ZOOKEEPER_CLIENT_PORT=2182 -KAFKA_BROKER_ID=1 -KAFKA_ZOOKEEPER_CONNECT=localhost:2182 -KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 -KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT -KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT -KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 - -# ============================================================================= -# 9. MONITORING -# ============================================================================= -GF_SECURITY_ADMIN_USER=test_admin -GF_SECURITY_ADMIN_PASSWORD=test_password -GF_USERS_ALLOW_SIGN_UP=false - -METRICS_AUTH_USERNAME=test_metrics -METRICS_AUTH_PASSWORD=test_password - -GRAFANA_HOSTNAME=localhost -PROMETHEUS_HOSTNAME=localhost - -# ============================================================================= -# 10. LOGGING CONFIGURATION -# ============================================================================= -LOGGING_LEVEL=DEBUG -LOGGING_REQUESTS=true -LOGGING_RESPONSES=true -LOGGING_REQUEST_HEADERS=true -LOGGING_REQUEST_BODY=true -LOGGING_RESPONSE_HEADERS=true -LOGGING_RESPONSE_BODY=true -LOGGING_STRUCTURED=true -LOGGING_CORRELATION_ID=true -LOGGING_REQUEST_ID_HEADER=X-Request-ID - -# ============================================================================= -# 11. CORS AND RATE LIMITING -# ============================================================================= -SERVER_CORS_ENABLED=true -SERVER_CORS_ALLOWED_ORIGINS=* -RATELIMIT_ENABLED=false -RATELIMIT_GLOBAL_LIMIT=10000 -RATELIMIT_GLOBAL_PERIOD_MINUTES=1 -RATELIMIT_INCLUDE_HEADERS=true - -# ============================================================================= -# 12. SPRING PROFILES AND GATEWAY -# ============================================================================= -SPRING_PROFILES_ACTIVE=test -GATEWAY_ADMIN_USER=test_admin -GATEWAY_ADMIN_PASSWORD=test_password diff --git a/config/README.md b/config/README.md deleted file mode 100644 index 274f77f2..00000000 --- a/config/README.md +++ /dev/null @@ -1,269 +0,0 @@ -# Zentrale Konfigurationsverwaltung - Single Source of Truth - -> **Version:** 4.0.0 -> **Datum:** 15. September 2025 -> **Status:** ✅ Produktiv - Eliminiert 38+ Port-Redundanzen und 72+ Spring-Profile-Duplikate - -## 🎯 Überblick - -Das **zentrale Konfigurationssystem** eliminiert Redundanzen über das gesamte Meldestelle-Projekt und stellt sicher, dass alle Konfigurationswerte aus einer **einzigen Quelle der Wahrheit** stammen. - -### Vor der Zentralisierung (Problem) - -``` -Port 8082 war in 38+ Dateien dupliziert: -├── gradle.properties -├── docker-compose.services.yml -├── dockerfiles/services/ping-service/Dockerfile -├── scripts/test/integration-test.sh -├── config/monitoring/prometheus.dev.yml -└── ... 33 weitere Dateien! -``` - -### Nach der Zentralisierung (Lösung) - -``` -Port 8082 einmalig in config/central.toml definiert: -├── config/central.toml [SINGLE SOURCE OF TRUTH] -└── scripts/config-sync.sh sync [Automatische Synchronisation] - └── 38+ Dateien automatisch aktualisiert ✓ -``` - -## 📁 Verzeichnisstruktur - -``` -config/ -├── central.toml # 🎯 MASTER-Konfigurationsdatei -├── README.md # 📖 Diese Dokumentation -├── .env.template # 🔧 Environment-Variables Template (Legacy) -└── monitoring/ # 📊 Monitoring-Konfigurationen - ├── prometheus.yml - ├── prometheus.dev.yml - └── grafana/ -``` - -## 🛠️ Verwendung - -### Schnellstart - -```bash -# 1. Aktuelle Konfiguration anzeigen -./scripts/config-sync.sh status - -# 2. Alle Konfigurationen synchronisieren -./scripts/config-sync.sh sync - -# 3. Konfiguration validieren -./scripts/config-sync.sh validate -``` - -### Port ändern (Beispiel) - -```bash -# 1. central.toml bearbeiten -vim config/central.toml - -[ports] -ping-service = 8092 # Geändert von 8082 - -# 2. Alle abhängigen Dateien aktualisieren -./scripts/config-sync.sh sync - -# ✅ Ergebnis: 38+ Dateien automatisch synchronisiert! -``` - -### Spring Profile ändern - -```bash -# 1. central.toml bearbeiten -[spring-profiles.defaults] -services = "production" # Geändert von "docker" - -# 2. Synchronisieren -./scripts/config-sync.sh sync - -# ✅ Ergebnis: 72+ Profile-Referenzen automatisch aktualisiert! -``` - -## 📋 Konfigurationsbereiche - -### 1. **Ports** - Eliminiert 38+ Redundanzen - -```toml -[ports] -# Infrastructure Services -api-gateway = 8081 -auth-server = 8087 -monitoring-server = 8088 - -# Application Services -ping-service = 8082 -members-service = 8083 -horses-service = 8084 -events-service = 8085 -masterdata-service = 8086 - -# External Infrastructure -postgres = 5432 -redis = 6379 -consul = 8500 -prometheus = 9090 -grafana = 3000 -``` - -**Synchronisiert folgende Dateien:** - -- `gradle.properties` - Service-Port-Eigenschaften -- `docker-compose*.yml` - Port-Mappings und Environment-Variablen -- `dockerfiles/*/Dockerfile` - EXPOSE-Statements -- `scripts/test/*.sh` - Test-Endpunkt-URLs -- `config/monitoring/*.yml` - Prometheus-Targets -- Und 25+ weitere Dateien! - -### 2. **Spring Profiles** - Eliminiert 72+ Duplikate - -```toml -[spring-profiles] -default = "default" -development = "dev" -docker = "docker" -production = "prod" -test = "test" - -[spring-profiles.defaults] -infrastructure = "default" # Infrastructure Services -services = "docker" # Application Services -clients = "dev" # Client Applications -``` - -**Synchronisiert folgende Dateien:** - -- Alle `dockerfiles/*/Dockerfile` - `SPRING_PROFILES_ACTIVE` Build-Args -- `docker-compose*.yml` - Spring-Profile Environment-Variablen -- `docker/build-args/*.env` - Build-Argument-Dateien -- Und 60+ weitere Referenzen! - -### 3. **Service Discovery** - Standardisiert URLs - -```toml -[services.ping-service] -name = "ping-service" -port = 8082 -internal-host = "ping-service" -external-host = "localhost" -internal-url = "http://ping-service:8082" -external-url = "http://localhost:8082" -health-endpoint = "/actuator/health/readiness" -metrics-endpoint = "/actuator/prometheus" -info-endpoint = "/actuator/info" -``` - -## 🚀 Scripts und Automatisierung - -### `scripts/config-sync.sh` - Haupttool - -```bash -# Alle Konfigurationen synchronisieren -./scripts/config-sync.sh sync - -# Nur bestimmte Bereiche synchronisieren -./scripts/config-sync.sh gradle # gradle.properties -./scripts/config-sync.sh compose # Docker Compose files -./scripts/config-sync.sh env # Environment files -./scripts/config-sync.sh docker-args # Docker build arguments -./scripts/config-sync.sh monitoring # Prometheus/Grafana config -./scripts/config-sync.sh tests # Test scripts - -# Status und Validierung -./scripts/config-sync.sh status # Aktuelle Konfiguration anzeigen -./scripts/config-sync.sh validate # TOML-Syntax validieren - -# Hilfe -./scripts/config-sync.sh --help -``` - -## 🎯 Best Practices - -### ✅ DO (Empfohlen) - -```bash -# Vor Änderungen Status prüfen -./scripts/config-sync.sh status - -# Nach Änderungen validieren -./scripts/config-sync.sh validate - -# Regelmäßig synchronisieren -./scripts/config-sync.sh sync - -# Backups vor wichtigen Änderungen -cp config/central.toml config/central.toml.backup -``` - -### ❌ DON'T (Vermeiden) - -```bash -# ❌ Niemals direkte Datei-Bearbeitung -vim docker-compose.yml # Änderungen gehen verloren! -vim gradle.properties # Wird überschrieben! - -# ✅ Stattdessen zentrale Konfiguration verwenden -vim config/central.toml -./scripts/config-sync.sh sync -``` - -## 🔍 Debugging und Troubleshooting - -### Häufige Probleme - -#### Problem: Synchronisation schlägt fehl - -```bash -# Lösung: Validierung prüfen -./scripts/config-sync.sh validate - -# TOML-Syntax-Fehler beheben -vim config/central.toml -``` - -#### Problem: Inkonsistente Konfiguration - -```bash -# Lösung: Status prüfen und re-synchronisieren -./scripts/config-sync.sh status -./scripts/config-sync.sh sync -``` - -#### Problem: Backup wiederherstellen - -```bash -# Backups anzeigen -ls -la *.bak.* - -# Wiederherstellen -cp gradle.properties.bak.20250915_103927 gradle.properties -``` - -### Validierung - -```bash -# Umfassende Validierung -./scripts/config-sync.sh validate - -# Prüft: -# ✓ TOML-Syntax -# ✓ Duplicate Sections -# ✓ Port-Konflikte -# ✓ Ungültige Werte -``` - -## 🚀 Migration und Integration - -Die zentrale Konfigurationsverwaltung ist **rückwärtskompatibel** und kann schrittweise eingeführt werden: - -1. **config/central.toml** erstellen ✅ -2. **scripts/config-sync.sh** ausführen ✅ -3. **Backups prüfen** und validieren ✅ -4. **Entwickler-Workflow** anpassen ✅ - -**🎉 Mit der zentralen Konfigurationsverwaltung haben Sie einen wartungsfreundlichen, skalierbaren und fehlerresistenten Ansatz für die Verwaltung aller Konfigurationswerte in Ihrem Meldestelle-Projekt!** diff --git a/config/detekt/detekt.yml b/config/detekt/detekt.yml new file mode 100644 index 00000000..272018e3 --- /dev/null +++ b/config/detekt/detekt.yml @@ -0,0 +1,52 @@ +build: + maxIssues: 0 + excludeCorrectable: false + +config: + validation: true + warningsAsErrors: false + +processors: + active: true + +console-reports: + active: true + exclude: + - 'ProjectStatisticsReport' + - 'ComplexityReport' + - 'NotificationReport' + +comments: + active: true + AbsentOrWrongFileLicense: + active: false + +style: + active: true + MagicNumber: + active: false + WildcardImport: + active: false + MaxLineLength: + active: true + maxLineLength: 140 + UnusedImports: + active: true + +complexity: + active: true + LongMethod: + active: true + threshold: 80 + TooManyFunctions: + active: true + thresholdInClasses: 30 + +performance: + active: true + +potential-bugs: + active: true + +exceptions: + active: true diff --git a/config/postgres/postgresql.conf b/config/postgres/postgresql.conf index 507689ad..dea4e80c 100644 --- a/config/postgres/postgresql.conf +++ b/config/postgres/postgresql.conf @@ -7,7 +7,7 @@ max_connections = 100 superuser_reserved_connections = 3 # Memory Settings -# These will be overridden by environment variables in docker-compose.yml +# These will be overridden by environment variables in docker-compose.yaml shared_buffers = 256MB # min 128kB work_mem = 16MB # min 64kB maintenance_work_mem = 64MB # min 1MB diff --git a/.env b/docker/.env similarity index 86% rename from .env rename to docker/.env index 8b623a70..5e831ef4 100644 --- a/.env +++ b/docker/.env @@ -51,7 +51,13 @@ GATEWAY_SERVER_PORT=8081 PING_SERVICE_PORT=8082:8082 PING_DEBUG_PORT=5006:5006 -# --- CLIENT APPLICATIONS --- -WEB_APP_PORT=4000:4000 +# --- WEB CLIENTS --- +# Web-App (Nginx inside container listens on 80) +WEB_APP_PORT=8080:80 + +# Desktop-App (VNC + noVNC) DESKTOP_APP_VNC_PORT=5901:5901 DESKTOP_APP_NOVNC_PORT=6080:6080 + +# Optional: Redis Passwort aktivieren (setzt --requirepass) +# REDIS_PASSWORD=change-me-strong diff --git a/docker/.env.example b/docker/.env.example index 441e1f8c..7c70fdd5 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -1,3 +1,31 @@ +<<<<<<< HEAD +# ========================================== +# Meldestelle – Docker Compose Environment +# Single Source of Truth (SSoT) +# ========================================== + +# --- PROJECT --- +COMPOSE_PROJECT_NAME=meldestelle + +# --- PORT MAPPINGS (host:container) --- +POSTGRES_PORT=5432:5432 +REDIS_PORT=6379:6379 +KC_PORT=8180:8080 +PGADMIN_PORT=8888:80 +PROMETHEUS_PORT=9090:9090 +GF_PORT=3000:3000 +CONSUL_PORT=8500:8500 +GATEWAY_PORT=8081:8081 +GATEWAY_DEBUG_PORT=5005:5005 +GATEWAY_SERVER_PORT=8081 +PING_SERVICE_PORT=8082:8082 +PING_DEBUG_PORT=5006:5006 +WEB_APP_PORT=4000:4000 +DESKTOP_APP_VNC_PORT=5901:5901 +DESKTOP_APP_NOVNC_PORT=6080:6080 + +# --- POSTGRES --- +======= # Core project name used as prefix for container names COMPOSE_PROJECT_NAME=meldestelle @@ -18,15 +46,35 @@ DESKTOP_APP_VNC_PORT=5900:5900 DESKTOP_APP_NOVNC_PORT=6080:6080 # Postgres +>>>>>>> origin/main POSTGRES_USER=meldestelle POSTGRES_PASSWORD=meldestelle POSTGRES_DB=meldestelle +<<<<<<< HEAD +# --- REDIS --- +# Optional password for Redis; leave empty to disable authentication in dev +REDIS_PASSWORD= + +# --- KEYCLOAK --- +======= # Keycloak +>>>>>>> origin/main KC_ADMIN_USER=admin KC_ADMIN_PASSWORD=admin KC_HOSTNAME=localhost +<<<<<<< HEAD +# --- PGADMIN --- +PGADMIN_EMAIL=admin@example.com +PGADMIN_PASSWORD=admin + +# --- GRAFANA --- +GF_ADMIN_USER=admin +GF_ADMIN_PASSWORD=admin + +# --- DOCKER BUILD OVERRIDES (optional) --- +======= # PgAdmin PGADMIN_EMAIL=admin@example.com PGADMIN_PASSWORD=admin @@ -36,6 +84,7 @@ GF_ADMIN_USER=admin GF_ADMIN_PASSWORD=admin # Docker build versions (optional overrides) +>>>>>>> origin/main DOCKER_GRADLE_VERSION=9.1.0 DOCKER_JAVA_VERSION=21 DOCKER_NODE_VERSION=22.21.0 diff --git a/docker/compose.hardcoded.yaml b/docker/compose.hardcoded.yaml new file mode 100644 index 00000000..edf08806 --- /dev/null +++ b/docker/compose.hardcoded.yaml @@ -0,0 +1,153 @@ +name: meldestelle-hardcoded + +services: + # --- DATENBANK --- + postgres: + image: postgres:16-alpine + container_name: meldestelle-postgres + restart: unless-stopped + ports: + - "5432:5432" + environment: + POSTGRES_USER: pg-user + POSTGRES_PASSWORD: pg-password + POSTGRES_DB: meldestelle + volumes: + - postgres-data:/var/lib/postgresql/data + # Falls du Init-Scripte hast, lassen wir die erstmal weg, + # um Fehlerquellen zu reduzieren, oder lassen den Pfad, falls er existiert: + - ./docker/core/postgres:/docker-entrypoint-initdb.d:Z + healthcheck: + test: [ "CMD-SHELL", "pg_isready -U pg-user -d meldestelle" ] + interval: 1s + timeout: 5s + retries: 3 + start_period: 30s + networks: + - meldestelle-network + + # --- DATENBANK-MANAGEMENT-TOOL --- + pgadmin: + image: dpage/pgadmin4:8 + container_name: pgadmin4_container + restart: unless-stopped + ports: + - "8888:80" + environment: + PGADMIN_DEFAULT_EMAIL: user@domain.com + PGADMIN_DEFAULT_PASSWORD: strong-password + volumes: + - pgadmin-data:/var/lib/pgadmin + healthcheck: + test: [ "CMD-SHELL", "wget --spider -q http://localhost:80/ || exit 1" ] + interval: 1s + timeout: 5s + retries: 3 + start_period: 30s + networks: + - meldestelle-network + + # --- CACHE --- + redis: + image: redis:7-alpine + container_name: meldestelle-redis + restart: unless-stopped + ports: + - "6379:6379" + volumes: + - redis-data:/data + command: redis-server --appendonly yes + healthcheck: + test: [ "CMD", "redis-cli" ] + interval: 1s + timeout: 5s + retries: 3 + networks: + - meldestelle-network + + # --- IDENTITY PROVIDER (Wartet auf Postgres) --- + keycloak: + image: quay.io/keycloak/keycloak:26.4 + container_name: meldestelle-keycloak + restart: unless-stopped + environment: + KC_HEALTH_ENABLED: true + KC_METRICS_ENABLED: true + KC_BOOTSTRAP_ADMIN_USERNAME: kc-admin + KC_BOOTSTRAP_ADMIN_PASSWORD: kc-password + KC_DB: postgres + KC_DB_URL: jdbc:postgresql://postgres:5432/meldestelle + KC_DB_USERNAME: pg-user + KC_DB_PASSWORD: pg-password + KC_HOSTNAME: localhost + ports: + - "8180:8080" + depends_on: + postgres: + condition: service_healthy + volumes: + - ./docker/core/keycloak:/opt/keycloak/data/import:Z + command: start-dev --import-realm + healthcheck: + test: [ "CMD-SHELL", "exec 3<>/dev/tcp/127.0.0.1/9000" ] + interval: 20s + timeout: 10s + retries: 5 + start_period: 60s + networks: + - meldestelle-network + + # --- MONITORING --- + prometheus: + image: prom/prometheus:v2.54.1 + container_name: meldestelle-prometheus + restart: unless-stopped + ports: + - "9090:9090" + volumes: + - prometheus-data:/prometheus + - ./docker/monitoring/prometheus:/etc/prometheus:Z + command: + - --config.file=/etc/prometheus/prometheus.yml + - --storage.tsdb.retention.time=15d + healthcheck: + test: [ "CMD", "wget", "--spider", "-q", "http://localhost:9090/-/healthy" ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + networks: + - meldestelle-network + + grafana: + image: grafana/grafana:11.3.0 + container_name: meldestelle-grafana + environment: + GF_SECURITY_ADMIN_USER: gf-admin + GF_SECURITY_ADMIN_PASSWORD: gf-password + ports: + - "3000:3000" + volumes: + - grafana-data:/var/lib/grafana + - ./docker/monitoring/grafana:/etc/grafana/provisioning:Z + depends_on: + - prometheus + healthcheck: + test: [ "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health" ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + networks: + - meldestelle-network + +volumes: + postgres-data: + pgadmin-data: + redis-data: + prometheus-data: + grafana-data: + +networks: + meldestelle-network: + driver: bridge diff --git a/dockerfiles/infrastructure/keycloak/Dockerfile b/docker/core/keycloak/Dockerfile similarity index 100% rename from dockerfiles/infrastructure/keycloak/Dockerfile rename to docker/core/keycloak/Dockerfile diff --git a/docker/docker-compose.clients.yml b/docker/docker-compose.clients.yaml similarity index 100% rename from docker/docker-compose.clients.yml rename to docker/docker-compose.clients.yaml diff --git a/docker/docker-compose.services.yml b/docker/docker-compose.services.yaml similarity index 100% rename from docker/docker-compose.services.yml rename to docker/docker-compose.services.yaml diff --git a/docker/docker-compose.yml b/docker/docker-compose.yaml similarity index 84% rename from docker/docker-compose.yml rename to docker/docker-compose.yaml index 8ff0bfba..fce1ac66 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yaml @@ -17,6 +17,10 @@ services: volumes: - postgres-data:/var/lib/postgresql/data - ./core/postgres:/docker-entrypoint-initdb.d:Z + # Central postgres.conf from config (optional) + - ../config/postgres/postgresql.conf:/etc/postgresql/postgresql.conf:Z + # Use central postgresql.conf if present + command: ["postgres", "-c", "config_file=/etc/postgresql/postgresql.conf"] healthcheck: test: [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}" ] interval: 5s @@ -36,7 +40,10 @@ services: - "${REDIS_PORT}" volumes: - redis-data:/data - command: redis-server --appendonly yes + # Central redis config + - ../config/redis/redis.conf:/usr/local/etc/redis/redis.conf:Z + # Use central redis.conf and optionally add --requirepass if REDIS_PASSWORD is set + command: ["sh", "-lc", "exec redis-server /usr/local/etc/redis/redis.conf ${REDIS_PASSWORD:+--requirepass $REDIS_PASSWORD}"] healthcheck: test: [ "CMD", "redis-cli" ] interval: 5s @@ -112,7 +119,8 @@ services: - "${PROMETHEUS_PORT}" volumes: - prometheus-data:/prometheus - - ./monitoring/prometheus:/etc/prometheus:Z + # Use central config as single source of truth + - ../config/monitoring/prometheus:/etc/prometheus:Z command: - --config.file=/etc/prometheus/prometheus.yml - --storage.tsdb.retention.time=15d @@ -138,7 +146,10 @@ services: - "${GF_PORT}" volumes: - grafana-data:/var/lib/grafana - - ./monitoring/grafana:/etc/grafana/provisioning:Z + # Provisioning (datasources/dashboards) from central config + - ../config/monitoring/grafana/provisioning:/etc/grafana/provisioning:Z + # Dashboards directory (referenced by provisioning file path: /var/lib/grafana/dashboards) + - ../config/monitoring/grafana/dashboards:/var/lib/grafana/dashboards:Z depends_on: - prometheus healthcheck: @@ -176,7 +187,7 @@ services: api-gateway: build: context: .. - dockerfile: dockerfiles/infrastructure/gateway/Dockerfile + dockerfile: backend/infrastructure/gateway/Dockerfile args: # Build-Args aus deinen .env Dateien (werden hier statisch benötigt für den Build) GRADLE_VERSION: 9.1.0 @@ -195,13 +206,13 @@ services: # --- VERBINDUNGEN --- # Keycloak URL (INTERN im Docker Netzwerk!) # Beachte: http://container-name:8080 (nicht localhost, nicht 8180) - SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: http://${COMPOSE_PROJECT_NAME}-keycloak:8080/realms/meldestelle + SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI: http://keycloak:8080/realms/meldestelle SPRING_CLOUD_CONSUL_HOST: consul SPRING_CLOUD_CONSUL_PORT: 8500 # WICHTIG: Das Gateway muss wissen, wie es von anderen Containern erreicht wird (nicht localhost!) SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME: api-gateway # Postgres Verbindung (für Routes/Session, falls nötig) - SPRING_DATASOURCE_URL: jdbc:postgresql://${COMPOSE_PROJECT_NAME}-postgres:5432/${POSTGRES_DB} + SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB} SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER} SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD} # Logging @@ -225,7 +236,7 @@ services: ping-service: build: context: .. - dockerfile: dockerfiles/services/ping-service/Dockerfile + dockerfile: backend/services/ping/Dockerfile args: GRADLE_VERSION: 9.1.0 JAVA_VERSION: 21 @@ -247,13 +258,13 @@ services: SPRING_CLOUD_CONSUL_DISCOVERY_HOSTNAME: ping-service # - DATENBANK VERBINDUNG - - SPRING_DATASOURCE_URL: jdbc:postgresql://${COMPOSE_PROJECT_NAME}-postgres:5432/${POSTGRES_DB} + SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB} SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER} SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD} SPRING_JPA_HIBERNATE_DDL_AUTO: validate # --- REDIS --- - SPRING_DATA_REDIS_HOST: ${COMPOSE_PROJECT_NAME}-redis + SPRING_DATA_REDIS_HOST: redis SPRING_DATA_REDIS_PORT: 6379 depends_on: consul: @@ -273,7 +284,7 @@ services: web-app: build: context: .. - dockerfile: dockerfiles/clients/web-app/Dockerfile + dockerfile: docker/frontends/web-app/Dockerfile args: GRADLE_VERSION: ${DOCKER_GRADLE_VERSION:-9.1.0} JAVA_VERSION: ${DOCKER_JAVA_VERSION:-21} @@ -284,6 +295,9 @@ services: restart: unless-stopped ports: - "${WEB_APP_PORT}" + volumes: + # Mount production nginx config (can be adjusted per env) + - ../config/nginx/nginx.prod.conf:/etc/nginx/nginx.conf:Z,ro depends_on: api-gateway: condition: service_started @@ -295,7 +309,7 @@ services: desktop-app: build: context: .. - dockerfile: dockerfiles/clients/desktop-app/Dockerfile + dockerfile: docker/frontends/desktop-app/Dockerfile container_name: ${COMPOSE_PROJECT_NAME}-desktop-app restart: unless-stopped environment: diff --git a/dockerfiles/clients/desktop-app/Dockerfile b/docker/frontends/desktop-app/Dockerfile similarity index 100% rename from dockerfiles/clients/desktop-app/Dockerfile rename to docker/frontends/desktop-app/Dockerfile diff --git a/dockerfiles/clients/desktop-app/entrypoint.sh b/docker/frontends/desktop-app/entrypoint.sh similarity index 100% rename from dockerfiles/clients/desktop-app/entrypoint.sh rename to docker/frontends/desktop-app/entrypoint.sh diff --git a/dockerfiles/clients/desktop-app/health-check.sh b/docker/frontends/desktop-app/health-check.sh similarity index 100% rename from dockerfiles/clients/desktop-app/health-check.sh rename to docker/frontends/desktop-app/health-check.sh diff --git a/dockerfiles/clients/desktop-app/supervisord.conf b/docker/frontends/desktop-app/supervisord.conf similarity index 100% rename from dockerfiles/clients/desktop-app/supervisord.conf rename to docker/frontends/desktop-app/supervisord.conf diff --git a/dockerfiles/clients/web-app/Dockerfile b/docker/frontends/web-app/Dockerfile similarity index 100% rename from dockerfiles/clients/web-app/Dockerfile rename to docker/frontends/web-app/Dockerfile diff --git a/dockerfiles/clients/web-app/downloads/index.html b/docker/frontends/web-app/downloads/index.html similarity index 100% rename from dockerfiles/clients/web-app/downloads/index.html rename to docker/frontends/web-app/downloads/index.html diff --git a/dockerfiles/clients/web-app/nginx.conf b/docker/frontends/web-app/nginx.conf similarity index 100% rename from dockerfiles/clients/web-app/nginx.conf rename to docker/frontends/web-app/nginx.conf diff --git a/dockerfiles/infrastructure/monitoring-server/Dockerfile b/docker/monitoring/Dockerfile similarity index 100% rename from dockerfiles/infrastructure/monitoring-server/Dockerfile rename to docker/monitoring/Dockerfile diff --git a/dockerfiles/templates/kotlin-multiplatform-web.Dockerfile b/docker/templates/kotlin-multiplatform-web.Dockerfile similarity index 100% rename from dockerfiles/templates/kotlin-multiplatform-web.Dockerfile rename to docker/templates/kotlin-multiplatform-web.Dockerfile diff --git a/dockerfiles/templates/spring-boot-service.Dockerfile b/docker/templates/spring-boot-service.Dockerfile similarity index 100% rename from dockerfiles/templates/spring-boot-service.Dockerfile rename to docker/templates/spring-boot-service.Dockerfile diff --git a/docs/clients/visionen/AntwortenOffenerFragenArchitekturReview.md b/docs/clients/visionen/AntwortenOffenerFragenArchitekturReview.md index 2e47083a..2dca2d81 100644 --- a/docs/clients/visionen/AntwortenOffenerFragenArchitekturReview.md +++ b/docs/clients/visionen/AntwortenOffenerFragenArchitekturReview.md @@ -9,7 +9,7 @@ **Eintrag im Guide:** -```kotlin +```text // GUIDELINE: Dependency Injection // Wir nutzen Koin. Module werden im `di` Package des Features definiert. @@ -25,7 +25,8 @@ val inventoryModule = module { // 2. Nutzung des ApiClients (Best Practice) // Wir injizieren IMMER den "apiClient" (mit Auth-Header), niemals den Default Client. val networkModule = module { - single(named("apiClient")) { ... } // Konfiguriert in :core:network + // Hinweis: Platzhalter (kein ausführbarer Code im Dokument) + single(named("apiClient")) { /* bereitgestellt in :core:network */ } } val myFeatureModule = module { @@ -133,14 +134,14 @@ suspend fun updateStock(item: Item) { **Eintrag im Guide:** -```kotlin +```text // GUIDELINE: Feature Isolation // 1. Features importieren NIEMALS andere Features im `build.gradle.kts`. // 2. Kommunikation nur über Navigation (Router). // 3. Gemeinsam genutzte Datenobjekte (z.B. UserID, ShopID) liegen in :core:domain. // FALSCH: -import com.project.features.billing.Invoice // Abhängigkeit zu anderem Feature! +// import com.project.features.billing.Invoice // Abhängigkeit zu anderem Feature! (nur zu Illustrationszwecken) // RICHTIG: // Feature A navigiert zu Feature B via Route diff --git a/docs/clients/visionen/MultiplatformApp_Ktor_SQLDelight_Doku.pdf b/docs/clients/visionen/MultiplatformApp_Ktor_SQLDelight_Doku.pdf new file mode 100644 index 0000000000000000000000000000000000000000..50930d447968d435a089be9ebd7a900d3ccddae7 GIT binary patch literal 2317813 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

##Yrc;M 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

Auiqg~&gbkJ_@4Q_PS%g=gm#Y?(U{vaN2z5KL- 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