{
  "openapi": "3.1.1",
  "info": {
    "title": "ClimbUp.Api.App",
    "description": "ClimbUp API. Browser callers use cookie + CSRF; mobile callers use Bearer JWT.",
    "version": "v1"
  },
  "servers": [
    {
      "url": "https://app-api.climb-up.app/"
    }
  ],
  "paths": {
    "/": {
      "get": {
        "tags": [
          "ClimbUp.Api.App"
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/ascents": {
      "get": {
        "tags": [
          "Ascents"
        ],
        "operationId": "Ascents_List",
        "parameters": [
          {
            "name": "routeId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "mine",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/AscentDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Ascents"
        ],
        "operationId": "Ascents_Create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AscentRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AscentRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AscentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AscentDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/ascents/{id}": {
      "get": {
        "tags": [
          "Ascents"
        ],
        "operationId": "Ascents_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AscentDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Ascents"
        ],
        "operationId": "Ascents_Delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/feed": {
      "get": {
        "tags": [
          "Feed"
        ],
        "operationId": "Feed_Feed",
        "parameters": [
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            }
          },
          {
            "name": "authorId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "scope",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PostDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Feed"
        ],
        "operationId": "Feed_Create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePostRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePostRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePostRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/feed/{id}": {
      "get": {
        "tags": [
          "Feed"
        ],
        "operationId": "Feed_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Feed"
        ],
        "operationId": "Feed_Delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/feed/media": {
      "post": {
        "tags": [
          "Feed"
        ],
        "operationId": "Feed_UploadMedia",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "$ref": "#/components/schemas/IFormFile"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostMediaUploadResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/feed/{id}/like": {
      "post": {
        "tags": [
          "Feed"
        ],
        "operationId": "Feed_ToggleLike",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PostDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/feed/{id}/comments": {
      "get": {
        "tags": [
          "Feed"
        ],
        "operationId": "Feed_Comments",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CommentDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Feed"
        ],
        "operationId": "Feed_AddComment",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCommentRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCommentRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCommentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CommentDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/groups": {
      "get": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_Mine",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/GroupDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_Create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGroupRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGroupRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGroupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupDetailDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/groups/discover": {
      "get": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_Discover",
        "parameters": [
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/GroupDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/groups/{id}": {
      "get": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupDetailDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_Update",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGroupRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGroupRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGroupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupDetailDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_Delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/groups/{id}/join": {
      "post": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_Join",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupDetailDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/groups/join": {
      "post": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_JoinByCode",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JoinGroupRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/JoinGroupRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/JoinGroupRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GroupDetailDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/groups/{id}/leave": {
      "delete": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_Leave",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/groups/{id}/members/{userId}": {
      "delete": {
        "tags": [
          "Groups"
        ],
        "operationId": "Groups_Kick",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/training": {
      "get": {
        "tags": [
          "Training"
        ],
        "operationId": "Training_List",
        "parameters": [
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TrainingSessionDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Training"
        ],
        "operationId": "Training_Create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTrainingSessionRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTrainingSessionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTrainingSessionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrainingSessionDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/training/{id}": {
      "get": {
        "tags": [
          "Training"
        ],
        "operationId": "Training_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrainingSessionDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Training"
        ],
        "operationId": "Training_Update",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTrainingSessionRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTrainingSessionRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTrainingSessionRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrainingSessionDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Training"
        ],
        "operationId": "Training_Delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/training/protocols": {
      "get": {
        "tags": [
          "TrainingProtocols"
        ],
        "operationId": "TrainingProtocols_List",
        "parameters": [
          {
            "name": "boardType",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "level",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/TrainingProtocolDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/training/protocols/{id}": {
      "get": {
        "tags": [
          "TrainingProtocols"
        ],
        "operationId": "TrainingProtocols_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrainingProtocolDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/auth/register": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Register a new climber account and bind it to the default gym. Sends an email\n    verification token. When confirmed-email is required, the account cannot sign in until\n    verified (no token issued yet); otherwise the user is logged in immediately.",
        "operationId": "Auth_Register",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterResponse"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/google": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Sign in with a Google ID token (Google Identity Services). Verifies the\ntoken against Google, then finds or creates the matching user by verified\nemail and issues the normal auth response. Gated on `Auth:Google:ClientId`.",
        "operationId": "Auth_GoogleSignIn",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GoogleSignInRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/GoogleSignInRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/GoogleSignInRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/verify-email": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Confirm an email using the token from registration / resend. On success the\n    user is logged in (returns an auth response).",
        "operationId": "Auth_VerifyEmail",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyEmailRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyEmailRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyEmailRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/resend-verification": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Resend the email verification token. Always returns 200 to avoid email enumeration.",
        "operationId": "Auth_ResendVerification",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResendVerificationRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ResendVerificationRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ResendVerificationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ResendVerificationResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/login": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Authenticate with email + password. Issues a JWT in the response body and an HttpOnly cookie for browser sessions.",
        "operationId": "Auth_Login",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/2fa/challenge": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Complete a 2FA login: exchange the challenge token from `POST /auth/login`\n    plus a TOTP code (or a recovery code) for the auth tokens.",
        "operationId": "Auth_TwoFactorChallenge",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorChallengeRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorChallengeRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorChallengeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/2fa": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Current user's 2FA status.",
        "operationId": "Auth_TwoFactorStatus",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwoFactorStatusResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/auth/2fa/enroll": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Start TOTP enrollment: returns the shared key and otpauth URI for the\n    authenticator app. Enrollment is confirmed via `POST /auth/2fa/verify`.",
        "operationId": "Auth_TwoFactorEnroll",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwoFactorEnrollResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/auth/2fa/verify": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Confirm TOTP enrollment with a code from the authenticator app.\n    Enables 2FA and returns the one-time recovery codes (shown once).",
        "operationId": "Auth_TwoFactorVerify",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorVerifyRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorVerifyRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorVerifyRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TwoFactorVerifyResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/auth/2fa/disable": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Disable 2FA. Requires a valid TOTP code (or recovery code); resets the authenticator key.",
        "operationId": "Auth_TwoFactorDisable",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorDisableRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorDisableRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/TwoFactorDisableRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "204": {
            "description": "No Content",
            "content": {
              "application/json": { }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/auth/accept-invite": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Accept a gym membership invite: sets the user's password and activates the membership. Returns an auth response so the client can log in immediately.",
        "operationId": "Auth_AcceptInvite",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AcceptInviteRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/AcceptInviteRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/AcceptInviteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "410": {
            "description": "Gone",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/forgot-password": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Request a password reset. Always returns 200 to avoid email enumeration. In Development the reset token is returned in the response body so the client can complete the flow without SMTP.",
        "operationId": "Auth_ForgotPassword",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ForgotPasswordRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ForgotPasswordRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ForgotPasswordRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ForgotPasswordResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/reset-password": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Complete a password reset using the token from `/auth/forgot-password`.",
        "operationId": "Auth_ResetPassword",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetPasswordRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/ResetPasswordRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/ResetPasswordRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/switch-gym": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Switch the active gym binding for the current user; issues a fresh token bound to the new gym.",
        "operationId": "Auth_SwitchGym",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SwitchGymRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SwitchGymRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SwitchGymRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/auth/refresh": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Exchange a valid refresh token for a fresh access token. Rotates the refresh token\n    (the old one is revoked) and re-reads roles from the database so role changes propagate.",
        "operationId": "Auth_Refresh",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/logout": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Clears the browser session cookies and revokes the presented refresh token.\n    Bearer-token callers can simply discard their access token.",
        "operationId": "Auth_Logout",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/RefreshRequest"
                  }
                ]
              }
            },
            "text/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/RefreshRequest"
                  }
                ]
              }
            },
            "application/*+json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "null"
                  },
                  {
                    "$ref": "#/components/schemas/RefreshRequest"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/csrf": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Returns the CSRF token the browser must attach as `X-CSRF-Token` on mutating requests.",
        "operationId": "Auth_Csrf",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CsrfResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/auth/memberships": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "List all gym memberships of the current user (workspace picker).",
        "operationId": "Auth_Memberships",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MembershipSummaryDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/auth/me": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Current authenticated user profile + gym binding.",
        "operationId": "Auth_Me",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/chats": {
      "get": {
        "tags": [
          "Chats"
        ],
        "operationId": "Chats_List",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ChatRoomDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Chats"
        ],
        "operationId": "Chats_Start",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartChatRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/StartChatRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/StartChatRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatRoomDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/chats/{roomId}/messages": {
      "get": {
        "tags": [
          "Chats"
        ],
        "operationId": "Chats_Messages",
        "parameters": [
          {
            "name": "roomId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "afterId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ChatMessageDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Chats"
        ],
        "operationId": "Chats_Send",
        "parameters": [
          {
            "name": "roomId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendChatMessageRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SendChatMessageRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SendChatMessageRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatMessageDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/follow/{userId}": {
      "post": {
        "tags": [
          "Follow"
        ],
        "summary": "Follow a user. Idempotent — following twice is a no-op.",
        "operationId": "Follow_Follow",
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FollowStatusDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Follow"
        ],
        "summary": "Unfollow a user. Idempotent.",
        "operationId": "Follow_Unfollow",
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FollowStatusDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/follow/status/{userId}": {
      "get": {
        "tags": [
          "Follow"
        ],
        "summary": "My relationship to a user plus their follower/following totals.",
        "operationId": "Follow_Status",
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FollowStatusDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/follow/followers": {
      "get": {
        "tags": [
          "Follow"
        ],
        "summary": "Users who follow userId (defaults to me).",
        "operationId": "Follow_Followers",
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FollowUserDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/follow/following": {
      "get": {
        "tags": [
          "Follow"
        ],
        "summary": "Users that userId follows (defaults to me).",
        "operationId": "Follow_Following",
        "parameters": [
          {
            "name": "userId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FollowUserDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/gyms": {
      "get": {
        "tags": [
          "Gyms"
        ],
        "summary": "List all gyms. Optional case-insensitive `search` matches name, city, or slug.",
        "operationId": "Gyms_List",
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/GymDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Gyms"
        ],
        "summary": "Create a new gym; the caller becomes its Owner. Any authenticated user may create one\n(self-serve onboarding) — switch into it afterwards via `POST /auth/switch-gym`.\nThe gym starts inactive: platform admins verify and activate it from the Admin console.",
        "operationId": "Gyms_Create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGymRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGymRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/CreateGymRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GymDto"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/gyms/nearby": {
      "get": {
        "tags": [
          "Gyms"
        ],
        "summary": "Gyms within radiusKm of (lat,lng),\nordered by distance ascending. PostGIS `ST_DWithin` on Gym.Location.",
        "operationId": "Gyms_Nearby",
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            }
          },
          {
            "name": "lng",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            }
          },
          {
            "name": "radiusKm",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double",
              "default": 25
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/GymDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          }
        }
      }
    },
    "/api/gyms/current": {
      "get": {
        "tags": [
          "Gyms"
        ],
        "summary": "The gym the current user is bound to.",
        "operationId": "Gyms_Current",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GymDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Gyms"
        ],
        "summary": "Update the current user's gym identity, location, and contact info.",
        "operationId": "Gyms_UpdateCurrent",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGymRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGymRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateGymRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GymDto"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/gyms/{id}": {
      "get": {
        "tags": [
          "Gyms"
        ],
        "operationId": "Gyms_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GymDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/gyms/current/logo": {
      "post": {
        "tags": [
          "Gyms"
        ],
        "summary": "Upload the current gym's logo (multipart form-data, field name `file`). Replaces any previous logo.",
        "operationId": "Gyms_UploadLogo",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "$ref": "#/components/schemas/IFormFile"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GymDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/matches/candidates": {
      "get": {
        "tags": [
          "Matches"
        ],
        "summary": "Discovery deck: opted-in climbers I haven't swiped yet.",
        "operationId": "Matches_Candidates",
        "parameters": [
          {
            "name": "discipline",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/Discipline"
            }
          },
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MatchCandidateDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/matches/swipe": {
      "post": {
        "tags": [
          "Matches"
        ],
        "summary": "Swipe on a candidate. Like may complete a mutual match.",
        "operationId": "Matches_Swipe",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SwipeRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SwipeRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SwipeRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SwipeResultDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/matches": {
      "get": {
        "tags": [
          "Matches"
        ],
        "summary": "My confirmed matches, newest first.",
        "operationId": "Matches_Mine",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MatchDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/matches/pending": {
      "get": {
        "tags": [
          "Matches"
        ],
        "summary": "Incoming likes waiting on my decision.",
        "operationId": "Matches_Pending",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/MatchDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/matches/preferences": {
      "get": {
        "tags": [
          "Matches"
        ],
        "summary": "My match preferences (creates defaults on first read).",
        "operationId": "Matches_GetPreferences",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchPreferencesDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Matches"
        ],
        "operationId": "Matches_UpdatePreferences",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMatchPreferencesRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMatchPreferencesRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMatchPreferencesRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MatchPreferencesDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/notifications": {
      "get": {
        "tags": [
          "Notifications"
        ],
        "summary": "Notifications for the current user, newest first.",
        "operationId": "Notifications_List",
        "parameters": [
          {
            "name": "unread",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/NotificationDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/notifications/unread-count": {
      "get": {
        "tags": [
          "Notifications"
        ],
        "summary": "Count of unread notifications.",
        "operationId": "Notifications_UnreadCount",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "pattern": "^-?(?:0|[1-9]\\d*)$",
                  "type": [
                    "integer",
                    "string"
                  ],
                  "format": "int32"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/notifications/{id}/read": {
      "post": {
        "tags": [
          "Notifications"
        ],
        "summary": "Mark one notification as read.",
        "operationId": "Notifications_MarkRead",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/notifications/broadcast": {
      "post": {
        "tags": [
          "Notifications"
        ],
        "summary": "Broadcast a notification to a gym audience (members/operators/role).",
        "operationId": "Notifications_Broadcast",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BroadcastNotificationRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/BroadcastNotificationRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/BroadcastNotificationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BroadcastNotificationResponse"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/notifications/read-all": {
      "post": {
        "tags": [
          "Notifications"
        ],
        "summary": "Mark every notification of the current user as read.",
        "operationId": "Notifications_MarkAllRead",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/partners": {
      "get": {
        "tags": [
          "Partners"
        ],
        "operationId": "Partners_Search",
        "parameters": [
          {
            "name": "discipline",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/Discipline"
            }
          },
          {
            "name": "gradeMin",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "gradeMax",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "lat",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            }
          },
          {
            "name": "lng",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            }
          },
          {
            "name": "radiusKm",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
              "type": [
                "number",
                "string"
              ],
              "format": "double"
            }
          },
          {
            "name": "sameGym",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PartnerCardDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/profile": {
      "get": {
        "tags": [
          "Profile"
        ],
        "summary": "Current user's profile.",
        "operationId": "Profile_Mine",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfileDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Profile"
        ],
        "summary": "Update the current user's profile.",
        "operationId": "Profile_Update",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProfileRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProfileRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProfileRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfileDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/profile/{userId}": {
      "get": {
        "tags": [
          "Profile"
        ],
        "summary": "Another user's profile.",
        "operationId": "Profile_Get",
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfileDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/profile/avatar": {
      "post": {
        "tags": [
          "Profile"
        ],
        "summary": "Upload an avatar image (multipart form-data, field name `file`). Replaces any previous avatar.",
        "operationId": "Profile_UploadAvatar",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "$ref": "#/components/schemas/IFormFile"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfileDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/profile/partner-prefs": {
      "put": {
        "tags": [
          "Profile"
        ],
        "summary": "Toggle partner-match opt-in and grade range.",
        "operationId": "Profile_UpdatePartnerPrefs",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePartnerPrefsRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePartnerPrefsRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePartnerPrefsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProfileDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/profile/certifications": {
      "get": {
        "tags": [
          "Profile"
        ],
        "summary": "Certifications issued to the current user across gyms (active only).",
        "operationId": "Profile_MyCertifications",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CertificationDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/profile/{userId}/certifications": {
      "get": {
        "tags": [
          "Profile"
        ],
        "summary": "Public certifications for another user (only IsActive).",
        "operationId": "Profile_UserCertifications",
        "parameters": [
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CertificationDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/profile/certifications/issue": {
      "post": {
        "tags": [
          "Profile"
        ],
        "summary": "Issue a certification to a member of the current gym (GymStaff only).",
        "operationId": "Profile_IssueCertification",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueCertificationRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueCertificationRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/IssueCertificationRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CertificationDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/profile/stats": {
      "get": {
        "tags": [
          "Profile"
        ],
        "summary": "Climbing stats of the current user for the current gym.",
        "operationId": "Profile_Stats",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserStatsDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/push-tokens": {
      "post": {
        "tags": [
          "PushTokens"
        ],
        "summary": "Register (or refresh) a push token for the current user/device.",
        "operationId": "PushTokens_Register",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterPushTokenRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterPushTokenRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterPushTokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PushTokenDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "get": {
        "tags": [
          "PushTokens"
        ],
        "summary": "List the current user's registered push tokens.",
        "operationId": "PushTokens_List",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PushTokenDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/push-tokens/{token}": {
      "delete": {
        "tags": [
          "PushTokens"
        ],
        "summary": "Unregister a push token by value (called on logout / disable notifications).",
        "operationId": "PushTokens_Unregister",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/push-tokens/test": {
      "post": {
        "tags": [
          "PushTokens"
        ],
        "summary": "Send a test push notification to the current user (dev/QA aid).",
        "operationId": "PushTokens_Test",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendTestPushRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SendTestPushRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SendTestPushRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes": {
      "get": {
        "tags": [
          "Routes"
        ],
        "summary": "Paged list of routes in the current gym with optional filters.",
        "operationId": "Routes_List",
        "parameters": [
          {
            "name": "Page",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          },
          {
            "name": "PageSize",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          },
          {
            "name": "Search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "SkipCount",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          },
          {
            "name": "TakeCount",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32"
            }
          },
          {
            "name": "sectorId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "wallId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "discipline",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/Discipline"
            }
          },
          {
            "name": "active",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PagedResponseOfRouteListItem"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Routes"
        ],
        "operationId": "Routes_Create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RouteRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/RouteRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/RouteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteDetailDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/by-qr/{token}": {
      "get": {
        "tags": [
          "Routes"
        ],
        "summary": "Resolve a QR token printed on a wall placard to its Route id + gym scope.\nCross-gym scans are allowed at lookup time; subsequent calls to\n`GET /routes/{id}` still enforce the caller's current gym scope.",
        "operationId": "Routes_GetByQrToken",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteByQrDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/tags": {
      "get": {
        "tags": [
          "Routes"
        ],
        "summary": "Route detail incl. tags and the current user's ascent if any.",
        "operationId": "Routes_Tags",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/{id}": {
      "get": {
        "tags": [
          "Routes"
        ],
        "operationId": "Routes_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteDetailDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Routes"
        ],
        "operationId": "Routes_Update",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RouteRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/RouteRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/RouteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteDetailDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Routes"
        ],
        "summary": "Soft-delete a route (moves it to trash).",
        "operationId": "Routes_Delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/{id}/active": {
      "put": {
        "tags": [
          "Routes"
        ],
        "summary": "Toggle the route's active flag.",
        "operationId": "Routes_SetActive",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BoolFlagRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/BoolFlagRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/BoolFlagRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/{id}/featured": {
      "put": {
        "tags": [
          "Routes"
        ],
        "summary": "Toggle the route's featured flag.",
        "operationId": "Routes_SetFeatured",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BoolFlagRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/BoolFlagRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/BoolFlagRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/trash": {
      "get": {
        "tags": [
          "Routes"
        ],
        "summary": "Soft-deleted routes of the current gym.",
        "operationId": "Routes_Trash",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RouteListItem"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/{id}/restore": {
      "post": {
        "tags": [
          "Routes"
        ],
        "summary": "Restore a soft-deleted route.",
        "operationId": "Routes_Restore",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/{id}/media": {
      "get": {
        "tags": [
          "Routes"
        ],
        "summary": "List media attached to a route.",
        "operationId": "Routes_ListMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RouteMediaDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Routes"
        ],
        "summary": "Upload a photo/video for a route (multipart form-data, field name `file`).",
        "operationId": "Routes_UploadMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "allOf": [
                  {
                    "type": "object",
                    "properties": {
                      "file": {
                        "$ref": "#/components/schemas/IFormFile"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "properties": {
                      "caption": {
                        "type": "string"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "properties": {
                      "isOfficial": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteMediaDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/{id}/media/{mediaId}": {
      "delete": {
        "tags": [
          "Routes"
        ],
        "summary": "Delete a route media entry and its file.",
        "operationId": "Routes_DeleteMedia",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "mediaId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/routes/{id}/feedback": {
      "get": {
        "tags": [
          "Routes"
        ],
        "summary": "Aggregate feedback for a route, the caller's own entry, and recent comments.",
        "operationId": "Routes_ListFeedback",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteFeedbackSummaryDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Routes"
        ],
        "summary": "Create or update the caller's feedback for a route. One entry per user.",
        "operationId": "Routes_UpsertFeedback",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertRouteFeedbackRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertRouteFeedbackRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertRouteFeedbackRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteFeedbackSummaryDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Routes"
        ],
        "summary": "Delete the caller's feedback for a route.",
        "operationId": "Routes_DeleteFeedback",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteFeedbackSummaryDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/sectors": {
      "get": {
        "tags": [
          "Sectors"
        ],
        "summary": "List sectors of the current gym.",
        "operationId": "Sectors_List",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SectorDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Sectors"
        ],
        "operationId": "Sectors_Create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SectorRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SectorRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SectorRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SectorDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/sectors/{id}": {
      "get": {
        "tags": [
          "Sectors"
        ],
        "operationId": "Sectors_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SectorDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Sectors"
        ],
        "operationId": "Sectors_Update",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SectorRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SectorRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SectorRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SectorDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Sectors"
        ],
        "operationId": "Sectors_Delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/settings": {
      "get": {
        "tags": [
          "Settings"
        ],
        "summary": "The current user's full settings (creates defaults on first read).",
        "operationId": "Settings_Get",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserSettingsDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Settings"
        ],
        "summary": "Update the current user's full settings.",
        "operationId": "Settings_Update",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserSettingsRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserSettingsRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateUserSettingsRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserSettingsDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/settings/locale": {
      "put": {
        "tags": [
          "Settings"
        ],
        "summary": "Set the current user's preferred UI locale (en | it | ar). Persisted in\n    user settings so every client (Gym Console, Coach web, mobile) can honour it.",
        "operationId": "Settings_UpdateLocale",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLocaleRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLocaleRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateLocaleRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdateLocaleResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/speed-runs/leaderboard": {
      "get": {
        "tags": [
          "SpeedRuns"
        ],
        "summary": "Best valid time per climber in the current gym, fastest first. Optionally\nscoped to a competition and/or a date window.",
        "operationId": "SpeedRuns_Leaderboard",
        "parameters": [
          {
            "name": "competitionId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SpeedRunLeaderboardDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/speed-runs/mine": {
      "get": {
        "tags": [
          "SpeedRuns"
        ],
        "summary": "The current user's own runs in the current gym, newest first.",
        "operationId": "SpeedRuns_Mine",
        "parameters": [
          {
            "name": "take",
            "in": "query",
            "schema": {
              "pattern": "^-?(?:0|[1-9]\\d*)$",
              "type": [
                "integer",
                "string"
              ],
              "format": "int32",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SpeedRunDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/spray-walls": {
      "get": {
        "tags": [
          "SprayWalls"
        ],
        "summary": "Spray walls in the current gym.",
        "operationId": "SprayWalls_List",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SprayWallDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "SprayWalls"
        ],
        "summary": "Create a spray wall from a photo (multipart, field `file`). Staff only.",
        "operationId": "SprayWalls_Create",
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "allOf": [
                  {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "properties": {
                      "file": {
                        "$ref": "#/components/schemas/IFormFile"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "properties": {
                      "width": {
                        "pattern": "^-?(?:0|[1-9]\\d*)$",
                        "type": [
                          "integer",
                          "string"
                        ],
                        "format": "int32"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "properties": {
                      "height": {
                        "pattern": "^-?(?:0|[1-9]\\d*)$",
                        "type": [
                          "integer",
                          "string"
                        ],
                        "format": "int32"
                      }
                    }
                  }
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SprayWallDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/spray-walls/{id}": {
      "get": {
        "tags": [
          "SprayWalls"
        ],
        "operationId": "SprayWalls_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SprayWallDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "SprayWalls"
        ],
        "summary": "Soft-delete a spray wall (staff only).",
        "operationId": "SprayWalls_Delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/spray-walls/{id}/routes": {
      "get": {
        "tags": [
          "SprayWalls"
        ],
        "operationId": "SprayWalls_Routes",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/SprayRouteDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "SprayWalls"
        ],
        "summary": "Create a route on a spray wall (any gym member).",
        "operationId": "SprayWalls_CreateRoute",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveSprayRouteRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveSprayRouteRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SaveSprayRouteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SprayRouteDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/spray-walls/routes/{routeId}": {
      "get": {
        "tags": [
          "SprayWalls"
        ],
        "operationId": "SprayWalls_GetRoute",
        "parameters": [
          {
            "name": "routeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SprayRouteDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "SprayWalls"
        ],
        "summary": "Update a spray route (setter or gym staff).",
        "operationId": "SprayWalls_UpdateRoute",
        "parameters": [
          {
            "name": "routeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveSprayRouteRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/SaveSprayRouteRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/SaveSprayRouteRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SprayRouteDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "SprayWalls"
        ],
        "operationId": "SprayWalls_DeleteRoute",
        "parameters": [
          {
            "name": "routeId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/walls": {
      "get": {
        "tags": [
          "Walls"
        ],
        "summary": "List walls of the current gym, optionally filtered by sector.",
        "operationId": "Walls_List",
        "parameters": [
          {
            "name": "sectorId",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WallDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "post": {
        "tags": [
          "Walls"
        ],
        "operationId": "Walls_Create",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WallRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/WallRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/WallRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WallDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/walls/{id}": {
      "get": {
        "tags": [
          "Walls"
        ],
        "operationId": "Walls_Get",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WallDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "put": {
        "tags": [
          "Walls"
        ],
        "operationId": "Walls_Update",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WallRequest"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/WallRequest"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/WallRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WallDto"
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      },
      "delete": {
        "tags": [
          "Walls"
        ],
        "summary": "Soft-delete a wall (moves it to trash).",
        "operationId": "Walls_Delete",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/walls/trash": {
      "get": {
        "tags": [
          "Walls"
        ],
        "summary": "Soft-deleted walls of the current gym.",
        "operationId": "Walls_Trash",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WallDto"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    },
    "/api/walls/{id}/restore": {
      "post": {
        "tags": [
          "Walls"
        ],
        "summary": "Restore a soft-deleted wall.",
        "operationId": "Walls_Restore",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": { }
            }
          },
          "500": {
            "description": "Server error."
          },
          "401": {
            "description": "Unauthorized."
          },
          "403": {
            "description": "Forbidden."
          }
        },
        "security": [
          {
            "Bearer": [ ],
            "Cookie": [ ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "AcceptInviteRequest": {
        "required": [
          "token",
          "password",
          "displayName"
        ],
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "password": {
            "type": "string"
          },
          "displayName": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "AscentDto": {
        "required": [
          "id",
          "routeId",
          "routeName",
          "routeGrade",
          "userId",
          "userName",
          "type",
          "attempts",
          "topped",
          "climbedAt",
          "notes",
          "rating",
          "perceivedGrade",
          "isOutdoor"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "routeId": {
            "type": "string",
            "format": "uuid"
          },
          "routeName": {
            "type": [
              "null",
              "string"
            ]
          },
          "routeGrade": {
            "type": "string"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "userName": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/AscentType"
          },
          "attempts": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "topped": {
            "type": "boolean"
          },
          "climbedAt": {
            "type": "string",
            "format": "date"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ]
          },
          "rating": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "perceivedGrade": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "isOutdoor": {
            "type": "boolean"
          }
        }
      },
      "AscentRequest": {
        "required": [
          "routeId",
          "type",
          "attempts",
          "topped",
          "climbedAt",
          "notes",
          "rating",
          "perceivedGrade",
          "isOutdoor",
          "shareAsPost"
        ],
        "type": "object",
        "properties": {
          "routeId": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "$ref": "#/components/schemas/AscentType"
          },
          "attempts": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "topped": {
            "type": "boolean"
          },
          "climbedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ]
          },
          "rating": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "perceivedGrade": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "isOutdoor": {
            "type": "boolean"
          },
          "shareAsPost": {
            "type": "boolean"
          }
        }
      },
      "AscentType": {
        "type": "integer"
      },
      "AuthResponse": {
        "required": [
          "token",
          "expiresAt",
          "user",
          "refreshToken",
          "refreshExpiresAt"
        ],
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "user": {
            "$ref": "#/components/schemas/MeResponse"
          },
          "refreshToken": {
            "type": "string"
          },
          "refreshExpiresAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BoolFlagRequest": {
        "required": [
          "value"
        ],
        "type": "object",
        "properties": {
          "value": {
            "type": "boolean"
          }
        }
      },
      "BroadcastNotificationRequest": {
        "required": [
          "title",
          "body",
          "type",
          "audience",
          "role"
        ],
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "body": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "type": "string"
          },
          "audience": {
            "type": "string"
          },
          "role": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/GymRole"
              }
            ]
          }
        }
      },
      "BroadcastNotificationResponse": {
        "required": [
          "sent"
        ],
        "type": "object",
        "properties": {
          "sent": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        }
      },
      "CertificationDto": {
        "required": [
          "id",
          "userId",
          "gymId",
          "gymName",
          "type",
          "grade",
          "issuedByUserId",
          "issuedByName",
          "issuedAt",
          "expiresAt",
          "notes",
          "isActive"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "gymId": {
            "type": "string",
            "format": "uuid"
          },
          "gymName": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/CertificationType"
          },
          "grade": {
            "type": [
              "null",
              "string"
            ]
          },
          "issuedByUserId": {
            "type": "string",
            "format": "uuid"
          },
          "issuedByName": {
            "type": "string"
          },
          "issuedAt": {
            "type": "string",
            "format": "date"
          },
          "expiresAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ]
          },
          "isActive": {
            "type": "boolean"
          }
        }
      },
      "CertificationType": {
        "type": "integer"
      },
      "ChatMessageDto": {
        "required": [
          "id",
          "roomId",
          "senderId",
          "senderDisplayName",
          "senderAvatarUrl",
          "content",
          "type",
          "createdAt",
          "editedAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "roomId": {
            "type": "string",
            "format": "uuid"
          },
          "senderId": {
            "type": "string",
            "format": "uuid"
          },
          "senderDisplayName": {
            "type": "string"
          },
          "senderAvatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "content": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "editedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          }
        }
      },
      "ChatRoomDto": {
        "required": [
          "id",
          "type",
          "otherUserId",
          "otherDisplayName",
          "otherAvatarUrl",
          "lastMessageContent",
          "lastMessageAt",
          "lastMessageSenderId",
          "unreadCount"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string"
          },
          "otherUserId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "otherDisplayName": {
            "type": [
              "null",
              "string"
            ]
          },
          "otherAvatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "lastMessageContent": {
            "type": [
              "null",
              "string"
            ]
          },
          "lastMessageAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "lastMessageSenderId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "unreadCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        }
      },
      "CommentDto": {
        "required": [
          "id",
          "postId",
          "userId",
          "userName",
          "userAvatarUrl",
          "content",
          "createdAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "postId": {
            "type": "string",
            "format": "uuid"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "userName": {
            "type": "string"
          },
          "userAvatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "content": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateCommentRequest": {
        "required": [
          "content"
        ],
        "type": "object",
        "properties": {
          "content": {
            "type": "string"
          }
        }
      },
      "CreateGroupRequest": {
        "required": [
          "name",
          "description",
          "type",
          "isPrivate",
          "maxMembers",
          "bindToGym"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "type": "string"
          },
          "isPrivate": {
            "type": "boolean"
          },
          "maxMembers": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "bindToGym": {
            "type": "boolean"
          }
        }
      },
      "CreateGymRequest": {
        "required": [
          "name",
          "slug",
          "description",
          "address",
          "city",
          "country",
          "phone",
          "email",
          "website",
          "latitude",
          "longitude"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "phone": {
            "type": [
              "null",
              "string"
            ]
          },
          "email": {
            "type": [
              "null",
              "string"
            ]
          },
          "website": {
            "type": [
              "null",
              "string"
            ]
          },
          "latitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "longitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "timezone": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "CreatePostRequest": {
        "required": [
          "type",
          "content",
          "media",
          "ascentId",
          "visibility"
        ],
        "type": "object",
        "properties": {
          "type": {
            "$ref": "#/components/schemas/PostType"
          },
          "content": {
            "type": [
              "null",
              "string"
            ]
          },
          "media": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            }
          },
          "ascentId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "visibility": {
            "$ref": "#/components/schemas/PostVisibility"
          }
        }
      },
      "CreateTrainingSessionRequest": {
        "required": [
          "type",
          "name",
          "startedAt",
          "endedAt",
          "durationMinutes",
          "notes",
          "rpe",
          "exercises"
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": "string"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "startedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "endedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "durationMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ]
          },
          "rpe": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "exercises": {
            "type": [
              "null",
              "string"
            ]
          },
          "bindToGym": {
            "type": "boolean",
            "default": true
          }
        }
      },
      "CsrfResponse": {
        "required": [
          "token",
          "headerName"
        ],
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "headerName": {
            "type": "string"
          }
        }
      },
      "Discipline": {
        "type": "integer"
      },
      "FeedAscentDto": {
        "required": [
          "routeName",
          "grade",
          "gradeSystem",
          "wallName",
          "type"
        ],
        "type": "object",
        "properties": {
          "routeName": {
            "type": "string"
          },
          "grade": {
            "type": "string"
          },
          "gradeSystem": {
            "$ref": "#/components/schemas/GradeSystem"
          },
          "wallName": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "$ref": "#/components/schemas/AscentType"
          }
        }
      },
      "FollowStatusDto": {
        "required": [
          "isFollowing",
          "followsMe",
          "followersCount",
          "followingCount"
        ],
        "type": "object",
        "properties": {
          "isFollowing": {
            "type": "boolean"
          },
          "followsMe": {
            "type": "boolean"
          },
          "followersCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "followingCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        },
        "description": "My relationship to a target user plus their follower/following totals."
      },
      "FollowUserDto": {
        "required": [
          "userId",
          "displayName",
          "avatarUrl",
          "city",
          "country",
          "isFollowedByMe"
        ],
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "avatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "city": {
            "type": [
              "null",
              "string"
            ]
          },
          "country": {
            "type": [
              "null",
              "string"
            ]
          },
          "isFollowedByMe": {
            "type": "boolean"
          }
        },
        "description": "A user in a followers/following list, with my relationship to them."
      },
      "ForgotPasswordRequest": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          }
        }
      },
      "ForgotPasswordResponse": {
        "required": [
          "sent",
          "devToken"
        ],
        "type": "object",
        "properties": {
          "sent": {
            "type": "boolean"
          },
          "devToken": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "GoogleSignInRequest": {
        "required": [
          "idToken"
        ],
        "type": "object",
        "properties": {
          "idToken": {
            "type": "string"
          }
        },
        "description": "Set the user's preferred UI locale (persisted in user settings, shared by all clients)."
      },
      "GradeSystem": {
        "type": "integer"
      },
      "GroupDetailDto": {
        "required": [
          "group",
          "members"
        ],
        "type": "object",
        "properties": {
          "group": {
            "$ref": "#/components/schemas/GroupDto"
          },
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GroupMemberDto"
            }
          }
        }
      },
      "GroupDto": {
        "required": [
          "id",
          "name",
          "description",
          "type",
          "avatarUrl",
          "isPrivate",
          "memberCount",
          "maxMembers",
          "myRole",
          "chatRoomId",
          "joinCode",
          "gymName"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "type": "string"
          },
          "avatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "isPrivate": {
            "type": "boolean"
          },
          "memberCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "maxMembers": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "myRole": {
            "type": [
              "null",
              "string"
            ]
          },
          "chatRoomId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "joinCode": {
            "type": [
              "null",
              "string"
            ]
          },
          "gymName": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "GroupMemberDto": {
        "required": [
          "userId",
          "displayName",
          "avatarUrl",
          "role",
          "joinedAt"
        ],
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "avatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "role": {
            "type": "string"
          },
          "joinedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "GymDto": {
        "required": [
          "id",
          "name",
          "slug",
          "description",
          "logoUrl",
          "coverUrl",
          "address",
          "city",
          "country",
          "phone",
          "email",
          "website",
          "latitude",
          "longitude",
          "isActive",
          "memberCount",
          "routeCount"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "logoUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "coverUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "phone": {
            "type": [
              "null",
              "string"
            ]
          },
          "email": {
            "type": [
              "null",
              "string"
            ]
          },
          "website": {
            "type": [
              "null",
              "string"
            ]
          },
          "latitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "longitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "isActive": {
            "type": "boolean"
          },
          "memberCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "routeCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        }
      },
      "GymRole": {
        "type": "integer"
      },
      "IFormFile": {
        "type": "string",
        "format": "binary"
      },
      "IssueCertificationRequest": {
        "required": [
          "userId",
          "type",
          "grade",
          "expiresAt",
          "notes"
        ],
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "$ref": "#/components/schemas/CertificationType"
          },
          "grade": {
            "type": [
              "null",
              "string"
            ]
          },
          "expiresAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "JoinGroupRequest": {
        "required": [
          "code"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          }
        }
      },
      "LoginRequest": {
        "required": [
          "email",
          "password"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        }
      },
      "LoginResponse": {
        "required": [
          "requires2fa",
          "twoFactorToken",
          "auth"
        ],
        "type": "object",
        "properties": {
          "requires2fa": {
            "type": "boolean"
          },
          "twoFactorToken": {
            "type": [
              "null",
              "string"
            ]
          },
          "auth": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AuthResponse"
              }
            ]
          }
        },
        "description": "Login result. When `Requires2fa` is true the credentials were valid but the\n    account has TOTP enabled: complete the sign-in via `POST /auth/2fa/challenge` with\n    `TwoFactorToken` and a code. Otherwise `Auth` carries the issued tokens."
      },
      "MatchCandidateDto": {
        "required": [
          "userId",
          "displayName",
          "avatarUrl",
          "city",
          "country",
          "gymName",
          "preferredDiscipline",
          "maxBoulderGrade",
          "maxLeadGrade",
          "bio",
          "distanceKm"
        ],
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "avatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "city": {
            "type": [
              "null",
              "string"
            ]
          },
          "country": {
            "type": [
              "null",
              "string"
            ]
          },
          "gymName": {
            "type": [
              "null",
              "string"
            ]
          },
          "preferredDiscipline": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Discipline"
              }
            ]
          },
          "maxBoulderGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "maxLeadGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "bio": {
            "type": [
              "null",
              "string"
            ]
          },
          "distanceKm": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          }
        },
        "description": "A swipe candidate in the discovery deck."
      },
      "MatchDto": {
        "required": [
          "id",
          "otherUserId",
          "otherDisplayName",
          "otherAvatarUrl",
          "status",
          "matchedAt",
          "chatRoomId"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "otherUserId": {
            "type": "string",
            "format": "uuid"
          },
          "otherDisplayName": {
            "type": "string"
          },
          "otherAvatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "type": "string"
          },
          "matchedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "chatRoomId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          }
        },
        "description": "A confirmed or pending match with the other climber."
      },
      "MatchPreferencesDto": {
        "required": [
          "lookingFor",
          "skillRange",
          "maxDistanceKm",
          "bio",
          "isActive"
        ],
        "type": "object",
        "properties": {
          "lookingFor": {
            "type": "string"
          },
          "skillRange": {
            "type": "string"
          },
          "maxDistanceKm": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "bio": {
            "type": [
              "null",
              "string"
            ]
          },
          "isActive": {
            "type": "boolean"
          }
        }
      },
      "MembershipSummaryDto": {
        "required": [
          "membershipId",
          "gymId",
          "gymName",
          "gymLogoUrl",
          "role",
          "isActive",
          "joinedAt"
        ],
        "type": "object",
        "properties": {
          "membershipId": {
            "type": "string",
            "format": "uuid"
          },
          "gymId": {
            "type": "string",
            "format": "uuid"
          },
          "gymName": {
            "type": "string"
          },
          "gymLogoUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "role": {
            "$ref": "#/components/schemas/GymRole"
          },
          "isActive": {
            "type": "boolean"
          },
          "joinedAt": {
            "type": "string",
            "format": "date"
          }
        }
      },
      "MeResponse": {
        "required": [
          "id",
          "email",
          "displayName",
          "avatarUrl",
          "gymId",
          "gymName",
          "gymRole"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "email": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          },
          "avatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "gymId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "gymName": {
            "type": [
              "null",
              "string"
            ]
          },
          "gymRole": {
            "type": [
              "null",
              "string"
            ]
          },
          "preferredLocale": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "NotificationDto": {
        "required": [
          "id",
          "type",
          "title",
          "body",
          "isRead",
          "createdAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": [
              "null",
              "string"
            ]
          },
          "isRead": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PagedResponseOfRouteListItem": {
        "required": [
          "items",
          "page",
          "pageSize",
          "total"
        ],
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RouteListItem"
            }
          },
          "page": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "pageSize": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "total": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "totalPages": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        },
        "description": "Uniform JSON envelope for paginated list endpoints."
      },
      "PartnerCardDto": {
        "required": [
          "userId",
          "displayName",
          "avatarUrl",
          "city",
          "country",
          "gymName",
          "preferredDiscipline",
          "partnerGradeMin",
          "partnerGradeMax",
          "maxBoulderGrade",
          "maxLeadGrade",
          "distanceKm"
        ],
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "avatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "city": {
            "type": [
              "null",
              "string"
            ]
          },
          "country": {
            "type": [
              "null",
              "string"
            ]
          },
          "gymName": {
            "type": [
              "null",
              "string"
            ]
          },
          "preferredDiscipline": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Discipline"
              }
            ]
          },
          "partnerGradeMin": {
            "type": [
              "null",
              "string"
            ]
          },
          "partnerGradeMax": {
            "type": [
              "null",
              "string"
            ]
          },
          "maxBoulderGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "maxLeadGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "distanceKm": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          }
        }
      },
      "PostDto": {
        "required": [
          "id",
          "authorId",
          "authorName",
          "authorAvatarUrl",
          "type",
          "content",
          "media",
          "gymName",
          "likesCount",
          "commentsCount",
          "likedByMe",
          "createdAt",
          "ascent"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "authorId": {
            "type": "string",
            "format": "uuid"
          },
          "authorName": {
            "type": "string"
          },
          "authorAvatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "$ref": "#/components/schemas/PostType"
          },
          "content": {
            "type": [
              "null",
              "string"
            ]
          },
          "media": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "gymName": {
            "type": [
              "null",
              "string"
            ]
          },
          "likesCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "commentsCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "likedByMe": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "ascent": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/FeedAscentDto"
              }
            ]
          }
        }
      },
      "PostMediaUploadResponse": {
        "required": [
          "url"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          }
        }
      },
      "PostType": {
        "type": "integer"
      },
      "PostVisibility": {
        "type": "integer"
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": [
              "null",
              "string"
            ]
          },
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "status": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "detail": {
            "type": [
              "null",
              "string"
            ]
          },
          "instance": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "ProfileDto": {
        "required": [
          "userId",
          "displayName",
          "email",
          "avatarUrl",
          "bio",
          "weightKg",
          "heightCm",
          "climbingSince",
          "preferredDiscipline",
          "maxBoulderGrade",
          "maxLeadGrade",
          "city",
          "country",
          "isPublic"
        ],
        "type": "object",
        "properties": {
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "avatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "bio": {
            "type": [
              "null",
              "string"
            ]
          },
          "weightKg": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "heightCm": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "climbingSince": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "preferredDiscipline": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Discipline"
              }
            ]
          },
          "maxBoulderGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "maxLeadGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "city": {
            "type": [
              "null",
              "string"
            ]
          },
          "country": {
            "type": [
              "null",
              "string"
            ]
          },
          "isPublic": {
            "type": "boolean"
          }
        }
      },
      "ProtocolStepDto": {
        "required": [
          "name",
          "workSec",
          "restSec",
          "reps",
          "sets",
          "grip",
          "edgeMm",
          "notes"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "workSec": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "restSec": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "reps": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "sets": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "grip": {
            "type": [
              "null",
              "string"
            ]
          },
          "edgeMm": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "PushTokenDto": {
        "required": [
          "id",
          "platform",
          "deviceName",
          "appVersion",
          "isActive",
          "lastUsedAt",
          "createdAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "platform": {
            "type": "string"
          },
          "deviceName": {
            "type": [
              "null",
              "string"
            ]
          },
          "appVersion": {
            "type": [
              "null",
              "string"
            ]
          },
          "isActive": {
            "type": "boolean"
          },
          "lastUsedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RefreshRequest": {
        "required": [
          "refreshToken"
        ],
        "type": "object",
        "properties": {
          "refreshToken": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "description": "Exchange a refresh token for a fresh access token (and a rotated refresh token).\n    Browser clients may omit the body and rely on the HttpOnly refresh cookie."
      },
      "RegisterPushTokenRequest": {
        "required": [
          "token",
          "platform",
          "deviceName",
          "appVersion"
        ],
        "type": "object",
        "properties": {
          "token": {
            "type": "string"
          },
          "platform": {
            "type": "string"
          },
          "deviceName": {
            "type": [
              "null",
              "string"
            ]
          },
          "appVersion": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "RegisterRequest": {
        "required": [
          "email",
          "password",
          "displayName"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "password": {
            "type": "string"
          },
          "displayName": {
            "type": "string"
          }
        }
      },
      "RegisterResponse": {
        "required": [
          "requiresVerification",
          "auth",
          "devVerificationToken"
        ],
        "type": "object",
        "properties": {
          "requiresVerification": {
            "type": "boolean"
          },
          "auth": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AuthResponse"
              }
            ]
          },
          "devVerificationToken": {
            "type": [
              "null",
              "string"
            ]
          }
        },
        "description": "Result of registration. When `RequiresVerification` is true the account exists\n    but cannot sign in until the email is confirmed, so `Auth` is null. Otherwise the user is\n    logged in immediately. `DevVerificationToken` is only populated in Development without SMTP."
      },
      "ResendVerificationRequest": {
        "required": [
          "email"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          }
        }
      },
      "ResendVerificationResponse": {
        "required": [
          "sent",
          "devToken"
        ],
        "type": "object",
        "properties": {
          "sent": {
            "type": "boolean"
          },
          "devToken": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "ResetPasswordRequest": {
        "required": [
          "email",
          "token",
          "newPassword"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "token": {
            "type": "string"
          },
          "newPassword": {
            "type": "string"
          }
        }
      },
      "RouteByQrDto": {
        "required": [
          "id",
          "gymId",
          "gymName",
          "name",
          "grade",
          "gradeSystem",
          "sectorName",
          "wallName",
          "isActive"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "gymId": {
            "type": "string",
            "format": "uuid"
          },
          "gymName": {
            "type": "string"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "grade": {
            "type": "string"
          },
          "gradeSystem": {
            "$ref": "#/components/schemas/GradeSystem"
          },
          "sectorName": {
            "type": "string"
          },
          "wallName": {
            "type": [
              "null",
              "string"
            ]
          },
          "isActive": {
            "type": "boolean"
          }
        },
        "description": "Minimal route info resolved from a QR token."
      },
      "RouteDetailDto": {
        "required": [
          "id",
          "name",
          "grade",
          "gradeSystem",
          "discipline",
          "color",
          "description",
          "setterNotes",
          "sectorId",
          "sectorName",
          "wallId",
          "wallName",
          "setterId",
          "setterName",
          "setAt",
          "removedAt",
          "plannedStripAt",
          "expectedAttempts",
          "isActive",
          "isFeatured",
          "ascentCount",
          "averageRating",
          "averageGradeOpinion",
          "tags",
          "myAscent"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "grade": {
            "type": "string"
          },
          "gradeSystem": {
            "$ref": "#/components/schemas/GradeSystem"
          },
          "discipline": {
            "$ref": "#/components/schemas/Discipline"
          },
          "color": {
            "type": [
              "null",
              "string"
            ]
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "setterNotes": {
            "type": [
              "null",
              "string"
            ]
          },
          "sectorId": {
            "type": "string",
            "format": "uuid"
          },
          "sectorName": {
            "type": "string"
          },
          "wallId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "wallName": {
            "type": [
              "null",
              "string"
            ]
          },
          "setterId": {
            "type": "string",
            "format": "uuid"
          },
          "setterName": {
            "type": "string"
          },
          "setAt": {
            "type": "string",
            "format": "date"
          },
          "removedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "plannedStripAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "expectedAttempts": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "isActive": {
            "type": "boolean"
          },
          "isFeatured": {
            "type": "boolean"
          },
          "ascentCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "averageRating": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "averageGradeOpinion": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "myAscent": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/AscentDto"
              }
            ]
          }
        }
      },
      "RouteFeedbackDto": {
        "required": [
          "id",
          "userId",
          "userName",
          "userAvatarUrl",
          "gradeOpinion",
          "qualityRating",
          "comment",
          "createdAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "userName": {
            "type": "string"
          },
          "userAvatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "gradeOpinion": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "qualityRating": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "comment": {
            "type": [
              "null",
              "string"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RouteFeedbackSummaryDto": {
        "required": [
          "averageRating",
          "averageGradeOpinion",
          "count",
          "myFeedback",
          "comments"
        ],
        "type": "object",
        "properties": {
          "averageRating": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "averageGradeOpinion": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "count": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "myFeedback": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/RouteFeedbackDto"
              }
            ]
          },
          "comments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RouteFeedbackDto"
            }
          }
        },
        "description": "Aggregate feedback for a route plus the caller's own entry."
      },
      "RouteListItem": {
        "required": [
          "id",
          "name",
          "grade",
          "gradeSystem",
          "discipline",
          "color",
          "sectorId",
          "sectorName",
          "wallId",
          "wallName",
          "setterName",
          "setAt",
          "plannedStripAt",
          "isActive",
          "isFeatured",
          "ascentCount",
          "averageRating"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "grade": {
            "type": "string"
          },
          "gradeSystem": {
            "$ref": "#/components/schemas/GradeSystem"
          },
          "discipline": {
            "$ref": "#/components/schemas/Discipline"
          },
          "color": {
            "type": [
              "null",
              "string"
            ]
          },
          "sectorId": {
            "type": "string",
            "format": "uuid"
          },
          "sectorName": {
            "type": "string"
          },
          "wallId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "wallName": {
            "type": [
              "null",
              "string"
            ]
          },
          "setterName": {
            "type": "string"
          },
          "setAt": {
            "type": "string",
            "format": "date"
          },
          "plannedStripAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "isActive": {
            "type": "boolean"
          },
          "isFeatured": {
            "type": "boolean"
          },
          "ascentCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "averageRating": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          }
        }
      },
      "RouteMediaDto": {
        "required": [
          "id",
          "routeId",
          "uploadedById",
          "uploadedByName",
          "type",
          "url",
          "thumbnailUrl",
          "caption",
          "isOfficial",
          "sortOrder",
          "createdAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "routeId": {
            "type": "string",
            "format": "uuid"
          },
          "uploadedById": {
            "type": "string",
            "format": "uuid"
          },
          "uploadedByName": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "thumbnailUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "caption": {
            "type": [
              "null",
              "string"
            ]
          },
          "isOfficial": {
            "type": "boolean"
          },
          "sortOrder": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RouteRequest": {
        "required": [
          "name",
          "grade",
          "gradeSystem",
          "discipline",
          "color",
          "description",
          "setterNotes",
          "sectorId",
          "wallId",
          "setterId",
          "setAt",
          "plannedStripAt",
          "expectedAttempts",
          "isActive",
          "isFeatured",
          "tags"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "grade": {
            "type": "string"
          },
          "gradeSystem": {
            "$ref": "#/components/schemas/GradeSystem"
          },
          "discipline": {
            "$ref": "#/components/schemas/Discipline"
          },
          "color": {
            "type": [
              "null",
              "string"
            ]
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "setterNotes": {
            "type": [
              "null",
              "string"
            ]
          },
          "sectorId": {
            "type": "string",
            "format": "uuid"
          },
          "wallId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "setterId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "setAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "plannedStripAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "expectedAttempts": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "isActive": {
            "type": "boolean"
          },
          "isFeatured": {
            "type": "boolean"
          },
          "tags": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "type": "string"
            }
          }
        }
      },
      "SaveSprayRouteRequest": {
        "required": [
          "name",
          "grade",
          "gradeSystem",
          "color",
          "description",
          "holds"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "grade": {
            "type": "string"
          },
          "gradeSystem": {
            "$ref": "#/components/schemas/GradeSystem"
          },
          "color": {
            "type": [
              "null",
              "string"
            ]
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "holds": {
            "type": [
              "null",
              "array"
            ],
            "items": {
              "$ref": "#/components/schemas/SprayHoldDto"
            }
          }
        }
      },
      "SectorDto": {
        "required": [
          "id",
          "name",
          "description",
          "type",
          "color",
          "sortOrder",
          "isActive",
          "wallCount",
          "routeCount"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "$ref": "#/components/schemas/SectorType"
          },
          "color": {
            "type": [
              "null",
              "string"
            ]
          },
          "sortOrder": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "isActive": {
            "type": "boolean"
          },
          "wallCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "routeCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        }
      },
      "SectorRequest": {
        "required": [
          "name",
          "description",
          "type",
          "color",
          "sortOrder",
          "isActive"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "$ref": "#/components/schemas/SectorType"
          },
          "color": {
            "type": [
              "null",
              "string"
            ]
          },
          "sortOrder": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "isActive": {
            "type": "boolean"
          }
        }
      },
      "SectorType": {
        "type": "integer"
      },
      "SendChatMessageRequest": {
        "required": [
          "body"
        ],
        "type": "object",
        "properties": {
          "body": {
            "type": "string"
          }
        }
      },
      "SendTestPushRequest": {
        "required": [
          "title",
          "body"
        ],
        "type": "object",
        "properties": {
          "title": {
            "type": [
              "null",
              "string"
            ]
          },
          "body": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "SpeedRunDto": {
        "required": [
          "id",
          "userId",
          "displayName",
          "timeSeconds",
          "isValid",
          "invalidationReason",
          "finishedAt",
          "competitionId"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "timeSeconds": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "isValid": {
            "type": "boolean"
          },
          "invalidationReason": {
            "type": [
              "null",
              "string"
            ]
          },
          "finishedAt": {
            "type": "string",
            "format": "date-time"
          },
          "competitionId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          }
        }
      },
      "SpeedRunLeaderboardDto": {
        "required": [
          "rank",
          "userId",
          "displayName",
          "avatarUrl",
          "bestTimeSeconds",
          "runCount",
          "achievedAt"
        ],
        "type": "object",
        "properties": {
          "rank": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "userId": {
            "type": "string",
            "format": "uuid"
          },
          "displayName": {
            "type": "string"
          },
          "avatarUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "bestTimeSeconds": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "runCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "achievedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SprayHoldDto": {
        "required": [
          "x",
          "y",
          "role"
        ],
        "type": "object",
        "properties": {
          "x": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "y": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "number",
              "string"
            ],
            "format": "double"
          },
          "role": {
            "type": "string"
          }
        },
        "description": "A marked hold: x/y normalized to 0..1 over the photo, plus its role."
      },
      "SprayRouteDto": {
        "required": [
          "id",
          "sprayWallId",
          "name",
          "grade",
          "gradeSystem",
          "color",
          "description",
          "setterId",
          "setterName",
          "holds",
          "createdAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "sprayWallId": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "grade": {
            "type": "string"
          },
          "gradeSystem": {
            "$ref": "#/components/schemas/GradeSystem"
          },
          "color": {
            "type": [
              "null",
              "string"
            ]
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "setterId": {
            "type": "string",
            "format": "uuid"
          },
          "setterName": {
            "type": "string"
          },
          "holds": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SprayHoldDto"
            }
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SprayWallDto": {
        "required": [
          "id",
          "name",
          "photoUrl",
          "thumbnailUrl",
          "photoWidth",
          "photoHeight",
          "routeCount",
          "createdAt"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "photoUrl": {
            "type": "string"
          },
          "thumbnailUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "photoWidth": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "photoHeight": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "routeCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "StartChatRequest": {
        "required": [
          "otherUserId"
        ],
        "type": "object",
        "properties": {
          "otherUserId": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "SwipeRequest": {
        "required": [
          "targetUserId",
          "like"
        ],
        "type": "object",
        "properties": {
          "targetUserId": {
            "type": "string",
            "format": "uuid"
          },
          "like": {
            "type": "boolean"
          }
        }
      },
      "SwipeResultDto": {
        "required": [
          "matchId",
          "status",
          "isMatch",
          "chatRoomId"
        ],
        "type": "object",
        "properties": {
          "matchId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string"
          },
          "isMatch": {
            "type": "boolean"
          },
          "chatRoomId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          }
        },
        "description": "Outcome of a swipe: whether it produced a mutual match + chat."
      },
      "SwitchGymRequest": {
        "required": [
          "gymId"
        ],
        "type": "object",
        "properties": {
          "gymId": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "TrainingProtocolDto": {
        "required": [
          "id",
          "boardType",
          "name",
          "description",
          "level",
          "durationMinutes",
          "isSystem",
          "gymId",
          "steps"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "boardType": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "level": {
            "type": "string"
          },
          "durationMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "isSystem": {
            "type": "boolean"
          },
          "gymId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          },
          "steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProtocolStepDto"
            }
          }
        }
      },
      "TrainingSessionDto": {
        "required": [
          "id",
          "type",
          "name",
          "startedAt",
          "endedAt",
          "durationMinutes",
          "notes",
          "rpe",
          "exercises",
          "gymId"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "startedAt": {
            "type": "string",
            "format": "date-time"
          },
          "endedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "durationMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ]
          },
          "rpe": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "exercises": {
            "type": [
              "null",
              "string"
            ]
          },
          "gymId": {
            "type": [
              "null",
              "string"
            ],
            "format": "uuid"
          }
        }
      },
      "TwoFactorChallengeRequest": {
        "required": [
          "email",
          "twoFactorToken",
          "code"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "twoFactorToken": {
            "type": "string"
          },
          "code": {
            "type": "string"
          }
        }
      },
      "TwoFactorDisableRequest": {
        "required": [
          "code"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          }
        }
      },
      "TwoFactorEnrollResponse": {
        "required": [
          "sharedKey",
          "otpauthUri"
        ],
        "type": "object",
        "properties": {
          "sharedKey": {
            "type": "string"
          },
          "otpauthUri": {
            "type": "string"
          }
        },
        "description": "Authenticator enrollment material: the Base32 shared key plus the\n    `otpauth://` URI to load into a TOTP app (QR-encodable client-side)."
      },
      "TwoFactorStatusResponse": {
        "required": [
          "enabled",
          "recoveryCodesLeft"
        ],
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "recoveryCodesLeft": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        }
      },
      "TwoFactorVerifyRequest": {
        "required": [
          "code"
        ],
        "type": "object",
        "properties": {
          "code": {
            "type": "string"
          }
        }
      },
      "TwoFactorVerifyResponse": {
        "required": [
          "enabled",
          "recoveryCodes"
        ],
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean"
          },
          "recoveryCodes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "description": "Returned once when TOTP is enabled: store the recovery codes safely, they are not retrievable later."
      },
      "UpdateGroupRequest": {
        "required": [
          "name",
          "description",
          "type",
          "isPrivate",
          "maxMembers"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "type": {
            "type": "string"
          },
          "isPrivate": {
            "type": "boolean"
          },
          "maxMembers": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          }
        }
      },
      "UpdateGymRequest": {
        "required": [
          "name",
          "slug",
          "description",
          "address",
          "city",
          "country",
          "phone",
          "email",
          "website",
          "latitude",
          "longitude"
        ],
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": [
              "null",
              "string"
            ]
          },
          "address": {
            "type": "string"
          },
          "city": {
            "type": "string"
          },
          "country": {
            "type": "string"
          },
          "phone": {
            "type": [
              "null",
              "string"
            ]
          },
          "email": {
            "type": [
              "null",
              "string"
            ]
          },
          "website": {
            "type": [
              "null",
              "string"
            ]
          },
          "latitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "longitude": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?(?:[eE][+-]?\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          }
        }
      },
      "UpdateLocaleRequest": {
        "required": [
          "locale"
        ],
        "type": "object",
        "properties": {
          "locale": {
            "type": "string"
          }
        }
      },
      "UpdateLocaleResponse": {
        "required": [
          "locale"
        ],
        "type": "object",
        "properties": {
          "locale": {
            "type": "string"
          }
        }
      },
      "UpdateMatchPreferencesRequest": {
        "required": [
          "lookingFor",
          "skillRange",
          "maxDistanceKm",
          "bio",
          "isActive"
        ],
        "type": "object",
        "properties": {
          "lookingFor": {
            "type": "string"
          },
          "skillRange": {
            "type": "string"
          },
          "maxDistanceKm": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "bio": {
            "type": [
              "null",
              "string"
            ]
          },
          "isActive": {
            "type": "boolean"
          }
        }
      },
      "UpdatePartnerPrefsRequest": {
        "required": [
          "lookingForPartner",
          "partnerGradeMin",
          "partnerGradeMax",
          "availabilityJson"
        ],
        "type": "object",
        "properties": {
          "lookingForPartner": {
            "type": "boolean"
          },
          "partnerGradeMin": {
            "type": [
              "null",
              "string"
            ]
          },
          "partnerGradeMax": {
            "type": [
              "null",
              "string"
            ]
          },
          "availabilityJson": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "UpdateProfileRequest": {
        "required": [
          "displayName",
          "bio",
          "weightKg",
          "heightCm",
          "climbingSince",
          "preferredDiscipline",
          "maxBoulderGrade",
          "maxLeadGrade",
          "city",
          "country",
          "isPublic"
        ],
        "type": "object",
        "properties": {
          "displayName": {
            "type": "string"
          },
          "bio": {
            "type": [
              "null",
              "string"
            ]
          },
          "weightKg": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "heightCm": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "climbingSince": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          },
          "preferredDiscipline": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/Discipline"
              }
            ]
          },
          "maxBoulderGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "maxLeadGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "city": {
            "type": [
              "null",
              "string"
            ]
          },
          "country": {
            "type": [
              "null",
              "string"
            ]
          },
          "isPublic": {
            "type": "boolean"
          }
        }
      },
      "UpdateTrainingSessionRequest": {
        "required": [
          "type",
          "name",
          "startedAt",
          "endedAt",
          "durationMinutes",
          "notes",
          "rpe",
          "exercises"
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": "string"
          },
          "name": {
            "type": [
              "null",
              "string"
            ]
          },
          "startedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "endedAt": {
            "type": [
              "null",
              "string"
            ],
            "format": "date-time"
          },
          "durationMinutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "notes": {
            "type": [
              "null",
              "string"
            ]
          },
          "rpe": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "exercises": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "UpdateUserSettingsRequest": {
        "required": [
          "pushNotifications",
          "emailNotifications",
          "language",
          "units",
          "showInMatching",
          "privacySettings"
        ],
        "type": "object",
        "properties": {
          "pushNotifications": {
            "type": "boolean"
          },
          "emailNotifications": {
            "type": "boolean"
          },
          "language": {
            "type": "string"
          },
          "units": {
            "type": "string"
          },
          "showInMatching": {
            "type": "boolean"
          },
          "privacySettings": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "UpsertRouteFeedbackRequest": {
        "required": [
          "gradeOpinion",
          "qualityRating",
          "comment"
        ],
        "type": "object",
        "properties": {
          "gradeOpinion": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "qualityRating": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "comment": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "UserSettingsDto": {
        "required": [
          "pushNotifications",
          "emailNotifications",
          "language",
          "units",
          "showInMatching",
          "privacySettings"
        ],
        "type": "object",
        "properties": {
          "pushNotifications": {
            "type": "boolean"
          },
          "emailNotifications": {
            "type": "boolean"
          },
          "language": {
            "type": "string"
          },
          "units": {
            "type": "string"
          },
          "showInMatching": {
            "type": "boolean"
          },
          "privacySettings": {
            "type": [
              "null",
              "string"
            ]
          }
        }
      },
      "UserStatsDto": {
        "required": [
          "totalAscents",
          "totalRoutes",
          "flashCount",
          "highestBoulderGrade",
          "highestLeadGrade",
          "currentStreakDays",
          "longestStreakDays",
          "lastClimbDate"
        ],
        "type": "object",
        "properties": {
          "totalAscents": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "totalRoutes": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "flashCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "highestBoulderGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "highestLeadGrade": {
            "type": [
              "null",
              "string"
            ]
          },
          "currentStreakDays": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "longestStreakDays": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "lastClimbDate": {
            "type": [
              "null",
              "string"
            ],
            "format": "date"
          }
        }
      },
      "VerifyEmailRequest": {
        "required": [
          "email",
          "token"
        ],
        "type": "object",
        "properties": {
          "email": {
            "type": "string"
          },
          "token": {
            "type": "string"
          }
        }
      },
      "WallAngle": {
        "type": "integer"
      },
      "WallDto": {
        "required": [
          "id",
          "sectorId",
          "sectorName",
          "name",
          "angle",
          "angleDegrees",
          "heightMeters",
          "imageUrl",
          "sortOrder",
          "isActive",
          "routeCount"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "sectorId": {
            "type": "string",
            "format": "uuid"
          },
          "sectorName": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "angle": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/WallAngle"
              }
            ]
          },
          "angleDegrees": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "heightMeters": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "imageUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "sortOrder": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "isActive": {
            "type": "boolean"
          },
          "routeCount": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          }
        }
      },
      "WallRequest": {
        "required": [
          "sectorId",
          "name",
          "angle",
          "angleDegrees",
          "heightMeters",
          "imageUrl",
          "sortOrder",
          "isActive"
        ],
        "type": "object",
        "properties": {
          "sectorId": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "angle": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/WallAngle"
              }
            ]
          },
          "angleDegrees": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "null",
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "heightMeters": {
            "pattern": "^-?(?:0|[1-9]\\d*)(?:\\.\\d+)?$",
            "type": [
              "null",
              "number",
              "string"
            ],
            "format": "double"
          },
          "imageUrl": {
            "type": [
              "null",
              "string"
            ]
          },
          "sortOrder": {
            "pattern": "^-?(?:0|[1-9]\\d*)$",
            "type": [
              "integer",
              "string"
            ],
            "format": "int32"
          },
          "isActive": {
            "type": "boolean"
          }
        }
      }
    },
    "securitySchemes": {
      "Bearer": {
        "type": "http",
        "description": "JWT issued by /api/auth/login. Mobile and programmatic clients send `Authorization: Bearer <jwt>`.",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      },
      "Cookie": {
        "type": "apiKey",
        "description": "HttpOnly session cookie set by /api/auth/login. Browser-only.",
        "name": "climbup_auth",
        "in": "cookie"
      },
      "CsrfToken": {
        "type": "apiKey",
        "description": "Antiforgery token from /api/auth/csrf; required on POST/PUT/PATCH/DELETE from cookie callers.",
        "name": "X-CSRF-Token",
        "in": "header"
      }
    }
  },
  "tags": [
    {
      "name": "ClimbUp.Api.App"
    },
    {
      "name": "Ascents"
    },
    {
      "name": "Feed"
    },
    {
      "name": "Groups"
    },
    {
      "name": "Training"
    },
    {
      "name": "TrainingProtocols"
    },
    {
      "name": "Auth"
    },
    {
      "name": "Chats"
    },
    {
      "name": "Follow"
    },
    {
      "name": "Gyms"
    },
    {
      "name": "Matches"
    },
    {
      "name": "Notifications"
    },
    {
      "name": "Partners"
    },
    {
      "name": "Profile"
    },
    {
      "name": "PushTokens"
    },
    {
      "name": "Routes"
    },
    {
      "name": "Sectors"
    },
    {
      "name": "Settings"
    },
    {
      "name": "SpeedRuns"
    },
    {
      "name": "SprayWalls"
    },
    {
      "name": "Walls"
    }
  ]
}