refactor(ping-service): remove CORS configuration from code, restructure modules, and update Gradle dependencies
Migrated CORS settings from code to `application.yaml` for better separation of concerns. Integrated `ping-api` into the new `contracts` module for improved modularity. Updated Gradle scripts and dependencies accordingly to reflect the new project structure.
This commit is contained in:
@@ -0,0 +1,202 @@
|
||||
**An:** Senior Backend Developer
|
||||
**Von:** Lead Software Architect
|
||||
**Betreff:** Arbeitsauftrag: Implementierung des `ping-service` (Tracer Bullet)
|
||||
|
||||
Guten Tag,
|
||||
|
||||
deine nächste Aufgabe ist die Implementierung unseres ersten Microservices, des `ping-service`. Dieser Service ist von
|
||||
strategischer Bedeutung, da er als **"Tracer Bullet"** und **Blaupause** für alle zukünftigen fachlichen Services dient.
|
||||
|
||||
Mit dieser Implementierung validieren wir die gesamte Kette: von der Service-Registrierung bei Consul über das
|
||||
Gateway-Routing und die Security mit Keycloak bis hin zur Observability mit Zipkin.
|
||||
|
||||
Deine Expertise in Spring Boot, DDD und sauberer Architektur ist hier entscheidend, um eine qualitativ hochwertige und
|
||||
wiederverwendbare Vorlage zu schaffen.
|
||||
|
||||
## Deine Aufgaben im Detail:
|
||||
|
||||
1. Modulstruktur anlegen
|
||||
|
||||
Bitte lege die folgende Modulstruktur unter backend/services/ping an. Beachte die neue, klarere Benennung des
|
||||
Implementierungsmoduls:
|
||||
|
||||
- `:backend:services:ping:ping-api`: Enthält die KMP-kompatiblen DTOs.
|
||||
- `:backend:services:ping:ping-infrastructure`: Enthält die Spring Boot Anwendung, Controller und Konfiguration.
|
||||
|
||||
Stelle sicher, dass die Module in der `settings.gradle.kts` registriert sind.
|
||||
|
||||
```kotlin
|
||||
include(
|
||||
":platform:platform-bom",
|
||||
":platform:platform-testing",
|
||||
":backend:services:ping:ping-api",
|
||||
":backend:services:ping:ping-infrastructure",
|
||||
":backend:gateway",
|
||||
// ":backend:services:registry:registry-api",
|
||||
// ":backend:services:registry:registry-domain",
|
||||
```
|
||||
|
||||
2. API-Definition in `:ping-api`
|
||||
|
||||
Definiere in `ping-api/src/commonMain/kotlin` ein einfaches, serialisierbares DTO. Dieses Modul darf **keine
|
||||
JVM-spezifischen Abhängigkeiten** enthalten, um die KMP-Kompatibilität für das Frontend zu gewährleisten.
|
||||
|
||||
```kotlin
|
||||
PingResponse.kt
|
||||
```
|
||||
```kotlin
|
||||
package de.meldestelle.api.ping
|
||||
|
||||
import kotlinx . serialization . Serializable
|
||||
|
||||
@Serializable
|
||||
data class PingResponse(
|
||||
val message: String,
|
||||
val principal: String? = null
|
||||
)
|
||||
```
|
||||
|
||||
3. Service-Implementierung in :ping-infrastructure
|
||||
|
||||
Implementiere die Spring Boot Anwendung.
|
||||
|
||||
- **`PingController.kt`:**
|
||||
- **`GET /api/ping`:** Ein öffentlicher Endpunkt, der eine `PingResponse("Pong", "anonymous")` zurückgibt.
|
||||
- **`GET /api/ping/secure`:** Ein durch Spring Security geschützter Endpunkt. Er soll den `preferred_username` aus dem `Jwt` Principal extrahieren und in der `PingResponse` zurückgeben.
|
||||
|
||||
Hier ist ein Implementierungsvorschlag für den Controller:
|
||||
|
||||
```kotlin
|
||||
// in backend/services/ping/ping-infrastructure/src/main/kotlin/.../PingController.kt
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/ping")
|
||||
class PingController {
|
||||
|
||||
@GetMapping
|
||||
fun pingPublic(): PingResponse {
|
||||
return PingResponse(message = "Pong", principal = "anonymous")
|
||||
}
|
||||
|
||||
@GetMapping("/secure")
|
||||
fun pingSecure(principal: Jwt): PingResponse {
|
||||
val username = principal.getClaimAsString("preferred_username")
|
||||
return PingResponse(message = "Pong (Secure)", principal = username)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. **Konfiguration**
|
||||
|
||||
Erstelle die `application.yml` für den Service. Sie muss die Anwendung für unsere Infrastruktur korrekt konfigurieren:
|
||||
|
||||
- **Service Name:** ping-service
|
||||
- **Service Discovery:** Registrierung bei Consul.
|
||||
- **Security:** Konfiguration als Resource Server, der JWTs vom `issuer-uri` unseres Keycloak-Containers validiert.
|
||||
- **Observability:** Actuator-Endpunkte (`health`, `info`, `prometheus`) freigeben und Tracing aktivieren.
|
||||
|
||||
```yaml
|
||||
# in backend/services/ping/ping-infrastructure/src/main/resources/application.yml
|
||||
|
||||
server:
|
||||
port: 8081 # Eindeutiger Port für den Service
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: ping-service
|
||||
|
||||
# --- Consul Discovery ---
|
||||
cloud:
|
||||
consul:
|
||||
host: consul
|
||||
port: 8500
|
||||
discovery:
|
||||
instance-id: \${spring.application.name}:\${random.value}
|
||||
health-check-path: /actuator/health
|
||||
health-check-interval: 10s
|
||||
|
||||
# --- Security (Keycloak) ---
|
||||
security:
|
||||
oauth2:
|
||||
resourceserver:
|
||||
jwt:
|
||||
issuer-uri: http://keycloak:8080/realms/meldestelle
|
||||
|
||||
# --- Observability ---
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: "health,info,prometheus"
|
||||
tracing:
|
||||
sampling:
|
||||
probability: 1.0 # Trace every request
|
||||
|
||||
logging:
|
||||
pattern:
|
||||
level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"
|
||||
```
|
||||
|
||||
5. **Build-Konfiguration(`build.gradle.kts`)
|
||||
|
||||
Achte auf die korrekte und saubere Definition der Abhängigkeiten.
|
||||
|
||||
- `ping-api/build.gradle.kts`
|
||||
```kotlin
|
||||
plugins {
|
||||
alias(libs.plugins.kotlin.multiplatform)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm() // Für die Nutzung im Backend
|
||||
js(IR) { browser() } // Für die Nutzung im Frontend
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `ping-infrastructure/build.gradle.kts`
|
||||
```kotlin
|
||||
plugins {
|
||||
alias(libs.plugins.spring.boot)
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
alias(libs.plugins.kotlin.spring)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// API-Modul einbinden
|
||||
implementation(project(":backend:services:ping:ping-api"))
|
||||
|
||||
// Unsere zentrale BOM für konsistente Versionen
|
||||
implementation(platform(project(":platform:platform-bom")))
|
||||
|
||||
// Spring Boot Starter
|
||||
implementation(libs.spring.boot.starter.web)
|
||||
implementation(libs.spring.boot.starter.actuator)
|
||||
implementation(libs.spring.boot.starter.security)
|
||||
implementation(libs.spring.boot.starter.oauth2.resource.server)
|
||||
|
||||
// Spring Cloud (Consul, OpenFeign etc.)
|
||||
implementation(libs.spring.cloud.starter.consul.discovery)
|
||||
|
||||
// Test-Abhängigkeiten
|
||||
testImplementation(platform(project(":platform:platform-testing")))
|
||||
testImplementation(libs.bundles.test.spring)
|
||||
}
|
||||
```
|
||||
|
||||
## Definition of Done:
|
||||
|
||||
Der Auftrag gilt als erledigt, wenn:
|
||||
1. Die Anwendung erfolgreich startet und sich im Consul UI als `UP` registriert.
|
||||
2. Ein `GET`-Request auf `http//localhost:8081/api/ping` (über das Gateway) den Status `200 OK` und die `{"message":"Pong", "principal":"anonymous"}` zurückgibt.
|
||||
3. Ein `GET`-Request auf `http//localhost:8081/api/ping/secure` ohne Token den Status `401 Unauthorized` zurückgibt.
|
||||
4. Ein `GET`-Request auf `http//localhost:8081/api/ping/secure` mit einem gültigen Keycloak-Token deb Status `200 OK` und eine Antwort mit dem korrekten Benutzernamen zurückgibt.
|
||||
5. Die Requests in der Zipkin UI als Trace sichtbar sind.
|
||||
|
||||
Bei Fragen zur Konfiguration oder zur Architektur stehe ich dir zur Verfügung.
|
||||
|
||||
Reference in New Issue
Block a user