openapi: 3.0.3
info:
  title: 'Doski API'
  description: |-
    REST API проекта «Доски» (Doski Bar).

    - **Mobile** (`/api/mobile/*`) — мобильное приложение и публичные QR-заказы
    - **Admin v1** (`/api/v1/*`) — админ-панель back.doski (Bearer Sanctum)
    - **R-Keeper входящий** — `getBonuses`, `giveOrder`, `createBooking`
    - **R-Keeper исходящий** — QR-заказы после оплаты ЮKassa → XML CreateOrder/SaveOrder (настройки в филиале)
    - **Webhooks** — ЮKassa

    **QR-заказ:** scan token → table-context → menu → create → payment (card + phone) → ЮKassa → webhook → R-Keeper.

    Авторизация админки: `POST /api/loginWithEmail` → Bearer token в заголовке `Authorization`.
  version: 1.1.0
  contact:
    name: 'Doski API Support'
servers:
  -
    url: 'https://api.doski.ea-s.tech'
    description: Staging
  -
    url: 'https://api.doski.bar'
    description: Production
  -
    url: 'http://localhost'
    description: Local
tags:
  -
    name: Auth
    description: 'Авторизация админ-панели'
  -
    name: 'Mobile — Public'
    description: 'Публичные методы без токена'
  -
    name: 'Mobile — QR Orders'
    description: 'Заказ по QR-коду на столе'
  -
    name: 'Mobile — Auth'
    description: 'Профиль пользователя (Sanctum)'
  -
    name: 'Mobile — Booking'
    description: 'Бронирование столов'
  -
    name: 'Mobile — Pages'
    description: 'Страницы приложения'
  -
    name: 'Mobile — Other'
    description: 'Прочие mobile-методы'
  -
    name: 'Admin — Users'
    description: 'Гости и персонал'
  -
    name: 'Admin — Branches'
    description: 'Филиалы, столы, настройки R-Keeper XML (URL, Station ID, ident)'
  -
    name: 'Admin — Bookings'
    description: Бронирования
  -
    name: 'Admin — Menu'
    description: 'Продукты и категории'
  -
    name: 'Admin — Content'
    description: 'События, публикации'
  -
    name: 'Admin — Reviews'
    description: Отзывы
  -
    name: 'Admin — Table Orders'
    description: 'Заказы по QR: список, детали, QR-токены столов'
  -
    name: 'Admin — Reports'
    description: Отчёты
  -
    name: 'Admin — Push'
    description: Push-уведомления
  -
    name: 'Admin — Settings'
    description: 'Глобальные настройки'
  -
    name: 'Admin — Files'
    description: 'Файлы и изображения'
  -
    name: 'Admin — Other'
    description: 'Прочие admin-методы'
  -
    name: R-Keeper
    description: 'Входящие вызовы от R-Keeper. Исходящая отправка QR-заказов — XML Interface, см. Admin — Branches'
  -
    name: Webhooks
    description: 'Внешние webhook (ЮKassa)'
