{"openapi":"3.1.0","info":{"title":"Trebek API","description":"FastAPI migration of the Trebek / TriviaMatic NestJS backend. Provides auth, file-upload, and games endpoints backed by a direct PostgreSQL connection.","version":"1.0.0"},"paths":{"/do-action":{"post":{"tags":["Do Action"],"summary":"Handle Do Action","operationId":"handle_do_action_do_action_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericDoActionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/do-app-action":{"post":{"tags":["Do App Action"],"summary":"Handle Do App Login Action","operationId":"handle_do_app_login_action_do_app_action_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenericDoActionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/trivia-login":{"post":{"tags":["Auth"],"summary":"Trivia Login","description":"Authenticate against the caller's external TriviaMatic session token\n(not a username/password login) and return a Trebek-issued JWT,\nprovisioning a local trivia_users row on first login.","operationId":"trivia_login_auth_trivia_login_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TriviaLoginResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/forgot-password":{"post":{"tags":["Auth"],"summary":"Forgot Password","description":"Send a 4-digit reset code to the user's email.","operationId":"forgot_password_auth_forgot_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/forgot-password-get-by-key":{"post":{"tags":["Auth"],"summary":"Forgot Password Get By Key","description":"Validate the 4-digit reset code and return a signed reset token.","operationId":"forgot_password_get_by_key_auth_forgot_password_get_by_key_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordGetByKeyRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/forgot-password-change":{"post":{"tags":["Auth"],"summary":"Forgot Password Change","description":"Verify the reset token and update the user's password.","operationId":"forgot_password_change_auth_forgot_password_change_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordChangeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoolResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/change-password":{"post":{"tags":["Auth"],"summary":"Change Password","description":"Change password for the currently authenticated user.","operationId":"change_password_auth_change_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoolResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/auth/check-password":{"post":{"tags":["Auth"],"summary":"Check Password","description":"Verify the current user's password without issuing a token.","operationId":"check_password_auth_check_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoolResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/auth/create-user-by-type":{"post":{"tags":["Auth"],"summary":"Create User By Type","description":"Create a new staff user (Compiler / Factchecker / Writer). Manager-only.","operationId":"create_user_by_type_auth_create_user_by_type_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUserByTypeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoolResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/auth/user-types":{"get":{"tags":["Auth"],"summary":"User Types","description":"Return all available user types.","operationId":"user_types_auth_user_types_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/UserTypeItem"},"type":"array","title":"Response User Types Auth User Types Get"}}}}}}},"/files/uploadfiletofolder":{"post":{"tags":["Files"],"summary":"Upload File To Folder","description":"Upload an image to S3 under a folder derived from image_id.","operationId":"upload_file_to_folder_files_uploadfiletofolder_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_to_folder_files_uploadfiletofolder_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileUploadResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/games/game-by-date":{"get":{"tags":["Games"],"summary":"Game By Date","description":"Look up a trivia game for a given date, preferring the requested game\nformat and falling back to any game scheduled that date.","operationId":"game_by_date_games_game_by_date_get","parameters":[{"name":"date","in":"query","required":true,"schema":{"type":"string","description":"Event date, e.g. 2024-01-01","title":"Date"},"description":"Event date, e.g. 2024-01-01"},{"name":"gameFormat","in":"query","required":true,"schema":{"type":"integer","description":"Numeric game format key (see GAME_FORMATS)","title":"Gameformat"},"description":"Numeric game format key (see GAME_FORMATS)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/games/replace-reported-question":{"post":{"tags":["Games"],"summary":"Replace Reported Question","description":"Replace a reported/flagged question in a round with a new question.","operationId":"replace_reported_question_games_replace_reported_question_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceReportedQuestionRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplaceReportedQuestionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/games/get-question_logs":{"get":{"tags":["Games"],"summary":"Get Question Logs","description":"Return edit-log and round-question-log entries for a question, mirroring\ntrebek-nestjs (dev) GamesService.getQuestionLogs(): edit history joined\nwith editor/rejector/writer names, plus per-round usage log entries\n(backfilled with game info when a log entry has no game_id of its own).","operationId":"get_question_logs_games_get_question_logs_get","parameters":[{"name":"questionId","in":"query","required":true,"schema":{"type":"string","description":"Question UUID to fetch logs for","title":"Questionid"},"description":"Question UUID to fetch logs for"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/games/round-question-log-game-add":{"post":{"tags":["Games"],"summary":"Round Question Log Game Add","description":"Attach a game_id to one or more round_questions_log entries by round_id.","operationId":"round_question_log_game_add_games_round_question_log_game_add_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoundQuestionLogGameAddRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoundQuestionLogGameAddResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"Body_upload_file_to_folder_files_uploadfiletofolder_post":{"properties":{"image":{"type":"string","contentMediaType":"application/octet-stream","title":"Image"},"image_id":{"type":"string","title":"Image Id"},"image_type":{"type":"string","title":"Image Type"}},"type":"object","required":["image","image_id","image_type"],"title":"Body_upload_file_to_folder_files_uploadfiletofolder_post"},"BoolResponse":{"properties":{"response":{"type":"boolean","title":"Response"}},"type":"object","required":["response"],"title":"BoolResponse"},"ChangePasswordRequest":{"properties":{"password":{"type":"string","title":"Password"},"newPassword":{"type":"string","title":"Newpassword"}},"type":"object","required":["password","newPassword"],"title":"ChangePasswordRequest"},"CheckPasswordRequest":{"properties":{"password":{"type":"string","title":"Password"}},"type":"object","required":["password"],"title":"CheckPasswordRequest"},"CreateUserByTypeRequest":{"properties":{"email":{"type":"string","title":"Email"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"firstName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Firstname"},"lastName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lastname"},"user_type_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"User Type Id"}},"type":"object","required":["email"],"title":"CreateUserByTypeRequest"},"FileUploadResponse":{"properties":{"message":{"type":"string","title":"Message"},"media_url":{"type":"string","title":"Media Url"}},"type":"object","required":["message","media_url"],"title":"FileUploadResponse"},"ForgotPasswordChangeRequest":{"properties":{"token":{"type":"string","title":"Token"},"password":{"type":"string","title":"Password"}},"type":"object","required":["token","password"],"title":"ForgotPasswordChangeRequest"},"ForgotPasswordGetByKeyRequest":{"properties":{"userKey":{"type":"integer","title":"Userkey"}},"type":"object","required":["userKey"],"title":"ForgotPasswordGetByKeyRequest"},"ForgotPasswordRequest":{"properties":{"email":{"type":"string","title":"Email"},"userTypeId":{"type":"integer","title":"Usertypeid"}},"type":"object","required":["email","userTypeId"],"title":"ForgotPasswordRequest"},"GenericDoActionRequest":{"properties":{"do_action":{"type":"string","title":"Do Action"},"data":{"additionalProperties":true,"type":"object","title":"Data"}},"type":"object","required":["do_action"],"title":"GenericDoActionRequest","description":"Generic passthrough, since `data` can hold very different shapes\ndepending on `do_action`."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"MessageResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"MessageResponse"},"ReplaceReportedQuestionRequest":{"properties":{"round_id":{"type":"string","title":"Round Id"},"old_question_id":{"type":"string","title":"Old Question Id"},"new_question_id":{"type":"string","title":"New Question Id"}},"type":"object","required":["round_id","old_question_id","new_question_id"],"title":"ReplaceReportedQuestionRequest"},"ReplaceReportedQuestionResponse":{"properties":{"response":{"type":"boolean","title":"Response"},"updated_rows":{"type":"integer","title":"Updated Rows"}},"type":"object","required":["response","updated_rows"],"title":"ReplaceReportedQuestionResponse"},"RoundQuestionLogGameAddItem":{"properties":{"game_id":{"type":"string","title":"Game Id"},"round_id":{"type":"string","title":"Round Id"},"round_order":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Round Order"}},"type":"object","required":["game_id","round_id"],"title":"RoundQuestionLogGameAddItem"},"RoundQuestionLogGameAddRequest":{"properties":{"data":{"items":{"$ref":"#/components/schemas/RoundQuestionLogGameAddItem"},"type":"array","title":"Data"}},"type":"object","required":["data"],"title":"RoundQuestionLogGameAddRequest"},"RoundQuestionLogGameAddResponse":{"properties":{"response":{"type":"boolean","title":"Response"}},"type":"object","required":["response"],"title":"RoundQuestionLogGameAddResponse"},"TokenResponse":{"properties":{"token":{"type":"string","title":"Token"}},"type":"object","required":["token"],"title":"TokenResponse"},"TriviaLoginResponse":{"properties":{"user_id":{"type":"string","title":"User Id"},"username":{"type":"string","title":"Username"},"email":{"type":"string","title":"Email"},"user_role":{"type":"string","title":"User Role"},"token":{"type":"string","title":"Token"}},"type":"object","required":["user_id","username","email","user_role","token"],"title":"TriviaLoginResponse"},"UserTypeItem":{"properties":{"user_type_id":{"type":"integer","title":"User Type Id"},"user_type_name":{"type":"string","title":"User Type Name"}},"type":"object","required":["user_type_id","user_type_name"],"title":"UserTypeItem"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}