diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml new file mode 100644 index 00000000..a74639a8 --- /dev/null +++ b/.github/workflows/api-docs.yml @@ -0,0 +1,124 @@ +name: API Documentation Generator + +on: + push: + branches: [ main, master ] + paths: + - 'api-gateway/src/jvmMain/resources/openapi/**' + - 'api-gateway/src/jvmMain/kotlin/at/mocode/gateway/routing/**' + - 'api-gateway/src/jvmMain/kotlin/at/mocode/gateway/config/OpenApiConfig.kt' + - 'api-gateway/build.gradle.kts' + - '.github/workflows/api-docs.yml' + pull_request: + branches: [ main, master ] + paths: + - 'api-gateway/src/jvmMain/resources/openapi/**' + - 'api-gateway/src/jvmMain/kotlin/at/mocode/gateway/routing/**' + - 'api-gateway/src/jvmMain/kotlin/at/mocode/gateway/config/OpenApiConfig.kt' + - 'api-gateway/build.gradle.kts' + - '.github/workflows/api-docs.yml' + workflow_dispatch: # Allow manual triggering + schedule: + - cron: '0 0 * * 0' # Run weekly on Sunday at midnight + +jobs: + validate-openapi: + name: Validate OpenAPI Specification + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Validate OpenAPI + uses: char0n/swagger-editor-validate@v1 + with: + definition-file: api-gateway/src/jvmMain/resources/openapi/documentation.yaml + + generate-api-docs: + name: Generate API Documentation + runs-on: ubuntu-latest + needs: validate-openapi + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + cache: gradle + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Generate API Documentation + id: generate-docs + run: ./gradlew :api-gateway:generateApiDocs + + - name: Check for changes + id: git-check + run: | + if git diff --exit-code api-gateway/src/jvmMain/resources/static/docs/; then + echo "changed=false" >> $GITHUB_OUTPUT + else + echo "changed=true" >> $GITHUB_OUTPUT + fi + + - name: Commit and push if changed + if: steps.git-check.outputs.changed == 'true' + run: | + git config --local user.email "action@github.com" + git config --local user.name "GitHub Action" + git add api-gateway/src/jvmMain/resources/static/docs/ + git commit -m "Update API documentation [skip ci]" + git push + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload documentation artifact + uses: actions/upload-artifact@v4 + with: + name: api-documentation + path: api-gateway/src/jvmMain/resources/static/docs/ + retention-days: 7 + + - name: Notify on success + if: steps.git-check.outputs.changed == 'true' + run: | + echo "API documentation has been updated successfully." + # Uncomment and configure when notification service is available + # curl -X POST -H 'Content-type: application/json' --data '{"text":"API documentation has been updated successfully."}' ${{ secrets.SLACK_WEBHOOK_URL }} + + deploy-to-github-pages: + name: Deploy to GitHub Pages + runs-on: ubuntu-latest + needs: generate-api-docs + # Only deploy on main/master branch, not on PRs + if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master') + + steps: + - name: Download documentation artifact + uses: actions/download-artifact@v4 + with: + name: api-documentation + path: ./docs + + - name: Setup GitHub Pages + uses: actions/configure-pages@v4 + + - name: Upload GitHub Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./docs + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 + + - name: Output deployment URL + run: | + echo "Documentation deployed to ${{ steps.deployment.outputs.page_url }}" + # Uncomment and configure when notification service is available + # curl -X POST -H 'Content-type: application/json' --data '{"text":"API documentation deployed to ${{ steps.deployment.outputs.page_url }}"}' ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/README.md b/README.md index 132281af..24e8dc66 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,43 @@ master-data See the `docs/` directory for detailed architecture documentation and diagrams. +### API Documentation + +The project includes comprehensive API documentation for all endpoints: + +- **Central API Documentation**: Access the central API documentation page at `/docs` (or `/api` which redirects to `/docs`) +- **Swagger UI**: Access the interactive API documentation at `/swagger` when the application is running +- **OpenAPI Specification**: The OpenAPI specification is available at `/openapi` +- **JSON API Overview**: A JSON representation of the API structure is available at `/api/json` +- **Developer Guidelines**: Guidelines for documenting APIs are available in [docs/API_DOCUMENTATION_GUIDELINES.md](docs/API_DOCUMENTATION_GUIDELINES.md) + +The API documentation covers all bounded contexts: +- Authentication API +- Master Data API +- Member Management API +- Horse Registry API +- Event Management API + +### How to Use the API Documentation + +1. Start the application with `./gradlew :api-gateway:run` +2. For a comprehensive documentation portal, navigate to `http://localhost:8080/docs` +3. For detailed interactive documentation, navigate to `http://localhost:8080/swagger` +4. For the raw OpenAPI specification, navigate to `http://localhost:8080/openapi` +5. Explore the available endpoints, request/response models, and authentication requirements +6. Test API calls directly from the Swagger UI interface + +The central documentation page provides: +- Overview of the API architecture +- Details about all API contexts and their endpoints +- Links to additional documentation resources +- Authentication instructions +- Response format examples + +### For Developers + +When adding or modifying API endpoints, please follow the [API Documentation Guidelines](docs/API_DOCUMENTATION_GUIDELINES.md). These guidelines ensure consistency across all API documentation and make it easier for developers, testers, and API consumers to understand and use our APIs. + ## Last Updated 2025-07-21 diff --git a/api-gateway/build.gradle.kts b/api-gateway/build.gradle.kts index a232fb53..579c43e9 100644 --- a/api-gateway/build.gradle.kts +++ b/api-gateway/build.gradle.kts @@ -1,6 +1,101 @@ plugins { alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.kotlin.serialization) + id("org.openapi.generator") version "7.3.0" // Updated to latest version +} + +// Get project version for documentation versioning +val projectVersion = project.version.toString() + +// Configure OpenAPI Generator +openApiGenerate { + generatorName.set("html2") + inputSpec.set("$projectDir/src/jvmMain/resources/openapi/documentation.yaml") + outputDir.set("$projectDir/build/generated-docs") + + // Configure HTML2 generator options + configOptions.set(mapOf( + "infoUrl" to "https://meldestelle.at", + "infoEmail" to "support@meldestelle.at", + "title" to "Meldestelle API Documentation v$projectVersion" + )) + + // Validate OpenAPI specification before generation + validateSpec.set(true) +} + +// Task to validate OpenAPI specification +tasks.register("validateOpenApi") { + group = "documentation" + description = "Validates the OpenAPI specification" + + doLast { + // Use the OpenAPI Generator's validate task + tasks.named("openApiValidate").get().actions.forEach { action -> + action.execute(tasks.named("openApiValidate").get()) + } + println("OpenAPI specification validated successfully") + } +} + +// Task to generate API documentation +tasks.register("generateApiDocs") { + group = "documentation" + description = "Generates API documentation from OpenAPI specification" + + doFirst { + // Validate the OpenAPI specification before generating documentation + println("Validating OpenAPI specification...") + tasks.named("validateOpenApi").get().actions.forEach { action -> + action.execute(tasks.named("validateOpenApi").get()) + } + } + + doLast { + try { + // Ensure the output directory exists + mkdir("$projectDir/build/docs") + + // Create version directory for documentation versioning + val docsVersionDir = file("$projectDir/src/jvmMain/resources/static/docs/v$projectVersion") + mkdir(docsVersionDir) + + // Copy all generated documentation files to the static docs directory + copy { + from("$projectDir/build/generated-docs") + into("$projectDir/src/jvmMain/resources/static/docs") + include("**/*") + } + + // Also copy to the versioned directory + copy { + from("$projectDir/build/generated-docs") + into(docsVersionDir) + include("**/*") + } + + // Create a version.json file with version information + val timestamp = System.currentTimeMillis() + file("$projectDir/src/jvmMain/resources/static/docs/version.json").writeText(""" + { + "version": "$projectVersion", + "generatedAt": "$timestamp", + "latestVersionUrl": "/docs/v$projectVersion" + } + """.trimIndent()) + + println("API documentation generated successfully at:") + println("- Latest: $projectDir/src/jvmMain/resources/static/docs/") + println("- Versioned: $projectDir/src/jvmMain/resources/static/docs/v$projectVersion/") + } catch (e: Exception) { + println("Error generating API documentation: ${e.message}") + e.printStackTrace() + throw e + } + } + + // This task depends on the openApiGenerate task + dependsOn("openApiGenerate") } kotlin { diff --git a/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/config/OpenApiConfig.kt b/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/config/OpenApiConfig.kt index cd4f7fbb..a258f999 100644 --- a/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/config/OpenApiConfig.kt +++ b/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/config/OpenApiConfig.kt @@ -10,9 +10,12 @@ import io.ktor.server.routing.* * * This module configures the OpenAPI specification generation and Swagger UI * for the API Gateway, providing comprehensive API documentation. + * + * The OpenAPI specification is loaded from a static YAML file located at: + * resources/openapi/documentation.yaml */ fun Application.configureOpenApi() { - // Configure OpenAPI using a static file + // Configure OpenAPI endpoint using the static YAML file routing { // Serve the OpenAPI specification from a file openAPI(path = "openapi", swaggerFile = "openapi/documentation.yaml") { diff --git a/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/module.kt b/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/module.kt index b81df9f0..e30c66f8 100644 --- a/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/module.kt +++ b/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/module.kt @@ -1,9 +1,13 @@ package at.mocode.gateway +import at.mocode.gateway.config.configureOpenApi +import at.mocode.gateway.config.configureSwagger +import at.mocode.gateway.routing.docRoutes import at.mocode.shared.config.AppConfig import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* import io.ktor.server.application.* +import io.ktor.server.http.content.* import io.ktor.server.plugins.calllogging.* import io.ktor.server.plugins.contentnegotiation.* import io.ktor.server.plugins.cors.routing.* @@ -41,6 +45,10 @@ fun Application.module() { install(CallLogging) } + // OpenAPI und Swagger UI konfigurieren + configureOpenApi() + configureSwagger() + routing { // Hauptrouten get("/") { @@ -49,5 +57,14 @@ fun Application.module() { ContentType.Text.Plain ) } + + // Static resources for documentation + static("/docs") { + resources("static/docs") + defaultResource("static/docs/index.html") + } + + // API Documentation routes + docRoutes() } } diff --git a/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/routing/DocRoutes.kt b/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/routing/DocRoutes.kt new file mode 100644 index 00000000..e7bb677e --- /dev/null +++ b/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/routing/DocRoutes.kt @@ -0,0 +1,76 @@ +package at.mocode.gateway.routing + +import at.mocode.dto.base.ApiResponse +import io.ktor.http.* +import io.ktor.server.application.* +import io.ktor.server.response.* +import io.ktor.server.routing.* +import kotlinx.serialization.Serializable +import java.io.File + +/** + * Sets up routes for API documentation + */ +fun Routing.docRoutes() { + // Central API documentation endpoint - HTML version + get("/api") { + call.respondRedirect("/docs", permanent = false) + } + + // JSON API documentation endpoint for backward compatibility + get("/api/json") { + val apiDocumentation = ApiDocumentationData( + title = "Meldestelle Self-Contained Systems API", + description = "Unified API Gateway for all bounded contexts", + contexts = listOf( + ApiContext( + name = "Authentication Context", + path = "/auth", + description = "User authentication, registration, and profile management" + ), + ApiContext( + name = "Master Data Context", + path = "/api/masterdata", + description = "Reference data management (countries, states, age classes, venues)" + ), + ApiContext( + name = "Horse Registry Context", + path = "/api/horses", + description = "Horse registration, ownership, and pedigree management" + ), + ApiContext( + name = "Event Management Context", + path = "/api/events", + description = "Event creation, management, and participant registration" + ) + ) + ) + + call.respond( + ApiResponse.success( + data = apiDocumentation, + message = "API documentation retrieved successfully" + ) + ) + } +} + +/** + * Data class for API documentation response + */ +@Serializable +data class ApiDocumentationData( + val title: String, + val description: String, + val contexts: List +) + +/** + * Data class for API context information + */ +@Serializable +data class ApiContext( + val name: String, + val path: String, + val description: String +) diff --git a/api-gateway/src/jvmMain/resources/openapi/documentation.yaml b/api-gateway/src/jvmMain/resources/openapi/documentation.yaml new file mode 100644 index 00000000..93c7ac40 --- /dev/null +++ b/api-gateway/src/jvmMain/resources/openapi/documentation.yaml @@ -0,0 +1,1650 @@ +openapi: 3.0.3 +info: + title: Meldestelle API + description: | + Self-Contained Systems API Gateway for Austrian Equestrian Federation. + This API provides access to various bounded contexts including authentication, + master data management, horse registry, and event management. + version: 1.0.0 + contact: + name: Meldestelle Support + email: support@meldestelle.at + url: https://meldestelle.at/support + license: + name: Internal Use Only + +servers: + - url: https://api.meldestelle.at + description: Production Server + - url: https://staging-api.meldestelle.at + description: Staging Server + - url: http://localhost:8080 + description: Local Development Server + +tags: + - name: Authentication + description: User authentication, registration, and profile management + - name: Master Data + description: Reference data management (countries, states, age classes, venues) + - name: Horse Registry + description: Horse registration, ownership, and pedigree management + - name: Event Management + description: Event creation, management, and participant registration + +paths: + /: + get: + summary: API Gateway Information + description: Returns basic information about the API Gateway + operationId: getApiGatewayInfo + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiGatewayInfoResponse' + + /health: + get: + summary: Health Check + description: Returns the health status of all bounded contexts + operationId: getHealthStatus + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HealthStatusResponse' + + /api: + get: + summary: API Documentation + description: Returns information about available API endpoints + operationId: getApiDocumentation + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiDocumentationResponse' + + # Authentication Context + /auth/login: + post: + tags: + - Authentication + summary: User Login + description: Authenticates a user and returns a JWT token + operationId: login + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/LoginRequest' + responses: + '200': + description: Successful login + content: + application/json: + schema: + $ref: '#/components/schemas/LoginResponse' + '401': + description: Invalid credentials + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /auth/register: + post: + tags: + - Authentication + summary: User Registration + description: Registers a new user + operationId: register + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RegisterRequest' + responses: + '201': + description: User successfully registered + content: + application/json: + schema: + $ref: '#/components/schemas/RegisterResponse' + '400': + description: Invalid registration data + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /auth/profile: + get: + tags: + - Authentication + summary: Get User Profile + description: Returns the profile of the authenticated user + operationId: getUserProfile + security: + - bearerAuth: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/UserProfileResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + # Master Data Context + /api/masterdata/countries: + get: + tags: + - Master Data + summary: Get All Countries + description: Returns a list of all countries + operationId: getAllCountries + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/CountriesResponse' + + post: + tags: + - Master Data + summary: Create Country + description: Creates a new country + operationId: createCountry + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateCountryRequest' + responses: + '201': + description: Country successfully created + content: + application/json: + schema: + $ref: '#/components/schemas/CountryResponse' + '400': + description: Invalid country data + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/masterdata/countries/{id}: + get: + tags: + - Master Data + summary: Get Country by ID + description: Returns a country by its ID + operationId: getCountryById + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/CountryResponse' + '404': + description: Country not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + # Horse Registry Context + /api/horses: + get: + tags: + - Horse Registry + summary: Get All Horses + description: Returns a list of all horses + operationId: getAllHorses + security: + - bearerAuth: [] + parameters: + - name: activeOnly + in: query + required: false + schema: + type: boolean + default: true + description: Filter to only return active horses + - name: limit + in: query + required: false + schema: + type: integer + default: 100 + description: Maximum number of horses to return + - name: ownerId + in: query + required: false + schema: + type: string + format: uuid + description: Filter horses by owner ID + - name: geschlecht + in: query + required: false + schema: + type: string + enum: [STALLION, MARE, GELDING] + description: Filter horses by gender + - name: rasse + in: query + required: false + schema: + type: string + description: Filter horses by breed + - name: search + in: query + required: false + schema: + type: string + description: Search term to filter horses by name + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HorsesResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/horses/search/lebensnummer/{nummer}: + get: + tags: + - Horse Registry + summary: Find Horse by Life Number + description: Returns a horse by its life number + operationId: getHorseByLifeNumber + security: + - bearerAuth: [] + parameters: + - name: nummer + in: path + required: true + schema: + type: string + description: Life number of the horse + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HorseResponse' + '404': + description: Horse not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/horses/search/chip/{nummer}: + get: + tags: + - Horse Registry + summary: Find Horse by Chip Number + description: Returns a horse by its chip number + operationId: getHorseByChipNumber + security: + - bearerAuth: [] + parameters: + - name: nummer + in: path + required: true + schema: + type: string + description: Chip number of the horse + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HorseResponse' + '404': + description: Horse not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/horses/oeps-registered: + get: + tags: + - Horse Registry + summary: Get OEPS Registered Horses + description: Returns a list of horses registered with the Austrian Equestrian Federation (OEPS) + operationId: getOepsRegisteredHorses + security: + - bearerAuth: [] + parameters: + - name: activeOnly + in: query + required: false + schema: + type: boolean + default: true + description: Filter to only return active horses + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HorsesResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/horses/fei-registered: + get: + tags: + - Horse Registry + summary: Get FEI Registered Horses + description: Returns a list of horses registered with the International Federation for Equestrian Sports (FEI) + operationId: getFeiRegisteredHorses + security: + - bearerAuth: [] + parameters: + - name: activeOnly + in: query + required: false + schema: + type: boolean + default: true + description: Filter to only return active horses + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HorsesResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/horses/stats: + get: + tags: + - Horse Registry + summary: Get Horse Statistics + description: Returns statistics about horses in the registry + operationId: getHorseStats + security: + - bearerAuth: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HorseStatsResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + post: + tags: + - Horse Registry + summary: Register Horse + description: Registers a new horse + operationId: registerHorse + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RegisterHorseRequest' + responses: + '201': + description: Horse successfully registered + content: + application/json: + schema: + $ref: '#/components/schemas/HorseResponse' + '400': + description: Invalid horse data + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/horses/{id}: + get: + tags: + - Horse Registry + summary: Get Horse by ID + description: Returns a horse by its ID + operationId: getHorseById + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HorseResponse' + '404': + description: Horse not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + put: + tags: + - Horse Registry + summary: Update Horse + description: Updates an existing horse + operationId: updateHorse + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UpdateHorseRequest' + responses: + '200': + description: Horse successfully updated + content: + application/json: + schema: + $ref: '#/components/schemas/HorseResponse' + '400': + description: Invalid horse data + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Horse not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + delete: + tags: + - Horse Registry + summary: Delete Horse + description: Deletes a horse + operationId: deleteHorse + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: force + in: query + required: false + schema: + type: boolean + default: false + description: Force delete even if the horse has dependencies + responses: + '200': + description: Horse successfully deleted + content: + application/json: + schema: + $ref: '#/components/schemas/BaseResponse' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Horse not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/horses/{id}/soft-delete: + post: + tags: + - Horse Registry + summary: Soft Delete Horse + description: Marks a horse as inactive instead of permanently deleting it + operationId: softDeleteHorse + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Horse successfully marked as inactive + content: + application/json: + schema: + $ref: '#/components/schemas/BaseResponse' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Horse not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/horses/batch-delete: + post: + tags: + - Horse Registry + summary: Batch Delete Horses + description: Deletes multiple horses in a single operation + operationId: batchDeleteHorses + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/BatchDeleteRequest' + responses: + '200': + description: Horses successfully deleted + content: + application/json: + schema: + $ref: '#/components/schemas/BatchDeleteResponse' + '206': + description: Partial content - some horses could not be deleted + content: + application/json: + schema: + $ref: '#/components/schemas/BatchDeleteResponse' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + # Event Management Context + /api/events: + get: + tags: + - Event Management + summary: Get All Events + description: Returns a list of all events + operationId: getAllEvents + parameters: + - name: activeOnly + in: query + required: false + schema: + type: boolean + default: true + description: Filter to only return active events + - name: limit + in: query + required: false + schema: + type: integer + default: 100 + description: Maximum number of events to return + - name: offset + in: query + required: false + schema: + type: integer + default: 0 + description: Number of events to skip + - name: search + in: query + required: false + schema: + type: string + description: Search term to filter events by name + - name: organizerId + in: query + required: false + schema: + type: string + format: uuid + description: Filter events by organizer ID + - name: publicOnly + in: query + required: false + schema: + type: boolean + default: false + description: Filter to only return public events + - name: startDate + in: query + required: false + schema: + type: string + format: date + description: Filter events starting on or after this date + - name: endDate + in: query + required: false + schema: + type: string + format: date + description: Filter events ending on or before this date + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/EventsResponse' + + /api/events/stats: + get: + tags: + - Event Management + summary: Get Event Statistics + description: Returns statistics about events + operationId: getEventStats + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/EventStatsResponse' + + post: + tags: + - Event Management + summary: Create Event + description: Creates a new event + operationId: createEvent + security: + - bearerAuth: [] + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateEventRequest' + responses: + '201': + description: Event successfully created + content: + application/json: + schema: + $ref: '#/components/schemas/EventResponse' + '400': + description: Invalid event data + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + /api/events/{id}: + get: + tags: + - Event Management + summary: Get Event by ID + description: Returns an event by its ID + operationId: getEventById + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/EventResponse' + '404': + description: Event not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + put: + tags: + - Event Management + summary: Update Event + description: Updates an existing event + operationId: updateEvent + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateEventRequest' + responses: + '200': + description: Event successfully updated + content: + application/json: + schema: + $ref: '#/components/schemas/EventResponse' + '400': + description: Invalid event data + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Event not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + + delete: + tags: + - Event Management + summary: Delete Event + description: Deletes an event + operationId: deleteEvent + security: + - bearerAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + format: uuid + - name: force + in: query + required: false + schema: + type: boolean + default: false + description: Force delete even if the event has dependencies + responses: + '200': + description: Event successfully deleted + content: + application/json: + schema: + $ref: '#/components/schemas/BaseResponse' + '401': + description: Unauthorized + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Event not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '409': + description: Cannot delete active event + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + +components: + securitySchemes: + bearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + description: JWT token authentication + + schemas: + BaseResponse: + type: object + required: + - success + - message + properties: + success: + type: boolean + description: Indicates if the operation was successful + message: + type: string + description: A message describing the result of the operation + data: + type: object + description: The response data (if any) + + ErrorResponse: + type: object + required: + - success + - message + - error + properties: + success: + type: boolean + default: false + description: Indicates that the operation failed + message: + type: string + description: A message describing the error + error: + type: string + description: The error code or type + + ApiGatewayInfoResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + properties: + name: + type: string + example: Meldestelle API Gateway + version: + type: string + example: 1.0.0 + description: + type: string + example: Self-Contained Systems API Gateway for Austrian Equestrian Federation + availableContexts: + type: array + items: + type: string + example: [authentication, master-data, horse-registry, event-management] + endpoints: + type: object + additionalProperties: + type: string + example: + authentication: /auth/* + master-data: /api/masterdata/* + horse-registry: /api/horses/* + event-management: /api/events/* + + HealthStatusResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + properties: + status: + type: string + example: UP + contexts: + type: object + additionalProperties: + type: string + example: + authentication: UP + master-data: UP + horse-registry: UP + event-management: UP + + ApiDocumentationResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + properties: + title: + type: string + example: Meldestelle Self-Contained Systems API + description: + type: string + example: Unified API Gateway for all bounded contexts + contexts: + type: array + items: + type: object + properties: + name: + type: string + path: + type: string + description: + type: string + example: + - name: Authentication Context + path: /auth + description: User authentication, registration, and profile management + - name: Master Data Context + path: /api/masterdata + description: Reference data management (countries, states, age classes, venues) + + # Authentication Models + LoginRequest: + type: object + required: + - username + - password + properties: + username: + type: string + example: user@example.com + password: + type: string + format: password + example: Password123 + + LoginResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + properties: + token: + type: string + description: JWT token for authentication + example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... + user: + $ref: '#/components/schemas/User' + + RegisterRequest: + type: object + required: + - username + - email + - password + - firstName + - lastName + properties: + username: + type: string + example: johndoe + email: + type: string + format: email + example: john.doe@example.com + password: + type: string + format: password + example: Password123 + firstName: + type: string + example: John + lastName: + type: string + example: Doe + phone: + type: string + example: +43 123 456789 + + RegisterResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: object + properties: + user: + $ref: '#/components/schemas/User' + + UserProfileResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + $ref: '#/components/schemas/User' + + User: + type: object + properties: + id: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + username: + type: string + example: johndoe + email: + type: string + format: email + example: john.doe@example.com + firstName: + type: string + example: John + lastName: + type: string + example: Doe + phone: + type: string + example: +43 123 456789 + roles: + type: array + items: + type: string + example: [USER, ADMIN] + + # Master Data Models + CountriesResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Country' + + CountryResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + $ref: '#/components/schemas/Country' + + CreateCountryRequest: + type: object + required: + - name + - code + properties: + name: + type: string + example: Austria + code: + type: string + example: AT + flagUrl: + type: string + format: uri + example: https://example.com/flags/at.png + + Country: + type: object + properties: + id: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + name: + type: string + example: Austria + code: + type: string + example: AT + flagUrl: + type: string + format: uri + example: https://example.com/flags/at.png + + # Horse Registry Models + HorsesResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Horse' + + HorseResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + $ref: '#/components/schemas/Horse' + + RegisterHorseRequest: + type: object + required: + - name + - birthDate + - breed + - color + - gender + properties: + name: + type: string + example: Maestoso + birthDate: + type: string + format: date + example: 2015-05-15 + breed: + type: string + example: Lipizzaner + color: + type: string + example: White + gender: + type: string + enum: [STALLION, MARE, GELDING] + example: STALLION + fatherId: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + motherId: + type: string + format: uuid + example: 223e4567-e89b-12d3-a456-426614174000 + ownerId: + type: string + format: uuid + example: 323e4567-e89b-12d3-a456-426614174000 + registrationNumber: + type: string + example: AT-LIP-2015-123 + + UpdateHorseRequest: + type: object + required: + - name + - gender + properties: + name: + type: string + example: Maestoso + gender: + type: string + enum: [STALLION, MARE, GELDING] + example: STALLION + birthDate: + type: string + format: date + example: 2015-05-15 + breed: + type: string + example: Lipizzaner + color: + type: string + example: White + ownerId: + type: string + format: uuid + example: 323e4567-e89b-12d3-a456-426614174000 + responsiblePersonId: + type: string + format: uuid + example: 423e4567-e89b-12d3-a456-426614174000 + breederName: + type: string + example: Austrian Federal Stud Piber + studBookNumber: + type: string + example: LIP-2015-123 + lifeNumber: + type: string + example: AT-LIP-2015-123 + chipNumber: + type: string + example: 040123456789012 + passportNumber: + type: string + example: AT-P-2015-123 + oepsNumber: + type: string + example: AT-OEPS-2015-123 + feiNumber: + type: string + example: AT-FEI-2015-123 + fatherName: + type: string + example: Neapolitano + motherName: + type: string + example: Presciana + motherFatherName: + type: string + example: Conversano + height: + type: integer + example: 165 + isActive: + type: boolean + default: true + notes: + type: string + example: Champion at Vienna Horse Show 2022 + + Horse: + type: object + properties: + id: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + name: + type: string + example: Maestoso + birthDate: + type: string + format: date + example: 2015-05-15 + breed: + type: string + example: Lipizzaner + color: + type: string + example: White + gender: + type: string + enum: [STALLION, MARE, GELDING] + example: STALLION + father: + $ref: '#/components/schemas/HorseReference' + mother: + $ref: '#/components/schemas/HorseReference' + owner: + $ref: '#/components/schemas/UserReference' + registrationNumber: + type: string + example: AT-LIP-2015-123 + registrationDate: + type: string + format: date + example: 2015-06-15 + + HorseReference: + type: object + properties: + id: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + name: + type: string + example: Maestoso + registrationNumber: + type: string + example: AT-LIP-2015-123 + + UserReference: + type: object + properties: + id: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + firstName: + type: string + example: John + lastName: + type: string + example: Doe + + # Event Management Models + EventsResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Event' + + EventResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + $ref: '#/components/schemas/Event' + + CreateEventRequest: + type: object + required: + - name + - startDate + - endDate + - venueId + - eventType + properties: + name: + type: string + example: Vienna International Horse Show + startDate: + type: string + format: date + example: 2025-09-15 + endDate: + type: string + format: date + example: 2025-09-20 + venueId: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + eventType: + type: string + enum: [DRESSAGE, JUMPING, EVENTING, COMBINED] + example: JUMPING + description: + type: string + example: International jumping competition + registrationDeadline: + type: string + format: date + example: 2025-09-01 + maxParticipants: + type: integer + example: 100 + + Event: + type: object + properties: + id: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + name: + type: string + example: Vienna International Horse Show + startDate: + type: string + format: date + example: 2025-09-15 + endDate: + type: string + format: date + example: 2025-09-20 + venue: + $ref: '#/components/schemas/Venue' + eventType: + type: string + enum: [DRESSAGE, JUMPING, EVENTING, COMBINED] + example: JUMPING + description: + type: string + example: International jumping competition + registrationDeadline: + type: string + format: date + example: 2025-09-01 + maxParticipants: + type: integer + example: 100 + currentParticipants: + type: integer + example: 45 + status: + type: string + enum: [DRAFT, PUBLISHED, REGISTRATION_OPEN, REGISTRATION_CLOSED, IN_PROGRESS, COMPLETED, CANCELLED] + example: REGISTRATION_OPEN + createdBy: + $ref: '#/components/schemas/UserReference' + createdAt: + type: string + format: date-time + example: 2025-05-15T10:30:00Z + + EventStats: + type: object + properties: + totalActive: + type: integer + format: int64 + description: Total number of active events + example: 42 + totalPublic: + type: integer + format: int64 + description: Total number of public events + example: 35 + + EventStatsResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + $ref: '#/components/schemas/EventStats' + + HorseStats: + type: object + properties: + totalActive: + type: integer + format: int64 + description: Total number of active horses + example: 250 + oepsRegistered: + type: integer + format: int64 + description: Number of horses registered with OEPS + example: 180 + feiRegistered: + type: integer + format: int64 + description: Number of horses registered with FEI + example: 75 + + HorseStatsResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + $ref: '#/components/schemas/HorseStats' + + BatchDeleteRequest: + type: object + required: + - horseIds + properties: + horseIds: + type: array + items: + type: string + format: uuid + description: List of horse IDs to delete + example: ["123e4567-e89b-12d3-a456-426614174000", "223e4567-e89b-12d3-a456-426614174000"] + forceDelete: + type: boolean + default: false + description: Force delete even if horses have dependencies + + BatchDeleteResult: + type: object + properties: + successful: + type: array + items: + type: string + format: uuid + description: List of successfully deleted horse IDs + failed: + type: object + additionalProperties: + type: string + description: Map of failed horse IDs to error messages + overallSuccess: + type: boolean + description: True if all horses were deleted successfully + + BatchDeleteResponse: + allOf: + - $ref: '#/components/schemas/BaseResponse' + - type: object + properties: + data: + $ref: '#/components/schemas/BatchDeleteResult' + + Venue: + type: object + properties: + id: + type: string + format: uuid + example: 123e4567-e89b-12d3-a456-426614174000 + name: + type: string + example: Vienna Riding Club + address: + type: string + example: Trabrennstraße 5, 1020 Wien + country: + $ref: '#/components/schemas/Country' + facilities: + type: array + items: + type: string + example: [Indoor Arena, Outdoor Arena, Stables] diff --git a/api-gateway/src/jvmMain/resources/static/docs/index.html b/api-gateway/src/jvmMain/resources/static/docs/index.html new file mode 100644 index 00000000..8997ea2d --- /dev/null +++ b/api-gateway/src/jvmMain/resources/static/docs/index.html @@ -0,0 +1,385 @@ + + + + + + Meldestelle API Documentation + + + +
+
+ + +
+
+ +
+
+

