{
  "openapi": "3.0.0",
  "info": {
    "title": "UOMysticmoon API",
    "version": "1.0.0",
    "description": "REST API for the UOMysticmoon website, wiki and admin panel — a private Ultima Online shard.\n\n### Authentication\n- **Web / admin panel** uses an httpOnly session cookie (`uomm_token`) issued by `POST /api/v1/auth/login` (plus `/login/totp` when 2FA is enabled).\n- **Native / mobile clients** use bearer access tokens from `POST /api/v1/auth/mobile/login`, refreshed via `/auth/mobile/refresh`.\n\nEndpoints under `/api/v1/admin/**` require a valid session; some are further restricted to the `admin` role (editors are limited to content)."
  },
  "servers": [
    {
      "url": "/",
      "description": "Same-origin (current host)"
    },
    {
      "url": "http://localhost:3000",
      "description": "Local development"
    }
  ],
  "tags": [
    {
      "name": "Health",
      "description": "Liveness probe"
    },
    {
      "name": "Auth",
      "description": "Web session login/logout (cookie + TOTP)"
    },
    {
      "name": "Auth · Mobile",
      "description": "Native bearer-token login, refresh and logout"
    },
    {
      "name": "Auth · SSO",
      "description": "OAuth2 / OIDC provider discovery and redirect flow"
    },
    {
      "name": "Public",
      "description": "Unauthenticated site content (settings, posts, wiki, contact)"
    },
    {
      "name": "Admin · Account",
      "description": "Self-service account security (2FA, linked identities)"
    },
    {
      "name": "Admin · Dashboard",
      "description": "Dashboard summary and site mode"
    },
    {
      "name": "Admin · Posts",
      "description": "News / five-on-friday / newsletter / screenshots + uploads"
    },
    {
      "name": "Admin · Wiki",
      "description": "Wiki pages, categories, tags and revisions"
    },
    {
      "name": "Admin · Settings",
      "description": "Site settings (admin only)"
    },
    {
      "name": "Admin · Activity",
      "description": "Admin activity log"
    },
    {
      "name": "Admin · Bot Activity",
      "description": "Bot-scoring/ban state and emergency unban (admin only)"
    },
    {
      "name": "Admin · Auth Providers",
      "description": "SSO provider configuration (admin only)"
    },
    {
      "name": "Admin · Users",
      "description": "User management (admin only)"
    }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "tags": [
          "Health"
        ],
        "summary": "Liveness probe",
        "description": "",
        "responses": {
          "200": {
            "description": "Service is up",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "ok"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/login": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Log in with username and password",
        "description": "On success sets the httpOnly session cookie. If the account has 2FA enabled, returns { totpRequired, challenge } instead and no cookie is set — complete login at POST /login/totp. Rate limited and behind bot/backoff guards.",
        "responses": {
          "200": {
            "description": "Session issued, or TOTP challenge required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Incorrect username or password",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts (rate limited / backoff)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/login/totp": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Complete login with a TOTP code",
        "description": "Second step for 2FA accounts. Exchange the challenge from /login plus the current authenticator code for a session cookie.",
        "responses": {
          "200": {
            "description": "Session issued",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LoginResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Invalid code or expired challenge",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts (rate limited / backoff)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TotpLoginRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/logout": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Log out (clear the session cookie)",
        "description": "",
        "responses": {
          "200": {
            "description": "Logged out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/me": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Current authenticated user",
        "description": "",
        "responses": {
          "200": {
            "description": "The signed-in user",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "$ref": "#/components/schemas/User"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/auth/mobile/login": {
      "post": {
        "tags": [
          "Auth · Mobile"
        ],
        "summary": "Native login → access + refresh tokens",
        "description": "Bearer-token login for native clients. Single-request 2FA: if the account has TOTP on and no/invalid code is supplied, returns 401 { totpRequired: true } and the client retries with a code.",
        "responses": {
          "200": {
            "description": "Access + refresh tokens",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MobileTokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials, or a TOTP code is required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts (rate limited / backoff)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MobileLoginRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/mobile/refresh": {
      "post": {
        "tags": [
          "Auth · Mobile"
        ],
        "summary": "Rotate a refresh token for a fresh token pair",
        "description": "Refresh tokens are single-use: the presented token is revoked and a new access + refresh pair is issued. Reusing a rotated token fails with 401.",
        "responses": {
          "200": {
            "description": "New access + refresh tokens",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MobileTokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or expired session",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many refresh attempts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MobileRefreshRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/mobile/logout": {
      "post": {
        "tags": [
          "Auth · Mobile"
        ],
        "summary": "Revoke the current (or all) refresh tokens",
        "description": "Requires a valid bearer access token. Revokes the given refresh token, or every session for the user when { all: true }. Idempotent.",
        "responses": {
          "200": {
            "description": "Logged out",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Missing or invalid bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MobileLogoutRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/providers": {
      "get": {
        "tags": [
          "Auth · SSO"
        ],
        "summary": "List enabled SSO providers",
        "description": "Public discovery used by the login page to render provider buttons. Never exposes secrets.",
        "responses": {
          "200": {
            "description": "Enabled, valid providers",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Provider"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        }
      }
    },
    "/api/v1/auth/sso/{provider}/start": {
      "get": {
        "tags": [
          "Auth · SSO"
        ],
        "summary": "Begin SSO login (redirect to the IdP)",
        "description": "Sets a short-lived signed transaction cookie and 302-redirects to the provider authorize URL. On error redirects back to the login page with an sso_error query param.",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider id (e.g. google, discord)."
          },
          {
            "name": "returnTo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Internal /admin path to return to after login."
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to the identity provider (or back to the login page on error)"
          }
        }
      }
    },
    "/api/v1/auth/sso/{provider}/link": {
      "get": {
        "tags": [
          "Auth · SSO"
        ],
        "summary": "Begin linking an SSO identity to the current account",
        "description": "Requires an authenticated session; the signed transaction captures the acting user so the callback can attach the external identity.",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider id (e.g. google, discord)."
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to the identity provider (or back to the account page on error)"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/auth/sso/{provider}/callback": {
      "get": {
        "tags": [
          "Auth · SSO"
        ],
        "summary": "OAuth redirect target — completes login or linking",
        "description": "The provider redirects here with code + state. On success sets the session cookie (login) or links the identity (link), then 302-redirects into /admin. Login is link-only: unknown identities are refused (sso_error=not_linked).",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider id (e.g. google, discord)."
          },
          {
            "name": "error",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "OAuth authorization code."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "OAuth state (matched against the tx cookie)."
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect into /admin on success, or back to login/account with an error code"
          }
        }
      }
    },
    "/api/v1/public/settings": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Public site settings",
        "description": "Whitelisted, non-sensitive settings the client needs to render the site.",
        "responses": {
          "200": {
            "description": "Key/value settings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        }
      }
    },
    "/api/v1/public/status": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Site mode / status",
        "description": "Current site mode (live or maintenance) so the client can show the maintenance page.",
        "responses": {
          "200": {
            "description": "Site status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "type": "string",
                      "example": "live"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        }
      }
    },
    "/api/v1/public/contact": {
      "post": {
        "tags": [
          "Public"
        ],
        "summary": "Send a contact message",
        "description": "Emails the site owner (or falls back to a mailto). Rate limited.",
        "responses": {
          "200": {
            "description": "Message sent",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Too many messages (rate limited)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "Mail delivery failed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/public/posts/{category}": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "List published posts in a category",
        "description": "Gated by site mode: during maintenance only admins with a valid session see content.",
        "parameters": [
          {
            "name": "category",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "news | five-on-friday | newsletter | screenshots"
          }
        ],
        "responses": {
          "200": {
            "description": "Published posts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Post"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Unknown category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/public/posts/{category}/{idOrSlug}": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Get a single published post",
        "description": "",
        "parameters": [
          {
            "name": "category",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Post category."
          },
          {
            "name": "idOrSlug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Numeric id or slug."
          }
        ],
        "responses": {
          "200": {
            "description": "The post",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Post"
                }
              }
            }
          },
          "404": {
            "description": "Unknown category or post not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/public/wiki": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "List published wiki pages",
        "description": "",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Published wiki pages",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WikiPage"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/public/wiki/categories": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "List wiki categories",
        "description": "",
        "responses": {
          "200": {
            "description": "Wiki categories",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WikiCategory"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/public/wiki/tags": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "List wiki tags",
        "description": "",
        "responses": {
          "200": {
            "description": "Wiki tags",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/public/wiki/{slug}": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Get a single published wiki page",
        "description": "",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wiki page slug."
          }
        ],
        "responses": {
          "200": {
            "description": "The wiki page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikiPage"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          },
          "503": {
            "description": "Service Unavailable"
          }
        }
      }
    },
    "/api/v1/admin/account": {
      "get": {
        "tags": [
          "Admin · Account"
        ],
        "summary": "Get the current account (self)",
        "description": "",
        "responses": {
          "200": {
            "description": "The account",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/account/totp/setup": {
      "post": {
        "tags": [
          "Admin · Account"
        ],
        "summary": "Begin 2FA enrollment (returns secret + QR)",
        "description": "",
        "responses": {
          "200": {
            "description": "otpauth URL and QR data to scan",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "otpauth_url": {
                      "type": "string"
                    },
                    "qr": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Two-factor already enabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/account/totp/enable": {
      "post": {
        "tags": [
          "Admin · Account"
        ],
        "summary": "Enable 2FA by confirming a code",
        "description": "",
        "responses": {
          "200": {
            "description": "2FA enabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Setup not started, or invalid code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Two-factor already enabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TotpCodeRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/account/totp/disable": {
      "post": {
        "tags": [
          "Admin · Account"
        ],
        "summary": "Disable 2FA by confirming a code",
        "description": "",
        "responses": {
          "200": {
            "description": "2FA disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Not enabled, or invalid code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TotpCodeRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/account/identities": {
      "get": {
        "tags": [
          "Admin · Account"
        ],
        "summary": "List linked SSO identities (self)",
        "description": "",
        "responses": {
          "200": {
            "description": "Linked identities",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "provider": {
                        "type": "string"
                      },
                      "email": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/account/identities/{provider}": {
      "delete": {
        "tags": [
          "Admin · Account"
        ],
        "summary": "Unlink an SSO identity (self)",
        "description": "",
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider id."
          }
        ],
        "responses": {
          "200": {
            "description": "Unlinked",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No linked account for that provider",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/dashboard": {
      "get": {
        "tags": [
          "Admin · Dashboard"
        ],
        "summary": "Dashboard summary counts",
        "description": "",
        "responses": {
          "200": {
            "description": "Summary counts (posts, wiki, users, site mode)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/site-mode": {
      "put": {
        "tags": [
          "Admin · Dashboard"
        ],
        "summary": "Set site mode (admin only)",
        "description": "Switch the site between live and maintenance.",
        "responses": {
          "200": {
            "description": "Updated site mode",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "mode": {
                      "type": "string",
                      "example": "maintenance"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SiteModeRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/posts": {
      "get": {
        "tags": [
          "Admin · Posts"
        ],
        "summary": "List all posts (including unpublished)",
        "description": "",
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Optional category filter."
          }
        ],
        "responses": {
          "200": {
            "description": "Posts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Post"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Admin · Posts"
        ],
        "summary": "Create a post",
        "description": "",
        "responses": {
          "201": {
            "description": "Created post",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Post"
                }
              }
            }
          },
          "400": {
            "description": "Validation error or unknown category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PostCreateRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/posts/upload": {
      "post": {
        "tags": [
          "Admin · Posts"
        ],
        "summary": "Upload a post image (multipart)",
        "description": "",
        "responses": {
          "201": {
            "description": "Stored image URL",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "image_url": {
                      "type": "string",
                      "example": "/uploads/1700000000-abcd.png"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "No image / disallowed type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/uploads": {
      "post": {
        "tags": [
          "Admin · Posts"
        ],
        "summary": "Upload an image for rich-text editors (multipart)",
        "description": "",
        "responses": {
          "201": {
            "description": "Stored file URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadResponse"
                }
              }
            }
          },
          "400": {
            "description": "No file / disallowed type",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "image": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/posts/{id}": {
      "get": {
        "tags": [
          "Admin · Posts"
        ],
        "summary": "Get a post by id",
        "description": "",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Post id."
          }
        ],
        "responses": {
          "200": {
            "description": "The post",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Post"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      },
      "put": {
        "tags": [
          "Admin · Posts"
        ],
        "summary": "Update a post",
        "description": "",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Post id."
          }
        ],
        "responses": {
          "200": {
            "description": "Updated post",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Post"
                }
              }
            }
          },
          "400": {
            "description": "Validation error or unknown category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PostCreateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Admin · Posts"
        ],
        "summary": "Delete a post",
        "description": "",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Post id."
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/posts/{id}/publish": {
      "patch": {
        "tags": [
          "Admin · Posts"
        ],
        "summary": "Publish / unpublish a post",
        "description": "",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Post id."
          }
        ],
        "responses": {
          "200": {
            "description": "Updated post",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Post"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublishRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/wiki/categories": {
      "get": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "List wiki categories",
        "description": "",
        "responses": {
          "200": {
            "description": "Wiki categories",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WikiCategory"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Create a wiki category",
        "description": "",
        "responses": {
          "201": {
            "description": "Created category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikiCategory"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Slug already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WikiCategoryCreateRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/wiki/categories/{id}": {
      "put": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Update a wiki category",
        "description": "",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Category id."
          }
        ],
        "responses": {
          "200": {
            "description": "Updated category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikiCategory"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Slug already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WikiCategoryCreateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Delete a wiki category",
        "description": "",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Category id."
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/wiki/tags": {
      "get": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "List wiki tags",
        "description": "",
        "responses": {
          "200": {
            "description": "Wiki tags",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/wiki": {
      "get": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "List all wiki pages (including unpublished)",
        "description": "",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "category",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Wiki pages",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WikiPage"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Create a wiki page",
        "description": "",
        "responses": {
          "201": {
            "description": "Created wiki page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikiPage"
                }
              }
            }
          },
          "400": {
            "description": "Validation error or unknown category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Slug already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WikiPageCreateRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/wiki/{slug}": {
      "get": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Get a wiki page by slug",
        "description": "",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wiki page slug."
          }
        ],
        "responses": {
          "200": {
            "description": "The wiki page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikiPage"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      },
      "put": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Update a wiki page (creates a revision)",
        "description": "",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wiki page slug."
          }
        ],
        "responses": {
          "200": {
            "description": "Updated wiki page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikiPage"
                }
              }
            }
          },
          "400": {
            "description": "Validation error or unknown category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/WikiPageCreateRequest"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "change_note": {
                        "type": "string",
                        "maxLength": 280
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Delete a wiki page",
        "description": "",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wiki page slug."
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/wiki/{slug}/publish": {
      "patch": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Publish / unpublish a wiki page",
        "description": "",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wiki page slug."
          }
        ],
        "responses": {
          "200": {
            "description": "Updated wiki page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikiPage"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PublishRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/wiki/{slug}/revisions": {
      "get": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "List revisions of a wiki page",
        "description": "",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wiki page slug."
          }
        ],
        "responses": {
          "200": {
            "description": "Revisions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/wiki/{slug}/revisions/{id}": {
      "get": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Get a single wiki revision",
        "description": "",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wiki page slug."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Revision id."
          }
        ],
        "responses": {
          "200": {
            "description": "The revision",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/wiki/{slug}/revisions/{id}/restore": {
      "post": {
        "tags": [
          "Admin · Wiki"
        ],
        "summary": "Restore a wiki page to a revision",
        "description": "",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Wiki page slug."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Revision id to restore."
          }
        ],
        "responses": {
          "200": {
            "description": "Restored wiki page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WikiPage"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request"
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/settings": {
      "get": {
        "tags": [
          "Admin · Settings"
        ],
        "summary": "Get all site settings (admin only)",
        "description": "",
        "responses": {
          "200": {
            "description": "All settings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      },
      "put": {
        "tags": [
          "Admin · Settings"
        ],
        "summary": "Update site settings (admin only)",
        "description": "",
        "responses": {
          "200": {
            "description": "Updated settings",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Body must be an object of key/value settings",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "description": "An object of key/value settings."
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/activity": {
      "get": {
        "tags": [
          "Admin · Activity"
        ],
        "summary": "List recent admin activity",
        "description": "",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Max rows to return."
          }
        ],
        "responses": {
          "200": {
            "description": "Activity entries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/bot-activity": {
      "get": {
        "tags": [
          "Admin · Bot Activity"
        ],
        "summary": "Bot-scoring / ban state and recent events (admin only)",
        "description": "",
        "responses": {
          "200": {
            "description": "Banned IPs, scores and recent events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/bot-activity/unban": {
      "post": {
        "tags": [
          "Admin · Bot Activity"
        ],
        "summary": "Emergency unban an IP (admin only)",
        "description": "",
        "responses": {
          "200": {
            "description": "Unbanned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Invalid IP",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UnbanRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/auth/providers": {
      "get": {
        "tags": [
          "Admin · Auth Providers"
        ],
        "summary": "List configured SSO providers (admin only)",
        "description": "",
        "responses": {
          "200": {
            "description": "Providers (secrets stripped)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ProviderConfig"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Admin · Auth Providers"
        ],
        "summary": "Create a custom SSO provider (admin only)",
        "description": "Built-in providers (google, discord) are configured via PUT, not created here.",
        "responses": {
          "201": {
            "description": "Created provider",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderConfig"
                }
              }
            }
          },
          "400": {
            "description": "Validation error, or a built-in/invalid kind",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Provider id already exists",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderCreateRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/auth/providers/{id}": {
      "put": {
        "tags": [
          "Admin · Auth Providers"
        ],
        "summary": "Update an SSO provider (admin only)",
        "description": "",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider id."
          }
        ],
        "responses": {
          "200": {
            "description": "Updated provider",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderConfig"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Provider not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProviderCreateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Admin · Auth Providers"
        ],
        "summary": "Delete a custom SSO provider (admin only)",
        "description": "Built-in providers cannot be deleted — disable them instead.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Provider id."
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Built-in provider cannot be deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Provider not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    },
    "/api/v1/admin/users": {
      "get": {
        "tags": [
          "Admin · Users"
        ],
        "summary": "List users (admin only)",
        "description": "",
        "responses": {
          "200": {
            "description": "Users",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/User"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      },
      "post": {
        "tags": [
          "Admin · Users"
        ],
        "summary": "Create a user (admin only)",
        "description": "",
        "responses": {
          "201": {
            "description": "Created user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Username already taken",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCreateRequest"
              }
            }
          }
        }
      }
    },
    "/api/v1/admin/users/{id}": {
      "put": {
        "tags": [
          "Admin · Users"
        ],
        "summary": "Update a user (admin only)",
        "description": "",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "User id."
          }
        ],
        "responses": {
          "200": {
            "description": "Updated user",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "400": {
            "description": "Validation error, or cannot demote the last admin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Username already taken",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UserCreateRequest"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Admin · Users"
        ],
        "summary": "Delete a user (admin only)",
        "description": "",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "User id."
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Message"
                }
              }
            }
          },
          "400": {
            "description": "Cannot delete your own account or the last admin",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Admin role required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Internal Server Error"
          }
        },
        "security": [
          {
            "cookieAuth": []
          },
          {
            "bearerAuth": []
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "cookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "uomm_token",
        "description": "Session JWT set as an httpOnly cookie by POST /api/v1/auth/login."
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Access token from POST /api/v1/auth/mobile/login (or /refresh)."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "message": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "Not found"
                  }
                }
              }
            }
          }
        }
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "errors": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "array"
                  },
                  "items": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string",
                        "example": "object"
                      },
                      "properties": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "object",
                            "properties": {
                              "type": {
                                "type": "string",
                                "example": "string"
                              },
                              "example": {
                                "type": "string",
                                "example": "field"
                              }
                            }
                          },
                          "msg": {
                            "type": "object",
                            "properties": {
                              "type": {
                                "type": "string",
                                "example": "string"
                              },
                              "example": {
                                "type": "string",
                                "example": "Invalid value"
                              }
                            }
                          },
                          "path": {
                            "type": "object",
                            "properties": {
                              "type": {
                                "type": "string",
                                "example": "string"
                              },
                              "example": {
                                "type": "string",
                                "example": "username"
                              }
                            }
                          },
                          "location": {
                            "type": "object",
                            "properties": {
                              "type": {
                                "type": "string",
                                "example": "string"
                              },
                              "example": {
                                "type": "string",
                                "example": "body"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "SafeUser": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "example": {
                    "type": "number",
                    "example": 1
                  }
                }
              },
              "username": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "admin"
                  }
                }
              },
              "role": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "enum": {
                    "type": "array",
                    "example": [
                      "admin",
                      "editor"
                    ],
                    "items": {
                      "type": "string"
                    }
                  },
                  "example": {
                    "type": "string",
                    "example": "admin"
                  }
                }
              }
            }
          }
        }
      },
      "LoginRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "username",
              "password"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "username": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "admin"
                  }
                }
              },
              "password": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "password"
                  },
                  "example": {
                    "type": "string",
                    "example": "super-secret"
                  }
                }
              },
              "company": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "description": {
                    "type": "string",
                    "example": "Honeypot — must be empty for humans."
                  },
                  "example": {
                    "type": "string",
                    "example": ""
                  }
                }
              }
            }
          }
        }
      },
      "LoginResponse": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "description": {
            "type": "string",
            "example": "Either a session (user) or, for 2FA accounts, a TOTP challenge to complete at /login/totp."
          },
          "properties": {
            "type": "object",
            "properties": {
              "user": {
                "$ref": "#/components/schemas/SafeUser"
              },
              "totpRequired": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "example": {
                    "type": "boolean",
                    "example": true
                  }
                }
              },
              "challenge": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "description": {
                    "type": "string",
                    "example": "Signed challenge token for the TOTP step."
                  }
                }
              }
            }
          }
        }
      },
      "TotpLoginRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "challenge",
              "code"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "challenge": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "description": {
                    "type": "string",
                    "example": "Token returned by /login when totpRequired."
                  }
                }
              },
              "code": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "123456"
                  }
                }
              }
            }
          }
        }
      },
      "MobileLoginRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "username",
              "password"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "username": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "admin"
                  }
                }
              },
              "password": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "password"
                  },
                  "example": {
                    "type": "string",
                    "example": "super-secret"
                  }
                }
              },
              "code": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "description": {
                    "type": "string",
                    "example": "TOTP code (only when 2FA is enabled)."
                  },
                  "example": {
                    "type": "string",
                    "example": "123456"
                  }
                }
              }
            }
          }
        }
      },
      "MobileTokenResponse": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "accessToken": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "description": {
                    "type": "string",
                    "example": "Short-lived bearer JWT."
                  }
                }
              },
              "refreshToken": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "description": {
                    "type": "string",
                    "example": "Long-lived, revocable refresh token."
                  }
                }
              },
              "expiresIn": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "description": {
                    "type": "string",
                    "example": "Access token lifetime in seconds."
                  },
                  "example": {
                    "type": "number",
                    "example": 900
                  }
                }
              },
              "user": {
                "$ref": "#/components/schemas/SafeUser"
              }
            }
          }
        }
      },
      "MobileRefreshRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "refreshToken"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "refreshToken": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  }
                }
              }
            }
          }
        }
      },
      "MobileLogoutRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "refreshToken": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "description": {
                    "type": "string",
                    "example": "Revoke a single session."
                  }
                }
              },
              "all": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "description": {
                    "type": "string",
                    "example": "Revoke every session for the user."
                  },
                  "example": {
                    "type": "boolean",
                    "example": false
                  }
                }
              }
            }
          }
        }
      },
      "Message": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "message": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "Logged out."
                  }
                }
              }
            }
          }
        }
      },
      "ContactRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "message"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "message": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 5000
                  },
                  "example": {
                    "type": "string",
                    "example": "When does the shard launch?"
                  }
                }
              },
              "email": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "email"
                  },
                  "example": {
                    "type": "string",
                    "example": "player@example.com"
                  }
                }
              },
              "name": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 100
                  },
                  "example": {
                    "type": "string",
                    "example": "Lord British"
                  }
                }
              }
            }
          }
        }
      },
      "Provider": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "google"
                  }
                }
              },
              "name": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "Google"
                  }
                }
              },
              "kind": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "enum": {
                    "type": "array",
                    "example": [
                      "oidc",
                      "oauth2"
                    ],
                    "items": {
                      "type": "string"
                    }
                  },
                  "example": {
                    "type": "string",
                    "example": "oidc"
                  }
                }
              }
            }
          }
        }
      },
      "ProviderConfig": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "okta"
                  }
                }
              },
              "kind": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "enum": {
                    "type": "array",
                    "example": [
                      "oidc",
                      "oauth2"
                    ],
                    "items": {
                      "type": "string"
                    }
                  },
                  "example": {
                    "type": "string",
                    "example": "oidc"
                  }
                }
              },
              "name": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "Okta"
                  }
                }
              },
              "enabled": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "example": {
                    "type": "boolean",
                    "example": true
                  }
                }
              },
              "clientId": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  }
                }
              },
              "authorizeUrl": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "uri"
                  }
                }
              },
              "tokenUrl": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "uri"
                  }
                }
              },
              "userinfoUrl": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "uri"
                  }
                }
              },
              "scopes": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "openid email profile"
                  }
                }
              },
              "priority": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "example": {
                    "type": "number",
                    "example": 10
                  }
                }
              }
            }
          }
        }
      },
      "ProviderCreateRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "id",
              "kind",
              "name"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "pattern": {
                    "type": "string",
                    "example": "^[a-z0-9-]+$"
                  },
                  "example": {
                    "type": "string",
                    "example": "okta"
                  }
                }
              },
              "kind": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "enum": {
                    "type": "array",
                    "example": [
                      "oidc",
                      "oauth2"
                    ],
                    "items": {
                      "type": "string"
                    }
                  },
                  "example": {
                    "type": "string",
                    "example": "oidc"
                  }
                }
              },
              "name": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 80
                  },
                  "example": {
                    "type": "string",
                    "example": "Okta"
                  }
                }
              },
              "enabled": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "example": {
                    "type": "boolean",
                    "example": true
                  }
                }
              },
              "clientId": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  }
                }
              },
              "secret": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "password"
                  }
                }
              },
              "authorizeUrl": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "uri"
                  }
                }
              },
              "tokenUrl": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "uri"
                  }
                }
              },
              "userinfoUrl": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "uri"
                  }
                }
              },
              "scopes": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 500
                  },
                  "example": {
                    "type": "string",
                    "example": "openid email profile"
                  }
                }
              },
              "priority": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "example": {
                    "type": "number",
                    "example": 10
                  }
                }
              }
            }
          }
        }
      },
      "Post": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "example": {
                    "type": "number",
                    "example": 12
                  }
                }
              },
              "category": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "news"
                  }
                }
              },
              "title": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "Server maintenance this weekend"
                  }
                }
              },
              "slug": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "server-maintenance-this-weekend"
                  }
                }
              },
              "body": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  }
                }
              },
              "image_url": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "/uploads/1700000000-abcd.png"
                  }
                }
              },
              "published": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "example": {
                    "type": "boolean",
                    "example": true
                  }
                }
              },
              "created_at": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "date-time"
                  }
                }
              },
              "updated_at": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "date-time"
                  }
                }
              }
            }
          }
        }
      },
      "PostCreateRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "category",
              "title"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "category": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "news"
                  }
                }
              },
              "title": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 200
                  },
                  "example": {
                    "type": "string",
                    "example": "Server maintenance this weekend"
                  }
                }
              },
              "body": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  }
                }
              },
              "image_url": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "description": {
                    "type": "string",
                    "example": "Required for the screenshots category."
                  }
                }
              },
              "published": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "example": {
                    "type": "boolean",
                    "example": false
                  }
                }
              }
            }
          }
        }
      },
      "PublishRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "published"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "published": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "example": {
                    "type": "boolean",
                    "example": true
                  }
                }
              }
            }
          }
        }
      },
      "UploadResponse": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "url": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "/uploads/1700000000-abcd.png"
                  }
                }
              }
            }
          }
        }
      },
      "WikiPage": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "example": {
                    "type": "number",
                    "example": 3
                  }
                }
              },
              "slug": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "getting-started"
                  }
                }
              },
              "title": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "Getting Started"
                  }
                }
              },
              "excerpt": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  }
                }
              },
              "body": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  }
                }
              },
              "category_id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "nullable": {
                    "type": "boolean",
                    "example": true
                  },
                  "example": {
                    "type": "number",
                    "example": 2
                  }
                }
              },
              "published": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "example": {
                    "type": "boolean",
                    "example": true
                  }
                }
              },
              "tags": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "array"
                  },
                  "items": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string",
                        "example": "string"
                      }
                    }
                  },
                  "example": {
                    "type": "array",
                    "example": [
                      "newbie",
                      "guide"
                    ],
                    "items": {
                      "type": "string"
                    }
                  }
                }
              },
              "created_at": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "date-time"
                  }
                }
              },
              "updated_at": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "date-time"
                  }
                }
              }
            }
          }
        }
      },
      "WikiPageCreateRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "slug",
              "title"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "slug": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "pattern": {
                    "type": "string",
                    "example": "^[a-z0-9-]+$"
                  },
                  "example": {
                    "type": "string",
                    "example": "getting-started"
                  }
                }
              },
              "title": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 200
                  },
                  "example": {
                    "type": "string",
                    "example": "Getting Started"
                  }
                }
              },
              "excerpt": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 400
                  }
                }
              },
              "body": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  }
                }
              },
              "category_id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "nullable": {
                    "type": "boolean",
                    "example": true
                  }
                }
              },
              "published": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "example": {
                    "type": "boolean",
                    "example": false
                  }
                }
              },
              "tags": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "array"
                  },
                  "items": {
                    "type": "object",
                    "properties": {
                      "type": {
                        "type": "string",
                        "example": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "WikiCategory": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "example": {
                    "type": "number",
                    "example": 2
                  }
                }
              },
              "slug": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "guides"
                  }
                }
              },
              "title": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "Guides"
                  }
                }
              },
              "description": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  }
                }
              },
              "sort_order": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "example": {
                    "type": "number",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      },
      "WikiCategoryCreateRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "slug",
              "title"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "slug": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "pattern": {
                    "type": "string",
                    "example": "^[a-z0-9-]+$"
                  },
                  "example": {
                    "type": "string",
                    "example": "guides"
                  }
                }
              },
              "title": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 200
                  },
                  "example": {
                    "type": "string",
                    "example": "Guides"
                  }
                }
              },
              "description": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 400
                  }
                }
              },
              "sort_order": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "example": {
                    "type": "number",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "properties": {
            "type": "object",
            "properties": {
              "id": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "integer"
                  },
                  "example": {
                    "type": "number",
                    "example": 1
                  }
                }
              },
              "username": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "admin"
                  }
                }
              },
              "role": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "enum": {
                    "type": "array",
                    "example": [
                      "admin",
                      "editor"
                    ],
                    "items": {
                      "type": "string"
                    }
                  },
                  "example": {
                    "type": "string",
                    "example": "admin"
                  }
                }
              },
              "totp_enabled": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "boolean"
                  },
                  "example": {
                    "type": "boolean",
                    "example": true
                  }
                }
              },
              "last_login_at": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "date-time"
                  },
                  "nullable": {
                    "type": "boolean",
                    "example": true
                  }
                }
              },
              "created_at": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "date-time"
                  }
                }
              }
            }
          }
        }
      },
      "UserCreateRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "username",
              "password"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "username": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "minLength": {
                    "type": "number",
                    "example": 3
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 32
                  },
                  "example": {
                    "type": "string",
                    "example": "editor1"
                  }
                }
              },
              "password": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "format": {
                    "type": "string",
                    "example": "password"
                  },
                  "minLength": {
                    "type": "number",
                    "example": 8
                  },
                  "maxLength": {
                    "type": "number",
                    "example": 64
                  }
                }
              },
              "role": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "enum": {
                    "type": "array",
                    "example": [
                      "admin",
                      "editor"
                    ],
                    "items": {
                      "type": "string"
                    }
                  },
                  "example": {
                    "type": "string",
                    "example": "editor"
                  }
                }
              }
            }
          }
        }
      },
      "TotpCodeRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "code"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "code": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "123456"
                  }
                }
              }
            }
          }
        }
      },
      "SiteModeRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "mode"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "mode": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "enum": {
                    "type": "array",
                    "example": [
                      "live",
                      "maintenance"
                    ],
                    "items": {
                      "type": "string"
                    }
                  },
                  "example": {
                    "type": "string",
                    "example": "live"
                  }
                }
              }
            }
          }
        }
      },
      "UnbanRequest": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "example": "object"
          },
          "required": {
            "type": "array",
            "example": [
              "ip"
            ],
            "items": {
              "type": "string"
            }
          },
          "properties": {
            "type": "object",
            "properties": {
              "ip": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "example": "string"
                  },
                  "example": {
                    "type": "string",
                    "example": "203.0.113.5"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}