openapi: 3.1.0 info: title: SEL Chat Coach API description: | Social-Emotional Learning Chat Coach API for teachers to practice conversations with simulated ADHD student agents and consult coaching agents. All endpoints require Basic Auth unless otherwise specified. version: 1.0.0 contact: name: API Support servers: - url: http://localhost:3000 description: Local development server - url: https://sel-chat-coach.example.com description: Production server (update with actual URL) security: - basicAuth: [] tags: - name: Health description: Service health check - name: Auth description: User authentication and registration - name: Conversations description: Conversation management - name: Messages description: Conversation messages - name: System Messages description: System-level contextual messages - name: Coach description: Coach interactions - name: Stats description: Statistics and analytics paths: /api/health: get: tags: [Health] summary: Health check description: Check if the API is running security: [] responses: '200': description: Service is healthy content: application/json: schema: type: object properties: status: type: string example: healthy timestamp: type: string format: date-time /api/auth/register: post: tags: [Auth] summary: Register a new user description: Create a new user account with username. Use BASIC_AUTH_PASSWORD to authenticate subsequent requests. security: [] requestBody: required: true content: application/json: schema: type: object required: [username, email, name] properties: username: type: string example: teacher_wang email: type: string format: email example: wang@example.com name: type: string example: 王老師 responses: '200': description: User created successfully content: application/json: schema: type: object properties: user: type: object properties: id: type: string format: uuid username: type: string message: type: string example: "User registered successfully. Use password 'cz-2025' to login." '400': $ref: '#/components/responses/BadRequest' /api/conversations: get: tags: [Conversations] summary: List all conversations description: Get all conversations for the authenticated user responses: '200': description: List of conversations content: application/json: schema: type: object properties: conversations: type: array items: $ref: '#/components/schemas/Conversation' '401': $ref: '#/components/responses/Unauthorized' /api/conversations/create: post: tags: [Conversations] summary: Create a new conversation description: Create a new conversation with a student personality and coach pairing requestBody: required: true content: application/json: schema: type: object required: [studentPromptId, coachPromptId] properties: studentPromptId: type: string enum: [grade_1, grade_2, grade_3, grade_4, grade_5, grade_6, grade_7, grade_8, grade_9, coach_direct] description: Student grade level or 'coach_direct' for direct coach chat example: grade_3 coachPromptId: type: string enum: [empathetic, structured, balanced] example: empathetic title: type: string example: 數學課專注力問題 include3ConversationSummary: type: boolean description: Include summary of last 3 conversations with this student responses: '200': description: Conversation created content: application/json: schema: type: object properties: conversation: $ref: '#/components/schemas/Conversation' message: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' /api/conversations/{conversationId}: get: tags: [Conversations] summary: Get conversation details parameters: - $ref: '#/components/parameters/ConversationId' responses: '200': description: Conversation details content: application/json: schema: $ref: '#/components/schemas/Conversation' '404': $ref: '#/components/responses/NotFound' put: tags: [Conversations] summary: Update conversation description: Update conversation title parameters: - $ref: '#/components/parameters/ConversationId' requestBody: required: true content: application/json: schema: type: object properties: title: type: string example: 更新的對話標題 responses: '200': description: Conversation updated content: application/json: schema: $ref: '#/components/schemas/Conversation' '404': $ref: '#/components/responses/NotFound' delete: tags: [Conversations] summary: Delete conversation parameters: - $ref: '#/components/parameters/ConversationId' responses: '200': description: Conversation deleted content: application/json: schema: type: object properties: message: type: string deletedCount: type: number '404': $ref: '#/components/responses/NotFound' /api/conversations/{conversationId}/messages: get: tags: [Messages] summary: Get conversation messages description: Retrieve all messages for a conversation parameters: - $ref: '#/components/parameters/ConversationId' responses: '200': description: List of messages content: application/json: schema: type: object properties: messages: type: array items: $ref: '#/components/schemas/Message' total: type: number '404': $ref: '#/components/responses/NotFound' /api/conversations/{conversationId}/message: post: tags: [Messages] summary: Send a message description: | Send a message in the conversation. Returns a streaming response. Uses Vercel AI SDK message format. parameters: - $ref: '#/components/parameters/ConversationId' requestBody: required: true content: application/json: schema: type: object required: [messages] properties: messages: type: array description: Array of messages in AI SDK format items: type: object properties: id: type: string role: type: string enum: [user, assistant, system] content: type: string parts: type: array items: type: object properties: type: type: string example: text text: type: string metadata: type: object properties: speaker: type: string enum: [student, coach] description: Who is being addressed (student) or who is responding (coach) quotedText: type: string quotedMessageId: type: string example: messages: - id: msg-1 role: user content: 你好,我有數學問題 parts: - type: text text: 你好,我有數學問題 metadata: speaker: student responses: '200': description: Streaming response with AI-generated message content: text/event-stream: schema: type: string '404': $ref: '#/components/responses/NotFound' /api/conversations/{conversationId}/system-messages: post: tags: [System Messages] summary: Create system message description: | Add a system message to the conversation for context. Use cases: student background info, medication status, session notes, milestones. parameters: - $ref: '#/components/parameters/ConversationId' requestBody: required: true content: application/json: schema: type: object required: [content] properties: content: type: string example: 學生剛吃了ADHD藥物(30分鐘前) responses: '200': description: System message created content: application/json: schema: type: object properties: message: $ref: '#/components/schemas/Message' success: type: boolean '400': $ref: '#/components/responses/BadRequest' '404': $ref: '#/components/responses/NotFound' /api/conversations/{conversationId}/system-messages/{messageId}: put: tags: [System Messages] summary: Update system message description: Update the content of an existing system message parameters: - $ref: '#/components/parameters/ConversationId' - $ref: '#/components/parameters/MessageId' requestBody: required: true content: application/json: schema: type: object required: [content] properties: content: type: string example: 學生剛吃了ADHD藥物(1小時前) responses: '200': description: System message updated content: application/json: schema: type: object properties: message: $ref: '#/components/schemas/Message' success: type: boolean '400': description: Bad request (e.g., trying to update non-system message) '404': $ref: '#/components/responses/NotFound' delete: tags: [System Messages] summary: Delete system message parameters: - $ref: '#/components/parameters/ConversationId' - $ref: '#/components/parameters/MessageId' responses: '200': description: System message deleted content: application/json: schema: type: object properties: success: type: boolean message: type: string '400': description: Bad request (e.g., trying to delete non-system message) '404': $ref: '#/components/responses/NotFound' /api/coach/types: get: tags: [Coach] summary: List available coaches description: Get list of available coach personalities responses: '200': description: List of coaches content: application/json: schema: type: object properties: coaches: type: array items: type: object properties: id: type: string example: empathetic name: type: string example: 王老師 description: type: string /api/stats: get: tags: [Stats] summary: Get user statistics description: Get conversation and message statistics for the authenticated user responses: '200': description: User statistics content: application/json: schema: type: object properties: totalConversations: type: number totalMessages: type: number conversationsByStudent: type: object components: securitySchemes: basicAuth: type: http scheme: basic description: Use username and the password from BASIC_AUTH_PASSWORD env var (default 'cz-2025') parameters: ConversationId: name: conversationId in: path required: true schema: type: string format: uuid description: Conversation ID MessageId: name: messageId in: path required: true schema: type: string format: uuid description: Message ID schemas: Conversation: type: object properties: id: type: string format: uuid userId: type: string format: uuid studentPromptId: type: string example: grade_3 studentName: type: string example: 小三學生 description: "Derived from student prompt template (not stored in database). Generated from student-prompts.ts based on studentPromptId." coachPromptId: type: string enum: [empathetic, structured, balanced] coachName: type: string example: 王老師 description: "Derived from coach prompt template (not stored in database). Generated from coach-prompts.ts based on coachPromptId." title: type: string titleSource: type: string enum: [auto, auto-locked, user] summary: type: string systemPrompt: type: string sourceConversationId: type: string format: uuid description: "ID of conversation this was branched from (null if not a branch)" branchedFromMessageId: type: string format: uuid description: "ID of message where this branch was created (null if not a branch)" createdAt: type: string format: date-time updatedAt: type: string format: date-time lastActiveAt: type: string format: date-time Message: type: object properties: id: type: string format: uuid conversationId: type: string format: uuid role: type: string enum: [user, assistant, system] speaker: type: string enum: [student, coach] description: Who is speaking in this message content: type: string responseId: type: string description: OpenAI Responses API response ID timestamp: type: string format: date-time quotedText: type: string description: Selected text being replied to quotedMessageId: type: string description: ID of message being replied to responses: BadRequest: description: Bad request content: application/json: schema: type: object properties: error: type: string example: Invalid input Unauthorized: description: Unauthorized content: application/json: schema: type: object properties: error: type: string example: Unauthorized NotFound: description: Resource not found content: application/json: schema: type: object properties: error: type: string example: Conversation not found