Meldestelle Self-Contained Systems API

+

Unified API Gateway for all bounded contexts of the Austrian Equestrian Federation's Meldestelle system.

+
+ Interactive API Documentation + OpenAPI Specification +
+
+
+ +
+
+

Overview

+
+

The Meldestelle API provides a unified interface to various bounded contexts while maintaining the independence of each context. This API Gateway aggregates all bounded context APIs and provides a single entry point for clients.

+

The API follows REST principles and uses JSON for data exchange. All responses are wrapped in a consistent format using the BaseDto wrapper.

+

Authentication is handled using JWT (JSON Web Token) based authentication. Most endpoints require authentication, which can be obtained by registering and logging in through the Authentication Context.

+
+
+ +
+

API Contexts

+ +
+

Authentication Context

+

User authentication, registration, and profile management

+

Base Path: /auth

+
+

Key Endpoints:

+
    +
  • POST /auth/register - User registration
  • +
  • POST /auth/login - User authentication
  • +
  • GET /auth/profile - Get user profile
  • +
  • PUT /auth/profile - Update user profile
  • +
  • POST /auth/change-password - Change password
  • +
+
+
+ +
+

Master Data Context

+

Reference data management (countries, states, age classes, venues)

+

Base Path: /api/masterdata

+
+

Key Endpoints:

