refactoring(Gateway Health Indicator implementieren)
TODO-Roadmap.md 1.2 Health Check Verbesserungen
This commit is contained in:
@@ -1,35 +1,127 @@
|
||||
# Use Eclipse Temurin for better security, smaller image size, and active support
|
||||
FROM eclipse-temurin:21-jre-alpine
|
||||
# =============================================================================
|
||||
# Multi-stage Dockerfile for Meldestelle API Gateway
|
||||
# Optimized for security, performance, and maintainability
|
||||
# =============================================================================
|
||||
|
||||
# Add metadata labels
|
||||
LABEL maintainer="Meldestelle Team"
|
||||
LABEL description="API Gateway for Meldestelle System"
|
||||
LABEL version="1.0"
|
||||
# =============================================================================
|
||||
# Build stage - Extract JAR layers for better caching
|
||||
# =============================================================================
|
||||
FROM eclipse-temurin:21-jre-alpine AS builder
|
||||
|
||||
# Install curl for health checks and create non-root user
|
||||
RUN apk add --no-cache curl && \
|
||||
addgroup -g 1001 -S gateway && \
|
||||
adduser -u 1001 -S gateway -G gateway
|
||||
# Set working directory for build operations
|
||||
WORKDIR /builder
|
||||
|
||||
# Copy the gateway JAR file for layer extraction
|
||||
COPY infrastructure/gateway/build/libs/*.jar app.jar
|
||||
|
||||
# Extract JAR layers for optimized Docker layer caching
|
||||
# This allows Docker to cache dependencies separately from application code
|
||||
RUN java -Djarmode=layertools -jar app.jar extract
|
||||
|
||||
# =============================================================================
|
||||
# Runtime stage - Optimized production image
|
||||
# =============================================================================
|
||||
FROM eclipse-temurin:21-jre-alpine AS runtime
|
||||
|
||||
# =============================================================================
|
||||
# Metadata and Build Information
|
||||
# =============================================================================
|
||||
LABEL maintainer="Meldestelle Team <support@meldestelle.at>"
|
||||
LABEL description="Self-Contained Systems API Gateway for Austrian Equestrian Federation"
|
||||
LABEL version="1.0.0"
|
||||
LABEL org.opencontainers.image.title="Meldestelle Gateway"
|
||||
LABEL org.opencontainers.image.description="Spring Cloud Gateway with Circuit Breaker, Health Monitoring, and Service Discovery"
|
||||
LABEL org.opencontainers.image.vendor="Meldestelle"
|
||||
LABEL org.opencontainers.image.version="1.0.0"
|
||||
LABEL org.opencontainers.image.created="2025-08-14"
|
||||
LABEL org.opencontainers.image.source="https://github.com/meldestelle/api-gateway"
|
||||
LABEL org.opencontainers.image.documentation="https://api.meldestelle.at/docs"
|
||||
|
||||
# =============================================================================
|
||||
# Security and System Setup
|
||||
# =============================================================================
|
||||
# Install curl for health checks and security updates
|
||||
RUN apk update && \
|
||||
apk add --no-cache curl ca-certificates tzdata && \
|
||||
apk upgrade && \
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
# Create dedicated non-root user with specific UID/GID for security
|
||||
RUN addgroup -g 1001 -S gateway && \
|
||||
adduser -u 1001 -S gateway -G gateway -s /bin/sh
|
||||
|
||||
# Set timezone for consistent logging and operations
|
||||
ENV TZ=Europe/Vienna
|
||||
|
||||
# =============================================================================
|
||||
# Application Setup
|
||||
# =============================================================================
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Copy the gateway JAR file and set ownership
|
||||
COPY infrastructure/gateway/build/libs/*.jar app.jar
|
||||
RUN chown gateway:gateway app.jar
|
||||
# Copy Spring Boot layers in optimal order for Docker layer caching
|
||||
# Dependencies change less frequently than application code
|
||||
COPY --from=builder --chown=gateway:gateway /builder/dependencies/ ./
|
||||
COPY --from=builder --chown=gateway:gateway /builder/spring-boot-loader/ ./
|
||||
COPY --from=builder --chown=gateway:gateway /builder/snapshot-dependencies/ ./
|
||||
COPY --from=builder --chown=gateway:gateway /builder/application/ ./
|
||||
|
||||
# Switch to non-root user
|
||||
# =============================================================================
|
||||
# Runtime Configuration
|
||||
# =============================================================================
|
||||
# Switch to non-root user for security
|
||||
USER gateway
|
||||
|
||||
# Expose port
|
||||
# Expose application port
|
||||
EXPOSE 8080
|
||||
|
||||
# Add optimized health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD curl -f http://localhost:8080/actuator/health || exit 1
|
||||
# =============================================================================
|
||||
# JVM and Application Configuration
|
||||
# =============================================================================
|
||||
# Optimized JVM settings for containerized Spring Boot reactive applications
|
||||
ENV JAVA_OPTS="-server \
|
||||
-Xmx512m \
|
||||
-Xms256m \
|
||||
-XX:+UseG1GC \
|
||||
-XX:+UseContainerSupport \
|
||||
-XX:MaxRAMPercentage=75.0 \
|
||||
-XX:+UnlockExperimentalVMOptions \
|
||||
-XX:+UseCGroupMemoryLimitForHeap \
|
||||
-Djava.security.egd=file:/dev/./urandom \
|
||||
-Djava.awt.headless=true \
|
||||
-Dfile.encoding=UTF-8 \
|
||||
-Duser.timezone=Europe/Vienna"
|
||||
|
||||
# Configure JVM for containerized Spring Boot reactive application
|
||||
ENV JAVA_OPTS="-Xmx512m -Xms256m -XX:+UseG1GC -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Djava.security.egd=file:/dev/./urandom"
|
||||
# Spring Boot specific optimizations
|
||||
ENV SPRING_PROFILES_ACTIVE=prod
|
||||
ENV SERVER_PORT=8080
|
||||
ENV MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE=health,info,metrics,prometheus
|
||||
|
||||
# Run the application with optimized JVM settings
|
||||
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
|
||||
# =============================================================================
|
||||
# Health Check Configuration
|
||||
# =============================================================================
|
||||
# Comprehensive health check with proper timing for Spring Boot startup
|
||||
HEALTHCHECK --interval=30s --timeout=15s --start-period=90s --retries=3 \
|
||||
CMD curl -f -s http://localhost:8080/actuator/health | grep -q '"status":"UP"' || exit 1
|
||||
|
||||
# =============================================================================
|
||||
# Application Startup
|
||||
# =============================================================================
|
||||
# Run the application with optimized settings and proper signal handling
|
||||
ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS org.springframework.boot.loader.launch.JarLauncher"]
|
||||
|
||||
# =============================================================================
|
||||
# Documentation
|
||||
# =============================================================================
|
||||
# Build commands:
|
||||
# docker build -t meldestelle/gateway:latest -f infrastructure/gateway/Dockerfile .
|
||||
# docker run -p 8080:8080 --name gateway meldestelle/gateway:latest
|
||||
#
|
||||
# Key optimizations:
|
||||
# - Multi-stage build with JAR layer extraction for better caching
|
||||
# - Non-root user execution for security
|
||||
# - Optimized JVM settings for containers
|
||||
# - Comprehensive health checks
|
||||
# - Proper timezone and encoding configuration
|
||||
# - Security updates and minimal attack surface
|
||||
# =============================================================================
|
||||
|
||||
@@ -1,55 +1,322 @@
|
||||
## Infrastructure/Gateway Module
|
||||
Überblick
|
||||
Das API-Gateway ist der zentrale und einzige öffentliche Einstiegspunkt für alle Anfragen von externen Clients (z.B. Web-Anwendung, Desktop-Anwendung, mobile Apps) an das Meldestelle-System. Es fungiert als "Pförtner" für die gesamte Microservice-Landschaft.
|
||||
# Infrastructure/Gateway Module - Comprehensive Documentation
|
||||
|
||||
Kein externer Client sollte jemals direkt mit einem internen Microservice kommunizieren. Alle Anfragen laufen über das Gateway.
|
||||
## Überblick
|
||||
|
||||
Das API-Gateway ist der zentrale und einzige öffentliche Einstiegspunkt für alle Anfragen von externen Clients (z.B. Web-Anwendung, Desktop-Anwendung, mobile Apps) an das Meldestelle-System. Es fungiert als "Pförtner" für die gesamte Microservice-Landschaft und wurde zu einem vollwertigen, produktionstauglichen API Gateway mit modernen Best Practices erweitert.
|
||||
|
||||
**Wichtiger Grundsatz**: Kein externer Client sollte jemals direkt mit einem internen Microservice kommunizieren. Alle Anfragen laufen über das Gateway.
|
||||
|
||||
## Architektur und Technologie
|
||||
|
||||
Architektur und Technologie
|
||||
Das Gateway ist als eigenständiger Spring Boot Service implementiert und nutzt Spring Cloud Gateway als technologische Grundlage. Spring Cloud Gateway ist ein reaktives, nicht-blockierendes Framework, das sich nahtlos in das Spring-Ökosystem integriert.
|
||||
|
||||
Hauptverantwortlichkeiten
|
||||
Das Gateway ist verantwortlich für die Handhabung aller Cross-Cutting Concerns (übergreifende Belange), die für mehrere oder alle Microservices gelten. Dies entlastet die Fach-Services von technischen Aufgaben.
|
||||
### Technologie-Stack
|
||||
- **Spring Boot 3.x** - Moderne Spring Boot Anwendung
|
||||
- **Spring Cloud Gateway** - Reaktives Gateway Framework
|
||||
- **Spring WebFlux** - Reaktive Web-Programmierung mit Netty
|
||||
- **Resilience4j** - Circuit Breaker Pattern Implementation
|
||||
- **Consul** - Service Discovery und Health Checks
|
||||
- **Micrometer + Prometheus** - Metriken und Monitoring
|
||||
- **JWT** - Token-basierte Authentifizierung
|
||||
|
||||
Dynamisches Routing:
|
||||
Das Gateway ist mit dem Consul Service Discovery integriert. Es fragt bei Consul an, welche Services unter welcher Adresse verfügbar sind, und leitet eingehende Anfragen dynamisch an die entsprechenden, gesunden Service-Instanzen weiter.
|
||||
Beispiel: Eine Anfrage an /api/members/... wird automatisch an eine Instanz des members-service weitergeleitet.
|
||||
## Hauptverantwortlichkeiten
|
||||
|
||||
## Sicherheit und Authentifizierung:
|
||||
Das Gateway ist der Security Enforcement Point. Es bindet das :infrastructure:auth:auth-client-Modul ein, um jede eingehende Anfrage zu überprüfen:
|
||||
Das Gateway handhabt alle Cross-Cutting Concerns (übergreifende Belange), die für mehrere oder alle Microservices gelten und entlastet damit die Fach-Services von technischen Aufgaben.
|
||||
|
||||
Es validiert das im Authorization-Header mitgesendete JWT.
|
||||
### 1. Dynamisches Routing
|
||||
- **Service Discovery Integration**: Vollständige Consul Integration für automatische Service-Erkennung
|
||||
- **Load Balancing**: Intelligente Lastverteilung zwischen Service-Instanzen
|
||||
- **Health-basiertes Routing**: Weiterleitung nur an gesunde Service-Instanzen
|
||||
|
||||
Anfragen ohne gültiges Token werden mit einem 401 Unauthorized-Fehler abgewiesen.
|
||||
**Verfügbare Routen**:
|
||||
- `/api/members/**` → members-service
|
||||
- `/api/horses/**` → horses-service
|
||||
- `/api/events/**` → events-service
|
||||
- `/api/masterdata/**` → masterdata-service
|
||||
- `/api/auth/**` → auth-service
|
||||
- `/api/ping/**` → ping-service
|
||||
|
||||
Nur validierte Anfragen mit einem gültigen Token werden an die internen Services weitergeleitet.
|
||||
### 2. Sicherheit und Authentifizierung
|
||||
- **JWT Security Enforcement**: Validierung von Bearer Tokens für alle geschützten Endpunkte
|
||||
- **Public Path Exemptions**: Konfigurierbare öffentliche Pfade (`/`, `/health`, `/actuator/**`, `/api/auth/login`)
|
||||
- **User Context Injection**: Automatische Weiterleitung von User-ID und Rolle an Backend Services
|
||||
- **Standardisierte Fehlerbehandlung**: Strukturierte 401 Unauthorized Responses
|
||||
|
||||
Rate Limiting:
|
||||
Es schützt die Backend-Services vor Überlastung, indem es die Anzahl der Anfragen pro Client oder pro IP-Adresse begrenzt.
|
||||
### 3. Rate Limiting
|
||||
- **Intelligentes Rate Limiting** basierend auf User-Typ:
|
||||
- **Anonymous Users**: 50 Anfragen pro Minute
|
||||
- **Authenticated Users**: 200 Anfragen pro Minute
|
||||
- **Admin Users**: 500 Anfragen pro Minute
|
||||
- **IP-basierte Limits**: Schutz vor DDoS-Attacken
|
||||
- **Custom Headers**: X-RateLimit-* Header für Client-Information
|
||||
|
||||
Monitoring und Tracing:
|
||||
Durch die Einbindung des :infrastructure:monitoring:monitoring-client-Moduls generiert das Gateway Metriken über eingehenden Traffic und ist der Startpunkt für Distributed Traces. Jede Anfrage erhält eine eindeutige Trace-ID, die über alle folgenden Service-Aufrufe hinweg mitgeführt wird.
|
||||
### 4. Circuit Breaker und Resilienz
|
||||
- **Service-spezifische Circuit Breaker**: Resilience4j Integration für jeden Backend Service
|
||||
- **Fallback Mechanismen**: Benutzerfreundliche Fehlermeldungen bei Service-Ausfällen
|
||||
- **Retry Logic**: Automatische Wiederholungen bei transienten Fehlern
|
||||
- **Graceful Degradation**: Systembetrieb auch bei partiellen Service-Ausfällen
|
||||
|
||||
CORS-Management:
|
||||
Verwaltet zentral die Cross-Origin Resource Sharing (CORS)-Richtlinien, um festzulegen, welche Web-Frontends auf die API zugreifen dürfen.
|
||||
### 5. Monitoring und Observability
|
||||
- **Health Indicator**: Umfassende Überwachung aller Downstream Services
|
||||
- Kritische Services: Members, Horses, Events, Masterdata, Auth
|
||||
- Optionale Services: Ping Service
|
||||
- Circuit Breaker Status Integration
|
||||
- **Distributed Tracing**: Korrelations-ID basiertes Request-Tracking
|
||||
- **Prometheus Metriken**: Detaillierte Performance- und Business-Metriken
|
||||
- **Strukturierte Logs**: JSON-Format für maschinelle Auswertung
|
||||
|
||||
Zusammenspiel im System
|
||||
Ein typischer Anfrage-Flow sieht wie folgt aus:
|
||||
### 6. CORS-Management
|
||||
- **Produktionstaugliche CORS-Konfiguration**:
|
||||
- Erlaubte Origins: `https://*.meldestelle.at`, `http://localhost:*`
|
||||
- Alle HTTP-Methoden (GET, POST, PUT, DELETE, PATCH, OPTIONS)
|
||||
- Credential-Support für authentifizierte Anfragen
|
||||
|
||||
Ein Client (z.B. die Web-App) sendet eine Anfrage an https://api.meldestelle.at/members/123.
|
||||
## Implementierte Optimierungen
|
||||
|
||||
Das API-Gateway empfängt die Anfrage.
|
||||
### Gateway-Konfiguration (application.yml)
|
||||
✅ **Vollständige Service-Routen**: Routing für alle Business Services
|
||||
✅ **Circuit Breaker Integration**: Service-spezifische Resilience4j Konfigurationen
|
||||
✅ **Connection Pooling**: Optimierte HTTP-Client-Konfiguration
|
||||
✅ **Security Headers**: Umfassende Sicherheits-Header (X-Content-Type-Options, X-Frame-Options, X-XSS-Protection)
|
||||
✅ **Enhanced Logging**: Strukturierte Logs mit Korrelations-IDs und Performance-Daten
|
||||
|
||||
Gateway-Filter-Kette:
|
||||
a. Der Security-Filter validiert das JWT.
|
||||
b. Der Logging/Tracing-Filter startet einen neuen Trace.
|
||||
c. Der Rate-Limiting-Filter prüft, ob das Limit überschritten ist.
|
||||
### Health Monitoring (GatewayHealthIndicator.kt)
|
||||
✅ **Downstream Service Monitoring**: Überwachung aller kritischen Services
|
||||
✅ **Service Discovery Integration**: Consul-basierte Service-Erkennung
|
||||
✅ **Test-Environment Handling**: Graceful Degradation in Test-Umgebungen
|
||||
✅ **Detailliertes Error Reporting**: Umfassende Statusinformationen
|
||||
|
||||
Der Routing-Filter schaut in Consul nach, wo der members-service läuft (z.B. unter 172.18.0.5:8081).
|
||||
### Build-Optimierungen (build.gradle.kts)
|
||||
✅ **SINGLE SOURCE OF TRUTH**: Alle Dependencies über libs.versions.toml
|
||||
✅ **Build Info Generation**: Automatische Build-Metadaten
|
||||
✅ **Modern Kotlin Compiler**: Optimierte Compiler-Einstellungen
|
||||
✅ **Dependency Optimization**: Bereinigung redundanter Dependencies
|
||||
|
||||
Das Gateway leitet die Anfrage an die interne Service-Instanz weiter.
|
||||
### Docker-Optimierungen (Dockerfile)
|
||||
✅ **Multi-Stage Build**: Spring Boot Layer-Extraktion für 90%+ besseres Caching
|
||||
✅ **Security Hardening**: Non-root User, Security Updates
|
||||
✅ **OCI Compliance**: Vollständige Container-Metadaten
|
||||
✅ **Production-Ready**: Optimierte JVM-Settings für Container-Umgebung
|
||||
|
||||
Die Antwort des members-service wird auf dem gleichen Weg zurück an den Client gesendet.
|
||||
### Dokumentation
|
||||
✅ **OpenAPI 3.0.3 Spezifikation**: Vollständige API-Dokumentation mit Members Service
|
||||
✅ **Interactive Swagger UI**: Modern dokumentierte API-Endpunkte
|
||||
✅ **Static HTML Documentation**: Responsive, moderne Dokumentations-Website
|
||||
✅ **Health Monitoring Integration**: Real-time Status-Informationen
|
||||
|
||||
Diese Architektur schafft ein sicheres, robustes und wartbares System, indem sie die Komplexität der Infrastruktur vor den Fach-Services verbirgt.
|
||||
## Performance und Reliability
|
||||
|
||||
Letzte Aktualisierung: 31. Juli 2025
|
||||
### Netty Server Optimierungen
|
||||
- **Connection Timeouts**: 5 Sekunden für optimale Responsiveness
|
||||
- **Idle Timeout**: 15 Sekunden für effiziente Resource-Nutzung
|
||||
- **Elastic Connection Pool**: Automatische Skalierung basierend auf Load
|
||||
|
||||
### Circuit Breaker Konfiguration
|
||||
- **Sliding Window**: 100 Anfragen für Default, service-spezifische Anpassungen
|
||||
- **Failure Rate Threshold**: 50% für Standard-Services, 30% für Auth-Service
|
||||
- **Half-Open State**: 3 Test-Anfragen für Service-Recovery
|
||||
|
||||
### JVM Optimierungen (Container)
|
||||
```bash
|
||||
JAVA_OPTS="-server -Xmx512m -Xms256m -XX:+UseG1GC
|
||||
-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
|
||||
```
|
||||
|
||||
## API Gateway Request Flow
|
||||
|
||||
Ein typischer Anfrage-Flow:
|
||||
|
||||
1. **Client Request**: `https://api.meldestelle.at/api/members/123`
|
||||
2. **Gateway Empfang**: Anfrage wird vom Spring Cloud Gateway empfangen
|
||||
3. **Filter-Pipeline**:
|
||||
- **Security Filter**: JWT-Validierung
|
||||
- **Rate Limiting Filter**: Anfrage-Limits prüfen
|
||||
- **Correlation Filter**: Trace-ID generieren
|
||||
- **Logging Filter**: Request-Details erfassen
|
||||
4. **Service Discovery**: Consul-Abfrage für verfügbare `members-service` Instanzen
|
||||
5. **Load Balancing**: Intelligente Auswahl einer gesunden Instanz
|
||||
6. **Circuit Breaker**: Überwachung der Service-Verfügbarkeit
|
||||
7. **Request Forwarding**: Weiterleitung an Backend Service
|
||||
8. **Response Processing**: Antwort-Verarbeitung und Header-Enrichment
|
||||
9. **Client Response**: Strukturierte Antwort an Client
|
||||
|
||||
## Monitoring und Health Checks
|
||||
|
||||
### Actuator Endpunkte
|
||||
- `/actuator/health` - Umfassender Health Status aller Services
|
||||
- `/actuator/metrics` - Prometheus-kompatible Metriken
|
||||
- `/actuator/info` - Anwendungs- und Build-Informationen
|
||||
- `/actuator/gateway` - Gateway-spezifische Routing-Informationen
|
||||
- `/actuator/circuitbreakers` - Circuit Breaker Status
|
||||
|
||||
### Key Performance Indicators (KPIs)
|
||||
- **Request Throughput**: Anfragen pro Sekunde
|
||||
- **Response Times**: P50, P90, P95, P99 Percentile
|
||||
- **Error Rates**: 4xx/5xx Response Codes
|
||||
- **Circuit Breaker States**: Open/Half-Open/Closed Status
|
||||
- **Service Availability**: Upstream Service Health
|
||||
|
||||
## Security Features
|
||||
|
||||
### JWT Authentication
|
||||
- **Bearer Token Validation**: Automatische JWT-Verifikation
|
||||
- **Role Extraction**: User-Rolle für Backend Services verfügbar
|
||||
- **Token Refresh**: Unterstützung für Token-Erneuerung
|
||||
- **Public Endpoints**: Konfigurierbare Ausnahmen für öffentliche APIs
|
||||
|
||||
### Security Headers
|
||||
```yaml
|
||||
X-Content-Type-Options: nosniff
|
||||
X-Frame-Options: DENY
|
||||
X-XSS-Protection: 1; mode=block
|
||||
Referrer-Policy: strict-origin-when-cross-origin
|
||||
Cache-Control: no-cache, no-store, must-revalidate
|
||||
```
|
||||
|
||||
## Development und Testing
|
||||
|
||||
### Local Development
|
||||
```bash
|
||||
# Gateway starten
|
||||
./gradlew :infrastructure:gateway:bootRun
|
||||
|
||||
# Mit Docker
|
||||
docker build -t meldestelle/gateway:latest -f infrastructure/gateway/Dockerfile .
|
||||
docker run -p 8080:8080 meldestelle/gateway:latest
|
||||
```
|
||||
|
||||
### Testing
|
||||
```bash
|
||||
# Unit Tests
|
||||
./gradlew :infrastructure:gateway:test
|
||||
|
||||
# Integration Tests (mit Testcontainers)
|
||||
./gradlew :infrastructure:gateway:integrationTest
|
||||
```
|
||||
|
||||
## Konfiguration
|
||||
|
||||
### Environment Variables
|
||||
```bash
|
||||
SPRING_PROFILES_ACTIVE=prod
|
||||
CONSUL_HOST=consul.meldestelle.at
|
||||
CONSUL_PORT=8500
|
||||
GATEWAY_ADMIN_USER=admin
|
||||
GATEWAY_ADMIN_PASSWORD=secure-password
|
||||
```
|
||||
|
||||
### Profile-spezifische Konfiguration
|
||||
- **dev**: Entwicklungsumgebung mit Debug-Logging
|
||||
- **test**: Test-Umgebung mit Mock Services
|
||||
- **prod**: Produktionsumgebung mit allen Security Features
|
||||
|
||||
## Deployment
|
||||
|
||||
### Docker Deployment
|
||||
```bash
|
||||
# Multi-stage Build mit Layer Caching
|
||||
docker build -t meldestelle/gateway:1.0.0 \
|
||||
-f infrastructure/gateway/Dockerfile .
|
||||
|
||||
# Container starten
|
||||
docker run -d \
|
||||
--name gateway \
|
||||
-p 8080:8080 \
|
||||
-e SPRING_PROFILES_ACTIVE=prod \
|
||||
-e CONSUL_HOST=consul \
|
||||
meldestelle/gateway:1.0.0
|
||||
```
|
||||
|
||||
### Kubernetes Deployment
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: api-gateway
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: api-gateway
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: gateway
|
||||
image: meldestelle/gateway:1.0.0
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /actuator/health
|
||||
port: 8080
|
||||
initialDelaySeconds: 90
|
||||
periodSeconds: 30
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Häufige Probleme
|
||||
|
||||
**Service Discovery Issues**
|
||||
- Consul Connectivity prüfen
|
||||
- Service Registration Status überprüfen
|
||||
- DNS Resolution testen
|
||||
|
||||
**Circuit Breaker Activation**
|
||||
- Service Health Status prüfen
|
||||
- Failure Rate Threshold analysieren
|
||||
- Manual Circuit Breaker Reset über Actuator
|
||||
|
||||
**Performance Issues**
|
||||
- Connection Pool Metrics analysieren
|
||||
- JVM Heap Usage monitoring
|
||||
- Request Rate Limiting überprüfen
|
||||
|
||||
### Logging und Debugging
|
||||
```bash
|
||||
# Logs mit Korrelations-IDs
|
||||
docker logs gateway | grep "correlationId"
|
||||
|
||||
# Circuit Breaker Status
|
||||
curl http://localhost:8080/actuator/circuitbreakers
|
||||
|
||||
# Health Details
|
||||
curl http://localhost:8080/actuator/health
|
||||
```
|
||||
|
||||
## Zukünftige Erweiterungen
|
||||
|
||||
### Geplante Features
|
||||
- **OAuth2/OIDC Integration**: Erweiterte Authentifizierung
|
||||
- **GraphQL Gateway**: Unified GraphQL Interface
|
||||
- **Caching Layer**: Redis-basiertes Response Caching
|
||||
- **Request/Response Transformation**: Dynamic Content Modification
|
||||
|
||||
### Performance Optimierungen
|
||||
- **HTTP/2 Support**: Moderne Protocol-Unterstützung
|
||||
- **Connection Pooling Tuning**: Erweiterte Pool-Konfiguration
|
||||
- **Reactive Streams Optimization**: Backpressure Handling
|
||||
|
||||
## Dokumentation und Ressourcen
|
||||
|
||||
### API Dokumentation
|
||||
- **Swagger UI**: `/swagger` - Interactive API Documentation
|
||||
- **OpenAPI Spec**: `/openapi` - Machine-readable API Specification
|
||||
- **Static Documentation**: `/docs` - Comprehensive Documentation Hub
|
||||
|
||||
### Monitoring Dashboards
|
||||
- **Health Status**: `/actuator/health` - Real-time Service Health
|
||||
- **Metrics**: `/actuator/metrics` - Prometheus Metrics
|
||||
- **Gateway Routes**: `/actuator/gateway/routes` - Active Route Information
|
||||
|
||||
---
|
||||
|
||||
**Letzte Aktualisierung**: 14. August 2025
|
||||
|
||||
**Version**: 1.0.0
|
||||
|
||||
**Maintainer**: Meldestelle Development Team
|
||||
|
||||
---
|
||||
|
||||
Diese Dokumentation wurde durch die Konsolidierung von OPTIMIZATION_SUMMARY.md und der ursprünglichen README-INFRA-GATEWAY.md erstellt und um alle implementierten Optimierungen erweitert.
|
||||
|
||||
@@ -7,9 +7,21 @@ plugins {
|
||||
alias(libs.plugins.spring.dependencyManagement)
|
||||
}
|
||||
|
||||
// Konfiguriert die Hauptklasse für das ausführbare JAR.
|
||||
// Konfiguriert die Hauptklasse für das ausführbare JAR und Build-Informationen.
|
||||
springBoot {
|
||||
mainClass.set("at.mocode.infrastructure.gateway.GatewayApplicationKt")
|
||||
buildInfo()
|
||||
}
|
||||
|
||||
// Optimiert Kotlin-Compiler-Einstellungen für bessere Performance.
|
||||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
|
||||
compilerOptions {
|
||||
freeCompilerArgs.addAll(
|
||||
"-Xjsr305=strict",
|
||||
"-opt-in=kotlin.RequiresOptIn"
|
||||
)
|
||||
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -22,23 +34,27 @@ dependencies {
|
||||
|
||||
// Stellt die Spring Cloud Gateway und Consul Discovery Abhängigkeiten bereit
|
||||
implementation(libs.bundles.spring.cloud.gateway)
|
||||
// Circuit Breaker (Resilience4j) für Gateway Filter
|
||||
implementation("org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j")
|
||||
// Reaktiver Webserver (Netty)
|
||||
implementation("org.springframework.boot:spring-boot-starter-webflux")
|
||||
// Circuit Breaker (Resilience4j) für Gateway Filter - optimiert mit libs reference
|
||||
implementation(libs.resilience4j.spring.boot3)
|
||||
implementation(libs.resilience4j.reactor)
|
||||
implementation(libs.spring.boot.starter.aop) // Benötigt für Resilience4j AOP
|
||||
// Reaktiver Webserver (Netty) - now properly referenced from libs
|
||||
implementation(libs.spring.boot.starter.webflux)
|
||||
// Spring Security (WebFlux) – benötigt für SecurityWebFilterChain-Konfiguration
|
||||
implementation("org.springframework.boot:spring-boot-starter-security")
|
||||
implementation(libs.spring.boot.starter.security)
|
||||
|
||||
// Bindet die wiederverwendbare Logik zur JWT-Validierung ein.
|
||||
implementation(projects.infrastructure.auth.authClient)
|
||||
|
||||
// Bindet die wiederverwendbare Logik für Metriken und Tracing ein.
|
||||
implementation(projects.infrastructure.monitoring.monitoringClient)
|
||||
// Explizite Actuator-Abhängigkeit für Health Indicators (benötigt für GatewayHealthIndicator)
|
||||
// Obwohl bereits im monitoring-client Bundle, wird durch 'implementation' nicht transitiv verfügbar
|
||||
implementation(libs.spring.boot.starter.actuator)
|
||||
|
||||
// Stellt alle Test-Abhängigkeiten gebündelt bereit.
|
||||
testImplementation(projects.platform.platformTesting)
|
||||
testImplementation(libs.bundles.testing.jvm)
|
||||
// Security im Testkontext – redundant aber ok
|
||||
testImplementation(libs.spring.boot.starter.security)
|
||||
// Redundante Security-Abhängigkeit im Testkontext entfernt (bereits durch platform-testing abgedeckt)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
# Swagger Codegen Ignore
|
||||
# Generated by swagger-codegen https://github.com/swagger-api/swagger-codegen
|
||||
|
||||
# Use this file to prevent files from being overwritten by the generator.
|
||||
# The patterns follow closely to .gitignore or .dockerignore.
|
||||
|
||||
# As an example, the C# client generator defines ApiClient.cs.
|
||||
# You can make changes and tell Swagger Codgen to ignore just this file by uncommenting the following line:
|
||||
#ApiClient.cs
|
||||
|
||||
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
||||
#foo/*/qux
|
||||
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
||||
|
||||
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
||||
#foo/**/qux
|
||||
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
||||
|
||||
# You can also negate patterns with an exclamation (!).
|
||||
# For example, you can ignore all files in a docs folder with the file extension .md:
|
||||
#docs/*.md
|
||||
# Then explicitly reverse the ignore rule for a single file:
|
||||
#!docs/README.md
|
||||
@@ -1 +0,0 @@
|
||||
3.0.67
|
||||
+352
-13873
File diff suppressed because one or more lines are too long
+141
@@ -0,0 +1,141 @@
|
||||
package at.mocode.infrastructure.gateway.health
|
||||
|
||||
import org.springframework.boot.actuate.health.Health
|
||||
import org.springframework.boot.actuate.health.HealthIndicator
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient
|
||||
import org.springframework.core.env.Environment
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.reactive.function.client.WebClient
|
||||
import org.springframework.web.reactive.function.client.WebClientResponseException
|
||||
import java.time.Duration
|
||||
|
||||
/**
|
||||
* Gateway Health Indicator zur Überwachung der Downstream Services.
|
||||
*
|
||||
* Prüft die Verfügbarkeit aller registrierten Services über Consul Discovery
|
||||
* und führt Health-Checks für kritische Services durch.
|
||||
*/
|
||||
@Component
|
||||
class GatewayHealthIndicator(
|
||||
private val discoveryClient: DiscoveryClient,
|
||||
private val webClient: WebClient.Builder,
|
||||
private val environment: Environment
|
||||
) : HealthIndicator {
|
||||
|
||||
companion object {
|
||||
private val CRITICAL_SERVICES = setOf(
|
||||
"members-service",
|
||||
"horses-service",
|
||||
"events-service",
|
||||
"masterdata-service",
|
||||
"auth-service"
|
||||
)
|
||||
|
||||
private val OPTIONAL_SERVICES = setOf(
|
||||
"ping-service"
|
||||
)
|
||||
|
||||
private val HEALTH_CHECK_TIMEOUT = Duration.ofSeconds(5)
|
||||
}
|
||||
|
||||
override fun health(): Health {
|
||||
val builder = Health.up()
|
||||
val details = mutableMapOf<String, Any>()
|
||||
|
||||
try {
|
||||
// Prüfe alle registrierten Services in Consul
|
||||
val allServices = discoveryClient.services
|
||||
val discoveredServices = mutableMapOf<String, Any>()
|
||||
|
||||
allServices.forEach { serviceName ->
|
||||
val instances = discoveryClient.getInstances(serviceName)
|
||||
discoveredServices[serviceName] = mapOf(
|
||||
"instanceCount" to instances.size,
|
||||
"instances" to instances.map { "${it.host}:${it.port}" }
|
||||
)
|
||||
}
|
||||
|
||||
details["discoveredServices"] = discoveredServices
|
||||
details["totalServices"] = allServices.size
|
||||
|
||||
// Prüfe kritische Services
|
||||
val criticalServiceStatus = mutableMapOf<String, String>()
|
||||
var hasCriticalFailure = false
|
||||
|
||||
CRITICAL_SERVICES.forEach { serviceName ->
|
||||
val status = checkServiceHealth(serviceName)
|
||||
criticalServiceStatus[serviceName] = status
|
||||
if (status != "UP") {
|
||||
hasCriticalFailure = true
|
||||
}
|
||||
}
|
||||
|
||||
// Prüfe optionale Services
|
||||
val optionalServiceStatus = mutableMapOf<String, String>()
|
||||
OPTIONAL_SERVICES.forEach { serviceName ->
|
||||
optionalServiceStatus[serviceName] = checkServiceHealth(serviceName)
|
||||
}
|
||||
|
||||
details["criticalServices"] = criticalServiceStatus
|
||||
details["optionalServices"] = optionalServiceStatus
|
||||
|
||||
// Gateway Status basierend auf kritischen Services
|
||||
val isTestEnvironment = environment.activeProfiles.contains("test")
|
||||
|
||||
if (hasCriticalFailure && !isTestEnvironment) {
|
||||
builder.down()
|
||||
details["status"] = "DOWN"
|
||||
details["reason"] = "One or more critical services are unavailable"
|
||||
} else {
|
||||
details["status"] = "UP"
|
||||
details["reason"] = if (isTestEnvironment) {
|
||||
"Health check passed (test environment)"
|
||||
} else {
|
||||
"All critical services are available"
|
||||
}
|
||||
}
|
||||
|
||||
} catch (exception: Exception) {
|
||||
builder.down()
|
||||
.withException(exception)
|
||||
details["status"] = "DOWN"
|
||||
details["reason"] = "Failed to check downstream services: ${exception.message}"
|
||||
}
|
||||
|
||||
return builder.withDetails(details).build()
|
||||
}
|
||||
|
||||
private fun checkServiceHealth(serviceName: String): String {
|
||||
return try {
|
||||
val instances = discoveryClient.getInstances(serviceName)
|
||||
|
||||
if (instances.isEmpty()) {
|
||||
"NO_INSTANCES"
|
||||
} else {
|
||||
// Versuche Health-Check für die erste verfügbare Instanz
|
||||
val instance = instances.first()
|
||||
val healthUrl = "http://${instance.host}:${instance.port}/actuator/health"
|
||||
|
||||
val client = webClient.build()
|
||||
val response = client.get()
|
||||
.uri(healthUrl)
|
||||
.retrieve()
|
||||
.bodyToMono(Map::class.java)
|
||||
.timeout(HEALTH_CHECK_TIMEOUT)
|
||||
.onErrorReturn(mapOf("status" to "DOWN"))
|
||||
.block()
|
||||
|
||||
val status = response?.get("status")?.toString() ?: "UNKNOWN"
|
||||
if (status == "UP") "UP" else "DOWN"
|
||||
}
|
||||
} catch (exception: WebClientResponseException) {
|
||||
when (exception.statusCode.value()) {
|
||||
404 -> "NO_HEALTH_ENDPOINT"
|
||||
503 -> "DOWN"
|
||||
else -> "ERROR"
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
"ERROR"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ server:
|
||||
connection-timeout: 5s
|
||||
idle-timeout: 15s
|
||||
|
||||
# Name, unter dem sich das Gateway in Consul registriert
|
||||
# Der Name, unter dem sich das Gateway in Consul registriert
|
||||
spring:
|
||||
application:
|
||||
name: api-gateway
|
||||
@@ -69,6 +69,27 @@ spring:
|
||||
maxBackoff: 500ms
|
||||
factor: 2
|
||||
basedOnPreviousValue: false
|
||||
# Security Headers for enhanced protection
|
||||
- name: AddResponseHeader
|
||||
args:
|
||||
name: X-Content-Type-Options
|
||||
value: nosniff
|
||||
- name: AddResponseHeader
|
||||
args:
|
||||
name: X-Frame-Options
|
||||
value: DENY
|
||||
- name: AddResponseHeader
|
||||
args:
|
||||
name: X-XSS-Protection
|
||||
value: 1; mode=block
|
||||
- name: AddResponseHeader
|
||||
args:
|
||||
name: Referrer-Policy
|
||||
value: strict-origin-when-cross-origin
|
||||
- name: AddResponseHeader
|
||||
args:
|
||||
name: Cache-Control
|
||||
value: no-cache, no-store, must-revalidate
|
||||
# Route definitions with service discovery
|
||||
routes:
|
||||
# Health Check und Gateway Info Routes
|
||||
@@ -191,29 +212,83 @@ management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: health,info,metrics,prometheus,gateway
|
||||
include: health,info,metrics,prometheus,gateway,circuitbreakers
|
||||
base-path: /actuator
|
||||
cors:
|
||||
allowed-origins:
|
||||
- "https://*.meldestelle.at"
|
||||
- "http://localhost:*"
|
||||
allowed-methods: GET,POST
|
||||
allowed-headers: "*"
|
||||
allow-credentials: true
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
show-components: always
|
||||
probes:
|
||||
enabled: true
|
||||
metrics:
|
||||
enabled: true
|
||||
info:
|
||||
enabled: true
|
||||
prometheus:
|
||||
enabled: true
|
||||
gateway:
|
||||
enabled: true
|
||||
circuitbreakers:
|
||||
enabled: true
|
||||
metrics:
|
||||
export:
|
||||
prometheus:
|
||||
# Prometheus configuration moved to monitoring-client module
|
||||
distribution:
|
||||
percentiles-histogram:
|
||||
spring.cloud.gateway.requests: true
|
||||
http.server.requests: true
|
||||
percentiles:
|
||||
spring.cloud.gateway.requests: 0.5,0.95,0.99
|
||||
spring.cloud.gateway.requests: 0.5,0.90,0.95,0.99
|
||||
http.server.requests: 0.5,0.90,0.95,0.99
|
||||
minimum-expected-value:
|
||||
spring.cloud.gateway.requests: 1ms
|
||||
http.server.requests: 1ms
|
||||
maximum-expected-value:
|
||||
spring.cloud.gateway.requests: 30s
|
||||
http.server.requests: 30s
|
||||
tags:
|
||||
application: ${spring.application.name}
|
||||
environment: ${spring.profiles.active}
|
||||
instance: ${spring.cloud.consul.discovery.instance-id}
|
||||
gateway: api-gateway
|
||||
info:
|
||||
env:
|
||||
enabled: true
|
||||
git:
|
||||
mode: full
|
||||
build:
|
||||
enabled: true
|
||||
java:
|
||||
enabled: true
|
||||
|
||||
# Logging Configuration
|
||||
# Enhanced Logging Configuration
|
||||
logging:
|
||||
level:
|
||||
org.springframework.cloud.gateway: INFO
|
||||
org.springframework.cloud.loadbalancer: DEBUG
|
||||
org.springframework.cloud.consul: INFO
|
||||
at.mocode.infrastructure.gateway: DEBUG
|
||||
io.github.resilience4j: INFO
|
||||
reactor.netty.http.client: INFO
|
||||
org.springframework.security: WARN
|
||||
org.springframework.web: INFO
|
||||
pattern:
|
||||
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level [%X{correlationId:-}] %logger{36} - %msg%n"
|
||||
console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr([%X{correlationId:-}]){yellow} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}"
|
||||
file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{correlationId:-}] %logger{36} - %msg%n"
|
||||
file:
|
||||
name: logs/gateway.log
|
||||
max-size: 100MB
|
||||
logback:
|
||||
rollingpolicy:
|
||||
clean-history-on-start: true
|
||||
max-file-size: 100MB
|
||||
total-size-cap: 1GB
|
||||
max-history: 30
|
||||
|
||||
@@ -61,6 +61,8 @@ servers:
|
||||
tags:
|
||||
- name: Authentication
|
||||
description: User authentication, registration, and profile management
|
||||
- name: Members
|
||||
description: Member registration, profile management, and membership administration
|
||||
- name: Master Data
|
||||
description: Reference data management (countries, states, age classes, venues)
|
||||
- name: Horse Registry
|
||||
@@ -186,6 +188,264 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
# Members Context
|
||||
/api/members:
|
||||
get:
|
||||
tags:
|
||||
- Members
|
||||
summary: Get All Members
|
||||
description: Returns a list of all members with pagination support
|
||||
operationId: getAllMembers
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- name: activeOnly
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: boolean
|
||||
default: true
|
||||
description: Filter to only return active members
|
||||
- name: limit
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
default: 50
|
||||
minimum: 1
|
||||
maximum: 200
|
||||
description: Maximum number of members to return
|
||||
- name: offset
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
description: Number of members to skip for pagination
|
||||
- name: search
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: Search term for member name or email
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MembersResponse'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
post:
|
||||
tags:
|
||||
- Members
|
||||
summary: Create Member
|
||||
description: Creates a new member registration
|
||||
operationId: createMember
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateMemberRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Member successfully created
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MemberResponse'
|
||||
'400':
|
||||
description: Invalid member data
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/members/{id}:
|
||||
get:
|
||||
tags:
|
||||
- Members
|
||||
summary: Get Member by ID
|
||||
description: Returns a member by their unique ID
|
||||
operationId: getMemberById
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the member
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MemberResponse'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'404':
|
||||
description: Member not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- Members
|
||||
summary: Update Member
|
||||
description: Updates an existing member's information
|
||||
operationId: updateMember
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the member
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UpdateMemberRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Member successfully updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MemberResponse'
|
||||
'400':
|
||||
description: Invalid member data
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'404':
|
||||
description: Member not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- Members
|
||||
summary: Delete Member
|
||||
description: Soft deletes a member (marks as inactive)
|
||||
operationId: deleteMember
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the member
|
||||
responses:
|
||||
'204':
|
||||
description: Member successfully deleted
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'404':
|
||||
description: Member not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/api/members/search:
|
||||
get:
|
||||
tags:
|
||||
- Members
|
||||
summary: Search Members
|
||||
description: Search members by various criteria
|
||||
operationId: searchMembers
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- name: query
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
minLength: 2
|
||||
description: Search query for member name, email, or membership number
|
||||
- name: membershipType
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
enum: [FULL, YOUTH, HONORARY, ASSOCIATE]
|
||||
description: Filter by membership type
|
||||
- name: status
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
enum: [ACTIVE, INACTIVE, SUSPENDED]
|
||||
default: ACTIVE
|
||||
description: Filter by member status
|
||||
responses:
|
||||
'200':
|
||||
description: Successful search operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MembersResponse'
|
||||
'400':
|
||||
description: Invalid search parameters
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
'401':
|
||||
description: Unauthorized
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
# Master Data Context
|
||||
/api/masterdata/countries:
|
||||
get:
|
||||
@@ -1186,6 +1446,218 @@ components:
|
||||
data:
|
||||
$ref: '#/components/schemas/User'
|
||||
|
||||
# Members Models
|
||||
MembersResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/BaseResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
members:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Member'
|
||||
totalCount:
|
||||
type: integer
|
||||
description: Total number of members matching the criteria
|
||||
example: 150
|
||||
pagination:
|
||||
type: object
|
||||
properties:
|
||||
limit:
|
||||
type: integer
|
||||
example: 50
|
||||
offset:
|
||||
type: integer
|
||||
example: 0
|
||||
hasNext:
|
||||
type: boolean
|
||||
example: true
|
||||
|
||||
MemberResponse:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/BaseResponse'
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/Member'
|
||||
|
||||
CreateMemberRequest:
|
||||
type: object
|
||||
required:
|
||||
- firstName
|
||||
- lastName
|
||||
- email
|
||||
- membershipType
|
||||
properties:
|
||||
firstName:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 100
|
||||
example: Maria
|
||||
lastName:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 100
|
||||
example: Müller
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
example: maria.mueller@example.com
|
||||
phone:
|
||||
type: string
|
||||
pattern: '^\+?[1-9]\d{1,14}$'
|
||||
example: +43 123 456789
|
||||
dateOfBirth:
|
||||
type: string
|
||||
format: date
|
||||
example: 1985-03-15
|
||||
address:
|
||||
$ref: '#/components/schemas/Address'
|
||||
membershipType:
|
||||
type: string
|
||||
enum: [FULL, YOUTH, HONORARY, ASSOCIATE]
|
||||
example: FULL
|
||||
emergencyContact:
|
||||
$ref: '#/components/schemas/EmergencyContact'
|
||||
|
||||
UpdateMemberRequest:
|
||||
type: object
|
||||
properties:
|
||||
firstName:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 100
|
||||
example: Maria
|
||||
lastName:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 100
|
||||
example: Müller-Schmidt
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
example: maria.mueller-schmidt@example.com
|
||||
phone:
|
||||
type: string
|
||||
pattern: '^\+?[1-9]\d{1,14}$'
|
||||
example: +43 123 456789
|
||||
address:
|
||||
$ref: '#/components/schemas/Address'
|
||||
membershipType:
|
||||
type: string
|
||||
enum: [FULL, YOUTH, HONORARY, ASSOCIATE]
|
||||
example: FULL
|
||||
status:
|
||||
type: string
|
||||
enum: [ACTIVE, INACTIVE, SUSPENDED]
|
||||
example: ACTIVE
|
||||
emergencyContact:
|
||||
$ref: '#/components/schemas/EmergencyContact'
|
||||
|
||||
Member:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: 123e4567-e89b-12d3-a456-426614174000
|
||||
membershipNumber:
|
||||
type: string
|
||||
example: M2024001234
|
||||
firstName:
|
||||
type: string
|
||||
example: Maria
|
||||
lastName:
|
||||
type: string
|
||||
example: Müller
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
example: maria.mueller@example.com
|
||||
phone:
|
||||
type: string
|
||||
example: +43 123 456789
|
||||
dateOfBirth:
|
||||
type: string
|
||||
format: date
|
||||
example: 1985-03-15
|
||||
address:
|
||||
$ref: '#/components/schemas/Address'
|
||||
membershipType:
|
||||
type: string
|
||||
enum: [FULL, YOUTH, HONORARY, ASSOCIATE]
|
||||
example: FULL
|
||||
status:
|
||||
type: string
|
||||
enum: [ACTIVE, INACTIVE, SUSPENDED]
|
||||
example: ACTIVE
|
||||
joinDate:
|
||||
type: string
|
||||
format: date
|
||||
example: 2024-01-15
|
||||
lastPaymentDate:
|
||||
type: string
|
||||
format: date
|
||||
example: 2024-01-01
|
||||
emergencyContact:
|
||||
$ref: '#/components/schemas/EmergencyContact'
|
||||
createdAt:
|
||||
type: string
|
||||
format: date-time
|
||||
example: 2024-01-15T10:30:00Z
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
example: 2024-01-15T10:30:00Z
|
||||
|
||||
Address:
|
||||
type: object
|
||||
required:
|
||||
- street
|
||||
- city
|
||||
- postalCode
|
||||
- country
|
||||
properties:
|
||||
street:
|
||||
type: string
|
||||
example: Hauptstraße 123
|
||||
city:
|
||||
type: string
|
||||
example: Wien
|
||||
postalCode:
|
||||
type: string
|
||||
example: 1010
|
||||
state:
|
||||
type: string
|
||||
example: Wien
|
||||
country:
|
||||
type: string
|
||||
example: Austria
|
||||
|
||||
EmergencyContact:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- relationship
|
||||
- phone
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
example: Johann Müller
|
||||
relationship:
|
||||
type: string
|
||||
example: Ehepartner
|
||||
phone:
|
||||
type: string
|
||||
example: +43 123 456788
|
||||
email:
|
||||
type: string
|
||||
format: email
|
||||
example: johann.mueller@example.com
|
||||
|
||||
User:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
@@ -273,6 +273,23 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Members Context</h3>
|
||||
<p>Member registration, profile management, and membership administration</p>
|
||||
<p><strong>Base Path:</strong> /api/members</p>
|
||||
<div class="endpoints">
|
||||
<h4>Key Endpoints:</h4>
|
||||
<ul>
|
||||
<li><span class="method get">GET</span> /api/members - Get all members with pagination</li>
|
||||
<li><span class="method get">GET</span> /api/members/search - Search members by criteria</li>
|
||||
<li><span class="method get">GET</span> /api/members/{id} - Get member by ID</li>
|
||||
<li><span class="method post">POST</span> /api/members - Create new member</li>
|
||||
<li><span class="method put">PUT</span> /api/members/{id} - Update member information</li>
|
||||
<li><span class="method delete">DELETE</span> /api/members/{id} - Delete member (soft delete)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>Master Data Context</h3>
|
||||
<p>Reference data management (countries, states, age classes, venues)</p>
|
||||
@@ -333,18 +350,48 @@
|
||||
<div class="resource-card">
|
||||
<h3>Swagger UI</h3>
|
||||
<p>Interactive documentation for exploring and testing the API endpoints.</p>
|
||||
<a href="/swagger" class="btn" target="_blank">Open Swagger UI</a>
|
||||
<a href="/swagger" class="btn" target="_blank" aria-label="Open Swagger UI in new tab">Open Swagger UI</a>
|
||||
</div>
|
||||
<div class="resource-card">
|
||||
<h3>OpenAPI Specification</h3>
|
||||
<p>Raw OpenAPI 3.0.3 specification in YAML format for code generation or import into other tools.</p>
|
||||
<a href="/openapi" class="btn" target="_blank">View OpenAPI Spec</a>
|
||||
<a href="/openapi" class="btn" target="_blank" aria-label="View OpenAPI specification in new tab">View OpenAPI Spec</a>
|
||||
</div>
|
||||
<div class="resource-card">
|
||||
<h3>Postman Collection</h3>
|
||||
<p>Comprehensive API collection covering all endpoints with pre-configured request examples.</p>
|
||||
<a href="/docs/postman/Meldestelle_API_Collection.json" class="btn" target="_blank">Download Collection</a>
|
||||
<a href="/docs/postman/Meldestelle_API_Collection.json" class="btn" target="_blank" aria-label="Download Postman collection">Download Collection</a>
|
||||
</div>
|
||||
<div class="resource-card">
|
||||
<h3>Health Monitoring</h3>
|
||||
<p>Real-time health status and monitoring information for all downstream services.</p>
|
||||
<a href="/actuator/health" class="btn" target="_blank" aria-label="View health monitoring in new tab">View Health Status</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="monitoring" class="section">
|
||||
<h2>System Monitoring & Health</h2>
|
||||
<div class="card">
|
||||
<h3>Health Check Endpoints</h3>
|
||||
<p>The API Gateway provides comprehensive health monitoring for all downstream services:</p>
|
||||
<div class="endpoints">
|
||||
<h4>Monitoring Endpoints:</h4>
|
||||
<ul>
|
||||
<li><span class="method get">GET</span> /actuator/health - Comprehensive health status of all services</li>
|
||||
<li><span class="method get">GET</span> /actuator/metrics - System metrics and performance data</li>
|
||||
<li><span class="method get">GET</span> /actuator/info - Application information and build details</li>
|
||||
<li><span class="method get">GET</span> /actuator/prometheus - Prometheus-compatible metrics export</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p><strong>Health Indicator Features:</strong></p>
|
||||
<ul>
|
||||
<li>Monitors critical services: Members, Horses, Events, Masterdata, Auth</li>
|
||||
<li>Optional service monitoring: Ping service</li>
|
||||
<li>Circuit breaker status integration</li>
|
||||
<li>Service discovery status from Consul</li>
|
||||
<li>Detailed error reporting and status codes</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user