openapi: 3.0.3
info:
  title: Global Travel Monitor Events API
  description: |
    Global Travel Monitor (GTM) API – Read-only Zugriff auf globale
    Sicherheits- und Reiserisiko-Events sowie Länder-Übersichten.
  version: 1.0.0
  contact:
    name: Global Travel Monitor Support

servers:
  - url: https://api.global-travel-monitor.de/v1
    description: Produktionsserver

security:
  - BearerAuth: []

tags:
  - name: Events
    description: Aktive Events abfragen
  - name: Basisdaten
    description: Kontinente, Länder, Regionen und Event-Kategorien

paths:
  /events:
    get:
      tags: [Events]
      summary: Events auflisten
      description: |
        Gibt eine paginierte Liste aller aktiven Events zurück (einschließlich
        zukünftiger Events). Dies umfasst sowohl von Global Travel Monitor gepflegte
        Events als auch Events von API-Partnern. Es werden nur Events zurückgegeben,
        die freigegeben (approved), aktiv und nicht archiviert sind. Mit start_date
        und end_date kann der Zeitraum eingegrenzt werden.
      parameters:
        - name: risk_level
          in: query
          schema:
            type: string
            enum: [high, medium, low, info]
          description: Filter nach Risikostufe
        - name: country
          in: query
          schema:
            type: string
            maxLength: 3
          description: "Filter nach Ländercode – ISO alpha-2 (z.B. DE) oder alpha-3 (z.B. DEU)"
        - name: event_category
          in: query
          schema:
            type: string
            maxLength: 50
          description: "Filter nach Event-Typ-Code (z.B. security)"
        - name: region
          in: query
          schema:
            type: integer
          description: Filter nach Region-ID (numerische ID)
        - name: source
          in: query
          schema:
            type: string
            maxLength: 100
          description: "Filter nach Event-Herkunft – Name des Anbieters (z.B. manual, API-Client-Name)"
        - name: start_date
          in: query
          schema:
            type: string
            format: date
          description: "Nur Events ab diesem Datum (z.B. 2026-03-01)"
        - name: end_date
          in: query
          schema:
            type: string
            format: date
          description: "Nur Events bis zu diesem Datum (z.B. 2026-04-30)"
        - name: per_page
          in: query
          schema:
            type: integer
            default: 25
            minimum: 1
            maximum: 100
          description: Einträge pro Seite
        - name: page
          in: query
          schema:
            type: integer
            default: 1
            minimum: 1
          description: Seitennummer
      responses:
        '200':
          description: Erfolgreiche Abfrage
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Event'
                  meta:
                    $ref: '#/components/schemas/PaginationMeta'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /events/{uuid}:
    parameters:
      - name: uuid
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: UUID des Events
    get:
      tags: [Events]
      summary: Einzelnes Event anzeigen
      responses:
        '200':
          description: Event gefunden
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    $ref: '#/components/schemas/Event'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /events/countries:
    get:
      tags: [Events]
      summary: Länder mit aktiven Events auflisten
      description: |
        Gibt eine Liste aller Länder zurück, die mindestens ein aktives Event haben,
        zusammen mit der Anzahl aktiver Events. Sortiert nach Anzahl (absteigend).
        Nicht paginiert.
      responses:
        '200':
          description: Erfolgreiche Abfrage
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/CountryWithEvents'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'

  /continents:
    get:
      tags: [Basisdaten]
      summary: Kontinente auflisten
      description: Gibt eine Liste aller Kontinente zurück.
      responses:
        '200':
          description: Erfolgreiche Abfrage
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ContinentItem'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '403':
          $ref: '#/components/responses/Forbidden'

  /countries:
    get:
      tags: [Basisdaten]
      summary: Alle Länder auflisten
      description: |
        Gibt eine Liste aller Länder zurück. Optional nach Kontinent filterbar.
      parameters:
        - name: continent
          in: query
          schema:
            type: string
            maxLength: 2
          description: "Filter nach Kontinent-Code (z.B. EU, AS, AF)"
      responses:
        '200':
          description: Erfolgreiche Abfrage
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Country'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '403':
          $ref: '#/components/responses/Forbidden'

  /regions:
    get:
      tags: [Basisdaten]
      summary: Regionen auflisten
      description: |
        Gibt eine Liste aller Regionen zurück.
        Optional nach Land filterbar.
      parameters:
        - name: country
          in: query
          schema:
            type: string
            maxLength: 3
          description: "Filter nach Ländercode – ISO alpha-2 (z.B. DE) oder alpha-3 (z.B. DEU)"
      responses:
        '200':
          description: Erfolgreiche Abfrage
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/Region'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '403':
          $ref: '#/components/responses/Forbidden'

  /event-categories:
    get:
      tags: [Basisdaten]
      summary: Verfügbare Event-Typen auflisten
      description: |
        Gibt eine Liste aller aktiven Event-Typen zurück.
        Nützlich um die gültigen Werte für den event_category-Filter zu ermitteln.
      responses:
        '200':
          description: Erfolgreiche Abfrage
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/EventCategory'
        '401':
          $ref: '#/components/responses/Unauthenticated'
        '403':
          $ref: '#/components/responses/Forbidden'

