openapi: 3.0.3
info:
  title: Hranostaj API
  version: 1.0.0
  description: >-
    Veřejné anonymní endpointy API Hranostaj.cz.

    Celý dokument pro strojové čtení nebo AI agenty: https://www.hranostaj.cz/openapi/hranostaj.yaml

servers:
  - url: https://www.hranostaj.cz/api
    description: Veřejný Hranostaj.cz

# Všechny endpointy jsou anonymní
security: []

paths:
  /home:
    $ref: './endpoints/home.yaml'
  /tags:
    $ref: './endpoints/tags.yaml'
  /browse/{id}:
    $ref: './endpoints/browse.yaml'
  /search:
    $ref: './endpoints/search.yaml'
  /game/{id}:
    $ref: './endpoints/game.yaml'
  /game-multiple/{id}:
    $ref: './endpoints/game-multiple.yaml'
  /game-multiple-details/{id}:
    $ref: './endpoints/game-multiple-details.yaml'
  /game-random:
    $ref: './endpoints/game-random.yaml'
  /games-ladder/{id}:
    $ref: './endpoints/games-ladder.yaml'
  /discussion/{id}:
    $ref: './endpoints/discussion.yaml'
  /all-comment-count/{id}:
    $ref: './endpoints/all-comment-count.yaml'
  /check-new-comments/{id}:
    $ref: './endpoints/check-new-comments.yaml'
  /game-rating-summary/{id}:
    $ref: './endpoints/game-rating-summary.yaml'
  /user/{id}:
    $ref: './endpoints/user.yaml'

