{"openapi":"3.1.0","info":{"title":"ox_speak_server","description":"","license":{"name":""},"version":"0.1.0"},"paths":{"/api/auth/claim-admin":{"post":{"tags":["auth"],"operationId":"claim_admin","responses":{"200":{"description":"Admin created successfully"},"400":{"description":"Bad request (token mismatch or user already exists)"},"500":{"description":"Internal server error"}}}},"/api/auth/login":{"post":{"tags":["auth"],"operationId":"login","responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"401":{"description":"Unauthorized"}}}},"/api/auth/ssh-challenge":{"post":{"tags":["auth"],"operationId":"ssh_challenge","responses":{"200":{"description":"SSH Challenge generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SshChallengeResponse"}}}},"404":{"description":"User not found"}}}},"/api/category":{"get":{"tags":["category"],"operationId":"category_list","parameters":[{"name":"server_id","in":"query","description":"Filter by server ID","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"List of categories","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CategoryResponse"}}}}}}},"post":{"tags":["category"],"operationId":"category_create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCategoryRequest"}}},"required":true},"responses":{"200":{"description":"Category created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponse"}}}},"403":{"description":"Forbidden"}}}},"/api/category/{id}":{"get":{"tags":["category"],"operationId":"category_detail","parameters":[{"name":"id","in":"path","description":"Category ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Category details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponse"}}}},"404":{"description":"Category not found"}}},"put":{"tags":["category"],"operationId":"category_update","parameters":[{"name":"id","in":"path","description":"Category ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCategoryRequest"}}},"required":true},"responses":{"200":{"description":"Category updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Category not found"}}},"delete":{"tags":["category"],"operationId":"category_delete","parameters":[{"name":"id","in":"path","description":"Category ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Category deleted"},"403":{"description":"Forbidden"},"404":{"description":"Category not found"}}}},"/api/channel":{"get":{"tags":["channel"],"operationId":"channel_list","responses":{"200":{"description":"List of all channels","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ChannelResponse"}}}}}}},"post":{"tags":["channel"],"operationId":"channel_create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChannelRequest"}}},"required":true},"responses":{"200":{"description":"Channel created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelResponse"}}}},"403":{"description":"Forbidden"}}}},"/api/channel/{id}":{"get":{"tags":["channel"],"operationId":"channel_detail","parameters":[{"name":"id","in":"path","description":"Channel ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Channel details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelResponse"}}}},"404":{"description":"Channel not found"}}},"put":{"tags":["channel"],"operationId":"channel_update","parameters":[{"name":"id","in":"path","description":"Channel ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateChannelRequest"}}},"required":true},"responses":{"200":{"description":"Channel updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChannelResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Channel not found"}}},"delete":{"tags":["channel"],"operationId":"channel_delete","parameters":[{"name":"id","in":"path","description":"Channel ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Channel deleted"},"403":{"description":"Forbidden"},"404":{"description":"Channel not found"}}}},"/api/message":{"get":{"tags":["message"],"operationId":"message_list","responses":{"200":{"description":"List of all messages","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MessageResponse"}}}}}}},"post":{"tags":["message"],"operationId":"message_create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMessageRequest"}}},"required":true},"responses":{"200":{"description":"Message created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Channel not found"}},"security":[{"jwt":[]}]}},"/api/message/{id}":{"get":{"tags":["message"],"operationId":"message_detail","parameters":[{"name":"id","in":"path","description":"Message ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Message details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"404":{"description":"Message not found"}}},"put":{"tags":["message"],"operationId":"message_update","parameters":[{"name":"id","in":"path","description":"Message ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMessageRequest"}}},"required":true},"responses":{"200":{"description":"Message updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Message not found"}}},"delete":{"tags":["message"],"operationId":"message_delete","parameters":[{"name":"id","in":"path","description":"Message ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Message deleted"},"403":{"description":"Forbidden"},"404":{"description":"Message not found"}}}},"/api/server":{"get":{"tags":["server"],"operationId":"server_list","responses":{"200":{"description":"List of all servers","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ServerResponse"}}}}}}},"post":{"tags":["server"],"operationId":"server_create","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServerRequest"}}},"required":true},"responses":{"200":{"description":"Server created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerResponse"}}}},"403":{"description":"Forbidden"}}}},"/api/server/{id}":{"get":{"tags":["server"],"operationId":"server_detail","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Server details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerResponse"}}}},"404":{"description":"Server not found"}}},"put":{"tags":["server"],"operationId":"server_update","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateServerRequest"}}},"required":true},"responses":{"200":{"description":"Server updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerResponse"}}}},"403":{"description":"Forbidden"},"404":{"description":"Server not found"}}},"delete":{"tags":["server"],"operationId":"server_delete","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"Server deleted"},"403":{"description":"Forbidden"},"404":{"description":"Server not found"}}}},"/api/server/{id}/password":{"get":{"tags":["server"],"operationId":"server_password","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Server password (hashed or plain depending on implementation)","content":{"application/json":{"schema":{"type":["string","null"]}}}},"404":{"description":"Server not found"}}}},"/api/server/{id}/tree":{"get":{"tags":["server"],"operationId":"tree","parameters":[{"name":"id","in":"path","description":"Server ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Server tree structure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerTreeResponse"}}}},"404":{"description":"Server not found"}}}},"/api/user":{"get":{"tags":["user"],"operationId":"user_list","responses":{"200":{"description":"List of all users","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserResponse"}}}}},"403":{"description":"Forbidden"}}}},"/api/user/me":{"get":{"tags":["user"],"operationId":"get_me","responses":{"200":{"description":"Current user information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"401":{"description":"Unauthorized"}},"security":[{"jwt":[]}]}},"/api/user/{id}":{"get":{"tags":["user"],"operationId":"user_detail","parameters":[{"name":"id","in":"path","description":"User ID","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"User details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"404":{"description":"User not found"}}}},"/handler/ws/":{"get":{"tags":["ws_handler"],"summary":"WebSocket documentation placeholder.","description":"This is not a real HTTP endpoint, but it documents the WebSocket behavior.\n\n**Connection:** `GET /handler/ws/`\n\n**Protocol:** JSON messages over WebSocket.\n\n### Client -> Server\n- `SendMessage`: Send a JSON object matching `CreateMessageRequest`.\n\n### Server -> Client\n- `MessageReceived`: Receive a JSON object matching `MessageResponse`.","operationId":"ws_doc","responses":{"101":{"description":"Switching Protocols to WebSocket"},"401":{"description":"Unauthorized (Invalid JWT)"}},"security":[{"jwt":[]}]}}},"components":{"schemas":{"CategoryQuery":{"type":"object","properties":{"server_id":{"type":["string","null"],"format":"uuid"}}},"CategoryResponse":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"ChannelResponse":{"type":"object","required":["id","position","channel_type"],"properties":{"category_id":{"type":["string","null"],"format":"uuid"},"channel_type":{"$ref":"#/components/schemas/ChannelType"},"id":{"type":"string","format":"uuid"},"name":{"type":["string","null"]},"position":{"type":"integer","format":"int32"},"server_id":{"type":["string","null"],"format":"uuid"}}},"ChannelType":{"type":"string","enum":["text","voice","d_m"]},"ClaimAdminRequest":{"type":"object","required":["token","username","password"],"properties":{"password":{"type":"string"},"token":{"type":"string"},"username":{"type":"string"}}},"CreateCategoryRequest":{"type":"object","required":["server_id","name"],"properties":{"name":{"type":"string"},"server_id":{"type":"string","format":"uuid"}}},"CreateChannelRequest":{"type":"object","required":["channel_type"],"properties":{"category_id":{"type":["string","null"],"format":"uuid"},"channel_type":{"$ref":"#/components/schemas/ChannelType"},"name":{"type":["string","null"]},"position":{"type":["integer","null"],"format":"int32"},"server_id":{"type":["string","null"],"format":"uuid"}}},"CreateMessageRequest":{"type":"object","required":["channel_id","content"],"properties":{"channel_id":{"type":"string","format":"uuid"},"content":{"type":"string"}}},"CreateServerRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"password":{"type":["string","null"]}}},"CreateUserRequest":{"type":"object","required":["username"],"properties":{"username":{"type":"string"}}},"ListCategoryQuery":{"type":"object","required":["server_id"],"properties":{"server_id":{"type":"string","format":"uuid"}}},"LoginRequest":{"type":"object","required":["username","password"],"properties":{"password":{"type":"string"},"username":{"type":"string"}}},"LoginResponse":{"type":"object","required":["token","username"],"properties":{"token":{"type":"string"},"username":{"type":"string"}}},"MessageResponse":{"type":"object","required":["id","channel_id","author_id","content"],"properties":{"author_id":{"type":"string","format":"uuid"},"channel_id":{"type":"string","format":"uuid"},"content":{"type":"string"},"id":{"type":"string","format":"uuid"}}},"ServerResponse":{"type":"object","required":["id","name","created_at","updated_at"],"properties":{"created_at":{"type":"string"},"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"updated_at":{"type":"string"}}},"ServerTreeResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/TreeItemType"}}}},"SshChallengeRequest":{"type":"object","required":["username"],"properties":{"username":{"type":"string"}}},"SshChallengeResponse":{"type":"object","required":["challenge"],"properties":{"challenge":{"type":"string"}}},"TreeItemType":{"oneOf":[{"allOf":[{"$ref":"#/components/schemas/CategoryResponse"},{"type":"object","required":["channels"],"properties":{"channels":{"type":"array","items":{"$ref":"#/components/schemas/ChannelResponse"}}}},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["category"]}}}]},{"allOf":[{"$ref":"#/components/schemas/ChannelResponse"},{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["channel"]}}}]}]},"UserResponse":{"type":"object","required":["id","username","pub_key"],"properties":{"id":{"type":"string","format":"uuid"},"pub_key":{"type":"string"},"username":{"type":"string"}}}},"securitySchemes":{"jwt":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}},"tags":[{"name":"ox-speak","description":"Ox Speak API"}]}