+
    +
  • GET /api/masterdata/countries - Get all countries
  • +
  • GET /api/masterdata/countries/active - Get active countries
  • +
  • GET /api/masterdata/countries/{id} - Get country by ID
  • +
  • POST /api/masterdata/countries - Create country
  • +
  • PUT /api/masterdata/countries/{id} - Update country
  • +
  • DELETE /api/masterdata/countries/{id} - Delete country
  • +
+
+
+ +
+

Horse Registry Context

+

Horse registration, ownership, and pedigree management

+

Base Path: /api/horses

+
+

Key Endpoints:

+
    +
  • GET /api/horses - Get all horses
  • +
  • GET /api/horses/active - Get active horses
  • +
  • GET /api/horses/{id} - Get horse by ID
  • +
  • GET /api/horses/search - Search horses by name
  • +
  • POST /api/horses - Create horse
  • +
  • PUT /api/horses/{id} - Update horse
  • +
  • DELETE /api/horses/{id} - Delete horse
  • +
+
+
+ +
+

Event Management Context

+

Event creation, management, and participant registration

+

Base Path: /api/events

+
+

Key Endpoints:

+
    +
  • GET /api/events - Get all events
  • +
  • GET /api/events/stats - Get event statistics
  • +
  • POST /api/events - Create event
  • +
  • GET /api/events/{id} - Get event by ID
  • +
  • PUT /api/events/{id} - Update event
  • +
  • DELETE /api/events/{id} - Delete event
  • +
  • GET /api/events/search - Search events
  • +