components:
  parameters:
    Sort:
      name: sort
      in: query
      description: Řazení seznamu `games`. Neplatná hodnota se bere jako `auto`.
      required: false
      schema:
        $ref: '#/components/schemas/GamesSort'
    NumGames:
      name: numGames
      in: query
      description: Počet her ve výsledku (0 až 50). Neplatná hodnota se nahradí výchozími 25.
      required: false
      schema:
        type: integer
        minimum: 0
        maximum: 50
        default: 25

  responses:
    LegacyBadRequest:
      description: Chybný vstup (starší API)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/LegacyError'
    LegacyNotFound:
      description: Objekt nebyl nalezen (starší API)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/LegacyError'
    BadRequest:
      description: Chybný nebo chybějící vstup
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: Objekt nebyl nalezen
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalError:
      description: Interní chyba serveru (včetně neplatného typu vstupních hodnot, např. nečíselné ID)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'

  schemas:
    # ---------- Společné obálky ----------
    LegacyError:
      type: object
      description: Chyba starších endpointů (HTTP kód odpovídá chybě)
      required: [error]
      properties:
        error:
          type: string
    ResponseBase:
      type: object
      description: Společné části obálky novějších endpointů
      required: [responseCode, responseText]
      properties:
        responseCode:
          type: integer
        responseText:
          type: string
        asUserId:
          type: integer
          nullable: true
          description: ID přihlášeného uživatele (u anonymních požadavků se nevyskytuje)
    SuccessResponse:
      allOf:
        - $ref: '#/components/schemas/ResponseBase'
        - type: object
          properties:
            responseCode:
              type: integer
              enum: [200]
            responseText:
              type: string
              example: OK
    ErrorResponse:
      allOf:
        - $ref: '#/components/schemas/ResponseBase'
        - type: object
          properties:
            responseCode:
              type: integer
              example: 400
            responseText:
              type: string
              description: Popis chyby

    # ---------- Hry ----------
    GamesSort:
      type: string
      enum: [auto, alphabet, best, worst, new, old]
      default: auto
    TagId:
      type: integer
      description: ID příznaku (prostředí nebo charakteru hry), viz endpoint /tags
      minimum: 1
      maximum: 29
    AgeGroup:
      type: string
      enum: [benjaminci, vlcata, skauti, roveri]
    GameDuration:
      type: string
      description: Délka hry – "t" + číslo 1 až 5 (1 neurčitelná, 2 do 12 min, 3 do 34 min, 4 do 111 min, 5 delší)
      enum: [t1, t2, t3, t4, t5]
    GamePreparation:
      type: string
      description: Náročnost přípravy – "p" + číslo 1 až 5 (1 bez přípravy … 5 sebevražedná)
      enum: [p1, p2, p3, p4, p5]
    GameBasics:
      type: object
      description: Základní údaje o hře
      properties:
        id:
          type: integer
        name:
          type: string
        date:
          type: string
          format: date-time
        views:
          type: integer
        subtitle:
          type: string
        author:
          type: string
        source:
          type: string
        requisities:
          type: string
          description: Potřebné pomůcky
        types:
          type: array
          description: ID příznaků charakteru hry
          items:
            $ref: '#/components/schemas/TagId'
        envs:
          type: array
          description: ID příznaků prostředí
          items:
            $ref: '#/components/schemas/TagId'
        players:
          type: object
          properties:
            from:
              type: integer
            to:
              type: integer
              description: 0 = neomezeno
        time:
          $ref: '#/components/schemas/GameDuration'
        preparation:
          $ref: '#/components/schemas/GamePreparation'
        age:
          type: array
          items:
            $ref: '#/components/schemas/AgeGroup'
        altsNum:
          type: integer
          description: Počet alternativních pravidel
        commentsNum:
          type: integer
          description: Počet komentářů
        score:
          type: number
        votes:
          type: integer
          description: Počet hodnocení
    GameLegacyPost:
      type: object
      description: Komentář nebo alternativní pravidlo ve zjednodušené podobě
      properties:
        name:
          type: string
        text:
          type: string
        date:
          type: string
          format: date-time
    GameDetail:
      allOf:
        - $ref: '#/components/schemas/GameBasics'
        - type: object
          properties:
            rules:
              type: string
              description: Text pravidel
            fullUrl:
              type: string
              format: uri
            comments:
              type: array
              items:
                $ref: '#/components/schemas/GameLegacyPost'
            alts:
              type: array
              items:
                $ref: '#/components/schemas/GameLegacyPost'
            similar:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string
            attachments:
              type: array
              items:
                type: object
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  size:
                    type: integer
                  url:
                    type: string
                    format: uri
                  type:
                    type: string
                    description: MIME typ
    SortedGameIds:
      type: object
      description: ID všech nalezených her seřazená podle jednotlivých kritérií
      properties:
        auto:
          type: array
          items: {type: integer}
        new:
          type: array
          items: {type: integer}
        old:
          type: array
          items: {type: integer}
        best:
          type: array
          items: {type: integer}
        worst:
          type: array
          items: {type: integer}
        alphabet:
          type: array
          items: {type: integer}
    GamesSearchResult:
      type: object
      properties:
        total:
          type: integer
          description: Celkový počet nalezených her
        sortedIds:
          $ref: '#/components/schemas/SortedGameIds'
        games:
          type: array
          description: Prvních `numGames` her dle zvoleného řazení
          items:
            $ref: '#/components/schemas/GameBasics'

    # ---------- Hodnocení her ----------
    GameRating:
      type: object
      properties:
        rating:
          type: integer
          minimum: 1
          maximum: 7
        date:
          type: string
          format: date-time
          nullable: true
    GameRatingSummary:
      type: object
      properties:
        votes:
          type: object
          description: Počty hlasů pro jednotlivé známky
          properties:
            '1': {type: integer}
            '2': {type: integer}
            '3': {type: integer}
            '4': {type: integer}
            '5': {type: integer}
            '6': {type: integer}
            '7': {type: integer}
        count:
          type: integer
        score:
          type: number
        ladder:
          type: integer
          nullable: true
          description: Pořadí v žebříčku
        myRating:
          type: object
          allOf:
            - $ref: '#/components/schemas/GameRating'
          nullable: true
          description: Hodnocení přihlášeného uživatele (u anonymních vždy null)

    # ---------- Diskuze ----------
    DiscussionType:
      type: string
      enum: [comment, alt]
      description: comment = komentáře, alt = alternativní pravidla
    ImageInfo:
      type: object
      properties:
        width:
          type: integer
        height:
          type: integer
        type:
          type: string
          description: MIME typ
        isImage:
          type: boolean
    Portrait:
      type: object
      description: Portrét uživatele
      properties:
        id:
          type: integer
          nullable: true
        url:
          type: string
        image:
          $ref: '#/components/schemas/ImageInfo'
    UserFile:
      type: object
      properties:
        id:
          type: integer
        url:
          type: string
        size:
          type: integer
        date:
          type: string
          format: date-time
          nullable: true
        image:
          type: object
          allOf:
            - $ref: '#/components/schemas/ImageInfo'
          nullable: true
        thumbnail:
          type: object
          nullable: true
          allOf:
            - $ref: '#/components/schemas/ImageInfo'
            - type: object
              properties:
                url:
                  type: string
    User:
      type: object
      properties:
        id:
          type: integer
          nullable: true
          description: Null u neregistrovaných autorů (staré komentáře)
        name:
          type: string
        portrait:
          type: object
          allOf:
            - $ref: '#/components/schemas/Portrait'
          nullable: true
    UserProfile:
      allOf:
        - $ref: '#/components/schemas/User'
        - type: object
          properties:
            city:
              type: string
              nullable: true
            sex:
              type: string
              enum: [m, f]
              nullable: true
            bio:
              type: string
              nullable: true
            web:
              type: string
              nullable: true
    CommentRating:
      type: object
      properties:
        id:
          type: integer
        rating:
          type: integer
          enum: [-1, 1]
        date:
          type: string
          format: date-time
          nullable: true
    CommentRatingsSummary:
      type: object
      properties:
        score:
          type: integer
        minus:
          type: integer
        plus:
          type: integer
        count:
          type: integer
        myRating:
          type: object
          allOf:
            - $ref: '#/components/schemas/CommentRating'
          nullable: true
          description: Hodnocení přihlášeného uživatele (u anonymních vždy null)
    CommentAttachment:
      type: object
      properties:
        id:
          type: integer
        label:
          type: string
        file:
          $ref: '#/components/schemas/UserFile'
    Comment:
      type: object
      properties:
        id:
          type: integer
        idGame:
          type: integer
        parentCommentId:
          type: integer
          nullable: true
        date:
          type: string
          format: date-time
        editedDate:
          type: string
          format: date-time
          nullable: true
        text:
          type: string
        author:
          $ref: '#/components/schemas/User'
        responses:
          type: array
          description: Odpovědi na komentář (rekurzivně)
          items:
            $ref: '#/components/schemas/Comment'
        ratings:
          $ref: '#/components/schemas/CommentRatingsSummary'
        attachments:
          type: array
          items:
            $ref: '#/components/schemas/CommentAttachment'

    # ---------- Příznaky ----------
    Tag:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/TagId'
        name:
          type: string
        games:
          type: integer
          description: Počet her s tímto příznakem
