chore(build, docs): add security module and update infrastructure decisions
- Created `backend/infrastructure/security` module with standardized configurations for OAuth2, JWT validation, CORS, and role mapping. - Updated ADRs to reflect resolved backend infrastructure decisions, including security standardization, persistence strategy, and Flyway schema location. - Enabled integration of the `security` module into relevant projects (e.g., `ping-service` and `gateway`).
This commit is contained in:
@@ -22,6 +22,7 @@ dependencies {
|
|||||||
implementation(projects.core.coreUtils)
|
implementation(projects.core.coreUtils)
|
||||||
implementation(projects.platform.platformDependencies)
|
implementation(projects.platform.platformDependencies)
|
||||||
implementation(projects.backend.infrastructure.monitoring.monitoringClient)
|
implementation(projects.backend.infrastructure.monitoring.monitoringClient)
|
||||||
|
implementation(projects.backend.infrastructure.security) // NEU: Security Module
|
||||||
|
|
||||||
// === GATEWAY-SPEZIFISCHE ABHÄNGIGKEITEN ===
|
// === GATEWAY-SPEZIFISCHE ABHÄNGIGKEITEN ===
|
||||||
// Die WebFlux-Abhängigkeit wird jetzt korrekt durch das BOM bereitgestellt.
|
// 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.gateway.server.webflux)
|
||||||
implementation(libs.spring.cloud.starter.consul.discovery)
|
implementation(libs.spring.cloud.starter.consul.discovery)
|
||||||
implementation(libs.spring.boot.starter.actuator)
|
implementation(libs.spring.boot.starter.actuator)
|
||||||
implementation(libs.spring.boot.starter.security)
|
// Security dependencies are now transitively provided by infrastructure.security,
|
||||||
implementation(libs.spring.boot.starter.oauth2.resource.server)
|
// but Gateway is WebFlux, so we might need specific WebFlux security if the shared module is WebMVC only.
|
||||||
implementation(libs.spring.security.oauth2.jose)
|
// 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)
|
implementation(libs.spring.cloud.starter.circuitbreaker.resilience4j)
|
||||||
|
|
||||||
// Ergänzende Observability (Logging, Jackson)
|
// Ergänzende Observability (Logging, Jackson)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ tasks.jar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(platform(projects.platform.platformBom))
|
||||||
implementation(projects.core.coreUtils)
|
implementation(projects.core.coreUtils)
|
||||||
implementation(projects.core.coreDomain)
|
implementation(projects.core.coreDomain)
|
||||||
implementation(projects.platform.platformDependencies)
|
implementation(projects.platform.platformDependencies)
|
||||||
@@ -33,4 +34,12 @@ dependencies {
|
|||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
implementation(libs.slf4j.api)
|
implementation(libs.slf4j.api)
|
||||||
|
|
||||||
|
// Testing
|
||||||
|
testImplementation(projects.platform.platformTesting)
|
||||||
|
testImplementation(libs.bundles.testing.jvm)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.test {
|
||||||
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
@@ -19,8 +19,10 @@ dependencies {
|
|||||||
// Our central BOM for consistent versions
|
// Our central BOM for consistent versions
|
||||||
implementation(platform(projects.platform.platformBom))
|
implementation(platform(projects.platform.platformBom))
|
||||||
implementation(projects.platform.platformDependencies)
|
implementation(projects.platform.platformDependencies)
|
||||||
// NEU: Zugriff auf die verschobenen DatabaseUtils
|
|
||||||
|
// Infrastructure Modules
|
||||||
implementation(projects.backend.infrastructure.persistence)
|
implementation(projects.backend.infrastructure.persistence)
|
||||||
|
implementation(projects.backend.infrastructure.security) // NEU: Security Module
|
||||||
|
|
||||||
// === Spring Boot & Cloud ===
|
// === Spring Boot & Cloud ===
|
||||||
// Standard dependencies for a secure microservice
|
// Standard dependencies for a secure microservice
|
||||||
|
|||||||
@@ -1,59 +1,9 @@
|
|||||||
# PENDING DECISIONS: Backend Infrastructure & Architecture
|
# PENDING DECISIONS: Backend Infrastructure & Architecture
|
||||||
|
|
||||||
**Status:** OPEN
|
**Status:** RESOLVED
|
||||||
**Date:** 2026-01-15
|
**Date:** 2026-01-15
|
||||||
**Requester:** Senior Backend Developer
|
**See:** [ADR 001: Backend Infrastructure & Architecture Decisions](001-backend-infrastructure-decisions.md)
|
||||||
**Target:** Lead Architect
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Context
|
*This document is kept for historical context. All decisions have been moved to ADR 001.*
|
||||||
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.
|
|
||||||
|
|||||||
@@ -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`.
|
||||||
@@ -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)
|
||||||
@@ -61,6 +61,9 @@ include(":backend:infrastructure:monitoring:monitoring-server")
|
|||||||
// --- PERSISTENCE ---
|
// --- PERSISTENCE ---
|
||||||
include(":backend:infrastructure:persistence")
|
include(":backend:infrastructure:persistence")
|
||||||
|
|
||||||
|
// --- SECURITY ---
|
||||||
|
include(":backend:infrastructure:security")
|
||||||
|
|
||||||
// === BACKEND - SERVICES ===
|
// === BACKEND - SERVICES ===
|
||||||
// --- ENTRIES (Nennungen) ---
|
// --- ENTRIES (Nennungen) ---
|
||||||
include(":backend:services:entries:entries-api")
|
include(":backend:services:entries:entries-api")
|
||||||
|
|||||||
Reference in New Issue
Block a user