--- type: Note status: REDIRECT owner: Curator last_update: 2026-04-03 --- # 🧪 Postman Tests — Vollständige Dokumentation (verschoben) Diese ausführliche Arbeitsversion wurde konsolidiert und in das zentrale Runbook für Betriebsanleitungen überführt. Aktuelle Fassung: - `docs/07_Infrastructure/runbooks/POSTMAN_API_Tests_Runbook.md` Archiv: - Zusammenfassung im Archiv: `docs/04_Agents/_archive/Postman_Tests_Dokumentation_2026-04-03.md` Hinweis: Diese Datei bleibt als Weiterleitung bestehen, damit bestehende Links nicht brechen. --- ### 2.4 Swagger UI | Feld | Wert | |-------------|-----------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/swagger` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` — Swagger HTML-Interface **Tipp:** Im Browser öffnen für interaktive API-Erkundung. --- ## 3. Ping Service > **Zweck:** Funktionsfähigkeit des Ping-Service testen, Circuit Breaker und Sync-Funktionen validieren. > **Direkt-URL:** `{{pingUrl}}` = `http://localhost:8082` > **Via Gateway:** `{{baseUrl}}` = `http://localhost:8081` --- ### 3.1 Simple Ping | Feld | Wert | |-------------|---------------------------| | **Methode** | `GET` | | **URL** | `{{pingUrl}}/ping/simple` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` ```json { "message": "pong", "timestamp": "2026-04-03T14:00:00+02:00", "service": "ping-service", "status": "simple" } ``` **Wozu:** Einfachster Smoke-Test — bestätigt dass der Service läuft und die DB erreichbar ist. --- ### 3.2 Simple Ping via Gateway | Feld | Wert | |-------------|---------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/ping/simple` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` (identisch wie 3.1) **Wozu:** Bestätigt dass das Gateway den Ping-Service korrekt routet (Service Discovery via Consul). --- ### 3.3 Enhanced Ping (mit Circuit Breaker) | Feld | Wert | |-----------------|-----------------------------| | **Methode** | `GET` | | **URL** | `{{pingUrl}}/ping/enhanced` | | **Auth** | Keine | | **Query-Param** | `simulate=false` (Standard) | **Erwartete Antwort:** `200 OK` ```json { "message": "enhanced pong", "timestamp": "...", "service": "ping-service", "status": "enhanced", "circuitBreakerStatus": "CLOSED" } ``` **Wozu:** Bestätigt dass Resilience4j Circuit Breaker korrekt konfiguriert ist. --- ### 3.4 Enhanced Ping — Fehler simulieren | Feld | Wert | |-------------|-------------------------------------------| | **Methode** | `GET` | | **URL** | `{{pingUrl}}/ping/enhanced?simulate=true` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` mit Fallback-Response (kein 500-Fehler!) ```json { "message": "fallback response", "status": "fallback", "circuitBreakerStatus": "OPEN", "error": "..." } ``` **Wozu:** Bestätigt dass der Circuit Breaker Fallback greift (60% simulierte Fehlerrate). Der Service antwortet trotz Fehler mit einem sinnvollen Fallback. **Mehrfach ausführen:** Nach ~5 Anfragen mit `simulate=true` öffnet der Circuit Breaker. --- ### 3.5 Public Ping (kein Auth erforderlich) | Feld | Wert | |-------------|---------------------------| | **Methode** | `GET` | | **URL** | `{{pingUrl}}/ping/public` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` **Wozu:** Bestätigt dass der `/ping/public`-Endpunkt ohne JWT-Token erreichbar ist (Security-Konfiguration). --- ### 3.6 Secure Ping (Auth erforderlich) | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `GET` | | **URL** | `{{pingUrl}}/ping/secure` | | **Header** | `Authorization: Bearer {{authToken}}` | **Mit gültigem Token:** `200 OK` **Ohne Token:** `401 Unauthorized` **Wozu:** Bestätigt dass JWT-Authentifizierung korrekt erzwungen wird. --- ### 3.7 Sync Pings (seit Timestamp) | Feld | Wert | |-----------------|-----------------------------------| | **Methode** | `GET` | | **URL** | `{{pingUrl}}/ping/sync` | | **Auth** | Keine | | **Query-Param** | `since=0` (alle Pings seit Epoch) | **Erwartete Antwort:** `200 OK` ```json [ { "id": "...", "message": "pong", "timestamp": "...", "lamportClock": 1 } ] ``` **Wozu:** Testet den LAN-Sync-Endpunkt (Lamport-Uhren, Event-Sourcing Light). `since` ist ein Unix-Timestamp in Millisekunden. --- ### 3.8 Ping Service Health | Feld | Wert | |-------------|---------------------------| | **Methode** | `GET` | | **URL** | `{{pingUrl}}/ping/health` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` ```json { "status": "up", "timestamp": "...", "service": "ping-service", "healthy": true } ``` --- ## 4. Authentication Context > **Zweck:** Benutzer-Registrierung, Login und Profilverwaltung über Keycloak testen. > **Reihenfolge:** Zuerst registrieren → dann einloggen → Token in `{{authToken}}` speichern. --- ### 4.1 User Registration | Feld | Wert | |-------------|----------------------------------| | **Methode** | `POST` | | **URL** | `{{baseUrl}}/auth/register` | | **Header** | `Content-Type: application/json` | **Request Body:** ```json { "email": "test@example.com", "password": "SecurePassword123!", "firstName": "Test", "lastName": "User", "phoneNumber": "+43123456789" } ``` **Erwartete Antwort:** `201 Created` ```json { "userId": "uuid-...", "email": "test@example.com", "message": "Registrierung erfolgreich" } ``` **Wozu:** Legt einen neuen Benutzer in Keycloak an. --- ### 4.2 User Login | Feld | Wert | |-------------|----------------------------------| | **Methode** | `POST` | | **URL** | `{{baseUrl}}/auth/login` | | **Header** | `Content-Type: application/json` | **Request Body:** ```json { "email": "test@example.com", "password": "SecurePassword123!" } ``` **Erwartete Antwort:** `200 OK` ```json { "accessToken": "eyJhbGci...", "refreshToken": "...", "expiresIn": 300 } ``` > **⚡ Tipp:** Postman-Test-Script einfügen um Token automatisch zu speichern: > ```javascript > var json = pm.response.json(); > pm.environment.set("authToken", json.accessToken); > ``` --- ### 4.3 Get User Profile | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/auth/profile` | | **Header** | `Authorization: Bearer {{authToken}}` | **Erwartete Antwort:** `200 OK` ```json { "userId": "...", "email": "test@example.com", "firstName": "Test", "lastName": "User" } ``` --- ### 4.4 Update User Profile | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `PUT` | | **URL** | `{{baseUrl}}/auth/profile` | | **Header** | `Content-Type: application/json` | | **Header** | `Authorization: Bearer {{authToken}}` | **Request Body:** ```json { "firstName": "Updated", "lastName": "User", "phoneNumber": "+43987654321" } ``` **Erwartete Antwort:** `200 OK` — aktualisierte Profildaten --- ### 4.5 Change Password | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `POST` | | **URL** | `{{baseUrl}}/auth/change-password` | | **Header** | `Content-Type: application/json` | | **Header** | `Authorization: Bearer {{authToken}}` | **Request Body:** ```json { "currentPassword": "SecurePassword123!", "newPassword": "NewSecurePassword456!" } ``` **Erwartete Antwort:** `200 OK` **Fehlerfall (falsches Passwort):** `400 Bad Request` --- ## 5. Master Data: Countries > **Zweck:** Länderstammdaten verwalten. Diese sind Voraussetzung für Pferde- und Reiter-Datensätze. > **Basis-URL:** `{{baseUrl}}/api/masterdata/countries` > **Hinweis:** GET-Endpunkte sind ohne Auth zugänglich; POST/PUT/DELETE benötigen `{{authToken}}`. --- ### 5.1 Get All Countries | Feld | Wert | |-------------|----------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/masterdata/countries` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` — Array aller Länder (inkl. inaktive) --- ### 5.2 Get Active Countries | Feld | Wert | |-------------|-----------------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/masterdata/countries/active` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` — Nur Länder mit `istAktiv: true` **Wozu:** Für Dropdown-Listen in der Desktop-App (nur aktive Länder anzeigen). --- ### 5.3 Get Country by ID | Feld | Wert | |-------------|------------------------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/masterdata/countries/{{countryId}}` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` — Einzelnes Land **Fehlerfall:** `404 Not Found` --- ### 5.4 Get Country by ISO Code | Feld | Wert | |-------------|-----------------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/masterdata/countries/iso/AT` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` ```json { "id": "...", "isoAlpha2Code": "AT", "nameDeutsch": "Österreich", "istEuMitglied": true, "istAktiv": true } ``` **Wozu:** Österreich ist das primäre Land — dieser Test prüft ob die Stammdaten korrekt befüllt sind. --- ### 5.5 Create Country | Feld | Wert | |-------------|----------------------------------------| | **Methode** | `POST` | | **URL** | `{{baseUrl}}/api/masterdata/countries` | | **Header** | `Content-Type: application/json` | | **Header** | `Authorization: Bearer {{authToken}}` | **Request Body:** ```json { "isoAlpha2Code": "TS", "isoAlpha3Code": "TST", "isoNumerischerCode": "999", "nameDeutsch": "Testland", "nameEnglisch": "Testland", "istEuMitglied": false, "istEwrMitglied": false, "istAktiv": true, "sortierReihenfolge": 999 } ``` **Erwartete Antwort:** `201 Created` > **⚡ Tipp:** `countryId` aus der Antwort in Environment-Variable speichern: > ```javascript > var json = pm.response.json(); > pm.environment.set("countryId", json.id); > ``` --- ### 5.6 Update Country | Feld | Wert | |-------------|------------------------------------------------------| | **Methode** | `PUT` | | **URL** | `{{baseUrl}}/api/masterdata/countries/{{countryId}}` | | **Header** | `Content-Type: application/json` | | **Header** | `Authorization: Bearer {{authToken}}` | **Request Body:** ```json { "isoAlpha2Code": "TS", "isoAlpha3Code": "TST", "isoNumerischerCode": "999", "nameDeutsch": "Updated Testland", "nameEnglisch": "Updated Testland", "istEuMitglied": false, "istEwrMitglied": false, "istAktiv": true, "sortierReihenfolge": 999 } ``` **Erwartete Antwort:** `200 OK` --- ### 5.7 Delete Country | Feld | Wert | |-------------|------------------------------------------------------| | **Methode** | `DELETE` | | **URL** | `{{baseUrl}}/api/masterdata/countries/{{countryId}}` | | **Header** | `Authorization: Bearer {{authToken}}` | **Erwartete Antwort:** `204 No Content` **Fehlerfall (nicht gefunden):** `404 Not Found` --- ## 6. Horse Registry (Pferde) > **Zweck:** Pferde-Stammdaten verwalten (CRUD). > **⚠️ Hinweis Tabellen-Name:** In der Datenbank heißt die Tabelle `horse` (englisch), nicht `pferd`. > **Basis-URL:** `{{baseUrl}}/api/horses` --- ### 6.1 Get All Horses | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/horses` | | **Header** | `Authorization: Bearer {{authToken}}` | **Erwartete Antwort:** `200 OK` — Array aller Pferde **Nach ZNS-Import:** Hier erscheinen alle importierten Pferde. --- ### 6.2 Get Active Horses | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/horses/active` | | **Header** | `Authorization: Bearer {{authToken}}` | **Erwartete Antwort:** `200 OK` — Nur Pferde mit `istAktiv: true` --- ### 6.3 Get Horse by ID | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/horses/{{horseId}}` | | **Header** | `Authorization: Bearer {{authToken}}` | **Erwartete Antwort:** `200 OK` ```json { "id": "uuid-...", "pferdeName": "Amadeus", "geschlecht": "WALLACH", "geburtsdatum": "2020-05-15", "rasse": "Warmblut", "farbe": "Braun", "stockmass": 165, "istAktiv": true } ``` --- ### 6.4 Search Horses by Name | Feld | Wert | |-------------|----------------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/horses/search` | | **Query** | `name=Test` (Suchbegriff), `limit=10` (max.) | | **Header** | `Authorization: Bearer {{authToken}}` | **Erwartete Antwort:** `200 OK` — gefilterte Pferde-Liste **Wozu:** Echtzeit-Suche in der Desktop-App. Testen mit einem Namen aus dem ZNS-Import. --- ### 6.5 Get Horses by Owner | Feld | Wert | |-------------|--------------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/horses/owner/{{ownerId}}` | | **Header** | `Authorization: Bearer {{authToken}}` | **Erwartete Antwort:** `200 OK` — alle Pferde eines bestimmten Besitzers --- ### 6.6 Create Horse | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `POST` | | **URL** | `{{baseUrl}}/api/horses` | | **Header** | `Content-Type: application/json` | | **Header** | `Authorization: Bearer {{authToken}}` | **Request Body:** ```json { "pferdeName": "Test Horse", "geschlecht": "WALLACH", "geburtsdatum": "2020-05-15", "rasse": "Warmblut", "farbe": "Braun", "zuechterName": "Test Breeder", "stockmass": 165, "istAktiv": true, "bemerkungen": "Test horse for API demonstration" } ``` **Gültige Werte für `geschlecht`:** `WALLACH`, `STUTE`, `HENGST` **Erwartete Antwort:** `201 Created` > **⚡ Tipp:** `horseId` automatisch speichern: > ```javascript > var json = pm.response.json(); > pm.environment.set("horseId", json.id); > ``` --- ### 6.7 Update Horse | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `PUT` | | **URL** | `{{baseUrl}}/api/horses/{{horseId}}` | | **Header** | `Content-Type: application/json` | | **Header** | `Authorization: Bearer {{authToken}}` | **Request Body:** ```json { "pferdeName": "Updated Test Horse", "geschlecht": "WALLACH", "geburtsdatum": "2020-05-15", "rasse": "Warmblut", "farbe": "Dunkelbraun", "zuechterName": "Updated Test Breeder", "stockmass": 167, "istAktiv": true, "bemerkungen": "Updated test horse for API demonstration" } ``` **Erwartete Antwort:** `200 OK` --- ### 6.8 Delete Horse | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `DELETE` | | **URL** | `{{baseUrl}}/api/horses/{{horseId}}` | | **Header** | `Authorization: Bearer {{authToken}}` | **Erwartete Antwort:** `204 No Content` --- ### 6.9 Batch Delete Horses | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `DELETE` | | **URL** | `{{baseUrl}}/api/horses/batch` | | **Header** | `Content-Type: application/json` | | **Header** | `Authorization: Bearer {{authToken}}` | **Request Body:** ```json { "horseIds": ["{{horseId1}}", "{{horseId2}}"], "forceDelete": false } ``` **`forceDelete: false`** → Nur löschen wenn keine Abhängigkeiten vorhanden **`forceDelete: true`** → Auch bei Abhängigkeiten löschen (⚠️ Vorsicht!) **Erwartete Antwort:** `200 OK` --- ### 6.10 Get Horse Statistics | Feld | Wert | |-------------|---------------------------------------| | **Methode** | `GET` | | **URL** | `{{baseUrl}}/api/horses/stats` | | **Header** | `Authorization: Bearer {{authToken}}` | **Erwartete Antwort:** `200 OK` ```json { "total": 42, "active": 38, "inactive": 4, "byGeschlecht": { "WALLACH": 20, "STUTE": 18, "HENGST": 4 } } ``` **Wozu:** Schnelle Übersicht über den Datenbestand nach dem ZNS-Import. --- ## 7. ZNS Import Service > **Zweck:** ZNS-Daten (Reiter, Pferde, Vereine, Funktionäre) aus einer `.zip`/`.dat`-Datei importieren. > **Direkt-URL:** `{{znsUrl}}` = `http://localhost:8095` > **Basis-Pfad:** `/api/v1/import/zns` --- ### 7.1 ZNS Import starten | Feld | Wert | |--------------|------------------------------------------| | **Methode** | `POST` | | **URL** | `{{znsUrl}}/api/v1/import/zns` | | **Body-Typ** | `form-data` | | **Key** | `file` (Type: **File**) | | **Value** | ZNS-Datei auswählen (`.zip` oder `.dat`) | **Schritt-für-Schritt in Postman:** 1. Methode: `POST` 2. URL: `http://localhost:8095/api/v1/import/zns` 3. Tab **Body** → **form-data** 4. Key: `file` → Typ auf **File** umstellen (Dropdown neben dem Key-Feld) 5. Value: ZNS-Datei auswählen 6. **Send** klicken **Erwartete Antwort:** `202 Accepted` ```json { "jobId": "abc-123-def-456", "status": "STARTED", "message": "Import gestartet", "startedAt": "2026-04-03T14:00:00+02:00" } ``` > **⚡ Tipp:** `jobId` automatisch speichern: > ```javascript > var json = pm.response.json(); > pm.environment.set("znsJobId", json.jobId); > ``` --- ### 7.2 ZNS Import-Status abfragen | Feld | Wert | |-------------|----------------------------------------------------| | **Methode** | `GET` | | **URL** | `{{znsUrl}}/api/v1/import/zns/{{znsJobId}}/status` | | **Auth** | Keine | **Antwort während Import:** `200 OK` ```json { "jobId": "abc-123-def-456", "status": "IN_PROGRESS", "processedRecords": 150, "totalRecords": 500, "progressPercent": 30, "startedAt": "2026-04-03T14:00:00+02:00" } ``` **Antwort nach Abschluss:** `200 OK` ```json { "jobId": "abc-123-def-456", "status": "COMPLETED", "processedRecords": 500, "totalRecords": 500, "progressPercent": 100, "importedReiter": 200, "importedPferde": 180, "importedVereine": 30, "importedFunktionaere": 90, "startedAt": "2026-04-03T14:00:00+02:00", "completedAt": "2026-04-03T14:01:30+02:00" } ``` **Mögliche Status-Werte:** | Status | Bedeutung | |---------------|----------------------------------------| | `STARTED` | Job wurde angenommen, noch nicht aktiv | | `IN_PROGRESS` | Import läuft gerade | | `COMPLETED` | Import erfolgreich abgeschlossen | | `FAILED` | Import fehlgeschlagen (Fehlerdetails) | **Wozu:** Status pollen bis `COMPLETED` — dann Daten in pgAdmin oder Desktop-App prüfen. --- ### 7.3 ZNS Import Health-Check | Feld | Wert | |-------------|------------------------------| | **Methode** | `GET` | | **URL** | `{{znsUrl}}/actuator/health` | | **Auth** | Keine | **Erwartete Antwort:** `200 OK` ```json { "status": "UP", "components": { "db": { "status": "UP" }, "diskSpace": { "status": "UP" } } } ``` **⚠️ Consul-Check:** Nach dem Neustart des ZNS-Service sollte er im Consul-UI unter http://localhost:8500 unter dem Namen `zns-import-service` erscheinen. --- ## 8. Empfohlene Test-Reihenfolge ### Schnell-Smoke-Test (5 Minuten) ``` 1. GET {{pingUrl}}/ping/simple → "pong" ✓ 2. GET {{baseUrl}}/health → "UP" ✓ 3. GET {{znsUrl}}/actuator/health → "UP" ✓ 4. GET {{baseUrl}}/api/masterdata/countries/iso/AT → Österreich ✓ ``` ### Vollständiger Integrations-Test (heute, ZNS-Import) ``` 1. GET {{pingUrl}}/ping/simple → Smoke-Test 2. GET {{pingUrl}}/ping/enhanced → Circuit Breaker CLOSED 3. GET {{pingUrl}}/ping/enhanced?simulate=true → Fallback greift 4. POST {{baseUrl}}/auth/login → Token speichern 5. GET {{baseUrl}}/api/masterdata/countries/iso/AT → Stammdaten vorhanden 6. GET {{baseUrl}}/api/horses → (leer vor Import) 7. GET {{znsUrl}}/actuator/health → ZNS bereit 8. POST {{znsUrl}}/api/v1/import/zns → ZNS-Datei hochladen → jobId speichern 9. GET {{znsUrl}}/api/v1/import/zns/{{znsJobId}}/status → Status pollen bis COMPLETED 10. GET {{baseUrl}}/api/horses → Pferde jetzt befüllt ✓ 11. GET {{baseUrl}}/api/horses/stats → Statistiken prüfen 12. GET {{baseUrl}}/api/horses/search?name=... → Suche testen ``` --- ## Anhang: Alle URLs auf einen Blick | Service | URL | Verwendung | |----------------|-----------------------|--------------------------| | API-Gateway | http://localhost:8081 | Haupt-Einstiegspunkt | | Ping (direkt) | http://localhost:8082 | Ping-Endpunkte direkt | | ZNS-Import | http://localhost:8095 | Import-Endpunkte | | Keycloak Admin | http://localhost:8180 | Auth-Verwaltung | | Consul UI | http://localhost:8500 | Service-Discovery prüfen | | Zipkin | http://localhost:9411 | Traces nachverfolgen | | pgAdmin | http://localhost:8888 | DB-Inhalte prüfen | | Mailpit | http://localhost:8025 | E-Mail-Mock |