{
  "openapi": "3.1.0",
  "info": {
    "title": "ReadIn API",
    "version": "1.0.0",
    "description": "REST API for the ReadIn script rehearsal app. Parse scripts, generate AI voices, and create rehearsal playback plans. Designed for consumption by web and native mobile clients.",
    "contact": {
      "name": "ReadIn",
      "url": "https://readin-jdbx.polsia.app"
    }
  },
  "servers": [
    {
      "url": "https://readin-jdbx.polsia.app",
      "description": "Production"
    },
    {
      "url": "http://localhost:3000",
      "description": "Local development"
    }
  ],
  "paths": {
    "/api/v1/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Health check",
        "description": "Returns server health status and available services.",
        "tags": ["System"],
        "responses": {
          "200": {
            "description": "Server is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "healthy" },
                    "version": { "type": "string", "example": "2.0.0" },
                    "services": {
                      "type": "object",
                      "properties": {
                        "tts": { "type": "boolean", "description": "Whether TTS (OpenAI) is configured" },
                        "database": { "type": "boolean", "description": "Whether database is connected" }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/voices": {
      "get": {
        "operationId": "listVoices",
        "summary": "List available TTS voices",
        "description": "Returns all available OpenAI TTS voices with descriptions. Use these voice IDs when calling the TTS endpoint or creating rehearsal plans.",
        "tags": ["Voices"],
        "responses": {
          "200": {
            "description": "List of voices",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "voices": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "string", "example": "alloy" },
                          "name": { "type": "string", "example": "Alloy" },
                          "description": { "type": "string", "example": "Neutral, balanced" }
                        }
                      }
                    },
                    "count": { "type": "integer", "example": 6 }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scripts/parse": {
      "post": {
        "operationId": "parseScript",
        "summary": "Parse a script into structured dialogue",
        "description": "Takes raw script text in CHARACTER: dialogue format and returns structured data with character detection, voice assignments, and line counts. Character names must be UPPERCASE.",
        "tags": ["Scripts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["text"],
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Raw script text. Each character line should follow the format: CHARACTER NAME: dialogue text",
                    "example": "MARCUS: You said you'd be there.\nELENA: I know what I said. But things changed.\nSARAH: Don't look at me like that."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Script parsed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean", "example": true },
                    "lines": {
                      "type": "array",
                      "description": "Ordered dialogue lines",
                      "items": {
                        "type": "object",
                        "properties": {
                          "character": { "type": "string", "example": "MARCUS" },
                          "dialogue": { "type": "string", "example": "You said you'd be there." }
                        }
                      }
                    },
                    "characters": {
                      "type": "array",
                      "description": "Unique character names in order of appearance",
                      "items": { "type": "string" },
                      "example": ["MARCUS", "ELENA", "SARAH"]
                    },
                    "voiceAssignments": {
                      "type": "object",
                      "description": "Mapping of character name to assigned voice ID",
                      "additionalProperties": { "type": "string" },
                      "example": { "MARCUS": "alloy", "ELENA": "echo", "SARAH": "fable" }
                    },
                    "lineCounts": {
                      "type": "object",
                      "description": "Number of lines per character",
                      "additionalProperties": { "type": "integer" },
                      "example": { "MARCUS": 1, "ELENA": 1, "SARAH": 1 }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/api/v1/tts/generate": {
      "post": {
        "operationId": "generateTTS",
        "summary": "Generate text-to-speech audio",
        "description": "Converts text to speech using OpenAI TTS. Returns MP3 audio. Text is truncated to 4096 characters. Results are cached for 1 hour.",
        "tags": ["TTS"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["text"],
                "properties": {
                  "text": {
                    "type": "string",
                    "description": "Text to convert to speech (max 4096 chars)",
                    "maxLength": 4096,
                    "example": "You said you'd be there. You promised me."
                  },
                  "voice": {
                    "type": "string",
                    "description": "Voice ID from /api/v1/voices. Defaults to 'alloy'.",
                    "enum": ["alloy", "echo", "fable", "onyx", "nova", "shimmer"],
                    "default": "alloy"
                  },
                  "speed": {
                    "type": "number",
                    "description": "Playback speed multiplier (0.25 to 4.0). Defaults to 1.0.",
                    "minimum": 0.25,
                    "maximum": 4.0,
                    "default": 1.0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Audio generated successfully",
            "headers": {
              "X-Voice": {
                "description": "Voice ID used for generation",
                "schema": { "type": "string" }
              },
              "X-Text-Length": {
                "description": "Length of text that was converted",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "audio/mpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Missing text",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "500": {
            "description": "TTS generation failed",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    },
    "/api/v1/rehearsal/plan": {
      "post": {
        "operationId": "createRehearsalPlan",
        "summary": "Create a rehearsal playback plan",
        "description": "Takes parsed script lines, selected character, and voice assignments to produce a sequenced playback plan. Each item includes timing, TTS payload, and gap durations. Native clients can use this to orchestrate playback without reimplementing the sequencing logic.",
        "tags": ["Rehearsal"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["lines", "selectedCharacter"],
                "properties": {
                  "lines": {
                    "type": "array",
                    "description": "Parsed script lines from /api/v1/scripts/parse",
                    "items": {
                      "type": "object",
                      "properties": {
                        "character": { "type": "string" },
                        "dialogue": { "type": "string" }
                      }
                    }
                  },
                  "selectedCharacter": {
                    "type": "string",
                    "description": "The character the user is playing",
                    "example": "ELENA"
                  },
                  "voiceAssignments": {
                    "type": "object",
                    "description": "Character-to-voice mapping from /api/v1/scripts/parse",
                    "additionalProperties": { "type": "string" }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rehearsal plan created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "selectedCharacter": { "type": "string" },
                    "summary": {
                      "type": "object",
                      "properties": {
                        "totalLines": { "type": "integer", "example": 13 },
                        "userLines": { "type": "integer", "example": 4 },
                        "aiLines": { "type": "integer", "example": 9 },
                        "estimatedDurationSec": { "type": "integer", "example": 120 },
                        "estimatedDurationMin": { "type": "number", "example": 2.0 }
                      }
                    },
                    "sequence": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "index": { "type": "integer", "description": "Line index in original script" },
                          "character": { "type": "string" },
                          "dialogue": { "type": "string" },
                          "isUser": { "type": "boolean", "description": "True if this is the user's line" },
                          "voice": { "type": "string", "nullable": true, "description": "Voice ID for AI lines, null for user lines" },
                          "wordCount": { "type": "integer" },
                          "estimatedDurationSec": { "type": "integer", "description": "Estimated speech duration in seconds" },
                          "gapDurationSec": { "type": "integer", "description": "Pause duration for user lines (0 for AI lines)" },
                          "ttsEndpoint": { "type": "string", "nullable": true, "description": "API endpoint to generate audio" },
                          "ttsPayload": {
                            "type": "object",
                            "nullable": true,
                            "description": "Request body for TTS endpoint",
                            "properties": {
                              "text": { "type": "string" },
                              "voice": { "type": "string" }
                            }
                          },
                          "delayAfterMs": { "type": "integer", "description": "Delay after line before next (ms)" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean", "example": false },
          "error": { "type": "string", "description": "Error code (e.g., MISSING_TEXT, TTS_FAILED)", "example": "MISSING_TEXT" },
          "message": { "type": "string", "description": "Human-readable error message", "example": "Text is required" }
        }
      }
    }
  },
  "tags": [
    { "name": "System", "description": "Health and status endpoints" },
    { "name": "Voices", "description": "Available TTS voices" },
    { "name": "Scripts", "description": "Script parsing and analysis" },
    { "name": "TTS", "description": "Text-to-speech audio generation" },
    { "name": "Rehearsal", "description": "Rehearsal playback planning" }
  ]
}
