refactoring(Gateway Health Indicator implementieren)
TODO-Roadmap.md 1.2 Health Check Verbesserungen
This commit is contained in:
+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