openapi: 3.0.3
info:
  title: Starnberger See API
  description: API for accessing water temperature measurements, forecasts, and DWD weather data.
  version: 1.2.0
servers:
  - url: /
    description: Local server
paths:
  /api/v1/latest:
    get:
      summary: Get the latest measurement
      description: Returns the single most recent temperature measurement.
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Measurement'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /api/v1/entries:
    get:
      summary: Get the last N entries
      description: Returns the last N temperature measurements.
      parameters:
        - name: limit
          in: query
          description: The number of entries to return. Must be between 1 and 128.
          required: false
          schema:
            type: integer
            default: 24
            minimum: 1
            maximum: 128
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Measurement'
        '400':
          description: Invalid limit parameter
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /api/v1/dwd:
    get:
      summary: Get latest DWD data
      description: Returns the latest DWD temperature range.
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DWD'
        '404':
          description: No DWD data available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /api/v1/weather:
    get:
      summary: Get latest Open-Meteo weather data
      description: Returns the fresh 12-hour Open-Meteo rain and wind context used for trip planning messages.
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OpenMeteoWeather'
        '404':
          description: No fresh weather data available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /api/v1/forecast:
    get:
      summary: Get the water temperature forecast
      description: Returns the next 12 hours of predicted Starnberger See water temperatures with 50 and 90 percent prediction intervals.
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Forecast'
        '404':
          description: No fresh forecast available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

components:
  schemas:
    Measurement:
      type: object
      required:
        - temperature
        - datetime
      properties:
        temperature:
          type: number
          description: The water temperature.
        datetime:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$'
          example: '2026-04-29T10:15:00'
          description: The timestamp of the measurement as Germany local time (Europe/Berlin), matching the NID Bayern source table.
    DWD:
      type: object
      required:
        - temperatureMin
        - temperatureMax
      properties:
        temperatureMin:
          type: number
          description: The minimum temperature from DWD.
        temperatureMax:
          type: number
          description: The maximum temperature from DWD.
    OpenMeteoWeather:
      type: object
      required:
        - source
        - generated_at
        - latitude
        - longitude
        - timezone
        - hourly
        - summary
      properties:
        source:
          type: string
          enum:
            - open-meteo
        generated_at:
          type: string
          format: date-time
          example: '2026-05-31T10:38:44Z'
        latitude:
          type: number
          example: 47.9
        longitude:
          type: number
          example: 11.32
        timezone:
          type: string
          enum:
            - Europe/Berlin
        hourly:
          type: array
          items:
            $ref: '#/components/schemas/OpenMeteoHour'
        summary:
          type: object
          required:
            - next_12h
          properties:
            next_12h:
              $ref: '#/components/schemas/OpenMeteoNext12h'
    OpenMeteoHour:
      type: object
      required:
        - time
        - temperature_2m
        - apparent_temperature
        - precipitation_probability
        - precipitation
        - rain
        - showers
        - weather_code
        - cloud_cover
        - wind_speed_10m
        - wind_gusts_10m
      properties:
        time:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$'
          example: '2026-05-31T12:00'
          description: Forecast hour as Germany local time (Europe/Berlin).
        temperature_2m:
          type: number
          nullable: true
          description: Air temperature in Celsius.
        apparent_temperature:
          type: number
          nullable: true
          description: Apparent air temperature in Celsius.
        precipitation_probability:
          type: integer
          nullable: true
          minimum: 0
          maximum: 100
          description: Precipitation probability in percent.
        precipitation:
          type: number
          nullable: true
          description: Precipitation amount in millimeters.
        rain:
          type: number
          nullable: true
          description: Rain amount in millimeters.
        showers:
          type: number
          nullable: true
          description: Showers amount in millimeters.
        weather_code:
          type: integer
          nullable: true
          description: WMO weather interpretation code.
        cloud_cover:
          type: integer
          nullable: true
          minimum: 0
          maximum: 100
          description: Total cloud cover in percent.
        wind_speed_10m:
          type: number
          nullable: true
          description: Wind speed at 10 meters.
        wind_gusts_10m:
          type: number
          nullable: true
          description: Wind gusts at 10 meters.
    OpenMeteoNext12h:
      type: object
      required:
        - will_rain
        - rain_level
        - precipitation_probability_max
        - precipitation_sum
        - rain_hours
        - first_rain_time
        - wind_gust_max
      properties:
        will_rain:
          type: boolean
        rain_level:
          type: string
          enum:
            - none
            - possible
            - likely
        precipitation_probability_max:
          type: integer
          nullable: true
          minimum: 0
          maximum: 100
        precipitation_sum:
          type: number
          description: Sum of precipitation over the next 12 forecast hours in millimeters.
        rain_hours:
          type: integer
          minimum: 0
        first_rain_time:
          type: string
          nullable: true
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}$'
        wind_gust_max:
          type: number
          nullable: true
    Forecast:
      type: object
      required:
        - base_time
        - lake_temp_now
        - generated_at
        - forecast
      properties:
        base_time:
          type: string
          format: date-time
          example: '2026-05-31T11:00:00Z'
          description: The latest observed lake timestamp used as the forecast base time.
        lake_temp_now:
          type: number
          example: 18.4
          description: The measured lake temperature at the forecast base time.
        generated_at:
          type: string
          format: date-time
          example: '2026-05-31T10:38:44Z'
          description: The timestamp when the prediction was generated.
        forecast:
          type: array
          description: Hourly prediction points, typically horizons 1 through 12.
          items:
            $ref: '#/components/schemas/ForecastPoint'
        mean_skill_pct:
          type: number
          example: 36.0
          description: Mean model skill as percent MAE reduction versus persistence, when provided.
        model:
          type: string
          example: HistGradientBoosting (absolute-error central + CQR quantiles) on deltas
          description: Human-readable model description, when provided.
    ForecastPoint:
      type: object
      required:
        - h
        - time
        - temp
        - p5
        - p95
        - p25
        - p75
      properties:
        h:
          type: integer
          minimum: 1
          maximum: 12
          example: 1
          description: Forecast horizon in hours after base_time.
        time:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$'
          example: '2026-05-31T12:00:00'
          description: The predicted point timestamp as an offsetless UTC wall-clock string, matching the app's measurement timestamps.
        temp:
          type: number
          example: 18.7
          description: The central predicted water temperature in Celsius.
        p5:
          type: number
          example: 18.4
          description: Lower bound of the 90 percent prediction interval in Celsius.
        p95:
          type: number
          example: 19.0
          description: Upper bound of the 90 percent prediction interval in Celsius.
        p25:
          type: number
          example: 18.6
          description: Lower bound of the 50 percent prediction interval in Celsius.
        p75:
          type: number
          example: 18.8
          description: Upper bound of the 50 percent prediction interval in Celsius.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: The error message.
