{"openapi":"3.1.1","info":{"title":"Choreo Planer","description":"This is the official Choreo Planer API documentation. Use this documentation as reference to integrate with the Choreo Planer backend.","license":{"name":"MIT","url":"https://mit-license.org/"},"contact":{"name":"Administrator","email":"admin@choreo-planer.de"},"version":"1.0.0"},"externalDocs":{"description":"Backend Code Documentation","url":"https://api.choreo-planer.de/docs/"},"servers":[{"url":"http://localhost:3000","description":"Development Server"},{"url":"https://api.choreo-planer.de","description":"Production Server"}],"paths":{"/user/":{"put":{"description":"Update the current user's information","tags":["Users"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"responses":{"200":{"description":"User updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"delete":{"description":"Delete the current user's account","tags":["Users"],"security":[{"userAuthentication":[]}],"responses":{"200":{"description":"User deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/user/revokeEmail/{id}":{"get":{"description":"Revoke a user's email address (renders a status page)","tags":["Users"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email revoked (renders a page)"}}}},"/user/confirmEmail/{id}":{"get":{"description":"Confirm a user's email address (renders a status page)","tags":["Users"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Email confirmed (renders a page)"}}}},"/user/access":{"get":{"description":"Get all users that the current user has access to (children)","tags":["User Access"],"security":[{"userAuthentication":[]}],"responses":{"200":{"description":"List of user access relationships","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/UserAccess"}}}}}}},"post":{"description":"Invite a user by email to share access","tags":["User Access"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"childEmail":{"type":"string"},"role":{"type":"string","enum":["coach","assistant","athlete"]}}}}}},"responses":{"200":{"description":"Invitation sent"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/user/access/owner":{"description":"Get all owners that have shared access with the current user","tags":["User Access"],"security":[{"userAuthentication":[]}],"responses":{"200":{"description":"List of owners","content":{"application/json":{"schema":{"type":"array"}}}}}},"/user/access/{id}":{"put":{"description":"Update a user access relationship","tags":["User Access"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string"},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated"}}},"delete":{"description":"Remove a user access relationship","tags":["User Access"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Removed"}}}},"/user/access/{id}/accept":{"post":{"description":"Accept an access invitation","tags":["User Access"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Accepted"}}}},"/user/access/{id}/decline":{"post":{"description":"Decline an access invitation","tags":["User Access"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Declined"},"404":{"description":"Access not found"}}}},"/team/{id}":{"get":{"description":"Get a specific team by ID, or all teams if no ID is provided. Optionally filter by name.","tags":["Teams"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Team(s) found","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/Team"},{"type":"array","items":{"$ref":"#/components/schemas/Team"}}]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Team not found"}}},"put":{"description":"Update a team by ID","tags":["Teams"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"responses":{"200":{"description":"Team updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Team not found"}}},"delete":{"description":"Delete a team by ID","tags":["Teams"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Team deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Team not found"}}}},"/team/":{"post":{"description":"Create a new team","tags":["Teams"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","clubId","seasonId"],"properties":{"name":{"type":"string"},"clubId":{"type":"string"},"seasonId":{"type":"string"},"ownerId":{"type":"string | null","description":"Owner ID. If null/undefined, falls back to actingUserId"}}}}}},"responses":{"200":{"description":"Team created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Team"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/seasonTeam/":{"post":{"description":"Create a new season-team association","tags":["SeasonTeams"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["teamId","seasonId"],"properties":{"teamId":{"type":"string"},"seasonId":{"type":"string"},"MemberIds":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"SeasonTeam created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeasonTeam"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/seasonTeam/{id}":{"put":{"description":"Copy members into a season team","tags":["SeasonTeams"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"MemberIds":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Members copied successfully","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Member"}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"delete":{"description":"Delete a season team by ID","tags":["SeasonTeams"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"SeasonTeam deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/season/":{"get":{"description":"Get all seasons for the current user","tags":["Seasons"],"security":[{"userAuthentication":[]}],"responses":{"200":{"description":"List of seasons","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Season"}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"post":{"description":"Create a new season","tags":["Seasons"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","year"],"properties":{"name":{"type":"string"},"year":{"type":"integer"},"ownerId":{"type":"string | null","description":"Owner ID. If null/undefined, falls back to actingUserId"}}}}}},"responses":{"200":{"description":"Season created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Season"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/position/":{"get":{"description":"Get all positions for a lineup (by lineupId query param)","tags":["Positions"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"lineupId","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of positions","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Position"}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/position/{id}":{"delete":{"description":"Delete a position by ID","tags":["Positions"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Position deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Position not found"}}}},"/notifications/":{"get":{"description":"Get all notifications for the current user","tags":["Notifications"],"security":[{"userAuthentication":[]}],"responses":{"200":{"description":"List of notifications","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/notifications/{id}/read":{"post":{"description":"Mark a notification as read","tags":["Notifications"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Notification marked as read"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/notifications/{id}/unread":{"post":{"description":"Mark a notification as unread","tags":["Notifications"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Notification marked as unread"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/notifications/{id}":{"delete":{"description":"Delete a notification by ID","tags":["Notifications"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Notification deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/member/":{"post":{"description":"Create a new member","tags":["Members"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","seasonTeamId"],"properties":{"name":{"type":"string"},"nickname":{"type":"string"},"abbreviation":{"type":"string"},"seasonTeamId":{"type":"string"}}}}}},"responses":{"200":{"description":"Member created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/member/{id}":{"put":{"description":"Update a member by ID","tags":["Members"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"responses":{"200":{"description":"Member updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Member not found"}}},"delete":{"description":"Delete a member by ID","tags":["Members"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Member deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Member not found"}}}},"/lineup/{id}/position/{positionId}":{"put":{"description":"Update a position in a lineup","tags":["Lineups"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"positionId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Position"}}}},"responses":{"200":{"description":"Position updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Position"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Position not found"}}}},"/lineup/{id}":{"delete":{"description":"Delete a lineup by ID","tags":["Lineups"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Lineup deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Lineup not found"}}}},"/hit/{id}":{"get":{"description":"Get a specific hit by ID, or all hits if no ID is provided","tags":["Hits"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hit(s) found","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/Hit"},{"type":"array","items":{"$ref":"#/components/schemas/Hit"}}]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Hit not found"}}},"put":{"description":"Update a hit by ID","tags":["Hits"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hit"}}}},"responses":{"200":{"description":"Hit updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hit"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Hit not found"}}},"delete":{"description":"Delete a hit by ID","tags":["Hits"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Hit deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Hit not found"}}}},"/hit/":{"post":{"description":"Create a new hit","tags":["Hits"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","count","choreoId"],"properties":{"name":{"type":"string"},"count":{"type":"integer"},"choreoId":{"type":"string"},"MemberIds":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Hit created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Hit"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/feedback/":{"post":{"description":"Submit feedback (optionally anonymous)","tags":["Feedback"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["stars","text"],"properties":{"stars":{"type":"integer","minimum":1,"maximum":5},"text":{"type":"string"}}}}}},"responses":{"200":{"description":"Feedback submitted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Feedback"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"get":{"description":"Get all feedback for the current user","tags":["Feedback"],"security":[{"userAuthentication":[]}],"responses":{"200":{"description":"List of feedback","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Feedback"}}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/contact/":{"post":{"description":"Send a new message to the support team","tags":["Contact"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","email","subject","message","category"],"properties":{"name":{"type":"string"},"email":{"type":"email"},"subject":{"type":"string"},"message":{"type":"string"},"category":{"type":"string"}}}}}},"responses":{"200":{"description":"Message Received","content":{"application/json":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequestError"}}}},"/club/{id}":{"get":{"description":"Get a specific club by ID, or all clubs if no ID is provided. Optionally filter by name.","tags":["Clubs"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":false,"schema":{"type":"string"}},{"name":"name","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Club(s) found","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/Club"},{"type":"array","items":{"$ref":"#/components/schemas/Club"}}]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Club not found"}}},"put":{"description":"Update a club by ID","tags":["Clubs"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Club"}}}},"responses":{"200":{"description":"Club updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Club"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Club not found"}}},"delete":{"description":"Delete a club by ID","tags":["Clubs"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Club deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Club not found"}}}},"/club/":{"post":{"description":"Create a new club","tags":["Clubs"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"ownerId":{"type":"string | null","description":"Owner ID. If null/undefined, falls back to actingUserId"}}}}}},"responses":{"200":{"description":"Club created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Club"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/club/{id}/clubLogo":{"put":{"description":"Upload a club logo for a club","tags":["Clubs"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"clubLogo":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Club logo uploaded successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Club"}}}},"400":{"description":"No file uploaded"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"get":{"description":"Get the club logo for a club","tags":["Clubs"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Club logo file"},"400":{"description":"No file uploaded"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"delete":{"description":"Delete the club logo for a club","tags":["Clubs"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Club logo deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/choreo/{id}":{"get":{"description":"Get a list of choreos or a specific choreo","tags":["Choreos"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Either a list of choreos if id was not defined or a specific choreo otherwise","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/Choreo"},{"type":"array","items":{"$ref":"#/components/schemas/Choreo"}}]}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Choreo was not found","content":{"application/json":{"schema":{"type":"string","example":"Not found"}}}}}},"put":{"description":"Update a choreo by ID","tags":["Choreos"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Choreo"}}}},"responses":{"200":{"description":"Choreo updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Choreo"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Choreo not found"}}},"delete":{"description":"Delete a choreo by ID","tags":["Choreos"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Choreo deleted successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"Choreo not found"}}}},"/choreo/":{"post":{"description":"Create a new choreo","tags":["Choreos"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","counts","matType","seasonTeamId"],"properties":{"name":{"type":"string"},"counts":{"type":"integer"},"matType":{"type":"string"},"seasonTeamId":{"type":"string"},"participants":{"type":"array","items":{"type":"string"}},"ownerId":{"type":"string | null","description":"Owner ID. If null/undefined, falls back to actingUserId"}}}}}},"responses":{"200":{"description":"Choreo created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Choreo"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/choreo/{id}/participants":{"post":{"description":"Add a participant to a choreo","tags":["Choreos"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["MemberId"],"properties":{"MemberId":{"type":"string"},"color":{"type":"string"}}}}}},"responses":{"200":{"description":"Participant added successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"patch":{"description":"Replace a participant in a choreo","tags":["Choreos"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["memberToRemoveId","memberToAddId"],"properties":{"memberToRemoveId":{"type":"string"},"memberToAddId":{"type":"string"}}}}}},"responses":{"200":{"description":"Participant replaced successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Choreo"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/choreo/{id}/participants/{participationId}":{"delete":{"description":"Remove a participant from a choreo","tags":["Choreos"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"participationId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Participant removed successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/choreo/{id}/participants/{participantId}":{"patch":{"description":"Change the color of a participant in a choreo","tags":["Choreos"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"participantId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["color"],"properties":{"color":{"type":"string"}}}}}},"responses":{"200":{"description":"Color changed successfully"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/auth/":{"post":{"description":"Registration endpoint","tags":["Authorization & Account Management"],"requestBody":{"$ref":"#/components/requestBodies/RegistrationRequestBody"},"responses":{"200":{"description":"User successfully registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JWT"}}}},"400":{"description":"User account could not be created","content":{"application/json":{"schema":{"type":"string","example":"User already exists"}}}}}}},"/auth/login":{"post":{"description":"Login endpoint","tags":["Authorization & Account Management"],"requestBody":{"$ref":"#/components/requestBodies/LoginRequestBody"},"responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JWT"}}}},"404":{"description":"User was not found"}}}},"/auth/ssoRequest":{"post":{"description":"Single Sign-On Request endpoint","tags":["Authorization & Account Management"],"requestBody":{"$ref":"#/components/requestBodies/ssoRequestRequestBody"},"responses":{"200":{"description":"SSO link was sent","content":{"application/json":{"schema":{"type":"string","example":"Single Sign-On link was sent to your email inbox."}}}},"400":{"description":"Email address not provided","content":{"application/json":{"schema":{"type":"string","example":"An email address is required."}}}}}}},"/auth/sso":{"post":{"description":"Single Sign-On Login endpoint","tags":["Authorization & Account Management"],"requestBody":{"$ref":"#/components/requestBodies/ssoRequestBody"},"responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JWT"}}}},"400":{"description":"User was not found","content":{"application/json":{"schema":{"type":"string","example":"A SSO token is required. Please contact admin@choreo-planer.de"}}}}}}},"/auth/me":{"get":{"description":"User information endpoint","tags":["Authorization & Account Management"],"security":[{"userAuthentication":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"put":{"description":"User update endpoint, sends confirmation email if email is updated","tags":["Authorization & Account Management"],"security":[{"userAuthentication":[]}],"requestBody":{"$ref":"#/components/requestBodies/UserUpdateRequestBody"},"responses":{"200":{"description":"Update successful"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"User was not found"}}}},"/auth/me/profilePicture":{"put":{"description":"Upload endpoint for profile picture","tags":["Authorization & Account Management"],"security":[{"userAuthentication":[]}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"profilePicture":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Upload successful","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"400":{"description":"No file uploaded","content":{"application/json":{"schema":{"type":"string","example":"No file uploaded."}}}},"401":{"$ref":"#/components/responses/UnauthorizedError"}}},"delete":{"description":"Delete the profile picture","tags":["Authorization & Account Management"],"security":[{"userAuthentication":[]}],"responses":{"200":{"description":"Deletion successful or no profile picture to be deleted"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/auth/me/profilePicture/:filename":{"get":{"description":"Profile picture retrieval endpoint","tags":["Authorization & Account Management"],"security":[{"userAuthentication":[]}],"parameters":[{"name":"filename","in":"path","description":"file name of the stored profilePicture. Defaults to the user id + the profilePictureExtension","required":true,"schema":{"type":"string","example":"a7ddc23a-3220-46ae-b640-22d8d480f5d1.png"}}],"responses":{"200":{"description":"Success"},"401":{"$ref":"#/components/responses/UnauthorizedError"},"404":{"description":"File not found"}}}},"/auth/me/resendEmailConfirmationLink":{"get":{"description":"Resend the email confirmation link in a new email, creates a notification","tags":["Authorization & Account Management"],"security":[{"userAuthentication":[]}],"responses":{"200":{"description":"Email was sent"},"401":{"$ref":"#/components/responses/UnauthorizedError"}}}},"/":{"get":{"description":"Server Status","tags":["General"],"responses":{"200":{"description":"Returns a status page with a positive status message and the server version"}}}},"/version":{"get":{"description":"Server version","tags":["General"],"responses":{"200":{"description":"Returns the server version"}}}},"/health":{"get":{"description":"Healthcheck with detailed service status","tags":["General"],"responses":{"200":{"description":"All required services are healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","degraded","unhealthy"]},"version":{"type":"string"},"uptime":{"type":"integer"},"formattedUptime":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"services":{"type":"object","properties":{"database":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy"]},"required":{"type":"boolean"},"message":{"type":"string"}}},"mail":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy","unconfigured","error"]},"required":{"type":"boolean"},"message":{"type":"string"}}},"featureFlags":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unhealthy","unconfigured","error"]},"required":{"type":"boolean"},"message":{"type":"string"}}},"logging":{"type":"object","properties":{"status":{"type":"string","enum":["healthy","unconfigured"]},"required":{"type":"boolean"}}}}},"featureFlags":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"enabled":{"type":"boolean"}}}},"oauthProviders":{"type":"array","items":{"type":"string"}}}}}}},"503":{"description":"One or more required services are unhealthy"}}}},"/api-docs":{"get":{"description":"This API documentation","tags":["General"],"responses":{"200":{"description":"Returns this documentation web page"}}}},"/openapi.json":{"get":{"summary":"Fetch the raw OpenAPI specification for this API","description":"Machine-readable OpenAPI 3.1 document describing every endpoint, schema and security requirement of the Choreo Planer API. The same document powers the interactive documentation served at `/api-docs`. Intended for coding agents, SDK generators and API clients.\n","tags":["Meta"],"security":[],"responses":{"200":{"description":"The OpenAPI specification","content":{"application/json":{"schema":{"type":"object","properties":{"openapi":{"type":"string","example":"3.1.1"},"info":{"type":"object","properties":{"title":{"type":"string"},"version":{"type":"string"}}},"servers":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"description":{"type":"string"}}}},"paths":{"type":"object","additionalProperties":true}}}}}}}}},"/docs":{"get":{"description":"JsDoc documentation","tags":["General"],"responses":{"200":{"description":"JsDoc documentation"}}}},"security":{"0":{"userAuthentication":[]}}},"components":{"requestBodies":{"RegistrationRequestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["username","email","password"],"properties":{"username":{"type":"string"},"email":{"type":"string","format":"email"},"password":{"type":"string","format":"password"}}}}}},"LoginRequestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["username","password"],"properties":{"username":{"type":"string"},"password":{"type":"string","format":"password"}}}}}},"ssoRequestRequestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"}}}}}},"ssoRequestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ssoToken"],"properties":{"ssoToken":{"$ref":"#/components/schema/JWT"}}}}}},"UserUpdateRequestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["username","email"],"properties":{"username":{"type":"string"},"email":{"type":"string","format":"email"}}}}}}},"securitySchemes":{"userAuthentication":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"responses":{"UnauthorizedError":{"description":"Unauthorized"},"BadRequestError":{"description":"Bad Request"}},"schemas":{"JWT":{"type":"string","example":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30"},"UserAccess":{"type":"object","required":["id","ownerUserId","childUserId","role"],"properties":{"id":{"type":"string","format":"uuid"},"ownerUserId":{"type":"string","format":"uuid"},"childUserId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["coach","assistant","athlete"]},"accepted":{"type":"boolean","default":false},"enabled":{"type":"boolean","default":true}}},"User":{"type":"object","required":["id","username"],"properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"email":{"type":"string","format":"email"},"emailConfirmed":{"type":"boolean","default":false},"profilePictureExtension":{"type":"string","example":".png"},"password":{"type":"string","format":"password"},"lastLoggedIn":{"type":"string","format":"date-time"}}},"Team":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"SeasonTeam":{"type":"object","required":["id","UserId"],"properties":{"id":{"type":"string","format":"uuid"},"UserId":{"type":"string","format":"uuid"},"creatorId":{"type":"string","format":"uuid"},"updaterId":{"type":"string","format":"uuid"}}},"Season":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"year":{"type":"integer"},"name":{"type":"string"},"creatorId":{"type":"string","format":"uuid"},"updaterId":{"type":"string","format":"uuid"}}},"Position":{"type":"object","required":["id","x","y"],"properties":{"id":{"type":"string","format":"uuid"},"x":{"type":"number"},"y":{"type":"number"},"creatorId":{"type":"string","format":"uuid"},"updaterId":{"type":"string","format":"uuid"}}},"Notification":{"type":"object","required":["id","title","message","read"],"properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"message":{"type":"string"},"read":{"type":"boolean","default":false}}},"Member":{"type":"object","required":["id","name","abbreviation"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"nickname":{"type":"string"},"abbreviation":{"type":"string"},"creatorId":{"type":"string","format":"uuid"},"updaterId":{"type":"string","format":"uuid"}}},"Lineup":{"type":"object","required":["id","startCount","endCount"],"properties":{"id":{"type":"string","format":"uuid"},"startCount":{"type":"integer","minimum":0},"endCount":{"type":"integer","minimum":0},"creatorId":{"type":"string","format":"uuid"},"updaterId":{"type":"string","format":"uuid"}}},"Hit":{"type":"object","required":["id","count","name"],"properties":{"id":{"type":"string","format":"uuid"},"count":{"type":"integer","minimum":0},"name":{"type":"string"},"creatorId":{"type":"string","format":"uuid"},"updaterId":{"type":"string","format":"uuid"}}},"Feedback":{"type":"object","required":["id","stars"],"properties":{"id":{"type":"string","format":"uuid"},"stars":{"type":"integer","minimum":1,"maximum":5},"text":{"type":"string"},"creatorId":{"type":"string","format":"uuid"},"updaterId":{"type":"string","format":"uuid"}}},"Club":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"logoExtension":{"type":"string","example":".png"},"creatorId":{"type":"string","format":"uuid"},"updaterId":{"type":"string","format":"uuid"}}},"Choreo":{"type":"object","required":["id","name","counts","matType"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"counts":{"type":"integer","minimum":0},"matType":{"type":"string","enum":["cheer","square","1:2","3:4"],"default":"cheer"},"creatorId":{"type":"string","format":"uuid"},"updaterId":{"type":"string","format":"uuid"}}},"Admin":{"type":"object","required":["id","username","password"],"properties":{"id":{"type":"string","format":"uuid"},"username":{"type":"string"},"password":{"type":"string","format":"password"}}}}},"tags":[{"name":"Contact"},{"name":"Choreos"},{"name":"Authorization & Account Management","description":"Endpoints for authentication and authorization"},{"name":"General","description":"General-purpose endpoints"}]}