openapi: 3.0.0
info:
  title: Orbital Server API
  version: 1.0.0
  description: |
    API for retrieving space launch and news information.
    
    Data Sources:
    - Space launches and agencies: The Space Devs API (ll.thespacedevs.com)
    - News articles: Spaceflight News API (api.spaceflightnewsapi.net)
    
    Caching Strategy:
    - Launches: Cached in database, refreshed hourly
    - News: Cached in database, refreshed periodically
    - Agencies: Cached in database indefinitely, fetched on-demand
    - Images: Cached in database, proxied through /images endpoint
    
    Rate Limiting:
    - Production: 15 requests per hour per IP, minimum 4 minutes between requests
    - Development: 7200 requests per hour per IP (2/sec), minimum 100ms between requests
    - Headers indicate remaining requests and reset time
    - Rate limit status is returned in response headers:
      - X-RateLimit-Limit: Maximum requests per hour
      - X-RateLimit-Remaining: Remaining requests in current window
      - X-RateLimit-Reset: Unix timestamp when the rate limit resets
    
    Error Handling:
    - All errors follow a consistent format with 'type' and 'message' fields
    - Common error types: VALIDATION_ERROR, NOT_FOUND, EXTERNAL_API_ERROR, RATE_LIMIT_ERROR
    - 404 responses indicate resource not found (including rate-limited external resources)
    - 429 responses indicate local rate limit exceeded
    - 500 responses indicate internal server or external API errors
    
    Web Pages:
    - / (Index): Landing page with feature overview and API information
    - /launches: Interactive page displaying upcoming space launches
    - /api/docs: Interactive API documentation with Swagger UI
    - /api/openapi.yaml: Raw OpenAPI specification
    
    Server Features:
    - Multi-layer caching with database persistence
    - Automatic rate limiting and request throttling
    - Image proxy and caching for external CDN resources
    - Dark mode support with system preference detection
    - Responsive web interface for all endpoints

servers:
  - url: https://orbtlapp.com
    description: Production server
  - url: https://localhost:1969
    description: Development server (HTTPS)
  - url: http://localhost:1969
    description: Development server (HTTP)

tags:
  - name: Launches
    description: Endpoints for retrieving space launch information
  - name: News
    description: Endpoints for retrieving space-related news articles
  - name: Agencies
    description: Endpoints for retrieving space agency information
  - name: System
    description: System and health check endpoints
  - name: Images
    description: Endpoints for retrieving cached images
  - name: Weather
    description: Endpoints for retrieving weather data for locations

