docs: massive restructuring of documentation, development guides and agent playbooks
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
---
|
||||
type: Reference
|
||||
status: ACTIVE
|
||||
owner: Backend Developer
|
||||
last_update: 2026-04-03
|
||||
---
|
||||
|
||||
# API-Übersicht Stammdaten
|
||||
|
||||
Abdeckung: Backend Sprint B‑1 (abgeschlossen). Konsolidierte Endpunkte für Reiter, Pferde, Vereine und Funktionäre. Implementiert mit Ktor; DTOs und Validierung in den jeweiligen Services.
|
||||
|
||||
Hinweis Tenant/Headers: Stammdaten sind global bzw. nicht tenant‑spezifisch. Für domain‑spezifische Vorgänge (Entries, Kassa) gilt ADR‑0021/`X-Event-Id`.
|
||||
|
||||
## Reiter (`/reiter`)
|
||||
|
||||
- GET `/reiter` — Liste (optional Filter: `lizenzKlasse`, `vereinId`; Pagination: `limit`, `offset`)
|
||||
- GET `/reiter/search?q=...` — Suche nach Name oder Satznummer
|
||||
- GET `/reiter/{id}` — Einzelabruf
|
||||
- GET `/reiter/satznummer/{nr}` — Lookup per Satznummer
|
||||
- POST `/reiter` — Anlegen
|
||||
- PUT `/reiter/{id}` — Aktualisieren (partiell)
|
||||
- DELETE `/reiter/{id}` — Löschen
|
||||
|
||||
Quelle: `backend/services/masterdata/masterdata-api/.../ReiterController.kt`
|
||||
|
||||
## Pferde (`/horse`)
|
||||
|
||||
- GET `/horse` — Liste (optional Filter: `jahrgang`, `besitzerId`; Pagination: `limit`, `offset`)
|
||||
- GET `/horse/search?q=...` — Suche nach Name/Nummern
|
||||
- GET `/horse/{id}` — Einzelabruf
|
||||
- POST `/horse` — Anlegen
|
||||
- PUT `/horse/{id}` — Aktualisieren (partiell)
|
||||
- DELETE `/horse/{id}` — Löschen
|
||||
|
||||
Quelle: `backend/services/masterdata/masterdata-api/.../HorseController.kt`
|
||||
|
||||
## Vereine (`/verein`)
|
||||
|
||||
- GET `/verein` — Liste (optional Filter: `verband`/Bundesland; Pagination: `limit`, `offset`)
|
||||
- GET `/verein/search?q=...` — Suche nach Name/Kurzname
|
||||
- GET `/verein/{id}` — Einzelabruf
|
||||
- POST `/verein` — Anlegen
|
||||
- PUT `/verein/{id}` — Aktualisieren (partiell)
|
||||
- DELETE `/verein/{id}` — Löschen
|
||||
|
||||
Quelle: `backend/services/masterdata/masterdata-api/.../VereinController.kt`
|
||||
|
||||
## Funktionäre (`/funktionaer`)
|
||||
|
||||
- GET `/funktionaer` — Liste (optional Filter: `rolle`; Pagination: `limit`, `offset`)
|
||||
- GET `/funktionaer/search?q=...` — Suche nach Name
|
||||
- GET `/funktionaer/{id}` — Einzelabruf
|
||||
- POST `/funktionaer` — Anlegen
|
||||
- PUT `/funktionaer/{id}` — Aktualisieren (partiell)
|
||||
- DELETE `/funktionaer/{id}` — Löschen
|
||||
|
||||
Quelle: `backend/services/masterdata/masterdata-api/.../FunktionaerController.kt`
|
||||
|
||||
## Standards
|
||||
|
||||
- Auth: Standard-Bearer optional je nach Deploymentprofil (siehe Service-Konfig)
|
||||
- Content-Type: `application/json; charset=utf-8`
|
||||
- Fehlerfälle: 400 (Validierung), 404 (nicht gefunden)
|
||||
@@ -0,0 +1,37 @@
|
||||
---
|
||||
type: Reference
|
||||
status: DRAFT
|
||||
owner: Backend Developer
|
||||
last_update: 2026-04-03
|
||||
---
|
||||
|
||||
# Kassa-API (Entwurf)
|
||||
|
||||
Abhängigkeit: Backend Sprint B‑2 (Kassa-Service) — laut Curator‑Roadmap noch offen. Dieses Dokument reserviert die Endpunkte und beschreibt die Erwartungen. Die Implementierungsdetails werden ergänzt, sobald der Service fertiggestellt ist.
|
||||
|
||||
Mandantenkontext: Erfordert `X-Event-Id` (ADR‑0021). Alle Kassa‑Operationen sind tenant‑lokal.
|
||||
|
||||
## Endpunkte (geplant)
|
||||
|
||||
- GET `/kassa/saldo` — Liefert den aktuellen Saldo der Veranstaltung und optional pro Turnier.
|
||||
- Query: `turnierId` (optional, UUID)
|
||||
- Response: `{ saldoCents: long, currency: "EUR", scope: "veranstaltung"|"turnier", turnierId?: UUID }`
|
||||
|
||||
- GET `/zahlvorgaenge` — Listet Kassa‑Buchungen/Zahlvorgänge (paginiert, filterbar).
|
||||
- Query: `turnierId?`, `teilnehmerId?`, `typ?` (EINZAHLUNG|AUSZAHLUNG|KORREKTUR), `limit`, `offset`
|
||||
- Response: Liste von Transaktionen mit Betrag, Zeit, Verweis (Teilnehmer/Turnier), Notiz
|
||||
|
||||
- POST `/zahlvorgaenge` — Erstellt einen neuen Zahlungsvorgang (Ein-/Auszahlung/Korrektur).
|
||||
- Body: `{ typ, betragCents, currency, referenz: { teilnehmerId?|turnierId? }, notiz? }`
|
||||
- Wirkung: Aktualisiert `teilnehmer_konten` bzw. `turnier_kassa` atomar.
|
||||
|
||||
## Validierung & Regeln (voraussichtlich)
|
||||
|
||||
- Atomare Konsistenz: Transaktion + Saldo‑Update innerhalb einer DB‑Transaktion.
|
||||
- Negativsaldo optional durch Feature‑Flag blockierbar.
|
||||
- Audit‑Trail pro Vorgang (who/when), Idempotenz‑Key optional.
|
||||
|
||||
## Implementierungsstand
|
||||
|
||||
- Datenstrukturen `teilnehmer_konten` und `turnier_kassa` sind per Flyway angelegt (siehe [Datenbankschema](../Schema/Database_Schema_V1-V009.md)).
|
||||
- Endpunkte folgen nach Abschluss Backend B‑2. Dieses Dokument wird dann auf `status: ACTIVE` gesetzt.
|
||||
@@ -0,0 +1,59 @@
|
||||
---
|
||||
type: Guide
|
||||
status: DRAFT
|
||||
owner: Backend Developer
|
||||
date: 2026-02-02
|
||||
last_update: 2026-03-15
|
||||
---
|
||||
|
||||
# Database Best Practices & Exposed 1.0.0
|
||||
|
||||
Dieser Guide beschreibt den korrekten Umgang mit der Datenbank-Schicht in unseren Backend-Services, basierend auf JetBrains Exposed 1.0.0.
|
||||
|
||||
## 1. Architektur-Prinzipien
|
||||
|
||||
* **Trennung:** Datenbank-Zugriffe gehören ausschließlich in die `infrastructure/persistence` Schicht. Services nutzen Repositories (Interfaces), keine direkten Exposed-Aufrufe.
|
||||
* **Transaktionen:** Jede geschäftliche Operation sollte in einer Transaktion laufen. Nutze dafür die Helper aus `DatabaseUtils.kt`.
|
||||
|
||||
## 2. Nutzung von `DatabaseUtils`
|
||||
|
||||
Wir haben zentrale Wrapper für Transaktionen, um Fehlerbehandlung und Logging zu vereinheitlichen.
|
||||
|
||||
### 2.1 Transaktionen starten
|
||||
|
||||
Nutze immer `transactionResult` (oder die Aliase `readTransaction` / `writeTransaction`), um Exposed-Code auszuführen.
|
||||
|
||||
```kotlin
|
||||
fun findUser(id: UUID): Result<User> = readTransaction {
|
||||
// 'this' ist hier eine JdbcTransaction
|
||||
UserTable.select { UserTable.id eq id }
|
||||
.map { /* row -> User(...) */ }
|
||||
.singleOrNull()
|
||||
}
|
||||
```
|
||||
|
||||
**Wichtig:** Der Lambda-Receiver ist `JdbcTransaction`. Das ermöglicht Zugriff auf Low-Level JDBC Funktionen, falls nötig.
|
||||
|
||||
### 2.2 Low-Level SQL (`exec`, `executeUpdate`)
|
||||
|
||||
Vermeide rohes SQL, wo immer möglich. Wenn es sein muss (z.B. für Performance-Optimierungen oder spezielle Postgres-Features), beachte folgende Regeln für Exposed 1.0.0:
|
||||
|
||||
* **`exec`:** Nutze immer `explicitStatementType`.
|
||||
```kotlin
|
||||
this.exec("SELECT 1", explicitStatementType = StatementType.SELECT) { rs -> /* handle ResultSet */ }
|
||||
```
|
||||
* **`executeUpdate`:** Nutze die Helper-Methode `DatabaseUtils.executeUpdate`, da sie sich um das korrekte Schließen von Statements kümmert (Exposed `PreparedStatementApi` ist nicht `AutoCloseable`).
|
||||
|
||||
## 3. Exposed 1.0.0 Besonderheiten
|
||||
|
||||
* **UUIDs:** Nutze `Table.javaUUID()` für `java.util.UUID` Spalten. `Table.uuid()` ist für `kotlin.uuid.Uuid` reserviert.
|
||||
* **JSONB:** Bei SQLite wird JSON automatisch gewrappt. Prüfe `castToJsonFormat` Flag.
|
||||
|
||||
## 4. Fehlerbehandlung
|
||||
|
||||
`DatabaseUtils` fängt `SQLException` ab und mappt sie auf unsere Domain-Fehler (`ErrorDto`):
|
||||
* Duplicate Key -> `ErrorCodes.DUPLICATE_ENTRY`
|
||||
* Foreign Key -> `ErrorCodes.FOREIGN_KEY_VIOLATION`
|
||||
* Timeout -> `ErrorCodes.DATABASE_TIMEOUT`
|
||||
|
||||
Wirf keine rohen Exceptions aus Repositories.
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
type: Guide
|
||||
status: REDIRECT
|
||||
owner: Curator
|
||||
tags: [testing, postman, backend, api]
|
||||
last_update: 2026-04-03
|
||||
---
|
||||
|
||||
# 🧪 Testanleitung: Ping‑Service & Gateway mit Postman (Weiterleitung)
|
||||
|
||||
Diese Seite wurde in ein zentrales Runbook für Betriebsanleitungen überführt.
|
||||
|
||||
Bitte nutze ab sofort das konsolidierte Runbook:
|
||||
|
||||
- Runbook: API‑Tests mit Postman
|
||||
`docs/07_Infrastructure/runbooks/POSTMAN_API_Tests_Runbook.md`
|
||||
|
||||
Hinweis: Dieser Eintrag bleibt als Verweis bestehen, damit bestehende Links nicht brechen.
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
type: Reference
|
||||
status: ACTIVE
|
||||
owner: Lead Architect
|
||||
last_update: 2026-04-03
|
||||
---
|
||||
|
||||
# Tenant-Isolation & Multi‑Tenant (Kurzfassung)
|
||||
|
||||
Vollständige Entscheidung: [ADR‑0021: Tenant‑Resolution‑Strategie (Schema‑per‑Tenant)](../01_Architecture/adr/0021-tenant-resolution-strategy-de.md).
|
||||
|
||||
## Kernaussagen
|
||||
|
||||
- Eine Veranstaltung = ein Tenant = ein Datenbankschema (Schema‑per‑Tenant).
|
||||
- Requests tragen `X-Event-Id`; Backend validiert gegen `control.tenants` und schaltet das Schema je Request.
|
||||
- Flyway führt Migrationen je Tenant‑Schema aus (eigene `flyway_schema_history`).
|
||||
- Stammdaten (Reiter/Pferde/Vereine/Funktionäre) sind global und nicht tenant‑spezifisch; Entries/Kassa sind tenant‑lokal.
|
||||
|
||||
## Umsetzung (Kurz)
|
||||
|
||||
- Web‑Layer: `TenantWebFilter` (Spring) bzw. Plugin (Ktor) liest `X-Event-Id` und legt `TenantContext` ab.
|
||||
- Persistence: SCHEMA‑Multitenancy (`SET search_path`) oder Hibernate‑`MultiTenantConnectionProvider`.
|
||||
- Registry: `control.tenants(event_id, schema_name, status, db_url?, version, created_at)`.
|
||||
|
||||
## Betroffene Bereiche
|
||||
|
||||
- Datenmodell tenant‑lokal: `veranstaltungen`, `turniere`, `bewerbe`, `abteilungen`, `teilnehmer_konten`, `turnier_kassa` (siehe [Datenbankschema](./Schema/Database_Schema_V1-V009.md)).
|
||||
- Services: Der Entries‑Service arbeitet mandantenfähig; andere Services bleiben Single‑Tenant/global (vgl. Backend‑Roadmap).
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
type: Reference
|
||||
status: ACTIVE
|
||||
owner: Backend Developer
|
||||
last_update: 2026-03-15
|
||||
---
|
||||
# Backend Dokumentation
|
||||
|
||||
Dieses Verzeichnis enthält die spezifische Dokumentation für alle Backend-Komponenten, einschließlich der Microservices und der Infrastruktur-Module wie dem API-Gateway.
|
||||
|
||||
## Struktur
|
||||
|
||||
* `Services/`: Enthält pro Service eine dedizierte Markdown-Datei, die dessen Zweck, API, Datenmodell und Konfiguration beschreibt.
|
||||
* `API/`: Querliegende API-Referenzen und Übersichten (Stammdaten, Kassa, usw.).
|
||||
* `Schema/`: Datenbankschemata und Migrationsübersichten (Flyway).
|
||||
* `Integration/`: Dokumentation zur Interaktion zwischen den Services (z.B. Event-Flows).
|
||||
|
||||
## Wichtige Einstiegspunkte
|
||||
|
||||
* **[Ping-Service](./Services/PingService_Reference.md):** Dient als technischer Blueprint und einfachstes Beispiel für einen Service.
|
||||
* **[API-Gateway](../07_Infrastructure/api-gateway.md):** Beschreibung des zentralen Einstiegspunkts für alle externen Anfragen.
|
||||
* **[Stammdaten-APIs (Reiter, Pferde, Vereine, Funktionäre)](./API/API_Uebersicht_Stammdaten.md):** Konsolidierte Endpunkt-Übersicht (Backend B‑1 abgeschlossen).
|
||||
* **[Datenbankschema V1–V009](./Schema/Database_Schema_V1-V009.md):** Tabellen und Constraints (veranstaltungen, turniere, bewerbe, abteilungen, teilnehmer_konten, turnier_kassa).
|
||||
* **[Kassa-API](./API/Kassa_API.md):** Platzhalter für Saldo/Transaktionen; wird ergänzt, sobald Backend B‑2 Kassa fertig ist.
|
||||
* **[Tenant-Isolation & Multi‑Tenant kurz](./Multi_Tenant_Kurz.md):** Zusammenfassung gem. ADR‑0021.
|
||||
@@ -0,0 +1,130 @@
|
||||
---
|
||||
type: Reference
|
||||
status: ACTIVE
|
||||
owner: Backend Developer
|
||||
last_update: 2026-04-03
|
||||
---
|
||||
|
||||
# Datenbankschema V1–V009 (Tenant‑Schema)
|
||||
|
||||
Quelle: Flyway‑Migrationen im Entries‑Service (`backend/services/entries/entries-service/src/main/resources/db/tenant/`), insbesondere `V2__domain_hierarchy.sql`.
|
||||
|
||||
Hinweis zur Architektur: Je Veranstaltung (Tenant) existiert ein eigenes Datenbankschema (ADR‑0021). Alle untenstehenden Tabellen werden pro Tenant‑Schema angelegt und sind somit mandantengetrennt.
|
||||
|
||||
## Tabellenübersicht
|
||||
|
||||
- `veranstaltungen` — Eine Veranstaltung (Singleton im Tenant‑Schema)
|
||||
- `turniere` — Turniere einer Veranstaltung (1:N zu `veranstaltungen`)
|
||||
- `bewerbe` — Bewerbe/Prüfungen eines Turniers (1:N zu `turniere`)
|
||||
- `abteilungen` — Abteilungen/Heats eines Bewerbs (1:N zu `bewerbe`)
|
||||
- `teilnehmer_konten` — Aggregierte Salden eines Teilnehmers über alle Turniere der Veranstaltung
|
||||
- `turnier_kassa` — Kassa‑Saldo pro Turnier
|
||||
|
||||
## Detaillierte Definitionen (aus V2__domain_hierarchy.sql)
|
||||
|
||||
### veranstaltungen
|
||||
Primärschlüssel: `id (UUID)`
|
||||
|
||||
Spalten:
|
||||
- `id UUID PRIMARY KEY`
|
||||
- `created_at TIMESTAMPTZ NOT NULL`
|
||||
- `updated_at TIMESTAMPTZ NOT NULL`
|
||||
|
||||
### turniere
|
||||
Primärschlüssel: `id (UUID)`
|
||||
Fremdschlüssel: `veranstaltung_id → veranstaltungen(id) ON DELETE CASCADE`
|
||||
|
||||
Spalten:
|
||||
- `id UUID PRIMARY KEY`
|
||||
- `veranstaltung_id UUID NOT NULL`
|
||||
- `oeps_turniernummer VARCHAR(50) NOT NULL`
|
||||
- `created_at TIMESTAMPTZ NOT NULL`
|
||||
- `updated_at TIMESTAMPTZ NOT NULL`
|
||||
|
||||
Indizes/Constraints:
|
||||
- `UNIQUE (oeps_turniernummer)` → `uq_turniere_oeps_nr`
|
||||
- `INDEX (veranstaltung_id)` → `idx_turniere_veranstaltung_id`
|
||||
|
||||
### bewerbe
|
||||
Primärschlüssel: `id (UUID)`
|
||||
Fremdschlüssel: `turnier_id → turniere(id) ON DELETE CASCADE`
|
||||
|
||||
Spalten:
|
||||
- `id UUID PRIMARY KEY`
|
||||
- `turnier_id UUID NOT NULL`
|
||||
- `klasse VARCHAR(50) NOT NULL`
|
||||
- `hoehe_cm INTEGER NULL`
|
||||
- `bezeichnung TEXT NOT NULL`
|
||||
- `created_at TIMESTAMPTZ NOT NULL`
|
||||
- `updated_at TIMESTAMPTZ NOT NULL`
|
||||
|
||||
Indizes:
|
||||
- `INDEX (turnier_id)` → `idx_bewerbe_turnier_id`
|
||||
- `INDEX (klasse)` → `idx_bewerbe_klasse`
|
||||
|
||||
### abteilungen
|
||||
Primärschlüssel: `id (UUID)`
|
||||
Fremdschlüssel: `bewerb_id → bewerbe(id) ON DELETE CASCADE`
|
||||
|
||||
Spalten:
|
||||
- `id UUID PRIMARY KEY`
|
||||
- `bewerb_id UUID NOT NULL`
|
||||
- `nr INTEGER NOT NULL`
|
||||
- `bezeichnung TEXT NOT NULL`
|
||||
- `typ VARCHAR(32) NOT NULL` (Werte: `SEPARATE_SIEGEREHRUNG`, `ORGANISATORISCH`)
|
||||
- `created_at TIMESTAMPTZ NOT NULL`
|
||||
- `updated_at TIMESTAMPTZ NOT NULL`
|
||||
|
||||
Constraints/Indizes:
|
||||
- `CHECK (typ IN ('SEPARATE_SIEGEREHRUNG','ORGANISATORISCH'))` → `chk_abteilungen_typ`
|
||||
- `UNIQUE (bewerb_id, nr)` → `uq_abteilungen_bewerb_nr`
|
||||
- `INDEX (bewerb_id)` → `idx_abteilungen_bewerb_id`
|
||||
- `INDEX (typ)` → `idx_abteilungen_typ`
|
||||
|
||||
### teilnehmer_konten
|
||||
Primärschlüssel: `id (UUID)`
|
||||
Fremdschlüssel: `veranstaltung_id → veranstaltungen(id) ON DELETE CASCADE`
|
||||
|
||||
Spalten:
|
||||
- `id UUID PRIMARY KEY`
|
||||
- `veranstaltung_id UUID NOT NULL`
|
||||
- `teilnehmer_id UUID NOT NULL`
|
||||
- `saldo_cents BIGINT NOT NULL DEFAULT 0`
|
||||
- `currency CHAR(3) NOT NULL DEFAULT 'EUR'`
|
||||
- `created_at TIMESTAMPTZ NOT NULL`
|
||||
- `updated_at TIMESTAMPTZ NOT NULL`
|
||||
|
||||
Indizes/Constraints:
|
||||
- `UNIQUE (veranstaltung_id, teilnehmer_id)` → `uq_tkonten_veranstaltung_teilnehmer`
|
||||
- `INDEX (veranstaltung_id)` → `idx_tkonten_veranstaltung_id`
|
||||
- `INDEX (teilnehmer_id)` → `idx_tkonten_teilnehmer_id`
|
||||
|
||||
### turnier_kassa
|
||||
Primärschlüssel: `id (UUID)`
|
||||
Fremdschlüssel: `turnier_id → turniere(id) ON DELETE CASCADE`
|
||||
|
||||
Spalten:
|
||||
- `id UUID PRIMARY KEY`
|
||||
- `turnier_id UUID NOT NULL`
|
||||
- `saldo_cents BIGINT NOT NULL DEFAULT 0`
|
||||
- `currency CHAR(3) NOT NULL DEFAULT 'EUR'`
|
||||
- `created_at TIMESTAMPTZ NOT NULL`
|
||||
- `updated_at TIMESTAMPTZ NOT NULL`
|
||||
|
||||
Indizes/Constraints:
|
||||
- `UNIQUE (turnier_id)` → `uq_turnier_kassa_turnier`
|
||||
- `INDEX (turnier_id)` → `idx_turnier_kassa_turnier_id`
|
||||
|
||||
## Versionierung / Flyway
|
||||
|
||||
- Die oben dokumentierten Tabellen sind in `V2__domain_hierarchy.sql` definiert.
|
||||
- Weitere Migrationen V1–V009 betreffen Bootstrap/Erweiterungen; diese Seite wird fortlaufend ergänzt, sobald neue fachrelevante Strukturen hinzukommen.
|
||||
|
||||
## Beziehungen (Kurz)
|
||||
|
||||
`veranstaltungen (1) ──< (N) turniere (1) ──< (N) bewerbe (1) ──< (N) abteilungen`
|
||||
|
||||
Separat aggregierend:
|
||||
|
||||
- `teilnehmer_konten` auf Veranstaltungsebene (pro Teilnehmer genau ein Konto)
|
||||
- `turnier_kassa` auf Turnierebene (pro Turnier genau ein Kassa‑Eintrag)
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
type: Reference
|
||||
status: ACTIVE
|
||||
owner: Backend Developer
|
||||
tags: [backend, service, reference, ping]
|
||||
last_update: 2026-04-03
|
||||
---
|
||||
|
||||
# 🎯 Ping Service Reference
|
||||
|
||||
Der `ping-service` ist der **"Tracer Bullet"** (Leuchtspurgeschoss) der Meldestelle-Architektur. Er ist kein Wegwerf-Prototyp, sondern die **Referenzimplementierung** für alle zukünftigen Microservices.
|
||||
|
||||
## 1. Mission & Verantwortung
|
||||
|
||||
* **Technischer Durchstich:** Beweist, dass die Kette *Frontend -> Gateway -> Service -> DB* funktioniert.
|
||||
* **Blueprint:** Definiert Standards für Architektur (DDD/Hexagonal), Testing, Security und Build-Prozesse.
|
||||
* **Infrastruktur-Validierung:** Testet die Integration mit Consul, Keycloak, Postgres, Redis und Zipkin.
|
||||
* **Offline-First Lab:** Hier wird die Delta-Sync-Logik (`/sync`) entwickelt und validiert, bevor sie in fachliche Services einzieht.
|
||||
|
||||
---
|
||||
|
||||
## 2. Technologie-Stack
|
||||
|
||||
* **Framework:** Spring Boot 3.5.x (Spring MVC, Tomcat).
|
||||
* **Sprache:** Kotlin 2.x (Coroutines für asynchrone Abläufe).
|
||||
* **Datenbank:** PostgreSQL (via Spring Data JPA).
|
||||
* **Migration:** Flyway (mit service-spezifischer Historientabelle `flyway_schema_history_ping`).
|
||||
* **Security:** OAuth2 Resource Server (JWT via Keycloak).
|
||||
* **Resilience:** Resilience4j (Circuit Breaker).
|
||||
* **API Contract:** KMP-Modul `:contracts:ping-api` (Shared Code mit Frontend).
|
||||
|
||||
---
|
||||
|
||||
## 3. Architektur (Hexagonal)
|
||||
|
||||
Der Service folgt strikt der **Ports & Adapters** (Hexagonal) Architektur:
|
||||
|
||||
1. **Domain (`at.mocode.ping.domain`):**
|
||||
* Der Kern. Enthält Entities (`Ping`) und Business-Regeln.
|
||||
* Frei von Frameworks (kein Spring, kein JPA).
|
||||
* Definiert Interfaces für Ports (`PingRepository`).
|
||||
|
||||
2. **Application (`at.mocode.ping.application`):**
|
||||
* Orchestriert die Use Cases (`PingUseCase`).
|
||||
* Steuert Transaktionen (`@Transactional`).
|
||||
* Verbindet Domain und Infrastructure.
|
||||
|
||||
3. **Infrastructure (`at.mocode.ping.infrastructure`):**
|
||||
* **Web:** `PingController` (REST API).
|
||||
* **Persistence:** `PingRepositoryAdapter` (JPA Implementierung).
|
||||
* **Security:** Global Config für JWT-Validierung.
|
||||
|
||||
---
|
||||
|
||||
## 4. API Endpunkte
|
||||
|
||||
| Methode | Pfad | Auth | Beschreibung |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `GET` | `/ping/simple` | 🔓 Public | Erstellt einen Ping in der DB. Testet Schreibzugriff. |
|
||||
| `GET` | `/ping/enhanced` | 🔓 Public | Testet Circuit Breaker. Parameter `simulate=true` löst Fehler aus. |
|
||||
| `GET` | `/ping/health` | 🔓 Public | Gibt Status "UP" zurück. |
|
||||
| `GET` | `/ping/public` | 🔓 Public | Expliziter Public-Test. |
|
||||
| `GET` | `/ping/secure` | 🔒 **Secure** | Erfordert Token mit Rolle `MELD_USER`. Testet Auth-Flow. |
|
||||
| `GET` | `/ping/sync` | 🔒 **Secure** | **Delta-Sync**. Liefert Änderungen seit `lastSyncTimestamp`. |
|
||||
|
||||
---
|
||||
|
||||
## 5. Getting Started
|
||||
|
||||
### A. Voraussetzungen
|
||||
* Java 25 (oder kompatibel).
|
||||
* Docker & Docker Compose (für Infrastruktur).
|
||||
|
||||
### B. Infrastruktur starten
|
||||
Bevor der Service laufen kann, braucht er Datenbank und Keycloak.
|
||||
```bash
|
||||
# Im Root-Verzeichnis
|
||||
docker compose --profile infra up -d
|
||||
```
|
||||
|
||||
### C. Starten via Gradle (Lokal)
|
||||
Ideal für Entwicklung und Debugging.
|
||||
```bash
|
||||
# Startet den Service im Profil "local"
|
||||
./gradlew :backend:services:ping:ping-service:bootRun
|
||||
```
|
||||
* **URL:** `http://localhost:8082` (Direktzugriff)
|
||||
* **Debug Port:** 5006
|
||||
|
||||
### D. Starten via Docker (Integration)
|
||||
Testet den Service im Container-Verbund (hinter dem Gateway).
|
||||
```bash
|
||||
# Baut das Image und startet es zusammen mit dem Gateway
|
||||
docker compose --profile backend up -d --build
|
||||
```
|
||||
* **URL (via Gateway):** `http://localhost:8081/api/ping/...`
|
||||
|
||||
---
|
||||
|
||||
## 6. Konfiguration
|
||||
|
||||
Die Konfiguration erfolgt primär über `application.yml` und Environment-Variables (12-Factor App).
|
||||
|
||||
| Variable | Default (Docker) | Beschreibung |
|
||||
| :--- | :--- | :--- |
|
||||
| `SERVER_PORT` | `8082` | Port des Services. |
|
||||
| `POSTGRES_DB_URL` | `jdbc:postgresql://postgres:5432/...` | JDBC URL. |
|
||||
| `SSEC_ISSUER_URI` | `http://keycloak:8080/...` | URL des Identity Providers (für Token-Check). |
|
||||
| `CONSUL_HOST` | `consul` | Host für Service Discovery. |
|
||||
|
||||
### Profile
|
||||
* `local`: Für lokale Entwicklung (nutzt `localhost` Adressen).
|
||||
* `docker`: Für Betrieb im Docker-Netzwerk (nutzt Service-Namen wie `postgres`).
|
||||
* `test`: Für Unit/Integration-Tests (nutzt H2 oder Testcontainers).
|
||||
|
||||
---
|
||||
|
||||
## 7. Testing
|
||||
|
||||
* **Unit Tests:** `./gradlew :backend:services:ping:ping-service:test`
|
||||
* **Manuelle Tests:** Siehe [Testing with Postman](../Guides/Testing_with_Postman.md).
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
---
|
||||
type: Task
|
||||
status: ARCHIVED
|
||||
owner: Senior Backend Developer
|
||||
created: 2026-01-15
|
||||
completed: 2026-01-16
|
||||
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.
|
||||
|
||||
* [x] **Security Configuration:**
|
||||
* Erstelle eine `SecurityConfig`-Klasse, die `SecurityFilterChain` konfiguriert.
|
||||
* Implementiere OAuth2 Resource Server Support (JWT Validierung).
|
||||
* Definiere globale CORS-Regeln (Frontend darf zugreifen).
|
||||
* [x] **Role Converter:**
|
||||
* Implementiere einen `KeycloakRoleConverter`, der die Rollen aus dem JWT (Realm/Resource Access) in Spring Security `GrantedAuthority` mapping.
|
||||
* **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.
|
||||
|
||||
* [x] **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."
|
||||
|
||||
* [x] **Flyway:**
|
||||
* Erstelle `src/main/resources/db/migration/V1__init_ping.sql`.
|
||||
* Definiere das Schema für die `ping` Tabelle.
|
||||
* [x] **API Implementation:**
|
||||
* Implementiere `/ping/public` (offen) und `/ping/secure` (benötigt Auth).
|
||||
* Nutze `@PreAuthorize("hasRole('MELD_USER')")` o.ä. zum Testen der Rollen.
|
||||
* [x] **Resilience:**
|
||||
* Konfiguriere Resilience4j (CircuitBreaker) für die DB-Verbindung (via `application.yml`).
|
||||
|
||||
### D. Gateway Integration (`backend/infrastructure/gateway`)
|
||||
* [x] **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/_archive/2026-03-15_MASTER_ROADMAP_2026_Q1.md)
|
||||
Reference in New Issue
Block a user