openapi: 3.0.3

info:
  title: Claude Microservice API
  version: "1.1.0"
  description: >
    API fuer den Claude Microservice. Unterstuetzt KI-Textgenerierung (Claude)
    sowie Audio-Transkription. Alle Endpunkte ausser /health erfordern eine
    Authentifizierung via X-API-Key Header.
  contact:
    name: sirplus.org
    url: https://claude.sirplus.org

servers:
  - url: https://claude.sirplus.org
    description: Produktionsserver

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API-Schluessel zur Authentifizierung

  schemas:
    HealthResponse:
      type: object
      properties:
        status:
          type: string
          example: ok
          description: Aktueller Dienststatus
        timestamp:
          type: string
          format: date-time
          example: "2025-01-27T12:00:00.000Z"
          description: Aktuelle Serverzeit
      required:
        - status
        - timestamp

    ClaudeJobResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            id:
              type: string
              example: job_abc123
              description: Eindeutige Job-ID
            status:
              type: string
              example: queued
              description: Aktueller Jobstatus
            stream_url:
              type: string
              example: /jobs/job_abc123/stream
              description: URL fuer Streaming-Events
            result_url:
              type: string
              example: /jobs/job_abc123
              description: URL zum Abrufen des Ergebnisses
          required:
            - id
            - status
            - stream_url
            - result_url
      required:
        - success
        - data

    TranscriptionJobResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            id:
              type: string
              example: job_xyz789
              description: Eindeutige Job-ID
            type:
              type: string
              example: transcription
              description: Job-Typ
            status:
              type: string
              example: queued
              description: Aktueller Jobstatus
            outputs:
              type: array
              items:
                type: string
              example:
                - plain
              description: Angeforderte Ausgabeformate
            result_url:
              type: string
              example: /jobs/job_xyz789
              description: URL zum Abrufen des Ergebnisses
          required:
            - id
            - type
            - status
            - outputs
            - result_url
      required:
        - success
        - data

    JobListItem:
      type: object
      properties:
        id:
          type: string
          example: job_abc123
          description: Eindeutige Job-ID
        type:
          type: string
          enum:
            - claude
            - transcription
          example: claude
          description: Art des Jobs
        status:
          type: string
          enum:
            - queued
            - processing
            - completed
            - failed
            - cancelled
          example: completed
          description: Aktueller Jobstatus
        created_at:
          type: string
          format: date-time
          example: "2025-01-27T12:00:00.000Z"
          description: Erstellungszeitpunkt

    ClaudeJobDetail:
      type: object
      properties:
        id:
          type: string
          example: job_abc123
        type:
          type: string
          example: claude
        status:
          type: string
          example: completed
        prompt:
          type: string
          example: Erklaere mir Quantencomputing.
          description: Der uebergebene Prompt
        model:
          type: string
          enum:
            - haiku
            - sonnet
            - opus
          example: sonnet
          description: Verwendetes Claude-Modell
        result:
          type: string
          description: Generiertes Ergebnis
        created_at:
          type: string
          format: date-time

    TranscriptionJobDetail:
      type: object
      properties:
        id:
          type: string
          example: job_xyz789
        type:
          type: string
          example: transcription
        status:
          type: string
          example: completed
        result:
          type: object
          properties:
            outputs:
              type: object
              description: Objekt mit den angeforderten Ausgabeformaten als Schluessel und den jeweiligen Ergebnissen als Werte.
              additionalProperties:
                type: string
        created_at:
          type: string
          format: date-time

    StreamResponse:
      type: object
      properties:
        status:
          type: string
          example: processing
          description: Aktueller Jobstatus
        events:
          type: array
          items:
            type: object
            properties:
              offset:
                type: integer
              data:
                type: string
            required:
              - offset
              - data
          description: Liste der Streaming-Events
        next_offset:
          type: integer
          example: 42
          description: Naechster Offset fuer Polling
      required:
        - status
        - events
        - next_offset

    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: string
          example: Nicht autorisiert
          description: Fehlermeldung

security:
  - ApiKeyAuth: []

