---
type: Report
status: ARCHIVED
owner: Lead Architect
date: 2026-01-10
tags: [backend, ping-service, task]
---

# Arbeitsauftrag: Implementierung des `ping-service` (Tracer Bullet)

**ARCHIVED:** This is the original task description. The implementation has evolved. Please refer to `docs/05_Backend/Services/PingService_Reference.md`.

---

**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 an. Beachte die neue, klarere Benennung des
Implementierungsmoduls:

- `:contracts:ping-api`: Enthält die KMP-kompatiblen DTOs.
- `:backend:services:ping:ping-service`: Enthält die Spring Boot Anwendung, Controller und Konfiguration.

Stelle sicher, dass die Module in der `settings.gradle.kts` registriert sind.

  ```text
  include(
  ":platform:platform-bom",
  ":platform:platform-testing",
  ":contracts:ping-api",
  ":backend:services:ping:ping-service",
  ":backend:infrastructure: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.

  ```text
  PingResponse.kt
  ```
  ```text
  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-service
   
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:

  ```text
  // in backend/services/ping/ping-service/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-service/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`
  ```text
      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-service/build.gradle.kts`
  ```text
      plugins {
        alias(libs.plugins.spring.boot)
        alias(libs.plugins.kotlin.jvm)
        alias(libs.plugins.kotlin.spring)
    }

    dependencies {
        // API-Modul einbinden
        implementation(project(":contracts: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.
