diff --git a/backend/infrastructure/gateway/build.gradle.kts b/backend/infrastructure/gateway/build.gradle.kts index ce159305..4e9f5c66 100644 --- a/backend/infrastructure/gateway/build.gradle.kts +++ b/backend/infrastructure/gateway/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { implementation(projects.core.coreUtils) implementation(projects.platform.platformDependencies) implementation(projects.backend.infrastructure.monitoring.monitoringClient) + implementation(projects.backend.infrastructure.security) // NEU: Security Module // === GATEWAY-SPEZIFISCHE ABHÄNGIGKEITEN === // Die WebFlux-Abhängigkeit wird jetzt korrekt durch das BOM bereitgestellt. @@ -32,9 +33,17 @@ dependencies { implementation(libs.spring.cloud.starter.gateway.server.webflux) implementation(libs.spring.cloud.starter.consul.discovery) implementation(libs.spring.boot.starter.actuator) - implementation(libs.spring.boot.starter.security) - implementation(libs.spring.boot.starter.oauth2.resource.server) - implementation(libs.spring.security.oauth2.jose) + // Security dependencies are now transitively provided by infrastructure.security, + // but Gateway is WebFlux, so we might need specific WebFlux security if the shared module is WebMVC only. + // However, starter-security works for both. Resource server might need check. + // For now, we keep explicit dependencies if they differ from the shared module or just rely on shared. + // Shared module has: starter-security, starter-oauth2-resource-server, jose, web. + // Gateway needs: starter-security, starter-oauth2-resource-server, jose. + // "web" (MVC) vs "webflux" (Reactive) conflict might occur if shared module pulls in MVC. + // CHECK: Shared module uses `implementation(libs.spring.web)`. This pulls in spring-webmvc usually? + // No, `spring-web` is common. `spring-boot-starter-web` pulls in MVC. + // The shared module build.gradle.kts uses `libs.spring.web`. + implementation(libs.spring.cloud.starter.circuitbreaker.resilience4j) // Ergänzende Observability (Logging, Jackson) diff --git a/backend/infrastructure/persistence/build.gradle.kts b/backend/infrastructure/persistence/build.gradle.kts index d690cc3e..4d9a360b 100644 --- a/backend/infrastructure/persistence/build.gradle.kts +++ b/backend/infrastructure/persistence/build.gradle.kts @@ -16,6 +16,7 @@ tasks.jar { } dependencies { + implementation(platform(projects.platform.platformBom)) implementation(projects.core.coreUtils) implementation(projects.core.coreDomain) implementation(projects.platform.platformDependencies) @@ -33,4 +34,12 @@ dependencies { // Logging implementation(libs.slf4j.api) + + // Testing + testImplementation(projects.platform.platformTesting) + testImplementation(libs.bundles.testing.jvm) +} + +tasks.test { + useJUnitPlatform() } diff --git a/backend/infrastructure/security/build.gradle.kts b/backend/infrastructure/security/build.gradle.kts new file mode 100644 index 00000000..7693678e --- /dev/null +++ b/backend/infrastructure/security/build.gradle.kts @@ -0,0 +1,40 @@ +plugins { + alias(libs.plugins.kotlinJvm) + alias(libs.plugins.kotlinSpring) + alias(libs.plugins.spring.boot) + alias(libs.plugins.spring.dependencyManagement) +} + +// Library module: do not create an executable Spring Boot jar here. +tasks.bootJar { + enabled = false +} + +tasks.jar { + enabled = true +} + +dependencies { + implementation(platform(projects.platform.platformBom)) + implementation(projects.platform.platformDependencies) + + // Spring Security & OAuth2 + implementation(libs.spring.boot.starter.security) + implementation(libs.spring.boot.starter.oauth2.resource.server) + implementation(libs.spring.security.oauth2.jose) + + // Web (for CORS config) + implementation(libs.spring.web) + + // Utils + implementation(libs.slf4j.api) + implementation(libs.jackson.module.kotlin) + + // Testing + testImplementation(projects.platform.platformTesting) + testImplementation(libs.spring.security.test) +} + +tasks.test { + useJUnitPlatform() +} diff --git a/backend/services/ping/ping-service/build.gradle.kts b/backend/services/ping/ping-service/build.gradle.kts index 51947758..911d14ba 100644 --- a/backend/services/ping/ping-service/build.gradle.kts +++ b/backend/services/ping/ping-service/build.gradle.kts @@ -19,8 +19,10 @@ dependencies { // Our central BOM for consistent versions implementation(platform(projects.platform.platformBom)) implementation(projects.platform.platformDependencies) - // NEU: Zugriff auf die verschobenen DatabaseUtils + + // Infrastructure Modules implementation(projects.backend.infrastructure.persistence) + implementation(projects.backend.infrastructure.security) // NEU: Security Module // === Spring Boot & Cloud === // Standard dependencies for a secure microservice diff --git a/docs/01_Architecture/adr/000-PENDING-backend-infrastructure-decisions.md b/docs/01_Architecture/adr/000-PENDING-backend-infrastructure-decisions.md index c1d1e76b..6641027e 100644 --- a/docs/01_Architecture/adr/000-PENDING-backend-infrastructure-decisions.md +++ b/docs/01_Architecture/adr/000-PENDING-backend-infrastructure-decisions.md @@ -1,59 +1,9 @@ # PENDING DECISIONS: Backend Infrastructure & Architecture -**Status:** OPEN +**Status:** RESOLVED **Date:** 2026-01-15 -**Requester:** Senior Backend Developer -**Target:** Lead Architect +**See:** [ADR 001: Backend Infrastructure & Architecture Decisions](001-backend-infrastructure-decisions.md) --- -## Context -During the analysis of the `backend/infrastructure` modules for the "Operation Tracer Bullet" (Phase 1), several inconsistencies were found that block the clean implementation of the `ping-service`. - -## Questions & Decisions Required - -### 1. Persistence Strategy: JPA vs. Exposed (BLOCKER) -**Observation:** -* `ping-service` imports `spring-boot-starter-data-jpa` (Hibernate). -* `backend/infrastructure/persistence` provides `DatabaseUtils` exclusively based on **Exposed** (Kotlin SQL Framework). -* Result: Two competing ORM approaches in the classpath. - -**Question:** -What is the standard technology for our microservices? -* **Option A (JPA/Hibernate):** The standard Spring way. `infrastructure/persistence` needs to be refactored. -* **Option B (Exposed):** The "Kotlin-Native" way. JPA must be removed from `ping-service`. - -*Recommendation:* Exposed fits better with DDD/Kotlin (less magic), but JPA has better Spring integration. - -### 2. Security Shared Module -**Observation:** -Roadmap requires OAuth2/RBAC. Currently, there is no `backend/infrastructure/security` module. Implementing security directly in `ping-service` violates DRY. - -**Question:** -Should a `backend/infrastructure/security` module be extracted in Phase 1 to encapsulate standard config (Resource Server, CORS, Role Mapping)? - -### 3. Messaging vs. Sync Protocol -**Observation:** -Roadmap specifies "Delta-Sync APIs" for Offline-First. -`backend/infrastructure/messaging` contains heavy **Kafka** (Reactor Kafka) dependencies. - -**Question:** -Does `ping-service` need Kafka for the "Tracer Bullet"? -* If Sync is REST-based (Pull), Kafka might be over-engineering for Phase 1. -* Should `PingEvents` be stored in DB (Outbox) or pushed to Kafka? - -### 4. Database Migration (Flyway) -**Observation:** -Flyway is required. No convention exists for script location. - -**Question:** -Where should Flyway scripts (`V1__init.sql`) be located? -* **Option A:** Inside the service (`ping-service/src/main/resources/db/migration`) -> "Database per Service". -* **Option B:** Centralized. - -*Recommendation:* Option A. - ---- - -## Next Steps -Please resolve these questions (especially #1) so development can proceed. +*This document is kept for historical context. All decisions have been moved to ADR 001.* diff --git a/docs/01_Architecture/adr/001-backend-infrastructure-decisions.md b/docs/01_Architecture/adr/001-backend-infrastructure-decisions.md new file mode 100644 index 00000000..52793787 --- /dev/null +++ b/docs/01_Architecture/adr/001-backend-infrastructure-decisions.md @@ -0,0 +1,67 @@ +# ADR 001: Backend Infrastructure & Architecture Decisions + +**Status:** ACCEPTED +**Date:** 2026-01-15 +**Author:** Lead Architect +**Context:** "Operation Tracer Bullet" (Phase 1) - Hardening of the `ping-service`. + +--- + +## 1. Persistence Strategy: JPA vs. Exposed + +**Decision:** **Hybrid Approach (Command/Query Separation)** +* **Primary (Command/Write):** We use **JPA (Hibernate)** for the standard "Write Model" in our microservices. + * *Reason:* Best integration with Spring Data, transaction management, and validation. Standard for Enterprise Spring Boot. +* **Secondary (Query/Read/Batch):** We allow **Exposed** for complex read queries or bulk operations where JPA overhead is too high. + * *Reason:* Kotlin-native, type-safe SQL generation, better performance for read-heavy operations. + +**Action:** +* The `backend/infrastructure/persistence` module will support **both**. +* `ping-service` will primarily use **JPA** for its entities (`PingEntity`). +* We will NOT remove JPA from `ping-service`. +* We will NOT remove Exposed from `infrastructure/persistence`. + +## 2. Security Shared Module + +**Decision:** **Extract `backend/infrastructure/security`** +* **Reason:** We strictly follow DRY (Don't Repeat Yourself). Security configuration (OAuth2 Resource Server, JWT Converter, CORS, Global Method Security) is identical for all microservices. +* **Scope:** + * `SecurityConfig`: Standard `SecurityFilterChain`. + * `KeycloakRoleConverter`: Extracting roles from JWT. + * `CorsConfig`: Centralized CORS policy. + +**Action:** +* Create `backend/infrastructure/security`. +* Move security logic from `ping-service` (if any) to this module. + +## 3. Messaging vs. Sync Protocol + +**Decision:** **REST-based Pull (Phase 1) -> Kafka (Phase 3)** +* **Phase 1 (Tracer Bullet):** We do **NOT** use Kafka for the simple `ping-service` yet. + * *Reason:* Keep the "Tracer Bullet" simple. We want to validate the HTTP/Auth chain first. +* **Phase 3 (Offline Sync):** We will introduce Kafka for the "Outbox Pattern" later. + * *Reason:* Reliable event delivery for offline clients requires a durable log. + +**Action:** +* Remove `reactor-kafka` dependency from `ping-service` for now to reduce noise. +* Focus on `PingEntity` (JPA) and REST endpoints. + +## 4. Database Migration (Flyway) + +**Decision:** **Database per Service (Option A)** +* **Reason:** Microservices autonomy. Each service owns its schema. +* **Location:** `src/main/resources/db/migration` inside each service module. +* **Naming:** `V{Version}__{Description}.sql` (e.g., `V1__init_ping_schema.sql`). + +**Action:** +* `ping-service` must contain `V1__init.sql`. +* `spring.flyway.enabled=true` in `application.yml`. + +--- + +## Summary of Tasks for Senior Backend Developer + +1. **Persistence:** Use JPA for `PingEntity`. +2. **Security:** Wait for `infrastructure/security` module (Architect will create skeleton) OR start implementing in `ping-service` and refactor later (preferred: Architect creates module now). +3. **Messaging:** Ignore Kafka for now. +4. **Flyway:** Create `V1__init.sql` in `ping-service`. diff --git a/docs/05_Backend/TASK_2026_Q1_Infrastructure_Hardening.md b/docs/05_Backend/TASK_2026_Q1_Infrastructure_Hardening.md new file mode 100644 index 00000000..7c296c34 --- /dev/null +++ b/docs/05_Backend/TASK_2026_Q1_Infrastructure_Hardening.md @@ -0,0 +1,79 @@ +--- +type: Task +status: OPEN +owner: Senior Backend Developer +created: 2026-01-15 +priority: HIGH +context: Operation Tracer Bullet (Phase 1) +--- + +# Arbeitsanweisung: Infrastructure Hardening & Security Implementation + +**Ziel:** Finalisierung der Backend-Infrastruktur-Module und Härtung des `ping-service` gemäß [ADR 001](../../01_Architecture/adr/001-backend-infrastructure-decisions.md). + +--- + +## 1. Kontext & Architektur-Entscheidungen + +Wir befinden uns in **Phase 1** ("Tracer Bullet"). Das Ziel ist ein stabiler, sicherer Durchstich vom Frontend bis zur Datenbank. +Die Architektur wurde wie folgt geschärft (siehe ADR 001): +* **Persistence:** Hybrid-Ansatz (JPA für Writes/Entities, Exposed für komplexe Reads). +* **Security:** Zentralisiertes Modul (`backend/infrastructure/security`). +* **Messaging:** Kafka ist für Phase 1 **out of scope**. Fokus auf REST. +* **Migration:** Flyway Skripte liegen direkt im Service (`db/migration`). + +--- + +## 2. Deine Aufgaben (Checkliste) + +### A. Security Module (`backend/infrastructure/security`) +Dieses Modul wurde neu angelegt. Fülle es mit Leben. + +* [ ] **Security Configuration:** + * Erstelle eine `SecurityConfig`-Klasse, die `SecurityFilterChain` konfiguriert. + * Implementiere OAuth2 Resource Server Support (JWT Validierung). + * Definiere globale CORS-Regeln (Frontend darf zugreifen). +* [ ] **Role Converter:** + * Implementiere einen `KeycloakRoleConverter`, der die Rollen aus dem JWT (Realm/Resource Access) in Spring Security `GrantedAuthority` mappt. +* **Wichtig:** Achte auf Kompatibilität. Das Gateway nutzt WebFlux (Reactive), die Services nutzen WebMVC (Servlet). Falls nötig, trenne die Konfigurationen oder nutze `ConditionalOnWebApplication`. + +### B. Persistence Layer (`backend/infrastructure/persistence`) +Das Modul ist bereits konfiguriert. + +* [ ] **Verwendung im Service:** + * Stelle sicher, dass der `ping-service` dieses Modul nutzt. + * Implementiere `PingEntity` als JPA Entity. + * Nutze `JpaRepository` für Standard-CRUD-Operationen. + +### C. Ping Service Hardening (`backend/services/ping/ping-service`) +Mache den Service "Production Ready". + +* [ ] **Flyway:** + * Erstelle `src/main/resources/db/migration/V1__init_ping.sql`. + * Definiere das Schema für die `ping` Tabelle. +* [ ] **API Implementation:** + * Implementiere `/ping/public` (offen) und `/ping/secure` (benötigt Auth). + * Nutze `@PreAuthorize("hasRole('MELD_USER')")` o.ä. zum Testen der Rollen. +* [ ] **Resilience:** + * Konfiguriere Resilience4j (CircuitBreaker) für die DB-Verbindung (via `application.yml`). + +### D. Gateway Integration (`backend/infrastructure/gateway`) +* [ ] **Routing:** + * Prüfe die `application.yml` im Gateway. + * Stelle sicher, dass Routen zum `ping-service` korrekt konfiguriert sind (via Service Discovery "ping-service"). + +--- + +## 3. Definition of Done + +1. Das Projekt kompiliert fehlerfrei (`./gradlew build`). +2. `docker compose up` startet Gateway, Ping-Service, Keycloak und Postgres ohne Fehler. +3. Ein Request auf `http://localhost:8080/ping/public` (via Gateway) liefert 200 OK. +4. Ein Request auf `http://localhost:8080/ping/secure` ohne Token liefert 401 Unauthorized. +5. Die Datenbank-Tabelle `ping` wurde durch Flyway automatisch erstellt. + +--- + +**Referenzen:** +* [ADR 001: Backend Infrastructure Decisions](../../01_Architecture/adr/001-backend-infrastructure-decisions.md) +* [Master Roadmap Q1 2026](../../01_Architecture/MASTER_ROADMAP_2026_Q1.md) diff --git a/settings.gradle.kts b/settings.gradle.kts index 6f504591..4939be11 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -61,6 +61,9 @@ include(":backend:infrastructure:monitoring:monitoring-server") // --- PERSISTENCE --- include(":backend:infrastructure:persistence") +// --- SECURITY --- +include(":backend:infrastructure:security") + // === BACKEND - SERVICES === // --- ENTRIES (Nennungen) --- include(":backend:services:entries:entries-api")