paths:
  /api-docs:
    get:
      tags:
        - 'Admin — Other'
      summary: SwaggerUi
      operationId: get_api-docs
      security: {  }
      responses:
        200:
          description: 'Успешный ответ'
  /api-docs/openapi.json:
    get:
      tags:
        - 'Admin — Other'
      summary: OpenapiJson
      operationId: get_api-docs_openapi.json
      security: {  }
      responses:
        200:
          description: 'Успешный ответ'
  /api-docs/openapi.yaml:
    get:
      tags:
        - 'Admin — Other'
      summary: OpenapiYaml
      operationId: get_api-docs_openapi.yaml
      security: {  }
      responses:
        200:
          description: 'Успешный ответ'
  /api/createBooking:
    post:
      tags:
        - R-Keeper
      summary: 'Создание брони из R-Keeper'
      operationId: post_createBooking
      security: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                -
                  $ref: '#/components/schemas/RkeeperAuth'
                -
                  type: object
                  additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/getBonuses:
    post:
      tags:
        - R-Keeper
      summary: 'Запрос списания бонусов (входящий)'
      operationId: post_getBonuses
      description: |-
        Входящий вызов **от R-Keeper** к Doski API.

        Поле `auth` обязательно (секрет интеграции).

        **Исходящая отправка QR-заказов** в R-Keeper — через XML Interface (CreateOrder/SaveOrder), настраивается в полях филиала (`rkeeper_xml_url`, `rkeeper_station_id`). См. Admin — Branches.
      security: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RkeeperGetBonusesRequest'
      responses:
        200:
          description: 'Данные пользователя и сумма списания'
          content:
            application/json:
              schema:
                type: object
        401:
          description: 'Ошибка авторизации'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /api/giveOrder:
    post:
      tags:
        - R-Keeper
      summary: 'Завершение заказа (начисление/списание бонусов)'
      operationId: post_giveOrder
      security: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RkeeperGiveOrderRequest'
      responses:
        200:
          description: 'Результат обработки заказа'
          content:
            application/json:
              schema:
                type: object
  /api/loginWithEmail:
    post:
      tags:
        - Auth
      summary: 'Вход в админ-панель'
      operationId: post_loginWithEmail
      description: 'Авторизация по email/password. Возвращает Sanctum Bearer token. Доступ только для role >= 1.'
      security: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
      responses:
        200:
          description: 'Успешный вход'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
        401:
          description: 'Неверные данные'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        422:
          $ref: '#/components/responses/ValidationError'
  /api/mobile/CreateReview:
    post:
      tags:
        - 'Mobile — Other'
      summary: 'Создать отзыв'
      operationId: post_mobile_CreateReview
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                branch_id:
                  type: integer
                rating:
                  type: integer
                text:
                  type: string
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/authWithCode:
    post:
      tags:
        - 'Mobile — Public'
      summary: 'Авторизация по SMS-коду'
      operationId: post_mobile_authWithCode
      description: 'Возвращает пользователя и Sanctum token. Регистрирует FCM token устройства.'
      security: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AuthWithCodeRequest'
      responses:
        200:
          description: 'Пользователь и token'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MobileUser'
  /api/mobile/booking:
    get:
      tags:
        - 'Mobile — Booking'
      summary: 'Мои бронирования'
      operationId: get_mobile_booking
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Список бронирований'
          content:
            application/json:
              schema:
                type: object
  '/api/mobile/booking/cancel/{booking}':
    get:
      tags:
        - 'Mobile — Booking'
      summary: 'Отменить бронирование'
      operationId: get_mobile_booking_cancel_booking
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/booking/create:
    post:
      tags:
        - 'Mobile — Booking'
      summary: 'Создать бронирование'
      operationId: post_mobile_booking_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - branch_id
                - date
                - time
                - people_count
              properties:
                branch_id:
                  type: integer
                date:
                  type: string
                  format: date
                time:
                  type: string
                people_count:
                  type: integer
                table_id:
                  type: integer
                comment:
                  type: string
      responses:
        200:
          description: 'Бронирование создано'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Booking'
  /api/mobile/booking/getBranch:
    get:
      tags:
        - 'Mobile — Booking'
      summary: 'Филиал для бронирования'
      operationId: get_mobile_booking_getBranch
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Branch'
  /api/mobile/booking/getPayment:
    post:
      tags:
        - 'Mobile — Booking'
      summary: 'Создать платёж ЮKassa для брони'
      operationId: post_mobile_booking_getPayment
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                booking_id:
                  type: integer
      responses:
        200:
          description: confirmation_url
          content:
            application/json:
              schema:
                type: object
  /api/mobile/booking/getTables:
    post:
      tags:
        - 'Mobile — Booking'
      summary: 'Доступные столы на дату/время'
      operationId: post_mobile_booking_getTables
      description: 'Throttle отключён для этого маршрута. Защита — кэш внутри контроллера.'
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - branch_id
                - date
                - time
                - people_count
              properties:
                branch_id:
                  type: integer
                date:
                  type: string
                time:
                  type: string
                people_count:
                  type: integer
      responses:
        200:
          description: 'Массив доступных столов'
          content:
            application/json:
              schema:
                type: object
  '/api/mobile/booking/{booking}':
    post:
      tags:
        - 'Mobile — Booking'
      summary: 'Обновить бронирование'
      operationId: post_mobile_booking_booking
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Booking'
    get:
      tags:
        - 'Mobile — Booking'
      summary: 'Бронирование по ID'
      operationId: get_mobile_booking_booking
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Booking'
  '/api/mobile/booking/{booking}/createMessage':
    post:
      tags:
        - 'Mobile — Booking'
      summary: 'Отправить сообщение'
      operationId: post_mobile_booking_booking_createMessage
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                message:
                  type: string
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/mobile/booking/{booking}/updateMessages':
    get:
      tags:
        - 'Mobile — Booking'
      summary: 'Сообщения бронирования'
      operationId: get_mobile_booking_booking_updateMessages
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/branches:
    get:
      tags:
        - 'Mobile — Public'
      summary: 'Список филиалов'
      operationId: get_mobile_branches
      security: {  }
      responses:
        200:
          description: 'Массив филиалов'
          content:
            application/json:
              schema:
                type: object
  '/api/mobile/branches/{branch}':
    get:
      tags:
        - 'Mobile — Public'
      summary: 'Филиал по ID'
      operationId: get_mobile_branches_branch
      security: {  }
      parameters:
        -
          name: branch
          in: path
          required: true
          schema:
            type: integer
          description: 'ID филиала'
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Branch'
  '/api/mobile/citys/{city}':
    get:
      tags:
        - 'Mobile — Public'
      summary: 'Филиалы города'
      operationId: get_mobile_citys_city
      security: {  }
      parameters:
        -
          name: city
          in: path
          required: true
          schema:
            type: integer
          description: city
      responses:
        200:
          description: 'Филиалы в городе'
          content:
            application/json:
              schema:
                type: object
  '/api/mobile/loyalty/{code}':
    get:
      tags:
        - 'Mobile — QR Orders'
      summary: 'Баланс бонусов по коду лояльности'
      operationId: get_mobile_loyalty_code
      security: {  }
      parameters:
        -
          name: code
          in: path
          required: true
          schema:
            type: string
          description: 'Код лояльности пользователя'
      responses:
        200:
          description: 'Информация о лояльности'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoyaltyInfo'
        404:
          description: 'Код не найден'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /api/mobile/menu:
    get:
      tags:
        - 'Mobile — QR Orders'
      summary: 'Публичное меню филиала'
      operationId: get_mobile_menu
      description: 'Меню для QR-заказа. Требует `branch_id` из ответа table-context.'
      security: {  }
      parameters:
        -
          name: branch_id
          in: query
          required: true
          schema:
            type: integer
          description: 'ID филиала'
      responses:
        200:
          description: 'Меню по типам и категориям'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicMenu'
        403:
          description: 'QR-заказы отключены'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        422:
          $ref: '#/components/responses/ValidationError'
  /api/mobile/pages/achivment_page:
    get:
      tags:
        - 'Mobile — Pages'
      summary: 'Страница достижений'
      operationId: get_mobile_pages_achivment_page
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/pages/events_page:
    get:
      tags:
        - 'Mobile — Pages'
      summary: 'Список событий'
      operationId: get_mobile_pages_events_page
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/pages/main_page:
    get:
      tags:
        - 'Mobile — Pages'
      summary: 'Главная страница приложения'
      operationId: get_mobile_pages_main_page
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/pages/menu_page:
    get:
      tags:
        - 'Mobile — Pages'
      summary: 'Страница меню'
      operationId: get_mobile_pages_menu_page
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/pages/publications_page:
    get:
      tags:
        - 'Mobile — Pages'
      summary: Публикации
      operationId: get_mobile_pages_publications_page
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/mobile/pages/single_event_page/{event}':
    get:
      tags:
        - 'Mobile — Pages'
      summary: 'Событие по ID'
      operationId: get_mobile_pages_single_event_page_event
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: event
          in: path
          required: true
          schema:
            type: integer
          description: event
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/mobile/pages/single_publication_page/{publication}':
    get:
      tags:
        - 'Mobile — Pages'
      summary: 'Публикация по ID'
      operationId: get_mobile_pages_single_publication_page_publication
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: publication
          in: path
          required: true
          schema:
            type: integer
          description: publication
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/preorder/create:
    post:
      tags:
        - 'Mobile — Other'
      summary: 'Создать предзаказ'
      operationId: post_mobile_preorder_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/mobile/preorder/{preorder}':
    post:
      tags:
        - 'Mobile — Other'
      summary: 'Обновить предзаказ'
      operationId: post_mobile_preorder_preorder
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: preorder
          in: path
          required: true
          schema:
            type: integer
          description: preorder
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/sendCode:
    post:
      tags:
        - 'Mobile — Public'
      summary: 'Отправить SMS-код'
      operationId: post_mobile_sendCode
      description: 'Отправляет 4-значный код на телефон. Тестовый номер `79999999999` → код `1234`.'
      security: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendCodeRequest'
      responses:
        200:
          description: 'Сообщение отправлено'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        400:
          description: 'Неверный формат телефона'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        503:
          description: 'SMS-сервис недоступен'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  '/api/mobile/table-context/{token}':
    get:
      tags:
        - 'Mobile — QR Orders'
      summary: 'Контекст стола по QR-токену'
      operationId: get_mobile_table-context_token
      description: |-
        Первый шаг после сканирования QR в приложении.

        QR содержит **только токен** (не URL). Проверяет: стол существует, филиал активен, `qr_orders_enabled = true`.
      security: {  }
      parameters:
        -
          name: token
          in: path
          required: true
          schema:
            type: string
          description: 'QR-токен стола (строка из QR-кода)'
      responses:
        200:
          description: 'Контекст стола'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TableContext'
        403:
          description: 'Филиал недоступен или QR-заказы отключены'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        404:
          description: 'Стол не найден'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /api/mobile/table-order/create:
    post:
      tags:
        - 'Mobile — QR Orders'
      summary: 'Создать заказ по столу'
      operationId: post_mobile_table-order_create
      description: |-
        Создаёт заказ в статусе `pending_payment_choice`.

        **Authorization (опционально):** Bearer Sanctum — для списания бонусов с аккаунта.

        Бонусы: максимум 25% от суммы. Гость без входа может передать `loyalty_code` + `loyalty_action: spend`.
      security: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TableOrderCreateRequest'
      responses:
        200:
          description: 'Заказ создан'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TableOrderCreateResponse'
        400:
          description: 'Блюдо недоступно / код лояльности неверен'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        403:
          description: 'QR-заказы отключены'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        404:
          description: 'Стол или филиал не найден'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        422:
          $ref: '#/components/responses/ValidationError'
  /api/mobile/table-order/successPayment:
    get:
      tags:
        - 'Mobile — QR Orders'
      summary: 'Return URL после оплаты ЮKassa'
      operationId: get_mobile_table-order_successPayment
      description: |-
        Вызывается после редиректа из WebView ЮKassa.

        Требует query-параметры `order_id` и `auth_Code`.

        Ответ plain text: `success` (заказ оплачен, webhook обработан) или `pending`.

        После `payment.succeeded` webhook автоматически отправляет заказ в R-Keeper (CreateOrder + SaveOrder), если у филиала задан `rkeeper_station_id`.
      security: {  }
      parameters:
        -
          name: order_id
          in: query
          required: true
          schema:
            type: integer
        -
          name: auth_Code
          in: query
          required: true
          schema:
            type: string
      responses:
        200:
          description: 'success или pending (text/plain)'
        403:
          description: forbidden
  '/api/mobile/table-order/{order}':
    get:
      tags:
        - 'Mobile — QR Orders'
      summary: 'Детали заказа по столу'
      operationId: get_mobile_table-order_order
      security: {  }
      parameters:
        -
          name: order
          in: path
          required: true
          schema:
            type: integer
          description: 'ID заказа по столу'
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TableOrder'
  '/api/mobile/table-order/{order}/cash':
    post:
      tags:
        - 'Mobile — QR Orders'
      summary: 'Недоступно (только онлайн-оплата)'
      operationId: post_mobile_table-order_order_cash
      description: 'QR-заказы оплачиваются только картой через ЮKassa.'
      security: {  }
      parameters:
        -
          name: order
          in: path
          required: true
          schema:
            type: integer
          description: 'ID заказа по столу'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        400:
          description: 'Оплата QR-заказа доступна только онлайн'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  '/api/mobile/table-order/{order}/payment':
    post:
      tags:
        - 'Mobile — QR Orders'
      summary: 'Онлайн-оплата заказа'
      operationId: post_mobile_table-order_order_payment
      description: |-
        Только оплата картой через ЮKassa.

        **Телефон для чека:** если пользователь **не авторизован**, передайте `phone` в теле запроса. Если авторизован — берётся `phone_number` из профиля, поле `phone` необязательно.

        Телефон уходит в `receipt.customer.phone` для фискального чека.
      security: {  }
      parameters:
        -
          name: order
          in: path
          required: true
          schema:
            type: integer
          description: 'ID заказа по столу'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TableOrderPaymentRequest'
      responses:
        200:
          description: 'URL оплаты ЮKassa'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TableOrderPaymentCardResponse'
        400:
          description: 'Оплата уже обработана'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        422:
          description: 'Не указан или неверный телефон'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationError'
  /api/mobile/user:
    get:
      tags:
        - 'Mobile — Auth'
      summary: 'Профиль пользователя'
      operationId: get_mobile_user
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MobileUser'
    post:
      tags:
        - 'Mobile — Auth'
      summary: 'Обновить профиль'
      operationId: post_mobile_user
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                surname:
                  type: string
                email:
                  type: string
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MobileUser'
  /api/mobile/user/DeleteUser:
    get:
      tags:
        - 'Mobile — Auth'
      summary: 'Удалить аккаунт'
      operationId: get_mobile_user_DeleteUser
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Аккаунт удалён'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/user/logout:
    post:
      tags:
        - 'Mobile — Auth'
      summary: Выход
      operationId: post_mobile_user_logout
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный выход'
  /api/mobile/user/regenerateCode:
    post:
      tags:
        - 'Mobile — Auth'
      summary: 'Перегенерировать код лояльности'
      operationId: post_mobile_user_regenerateCode
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Новый custom_code'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/user/updateImage:
    post:
      tags:
        - 'Mobile — Auth'
      summary: 'Обновить аватар'
      operationId: post_mobile_user_updateImage
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                image:
                  type: string
                  format: binary
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/mobile/user/updateLastTime:
    get:
      tags:
        - 'Mobile — Auth'
      summary: 'Обновить last_visit'
      operationId: get_mobile_user_updateLastTime
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/achivments:
    get:
      tags:
        - 'Admin — Other'
      summary: Достижения
      operationId: get_v1_achivments
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/achivments/create:
    post:
      tags:
        - 'Admin — Other'
      summary: 'Создать достижение'
      operationId: post_v1_achivments_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/achivments/{achivment}':
    get:
      tags:
        - 'Admin — Other'
      summary: 'Достижение по ID'
      operationId: get_v1_achivments_achivment
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: achivment
          in: path
          required: true
          schema:
            type: integer
          description: achivment
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    post:
      tags:
        - 'Admin — Other'
      summary: 'Обновить достижение'
      operationId: post_v1_achivments_achivment
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: achivment
          in: path
          required: true
          schema:
            type: integer
          description: achivment
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    delete:
      tags:
        - 'Admin — Other'
      summary: 'Удалить достижение'
      operationId: delete_v1_achivments_achivment
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: achivment
          in: path
          required: true
          schema:
            type: integer
          description: achivment
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/bookings:
    get:
      tags:
        - 'Admin — Bookings'
      summary: 'Список бронирований'
      operationId: get_v1_bookings
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: Бронирования
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pagination'
  /api/v1/bookings/create:
    post:
      tags:
        - 'Admin — Bookings'
      summary: 'Создать бронирование (админ)'
      operationId: post_v1_bookings_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Booking'
  /api/v1/bookings/indexWithoutPaginate:
    get:
      tags:
        - 'Admin — Bookings'
      summary: 'Бронирования без пагинации'
      operationId: get_v1_bookings_indexWithoutPaginate
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/bookings/{booking}':
    get:
      tags:
        - 'Admin — Bookings'
      summary: 'Бронирование по ID'
      operationId: get_v1_bookings_booking
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Booking'
    post:
      tags:
        - 'Admin — Bookings'
      summary: 'Обновить бронирование'
      operationId: post_v1_bookings_booking
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Booking'
  '/api/v1/bookings/{booking}/changePreorderStatus':
    post:
      tags:
        - 'Admin — Bookings'
      summary: 'Сменить статус предзаказа'
      operationId: post_v1_bookings_booking_changePreorderStatus
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/bookings/{booking}/createMessage':
    post:
      tags:
        - 'Admin — Bookings'
      summary: 'Сообщение к брони'
      operationId: post_v1_bookings_booking_createMessage
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/bookings/{booking}/preorder':
    post:
      tags:
        - 'Admin — Bookings'
      summary: 'Обновить предзаказ брони'
      operationId: post_v1_bookings_booking_preorder
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: booking
          in: path
          required: true
          schema:
            type: integer
          description: booking
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/branches:
    get:
      tags:
        - 'Admin — Branches'
      summary: 'Список филиалов'
      operationId: get_v1_branches
      description: 'Включает R-Keeper поля (`rkeeper_xml_url`, `rkeeper_station_id`, …). Пароль `rkeeper_password` не возвращается.'
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Филиалы с Booking_times'
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Branch'
  /api/v1/branches/create:
    post:
      tags:
        - 'Admin — Branches'
      summary: 'Создать филиал'
      operationId: post_v1_branches_create
      description: 'Создание филиала с настройками R-Keeper, бронирования и QR-заказов.'
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BranchCreateRequest'
      responses:
        200:
          description: 'Филиал создан'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Branch'
  /api/v1/branches/getTables:
    post:
      tags:
        - 'Admin — Branches'
      summary: 'Столы филиала (админ)'
      operationId: post_v1_branches_getTables
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                branch_id:
                  type: integer
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/branches/{branch}':
    get:
      tags:
        - 'Admin — Branches'
      summary: 'Филиал с аналитикой'
      operationId: get_v1_branches_branch
      description: 'Полные данные филиала включая настройки R-Keeper и столы.'
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: branch
          in: path
          required: true
          schema:
            type: integer
          description: 'ID филиала'
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Branch'
    post:
      tags:
        - 'Admin — Branches'
      summary: 'Обновить филиал'
      operationId: post_v1_branches_branch
      description: |-
        Обновление филиала.

        **QR-заказы:** `settings.qr_orders_enabled` (boolean).

        **R-Keeper (исходящие QR-заказы):**
        - `rkeeper_xml_url` — URL XML API
        - `rkeeper_station_id` — **обязателен** для отправки на кухню
        - `rkeeper_waiter_code` — необязательно
        - `rkeeper_login` / `rkeeper_password` — если отличаются от глобальных
        - `price_ident`, `thread_ident`, `custom_id` — как для меню

        Пустой `rkeeper_password` при update — пароль не меняется.
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: branch
          in: path
          required: true
          schema:
            type: integer
          description: 'ID филиала'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BranchUpdateRequest'
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Branch'
    delete:
      tags:
        - 'Admin — Branches'
      summary: 'Удалить филиал'
      operationId: delete_v1_branches_branch
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: branch
          in: path
          required: true
          schema:
            type: integer
          description: 'ID филиала'
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/categories/create:
    post:
      tags:
        - 'Admin — Menu'
      summary: 'Создать категорию'
      operationId: post_v1_categories_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/categories/{category_type?}':
    get:
      tags:
        - 'Admin — Menu'
      summary: Категории
      operationId: 'get_v1_categories_category_type?'
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/categories/{category}':
    post:
      tags:
        - 'Admin — Menu'
      summary: 'Обновить категорию'
      operationId: post_v1_categories_category
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: category
          in: path
          required: true
          schema:
            type: integer
          description: category
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    delete:
      tags:
        - 'Admin — Menu'
      summary: 'Удалить категорию'
      operationId: delete_v1_categories_category
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: category
          in: path
          required: true
          schema:
            type: integer
          description: category
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/cities:
    get:
      tags:
        - 'Admin — Other'
      summary: 'Список городов'
      operationId: get_v1_cities
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/cities/create:
    post:
      tags:
        - 'Admin — Other'
      summary: 'Создать город'
      operationId: post_v1_cities_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/cities/{city}':
    get:
      tags:
        - 'Admin — Other'
      summary: 'Город по ID'
      operationId: get_v1_cities_city
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: city
          in: path
          required: true
          schema:
            type: integer
          description: city
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    post:
      tags:
        - 'Admin — Other'
      summary: 'Обновить город'
      operationId: post_v1_cities_city
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: city
          in: path
          required: true
          schema:
            type: integer
          description: city
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/events:
    get:
      tags:
        - 'Admin — Content'
      summary: 'Список событий'
      operationId: get_v1_events
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: События
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pagination'
  /api/v1/events/create:
    post:
      tags:
        - 'Admin — Content'
      summary: 'Создать событие'
      operationId: post_v1_events_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/events/{event}':
    get:
      tags:
        - 'Admin — Content'
      summary: 'Событие по ID'
      operationId: get_v1_events_event
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: event
          in: path
          required: true
          schema:
            type: integer
          description: event
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    post:
      tags:
        - 'Admin — Content'
      summary: 'Обновить событие'
      operationId: post_v1_events_event
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: event
          in: path
          required: true
          schema:
            type: integer
          description: event
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    delete:
      tags:
        - 'Admin — Content'
      summary: 'Удалить событие'
      operationId: delete_v1_events_event
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: event
          in: path
          required: true
          schema:
            type: integer
          description: event
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/files:
    get:
      tags:
        - 'Admin — Files'
      summary: 'Список файлов'
      operationId: get_v1_files
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/files/createImage:
    post:
      tags:
        - 'Admin — Files'
      summary: 'Загрузить изображение'
      operationId: post_v1_files_createImage
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                image:
                  type: string
                  format: binary
      responses:
        200:
          description: 'URL загруженного файла'
          content:
            application/json:
              schema:
                type: object
  /api/v1/logout:
    post:
      tags:
        - Auth
      summary: 'Выход из админки'
      operationId: post_v1_logout
      description: 'Удаляет все Sanctum-токены текущего пользователя.'
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный выход'
  /api/v1/main:
    get:
      tags:
        - 'Admin — Other'
      summary: 'Дашборд главной админки'
      operationId: get_v1_main
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/orders/create:
    post:
      tags:
        - 'Admin — Other'
      summary: 'Создать заказ (R-Keeper)'
      operationId: post_v1_orders_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/products:
    get:
      tags:
        - 'Admin — Menu'
      summary: 'Список продуктов'
      operationId: get_v1_products
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/products/UpdateFromR7:
    get:
      tags:
        - 'Admin — Menu'
      summary: 'Синхронизация меню из R-Keeper'
      operationId: get_v1_products_UpdateFromR7
      description: 'GET-запрос к XML Interface (`GetRefData`). Обновляет продукты и цены по `price_ident` / `thread_ident` филиалов.'
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Продукты обновлены'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/products/type/{category_type?}':
    get:
      tags:
        - 'Admin — Menu'
      summary: 'Продукты по типу категории'
      operationId: 'get_v1_products_type_category_type?'
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/products/{product}':
    get:
      tags:
        - 'Admin — Menu'
      summary: 'Продукт по ID'
      operationId: get_v1_products_product
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: product
          in: path
          required: true
          schema:
            type: integer
          description: product
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    post:
      tags:
        - 'Admin — Menu'
      summary: 'Обновить продукт'
      operationId: post_v1_products_product
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: product
          in: path
          required: true
          schema:
            type: integer
          description: product
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/publications:
    get:
      tags:
        - 'Admin — Content'
      summary: Публикации
      operationId: get_v1_publications
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: Публикации
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pagination'
  /api/v1/publications/create:
    post:
      tags:
        - 'Admin — Content'
      summary: 'Создать публикацию'
      operationId: post_v1_publications_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/publications/{publication}':
    get:
      tags:
        - 'Admin — Content'
      summary: 'Публикация по ID'
      operationId: get_v1_publications_publication
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: publication
          in: path
          required: true
          schema:
            type: integer
          description: publication
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    post:
      tags:
        - 'Admin — Content'
      summary: 'Обновить публикацию'
      operationId: post_v1_publications_publication
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: publication
          in: path
          required: true
          schema:
            type: integer
          description: publication
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    delete:
      tags:
        - 'Admin — Content'
      summary: 'Удалить публикацию'
      operationId: delete_v1_publications_publication
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: publication
          in: path
          required: true
          schema:
            type: integer
          description: publication
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/push:
    get:
      tags:
        - 'Admin — Push'
      summary: 'Список push-рассылок'
      operationId: get_v1_push
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: Push
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pagination'
  /api/v1/push/Pushv2:
    post:
      tags:
        - 'Admin — Push'
      summary: 'Отправить push (v2)'
      operationId: post_v1_push_Pushv2
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/push/SendPush:
    post:
      tags:
        - 'Admin — Push'
      summary: 'Отправить push (v1)'
      operationId: post_v1_push_SendPush
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/push/create:
    post:
      tags:
        - 'Admin — Push'
      summary: 'Создать рассылку'
      operationId: post_v1_push_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/push/diagnose:
    get:
      tags:
        - 'Admin — Push'
      summary: 'Диагностика Firebase'
      operationId: get_v1_push_diagnose
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/push/{push_notification}':
    post:
      tags:
        - 'Admin — Push'
      summary: 'Обновить рассылку'
      operationId: post_v1_push_push_notification
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: push_notification
          in: path
          required: true
          schema:
            type: integer
          description: push_notification
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    get:
      tags:
        - 'Admin — Push'
      summary: 'Рассылка по ID'
      operationId: get_v1_push_push_notification
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: push_notification
          in: path
          required: true
          schema:
            type: integer
          description: push_notification
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    delete:
      tags:
        - 'Admin — Push'
      summary: 'Удалить рассылку'
      operationId: delete_v1_push_push_notification
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: push_notification
          in: path
          required: true
          schema:
            type: integer
          description: push_notification
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/push/{push_notification}/resend':
    post:
      tags:
        - 'Admin — Push'
      summary: 'Повторная отправка'
      operationId: post_v1_push_push_notification_resend
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: push_notification
          in: path
          required: true
          schema:
            type: integer
          description: push_notification
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/reports/bonuses:
    get:
      tags:
        - 'Admin — Reports'
      summary: 'Отчёт по бонусам'
      operationId: get_v1_reports_bonuses
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: date_from
          in: query
          schema:
            type: string
            format: date
        -
          name: date_to
          in: query
          schema:
            type: string
            format: date
        -
          name: branch_id
          in: query
          schema:
            type: integer
      responses:
        200:
          description: Отчёт
          content:
            application/json:
              schema:
                type: object
  /api/v1/reviews:
    get:
      tags:
        - 'Admin — Reviews'
      summary: 'Список отзывов'
      operationId: get_v1_reviews
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: Отзывы
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pagination'
  /api/v1/reviews/putBonuces:
    post:
      tags:
        - 'Admin — Reviews'
      summary: 'Начислить бонусы за отзыв'
      operationId: post_v1_reviews_putBonuces
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/reviews/{review}':
    delete:
      tags:
        - 'Admin — Reviews'
      summary: 'Удалить отзыв'
      operationId: delete_v1_reviews_review
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: review
          in: path
          required: true
          schema:
            type: integer
          description: review
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    get:
      tags:
        - 'Admin — Reviews'
      summary: 'Отзыв по ID'
      operationId: get_v1_reviews_review
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: review
          in: path
          required: true
          schema:
            type: integer
          description: review
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    post:
      tags:
        - 'Admin — Reviews'
      summary: 'Обновить отзыв'
      operationId: post_v1_reviews_review
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: review
          in: path
          required: true
          schema:
            type: integer
          description: review
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/settings:
    get:
      tags:
        - 'Admin — Settings'
      summary: 'Глобальные настройки'
      operationId: get_v1_settings
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    post:
      tags:
        - 'Admin — Settings'
      summary: 'Обновить настройки'
      operationId: post_v1_settings
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/table-orders:
    get:
      tags:
        - 'Admin — Table Orders'
      summary: 'Список QR-заказов'
      operationId: get_v1_table-orders
      description: 'Пагинация. Фильтры: `branch_id`, `date_from`, `date_to`, `per_page`. Role 3/4 — только свои филиалы.'
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: branch_id
          in: query
          schema:
            type: integer
        -
          name: date_from
          in: query
          schema:
            type: string
            format: date
        -
          name: date_to
          in: query
          schema:
            type: string
            format: date
        -
          name: per_page
          in: query
          schema:
            type: integer
            default: 30
      responses:
        200:
          description: 'Список заказов по столам'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pagination'
  '/api/v1/table-orders/{tableOrder}':
    get:
      tags:
        - 'Admin — Table Orders'
      summary: 'Детали QR-заказа'
      operationId: get_v1_table-orders_tableOrder
      description: 'Включает `customer_phone`, `rkeeper_visit_id`, `rkeeper_order_ident`, `rkeeper_status`.'
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: tableOrder
          in: path
          required: true
          schema:
            type: integer
          description: 'ID заказа по столу'
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TableOrder'
  '/api/v1/tables/{branch}/create':
    post:
      tags:
        - 'Admin — Branches'
      summary: 'Создать стол'
      operationId: post_v1_tables_branch_create
      description: '`number` должен совпадать с Table code в R-Keeper для QR-заказов.'
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: branch
          in: path
          required: true
          schema:
            type: integer
          description: 'ID филиала'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TableInput'
      responses:
        200:
          description: 'Стол создан'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Table'
  '/api/v1/tables/{table}':
    post:
      tags:
        - 'Admin — Branches'
      summary: 'Обновить стол'
      operationId: post_v1_tables_table
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: table
          in: path
          required: true
          schema:
            type: integer
          description: 'ID стола'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TableInput'
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Table'
    delete:
      tags:
        - 'Admin — Branches'
      summary: 'Удалить стол'
      operationId: delete_v1_tables_table
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: table
          in: path
          required: true
          schema:
            type: integer
          description: 'ID стола'
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/tables/{table}/qr':
    get:
      tags:
        - 'Admin — Table Orders'
      summary: 'Получить/сгенерировать QR-токен стола'
      operationId: get_v1_tables_table_qr
      description: |-
        Генерирует `qr_token` если отсутствует.

        **`qr_content`** — строка для кодирования в QR (только токен, без URL).

        Приложение сканирует → `GET /api/mobile/table-context/{token}`.
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: table
          in: path
          required: true
          schema:
            type: integer
          description: 'ID стола'
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TableQrResponse'
  /api/v1/user:
    get:
      tags:
        - Auth
      summary: 'Текущий пользователь админки'
      operationId: get_v1_user
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LoginResponse'
  /api/v1/users/guests:
    get:
      tags:
        - 'Admin — Users'
      summary: 'Список гостей'
      operationId: get_v1_users_guests
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: Гости
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pagination'
  /api/v1/users/guests/deleted:
    get:
      tags:
        - 'Admin — Users'
      summary: 'Удалённые гости'
      operationId: get_v1_users_guests_deleted
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/users/guests/{user}':
    get:
      tags:
        - 'Admin — Users'
      summary: 'Гость по ID'
      operationId: get_v1_users_guests_user
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: user
          in: path
          required: true
          schema:
            type: integer
          description: user
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MobileUser'
    post:
      tags:
        - 'Admin — Users'
      summary: 'Обновить гостя'
      operationId: post_v1_users_guests_user
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: user
          in: path
          required: true
          schema:
            type: integer
          description: user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    delete:
      tags:
        - 'Admin — Users'
      summary: 'Удалить гостя'
      operationId: delete_v1_users_guests_user
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: user
          in: path
          required: true
          schema:
            type: integer
          description: user
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/users/guests/{user}/deposits-history':
    get:
      tags:
        - 'Admin — Users'
      summary: 'История бонусов гостя'
      operationId: get_v1_users_guests_user_deposits-history
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: user
          in: path
          required: true
          schema:
            type: integer
          description: user
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/users/staff:
    get:
      tags:
        - 'Admin — Users'
      summary: 'Список персонала'
      operationId: get_v1_users_staff
      security:
        -
          sanctum: {  }
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/v1/users/staff/create:
    post:
      tags:
        - 'Admin — Users'
      summary: 'Создать сотрудника'
      operationId: post_v1_users_staff_create
      security:
        -
          sanctum: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  '/api/v1/users/staff/{user}':
    get:
      tags:
        - 'Admin — Users'
      summary: 'Сотрудник по ID'
      operationId: get_v1_users_staff_user
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: user
          in: path
          required: true
          schema:
            type: integer
          description: user
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdminUser'
    post:
      tags:
        - 'Admin — Users'
      summary: 'Обновить сотрудника'
      operationId: post_v1_users_staff_user
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: user
          in: path
          required: true
          schema:
            type: integer
          description: user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
    delete:
      tags:
        - 'Admin — Users'
      summary: 'Удалить сотрудника'
      operationId: delete_v1_users_staff_user
      security:
        -
          sanctum: {  }
      parameters:
        -
          name: user
          in: path
          required: true
          schema:
            type: integer
          description: user
      responses:
        200:
          description: 'Успешный ответ'
          content:
            application/json:
              schema:
                type: object
  /api/yookassa/webhook:
    post:
      tags:
        - Webhooks
      summary: 'Webhook ЮKassa'
      operationId: post_yookassa_webhook
      description: |-
        Обрабатывает события ЮKassa.

        **QR-заказ (`metadata.type = table_order`):**
        - `payment.succeeded` → `payment_status: paid`, отправка в R-Keeper XML (CreateOrder + SaveOrder), начисление бонусов авторизованному
        - `payment.canceled` / failed → `payment_status: payment_failed`

        **Бронирование:** по `metadata.booking_id` — как раньше.
      security: {  }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/YookassaWebhookEvent'
      responses:
        200:
          description: OK
