openapi: "3.1.0"

info:
    title: ExtraNetWork API
    version: "1.5.22"
    description: |
        ExtraNetWork Otel Yönetim Platformu — tam endpoint dokümantasyonu.

        ## Kimlik Doğrulama

        | Header | Kullanım |
        |---|---|
        | `authToken` | JWT — login'den dönen token (çoğu endpoint) |
        | `bookingEngineToken` | Booking Engine widget endpointleri |
        | `myWebToken` | MyWeb public site endpointleri |

        ## Body Konvansiyonu

        Login hariç **tüm POST/PUT/PATCH** endpointleri şu formatta body bekler:
        ```json
        { "params": { ... } }
        ```

        ## Middleware Zinciri (iç endpointler)
        `cors → LanguageSetting → jwt.auth → userRoutePermissionAuthorize → property → contentWizard → checkPropertyChannelConnection`

servers:
    - url: http://api.extranetwork.local
      description: Local (Herd)
    - url: https://api.extranetwork.com
      description: Production

components:
    securitySchemes:
        authToken:
            type: apiKey
            in: header
            name: authToken
            description: "JWT token — `auth/login` response'undan alınır."
        bookingEngineToken:
            type: apiKey
            in: header
            name: bookingEngineToken
            description: Booking Engine widget için sabit token.
        myWebToken:
            type: apiKey
            in: header
            name: myWebToken
            description: MyWeb public site için sabit token.

    schemas:
        # NOTE:
        # Bu projede helper `apiResponse()` body içinde klasik `{ status: 1|0 }` dönmez.
        # Gerçek output:
        # {
        #   "status": 200,
        #   "error": false,
        #   "errorCode": null,
        #   "message": null,
        #   "data": { ... }
        # }
        ApiResponse:
            type: object
            required: [status, error, errorCode, message, data]
            properties:
                status:
                    type: integer
                    description: HTTP status code'nun body içindeki tekrarıdır.
                    example: 200
                error:
                    type: boolean
                    description: "`true` ise istek hata ile sonuçlanmıştır."
                    example: false
                errorCode:
                    oneOf:
                        - type: integer
                        - type: string
                        - type: "null"
                    description: "Uygulamaya özel hata kodu. Çoğu endpoint'te `null` döner."
                    example: null
                message:
                    type: ["string", "null"]
                    description: "Başarılı durumda çoğunlukla `null`, hata durumunda insan okunabilir mesaj."
                    example: null
                data:
                    description: Endpoint'e göre değişen veri
                    oneOf:
                        - type: object
                          additionalProperties: true
                        - type: array
                          items: {}
                    example: {}

        ParamsBody:
            type: object
            required: [params]
            properties:
                params:
                    type: object
                    additionalProperties: true
                    description: Endpoint'e özgü parametreler

        LoginRequest:
            type: object
            required: [email, password]
            properties:
                email:
                    type: string
                    format: email
                    example: admin@extranetwork.com
                password:
                    type: string
                    format: password
                    example: "Admin@1234!"
                remember_me:
                    type: boolean
                    default: false
                locale:
                    type: string
                    example: tr
                    description: "İki harfli dil kodu: tr, en, de…"
                onesignal_key:
                    type: ["string", "null"]
                    description: OneSignal push notification anahtarı

        LoginResponseData:
            type: object
            required: [token, expire_time, locale, property_list, user]
            properties:
                token:
                    type: string
                    description: JWT token — authToken header'ına eklenecek
                    example: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.example
                expire_time:
                    type: string
                    format: date-time
                    example: "2026-05-11T09:15:00+03:00"
                locale:
                    type: string
                    example: tr
                user:
                    $ref: "#/components/schemas/LoginUserSummary"
                property_list:
                    type: array
                    items:
                        $ref: "#/components/schemas/LoginPropertySummary"

        LoginResponse:
            allOf:
                - $ref: "#/components/schemas/ApiResponse"
                - type: object
                  properties:
                      data:
                          $ref: "#/components/schemas/LoginResponseData"

        RefreshTokenResponseData:
            type: object
            required: [token, expire_time]
            properties:
                token:
                    type: string
                    description: Yenilenmiş JWT token. Sonraki isteklerde eski token yerine kullanılmalıdır.
                    example: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.refreshed
                expire_time:
                    type: string
                    format: date-time
                    example: "2026-05-07T21:15:00+03:00"

        RefreshTokenResponse:
            allOf:
                - $ref: "#/components/schemas/ApiResponse"
                - type: object
                  properties:
                      data:
                          $ref: "#/components/schemas/RefreshTokenResponseData"

        LogoutResponse:
            allOf:
                - $ref: "#/components/schemas/ApiResponse"
                - type: object
                  properties:
                      data:
                          type: object
                          description: Logout endpoint'i boş obje döner.
                          example: {}

        LoginUserSummary:
            type: object
            required: [name, surname, language]
            properties:
                name:
                    type: string
                    example: Ahmet
                surname:
                    type: string
                    example: Yılmaz
                language:
                    type: string
                    example: tr

        LoginPropertySummary:
            type: object
            required: [id, name, default_photo]
            properties:
                id:
                    type: integer
                    example: 42
                name:
                    type: string
                    example: Grand Palace Hotel
                default_photo:
                    type: string
                    description: Property için thumbnail veya placeholder görseli.
                    example: https://cdn.extranetwork.com/property-photos/42/main_thumbnail.jpg

        UserObject:
            type: object
            properties:
                id:
                    type: integer
                    example: 1
                name:
                    type: string
                    example: Admin
                email:
                    type: string
                    format: email
                    example: admin@extranetwork.com
                role:
                    type: string
                    example: super_admin
                locale:
                    type: string
                    example: tr
                created_at:
                    type: string
                    format: date-time
                updated_at:
                    type: string
                    format: date-time

        UserCreateParams:
            type: object
            description: |
                Legacy create/register payload'ı.

                Dikkat:
                - Servis gelen `password` alanını doğrudan kullanmaz.
                - İç tarafta rasgele 6 karakterlik bir şifre üretir ve kullanıcıya mail ile iletir.
            required: [name, email]
            properties:
                name:
                    type: string
                    example: Ahmet Yılmaz
                surname:
                    type: string
                    example: Demir
                email:
                    type: string
                    format: email
                    example: ahmet@otel.com
                password:
                    type: string
                    format: password
                    description: İstemci bazında gönderilse bile servis tarafında override edilir.
                    example: "Sifre@123"
                gender:
                    type: ["string", "null"]
                    example: male
                phone:
                    type: ["string", "null"]
                    example: "+905551112233"
                language:
                    type: string
                    example: tr
                status:
                    type: integer
                    description: Genelde public register'da 0, register-with-property akışında 1 olarak ayarlanır.
                    example: 0

        UserRegisterWithPropertyParams:
            type: object
            required: [name, email, property_name]
            properties:
                name:
                    type: string
                    example: Ahmet
                surname:
                    type: string
                    example: Demir
                email:
                    type: string
                    format: email
                    example: ahmet@otel.com
                phone:
                    type: ["string", "null"]
                    example: "+905551112233"
                language:
                    type: ["string", "null"]
                    example: en
                property_name:
                    type: string
                    example: Grand Palace Hotel
                web:
                    type: ["string", "null"]
                    example: www.grandpalacehotel.com

        UserUpdateParams:
            type: object
            required: [update_user_id, user_update_data]
            properties:
                update_user_id:
                    type: integer
                    example: 5
                user_update_data:
                    type: object
                    description: Sadece izinli alanlar güncellenebilir.
                    properties:
                        name:
                            type: string
                        surname:
                            type: string
                        gender:
                            type: ["string", "null"]
                        phone:
                            type: ["string", "null"]
                        password:
                            type: string
                            format: password
                        status:
                            type: integer
                            enum: [0, 1]

        ChangePasswordParams:
            type: object
            required: [old_password, password, password_confirmation]
            properties:
                old_password:
                    type: string
                    format: password
                password:
                    type: string
                    format: password
                    minLength: 6
                password_confirmation:
                    type: string
                    format: password

        AddUserPropertyParams:
            type: object
            required: [add_user_id, add_property_id]
            properties:
                add_user_id:
                    type: integer
                    example: 5
                add_property_id:
                    type: integer
                    example: 12

        RemoveUserPropertyParams:
            type: object
            required: [remove_user_id, remove_property_id]
            properties:
                remove_user_id:
                    type: integer
                    example: 5
                remove_property_id:
                    type: integer
                    example: 12

        ForgotPasswordParams:
            type: object
            required: [email]
            properties:
                email:
                    type: string
                    format: email
                    example: ahmet@otel.com

        ResetPasswordParams:
            type: object
            required: [email, key, password, password_confirmation]
            properties:
                email:
                    type: string
                    format: email
                    example: ahmet@otel.com
                key:
                    type: string
                    minLength: 128
                    description: "E-posta linkinden gelen `key` değeri. Servis tarafında `hash_key` olarak kullanılır."
                password:
                    type: string
                    format: password
                    minLength: 6
                password_confirmation:
                    type: string
                    format: password

        NewPasswordParams:
            type: object
            required: [email, key, password, password_confirmation]
            properties:
                email:
                    type: string
                    format: email
                    example: ahmet@otel.com
                key:
                    type: string
                    minLength: 128
                    description: "Aktivasyon linkinden gelen `key` değeri."
                password:
                    type: string
                    format: password
                    minLength: 6
                password_confirmation:
                    type: string
                    format: password

        CheckKeyParams:
            type: object
            required: [email, key]
            properties:
                email:
                    type: string
                    format: email
                    example: ahmet@otel.com
                key:
                    type: string
                    minLength: 128
                    description: Kullanıcı aktivasyon anahtarı

        JwtTokenPayload:
            type: object
            properties:
                token:
                    type: string
                    example: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.example
                iat:
                    type: integer
                    example: 1778046300
                remember_me:
                    type: boolean
                    example: false
                exp:
                    type: integer
                    example: 1778478300

        UserEntity:
            type: object
            properties:
                id:
                    type: integer
                    example: 18
                name:
                    type: string
                    example: Ahmet
                surname:
                    type: string
                    example: Demir
                email:
                    type: string
                    format: email
                    example: ahmet@otel.com
                gender:
                    type: ["string", "null"]
                    example: male
                phone:
                    type: ["string", "null"]
                    example: "+905551112233"
                language:
                    type: ["string", "null"]
                    example: tr
                status:
                    type: integer
                    example: 1
                hash_key:
                    type: string
                    example: 6f35bf0f7c2d27f2d0f2cc2cbb50235e4ee4dc44716f6d7a9d2b8355b9f663e8fd99ac6d88b0ff1ea6ea117f4d61375c3e7f04810dd3c70c2bfc4cbd6f0a61b0
                userPassword:
                    type: string
                    description: Servisin ürettiği geçici şifre; her endpointte dönmeyebilir.
                    example: aB12xZ

        PublicUserRegisterResponseData:
            type: object
            properties:
                user:
                    $ref: "#/components/schemas/UserEntity"
                token:
                    $ref: "#/components/schemas/JwtTokenPayload"

        RegisterWithPropertyResponseData:
            type: object
            properties:
                token:
                    type: string
                expire_time:
                    type: string
                    format: date-time
                locale:
                    type: ["string", "null"]
                property_list:
                    type: array
                    items:
                        $ref: "#/components/schemas/LoginPropertySummary"
                user:
                    type: object
                    properties:
                        name:
                            type: string
                        surname:
                            type: string

        UserProfile:
            type: object
            properties:
                id:
                    type: integer
                email:
                    type: string
                    format: email
                name:
                    type: string
                surname:
                    type: string
                gender:
                    type: ["string", "null"]
                language:
                    type: string
                phone:
                    type: ["string", "null"]

        LanguageOption:
            type: object
            properties:
                id:
                    type: integer
                code:
                    type: string
                    example: tr
                name:
                    type: string
                    example: Turkish
                status:
                    type: integer
                    example: 1
                language_key:
                    type: string
                    example: tr_TR

        UserProfileResponseData:
            type: object
            properties:
                profile:
                    $ref: "#/components/schemas/UserProfile"
                languages:
                    type: array
                    items:
                        $ref: "#/components/schemas/LanguageOption"

        UserSetPropertyParams:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 12

        UserMenuParams:
            type: object
            properties:
                property_id:
                    type: integer
                    description: Belirli bir property için menü filtrelemek istenirse gönderilir.
                    example: 42
                locale:
                    type: string
                    description: Menü ağacını locale bazlı üretmek için kullanılır.
                    example: tr

        PropertyMenuNode:
            type: object
            additionalProperties: true
            description: Permission servisi tarafından dönen menü düğümü. Yapı derinliği role göre değişebilir.

        UserMenuProperty:
            type: object
            properties:
                id:
                    type: integer
                    example: 42
                name:
                    type: string
                    example: Grand Palace Hotel
                property_menu:
                    type: array
                    items:
                        $ref: "#/components/schemas/PropertyMenuNode"

        UserMenuResponseData:
            type: object
            properties:
                property_list:
                    type: array
                    items:
                        $ref: "#/components/schemas/UserMenuProperty"

        LanguageItem:
            type: object
            properties:
                id:
                    type: integer
                    example: 1
                code:
                    type: string
                    example: tr
                name:
                    type: string
                    example: Turkish
                status:
                    type: integer
                    example: 1
                language_key:
                    type: string
                    example: tr_TR

        NullDescriptionItem:
            type: object
            properties:
                language_code:
                    type: string
                    example: tr
                description:
                    type: ["string", "null"]
                    example: null

        CurrencyItem:
            type: object
            additionalProperties: true
            description: Currency repository'den dönen aktif para birimi kaydı.
            properties:
                id:
                    type: integer
                    example: 1
                code:
                    type: string
                    example: TRY
                name:
                    type: string
                    example: Turkish Lira
                status:
                    type: integer
                    example: 1
                is_basic:
                    type: integer
                    example: 1

        ContactFormParams:
            type: object
            required: [name, surname, email, subject]
            properties:
                name:
                    type: string
                    maxLength: 100
                    example: Ahmet
                surname:
                    type: string
                    maxLength: 100
                    example: Demir
                email:
                    type: string
                    format: email
                    maxLength: 150
                    example: ahmet@otel.com
                subject:
                    type: string
                    maxLength: 500
                    example: Demo talebi oluşturmak istiyorum.

        PropertyListParams:
            type: object
            properties:
                locale:
                    type: string
                    example: tr

        PropertyListItem:
            type: object
            properties:
                id:
                    type: integer
                    example: 42
                name:
                    type: string
                    example: Grand Palace Hotel
                default_photo:
                    type: string
                    example: https://cdn.extranetwork.com/property-photos/42/main_thumbnail.jpg
                property_menu:
                    type: array
                    items:
                        $ref: "#/components/schemas/PropertyMenuNode"

        PropertyListResponseData:
            type: object
            properties:
                property_list:
                    type: array
                    items:
                        $ref: "#/components/schemas/PropertyListItem"

        PropertyCreateResponseData:
            type: object
            additionalProperties: true
            description: Yeni oluşturulan property kaydı. Repository çıktısı model alanlarını içerir.
            properties:
                id:
                    type: integer
                    example: 42
                name:
                    type: string
                    example: enw-your_property_name
                status:
                    type: integer
                    example: 2
                created_by:
                    type: integer
                    example: 5
                updated_by:
                    type: integer
                    example: 5

        PropertyInfoGetParams:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 42
                locale:
                    type: string
                    example: tr

        PropertyInfoUpdateParams:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 42
                locale:
                    type: string
                    example: tr
                has_locale_name:
                    type: boolean
                    default: false
                property_info:
                    type: object
                    additionalProperties: true
                    description: Property ana bilgileri. Servis bu payload içinden alan bazlı update yapar.
                additional_info:
                    type: object
                    additionalProperties: true
                    description: Property additional info anahtar/değer alanları.
                property_language_spoken:
                    type: array
                    items:
                        oneOf:
                            - type: string
                            - type: object
                              additionalProperties: true

        PropertyContentCodeParams:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 42
                content_code:
                    type: ["string", "null"]
                    minLength: 5
                    maxLength: 10
                    example: ABC12

        PropertyTypeItem:
            type: object
            properties:
                id:
                    type: integer
                    example: 1
                name:
                    type: string
                    example: Hotel
                language_key:
                    type: string
                    example: property_type_hotel

        PropertyChainItem:
            type: object
            properties:
                id:
                    type: integer
                    example: 1
                name:
                    type: string
                    example: Independent
                loyalty:
                    type: ["string", "null"]
                    example: null

        CountryItem:
            type: object
            additionalProperties: true
            properties:
                id:
                    type: integer
                    example: 223
                name:
                    type: string
                    example: Turkey

        GeneralTimezoneItem:
            type: object
            properties:
                id:
                    type: integer
                    example: 1
                location:
                    type: string
                    example: Europe/Istanbul
                description:
                    type: string
                    example: GMT+03:00 Istanbul
                action_type:
                    type: string
                    example: plus
                hour:
                    type: integer
                    example: 3
                minute:
                    type: integer
                    example: 0

        PropertyInfoPayload:
            type: object
            additionalProperties: true
            properties:
                id:
                    type: integer
                    example: 42
                name:
                    type: string
                    example: Grand Palace Hotel
                property_type_id:
                    type: integer
                    example: 1
                chain_id:
                    type: integer
                    example: 1
                rating:
                    type: integer
                    example: 5
                official_name:
                    type: ["string", "null"]
                    example: Grand Palace Hotel Resort Spa
                tax_office:
                    type: ["string", "null"]
                    example: Beşiktaş
                tax_number:
                    type: ["string", "null"]
                    example: 1234567890
                currency_type:
                    type: ["string", "null"]
                    example: TRY
                country:
                    type: ["string", "null"]
                    example: TR
                has_locale_name:
                    type: boolean
                    example: false

        PropertyInfoGetResponseData:
            type: object
            properties:
                get_property:
                    type: object
                    properties:
                        property_info:
                            $ref: "#/components/schemas/PropertyInfoPayload"
                        property_language_spoken:
                            type: array
                            items:
                                additionalProperties: true
                        additional_info:
                            type: object
                            additionalProperties: true
                minimum_age_policies:
                    type: array
                    items:
                        additionalProperties: true
                property_type:
                    type: array
                    items:
                        $ref: "#/components/schemas/PropertyTypeItem"
                property_chains:
                    type: array
                    items:
                        $ref: "#/components/schemas/PropertyChainItem"
                countries:
                    type: array
                    items:
                        $ref: "#/components/schemas/CountryItem"
                general_timezone:
                    type: array
                    items:
                        $ref: "#/components/schemas/GeneralTimezoneItem"

        PropertyIdParams:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 42

        PropertyDateRangeParams:
            type: object
            required: [property_id, start_date, finish_date]
            properties:
                property_id:
                    type: integer
                    example: 42
                start_date:
                    type: string
                    format: date
                    example: "2026-01-01"
                finish_date:
                    type: string
                    format: date
                    example: "2026-01-31"

        PropertyDashboardResponseData:
            type: object
            additionalProperties: true
            properties:
                hotel_name:
                    type: string
                    example: Grand Palace Hotel
                site_hints:
                    oneOf:
                        - type: object
                          additionalProperties: true
                        - type: array
                          items:
                              additionalProperties: true
                content_code:
                    type: ["string", "null"]
                    example: ABC12

        PropertyPabDashboardResponseData:
            type: object
            additionalProperties: true
            description: Property network dashboard verisi. İç yapı servis çıktısına göre değişebilir.

        PropertyDashboardPlusSummaryResponseData:
            type: object
            properties:
                propertyId:
                    type: integer
                    example: 42
                propertyName:
                    type: string
                    example: Grand Palace Hotel
                todayCheckin:
                    oneOf:
                        - type: integer
                        - type: number
                    example: 4
                todayCheckout:
                    oneOf:
                        - type: integer
                        - type: number
                    example: 3
                lengthOfStay:
                    oneOf:
                        - type: integer
                        - type: number
                    example: 2.4
                lengthOfBooking:
                    oneOf:
                        - type: integer
                        - type: number
                    example: 12
                totalBooking:
                    oneOf:
                        - type: object
                          additionalProperties: true
                        - type: array
                          items:
                              additionalProperties: true
                totalPax:
                    oneOf:
                        - type: object
                          additionalProperties: true
                        - type: array
                          items:
                              additionalProperties: true
                averageDailyRate:
                    oneOf:
                        - type: object
                          additionalProperties: true
                        - type: array
                          items:
                              additionalProperties: true

        PropertyAnalyticsResponseData:
            oneOf:
                - type: object
                  additionalProperties: true
                - type: array
                  items:
                      additionalProperties: true
            description: Dashboard Plus alt endpoint çıktısı. Servis çıktısına göre object veya liste olabilir.

        BookingEngineReportParams:
            type: object
            required: [property_id, start_date, finish_date, type]
            properties:
                property_id:
                    type: integer
                    example: 42
                start_date:
                    type: string
                    format: date
                    example: "2026-01-01"
                finish_date:
                    type: string
                    format: date
                    example: "2026-01-31"
                type:
                    type: string
                    enum: [TRS, GTR, DSR, DSS, UCR, ULR]
                    example: TRS
                channel_id:
                    type: integer
                    description: Sadece `DSS` rapor tipinde gereklidir.
                    example: 3

        CouponCodeReportParams:
            type: object
            required: [property_id, start_date, finish_date]
            properties:
                property_id:
                    type: integer
                    example: 42
                start_date:
                    type: string
                    format: date
                    example: "2026-01-01"
                finish_date:
                    type: string
                    format: date
                    example: "2026-01-31"
                code:
                    type: ["string", "null"]
                    example: WINTER25
                status:
                    type: integer
                    description: Varsayılan değer 1.
                    example: 1

        CouponCodeReportItem:
            type: object
            properties:
                id:
                    type: integer
                    example: 1001
                transaction_period:
                    type: ["string", "null"]
                    example: 2026-01
                checkout_period:
                    type: ["string", "null"]
                    example: 2026-02
                code:
                    type: ["string", "null"]
                    example: WINTER25
                booking_code:
                    type: ["string", "null"]
                    example: ENW-2026-0001
                name_surname:
                    type: ["string", "null"]
                    example: Ahmet Demir
                checkin_date:
                    type: ["string", "null"]
                    format: date
                checkout_date:
                    type: ["string", "null"]
                    format: date
                length_of_stay:
                    type: ["integer", "null"]
                    example: 3
                length_of_booking:
                    type: ["integer", "null"]
                    example: 12
                total:
                    oneOf:
                        - type: integer
                        - type: number
                        - type: "null"
                    example: 4500
                total_formatted:
                    type: ["string", "null"]
                    example: 4.500,00 TRY
                currency_code:
                    type: ["string", "null"]
                    example: TRY
                status:
                    type: ["integer", "null"]
                    example: 1
                status_name:
                    type: ["string", "null"]
                    example: Confirmed
                status_language_key:
                    type: ["string", "null"]
                    example: booking_status_confirmed
                time:
                    type: ["string", "null"]
                time_formatted:
                    type: ["string", "null"]
                    example: 31.01.2026 14:35:00

        PropertyLocaleParams:
            type: object
            properties:
                locale:
                    type: string
                    example: tr

        PropertyScopedLocaleParams:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 42
                locale:
                    type: string
                    example: tr

        PropertyContactUpdateParams:
            type: object
            required: [property_id, contact]
            properties:
                property_id:
                    type: integer
                    example: 42
                contact:
                    type: object
                    additionalProperties: true
                    description: İletişim bilgileri payload'ı. Servis contact alanlarını buradan işler.
                property_info:
                    type: object
                    additionalProperties: true
                    description: Sadece `official_name`, `tax_office`, `tax_number` alanları dikkate alınır.

        PropertyExecutiveParams:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 42
                locale:
                    type: string
                    example: tr
                executive_type:
                    oneOf:
                        - type: string
                        - type: object
                          additionalProperties: true
                    description: Executive işlem payload'ı. İç yapı servis tarafında değerlendirilir.

        PropertyExecutiveDeleteParams:
            type: object
            required: [property_id, property_executive_id]
            properties:
                property_id:
                    type: integer
                    example: 42
                property_executive_id:
                    type: integer
                    example: 7
                locale:
                    type: string
                    example: tr

        PropertyConfigParams:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 42
                locale:
                    type: string
                    example: tr
                config_keys:
                    oneOf:
                        - type: array
                          items:
                              type: string
                        - type: object
                          additionalProperties: true
                    description: Config anahtarları veya update payload'ı.

        PropertyBrandGetParams:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 42
                locale:
                    type: string
                    example: tr

        PropertyBrandUpdateForm:
            type: object
            required: [property_id]
            properties:
                property_id:
                    type: integer
                    example: 42
                title:
                    type: string
                    example: Grand Palace Hotel
                colors:
                    oneOf:
                        - type: array
                          items:
                              type: string
                        - type: string
                    description: Brand renk kodları.
                    example: '["#000000","#ffffff"]'
                logo_path:
                    type: string
                    example: /property-brand/42/logo.png
                logo_name:
                    type: string
                    example: logo.png
                photo:
                    type: string
                    format: binary

        PropertyInfoGenericResponse:
            oneOf:
                - type: object
                  additionalProperties: true
                - type: array
                  items:
                      additionalProperties: true
            description: Legacy property info endpoint'lerinin servis çıktısı.

        PropertySummary:
            type: object
            properties:
                id:
                    type: integer
                    example: 42
                name:
                    type: string
                    example: "Grand Palace Hotel"
                status:
                    type: integer
                    example: 1

    requestBodies:
        Params:
            required: true
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ParamsBody"

    responses:
        Success:
            description: Başarılı yanıt
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ApiResponse"
                    example:
                        status: 200
                        error: false
                        errorCode: null
                        message: null
                        data: {}
        BadRequest:
            description: Validation veya business-rule hatasi
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ApiResponse"
                    example:
                        status: 400
                        error: true
                        errorCode: null
                        message: Email or password is wrong.
                        data: {}
        Unauthorized:
            description: Token eksik veya geçersiz
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ApiResponse"
                    example:
                        status: 401
                        error: true
                        errorCode: null
                        message: Unauthorized
                        data: {}
        Forbidden:
            description: Yetkisiz erişim — permission veya property mapping yok
            content:
                application/json:
                    schema:
                        $ref: "#/components/schemas/ApiResponse"
                    example:
                        status: 403
                        error: true
                        errorCode: null
                        message: Forbidden
                        data: {}