paths:
  /health:
    get:
      summary: Dienststatus pruefen
      description: >
        Gibt den aktuellen Gesundheitsstatus des Dienstes zurueck.
        Dieser Endpunkt erfordert keine Authentifizierung.
      operationId: getHealth
      tags:
        - System
      security: []
      responses:
        "200":
          description: Dienst ist verfuegbar
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HealthResponse"

  /jobs:
    post:
      summary: Neuen Job erstellen
      description: >
        Erstellt einen neuen Job. Unterstuetzt zwei Modi -
        (1) Claude-Textgenerierung (Standard) und
        (2) Audio-Transkription (type=transcription).
      operationId: createJob
      tags:
        - Jobs
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              oneOf:
                - title: Claude-Job
                  type: object
                  description: Textgenerierung mit Claude. Sende einen Prompt und optionale Dateianhaenge.
                  properties:
                    type:
                      type: string
                      enum:
                        - claude
                      default: claude
                      description: Job-Typ (Standard ist claude)
                    prompt:
                      type: string
                      description: Der Prompt fuer die KI-Generierung
                      example: Fasse dieses Dokument zusammen.
                    model:
                      type: string
                      enum:
                        - haiku
                        - sonnet
                        - opus
                      default: sonnet
                      description: Zu verwendendes Claude-Modell. haiku ist schnell, sonnet ist ausgewogen, opus ist leistungsstark.
                    attachments:
                      type: array
                      items:
                        type: string
                        format: binary
                      description: Optionale Dateianhaenge (Bilder, PDFs, etc.)
                  required:
                    - prompt
                - title: Transkriptions-Job
                  type: object
                  description: Audio-Transkription. Sende eine Audiodatei und konfiguriere die gewuenschten Ausgabeformate.
                  properties:
                    type:
                      type: string
                      enum:
                        - transcription
                      description: Muss den Wert transcription haben
                    file:
                      type: string
                      format: binary
                      description: Audiodatei zur Transkription (z.B. MP3, WAV, M4A)
                    output:
                      type: string
                      description: JSON-Array-String mit gewuenschten Ausgabeformaten. Moegliche Werte sind plain, compact, bullets und doc.
                      default: "[\"plain\"]"
                      example: "[\"plain\",\"bullets\"]"
                    language:
                      type: string
                      description: Optionaler Sprachcode (z.B. de fuer Deutsch, en fuer Englisch). Wenn nicht angegeben, wird die Sprache automatisch erkannt.
                      example: de
                  required:
                    - type
                    - file
      responses:
        "201":
          description: Job erfolgreich erstellt
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/ClaudeJobResponse"
                  - $ref: "#/components/schemas/TranscriptionJobResponse"
        "400":
          description: Ungueltige Anfrage (z.B. fehlender Prompt oder Datei)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: Nicht autorisiert - API-Schluessel fehlt oder ungueltig
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

    get:
      summary: Alle Jobs auflisten
      description: Gibt eine Liste aller Jobs des authentifizierten Benutzers zurueck.
      operationId: listJobs
      tags:
        - Jobs
      responses:
        "200":
          description: Liste der Jobs
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/JobListItem"
        "401":
          description: Nicht autorisiert
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /jobs/{id}:
    get:
      summary: Job-Details abrufen
      description: >
        Gibt die vollstaendigen Details eines bestimmten Jobs zurueck.
        Die Antwortstruktur haengt vom Job-Typ ab (claude oder transcription).
      operationId: getJob
      tags:
        - Jobs
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Eindeutige Job-ID
      responses:
        "200":
          description: Job-Details
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/ClaudeJobDetail"
                  - $ref: "#/components/schemas/TranscriptionJobDetail"
        "401":
          description: Nicht autorisiert
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Job nicht gefunden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

    delete:
      summary: Job loeschen oder abbrechen
      description: >
        Loescht einen abgeschlossenen Job oder bricht einen laufenden Job ab.
        Nur der Ersteller des Jobs kann diesen loeschen.
      operationId: deleteJob
      tags:
        - Jobs
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Eindeutige Job-ID
      responses:
        "200":
          description: Job erfolgreich geloescht oder abgebrochen
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: Job erfolgreich geloescht
        "401":
          description: Nicht autorisiert
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Job nicht gefunden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /jobs/{id}/stream:
    get:
      summary: Streaming-Events abrufen
      description: >
        Ruft Streaming-Events fuer einen laufenden Job ab. Verwende den
        offset-Parameter fuer inkrementelles Polling, um nur neue Events
        seit dem letzten Abruf zu erhalten.
      operationId: streamJob
      tags:
        - Jobs
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Eindeutige Job-ID
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            default: 0
          description: Offset fuer inkrementelles Polling. Verwende den Wert von next_offset aus der vorherigen Antwort.
      responses:
        "200":
          description: Streaming-Events
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/StreamResponse"
        "401":
          description: Nicht autorisiert
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Job nicht gefunden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"

  /jobs/{id}/download/{filename}:
    get:
      summary: Generierte Datei herunterladen
      description: >
        Laedt eine vom Job generierte Datei herunter (z.B. transcript.pdf,
        transcript.docx). Erfordert Authentifizierung und Eigentuemerpruefung.
        Nur der Ersteller des Jobs kann Dateien herunterladen.
      operationId: downloadJobFile
      tags:
        - Jobs
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
          description: Eindeutige Job-ID
        - name: filename
          in: path
          required: true
          schema:
            type: string
          description: Name der herunterzuladenden Datei (z.B. transcript.pdf)
          example: transcript.pdf
      responses:
        "200":
          description: Dateiinhalt
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
            application/pdf:
              schema:
                type: string
                format: binary
        "401":
          description: Nicht autorisiert
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Zugriff verweigert - keine Berechtigung fuer diesen Job
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Job oder Datei nicht gefunden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