components:
  securitySchemes:
    sanctum:
      type: http
      scheme: bearer
      bearerFormat: Sanctum
      description: 'Токен из POST /api/loginWithEmail или mobile authWithCode'
    rkeeperAuth:
      type: apiKey
      in: body
      name: auth
      description: 'Секретный ключ в теле запроса (поле auth)'
  schemas:
    Error:
      type: object
      properties:
        message:
          type: string
          example: 'Описание ошибки'
    ValidationError:
      type: object
      properties:
        message:
          type: string
          example: 'The given data was invalid.'
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
    LoginRequest:
      type: object
      required:
        - email
        - password
      properties:
        email:
          type: string
          format: email
          example: admin@doski.bar
        password:
          type: string
          format: password
    LoginResponse:
      type: object
      properties:
        user:
          $ref: '#/components/schemas/AdminUser'
        token:
          type: string
          description: 'Bearer Sanctum token'
    AdminUser:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        surname:
          type: string
        email:
          type: string
        role:
          type: integer
          description: '1=superadmin, 2=admin, 3=branch admin, 4=manager'
        AdminBranches:
          type: array
          items:
            type: object
    TableContext:
      type: object
      properties:
        branch:
          type: object
          properties:
            id:
              type: integer
            title:
              type: string
            city:
              type: string
              nullable: true
            address:
              type: string
              nullable: true
        table:
          type: object
          properties:
            id:
              type: integer
            number:
              type: string
            seats:
              type: integer
        visit_time:
          type: string
          example: '14:30'
        qr_token:
          type: string
    PublicMenu:
      type: object
      properties:
        types:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
              title:
                type: string
              Categories:
                type: array
                items:
                  type: object
              products:
                type: array
                items:
                  $ref: '#/components/schemas/MenuProduct'
    MenuProduct:
      type: object
      properties:
        id:
          type: integer
        title:
          type: string
        titleR7:
          type: string
          nullable: true
        Ident:
          type: string
          nullable: true
        category_id:
          type: integer
        pivot:
          type: object
          properties:
            price:
              type: integer
              description: 'Цена в копейках или рублях (как в БД)'
            branch_id:
              type: integer
            product_id:
              type: integer
        Image:
          type: object
          nullable: true
        Category:
          type: object
          nullable: true
    LoyaltyInfo:
      type: object
      properties:
        balance:
          type: integer
        name:
          type: string
    TableOrderCreateRequest:
      type: object
      required:
        - branch_id
        - table_id
        - items
      properties:
        branch_id:
          type: integer
        table_id:
          type: integer
        items:
          type: array
          minItems: 1
          items:
            type: object
            required:
              - product_id
              - quantity
            properties:
              product_id:
                type: integer
              quantity:
                type: integer
                minimum: 1
        bonuses_to_spend:
          type: integer
          minimum: 0
          description: 'Макс. 25% от суммы заказа'
        loyalty_code:
          type: string
          description: 'Код лояльности (custom_code пользователя)'
        loyalty_action:
          type: string
          enum:
            - spend
            - earn
    TableOrderCreateResponse:
      type: object
      properties:
        order_id:
          type: integer
        status:
          type: string
          example: pending_payment_choice
        total:
          type: integer
        bonuses_spent:
          type: integer
        total_paid:
          type: integer
    TableOrderPaymentRequest:
      type: object
      required:
        - payment_method
      properties:
        payment_method:
          type: string
          enum:
            - card
          description: 'Только онлайн-оплата'
        phone:
          type: string
          example: '+7 (999) 123-45-67'
          description: 'Телефон для чека ЮKassa. Обязателен, если пользователь не авторизован.'
    TableOrderPaymentCardResponse:
      type: object
      properties:
        confirmation_url:
          type: string
          format: uri
        order_id:
          type: integer
    TableOrderPaymentCashResponse:
      deprecated: true
      type: object
      description: 'Не используется — QR-заказы только с онлайн-оплатой'
      properties:
        message:
          type: string
          example: 'Оплата QR-заказа доступна только онлайн'
    BranchSettings:
      type: object
      properties:
        interval_book:
          type: string
          example: '00:30'
          description: 'Интервал бронирования'
        first_hour_book:
          type: string
          example: '08:00:00'
        last_hour_book:
          type: string
          example: '23:00:00'
        pre_booking_time:
          type: integer
          description: 'За сколько дней возможна бронь'
        payment_return_time:
          type: string
          nullable: true
        qr_orders_enabled:
          type: boolean
          description: 'Разрешить заказы по QR на столе'
    BranchRkeeperConfig:
      type: object
      description: 'Настройки XML Interface R-Keeper для филиала. Station ID обязателен для отправки QR-заказов на кухню.'
      properties:
        custom_id:
          type: string
          description: 'ID ресторана в R-Keeper (restaurant)'
        price_ident:
          type: string
          description: 'Price_ident — тип цены в R7'
        thread_ident:
          type: string
          description: 'Trade_Ident — торговая группа в R7'
        rkeeper_xml_url:
          type: string
          format: uri
          example: 'https://host:82/rk7api/v0/xmlinterface.xml'
          description: 'URL XML API филиала. Если пусто — используется RKEEPER_DEFAULT_XML_URL'
        rkeeper_station_id:
          type: string
          example: '15015'
          description: 'Station ID для SaveOrder. Обязателен для QR-заказов'
        rkeeper_waiter_code:
          type: string
          nullable: true
          description: 'Waiter code для CreateOrder (необязательно)'
        rkeeper_login:
          type: string
          nullable: true
          description: 'Логин XML API. Если пусто — глобальный rkeeper_login'
        rkeeper_password:
          type: string
          format: password
          writeOnly: true
          description: 'Пароль XML API. Не возвращается в GET. Пустое значение при update — не менять'
    BranchCreateRequest:
      type: object
      required:
        - title
        - address
        - city_id
        - settings
        - oppening_time
      allOf:
        -
          $ref: '#/components/schemas/BranchRkeeperConfig'
        -
          type: object
          properties:
            title:
              type: string
            address:
              type: string
            city_id:
              type: integer
            phone:
              type: string
              nullable: true
            vk_href:
              type: string
              nullable: true
            inst_href:
              type: string
              nullable: true
            tg_href:
              type: string
              nullable: true
            coord:
              type: string
              nullable: true
            is_active:
              type: boolean
            settings:
              $ref: '#/components/schemas/BranchSettings'
            oppening_time:
              type: object
              description: 'Часы работы по дням недели'
            branch_blocked_booking:
              type: array
              items:
                type: object
            branch_extra_hours:
              type: array
              items:
                type: object
            branch_paid_booking:
              type: array
              items:
                type: object
    BranchUpdateRequest:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/BranchRkeeperConfig'
        -
          type: object
          properties:
            title:
              type: string
            address:
              type: string
            phone:
              type: string
              nullable: true
            vk_href:
              type: string
              nullable: true
            inst_href:
              type: string
              nullable: true
            tg_href:
              type: string
              nullable: true
            coord:
              type: string
              nullable: true
            is_active:
              type: boolean
            image_id:
              type: integer
              nullable: true
            settings:
              $ref: '#/components/schemas/BranchSettings'
            oppening_time:
              type: object
            branch_blocked_booking:
              type: array
              items:
                type: object
            branch_extra_hours:
              type: array
              items:
                type: object
            branch_paid_booking:
              type: array
              items:
                type: object
            images:
              type: array
              items:
                type: object
            admins:
              type: array
              items:
                type: object
            tables:
              type: array
              items:
                $ref: '#/components/schemas/TableInput'
    TableInput:
      type: object
      properties:
        id:
          type: integer
          nullable: true
        number:
          type: string
          description: 'Номер стола = Table code в R-Keeper'
        number_of_people:
          type: integer
        coord_x:
          type: number
          nullable: true
        coord_y:
          type: number
          nullable: true
    Table:
      type: object
      properties:
        id:
          type: integer
        branch_id:
          type: integer
        number:
          type: string
          description: 'Код стола в R-Keeper (Table code)'
        number_of_people:
          type: integer
        qr_token:
          type: string
          nullable: true
          description: 'Токен для QR-заказа'
    Branch:
      type: object
      allOf:
        -
          $ref: '#/components/schemas/BranchRkeeperConfig'
        -
          type: object
          properties:
            id:
              type: integer
            title:
              type: string
            address:
              type: string
            phone:
              type: string
              nullable: true
            vk_href:
              type: string
              nullable: true
            inst_href:
              type: string
              nullable: true
            tg_href:
              type: string
              nullable: true
            coord:
              type: string
              nullable: true
            is_active:
              type: boolean
            city_id:
              type: integer
            settings:
              $ref: '#/components/schemas/BranchSettings'
            oppening_time:
              type: object
              nullable: true
            tables:
              type: array
              items:
                $ref: '#/components/schemas/Table'
            Tables:
              type: array
              items:
                $ref: '#/components/schemas/Table'
            Settings:
              $ref: '#/components/schemas/BranchSettings'
            Booking_times:
              type: array
              items:
                type: string
    TableOrder:
      type: object
      properties:
        id:
          type: integer
        branch_id:
          type: integer
        table_id:
          type: integer
        user_id:
          type: integer
          nullable: true
        items:
          type: array
          items:
            type: object
            properties:
              product_id:
                type: integer
              title:
                type: string
              ident:
                type: string
                nullable: true
              quantity:
                type: integer
              price:
                type: integer
              line_total:
                type: integer
        total:
          type: integer
        bonuses_spent:
          type: integer
        total_paid:
          type: integer
        payment_method:
          type: string
          nullable: true
          enum:
            - card
        payment_status:
          type: string
          enum:
            - pending_payment_choice
            - pending
            - paid
            - payment_failed
          description: 'cash_pending — legacy, QR сейчас только card'
        rkeeper_status:
          type: string
          enum:
            - pending
            - sent
            - error
          description: 'sent — заказ ушёл в R-Keeper (CreateOrder + SaveOrder)'
        rkeeper_visit_id:
          type: string
          nullable: true
          description: 'VisitID из ответа R-Keeper CreateOrder'
        rkeeper_order_ident:
          type: string
          nullable: true
          description: 'OrderID из ответа R-Keeper CreateOrder'
        rkeeper_order_guid:
          type: string
          nullable: true
          description: 'guid заказа в R-Keeper'
        yookassa_payment_id:
          type: string
          nullable: true
        loyalty_code:
          type: string
          nullable: true
        customer_phone:
          type: string
          nullable: true
          description: 'Телефон для чека'
        branch:
          type: object
        table:
          type: object
        user:
          type: object
          nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    TableQrResponse:
      type: object
      properties:
        table_id:
          type: integer
        table_number:
          type: string
        branch_id:
          type: integer
        branch_title:
          type: string
        qr_token:
          type: string
          description: 'Содержимое QR-кода (только токен)'
        qr_content:
          type: string
        url:
          type: string
        deep_link:
          type: string
          nullable: true
    SendCodeRequest:
      type: object
      required:
        - phone
      properties:
        phone:
          type: string
          example: '+7 (999) 123-45-67'
    AuthWithCodeRequest:
      type: object
      required:
        - phone
        - code
        - fcmToken
      properties:
        phone:
          type: string
        code:
          type: string
          example: '1234'
        fcmToken:
          type: string
          description: 'Firebase Cloud Messaging token'
    MobileUser:
      type: object
      properties:
        id:
          type: integer
        phone_number:
          type: string
        name:
          type: string
          nullable: true
        surname:
          type: string
          nullable: true
        balance:
          type: integer
        custom_code:
          type: string
          description: 'Код лояльности'
        token:
          type: string
          description: 'Sanctum token (только при authWithCode)'
    Pagination:
      type: object
      properties:
        current_page:
          type: integer
        data:
          type: array
          items:
            type: object
        per_page:
          type: integer
        total:
          type: integer
        last_page:
          type: integer
    RkeeperAuth:
      type: object
      required:
        - auth
      properties:
        auth:
          type: string
          description: 'Секретный ключ интеграции R-Keeper'
    RkeeperGetBonusesRequest:
      allOf:
        -
          $ref: '#/components/schemas/RkeeperAuth'
        -
          type: object
          required:
            - customer_id
            - order
            - total_paid
          properties:
            customer_id:
              type: string
              description: 'custom_code пользователя'
            order:
              type: string
            total_paid:
              type: number
    RkeeperGiveOrderRequest:
      allOf:
        -
          $ref: '#/components/schemas/RkeeperAuth'
        -
          type: object
          required:
            - customer_id
            - is_bonuses_write_off
            - restaurant
            - order
            - total_paid
          properties:
            customer_id:
              type: string
            is_bonuses_write_off:
              type: boolean
            restaurant:
              type: string
              description: 'custom_id филиала'
            order:
              type: string
            total_paid:
              type: number
    YookassaWebhookEvent:
      type: object
      description: 'Событие ЮKassa. Для QR-заказов: object.metadata.type=table_order, object.metadata.order_id'
      properties:
        event:
          type: string
          example: payment.succeeded
        object:
          type: object
          properties:
            id:
              type: string
            status:
              type: string
              enum:
                - succeeded
                - canceled
                - pending
            metadata:
              type: object
              properties:
                type:
                  type: string
                  enum: [table_order]
                  description: 'table_order или booking_id для брони'
                order_id:
                  type: integer
                  description: 'ID table_orders'
                booking_id:
                  type: integer
    Booking:
      type: object
      properties:
        id:
          type: integer
        branch_id:
          type: integer
        user_id:
          type: integer
        date:
          type: string
          format: date
        time:
          type: string
        people_count:
          type: integer
        status:
          type: string
        payment_status:
          type: string
          nullable: true
  responses:
    Unauthorized:
      description: 'Не авторизован'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: 'Не найдено'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ValidationError:
      description: 'Ошибка валидации'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'