components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: "API-Token im Format \"Bearer {token}\""

  schemas:
    Event:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: UUID des Events
          example: 550e8400-e29b-41d4-a716-446655440000
        title:
          type: string
          example: Earthquake in Turkey
        description:
          type: string
          nullable: true
          example: A 6.2 magnitude earthquake struck southeastern Turkey.
        risk_level:
          type: string
          enum: [high, medium, low, info]
          example: high
        start_date:
          type: string
          format: date-time
          nullable: true
          example: "2025-03-15T08:30:00Z"
        end_date:
          type: string
          format: date-time
          nullable: true
          description: "null = andauernd"
          example: null
        latitude:
          type: number
          format: float
          nullable: true
          example: 37.7749
        longitude:
          type: number
          format: float
          nullable: true
          example: 35.3214
        event_categories:
          type: array
          items:
            $ref: '#/components/schemas/EventCategory'
        countries:
          type: array
          items:
            $ref: '#/components/schemas/EventCountry'
        source:
          $ref: '#/components/schemas/EventSource'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    EventCategory:
      type: object
      properties:
        code:
          type: string
          example: security
        name:
          type: string
          example: Sicherheit

    Region:
      type: object
      properties:
        id:
          type: integer
          example: 42
        name_de:
          type: string
          example: Bayern
        name_en:
          type: string
          example: Bavaria
        code:
          type: string
          example: BY
        country_iso_code:
          type: string
          nullable: true
          example: DE
        country_name_de:
          type: string
          nullable: true
          example: Deutschland
        lat:
          type: number
          format: float
          nullable: true
          example: 48.7904
        lng:
          type: number
          format: float
          nullable: true
          example: 11.4979

    ContinentItem:
      type: object
      properties:
        code:
          type: string
          example: EU
        name_de:
          type: string
          example: Europa
        name_en:
          type: string
          example: Europe
        lat:
          type: number
          format: float
          nullable: true
          example: 54.526
        lng:
          type: number
          format: float
          nullable: true
          example: 15.2551

    EventCountry:
      type: object
      properties:
        iso_code:
          type: string
          example: TR
        iso3_code:
          type: string
          example: TUR
        name_de:
          type: string
          example: Tuerkei
        name_en:
          type: string
          example: Turkey
        continent:
          type: string
          nullable: true
          example: Asia
        latitude:
          type: number
          format: float
          nullable: true
          description: Breitengrad (Event-Standort im Land)
          example: 37.7749
        longitude:
          type: number
          format: float
          nullable: true
          description: Längengrad (Event-Standort im Land)
          example: 35.3214

    Country:
      type: object
      properties:
        iso_code:
          type: string
          example: DE
        iso3_code:
          type: string
          example: DEU
        name_de:
          type: string
          example: Deutschland
        name_en:
          type: string
          example: Germany
        continent:
          type: string
          nullable: true
          example: Europe
        continent_de:
          type: string
          nullable: true
          example: Europa
        lat:
          type: number
          format: float
          nullable: true
          example: 51.1657
        lng:
          type: number
          format: float
          nullable: true
          example: 10.4515
        is_eu_member:
          type: boolean
          example: true
        is_schengen_member:
          type: boolean
          example: true

    CountryWithEvents:
      type: object
      properties:
        iso_code:
          type: string
          example: DE
        iso3_code:
          type: string
          example: DEU
        name_de:
          type: string
          example: Deutschland
        name_en:
          type: string
          example: Germany
        continent:
          type: string
          nullable: true
          example: Europe
        continent_de:
          type: string
          nullable: true
          example: Europa
        lat:
          type: number
          format: float
          nullable: true
          example: 51.1657
        lng:
          type: number
          format: float
          nullable: true
          example: 10.4515
        is_eu_member:
          type: boolean
          example: true
        is_schengen_member:
          type: boolean
          example: true
        active_events_count:
          type: integer
          example: 3

    EventSource:
      type: object
      description: Herkunft des Events
      properties:
        type:
          type: string
          description: "Quelle: manual, api_client, passolution_infosystem, etc."
          example: api_client
        name:
          type: string
          nullable: true
          description: Name des API-Partners (bei API-Client-Events)
          example: Partner XY GmbH

    PaginationMeta:
      type: object
      properties:
        current_page:
          type: integer
          example: 1
        per_page:
          type: integer
          example: 25
        total:
          type: integer
          example: 142
        last_page:
          type: integer
          example: 6

    Error:
      type: object
      properties:
        success:
          type: boolean
          example: false
        message:
          type: string

    ValidationError:
      type: object
      properties:
        success:
          type: boolean
          example: false
        message:
          type: string
          example: The given data was invalid.
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          example:
            risk_level: ["The selected risk_level is invalid."]
            per_page: ["The per page field must be between 1 and 100."]

  responses:
    Unauthenticated:
      description: Nicht authentifiziert – Token fehlt oder ungültig
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            success: false
            message: Unauthenticated.

    Forbidden:
      description: Zugriff verweigert
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            success: false
            message: Token does not have the required permissions.

    NotFound:
      description: Ressource nicht gefunden
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            success: false
            message: Event not found

    ValidationError:
      description: Validierungsfehler
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'

    TooManyRequests:
      description: Rate Limit überschritten (60 Requests pro Minute)
      headers:
        Retry-After:
          schema:
            type: integer
          description: Sekunden bis zum nächsten erlaubten Request
