openapi: 3.0.3
info:
  title: LaevZanjir SaaS API
  description: |
    LaevZanjir SaaS API — Meta Ads → Telegram bot orqali lid boshqarish.

    **Stack:** Cloudflare Pages Functions + D1 + KV + R2
    **Base URL:** `https://laevzanjir.com/api`

    Barcha javoblar standart formatda:
    ```json
    { "ok": true,  "data": { ... } }
    { "ok": false, "error": "...", "code": "E001" }
    ```

    Auth: HTTP-only cookie (`session=...`). Login orqali olinadi. Webhook'lar uchun token (Telegram secret, Click MD5).
  version: 2.9.0
  contact:
    name: LaevZanjir
    url: https://laevzanjir.com/contact
    email: hello@laevzanjir.com
  license:
    name: Proprietary

servers:
  - url: https://laevzanjir.com/api
    description: Production
  - url: http://localhost:8788/api
    description: Local (wrangler pages dev)

tags:
  - name: Auth
    description: Foydalanuvchi auth (signup, login, logout, Telegram WebApp)
  - name: Users
    description: Joriy foydalanuvchi profili
  - name: Clients
    description: Mijozlar CRUD (admin/manager)
  - name: Leads
    description: Lid'lar (Meta Ads, qo'lda kiritish)
  - name: Payments
    description: Click/Payme/manual to'lovlar + refund + subscription
  - name: Reports
    description: Kunlik/haftalik/oylik atchot + PDF
  - name: Stats
    description: Real-time statistika
  - name: Webhooks
    description: Tashqi integratsiyalar (Telegram, Click, Payme, Sheets)
  - name: System
    description: Health, status, incidents, audit log