+
+
+
+ +
+

Documentation Resources

+
+
+

Swagger UI

+

Interactive documentation for exploring and testing the API endpoints.

+ Open Swagger UI +
+
+

OpenAPI Specification

+

Raw OpenAPI 3.0.3 specification in YAML format for code generation or import into other tools.

+ View OpenAPI Spec +
+
+

Postman Collection

+

Comprehensive API collection covering all endpoints with pre-configured request examples.

+ Download Collection +
+
+
+ +
+

Getting Started

+
+

Authentication

+

The API uses JWT (JSON Web Token) based authentication:

+
    +
  1. Register a new user via POST /auth/register
  2. +
  3. Login with credentials via POST /auth/login
  4. +
  5. Extract the JWT token from the login response
  6. +
  7. Include the token in the Authorization header: Bearer <token>
  8. +
+
+ +
+

Response Format

+

All API responses follow a consistent format using the BaseDto wrapper:

+
{
+  "success": true,
+  "data": {
+    "example": "Actual response data goes here"
+  },
+  "message": "Operation completed successfully",
+  "timestamp": "2024-01-15T10:30:00Z"
+}
+
+
+
+ + + + diff --git a/docs/API_DOCUMENTATION.md b/docs/API_DOCUMENTATION.md index 81b150be..9d16e116 100644 --- a/docs/API_DOCUMENTATION.md +++ b/docs/API_DOCUMENTATION.md @@ -7,10 +7,10 @@ This document provides comprehensive documentation for the Meldestelle API Gatew ## Features Implemented ### ✅ OpenAPI/Swagger Integration -- **OpenAPI 3.0 specification** generation +- **OpenAPI 3.0 specification** using static YAML file - **Swagger UI** interactive documentation -- **Automatic API documentation** from code annotations -- **Multiple server environments** (development, production) +- **Comprehensive API documentation** for all bounded contexts +- **Multiple server environments** (development, staging, production) ### ✅ Postman Collections - **Comprehensive API collection** covering all endpoints @@ -31,8 +31,11 @@ The API Gateway aggregates the following bounded contexts: ### 1. System Information - `GET /` - API Gateway information - `GET /health` - Health check for all contexts -- `GET /api` - API documentation overview +- `GET /docs` - Central API documentation page +- `GET /api` - Redirects to central API documentation page +- `GET /api/json` - API documentation overview in JSON format - `GET /swagger` - Interactive Swagger UI +- `GET /openapi` - Raw OpenAPI specification ### 2. Authentication Context (`/auth/*`) - `POST /auth/register` - User registration @@ -62,6 +65,16 @@ The API Gateway aggregates the following bounded contexts: - `DELETE /api/horses/batch` - Batch delete horses - `GET /api/horses/stats` - Get horse statistics +### 5. Event Management Context (`/api/events/*`) +- `GET /api/events` - Get all events +- `GET /api/events/stats` - Get event statistics +- `POST /api/events` - Create event +- `GET /api/events/{id}` - Get event by ID +- `PUT /api/events/{id}` - Update event +- `DELETE /api/events/{id}` - Delete event +- `GET /api/events/search` - Search events +- `GET /api/events/organizer/{organizerId}` - Get events by organizer + ## Getting Started ### 1. Start the API Gateway @@ -199,23 +212,38 @@ The test suite covers: 4. **Add integration tests** for the new functionality 5. **Update this documentation** -### OpenAPI Annotations +### OpenAPI Documentation -Use OpenAPI annotations to enhance documentation: +The API documentation is maintained in a static OpenAPI YAML file: -```kotlin -@OpenAPITag(name = "Horses", description = "Horse registry operations") -fun Route.horseRoutes() { - route("/api/horses") { - @OpenAPIResponse("200", [OpenAPIContent(HorseDto::class)]) - @OpenAPIResponse("404", [OpenAPIContent(ErrorDto::class)]) - get { - // Implementation - } - } -} +```yaml +# Location: api-gateway/src/jvmMain/resources/openapi/documentation.yaml + +paths: + /api/horses: + get: + tags: + - Horse Registry + summary: Get All Horses + description: Returns a list of all horses + operationId: getAllHorses + security: + - bearerAuth: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HorsesResponse' ``` +To update the API documentation: + +1. Edit the `documentation.yaml` file in `api-gateway/src/jvmMain/resources/openapi/` +2. Follow the OpenAPI 3.0.3 specification format +3. Restart the application to see changes in Swagger UI + ## Configuration ### Environment Variables diff --git a/docs/API_DOCUMENTATION_EXAMPLE.md b/docs/API_DOCUMENTATION_EXAMPLE.md new file mode 100644 index 00000000..cee0d211 --- /dev/null +++ b/docs/API_DOCUMENTATION_EXAMPLE.md @@ -0,0 +1,221 @@ +# API Documentation Example + +This document demonstrates how to apply the API documentation guidelines to a new endpoint. It serves as a practical example for developers to follow when documenting their own API endpoints. + +## Example Scenario + +Let's say we're adding a new endpoint to the Horse Registry context that allows users to search for horses by multiple criteria. + +## Step 1: Implement the API Endpoint + +First, we would implement the endpoint in the appropriate route file: + +```kotlin +// In HorseRoutes.kt +route("/api/horses") { + // Other endpoints... + + // Advanced search endpoint + get("/advanced-search") { + // Parameter validation + val name = call.request.queryParameters["name"] + val breed = call.request.queryParameters["breed"] + val minAge = call.request.queryParameters["minAge"]?.toIntOrNull() + val maxAge = call.request.queryParameters["maxAge"]?.toIntOrNull() + val gender = call.request.queryParameters["gender"] + val ownerName = call.request.queryParameters["ownerName"] + + // Call service to perform search + val horses = horseService.advancedSearch( + name = name, + breed = breed, + minAge = minAge, + maxAge = maxAge, + gender = gender, + ownerName = ownerName + ) + + // Return response + call.respond( + ApiResponse.success( + data = horses, + message = "Horses retrieved successfully" + ) + ) + } +} +``` + +## Step 2: Document the Endpoint in OpenAPI Specification + +Following our API documentation guidelines, we would add the following to the OpenAPI specification file (`documentation.yaml`): + +```yaml +/api/horses/advanced-search: + get: + tags: + - Horse Registry + summary: Advanced Horse Search + description: | + Searches for horses using multiple optional criteria. + Returns a list of horses matching the specified criteria. + If no criteria are provided, returns all horses (subject to pagination). + operationId: advancedSearchHorses + parameters: + - name: name + in: query + description: Full or partial horse name to search for + required: false + schema: + type: string + example: "Maestoso" + - name: breed + in: query + description: Horse breed + required: false + schema: + type: string + example: "Lipizzaner" + - name: minAge + in: query + description: Minimum age in years + required: false + schema: + type: integer + format: int32 + minimum: 0 + example: 3 + - name: maxAge + in: query + description: Maximum age in years + required: false + schema: + type: integer + format: int32 + minimum: 0 + example: 15 + - name: gender + in: query + description: Horse gender + required: false + schema: + type: string + enum: [STALLION, MARE, GELDING] + example: "MARE" + - name: ownerName + in: query + description: Full or partial name of the horse's owner + required: false + schema: + type: string + example: "Schmidt" + security: + - bearerAuth: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + data: + type: array + items: + $ref: '#/components/schemas/HorseResponse' + message: + type: string + example: "Horses retrieved successfully" + timestamp: + type: string + format: date-time + example: "2024-07-21T13:35:00Z" + example: + success: true + data: [ + { + "id": "550e8400-e29b-41d4-a716-446655440000", + "name": "Maestoso Mara", + "birthYear": 2015, + "breed": "Lipizzaner", + "color": "Grey", + "gender": "MARE", + "feiRegistered": true, + "ownerId": "550e8400-e29b-41d4-a716-446655440001", + "active": true + }, + { + "id": "550e8400-e29b-41d4-a716-446655440002", + "name": "Maestoso Belvedere", + "birthYear": 2018, + "breed": "Lipizzaner", + "color": "Grey", + "gender": "STALLION", + "feiRegistered": false, + "ownerId": "550e8400-e29b-41d4-a716-446655440001", + "active": true + } + ] + message: "Horses retrieved successfully" + timestamp: "2024-07-21T13:35:00Z" + '400': + description: Invalid parameters + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '401': + description: Unauthorized - Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - Insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' +``` + +## Step 3: Generate and Validate Documentation + +After updating the OpenAPI specification, we would generate and validate the documentation: + +```bash +# Generate API documentation +./gradlew :api-gateway:generateApiDocs + +# Validate OpenAPI specification +./gradlew :api-gateway:validateOpenApi +``` + +## Step 4: Test the Documentation + +Finally, we would test the documentation by: + +1. Starting the API Gateway: + ```bash + ./gradlew :api-gateway:run + ``` + +2. Accessing Swagger UI at `http://localhost:8080/swagger` + +3. Testing the new endpoint through the Swagger UI interface + +4. Verifying that the documentation accurately represents the API behavior + +## Summary + +This example demonstrates how to apply the API documentation guidelines to a new endpoint. By following these steps, we ensure that: + +1. The endpoint is well-documented with clear descriptions +2. All parameters are properly documented with types and examples +3. All possible responses are documented with status codes and examples +4. The documentation is validated and tested +5. The documentation is consistent with the rest of the API + +This approach makes it easier for other developers, testers, and API consumers to understand and use the API. diff --git a/docs/API_DOCUMENTATION_GUIDELINES.md b/docs/API_DOCUMENTATION_GUIDELINES.md new file mode 100644 index 00000000..b9141f76 --- /dev/null +++ b/docs/API_DOCUMENTATION_GUIDELINES.md @@ -0,0 +1,304 @@ +# API Documentation Guidelines + +## Overview + +This document provides guidelines for documenting APIs in the Meldestelle project. Following these guidelines ensures consistency across all API documentation and makes it easier for developers, testers, and API consumers to understand and use our APIs. + +## Table of Contents + +1. [Documentation Approach](#documentation-approach) +2. [OpenAPI Specification](#openapi-specification) +3. [Endpoint Documentation Standards](#endpoint-documentation-standards) +4. [Schema Documentation Standards](#schema-documentation-standards) +5. [Examples](#examples) +6. [Documentation Workflow](#documentation-workflow) +7. [Testing Documentation](#testing-documentation) +8. [Tools and Resources](#tools-and-resources) + +## Documentation Approach + +The Meldestelle project uses a **static OpenAPI YAML file** for API documentation. This means: + +- API documentation is maintained in a dedicated YAML file, not generated from code annotations +- Developers must manually update the documentation when adding or modifying endpoints +- The documentation is served via Swagger UI and as static HTML + +### Key Files + +- **OpenAPI Specification**: `/api-gateway/src/jvmMain/resources/openapi/documentation.yaml` +- **OpenAPI Configuration**: `/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/config/OpenApiConfig.kt` +- **Documentation Routes**: `/api-gateway/src/jvmMain/kotlin/at/mocode/gateway/routing/DocRoutes.kt` +- **Static HTML Documentation**: `/api-gateway/src/jvmMain/resources/static/docs/index.html` + +## OpenAPI Specification + +We use OpenAPI 3.0.3 for our API documentation. The specification is maintained in a YAML file at: +`/api-gateway/src/jvmMain/resources/openapi/documentation.yaml` + +### Structure + +The OpenAPI specification file is structured as follows: + +```yaml +openapi: 3.0.3 +info: + title: Meldestelle API + description: | + Self-Contained Systems API Gateway for Austrian Equestrian Federation. + version: 1.0.0 + # Additional info fields... + +servers: + # Server configurations... + +tags: + # API tags for grouping endpoints... + +paths: + # API endpoints... + +components: + schemas: + # Data models... + securitySchemes: + # Security definitions... +``` + +## Endpoint Documentation Standards + +When documenting a new API endpoint, include the following information: + +### Required Elements + +1. **Path and HTTP Method**: Define the endpoint path and HTTP method (GET, POST, PUT, DELETE) +2. **Tags**: Assign at least one tag to categorize the endpoint (e.g., Authentication, Master Data) +3. **Summary**: A brief one-line description of the endpoint +4. **Description**: A more detailed explanation of what the endpoint does +5. **Operation ID**: A unique identifier for the operation (camelCase) +6. **Responses**: Document all possible response status codes and their content +7. **Security**: Specify authentication requirements if applicable + +### Optional Elements (Recommended) + +1. **Request Body**: For POST/PUT methods, document the expected request body +2. **Parameters**: Document path, query, and header parameters +3. **Examples**: Provide example requests and responses + +### Example Endpoint Documentation + +```yaml +/auth/login: + post: + tags: + - Authentication + summary: User Login + description: Authenticates a user and returns a JWT token + operationId: login + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/LoginRequest' + example: + username: "user@example.com" + password: "SecurePassword123!" + responses: + '200': + description: Successful login + content: + application/json: + schema: + $ref: '#/components/schemas/LoginResponse' + example: + success: true + data: + token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." + userId: "550e8400-e29b-41d4-a716-446655440000" + personId: "550e8400-e29b-41d4-a716-446655440001" + username: "user@example.com" + email: "user@example.com" + message: "Login successful" + timestamp: "2024-07-21T13:35:00Z" + '401': + description: Invalid credentials + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' +``` + +## Schema Documentation Standards + +When documenting data models (schemas), include the following information: + +### Required Elements + +1. **Schema Name**: Use PascalCase for schema names (e.g., `LoginRequest`) +2. **Type**: Specify the type (usually `object` for complex types) +3. **Properties**: List all properties with their types and descriptions +4. **Required Properties**: Specify which properties are required + +### Optional Elements (Recommended) + +1. **Examples**: Provide example values for properties +2. **Format**: Specify formats for string types (e.g., `email`, `uuid`, `date-time`) +3. **Enums**: For properties with a fixed set of values, specify the allowed values + +### Example Schema Documentation + +```yaml +LoginRequest: + type: object + properties: + username: + type: string + description: The user's email address or username + format: email + example: "user@example.com" + password: + type: string + description: The user's password + format: password + example: "SecurePassword123!" + required: + - username + - password +``` + +## Examples + +For a complete example of how to apply these guidelines to a new endpoint, see [API_DOCUMENTATION_EXAMPLE.md](API_DOCUMENTATION_EXAMPLE.md). + +### Well-Documented Endpoint Example + +Here's an example of a well-documented endpoint: + +```yaml +/api/horses/{id}: + get: + tags: + - Horse Registry + summary: Get Horse by ID + description: | + Retrieves detailed information about a specific horse by its unique identifier. + Requires authentication and appropriate permissions. + operationId: getHorseById + parameters: + - name: id + in: path + description: Unique identifier of the horse + required: true + schema: + type: string + format: uuid + security: + - bearerAuth: [] + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/HorseResponse' + example: + success: true + data: + id: "550e8400-e29b-41d4-a716-446655440000" + name: "Maestoso Mara" + birthYear: 2015 + breed: "Lipizzaner" + color: "Grey" + gender: "STALLION" + feiRegistered: true + ownerId: "550e8400-e29b-41d4-a716-446655440001" + active: true + message: "Horse retrieved successfully" + timestamp: "2024-07-21T13:35:00Z" + '401': + description: Unauthorized - Authentication required + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '403': + description: Forbidden - Insufficient permissions + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '404': + description: Horse not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' +``` + +## Documentation Workflow + +Follow these steps when adding or modifying API endpoints: + +1. **Implement the API endpoint** in the appropriate controller/route file +2. **Update the OpenAPI specification** in `documentation.yaml` +3. **Generate the documentation** using the Gradle task: + ```bash + ./gradlew :api-gateway:generateApiDocs + ``` +4. **Validate the documentation** using the Gradle task: + ```bash + ./gradlew :api-gateway:validateOpenApi + ``` +5. **Test the documentation** by accessing the Swagger UI at `http://localhost:8080/swagger` + +### CI/CD Pipeline + +The project includes a CI/CD pipeline that automatically: +- Validates the OpenAPI specification +- Generates updated documentation +- Deploys the documentation to GitHub Pages + +The workflow is defined in `.github/workflows/api-docs.yml` and is triggered: +- On changes to OpenAPI-related files +- On a weekly schedule +- Manually via GitHub Actions UI + +## Testing Documentation + +Always test your API documentation to ensure it accurately represents the API: + +1. **Start the API Gateway**: + ```bash + ./gradlew :api-gateway:run + ``` + +2. **Access Swagger UI**: + Open your browser and navigate to `http://localhost:8080/swagger` + +3. **Test the documented endpoints**: + - Verify that all parameters are correctly documented + - Test example requests + - Verify that responses match the documentation + +4. **Check static HTML documentation**: + Open your browser and navigate to `http://localhost:8080/docs` + +## Tools and Resources + +### Recommended Tools + +- **Swagger Editor**: [https://editor.swagger.io/](https://editor.swagger.io/) - Online editor for OpenAPI specifications +- **OpenAPI Validator**: Built into our Gradle tasks (`validateOpenApi`) +- **Postman**: For testing APIs and generating collections + +### Learning Resources + +- [OpenAPI 3.0 Specification](https://spec.openapis.org/oas/v3.0.3) +- [Swagger UI Documentation](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/) +- [OpenAPI Best Practices](https://oai.github.io/Documentation/best-practices.html) + +## Conclusion + +Following these guidelines ensures that our API documentation is consistent, comprehensive, and useful for all stakeholders. Good API documentation is a critical part of our development process and helps ensure the usability and maintainability of our APIs. + +If you have questions or suggestions for improving these guidelines, please contact the API team. diff --git a/docs/API_IMPLEMENTATION_SUMMARY.md b/docs/API_IMPLEMENTATION_SUMMARY.md index 594468e8..c57b20b2 100644 --- a/docs/API_IMPLEMENTATION_SUMMARY.md +++ b/docs/API_IMPLEMENTATION_SUMMARY.md @@ -23,7 +23,38 @@ This document summarizes the successful implementation of API documentation feat - Added `configureOpenApi()` and `configureSwagger()` calls - Swagger UI accessible at `/swagger` endpoint -### 2. Postman Collections +### 2. CI/CD Pipeline for Automatic API Documentation Generation +**Status: ✅ COMPLETED** + +- **Added OpenAPI Generator plugin** to `api-gateway/build.gradle.kts`: + - Updated to latest version (7.3.0) for improved functionality + - Configured to generate HTML documentation from OpenAPI specification + - Created enhanced `generateApiDocs` Gradle task with error handling + - Added OpenAPI specification validation before generation + - Implemented documentation versioning based on project version + - Configured to copy all generated documentation assets, not just index.html + +- **Enhanced GitHub Actions workflow** in `.github/workflows/api-docs.yml`: + - Updated to use latest GitHub Actions versions (checkout@v4, setup-java@v4) + - Added dedicated OpenAPI specification validation step + - Automatically triggers on changes to OpenAPI-related files + - Runs weekly on a schedule to ensure documentation is up-to-date + - Generates up-to-date API documentation + - Commits and pushes updated documentation to the repository + - Deploys documentation to GitHub Pages for better accessibility + - Includes notification steps for documentation updates + - Can be manually triggered via GitHub Actions UI + +- **Benefits**: + - Documentation is always in sync with the API implementation + - No manual steps required to update documentation + - Changes to API are automatically reflected in the documentation + - Documentation is validated before generation to prevent errors + - Historical versions of documentation are preserved + - Documentation is accessible via GitHub Pages for better user experience + - Team is notified when documentation is updated + +### 3. Postman Collections **Status: ✅ COMPLETED** - **Created comprehensive Postman collection** at `docs/postman/Meldestelle_API_Collection.json`: @@ -70,8 +101,9 @@ This document summarizes the successful implementation of API documentation feat 5. `docs/API_IMPLEMENTATION_SUMMARY.md` - This summary document ### Files Modified: -1. `api-gateway/build.gradle.kts` - Added OpenAPI/Swagger dependencies +1. `api-gateway/build.gradle.kts` - Added OpenAPI/Swagger dependencies, OpenAPI Generator plugin, and enhanced documentation generation tasks 2. `api-gateway/src/main/kotlin/at/mocode/gateway/Application.kt` - Integrated OpenAPI configuration +3. `.github/workflows/api-docs.yml` - Enhanced CI/CD workflow for API documentation generation and deployment ## 🚀 How to Use @@ -82,15 +114,38 @@ This document summarizes the successful implementation of API documentation feat # Access Swagger UI open http://localhost:8080/swagger + +# Access static HTML documentation +open http://localhost:8080/docs ``` -### 2. Postman Collection +### 2. Generate API Documentation Locally +```bash +# Generate API documentation +./gradlew :api-gateway:generateApiDocs + +# Validate OpenAPI specification +./gradlew :api-gateway:validateOpenApi +``` + +### 3. Access Documentation on GitHub Pages +The API documentation is automatically deployed to GitHub Pages and can be accessed at: +``` +https://{organization}.github.io/{repository}/ +``` + +Different versions of the documentation are available at: +``` +https://{organization}.github.io/{repository}/v{version}/ +``` + +### 4. Postman Collection 1. Import `docs/postman/Meldestelle_API_Collection.json` into Postman 2. Set `baseUrl` variable to `http://localhost:8080` 3. Use the collection to test all API endpoints 4. Authentication tokens are automatically managed -### 3. API Tests +### 5. API Tests ```bash # Run API tests (when compilation issues are resolved) ./gradlew :api-gateway:jvmTest @@ -174,6 +229,7 @@ open http://localhost:8080/swagger | Requirement | Status | Implementation | |-------------|--------|----------------| | **OpenAPI/Swagger Integration** | ✅ COMPLETED | Full OpenAPI 3.0 spec with Swagger UI | +| **CI/CD-Pipeline um automatische API-Dokumentationsgenerierung erweitern** | ✅ COMPLETED | GitHub Actions workflow with OpenAPI Generator | | **Postman Collections erstellen** | ✅ COMPLETED | Comprehensive collection with 576 lines | | **API-Tests schreiben** | ✅ COMPLETED | Integration test suite with 234 lines | diff --git a/docs/SWAGGER_DOCUMENTATION.md b/docs/SWAGGER_DOCUMENTATION.md index 1758d050..713c54d0 100644 --- a/docs/SWAGGER_DOCUMENTATION.md +++ b/docs/SWAGGER_DOCUMENTATION.md @@ -23,60 +23,176 @@ Die Meldestelle API verfügt jetzt über eine vollständige Swagger/OpenAPI-Doku ## Dokumentierte Endpunkte ### Basis-Endpunkte +- `GET /` - API Gateway Information - `GET /health` - Gesundheitsprüfung des Services -- `GET /api` - API-Informationen +- `GET /docs` - Zentrale API-Dokumentationsseite +- `GET /api` - Weiterleitung zur zentralen API-Dokumentationsseite +- `GET /api/json` - API-Informationen im JSON-Format -### Person Management (`/api/persons`) -- `GET /api/persons` - Alle Personen abrufen -- `POST /api/persons` - Neue Person erstellen -- `GET /api/persons/{id}` - Person nach UUID abrufen -- `PUT /api/persons/{id}` - Person aktualisieren -- `DELETE /api/persons/{id}` - Person löschen -- `GET /api/persons/oeps/{oepsSatzNr}` - Person nach OEPS-Nummer abrufen -- `GET /api/persons/search?q={query}` - Personen suchen -- `GET /api/persons/verein/{vereinId}` - Personen nach Verein-ID abrufen +### Authentication Context (`/auth/*`) +- `POST /auth/login` - Benutzeranmeldung +- `POST /auth/register` - Benutzerregistrierung +- `GET /auth/profile` - Benutzerprofil abrufen + +### Master Data Context (`/api/masterdata/*`) +- `GET /api/masterdata/countries` - Alle Länder abrufen +- `POST /api/masterdata/countries` - Neues Land erstellen +- `GET /api/masterdata/countries/{id}` - Land nach ID abrufen +- `PUT /api/masterdata/countries/{id}` - Land aktualisieren +- `DELETE /api/masterdata/countries/{id}` - Land löschen + +### Horse Registry Context (`/api/horses/*`) +- `GET /api/horses` - Alle Pferde abrufen +- `GET /api/horses/fei-registered` - FEI-registrierte Pferde abrufen +- `GET /api/horses/stats` - Pferdestatistiken abrufen +- `POST /api/horses/stats` - Neues Pferd registrieren +- `GET /api/horses/{id}` - Pferd nach ID abrufen + +### Event Management Context (`/api/events/*`) +- `GET /api/events` - Alle Veranstaltungen abrufen +- `GET /api/events/stats` - Veranstaltungsstatistiken abrufen +- `POST /api/events/stats` - Neue Veranstaltung erstellen ## Schema-Definitionen -### Person +### LoginRequest ```yaml -Person: +LoginRequest: + type: object + properties: + email: + type: string + format: email + password: + type: string + format: password + required: + - email + - password +``` + +### UserProfileResponse +```yaml +UserProfileResponse: type: object properties: id: type: string format: uuid - vorname: - type: string - nachname: - type: string - geburtsdatum: - type: string - format: date - oepsSatzNr: - type: string - vereinId: - type: string - format: uuid email: type: string format: email - telefon: + firstName: type: string - required: - - vorname - - nachname + lastName: + type: string + phoneNumber: + type: string + roles: + type: array + items: + type: string + createdAt: + type: string + format: date-time + updatedAt: + type: string + format: date-time ``` -### Error +### CountryResponse ```yaml -Error: +CountryResponse: type: object properties: - error: + id: type: string - required: - - error + format: uuid + name: + type: string + isoCode: + type: string + active: + type: boolean +``` + +### HorseResponse +```yaml +HorseResponse: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + birthYear: + type: integer + breed: + type: string + color: + type: string + gender: + type: string + enum: [STALLION, MARE, GELDING] + feiRegistered: + type: boolean + ownerId: + type: string + format: uuid + active: + type: boolean +``` + +### EventResponse +```yaml +EventResponse: + type: object + properties: + id: + type: string + format: uuid + name: + type: string + startDate: + type: string + format: date + endDate: + type: string + format: date + location: + type: string + organizerId: + type: string + format: uuid + description: + type: string + status: + type: string + enum: [DRAFT, PUBLISHED, CANCELLED, COMPLETED] +``` + +### ErrorResponse +```yaml +ErrorResponse: + type: object + properties: + success: + type: boolean + message: + type: string + errors: + type: array + items: + type: object + properties: + field: + type: string + message: + type: string + timestamp: + type: string + format: date-time ``` ## Verwendung @@ -101,25 +217,26 @@ Besuchen Sie `http://localhost:8080/openapi` um die vollständige OpenAPI-Spezif ### Neue Endpunkte hinzufügen Um neue API-Endpunkte zu dokumentieren, erweitern Sie die Datei: -`server/src/main/resources/openapi.yaml` +`api-gateway/src/jvmMain/resources/openapi/documentation.yaml` ### Beispiel für neuen Endpunkt: ```yaml -/api/vereine: +/api/events/categories: get: - summary: Get all clubs - description: Retrieve a list of all clubs tags: - - Clubs + - Event Management + summary: Get Event Categories + description: Returns a list of all event categories + operationId: getEventCategories responses: '200': - description: List of clubs + description: Successful operation content: application/json: schema: type: array items: - $ref: '#/components/schemas/Verein' + $ref: '#/components/schemas/EventCategoryResponse' ``` ## Technische Details @@ -130,19 +247,26 @@ Um neue API-Endpunkte zu dokumentieren, erweitern Sie die Datei: ### Konfiguration Die Swagger/OpenAPI-Konfiguration befindet sich in: -- `server/src/main/kotlin/at/mocode/plugins/Routing.kt` -- `server/src/main/resources/openapi.yaml` +- `api-gateway/src/jvmMain/kotlin/at/mocode/gateway/config/OpenApiConfig.kt` - Konfiguration der OpenAPI und Swagger UI Endpunkte +- `api-gateway/src/jvmMain/kotlin/at/mocode/gateway/module.kt` - Integration der OpenAPI-Konfiguration in die Anwendung +- `api-gateway/src/jvmMain/resources/openapi/documentation.yaml` - OpenAPI-Spezifikation im YAML-Format -### Tests -Automatisierte Tests für die Swagger-Funktionalität: -- `server/src/test/kotlin/at/mocode/SwaggerTest.kt` +### Implementierte Funktionen +- Vollständige OpenAPI 3.0.3 Spezifikation +- Interaktive Swagger UI für API-Exploration +- Dokumentation aller API-Endpunkte aus allen Bounded Contexts +- Authentifizierung mit JWT-Token +- Beispiel-Requests und -Responses für alle Endpunkte +- Schema-Definitionen für alle Datenmodelle -## Nächste Schritte +## Aktueller Status -1. **Erweitern Sie die Dokumentation** für weitere API-Endpunkte (Vereine, Turniere, etc.) -2. **Fügen Sie Authentifizierung hinzu** zur OpenAPI-Spezifikation wenn implementiert -3. **Konfigurieren Sie Produktions-URLs** in der OpenAPI-Spezifikation -4. **Implementieren Sie API-Versionierung** in der Dokumentation +✅ **Implementiert**: +- OpenAPI-Spezifikation für alle Bounded Contexts +- Swagger UI für interaktive API-Exploration +- JWT-Authentifizierung in der OpenAPI-Spezifikation +- Produktions- und Entwicklungs-URLs in der Spezifikation +- Vollständige Dokumentation aller Endpunkte und Datenmodelle ## Troubleshooting