openapi: 3.0.3 info: title: StoryTeller API version: 1.0.0 description: OpenAPI-first API for StoryTeller. servers: - url: /api tags: - name: Auth - name: Users - name: Scenarios - name: Stories - name: Settings paths: /auth/login: post: tags: [Auth] operationId: login requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/LoginRequest' responses: '200': description: Login successful. content: application/json: schema: $ref: '#/components/schemas/LoginResponse' /users: get: tags: [Users] operationId: listUsers responses: '200': description: List users. content: application/json: schema: type: array items: $ref: '#/components/schemas/User' post: tags: [Users] operationId: createUser requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateUserRequest' responses: '201': description: User created. content: application/json: schema: $ref: '#/components/schemas/User' /users/{userId}: put: tags: [Users] operationId: updateUser parameters: - $ref: '#/components/parameters/UserId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateUserRequest' responses: '200': description: User updated. content: application/json: schema: $ref: '#/components/schemas/User' delete: tags: [Users] operationId: deleteUser parameters: - $ref: '#/components/parameters/UserId' responses: '204': description: User deleted. /scenarios: get: tags: [Scenarios] operationId: listScenarios responses: '200': description: List scenarios for the authenticated user. content: application/json: schema: type: array items: $ref: '#/components/schemas/Scenario' post: tags: [Scenarios] operationId: createScenario requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateScenarioRequest' responses: '201': description: Scenario created. content: application/json: schema: $ref: '#/components/schemas/Scenario' /scenarios/{scenarioId}: get: tags: [Scenarios] operationId: getScenario parameters: - $ref: '#/components/parameters/ScenarioId' responses: '200': description: Get scenario. content: application/json: schema: $ref: '#/components/schemas/Scenario' put: tags: [Scenarios] operationId: updateScenario parameters: - $ref: '#/components/parameters/ScenarioId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateScenarioRequest' responses: '200': description: Scenario updated. content: application/json: schema: $ref: '#/components/schemas/Scenario' delete: tags: [Scenarios] operationId: deleteScenario parameters: - $ref: '#/components/parameters/ScenarioId' responses: '204': description: Scenario deleted. /settings: get: tags: [Settings] operationId: getSettings responses: '200': description: Current settings and available Ollama models. content: application/json: schema: $ref: '#/components/schemas/Settings' put: tags: [Settings] operationId: updateSettings requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateSettingsRequest' responses: '200': description: Settings updated; returns current merged settings. content: application/json: schema: $ref: '#/components/schemas/Settings' /stories: get: tags: [Stories] operationId: listStories responses: '200': description: List stories for the authenticated user. content: application/json: schema: type: array items: $ref: '#/components/schemas/Story' post: tags: [Stories] operationId: startStory requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/StartStoryRequest' responses: '201': description: Story created. content: application/json: schema: $ref: '#/components/schemas/Story' /stories/{storyId}: get: tags: [Stories] operationId: getStory parameters: - $ref: '#/components/parameters/StoryId' responses: '200': description: Get story. content: application/json: schema: $ref: '#/components/schemas/Story' put: tags: [Stories] operationId: updateStory parameters: - $ref: '#/components/parameters/StoryId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateStoryRequest' responses: '200': description: Story updated. content: application/json: schema: $ref: '#/components/schemas/Story' delete: tags: [Stories] operationId: deleteStory parameters: - $ref: '#/components/parameters/StoryId' responses: '204': description: Story deleted. /stories/{storyId}/steps: get: tags: [Stories] operationId: listStorySteps parameters: - $ref: '#/components/parameters/StoryId' responses: '200': description: List story steps. content: application/json: schema: type: array items: $ref: '#/components/schemas/StoryStep' /stories/{storyId}/steps/{stepId}: put: tags: [Stories] operationId: updateStoryStep parameters: - $ref: '#/components/parameters/StoryId' - $ref: '#/components/parameters/StepId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateStepRequest' responses: '200': description: Step updated. content: application/json: schema: $ref: '#/components/schemas/StoryStep' /stories/{storyId}/generate-step: post: tags: [Stories] operationId: generateStoryStep parameters: - $ref: '#/components/parameters/StoryId' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/GenerateStepRequest' responses: '200': description: Next step generated. content: application/json: schema: $ref: '#/components/schemas/GenerateStepResponse' components: parameters: UserId: in: path name: userId required: true schema: type: integer format: int64 ScenarioId: in: path name: scenarioId required: true schema: type: integer format: int64 StoryId: in: path name: storyId required: true schema: type: integer format: int64 StepId: in: path name: stepId required: true schema: type: integer format: int64 schemas: LoginRequest: type: object required: [username, password] properties: username: type: string password: type: string LoginResponse: type: object required: [token, userId, username, isAdmin] properties: token: type: string userId: type: integer format: int64 username: type: string isAdmin: type: boolean User: type: object required: [id, username, isAdmin, active] properties: id: type: integer format: int64 username: type: string isAdmin: type: boolean active: type: boolean CreateUserRequest: type: object required: [username, password, isAdmin] properties: username: type: string password: type: string isAdmin: type: boolean UpdateUserRequest: type: object properties: username: type: string password: type: string isAdmin: type: boolean active: type: boolean CharacterDto: type: object required: [name, role, description] properties: name: type: string role: type: string description: type: string Scenario: type: object required: [id, title, startingSceneDescription, startingCharacters] properties: id: type: integer format: int64 title: type: string description: type: string startingSceneDescription: type: string startingCharacters: type: array items: $ref: '#/components/schemas/CharacterDto' CreateScenarioRequest: type: object required: [title, startingSceneDescription, startingCharacters] properties: title: type: string description: type: string startingSceneDescription: type: string startingCharacters: type: array items: $ref: '#/components/schemas/CharacterDto' UpdateScenarioRequest: type: object properties: title: type: string description: type: string startingSceneDescription: type: string startingCharacters: type: array items: $ref: '#/components/schemas/CharacterDto' Story: type: object required: [id, title, scenarioId, currentSceneDescription, currentSceneCharacters, status] properties: id: type: integer format: int64 title: type: string scenarioId: type: integer format: int64 currentSceneDescription: type: string currentSceneCharacters: type: array items: $ref: '#/components/schemas/CharacterDto' status: type: string enum: [ACTIVE, ARCHIVED, DELETED] StartStoryRequest: type: object required: [scenarioId] properties: scenarioId: type: integer format: int64 title: type: string description: Optional override; defaults to the scenario title. UpdateStoryRequest: type: object properties: title: type: string currentSceneDescription: type: string currentSceneCharacters: type: array items: $ref: '#/components/schemas/CharacterDto' StoryStep: type: object required: [id, stepNumber, content, addedToScene] properties: id: type: integer format: int64 stepNumber: type: integer content: type: string userDirection: type: string addedToScene: type: boolean UpdateStepRequest: type: object properties: content: type: string GenerateStepRequest: type: object required: [direction] properties: direction: type: string currentSceneDescription: type: string currentCharacters: type: array items: $ref: '#/components/schemas/CharacterDto' GenerateStepResponse: type: object required: [step, compacted] properties: step: $ref: '#/components/schemas/StoryStep' compacted: type: boolean description: True if context compaction was performed before generation. updatedScene: type: string description: New scene description after compaction, if compacted is true. updatedCharacters: type: array items: $ref: '#/components/schemas/CharacterDto' description: Updated characters after compaction, if compacted is true. Settings: type: object required: [ollamaBaseUrl, ollamaModel, contextCharLimit, availableModels] properties: ollamaBaseUrl: type: string description: Ollama server base URL. ollamaModel: type: string description: Selected model name for story generation. contextCharLimit: type: integer description: Context character limit before compaction. availableModels: type: array items: $ref: '#/components/schemas/OllamaModelInfo' description: Models returned by Ollama /api/tags (empty if unreachable). OllamaModelInfo: type: object required: [name] properties: name: type: string UpdateSettingsRequest: type: object properties: ollamaBaseUrl: type: string ollamaModel: type: string contextCharLimit: type: integer