paths:
  # ---------- AUTH ----------
  /auth/signup:
    post:
      tags: [Auth]
      summary: Email/password ro'yxatdan o'tish
      description: Yangi user yaratadi (role=manager) + session cookie qaytaradi.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email: { type: string, format: email }
                password: { type: string, minLength: 6 }
                name: { type: string }
      responses:
        '201':
          description: User yaratildi
          headers:
            Set-Cookie:
              schema: { type: string, example: 'session=...; HttpOnly; Secure' }
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AuthResponse' }
        '400': { $ref: '#/components/responses/BadRequest' }
        '409': { $ref: '#/components/responses/Conflict' }

  /auth/email:
    post:
      tags: [Auth]
      summary: Email/password bilan login
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [email, password]
              properties:
                email: { type: string, format: email }
                password: { type: string }
      responses:
        '200':
          description: Login OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AuthResponse' }
        '401': { $ref: '#/components/responses/Unauthorized' }

  /auth/telegram:
    post:
      tags: [Auth]
      summary: Telegram WebApp initData orqali login
      description: Mini App ichidan `Telegram.WebApp.initData` ni yuboradi. Server HMAC tekshiradi.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [initData]
              properties:
                initData: { type: string, description: 'tg.initData raw string' }
      responses:
        '200':
          description: Auth OK (cookie set)
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AuthResponse' }
        '401': { $ref: '#/components/responses/Unauthorized' }

  /auth/logout:
    post:
      tags: [Auth]
      summary: Logout (session o'chiriladi)
      security: [{ cookieAuth: [] }]
      responses:
        '200':
          description: Logout OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OkVoid' }

  # ---------- USERS ----------
  /users/me:
    get:
      tags: [Users]
      summary: Joriy user profili
      security: [{ cookieAuth: [] }]
      responses:
        '200':
          description: User obyekti
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UserResponse' }
        '401': { $ref: '#/components/responses/Unauthorized' }
    patch:
      tags: [Users]
      summary: Profil yangilash (name, lang)
      security: [{ cookieAuth: [] }]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name: { type: string }
                lang: { type: string, enum: [uz, ru, en] }
      responses:
        '200':
          description: Yangilangan
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UserResponse' }

  /users/password:
    post:
      tags: [Users]
      summary: Parolni almashtirish
      security: [{ cookieAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [current, next]
              properties:
                current: { type: string }
                next: { type: string, minLength: 6 }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OkVoid' }
        '401': { $ref: '#/components/responses/Unauthorized' }

  # ---------- CLIENTS ----------
  /clients:
    get:
      tags: [Clients]
      summary: Mijozlar ro'yxati
      security: [{ cookieAuth: [] }]
      parameters:
        - { name: status, in: query, schema: { type: string, enum: [active, paused, churned], default: active } }
        - { name: limit, in: query, schema: { type: integer, default: 50, maximum: 100 } }
      responses:
        '200':
          description: Mijozlar
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkList'
                  - properties:
                      data:
                        type: array
                        items: { $ref: '#/components/schemas/Client' }
    post:
      tags: [Clients]
      summary: Yangi mijoz yaratish
      security: [{ cookieAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ClientInput' }
      responses:
        '200':
          description: Yaratildi
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Ok'
                  - properties:
                      data:
                        type: object
                        properties:
                          id: { type: string }
                          slug: { type: string }
                          name: { type: string }
        '409': { $ref: '#/components/responses/Conflict' }

  /clients/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Clients]
      summary: Bitta mijoz
      security: [{ cookieAuth: [] }]
      responses:
        '200':
          description: Mijoz
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Ok'
                  - properties:
                      data: { $ref: '#/components/schemas/Client' }
        '404': { $ref: '#/components/responses/NotFound' }
    patch:
      tags: [Clients]
      summary: Mijoz ma'lumotlarini yangilash
      security: [{ cookieAuth: [] }]
      requestBody:
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ClientInput' }
      responses:
        '200':
          description: Yangilandi
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OkVoid' }

  /clients/{id}/balance:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Clients]
      summary: Mijoz balansi va kunlik runway
      security: [{ cookieAuth: [] }]
      responses:
        '200':
          description: Balance + runway
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      balance: { type: integer, description: 'sent (cents)' }
                      daily_budget: { type: integer }
                      days_left: { type: integer }

  /clients/{id}/pause:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Clients]
      summary: Mijozni to'xtatish (status=paused)
      security: [{ cookieAuth: [] }]
      responses:
        '200':
          description: Pause OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OkVoid' }

  /clients/{id}/resume:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Clients]
      summary: Mijozni qayta yoqish (status=active)
      security: [{ cookieAuth: [] }]
      responses:
        '200':
          description: Resume OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OkVoid' }

  /clients/{id}/subscription:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Clients]
      summary: Mijoz subscription holati
      security: [{ cookieAuth: [] }]
      responses:
        '200':
          description: Subscription info
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      monthly_fee: { type: integer }
                      balance: { type: integer }
                      next_due_at: { type: integer }
                      status: { type: string }

  # ---------- LEADS ----------
  /leads:
    get:
      tags: [Leads]
      summary: Lid'lar ro'yxati (filter mumkin)
      security: [{ cookieAuth: [] }]
      parameters:
        - { name: client_id, in: query, schema: { type: string } }
        - { name: status, in: query, schema: { type: string, enum: [new, contacted, qualified, won, lost] } }
        - { name: limit, in: query, schema: { type: integer, default: 50, maximum: 200 } }
        - { name: offset, in: query, schema: { type: integer, default: 0 } }
      responses:
        '200':
          description: Lidlar
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkList'
                  - properties:
                      data:
                        type: array
                        items: { $ref: '#/components/schemas/Lead' }
    post:
      tags: [Leads]
      summary: Yangi lid (admin yoki webhook)
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/LeadInput' }
      responses:
        '200':
          description: Lid yaratildi
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Ok' }
        '404': { $ref: '#/components/responses/NotFound' }

  /leads/{id}:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Leads]
      summary: Bitta lid + timeline
      security: [{ cookieAuth: [] }]
      responses:
        '200':
          description: Lid
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Ok'
                  - properties:
                      data:
                        allOf:
                          - $ref: '#/components/schemas/Lead'
                          - properties:
                              events:
                                type: array
                                items: { $ref: '#/components/schemas/LeadEvent' }
    patch:
      tags: [Leads]
      summary: Lid statusini/sifatini/eslatmasini yangilash
      security: [{ cookieAuth: [] }]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status: { type: string, enum: [new, contacted, qualified, won, lost] }
                quality: { type: integer, minimum: 1, maximum: 5 }
                notes: { type: string }
      responses:
        '200':
          description: Yangilandi
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OkVoid' }

  /lead-events:
    post:
      tags: [Leads]
      summary: Lid timeline'iga voqea qo'shish
      security: [{ cookieAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [lead_id, type]
              properties:
                lead_id: { type: string }
                type: { type: string, example: 'note.added' }
                payload: { type: object }
      responses:
        '200':
          description: Voqea yozildi
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Ok' }

  # ---------- PAYMENTS ----------
  /payments:
    get:
      tags: [Payments]
      summary: To'lovlar ro'yxati
      security: [{ cookieAuth: [] }]
      parameters:
        - { name: client_id, in: query, schema: { type: string } }
        - { name: limit, in: query, schema: { type: integer, default: 50, maximum: 200 } }
      responses:
        '200':
          description: To'lovlar
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkList'
                  - properties:
                      data:
                        type: array
                        items: { $ref: '#/components/schemas/Payment' }
    post:
      tags: [Payments]
      summary: Qo'lda to'lov yozish (service_fee avtomat)
      security: [{ cookieAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/PaymentInput' }
      responses:
        '200':
          description: To'lov yozildi
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Ok' }

  /payments/{id}/refund:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    post:
      tags: [Payments]
      summary: To'lovni qaytarish
      security: [{ cookieAuth: [] }]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                reason: { type: string }
      responses:
        '200':
          description: Refund yozildi
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OkVoid' }

  # ---------- REPORTS ----------
  /reports:
    get:
      tags: [Reports]
      summary: Atchotlar ro'yxati
      security: [{ cookieAuth: [] }]
      parameters:
        - { name: client_id, in: query, schema: { type: string } }
        - { name: type, in: query, schema: { type: string, enum: [daily, weekly, monthly] } }
        - { name: limit, in: query, schema: { type: integer, default: 30 } }
      responses:
        '200':
          description: Atchotlar
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkList'
                  - properties:
                      data:
                        type: array
                        items: { $ref: '#/components/schemas/Report' }

  /reports/generate:
    post:
      tags: [Reports]
      summary: Yangi atchot generatsiya (PDF + R2 + Telegram)
      security: [{ cookieAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [client_id, date]
              properties:
                client_id: { type: string }
                date: { type: string, format: date }
                type: { type: string, enum: [daily, weekly, monthly], default: daily }
      responses:
        '200':
          description: Atchot yaratildi
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Ok'
                  - properties:
                      data: { $ref: '#/components/schemas/Report' }

  /reports/{id}/pdf:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Reports]
      summary: Atchot PDF (R2 redirect)
      security: [{ cookieAuth: [] }]
      responses:
        '302':
          description: Redirect to signed R2 URL

  /reports/{id}/download:
    parameters:
      - { name: id, in: path, required: true, schema: { type: string } }
    get:
      tags: [Reports]
      summary: Atchot PDF (inline stream)
      security: [{ cookieAuth: [] }]
      responses:
        '200':
          description: PDF stream
          content:
            application/pdf:
              schema: { type: string, format: binary }

  # ---------- STATS ----------
  /stats:
    get:
      tags: [Stats]
      summary: Real-time statistika
      security: [{ cookieAuth: [] }]
      parameters:
        - { name: client_id, in: query, schema: { type: string } }
        - { name: range, in: query, schema: { type: string, enum: [today, 7d, 30d], default: 7d } }
      responses:
        '200':
          description: Statistika
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      leads_total: { type: integer }
                      leads_won: { type: integer }
                      spend: { type: integer, description: 'cents' }
                      cpl: { type: integer, description: 'cents per lead' }
                      cr_pct: { type: number, description: 'conversion rate' }

  # ---------- WEBHOOKS ----------
  /webhook/telegram:
    post:
      tags: [Webhooks]
      summary: Telegram bot webhook
      description: Telegram Bot API webhook (secret header tekshirib). Update'larni qabul qiladi.
      parameters:
        - name: X-Telegram-Bot-Api-Secret-Token
          in: header
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema: { type: object, description: 'Telegram Update' }
      responses:
        '200': { description: OK }
        '401': { description: 'Wrong secret' }

  /webhook/click:
    post:
      tags: [Webhooks]
      summary: Click.uz to'lov webhook
      description: |
        Click prepare/complete. MD5 signature + sign_time.
        Status: 0=prepare, 1=complete, -1=cancelled.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                click_trans_id: { type: string }
                merchant_trans_id: { type: string }
                amount: { type: number }
                sign_string: { type: string }
                action: { type: string, enum: ['0', '1'] }
      responses:
        '200': { description: 'OK / error JSON' }

  /webhook/payme:
    post:
      tags: [Webhooks]
      summary: Payme JSON-RPC webhook
      description: |
        Methods: CheckPerformTransaction, CreateTransaction, PerformTransaction, CancelTransaction, CheckTransaction, GetStatement.
        Auth: Basic (Paycom:KEY).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                jsonrpc: { type: string, example: '2.0' }
                id: { oneOf: [{ type: integer }, { type: string }] }
                method: { type: string }
                params: { type: object }
      responses:
        '200': { description: 'JSON-RPC result/error' }

  /webhook/sheets:
    post:
      tags: [Webhooks]
      summary: Google Sheets webhook (lid kiritish)
      description: Apps Script tomonidan chaqiriladi (X-Sheets-Token bilan).
      parameters:
        - name: X-Sheets-Token
          in: header
          required: true
          schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [client_slug, full_name, phone]
              properties:
                client_slug: { type: string }
                full_name: { type: string }
                phone: { type: string }
                email: { type: string }
      responses:
        '200': { description: 'OK' }

  # ---------- FILES ----------
  /files/upload:
    post:
      tags: [System]
      summary: Faylni R2'ga yuklash
      security: [{ cookieAuth: [] }]
      requestBody:
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file: { type: string, format: binary }
      responses:
        '200':
          description: Yuklandi
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/Ok'
                  - properties:
                      data:
                        type: object
                        properties:
                          key: { type: string }
                          url: { type: string }
                          size: { type: integer }

  # ---------- SYSTEM ----------
  /health:
    get:
      tags: [System]
      summary: Health check (D1, KV, R2)
      responses:
        '200':
          description: Healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      db: { type: boolean }
                      kv: { type: boolean }
                      r2: { type: boolean }
                      version: { type: string }
                      uptime: { type: integer }

  /status:
    get:
      tags: [System]
      summary: Public status endpoint (uptime, incidents)
      responses:
        '200':
          description: Status
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: { type: boolean }
                  data:
                    type: object
                    properties:
                      services:
                        type: array
                        items:
                          type: object
                          properties:
                            name: { type: string }
                            status: { type: string, enum: [operational, degraded, down] }
                      incidents:
                        type: array
                        items: { $ref: '#/components/schemas/Incident' }

  /status/incidents:
    get:
      tags: [System]
      summary: Hodisalar tarixi
      responses:
        '200':
          description: Incidents
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkList'
                  - properties:
                      data:
                        type: array
                        items: { $ref: '#/components/schemas/Incident' }

  /audit:
    get:
      tags: [System]
      summary: Audit log (admin only)
      security: [{ cookieAuth: [] }]
      parameters:
        - { name: limit, in: query, schema: { type: integer, default: 100 } }
        - { name: action, in: query, schema: { type: string } }
      responses:
        '200':
          description: Audit log
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkList'
                  - properties:
                      data:
                        type: array
                        items: { $ref: '#/components/schemas/AuditEntry' }

  /contact:
    post:
      tags: [System]
      summary: Marketing contact form
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, email, message]
              properties:
                name: { type: string }
                email: { type: string, format: email }
                phone: { type: string }
                message: { type: string }
      responses:
        '200':
          description: Murojaat qabul qilindi
          content:
            application/json:
              schema: { $ref: '#/components/schemas/OkVoid' }

components:
  securitySchemes:
    cookieAuth:
      type: apiKey
      in: cookie
      name: session

  schemas:
    Ok:
      type: object
      properties:
        ok: { type: boolean, example: true }
        data: { type: object }

    OkVoid:
      type: object
      properties:
        ok: { type: boolean, example: true }

    OkList:
      type: object
      properties:
        ok: { type: boolean, example: true }
        meta:
          type: object
          properties:
            count: { type: integer }
            limit: { type: integer }
            offset: { type: integer }

    Error:
      type: object
      required: [ok, error]
      properties:
        ok: { type: boolean, example: false }
        error: { type: string }
        code: { type: string, example: 'E001' }

    User:
      type: object
      properties:
        id: { type: string, example: 'u_abc123' }
        email: { type: string, format: email }
        name: { type: string }
        role: { type: string, enum: [owner, admin, manager, viewer, client] }
        image: { type: string, nullable: true }

    AuthResponse:
      type: object
      properties:
        ok: { type: boolean }
        data:
          type: object
          properties:
            user: { $ref: '#/components/schemas/User' }

    UserResponse:
      type: object
      properties:
        ok: { type: boolean }
        data: { $ref: '#/components/schemas/User' }

    Client:
      type: object
      properties:
        id: { type: string, example: 'c_abc123' }
        name: { type: string }
        slug: { type: string }
        phone: { type: string }
        email: { type: string }
        telegram_id: { type: string }
        business_type: { type: string }
        monthly_fee: { type: integer, description: 'cents' }
        daily_budget: { type: integer }
        balance: { type: integer }
        status: { type: string, enum: [active, paused, churned] }
        created_at: { type: integer, description: 'unix timestamp' }

    ClientInput:
      type: object
      required: [name]
      properties:
        name: { type: string, minLength: 2 }
        slug: { type: string }
        phone: { type: string }
        email: { type: string }
        telegram_id: { type: string }
        business_type: { type: string }
        daily_budget: { type: integer }
        monthly_fee: { type: integer }
        meta_ad_account: { type: string }
        notes: { type: string }

    Lead:
      type: object
      properties:
        id: { type: string, example: 'l_abc123' }
        client_id: { type: string }
        client_name: { type: string }
        client_slug: { type: string }
        full_name: { type: string }
        phone: { type: string }
        email: { type: string }
        source: { type: string, example: 'meta_ads' }
        campaign_id: { type: string }
        status: { type: string, enum: [new, contacted, qualified, won, lost] }
        quality: { type: integer, minimum: 1, maximum: 5 }
        notes: { type: string }
        created_at: { type: integer }

    LeadInput:
      type: object
      required: [client_id, full_name, phone]
      properties:
        client_id: { type: string }
        full_name: { type: string }
        phone: { type: string }
        email: { type: string }
        source: { type: string, default: 'meta_ads' }
        campaign_id: { type: string }
        notes: { type: string }
        metadata: { type: object }

    LeadEvent:
      type: object
      properties:
        id: { type: string }
        lead_id: { type: string }
        type: { type: string, example: 'status.changed' }
        payload: { type: object }
        user_id: { type: string }
        created_at: { type: integer }

    Payment:
      type: object
      properties:
        id: { type: string, example: 'p_abc123' }
        client_id: { type: string }
        client_name: { type: string }
        amount: { type: integer, description: 'cents' }
        currency: { type: string, example: 'USD' }
        method: { type: string, enum: [click, payme, uzcard, humo, manual, bank] }
        provider_txn: { type: string }
        daily_budget: { type: integer }
        service_fee: { type: integer }
        status: { type: string, enum: [pending, paid, failed, refunded] }
        paid_at: { type: integer }
        for_date: { type: string, format: date }

    PaymentInput:
      type: object
      required: [client_id, amount, method]
      properties:
        client_id: { type: string }
        amount: { type: integer, description: 'cents' }
        daily_budget: { type: integer }
        method: { type: string, enum: [click, payme, uzcard, humo, manual, bank] }
        for_date: { type: string, format: date }
        paid_at: { type: integer }
        provider_txn: { type: string }
        notes: { type: string }

    Report:
      type: object
      properties:
        id: { type: string }
        client_id: { type: string }
        date: { type: string, format: date }
        type: { type: string, enum: [daily, weekly, monthly] }
        leads_total: { type: integer }
        leads_won: { type: integer }
        ad_spend: { type: integer }
        service_fee: { type: integer }
        summary: { type: string }
        pdf_url: { type: string }
        sent_to_telegram: { type: boolean }
        created_at: { type: integer }

    Incident:
      type: object
      properties:
        id: { type: string }
        title: { type: string }
        status: { type: string, enum: [investigating, identified, monitoring, resolved] }
        severity: { type: string, enum: [minor, major, critical] }
        body: { type: string }
        started_at: { type: integer }
        resolved_at: { type: integer, nullable: true }

    AuditEntry:
      type: object
      properties:
        id: { type: string }
        user_id: { type: string, nullable: true }
        client_id: { type: string, nullable: true }
        action: { type: string, example: 'client.created' }
        entity: { type: string }
        entity_id: { type: string }
        diff: { type: object }
        ip_address: { type: string }
        created_at: { type: integer }

  responses:
    BadRequest:
      description: Invalid input
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Unauthorized:
      description: Not authenticated
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Conflict:
      description: Already exists
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