paths:
  /api/health:
    get:
      tags:
        - System
      summary: Health check endpoint
      description: Simple health check to verify server status and environment
      responses:
        '200':
          description: Server is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: "OK"
                  env:
                    type: string
                    example: "development"
                  version:
                    type: string
                    example: "1.0.0"
                  uptime:
                    type: string
                    example: "24h0m0s"
                  database:
                    type: string
                    example: "connected"
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '503':
          description: Service unavailable (database connection failed)

  /api/weather:
    get:
      tags:
        - Weather
      summary: Get weather data
      description: Retrieve current weather or forecast data for a location
      parameters:
        - name: location
          in: query
          description: Location name (e.g., "London,UK")
          required: false
          schema:
            type: string
        - name: lat
          in: query
          description: Latitude coordinate
          required: false
          schema:
            type: number
            format: float
        - name: lon
          in: query
          description: Longitude coordinate
          required: false
          schema:
            type: number
            format: float
        - name: forecast
          in: query
          description: Set to "true" to get a forecast instead of current weather
          required: false
          schema:
            type: boolean
            default: false
      responses:
        '200':
          description: Weather data
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/WeatherData'
                  - $ref: '#/components/schemas/ForecastData'
        '400':
          description: Bad request - Missing required parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'
        '503':
          description: Weather API is not configured
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /api/batch:
    get:
      tags:
        - System
      summary: Get upcoming launches and news articles
      description: Retrieve upcoming launches and news articles concurrently. This endpoint is useful for populating initial views with a single call.
      responses:
        '200':
          description: Batch data for launches and news
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BatchResponse'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'

  /api/launches/upcoming:
    get:
      tags:
        - Launches
      summary: Get upcoming launches
      description: Retrieve a list of upcoming space launches
      parameters:
        - name: limit
          in: query
          description: Maximum number of launches to return
          required: false
          schema:
            type: integer
            default: 9
            minimum: 1
            maximum: 100
      responses:
        '200':
          description: List of upcoming launches
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Launch'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'

  /api/news:
    get:
      tags:
        - News
      summary: Get latest space news
      description: Retrieve the latest space-related news articles
      parameters:
        - name: limit
          in: query
          description: Maximum number of articles to return
          required: false
          schema:
            type: integer
            default: 10
            minimum: 1
            maximum: 100
      responses:
        '200':
          description: List of news articles
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/NewsArticle'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'

  /api/agencies/{id}:
    get:
      tags:
        - Agencies
      summary: Get agency details
      description: Retrieve details about a specific space agency
      parameters:
        - name: id
          in: path
          description: Agency ID
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Agency details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agency'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'

  /api/images/{path}:
    get:
      tags:
        - Images
      summary: Get cached image
      description: |
        Retrieve a cached image from the server. Images are cached from the Space Devs CDN.
        If an image is not in the cache, it will be downloaded and cached before being served.
        Images are cached for 24 hours.

        Note: Provide only the image filename in {path}, e.g., 'falcon_9_image_20230807133459.jpeg'. Do not include full URLs or encode them—the server handles proxying from the CDN.
      parameters:
        - name: path
          in: path
          description: Image filename (e.g., 'falcon_9_image_20230807133459.jpeg', not a full URL)
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Image file
          headers:
            Content-Type:
              schema:
                type: string
                example: "image/jpeg"
            Cache-Control:
              schema:
                type: string
                example: "public, max-age=86400"
            X-Cache:
              schema:
                type: string
                enum: ["HIT", "MISS"]
                example: "HIT"
            X-Cache-Source:
              schema:
                type: string
                enum: ["db", "cdn"]
                example: "db"
            X-Cache-Age:
              schema:
                type: string
                example: "2h3m15s"
          content:
            image/*:
              schema:
                type: string
                format: binary
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'

  /api/images/maps/{path}:
    get:
      tags:
        - Images
      summary: Get cached map image
      description: |
        Retrieve a cached map image from the server. Map images are cached from the Space Devs CDN.
        If an image is not in the cache, it will be downloaded and cached before being served.
        Images are cached for 24 hours.

        Note: Provide only the map image filename in {path}, e.g., 'map_image_example.jpeg'. Do not include full URLs or encode them—the server handles proxying from the CDN.
      parameters:
        - name: path
          in: path
          description: Map image filename (e.g., 'map_image_example.jpeg', not a full URL)
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Map image file
          headers:
            Content-Type:
              schema:
                type: string
                example: "image/jpeg"
            Cache-Control:
              schema:
                type: string
                example: "public, max-age=86400"
            X-Cache:
              schema:
                type: string
                enum: ["HIT", "MISS"]
                example: "HIT"
            X-Cache-Source:
              schema:
                type: string
                enum: ["db", "cdn"]
                example: "db"
            X-Cache-Age:
              schema:
                type: string
                example: "2h3m15s"
          content:
            image/*:
              schema:
                type: string
                format: binary
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalError'

components:
  schemas:
    Launch:
      type: object
      properties:
        id:
          type: string
          description: Unique identifier of the launch
        name:
          type: string
          description: Name of the launch mission
        status:
          type: string
          description: Current status of the launch
        net:
          type: string
          format: date-time
          description: No earlier than (NET) launch time
        window_start:
          type: string
          format: date-time
          description: Start of launch window
        window_end:
          type: string
          format: date-time
          description: End of launch window
        launch_service_provider:
          type: object
          properties:
            name:
              type: string
            url:
              type: string
        rocket:
          type: object
          properties:
            configuration:
              type: object
              properties:
                name:
                  type: string
                url:
                  type: string
        pad:
          type: object
          properties:
            name:
              type: string
            url:
              type: string
            map_image:
              type: string
            location:
              type: object
              properties:
                name:
                  type: string
                url:
                  type: string
                map_image:
                  type: string
        mission:
          type: object
          properties:
            name:
              type: string
            description:
              type: string
            agencies:
              type: array
              items:
                type: object
                properties:
                  name:
                    type: string
                  url:
                    type: string
        image:
          type: object
          properties:
            image_url:
              type: string
            thumbnail_url:
              type: string
      required:
        - id
        - name
        - status
        - net

    NewsArticle:
      type: object
      properties:
        id:
          type: integer
          description: Unique identifier of the article
        title:
          type: string
          description: Article title
        url:
          type: string
          description: URL to the full article
        published_at:
          type: string
          format: date-time
          description: Publication date and time
        summary:
          type: string
          description: Brief summary of the article
        image_url:
          type: string
          description: URL to article's main image
      required:
        - id
        - title
        - url
        - published_at

    Error:
      type: object
      properties:
        type:
          type: string
          description: Type of error (e.g., VALIDATION_ERROR)
        message:
          type: string
          description: Detailed error message

    Agency:
      type: object
      properties:
        id:
          type: integer
          description: Unique identifier of the agency
        name:
          type: string
          description: Full name of the agency
        url:
          type: string
          description: URL to the agency's details on our API
        original_url:
          type: string
          description: Original URL from Space Devs API
        abbrev:
          type: string
          description: Agency abbreviation
        type:
          type: string
          description: Type of agency (e.g., Government, Commercial)
        description:
          type: string
          description: Detailed description of the agency
        administrator:
          type: string
          description: Current administrator of the agency
        founding_year:
          type: integer
          description: Year the agency was founded
        launchers:
          type: string
          description: List of launchers operated by the agency
        spacecraft:
          type: string
          description: List of spacecraft operated by the agency
        parent:
          type: string
          description: Parent organization if applicable
        image_url:
          type: string
          description: URL to the agency's main image
        logo_url:
          type: string
          description: URL to the agency's logo
        country_code:
          type: string
          description: ISO country code
        featured:
          type: boolean
          description: Whether this is a featured agency
        total_launch_count:
          type: integer
          description: Total number of launches
        successful_launches:
          type: integer
          description: Number of successful launches
        consecutive_successful_launches:
          type: integer
          description: Number of consecutive successful launches
        failed_launches:
          type: integer
          description: Number of failed launches
        pending_launches:
          type: integer
          description: Number of pending launches
        last_updated:
          type: string
          format: date-time
          description: Last time the agency data was updated
      required:
        - id
        - name
        - url
        - original_url

    WeatherData:
      type: object
      description: Current weather data for a location
      properties:
        coord:
          type: object
          properties:
            lon:
              type: number
              format: float
              description: Longitude of the location
            lat:
              type: number
              format: float
              description: Latitude of the location
        weather:
          type: array
          description: Weather conditions
          items:
            type: object
            properties:
              id:
                type: integer
                description: Weather condition id
              main:
                type: string
                description: Group of weather parameters (Rain, Snow, Clouds etc.)
              description:
                type: string
                description: Weather condition within the group
              icon:
                type: string
                description: Weather icon id
        base:
          type: string
          description: Internal parameter
        main:
          type: object
          description: Main weather parameters
          properties:
            temp:
              type: number
              format: float
              description: Temperature in Celsius
            feels_like:
              type: number
              format: float
              description: Temperature that accounts for human perception
            temp_min:
              type: number
              format: float
              description: Minimum temperature
            temp_max:
              type: number
              format: float
              description: Maximum temperature
            pressure:
              type: integer
              description: Atmospheric pressure in hPa
            humidity:
              type: integer
              description: Humidity percentage
            sea_level:
              type: integer
              description: Atmospheric pressure at sea level
            grnd_level:
              type: integer
              description: Atmospheric pressure at ground level
        visibility:
          type: integer
          description: Visibility in meters
        wind:
          type: object
          description: Wind information
          properties:
            speed:
              type: number
              format: float
              description: Wind speed in m/s
            deg:
              type: integer
              description: Wind direction in degrees
            gust:
              type: number
              format: float
              description: Wind gust in m/s
        clouds:
          type: object
          description: Cloud information
          properties:
            all:
              type: integer
              description: Cloudiness percentage
        rain:
          type: object
          description: Rain information
          properties:
            1h:
              type: number
              format: float
              description: Rain volume for the last 1 hour, mm
            3h:
              type: number
              format: float
              description: Rain volume for the last 3 hours, mm
        snow:
          type: object
          description: Snow information
          properties:
            1h:
              type: number
              format: float
              description: Snow volume for the last 1 hour, mm
            3h:
              type: number
              format: float
              description: Snow volume for the last 3 hours, mm
        dt:
          type: integer
          description: Time of data calculation, unix, UTC
        sys:
          type: object
          description: System information
          properties:
            type:
              type: integer
              description: Internal parameter
            id:
              type: integer
              description: Internal parameter
            country:
              type: string
              description: Country code
            sunrise:
              type: integer
              description: Sunrise time, unix, UTC
            sunset:
              type: integer
              description: Sunset time, unix, UTC
        timezone:
          type: integer
          description: Shift in seconds from UTC
        id:
          type: integer
          description: City ID
        name:
          type: string
          description: City name
        cod:
          type: integer
          description: Internal parameter
      required:
        - weather
        - main
        - dt
        - name

    ForecastData:
      type: object
      description: Forecast data for a location
      properties:
        cod:
          type: string
          description: Internal parameter
        message:
          type: integer
          description: Internal parameter
        cnt:
          type: integer
          description: Number of timestamps returned
        list:
          type: array
          description: List of forecast data
          items:
            type: object
            properties:
              dt:
                type: integer
                description: Time of data forecasted, unix, UTC
              main:
                type: object
                description: Main weather parameters
                properties:
                  temp:
                    type: number
                    format: float
                    description: Temperature in Celsius
                  feels_like:
                    type: number
                    format: float
                    description: Temperature that accounts for human perception
                  temp_min:
                    type: number
                    format: float
                    description: Minimum temperature
                  temp_max:
                    type: number
                    format: float
                    description: Maximum temperature
                  pressure:
                    type: integer
                    description: Atmospheric pressure in hPa
                  sea_level:
                    type: integer
                    description: Atmospheric pressure at sea level
                  grnd_level:
                    type: integer
                    description: Atmospheric pressure at ground level
                  humidity:
                    type: integer
                    description: Humidity percentage
                  temp_kf:
                    type: number
                    format: float
                    description: Internal parameter
              weather:
                type: array
                description: Weather conditions
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                      description: Weather condition id
                    main:
                      type: string
                      description: Group of weather parameters (Rain, Snow, Clouds etc.)
                    description:
                      type: string
                      description: Weather condition within the group
                    icon:
                      type: string
                      description: Weather icon id
              clouds:
                type: object
                description: Cloud information
                properties:
                  all:
                    type: integer
                    description: Cloudiness percentage
              wind:
                type: object
                description: Wind information
                properties:
                  speed:
                    type: number
                    format: float
                    description: Wind speed in m/s
                  deg:
                    type: integer
                    description: Wind direction in degrees
                  gust:
                    type: number
                    format: float
                    description: Wind gust in m/s
              visibility:
                type: integer
                description: Visibility in meters
              pop:
                type: number
                format: float
                description: Probability of precipitation
              rain:
                type: object
                description: Rain information
                properties:
                  3h:
                    type: number
                    format: float
                    description: Rain volume for the last 3 hours, mm
              snow:
                type: object
                description: Snow information
                properties:
                  3h:
                    type: number
                    format: float
                    description: Snow volume for the last 3 hours, mm
              sys:
                type: object
                description: System information
                properties:
                  pod:
                    type: string
                    description: Part of day (n - night, d - day)
              dt_txt:
                type: string
                description: Time of data forecasted, ISO, UTC
        city:
          type: object
          description: City information
          properties:
            id:
              type: integer
              description: City ID
            name:
              type: string
              description: City name
            coord:
              type: object
              properties:
                lat:
                  type: number
                  format: float
                  description: Latitude of the city
                lon:
                  type: number
                  format: float
                  description: Longitude of the city
            country:
              type: string
              description: Country code
            population:
              type: integer
              description: City population
            timezone:
              type: integer
              description: Shift in seconds from UTC
            sunrise:
              type: integer
              description: Sunrise time, unix, UTC
            sunset:
              type: integer
              description: Sunset time, unix, UTC
      required:
        - list
        - city

    BatchResponse:
      type: object
      properties:
        launches:
          $ref: '#/components/schemas/LaunchResponse'
        news:
          $ref: '#/components/schemas/NewsResponse'
        launches_from_cache:
          type: boolean
          description: Indicates if the launch data was served from cache.
          readOnly: true
        news_from_cache:
          type: boolean
          description: Indicates if the news data was served from cache.
          readOnly: true

    LaunchResponse:
      type: object
      properties:
        launches:
          type: array
          items:
            $ref: '#/components/schemas/Launch'
        count:
          type: integer
          description: Number of launches returned.

    NewsResponse:
      type: object
      properties:
        articles:
          type: array
          items:
            $ref: '#/components/schemas/NewsArticle'
        count:
          type: integer
          description: Number of articles returned.
        total:
          type: integer
          description: Total number of articles available (might differ from count if pagination was implemented, currently same as count).

  responses:
    NotFound:
      description: The specified resource was not found
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                example: "NOT_FOUND"
              message:
                type: string
                example: "Resource not found"

    TooManyRequests:
      description: Too many requests, please try again later
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                example: "RATE_LIMIT_ERROR"
              message:
                type: string
                example: "Rate limit exceeded. Try again after 2025-02-19T02:37:38-05:00"

    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            type: object
            properties:
              type:
                type: string
                example: "INTERNAL_ERROR"
              message:
                type: string
                example: "An internal error occurred" 