openapi: 3.0.3
info:
  title: Krim Booking API
  version: 0.1.0
  license:
    name: Proprietary
    url: https://krimbooking.site
servers:
  - url: https://api.krimbooking.site
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  parameters:
    page:
      name: page
      in: query
      schema: { type: integer, minimum: 1, default: 1 }
    perPage:
      name: per_page
      in: query
      schema: { type: integer, minimum: 1, maximum: 100 }
    searchQ:
      name: q
      in: query
      schema: { type: string }
      description: Search query
  schemas:
    PaginationMeta:
      type: object
      properties:
        page: { type: integer }
        per_page: { type: integer }
        total: { type: integer }
        total_pages: { type: integer }
paths:
  /v1/health:
    get:
      summary: Health check
      operationId: getHealth
      security: []
      responses:
        '200':
          description: OK
        '400':
          description: Bad request
        '503':
          description: Service unavailable
  /v1/public/sitemap-data:
    get:
      summary: Sitemap URLs
      operationId: getSitemapData
      security: []
      responses:
        '200':
          description: URL list
        '400':
          description: Bad request
  /v1/public/regions:
    get:
      summary: Active regions with places
      operationId: listPublicRegions
      security: []
      responses:
        '200':
          description: Region list
  /v1/public/objects:
    get:
      summary: Published accommodation objects
      operationId: listPublicObjects
      security: []
      parameters:
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/perPage'
        - $ref: '#/components/parameters/searchQ'
        - name: region
          in: query
          schema: { type: string }
        - name: place
          in: query
          schema: { type: string }
        - name: type
          in: query
          schema: { type: string, enum: [hotel, apart_hotel, apartment, villa, guesthouse, hostel] }
      responses:
        '200':
          description: Object list with pagination meta
  /v1/public/objects/{regionSlug}/{slug}:
    get:
      summary: Published object by region and slug
      operationId: getPublicObject
      security: []
      parameters:
        - name: regionSlug
          in: path
          required: true
          schema: { type: string }
        - name: slug
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Object detail
        '404':
          description: Not found
  /v1/admin/auth/login:
    post:
      summary: Admin login
      operationId: adminLogin
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email: { type: string }
                password: { type: string }
      responses:
        '200':
          description: Tokens and permissions
        '401':
          description: Invalid credentials
        '403':
          description: Access denied
  /v1/admin/auth/forgot-password:
    post:
      summary: Request admin password reset email
      operationId: adminForgotPassword
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email]
              properties:
                email: { type: string, format: email }
      responses:
        '200':
          description: Generic success message (no email enumeration)
  /v1/admin/auth/reset-password/validate:
    get:
      summary: Validate password reset token
      operationId: adminValidateResetToken
      security: []
      parameters:
        - in: query
          name: token
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Token validity flag
  /v1/admin/auth/reset-password:
    post:
      summary: Set new password with reset token
      operationId: adminResetPassword
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [token, password]
              properties:
                token: { type: string }
                password: { type: string, minLength: 8 }
      responses:
        '200':
          description: Password reset applied
        '400':
          description: Invalid or expired token
  /v1/admin/auth/refresh:
    post:
      summary: Refresh access token
      operationId: adminRefresh
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [refresh_token]
              properties:
                refresh_token: { type: string }
      responses:
        '200':
          description: New tokens
  /v1/admin/me:
    get:
      summary: Current admin user
      operationId: adminMe
      security:
        - bearerAuth: []
      responses:
        '200':
          description: User, role, permissions
    patch:
      summary: Update current admin profile
      operationId: adminMeUpdate
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name: { type: string }
                last_name: { type: string, nullable: true }
                patronymic: { type: string, nullable: true }
                email: { type: string, format: email }
                phone: { type: string, nullable: true }
      responses:
        '200':
          description: Updated user, role, permissions
  /v1/admin/me/password:
    post:
      summary: Change current admin password
      operationId: adminMePassword
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [current_password, new_password]
              properties:
                current_password: { type: string }
                new_password: { type: string, minLength: 8 }
      responses:
        '200':
          description: Password changed, refresh tokens revoked
  /v1/admin/users:
    get:
      summary: List platform admin users
      operationId: listAdminUsers
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/perPage'
        - $ref: '#/components/parameters/searchQ'
        - name: status
          in: query
          schema: { type: string, enum: [active, blocked] }
        - name: role_id
          in: query
          schema: { type: integer }
      responses:
        '200':
          description: User list with pagination meta
    post:
      summary: Create platform admin user
      operationId: createAdminUser
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Created user
  /v1/admin/users/{id}:
    get:
      summary: Get admin user
      operationId: getAdminUser
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: User
    patch:
      summary: Update admin user
      operationId: updateAdminUser
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Updated user
  /v1/admin/users/{id}/impersonate:
    post:
      summary: Impersonate admin user
      operationId: impersonateAdminUser
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Tokens for target user with impersonator metadata
  /v1/admin/auth/stop-impersonation:
    post:
      summary: Stop impersonation session
      operationId: stopImpersonation
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Tokens for original admin user
  /v1/admin/regions:
    get:
      summary: List regions
      operationId: listAdminRegions
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/perPage'
        - $ref: '#/components/parameters/searchQ'
        - name: is_active
          in: query
          schema: { type: string, enum: ['0', '1', 'true', 'false'] }
      responses:
        '200':
          description: Region list with pagination meta
    post:
      summary: Create region
      operationId: createAdminRegion
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Created
  /v1/admin/regions/{id}/places:
    get:
      summary: List places in region
      operationId: listAdminPlaces
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/perPage'
        - $ref: '#/components/parameters/searchQ'
        - name: kind
          in: query
          schema: { type: string, enum: [city, resort, settlement] }
        - name: is_active
          in: query
          schema: { type: string, enum: ['0', '1', 'true', 'false'] }
      responses:
        '200':
          description: Place list with pagination meta
  /v1/admin/organizations:
    get:
      summary: List organizations (for object form select)
      operationId: listAdminOrganizations
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/perPage'
        - $ref: '#/components/parameters/searchQ'
      responses:
        '200':
          description: Organization list
  /v1/admin/objects:
    get:
      summary: List accommodation objects
      operationId: listAdminObjects
      security:
        - bearerAuth: []
      parameters:
        - $ref: '#/components/parameters/page'
        - $ref: '#/components/parameters/perPage'
        - $ref: '#/components/parameters/searchQ'
        - name: status
          in: query
          schema: { type: string, enum: [draft, published, archived] }
        - name: type
          in: query
          schema: { type: string, enum: [hotel, apart_hotel, apartment, villa, guesthouse, hostel] }
        - name: region_id
          in: query
          schema: { type: integer }
        - name: place_id
          in: query
          schema: { type: integer }
        - name: organization_id
          in: query
          schema: { type: integer }
      responses:
        '200':
          description: Object list with pagination meta
    post:
      summary: Create object
      operationId: createAdminObject
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Created
  /v1/admin/objects/{id}:
    get:
      summary: Get object by id
      operationId: getAdminObject
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Object detail
    patch:
      summary: Update object
      operationId: updateAdminObject
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Updated
    delete:
      summary: Delete object
      operationId: deleteAdminObject
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: integer }
      responses:
        '200':
          description: Deleted
  /v1/admin/roles:
    get:
      summary: List roles with permissions
      operationId: listAdminRoles
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Role list
  /v1/admin/permissions:
    get:
      summary: List all permissions
      operationId: listAdminPermissions
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Permission list
  /v1/admin/dashboard:
    get:
      summary: Admin dashboard stub
      operationId: getAdminDashboard
      security:
        - bearerAuth: []
      responses:
        '200':
          description: OK
        '401':
          description: Unauthorized