tags:
    - name: Auth
      description: Login, logout, token yenileme, şifre işlemleri
    - name: User
      description: Kullanıcı CRUD, profil, property mapping
    - name: Property
      description: Property CRUD, dashboard, raporlar
    - name: Property Info
      description: Contact, brand, config, executive, type, chain
    - name: Content
      description: Property content, fact, additional info
    - name: Photo
      description: Fotoğraf yönetimi, kategoriler, yayın
    - name: Place
      description: Tesis içi yer/alan yönetimi
    - name: Awards
      description: Ödüller ve sertifikalar
    - name: Room
      description: Oda yapısı, yatak, tip referansları
    - name: Rate
      description: Room rate + mapping + channel/inclusion mapping
    - name: Channel
      description: Channel mapping, group, contact, nonrefundable, destination
    - name: Policy
      description: İptal politikası ve kişi fiyatlama politikası
    - name: Inventory
      description: Oda/grup inventory, bulk update, rate-availability
    - name: Booking
      description: Property bookings, transactions, tickets
    - name: Payment
      description: Ödeme dashboard/mapping/installments/manual
    - name: Offer
      description: Teklif yönetimi
    - name: Promotion
      description: Promosyon yönetimi
    - name: CPA
      description: Competitor Price Analysis
    - name: Reputation
      description: Yorum ve itibar yönetimi
    - name: Web Builder
      description: PropertyWeb / content / popup / component
    - name: MyWeb
      description: Public website renderer (myWebToken)
    - name: Booking Engine
      description: BookingEngine widget API (bookingEngineToken)
    - name: Payment Link
      description: Ödeme linki başlatma ve onaylama
    - name: CM-Reseliva
      description: "Channel Manager: Reseliva"
    - name: CM-Channex
      description: "Channel Manager: Channex"
    - name: CM-HotelRunner
      description: "Channel Manager: HotelRunner"
    - name: CM-ElektraWeb
      description: "Channel Manager: ElektraWeb"
    - name: CM-Athena
      description: "Channel Manager: Athena"
    - name: CM-Fina
      description: "Channel Manager: Fina"
    - name: CM-SistemOtel
      description: "Channel Manager: SistemOtel"
    - name: CM-1C
      description: "Channel Manager: 1C"
    - name: CM-HyperGuest
      description: "Channel Manager: HyperGuest"
    - name: Meta-Trivago
      description: "MetaSearch: Trivago"
    - name: Meta-Yandex
      description: "MetaSearch: Yandex"
    - name: Meta-Google
      description: "MetaSearch: Google"
    - name: Product
      description: Property products, addons, coupons
    - name: AI
      description: OpenAI integrations
    - name: Export
      description: PDF / Excel exportları
    - name: Utility
      description: Test, language, currency, contact-form

paths:
    # ══════════════════════════════════════════════════════
    # 1 ─ AUTH
    # ══════════════════════════════════════════════════════

    /app/v1/auth/login:
        post:
            tags: [Auth]
            summary: Login
            description: |
                Kullanıcı e-posta ve şifre ile giriş yapar.

                Başarılı durumda:
                - yeni bir JWT üretilir
                - token'in `md5` özeti `api_access_token` tablosuna yazılır
                - aktif property mapping listesi döner
                - opsiyonel `onesignal_key` gönderildiyse kullanıcıya kaydedilir

                Başarılı yanıtta `data.token` sonraki tüm isteklerde `authToken` header'ı olarak gönderilmelidir.

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: authLogin
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/LoginRequest"
                        example:
                            email: admin@extranetwork.com
                            password: "Admin@1234!"
                            remember_me: true
                            locale: tr
                            onesignal_key: "4c8f56d2-7bcb-4cf6-87df-123456789abc"
            responses:
                "200":
                    description: Başarılı giriş
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/LoginResponse"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.example
                                    expire_time: "2026-05-11T09:15:00+03:00"
                                    locale: tr
                                    property_list:
                                        - id: 42
                                          name: Grand Palace Hotel
                                          default_photo: https://cdn.extranetwork.com/property-photos/42/main_thumbnail.jpg
                                    user:
                                        name: Ahmet
                                        surname: Yılmaz
                                        language: tr
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/auth/refresh-token:
        get:
            tags: [Auth]
            summary: Token yenile
            description: |
                Mevcut geçerli JWT'yi yenileyerek yeni bir token döner.

                Kod davranışı:
                - `authToken` header'ı decode edilir
                - `api_access_token` içinde kayıtlı ve invalidate edilmemiş token aranır
                - yeni JWT üretilir
                - mevcut token satırı yeni `md5(token)` ve `expire_date` ile güncellenir

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: authRefreshToken
            security:
                - authToken: []
            responses:
                "200":
                    description: Başarılı token yenileme
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/RefreshTokenResponse"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.refreshed
                                    expire_time: "2026-05-07T21:15:00+03:00"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/logout:
        post:
            tags: [Auth]
            summary: Logout
            description: |
                Token'ı geçersiz kılar, oturumu kapatır.

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: authLogout
            security:
                - authToken: []
            responses:
                "200":
                    description: Başarılı logout
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/LogoutResponse"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: Logged out.
                                data: {}
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    # ══════════════════════════════════════════════════════
    # 2 ─ USER (public — jwt yok)
    # ══════════════════════════════════════════════════════

    /app/v1/user/register:
        post:
            tags: [User]
            summary: Kullanıcı kaydı
            description: |
                Yeni kullanıcı oluşturur (property olmadan).

                Legacy davranış:
                - gelen payload `params` altında beklenir
                - servis kendi geçici şifresini üretir
                - response içinde `user` ve JWT payload birlikte döner

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: userRegister
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/UserCreateParams"
                        example:
                            params:
                                name: Ahmet
                                surname: Demir
                                email: ahmet@otel.com
                                phone: "+905551112233"
                                language: tr
            responses:
                "200":
                    description: Başarılı kayıt
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PublicUserRegisterResponseData"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    user:
                                        id: 18
                                        name: Ahmet
                                        surname: Demir
                                        email: ahmet@otel.com
                                        language: tr
                                        status: 0
                                        hash_key: 6f35bf0f7c2d27f2d0f2cc2cbb50235e4ee4dc44716f6d7a9d2b8355b9f663e8fd99ac6d88b0ff1ea6ea117f4d61375c3e7f04810dd3c70c2bfc4cbd6f0a61b0
                                        userPassword: aB12xZ
                                    token:
                                        token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.example
                                        iat: 1778046300
                                        remember_me: false
                                        exp: 1778478300
                "400":
                    $ref: "#/components/responses/BadRequest"

    /app/v1/user/register-user-with-property:
        post:
            tags: [User]
            summary: Kullanıcı + property kaydı
            description: |
                Yeni kullanıcı ve property'yi aynı anda oluşturur.

                Bu akış:
                - aktif user kaydı açar
                - property oluşturur
                - user/property mapping yazar
                - default property ürünlerini tanımlar
                - JWT ve `api_access_token` kaydı oluşturur

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: userRegisterWithProperty
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/UserRegisterWithPropertyParams"
            responses:
                "200":
                    description: Başarılı kullanıcı + property kaydı
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/RegisterWithPropertyResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /app/v1/user/check-key:
        post:
            tags: [User]
            summary: Aktivasyon anahtarı kontrolü
            description: |
                E-posta aktivasyon veya davet anahtarının geçerliliğini kontrol eder.

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: userCheckKey
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/CheckKeyParams"
                        example:
                            params:
                                email: ahmet@otel.com
                                key: 6f35bf0f7c2d27f2d0f2cc2cbb50235e4ee4dc44716f6d7a9d2b8355b9f663e8fd99ac6d88b0ff1ea6ea117f4d61375c3e7f04810dd3c70c2bfc4cbd6f0a61b0
            responses:
                "200":
                    $ref: "#/components/responses/Success"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /app/v1/user/forgot-password:
        post:
            tags: [User]
            summary: Şifremi unuttum
            description: |
                Verilen e-posta adresine şifre sıfırlama linki gönderir.

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: userForgotPassword
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/ForgotPasswordParams"
                        example:
                            params:
                                email: ahmet@otel.com
            responses:
                "200":
                    $ref: "#/components/responses/Success"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /app/v1/user/reset-password:
        post:
            tags: [User]
            summary: Şifre sıfırla (token ile)
            description: |
                E-posta ile gelen token kullanılarak şifre sıfırlanır.

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: userResetPassword
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/ResetPasswordParams"
                        example:
                            params:
                                email: ahmet@otel.com
                                key: 6f35bf0f7c2d27f2d0f2cc2cbb50235e4ee4dc44716f6d7a9d2b8355b9f663e8fd99ac6d88b0ff1ea6ea117f4d61375c3e7f04810dd3c70c2bfc4cbd6f0a61b0
                                password: "YeniSifre123"
                                password_confirmation: "YeniSifre123"
            responses:
                "200":
                    $ref: "#/components/responses/Success"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /app/v1/user/new-password:
        post:
            tags: [User]
            summary: Yeni şifre belirle (ilk giriş)
            description: |
                Aktivasyon aşamasındaki kullanıcının kalıcı şifresini belirler.

                Not:
                - request'te `params.key` alınır
                - controller bunu servis için `hash_key` alanına map eder

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: userNewPassword
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/NewPasswordParams"
                        example:
                            params:
                                email: ahmet@otel.com
                                key: 6f35bf0f7c2d27f2d0f2cc2cbb50235e4ee4dc44716f6d7a9d2b8355b9f663e8fd99ac6d88b0ff1ea6ea117f4d61375c3e7f04810dd3c70c2bfc4cbd6f0a61b0
                                password: "YeniSifre123"
                                password_confirmation: "YeniSifre123"
            responses:
                "200":
                    $ref: "#/components/responses/Success"
                "400":
                    $ref: "#/components/responses/BadRequest"

    # ══════════════════════════════════════════════════════
    # 3 ─ USER (jwt.auth gerekli)
    # ══════════════════════════════════════════════════════

    /app/v1/user:
        get:
            tags: [User]
            summary: Kullanıcı listesi
            description: |
                Sisteme kayıtlı kullanıcıları döner.

                Legacy not:
                - controller `request->params` bekliyor
                - filtreleme kriterleri uygulama tarafında query/body uyarlaması ile set ediliyor olabilir
                - bu nedenle response kesin, request ise kısmen legacy davranıştadır

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: userGetList
            security:
                - authToken: []
            responses:
                "200":
                    description: Kullanıcı listesi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              type: array
                                              items:
                                                  $ref: "#/components/schemas/UserObject"
                "401":
                    $ref: "#/components/responses/Unauthorized"
                "400":
                    $ref: "#/components/responses/BadRequest"

    /app/v1/user/create:
        post:
            tags: [User]
            summary: Kullanıcı oluştur
            description: |
                Yeni kullanıcı ekler (admin tarafından).

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: userCreate
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/UserCreateParams"
            responses:
                "200":
                    description: Başarılı kullanıcı oluşturma
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              type: object
                                              properties:
                                                  user:
                                                      $ref: "#/components/schemas/UserEntity"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/user/update:
        post:
            tags: [User]
            summary: Kullanıcı güncelle
            description: |
                Mevcut kullanıcı bilgilerini günceller.

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: userUpdate
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/UserUpdateParams"
                        example:
                            params:
                                update_user_id: 18
                                user_update_data:
                                    name: Ahmet
                                    surname: Demir
                                    phone: "+905551112233"
                                    status: 1
            responses:
                "200":
                    description: Başarılı kullanıcı güncelleme
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              type: object
                                              properties:
                                                  user:
                                                      $ref: "#/components/schemas/UserEntity"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/user/change-password:
        post:
            tags: [User]
            summary: Şifre değiştir
            description: |
                Oturumdaki kullanıcının şifresini değiştirir (eski şifre gerekli).

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: userChangePassword
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/ChangePasswordParams"
                        example:
                            params:
                                old_password: "EskiSifre123"
                                password: "YeniSifre123"
                                password_confirmation: "YeniSifre123"
            responses:
                "200":
                    $ref: "#/components/responses/Success"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/user/add-user-property:
        post:
            tags: [User]
            summary: Kullanıcıya property ekle
            description: |
                Bir kullanıcıyı belirli bir property'ye bağlar.

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: userAddProperty
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/AddUserPropertyParams"
                        example:
                            params:
                                add_user_id: 18
                                add_property_id: 42
            responses:
                "200":
                    $ref: "#/components/responses/Success"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/user/remove-user-property:
        post:
            tags: [User]
            summary: Kullanıcıdan property kaldır
            description: |
                Kullanıcının belirtilen property ile bağlantısını keser.

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: userRemoveProperty
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/RemoveUserPropertyParams"
                        example:
                            params:
                                remove_user_id: 18
                                remove_property_id: 42
            responses:
                "200":
                    $ref: "#/components/responses/Success"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/user/set-user-property:
        post:
            tags: [User]
            summary: Aktif property seç
            description: |
                Kullanıcının aktif çalışacağı property'yi belirler.
                Sonraki isteklerde bu property baz alınır.

                **Middleware:** `cors, LanguageSetting, jwt.auth, property`
                **Auth:** `authToken`
            operationId: userSetProperty
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/UserSetPropertyParams"
            responses:
                "200":
                    description: Aktif property secimi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              type: object
                                              properties:
                                                  hotel_user_mapping:
                                                      type: object
                                                      additionalProperties: true
                                                  application_cache:
                                                      type: object
                                                      additionalProperties: true
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/user/profile/get:
        post:
            tags: [User]
            summary: Profil bilgisi al
            description: |
                Oturumdaki kullanıcının profil detaylarını döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: userGetProfile
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            description: Controller sadece body varligini kontrol eder; payload icerigi kullanilmaz.
                            additionalProperties: true
                        example: {}
            responses:
                "200":
                    description: Kullanıcı profili
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/UserProfileResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/user/profile/update:
        post:
            tags: [User]
            summary: Profil güncelle
            description: |
                Oturumdaki kullanıcının profil bilgilerini günceller.

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: userUpdateProfile
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    type: object
                                    properties:
                                        name:
                                            type: string
                                            example: Ahmet
                                        surname:
                                            type: string
                                            example: Demir
                                        gender:
                                            type: ["string", "null"]
                                            example: male
                                        language:
                                            type: string
                                            example: tr
                                        phone:
                                            type: ["string", "null"]
                        example:
                            params:
                                name: Ahmet
                                surname: Demir
                                gender: male
                                language: tr
                                phone: "+905551112233"
            responses:
                "200":
                    $ref: "#/components/responses/Success"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/user-menu:
        post:
            tags: [User]
            summary: Kullanıcı property menüsü
            description: |
                Kullanıcının erişebildiği property'leri ve menü yapısını döner.
                Login sonrası sidebar/navigation için kullanılır.

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: userPropertyMenu
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/UserMenuParams"
                        example:
                            params:
                                locale: tr
                                property_id: 42
            responses:
                "200":
                    description: Property listesi ve menü
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/UserMenuResponseData"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    property_list:
                                        - id: 42
                                          name: Grand Palace Hotel
                                          property_menu:
                                              - key: dashboard
                                                title: Dashboard
                                                children: []
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    # ══════════════════════════════════════════════════════
    # 4 ─ UTILITY (public)
    # ══════════════════════════════════════════════════════

    /app/v1/languages/get/{param}:
        get:
            tags: [Utility]
            summary: Dil listesi
            description: |
                Dil listesini döner.

                Desteklenen path parametreleri:
                - `all`: tüm aktif diller
                - `app`: uygulamada yayınlanan diller

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: utilityGetLanguages
            parameters:
                - in: path
                  name: param
                  required: true
                  schema:
                      type: string
                      enum: [all, app]
                  description: Listeleme modu
            responses:
                "200":
                    description: Dil listesi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              type: array
                                              items:
                                                  $ref: "#/components/schemas/LanguageItem"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    - id: 1
                                      code: tr
                                      name: Turkish
                                      status: 1
                                      language_key: tr_TR
                                    - id: 2
                                      code: en
                                      name: English
                                      status: 1
                                      language_key: en_US
                "400":
                    $ref: "#/components/responses/BadRequest"

    /app/v1/languages/get-null-description:
        get:
            tags: [Utility]
            summary: Boş dil açıklama şablonu
            description: |
                Aktif uygulama dilleri için boş açıklama şablonu döner.

                Response her dil için:
                - `language_code`
                - `description: null`

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: utilityGetNullLanguageDescriptions
            responses:
                "200":
                    description: Dil açıklama şablonu
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              type: array
                                              items:
                                                  $ref: "#/components/schemas/NullDescriptionItem"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    - language_code: tr
                                      description: null
                                    - language_code: en
                                      description: null

    /app/v1/currency:
        get:
            tags: [Utility]
            summary: Para birimi listesi
            description: |
                Aktif para birimlerini alfabetik sırayla döner.

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: utilityGetCurrencyList
            responses:
                "200":
                    description: Para birimi listesi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              type: array
                                              items:
                                                  $ref: "#/components/schemas/CurrencyItem"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    - id: 1
                                      code: TRY
                                      name: Turkish Lira
                                      status: 1
                                      is_basic: 1
                                    - id: 2
                                      code: EUR
                                      name: Euro
                                      status: 1
                                      is_basic: 1
                "500":
                    description: Sunucu hatası
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"

    /app/v1/contact-form:
        post:
            tags: [Utility]
            summary: İletişim formu gönder
            description: |
                Genel iletişim formunu kuyruğa alır ve ilgili adrese e-posta gönderir.

                Header'da `language` gönderilirse çeviri locale'i o dile çekilir.

                **Middleware:** `cors, LanguageSetting`
                **Auth:** Yok
            operationId: utilitySendContactForm
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/ContactFormParams"
                        example:
                            params:
                                name: Ahmet
                                surname: Demir
                                email: ahmet@otel.com
                                subject: Demo talebi oluşturmak istiyorum.
            responses:
                "200":
                    description: Form başarıyla kuyruğa alındı
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data: []
                "400":
                    $ref: "#/components/responses/BadRequest"

    # ══════════════════════════════════════════════════════
    # 5 ─ PROPERTY (entry points)
    # ══════════════════════════════════════════════════════

    /app/v1/property/info/list:
        post:
            tags: [Property]
            summary: Property listesi
            description: |
                Giriş yapan kullanıcının erişebildiği aktif property listesini döner.

                Response içinde her property için:
                - temel kimlik bilgileri
                - varsayılan fotoğraf
                - role göre üretilmiş `property_menu`

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: propertyList
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyListParams"
                        example:
                            params:
                                locale: tr
            responses:
                "200":
                    description: Property listesi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyListResponseData"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    property_list:
                                        - id: 42
                                          name: Grand Palace Hotel
                                          default_photo: https://cdn.extranetwork.com/property-photos/42/main_thumbnail.jpg
                                          property_menu:
                                              - key: dashboard
                                                title: Dashboard
                                                children: []
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/create:
        post:
            tags: [Property]
            summary: Yeni property oluştur
            description: |
                Oturumdaki kullanıcı için başlangıç seviyesinde bir property oluşturur.

                Kod davranışı:
                - property adı çeviri anahtarından `enw-your_property_name` olarak set edilir
                - `status = 2` ile oluşturulur
                - kullanıcı/property mapping yazılır
                - default property ürünleri tanımlanır

                Request body içeriği fiilen kullanılmaz; controller yalnızca body varlığını kontrol eder.

                **Middleware:** `cors, LanguageSetting, jwt.auth`
                **Auth:** `authToken`
            operationId: propertyCreate
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    type: object
                                    additionalProperties: true
                                    description: Boş obje gönderilebilir.
                        example:
                            params: {}
            responses:
                "200":
                    description: Property oluşturuldu
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyCreateResponseData"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    id: 42
                                    name: enw-your_property_name
                                    status: 2
                                    created_by: 5
                                    updated_by: 5
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/info/get:
        post:
            tags: [Property]
            summary: Property detayını getir
            description: |
                Belirli bir property için edit ekranının temel verilerini döner.

                Response içinde:
                - `get_property.property_info`
                - `property_language_spoken`
                - `additional_info`
                - `minimum_age_policies`
                - referans listeler (`property_type`, `property_chains`, `countries`, `general_timezone`)

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyInfoGet
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyInfoGetParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
            responses:
                "200":
                    description: Property detay verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyInfoGetResponseData"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    get_property:
                                        property_info:
                                            id: 42
                                            name: Grand Palace Hotel
                                            property_type_id: 1
                                            chain_id: 1
                                            rating: 5
                                            currency_type: TRY
                                            country: TR
                                            has_locale_name: false
                                        property_language_spoken:
                                            - language_code: tr
                                              selected: true
                                        additional_info:
                                            locale_name: null
                                    minimum_age_policies:
                                        - value: 0
                                          label: All Ages
                                    property_type:
                                        - id: 1
                                          name: Hotel
                                          language_key: property_type_hotel
                                    property_chains:
                                        - id: 1
                                          name: Independent
                                          loyalty: null
                                    countries:
                                        - id: 223
                                          name: Turkey
                                    general_timezone:
                                        - id: 1
                                          location: Europe/Istanbul
                                          description: GMT+03:00 Istanbul
                                          action_type: plus
                                          hour: 3
                                          minute: 0
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/info/update:
        post:
            tags: [Property]
            summary: Property bilgilerini güncelle
            description: |
                Property ana bilgileri, ek bilgileri ve konuşulan dilleri günceller.

                Bu endpoint `contentWizard` middleware arkasındadır ve wizard adımlarında da kullanılır.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property, contentWizard`
                **Auth:** `authToken`
            operationId: propertyInfoUpdate
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyInfoUpdateParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
                                has_locale_name: false
                                property_info:
                                    name: Grand Palace Hotel
                                    property_type_id: 1
                                    chain_id: 1
                                    rating: 5
                                    currency_type: TRY
                                additional_info:
                                    locale_name: null
                                property_language_spoken:
                                    - tr
                                    - en
            responses:
                "200":
                    description: Property bilgileri güncellendi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data:
                                    updated: true
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/update/content-code:
        post:
            tags: [Property]
            summary: Property content code güncelle
            description: |
                Property için içerik doğrulama kodunu günceller.

                Validator kuralı:
                - `content_code` nullable
                - minimum 5, maksimum 10 karakter

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property, contentWizard`
                **Auth:** `authToken`
            operationId: propertyUpdateContentCode
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyContentCodeParams"
                        example:
                            params:
                                property_id: 42
                                content_code: ABC12
            responses:
                "200":
                    description: Content code güncellendi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                            example:
                                status: 200
                                error: false
                                errorCode: null
                                message: null
                                data: []
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/dashboard:
        post:
            tags: [Property]
            summary: Property dashboard
            description: |
                Property dashboard özet verisini döner.

                Kod tarafında ayrıca:
                - property adı `hotel_name` olarak eklenir
                - `site_hints` eklenir
                - `content_code` eklenir

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyDashboard
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyIdParams"
                        example:
                            params:
                                property_id: 42
            responses:
                "200":
                    description: Dashboard verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyDashboardResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/pab-dashboard:
        post:
            tags: [Property]
            summary: Property PAB dashboard
            description: |
                Property network tarafındaki özet dashboard verisini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyPabDashboard
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyIdParams"
                        example:
                            params:
                                property_id: 42
            responses:
                "200":
                    description: PAB dashboard verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyPabDashboardResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/dashboard-plus:
        post:
            tags: [Property]
            summary: Dashboard Plus özeti
            description: |
                Date range bazlı Dashboard Plus özet KPI verisini döner.

                Tarih kuralı:
                - maksimum 180 gün aralığı
                - `finish_date`, `start_date`'ten önce olamaz

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyDashboardPlus
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyDateRangeParams"
                        example:
                            params:
                                property_id: 42
                                start_date: "2026-01-01"
                                finish_date: "2026-01-31"
            responses:
                "200":
                    description: Dashboard Plus özet verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyDashboardPlusSummaryResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/dashboard-plus/web-visitor:
        post:
            tags: [Property]
            summary: Dashboard Plus web visitor
            description: |
                Belirli tarih aralığı için web visitor analytics verisini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyDashboardPlusWebVisitor
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyDateRangeParams"
                        example:
                            params:
                                property_id: 42
                                start_date: "2026-01-01"
                                finish_date: "2026-01-31"
            responses:
                "200":
                    description: Web visitor analitik verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyAnalyticsResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/dashboard-plus/guest-demographic:
        post:
            tags: [Property]
            summary: Dashboard Plus guest demographic
            description: |
                Belirli tarih aralığı için guest demographic analytics verisini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyDashboardPlusGuestDemographic
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyDateRangeParams"
                        example:
                            params:
                                property_id: 42
                                start_date: "2026-01-01"
                                finish_date: "2026-01-31"
            responses:
                "200":
                    description: Guest demographic analitik verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyAnalyticsResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/dashboard-plus/top-channel:
        post:
            tags: [Property]
            summary: Dashboard Plus top channel
            description: |
                Belirli tarih aralığı için top channel analytics verisini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyDashboardPlusTopChannel
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyDateRangeParams"
                        example:
                            params:
                                property_id: 42
                                start_date: "2026-01-01"
                                finish_date: "2026-01-31"
            responses:
                "200":
                    description: Top channel analitik verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyAnalyticsResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/dashboard-plus/channel-forecast:
        post:
            tags: [Property]
            summary: Dashboard Plus channel forecast
            description: |
                Belirli tarih aralığı için channel forecast analytics verisini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyDashboardPlusChannelForecast
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyDateRangeParams"
                        example:
                            params:
                                property_id: 42
                                start_date: "2026-01-01"
                                finish_date: "2026-01-31"
            responses:
                "200":
                    description: Channel forecast analitik verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyAnalyticsResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/booking-engine-report:
        post:
            tags: [Property]
            summary: Booking Engine raporu
            description: |
                Booking Engine arama ve dönüşüm raporlarını döner.

                Desteklenen tipler:
                - `TRS`: Transaction Report
                - `GTR`: Guest Transaction Report
                - `DSR`: Date Search Report
                - `DSS`: Date Search Stay Report
                - `UCR`: User Country Report
                - `ULR`: User Language Report

                Tarih kuralı:
                - maksimum 180 gün aralığı
                - `finish_date`, `start_date`'ten önce olamaz
                - `channel_id` sadece `DSS` tipinde gerekir

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyBookingEngineReport
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/BookingEngineReportParams"
                        example:
                            params:
                                property_id: 42
                                start_date: "2026-01-01"
                                finish_date: "2026-01-31"
                                type: TRS
            responses:
                "200":
                    description: Booking Engine rapor verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              $ref: "#/components/schemas/PropertyAnalyticsResponseData"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/coupon-code-report:
        post:
            tags: [Property]
            summary: Coupon code raporu
            description: |
                Belirli tarih aralığında coupon code performans raporunu döner.

                Filtreler:
                - `code` verilmezse tüm coupon code kayıtları döner
                - `status` verilmezse varsayılan `1`

                Tarih kuralı:
                - maksimum 180 gün aralığı
                - `finish_date`, `start_date`'ten önce olamaz

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyCouponCodeReport
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/CouponCodeReportParams"
                        example:
                            params:
                                property_id: 42
                                start_date: "2026-01-01"
                                finish_date: "2026-01-31"
                                code: WINTER25
                                status: 1
            responses:
                "200":
                    description: Coupon code rapor verisi
                    content:
                        application/json:
                            schema:
                                allOf:
                                    - $ref: "#/components/schemas/ApiResponse"
                                    - type: object
                                      properties:
                                          data:
                                              type: array
                                              items:
                                                  $ref: "#/components/schemas/CouponCodeReportItem"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    # ══════════════════════════════════════════════════════
    # 6 ─ PROPERTY INFO
    # ══════════════════════════════════════════════════════

    /app/v1/property/type/list:
        post:
            tags: [Property Info]
            summary: Property type listesi
            description: |
                Property type referans listesini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyTypeList
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyLocaleParams"
                        example:
                            params:
                                locale: tr
            responses:
                "200":
                    description: Property type listesi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/chain/list:
        post:
            tags: [Property Info]
            summary: Property chain listesi
            description: |
                Property chain referans listesini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyChainList
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyLocaleParams"
                        example:
                            params:
                                locale: tr
            responses:
                "200":
                    description: Property chain listesi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/contact/list:
        post:
            tags: [Property Info]
            summary: Property contact detayı
            description: |
                Property contact bilgisini ve property'nin temel verilerini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyContactList
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyScopedLocaleParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
            responses:
                "200":
                    description: Property contact verisi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/contact/update:
        post:
            tags: [Property Info]
            summary: Property contact güncelle
            description: |
                Property contact bilgisini günceller veya oluşturur.

                İsteğe bağlı olarak `property_info` altında:
                - `official_name`
                - `tax_office`
                - `tax_number`
                alanları da aynı istekte güncellenebilir.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property, contentWizard`
                **Auth:** `authToken`
            operationId: propertyContactUpdate
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyContactUpdateParams"
                        example:
                            params:
                                property_id: 42
                                contact:
                                    phone: "+902121112233"
                                    email: info@grandpalace.com
                                property_info:
                                    official_name: Grand Palace Hotel Resort Spa
                                    tax_office: Beşiktaş
                                    tax_number: "1234567890"
            responses:
                "200":
                    description: Property contact güncellendi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/executive/get:
        post:
            tags: [Property Info]
            summary: Property executive detayı
            description: |
                Property executive bilgisini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyExecutiveGet
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyScopedLocaleParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
            responses:
                "200":
                    description: Executive detay verisi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/executive/list:
        post:
            tags: [Property Info]
            summary: Property executive listesi
            description: |
                Property executive listesini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property, contentWizard`
                **Auth:** `authToken`
            operationId: propertyExecutiveList
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyScopedLocaleParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
            responses:
                "200":
                    description: Executive listesi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/executive/add:
        post:
            tags: [Property Info]
            summary: Property executive ekle
            description: |
                Property'ye executive kaydı ekler.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyExecutiveAdd
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyExecutiveParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
                                executive_type:
                                    name: Ahmet
                                    surname: Demir
                                    title: General Manager
            responses:
                "200":
                    description: Executive eklendi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/executive/update:
        post:
            tags: [Property Info]
            summary: Property executive güncelle
            description: |
                Property executive kaydını günceller.

                Hata durumunda controller eski executive verisini `data` içinde dönebilir.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyExecutiveUpdate
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyExecutiveParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
                                executive_type:
                                    id: 7
                                    name: Ahmet
                                    surname: Demir
            responses:
                "200":
                    description: Executive güncellendi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/executive/delete:
        post:
            tags: [Property Info]
            summary: Property executive sil
            description: |
                Property executive kaydını pasife çeker.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyExecutiveDelete
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyExecutiveDeleteParams"
                        example:
                            params:
                                property_id: 42
                                property_executive_id: 7
                                locale: tr
            responses:
                "200":
                    description: Executive silindi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/config/list:
        post:
            tags: [Property Info]
            summary: Property config listesi
            description: |
                Property config değerlerini döner.

                `config_keys` gönderilirse filtreli sonuç dönebilir.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyConfigList
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyConfigParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
                                config_keys:
                                    - checkin_time
                                    - checkout_time
            responses:
                "200":
                    description: Property config verisi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/config/update:
        post:
            tags: [Property Info]
            summary: Property config güncelle
            description: |
                Property config değerlerini günceller.

                `config_keys` içinde update edilecek anahtar/değer yapısı gönderilir.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyConfigUpdate
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyConfigParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
                                config_keys:
                                    checkin_time: "14:00"
                                    checkout_time: "12:00"
            responses:
                "200":
                    description: Property config güncellendi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/brand/get:
        post:
            tags: [Property Info]
            summary: Property brand detayı
            description: |
                Property brand bilgisini döner.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyBrandGet
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyBrandGetParams"
                        example:
                            params:
                                property_id: 42
                                locale: tr
            responses:
                "200":
                    description: Property brand verisi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/brand/update:
        post:
            tags: [Property Info]
            summary: Property brand güncelle
            description: |
                Property brand bilgilerini günceller.

                Bu endpoint `multipart/form-data` bekler ve opsiyonel logo dosyası alabilir.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyBrandUpdate
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    multipart/form-data:
                        schema:
                            $ref: "#/components/schemas/PropertyBrandUpdateForm"
            responses:
                "200":
                    description: Property brand güncellendi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"

    /app/v1/property/brand/clear-logo:
        post:
            tags: [Property Info]
            summary: Property brand logo temizle
            description: |
                Property brand logo alanını temizler.

                **Middleware:** `cors, LanguageSetting, jwt.auth, userRoutePermissionAuthorize, property`
                **Auth:** `authToken`
            operationId: propertyBrandClearLogo
            security:
                - authToken: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            type: object
                            required: [params]
                            properties:
                                params:
                                    $ref: "#/components/schemas/PropertyBrandGetParams"
                        example:
                            params:
                                property_id: 42
            responses:
                "200":
                    description: Brand logo temizlendi
                    content:
                        application/json:
                            schema:
                                $ref: "#/components/schemas/ApiResponse"
                "400":
                    $ref: "#/components/responses/BadRequest"
                "401":
                    $ref: "#/components/responses/Unauthorized"
