openapi: 3.0.3
info:
  title: Blitzly API
  description: |
    API-first architecture dla platformy do generowania reklam i landing pages.

    ## Autentykacja

    API wspiera dwa rodzaje autentykacji:
    - **Session** - dla frontendu Livewire/web
    - **Bearer Token** (Sanctum) - dla zewnętrznych integracji

    ## Kontekst workspace

    Większość endpointów wymaga kontekstu workspace. Przekaż go przez header:
    ```
    X-Workspace: {workspace_id}
    ```

    ## Rate Limiting

    API stosuje rate limiting:
    - Login: 5 prób/minutę per IP
    - Register: 3 próby/minutę per IP
    - AI Generation: 20 żądań/minutę per workspace
    - Image Generation: 10 żądań/minutę per workspace
    - Drive Upload: 30 żądań/minutę per workspace

  version: 1.0.0
  contact:
    name: API Support
    email: support@blitzly.com
  license:
    name: Proprietary
    url: https://blitzly.com/terms

servers:
  - url: https://blitzly.com/api/v1
    description: Production server
  - url: http://localhost/api/v1
    description: Local development

tags:
  - name: Auth
    description: Autentykacja i zarządzanie użytkownikami
  - name: Workspaces
    description: Zarządzanie workspace'ami
  - name: Drive
    description: Zarządzanie plikami i folderami
  - name: Drive Assets
    description: Zarządzanie assetami elementów Drive
  - name: Templates
    description: Zarządzanie szablonami treści
  - name: Agent
    description: Konwersacje z agentem AI i zarządzanie wiadomościami
  - name: Website Pages
    description: Zarządzanie stronami w projektach website
  - name: Pipelines
    description: Zarządzanie pipeline'ami (flow editor)
  - name: AI
    description: Generowanie treści przez AI
  - name: Drive Batch
    description: Operacje batch na wielu elementach Drive
  - name: Drive Folders
    description: Operacje na folderach i breadcrumbs
  - name: Drive Share
    description: Udostepnianie i publikacja elementów
  - name: Drive Trash
    description: Kosz - soft delete, przywracanie, trwale usuwanie
  - name: Drive Collections
    description: Zarządzanie kolekcjami elementów
  - name: Drive Upload
    description: Upload plików do Drive
  - name: Folder Guidelines
    description: Wytyczne AI dla folderów z dziedziczeniem kaskadowym
  - name: Folder Guidelines Rules
    description: Reguły zabronionych wyrażeń i zmienne kontekstowe
  - name: User
    description: Przełączanie kontekstu (workspace/projekt), preferencje
  - name: Billing
    description: Plany subskrypcyjne, kredyty, doładowania
  - name: AI Usage
    description: Statystyki i logi użycia AI
  - name: Variables
    description: Zarządzanie zmiennymi (CRUD)
  - name: VisualIdentities
    description: Identyfikacja wizualna projektów
  - name: Prompts
    description: Zarządzanie promptami (CRUD)
  - name: FeatureRequests
    description: Zgłoszenia funkcjonalności
  - name: Dashboard
    description: Dashboard - szybkie akcje, presety, widgety
  - name: JTBD
    description: Jobs To Be Done - szablony i ulubione
  - name: Search
    description: Unified search across modules
  - name: Slideshow
    description: Budowanie prezentacji (slideshow)
  - name: Jobs
    description: Zunifikowany system statusów zadań (Unified Job Service)

security:
  - bearerAuth: []

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Sanctum Token
      description: |
        Token Sanctum uzyskany z endpointu /auth/login.

        Przykład:
        ```
        Authorization: Bearer 1|abc123xyz...
        ```

  schemas:
    # === Common Schemas ===
    SuccessResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          nullable: true
        message:
          type: string
          nullable: true
        meta:
          type: object
          nullable: true

    ErrorResponse:
      type: object
      required:
        - success
        - message
      properties:
        success:
          type: boolean
          example: false
        message:
          type: string
          example: "Resource not found"
        errors:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          example:
            email: ["The email field is required."]

    PaginationMeta:
      type: object
      properties:
        current_page:
          type: integer
          example: 1
        per_page:
          type: integer
          example: 15
        total:
          type: integer
          example: 100
        last_page:
          type: integer
          example: 7
        from:
          type: integer
          example: 1
        to:
          type: integer
          example: 15

    # === User Schema ===
    User:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "Jan Kowalski"
        email:
          type: string
          format: email
          example: "jan@example.com"
        avatar:
          type: string
          nullable: true
          example: "https://example.com/avatar.jpg"
        current_workspace_id:
          type: integer
          nullable: true
          example: 1
        current_project_id:
          type: integer
          nullable: true
          example: 1
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    # === Workspace Schema ===
    Workspace:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "Moja Firma"
        slug:
          type: string
          example: "moja-firma"
        description:
          type: string
          nullable: true
        credit_balance:
          type: number
          format: float
          example: 100.50
        owner_id:
          type: integer
          example: 1
        users_count:
          type: integer
          example: 5
        projects_count:
          type: integer
          example: 3
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    WorkspaceListItem:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "Moja Firma"
        slug:
          type: string
          example: "moja-firma"
        role:
          type: string
          enum: [owner, admin, member]
          example: "owner"
        credit_balance:
          type: number
          format: float
          example: 100.50
        users_count:
          type: integer
          example: 5
        projects_count:
          type: integer
          example: 3
        created_at:
          type: string
          format: date-time

    # === Drive Item Schema ===
    DriveItem:
      type: object
      properties:
        id:
          type: integer
          example: 123
        name:
          type: string
          example: "Kampania Q1 2024"
        type:
          type: string
          enum:
            - folder
            - text
            - note
            - document
            - image
            - file
            - html
            - css
            - js
            - landing_page
            - landing_site
            - table
            - ad
            - prompt
            - list
            - color
            - ai_image
            - site_analysis
            - video
            - font
          example: "folder"
        parent_id:
          type: integer
          nullable: true
          example: null
        project_id:
          type: integer
          example: 1
        content:
          type: object
          nullable: true
          additionalProperties: true
          example:
            title: "Nagłówek kampanii"
            description: "Opis kampanii reklamowej"
        description:
          type: string
          nullable: true
        file_path:
          type: string
          nullable: true
          example: "drive/images/banner.jpg"
        mime_type:
          type: string
          nullable: true
          example: "image/jpeg"
        file_size:
          type: integer
          nullable: true
          example: 1048576
        generated_html:
          type: string
          nullable: true
        is_published:
          type: boolean
          example: false
        public_token:
          type: string
          nullable: true
        is_favorite:
          type: boolean
          example: false
        title:
          type: string
          nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    DriveItemCreate:
      type: object
      required:
        - name
        - type
      properties:
        name:
          type: string
          maxLength: 255
          example: "Nowy folder"
        type:
          type: string
          enum:
            - folder
            - text
            - note
            - document
            - image
            - file
            - html
            - css
            - js
            - landing_page
            - landing_site
            - table
            - ad
            - prompt
            - list
            - color
            - ai_image
            - site_analysis
            - video
            - font
          example: "folder"
        parent_id:
          type: integer
          nullable: true
          example: null
        project_id:
          type: integer
          nullable: true
        template_id:
          type: integer
          nullable: true
        content:
          type: object
          nullable: true
          additionalProperties: true
        description:
          type: string
          nullable: true

    DriveItemUpdate:
      type: object
      properties:
        name:
          type: string
          maxLength: 255
          example: "Zaktualizowana nazwa"
        content:
          type: object
          nullable: true
          additionalProperties: true
        description:
          type: string
          nullable: true
        order:
          type: integer
        generated_html:
          type: string
          nullable: true

    Breadcrumb:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "Folder główny"
        type:
          type: string
          example: "folder"

    # === Template Schema ===
    Template:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "Banner reklamowy"
        code:
          type: string
          pattern: "^[a-z0-9_]+$"
          example: "banner_reklamowy"
        description:
          type: string
          nullable: true
          example: "Szablon dla banerów reklamowych"
        type:
          type: string
          nullable: true
          example: "ad"
        button_name:
          type: string
          nullable: true
          example: "Utwórz banner"
        button_icon:
          type: string
          nullable: true
          example: "🖼️"
        schema_definition:
          type: object
          nullable: true
          properties:
            fields:
              type: array
              items:
                $ref: '#/components/schemas/TemplateField'
            show_assets:
              type: boolean
            asset_ids:
              type: array
              items:
                type: integer
        is_active:
          type: boolean
          example: true
        show_in_types:
          type: boolean
          example: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    TemplateField:
      type: object
      properties:
        type:
          type: string
          enum: [text, textarea, number, select, boolean, image, color, html, markdown, prompt, rich_text]
          example: "text"
        label:
          type: string
          nullable: true
          example: "Nagłówek"
        placeholder:
          type: string
          nullable: true
          example: "Wpisz nagłówek..."
        multiple:
          type: boolean
          nullable: true
        required:
          type: boolean
          nullable: true
        limit:
          type: integer
          nullable: true
        options:
          type: array
          nullable: true
          items:
            type: string
        ai_enabled:
          type: boolean
          nullable: true
        ai_system_prompt:
          type: string
          nullable: true
        default_value:
          type: string
          nullable: true

    TemplateCreate:
      type: object
      required:
        - name
        - code
      properties:
        name:
          type: string
          minLength: 2
          maxLength: 255
          example: "Banner reklamowy"
        code:
          type: string
          minLength: 2
          maxLength: 100
          pattern: "^[a-z0-9_]+$"
          example: "banner_reklamowy"
        description:
          type: string
          nullable: true
          maxLength: 2000
        type:
          type: string
          nullable: true
          maxLength: 100
        button_name:
          type: string
          nullable: true
          maxLength: 100
        button_icon:
          type: string
          nullable: true
          maxLength: 10
        schema_definition:
          type: object
          nullable: true
        is_active:
          type: boolean
        show_in_types:
          type: boolean

    # === Agent Schemas ===
    AgentConversation:
      type: object
      properties:
        id:
          type: integer
          example: 42
        title:
          type: string
          example: "Analiza strony internetowej"
        status:
          type: string
          enum: [active, archived, closed]
          example: "active"
        agent_definition_id:
          type: integer
          nullable: true
          example: 1
        messages_count:
          type: integer
          example: 5
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    AgentMessage:
      type: object
      properties:
        role:
          type: string
          enum: [user, assistant, system]
          example: "user"
        content:
          type: string
          example: "Przeanalizuj stronę anthropic.com"
        tool_calls:
          type: array
          nullable: true
          items:
            type: object
            properties:
              name:
                type: string
                example: "fetch_webpage"
              arguments:
                type: object

    AgentJobStatus:
      type: object
      properties:
        job_id:
          type: string
          format: uuid
          example: "550e8400-e29b-41d4-a716-446655440000"
        status:
          type: string
          enum: [pending, processing, completed, failed]
          example: "completed"
        progress:
          type: integer
          minimum: 0
          maximum: 100
          example: 100
        result:
          type: object
          nullable: true
        error:
          type: string
          nullable: true

    # === Website Page Schema ===
    WebsitePage:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "Strona główna"
        slug:
          type: string
          example: "strona-glowna"
        html:
          type: string
          nullable: true
          description: Pełny HTML strony
        sections:
          type: array
          nullable: true
          items:
            type: object
            properties:
              id:
                type: string
              type:
                type: string
              html:
                type: string
        show_in_menu:
          type: boolean
          example: true
        order:
          type: integer
          example: 0
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    # === Pipeline Schema ===
    Pipeline:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "Generowanie kampanii"
        description:
          type: string
          nullable: true
          example: "Pipeline do automatycznego generowania materiałów kampanii"
        nodes:
          type: array
          items:
            $ref: '#/components/schemas/PipelineNode'
        edges:
          type: array
          items:
            $ref: '#/components/schemas/PipelineEdge'
        viewport:
          type: object
          properties:
            x:
              type: number
            y:
              type: number
            zoom:
              type: number
        project_id:
          type: integer
          example: 1
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    PipelineNode:
      type: object
      properties:
        id:
          type: string
          example: "node_1"
        type:
          type: string
          example: "ai_text"
        position:
          type: object
          properties:
            x:
              type: number
            y:
              type: number
        data:
          type: object
          additionalProperties: true
          description: Dynamiczne dane specyficzne dla typu node'a

    PipelineEdge:
      type: object
      properties:
        id:
          type: string
          example: "edge_1"
        source:
          type: string
          example: "node_1"
        target:
          type: string
          example: "node_2"
        sourceHandle:
          type: string
          nullable: true
        targetHandle:
          type: string
          nullable: true

    PipelineCreate:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          maxLength: 255
          example: "Nowy pipeline"
        description:
          type: string
          nullable: true
          maxLength: 2000
        nodes:
          type: array
          items:
            $ref: '#/components/schemas/PipelineNode'
        edges:
          type: array
          items:
            $ref: '#/components/schemas/PipelineEdge'
        viewport:
          type: object
          properties:
            x:
              type: number
              default: 0
            y:
              type: number
              default: 0
            zoom:
              type: number
              default: 1

    # === AI Schemas ===
    AiTextGenerateRequest:
      type: object
      required:
        - prompt
      properties:
        prompt:
          type: string
          maxLength: 10000
          description: Prompt do wygenerowania tekstu
          example: "Napisz chwytliwy nagłówek reklamowy dla sklepu z elektroniką"
        system_prompt:
          type: string
          maxLength: 5000
          nullable: true
          description: System prompt definiujący kontekst AI
          example: "Jesteś ekspertem od marketingu cyfrowego"
        model:
          type: string
          default: "gemini-3-pro-preview"
          example: "gemini-3-pro-preview"
        max_tokens:
          type: integer
          minimum: 1
          maximum: 8000
          default: 2000
          example: 2000
        temperature:
          type: number
          minimum: 0
          maximum: 2
          default: 0.7
          example: 0.7

    AiTextGenerateResponse:
      type: object
      properties:
        text:
          type: string
          example: "Odkryj świat technologii w zasięgu ręki!"
        usage:
          type: object
          nullable: true
          properties:
            prompt_tokens:
              type: integer
              example: 25
            completion_tokens:
              type: integer
              example: 15
            total_tokens:
              type: integer
              example: 40

    AiImageGenerateRequest:
      type: object
      required:
        - prompt
      properties:
        prompt:
          type: string
          maxLength: 5000
          description: Opis obrazu do wygenerowania
          example: "Nowoczesny baner reklamowy dla e-commerce, minimalistyczny styl, niebieskie odcienie"
        model:
          type: string
          nullable: true
          example: "nanobanana"
        size:
          type: string
          enum: ["256x256", "512x512", "1024x1024"]
          nullable: true
          example: "1024x1024"
        style:
          type: string
          nullable: true
          example: "photorealistic"

    AiImageGenerateResponse:
      type: object
      properties:
        url:
          type: string
          format: uri
          example: "https://storage.example.com/images/generated-123.png"
        model:
          type: string
          example: "nanobanana"

    AiImageAsyncResponse:
      type: object
      properties:
        job_id:
          type: string
          format: uuid
          example: "550e8400-e29b-41d4-a716-446655440000"
        status:
          type: string
          enum: [pending, processing, completed, failed]
          example: "pending"
        model:
          type: string
          example: "gemini-3-pro-image-preview"

    AiJobStatus:
      type: object
      properties:
        job_id:
          type: string
          format: uuid
          example: "550e8400-e29b-41d4-a716-446655440000"
        status:
          type: string
          enum: [pending, processing, completed, failed]
          example: "completed"
        progress:
          type: integer
          minimum: 0
          maximum: 100
          example: 100
        stage:
          type: string
          nullable: true
          example: "Generowanie zakończone"
        image_url:
          type: string
          format: uri
          nullable: true
          example: "https://storage.example.com/images/generated-123.png"
        error:
          type: string
          nullable: true

    AiChatRequest:
      type: object
      required:
        - messages
      properties:
        messages:
          type: array
          minItems: 1
          items:
            type: object
            required:
              - role
              - content
            properties:
              role:
                type: string
                enum: [user, assistant, system]
              content:
                type: string
          example:
            - role: "system"
              content: "Jesteś asystentem marketingu"
            - role: "user"
              content: "Zaproponuj hasło reklamowe"
        model:
          type: string
          nullable: true
          example: "gemini-3-pro-preview"
        max_tokens:
          type: integer
          minimum: 1
          maximum: 8000
          nullable: true
          example: 2000
        temperature:
          type: number
          minimum: 0
          maximum: 2
          nullable: true
          example: 0.7

    AiChatResponse:
      type: object
      properties:
        message:
          type: object
          properties:
            role:
              type: string
              example: "assistant"
            content:
              type: string
              example: "Oto propozycja hasła: 'Twoja wizja, nasza technologia'"
        usage:
          type: object
          nullable: true
          properties:
            prompt_tokens:
              type: integer
            completion_tokens:
              type: integer
            total_tokens:
              type: integer

    # === Guidelines Schema ===
    GuidelinesUpdate:
      type: object
      description: Dane do aktualizacji wytycznych folderu
      properties:
        tone:
          type: string
          nullable: true
          maxLength: 500
          description: Ton komunikacji (np. profesjonalny, kreatywny)
          example: "profesjonalny"
        style:
          type: string
          nullable: true
          maxLength: 500
          description: Styl pisania (np. zwięzły, opisowy)
          example: "zwięzły i jasny"
        language:
          type: string
          nullable: true
          maxLength: 100
          description: Język treści
          example: "pl"
        instructions:
          type: string
          nullable: true
          maxLength: 5000
          description: Dodatkowe instrukcje dla AI
          example: "Pisz w sposób przystępny dla klienta B2B"
        forbidden_rules:
          type: array
          nullable: true
          items:
            type: object
            properties:
              rule:
                type: string
              reason:
                type: string
                nullable: true
        context_variables:
          type: object
          nullable: true
          additionalProperties:
            type: string
          example:
            brand_name: "Blitzly"
            industry: "SaaS"
        asset_ids:
          type: array
          nullable: true
          items:
            type: integer
          description: ID assetów kontekstowych
        inheritance_mode:
          type: string
          nullable: true
          enum: [extend, override, isolate]
          description: |
            Tryb dziedziczenia:
            - extend: rozszerza wytyczne rodzica
            - override: nadpisuje wytyczne rodzica
            - isolate: ignoruje wytyczne rodzica
          example: "extend"
        version:
          type: integer
          nullable: true
          description: Wersja wytycznych (optimistic locking)

    # === Variable Schema ===
    Variable:
      type: object
      properties:
        id:
          type: integer
          example: 1
        key:
          type: string
          example: "company_name"
        value:
          type: string
          example: "Moja Firma Sp. z o.o."
        description:
          type: string
          nullable: true
          example: "Oficjalna nazwa firmy"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time

    # === Collection Schema ===
    DriveCollection:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: "Materiały kampanii"
        items_count:
          type: integer
          example: 12
        created_at:
          type: string
          format: date-time

    # === Job Status Schema ===
    UnifiedJobStatus:
      type: object
      properties:
        job_id:
          type: string
          example: "550e8400-e29b-41d4-a716-446655440000"
        job_type:
          type: string
          enum: [image, text, agent, workflow, node, website, field, creative, layout, design, analysis, cell]
          example: "image"
        status:
          type: string
          enum: [pending, processing, completed, failed, cancelled]
          example: "completed"
        progress:
          type: integer
          minimum: 0
          maximum: 100
          example: 100
        stage:
          type: string
          nullable: true
          example: "Zakończone"
        job_label:
          type: string
          nullable: true
          example: "Banner kampanii"
        result:
          type: object
          nullable: true
        error:
          type: string
          nullable: true
        started_at:
          type: string
          format: date-time
          nullable: true
        completed_at:
          type: string
          format: date-time
          nullable: true

  parameters:
    WorkspaceHeader:
      name: X-Workspace
      in: header
      required: true
      description: ID aktualnego workspace
      schema:
        type: integer
        example: 1

    ProjectHeader:
      name: X-Project
      in: header
      required: false
      description: ID aktualnego projektu (opcjonalnie)
      schema:
        type: integer
        example: 1

    IdPath:
      name: id
      in: path
      required: true
      description: ID zasobu
      schema:
        type: integer
        example: 1

    PageQuery:
      name: page
      in: query
      description: Numer strony
      schema:
        type: integer
        default: 1
        example: 1

    PerPageQuery:
      name: per_page
      in: query
      description: Liczba elementów na stronie
      schema:
        type: integer
        default: 15
        maximum: 100
        example: 15

  responses:
    Unauthorized:
      description: Brak autoryzacji - nieprawidłowy lub brakujący token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            message: "Unauthorized"

    Forbidden:
      description: Brak uprawnień do zasobu
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            message: "Access denied"

    NotFound:
      description: Zasób nie został znaleziony
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            message: "Resource not found"

    ValidationError:
      description: Błąd walidacji danych wejściowych
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            message: "Validation failed"
            errors:
              name: ["The name field is required."]
              email: ["The email must be a valid email address."]

    InsufficientCredits:
      description: Niewystarczająca ilość kredytów
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            success: false
            message: "Insufficient credits"

paths:
  # ==========================================================================
  # AUTH ENDPOINTS
  # ==========================================================================
  /auth/login:
    post:
      tags:
        - Auth
      summary: Logowanie i pobranie tokena API
      description: |
        Logowanie użytkownika i zwrócenie tokena Bearer do autoryzacji kolejnych żądań.

        Rate limit: 5 prób/minutę per IP
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - password
              properties:
                email:
                  type: string
                  format: email
                  example: "user@example.com"
                password:
                  type: string
                  format: password
                  example: "secret123"
                device_name:
                  type: string
                  description: Nazwa urządzenia/aplikacji do identyfikacji tokena
                  example: "iPhone 15 Pro"
      responses:
        '200':
          description: Pomyślne logowanie
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          token:
                            type: string
                            example: "1|abc123xyz789..."
                          token_type:
                            type: string
                            example: "Bearer"
                          user:
                            $ref: '#/components/schemas/User'
                      message:
                        type: string
                        example: "Login successful"
              example:
                success: true
                data:
                  token: "1|abc123xyz789def456..."
                  token_type: "Bearer"
                  user:
                    id: 1
                    name: "Jan Kowalski"
                    email: "jan@example.com"
                    avatar: null
                    current_workspace_id: 1
                    current_project_id: 1
                message: "Login successful"
        '401':
          description: Nieprawidłowe dane logowania
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "Invalid credentials"
                errors:
                  email: ["The provided credentials are incorrect."]
        '403':
          description: Konto zablokowane
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "Account is blocked"

  /auth/register:
    post:
      tags:
        - Auth
      summary: Rejestracja nowego użytkownika
      description: |
        Rejestracja nowego konta. Automatycznie tworzy domyślny workspace.

        Rate limit: 3 próby/minutę per IP
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - email
                - password
                - password_confirmation
              properties:
                name:
                  type: string
                  example: "Jan Kowalski"
                email:
                  type: string
                  format: email
                  example: "jan@example.com"
                password:
                  type: string
                  format: password
                  minLength: 8
                  example: "secretpassword123"
                password_confirmation:
                  type: string
                  format: password
                  example: "secretpassword123"
      responses:
        '201':
          description: Użytkownik zarejestrowany
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          token:
                            type: string
                          token_type:
                            type: string
                          user:
                            $ref: '#/components/schemas/User'
              example:
                success: true
                data:
                  token: "1|newtoken123..."
                  token_type: "Bearer"
                  user:
                    id: 5
                    name: "Jan Kowalski"
                    email: "jan@example.com"
                    current_workspace_id: 3
                    current_project_id: 4
                message: "Registration successful"
        '422':
          $ref: '#/components/responses/ValidationError'

  /auth/logout:
    post:
      tags:
        - Auth
      summary: Wylogowanie
      description: Unieważnia aktualny token API
      responses:
        '200':
          description: Pomyślne wylogowanie
          content:
            application/json:
              example:
                success: true
                data: null
                message: "Logged out successfully"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /auth/me:
    get:
      tags:
        - Auth
      summary: Dane zalogowanego użytkownika
      description: Zwraca pełne dane aktualnie zalogowanego użytkownika wraz z workspace'ami
      responses:
        '200':
          description: Dane użytkownika
          content:
            application/json:
              example:
                success: true
                data:
                  id: 1
                  name: "Jan Kowalski"
                  email: "jan@example.com"
                  avatar: null
                  current_workspace_id: 1
                  current_project_id: 1
                  current_workspace:
                    id: 1
                    name: "Moja Firma"
                    slug: "moja-firma"
                  current_project:
                    id: 1
                    name: "Kampania Q1"
                    slug: "kampania-q1"
                  workspaces:
                    - id: 1
                      name: "Moja Firma"
                      slug: "moja-firma"
                      role: "owner"
                    - id: 2
                      name: "Klient ABC"
                      slug: "klient-abc"
                      role: "member"
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ==========================================================================
  # WORKSPACE ENDPOINTS
  # ==========================================================================
  /workspaces:
    get:
      tags:
        - Workspaces
      summary: Lista workspace'ów użytkownika
      description: Zwraca wszystkie workspace'y, do których użytkownik ma dostęp
      responses:
        '200':
          description: Lista workspace'ów
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/WorkspaceListItem'
              example:
                success: true
                data:
                  - id: 1
                    name: "Moja Firma"
                    slug: "moja-firma"
                    role: "owner"
                    credit_balance: 100.50
                    users_count: 5
                    projects_count: 3
                    created_at: "2024-01-15T10:30:00Z"
                  - id: 2
                    name: "Klient ABC"
                    slug: "klient-abc"
                    role: "member"
                    credit_balance: 50.00
                    users_count: 3
                    projects_count: 2
                    created_at: "2024-02-01T14:00:00Z"
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Workspaces
      summary: Utwórz nowy workspace
      description: Tworzy nowy workspace i opcjonalnie domyślny projekt
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: "Nowy Workspace"
                slug:
                  type: string
                  maxLength: 255
                  example: "nowy-workspace"
                description:
                  type: string
                  maxLength: 1000
                  example: "Opis workspace'a"
                create_default_project:
                  type: boolean
                  default: true
                  description: Czy utworzyć domyślny projekt
                switch_to:
                  type: boolean
                  default: false
                  description: Czy przełączyć się na nowy workspace
      responses:
        '201':
          description: Workspace utworzony
          content:
            application/json:
              example:
                success: true
                data:
                  id: 5
                  name: "Nowy Workspace"
                  slug: "nowy-workspace"
                  description: "Opis workspace'a"
                  credit_balance: 0
                  default_project_id: 10
                message: "Workspace created"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /workspaces/{workspace}:
    get:
      tags:
        - Workspaces
      summary: Szczegóły workspace
      description: Zwraca szczegółowe informacje o workspace
      parameters:
        - name: workspace
          in: path
          required: true
          schema:
            type: integer
          example: 1
      responses:
        '200':
          description: Dane workspace
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Workspace'
              example:
                success: true
                data:
                  id: 1
                  name: "Moja Firma"
                  slug: "moja-firma"
                  credit_balance: 100.50
                  owner_id: 1
                  users_count: 5
                  projects_count: 3
                  created_at: "2024-01-15T10:30:00Z"
                  updated_at: "2024-03-01T08:00:00Z"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Workspaces
      summary: Aktualizuj workspace
      description: |
        Aktualizuje dane workspace.

        Wymaga roli `owner` lub `admin`.
      parameters:
        - name: workspace
          in: path
          required: true
          schema:
            type: integer
          example: 1
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: "Zaktualizowana nazwa"
                slug:
                  type: string
                  maxLength: 255
                  example: "zaktualizowany-slug"
      responses:
        '200':
          description: Workspace zaktualizowany
          content:
            application/json:
              example:
                success: true
                data:
                  id: 1
                  name: "Zaktualizowana nazwa"
                  slug: "zaktualizowany-slug"
                message: "Workspace updated"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Workspaces
      summary: Usuń workspace
      description: |
        Usuwa workspace i wszystkie powiązane dane.

        **UWAGA:** Ta operacja jest nieodwracalna!

        Wymaga roli `owner`.
      parameters:
        - name: workspace
          in: path
          required: true
          schema:
            type: integer
          example: 1
      responses:
        '200':
          description: Workspace usunięty
          content:
            application/json:
              example:
                success: true
                data: null
                message: "Workspace deleted"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'

  # ==========================================================================
  # DRIVE ENDPOINTS
  # ==========================================================================
  /drive:
    get:
      tags:
        - Drive
      summary: Lista elementów Drive
      description: |
        Zwraca listę elementów (plików i folderów) z Drive.

        Wspiera filtrowanie, sortowanie i paginację.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: parent_id
          in: query
          description: ID folderu nadrzędnego (null = root)
          schema:
            type: integer
            nullable: true
        - name: type
          in: query
          description: Filtruj po typie elementu
          schema:
            type: string
            enum: [folder, text, image, video, ad, prompt, list, color]
        - name: types
          in: query
          description: Filtruj po wielu typach (tablica)
          schema:
            type: array
            items:
              type: string
        - name: search
          in: query
          description: Szukaj po nazwie
          schema:
            type: string
        - name: favorites
          in: query
          description: Tylko ulubione
          schema:
            type: boolean
        - name: recent
          in: query
          description: Ostatnio używane
          schema:
            type: boolean
        - name: shared
          in: query
          description: Udostępnione
          schema:
            type: boolean
        - name: collection_id
          in: query
          description: Filtruj po kolekcji
          schema:
            type: integer
        - name: sort_field
          in: query
          description: Pole sortowania
          schema:
            type: string
            default: created_at
            enum: [created_at, updated_at, name, type]
        - name: sort_direction
          in: query
          description: Kierunek sortowania
          schema:
            type: string
            default: desc
            enum: [asc, desc]
        - name: with_path
          in: query
          description: Dołącz ścieżkę do elementu
          schema:
            type: boolean
        - $ref: '#/components/parameters/PerPageQuery'
      responses:
        '200':
          description: Lista elementów
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/DriveItem'
              example:
                success: true
                data:
                  - id: 1
                    name: "Kampanie 2024"
                    type: "folder"
                    parent_id: null
                    project_id: 1
                    is_favorite: false
                    created_at: "2024-01-15T10:00:00Z"
                    updated_at: "2024-03-01T12:00:00Z"
                  - id: 2
                    name: "Banner główny"
                    type: "image"
                    parent_id: 1
                    project_id: 1
                    file_path: "drive/images/banner.jpg"
                    mime_type: "image/jpeg"
                    file_size: 1048576
                    is_favorite: true
                    created_at: "2024-02-01T14:00:00Z"
                    updated_at: "2024-02-15T09:30:00Z"
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Drive
      summary: Utwórz nowy element
      description: Tworzy nowy element w Drive (folder, dokument, itp.)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DriveItemCreate'
            examples:
              folder:
                summary: Tworzenie folderu
                value:
                  name: "Nowy folder"
                  type: "folder"
                  parent_id: null
              text:
                summary: Tworzenie dokumentu tekstowego
                value:
                  name: "Notatka"
                  type: "text"
                  parent_id: 1
                  content:
                    body: "Treść notatki..."
              prompt:
                summary: Tworzenie prompta AI
                value:
                  name: "Prompt reklamowy"
                  type: "prompt"
                  parent_id: 1
                  content:
                    prompt: "Napisz reklamę dla {{product}}"
                    variables:
                      - product
      responses:
        '201':
          description: Element utworzony
          content:
            application/json:
              example:
                success: true
                data:
                  id: 123
                  name: "Nowy folder"
                  type: "folder"
                  parent_id: null
                  project_id: 1
                message: "Item created"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/{id}:
    get:
      tags:
        - Drive
      summary: Szczegóły elementu
      description: Zwraca pełne dane elementu wraz z breadcrumbs
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '200':
          description: Dane elementu
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        allOf:
                          - $ref: '#/components/schemas/DriveItem'
                          - type: object
                            properties:
                              breadcrumbs:
                                type: array
                                items:
                                  $ref: '#/components/schemas/Breadcrumb'
                              children_count:
                                type: integer
              example:
                success: true
                data:
                  id: 2
                  name: "Banner główny"
                  type: "image"
                  parent_id: 1
                  project_id: 1
                  content: null
                  description: "Banner reklamowy Q1 2024"
                  file_path: "drive/images/banner.jpg"
                  mime_type: "image/jpeg"
                  file_size: 1048576
                  is_published: false
                  is_favorite: true
                  created_at: "2024-02-01T14:00:00Z"
                  updated_at: "2024-02-15T09:30:00Z"
                  parent:
                    id: 1
                    name: "Kampanie 2024"
                    type: "folder"
                  children_count: 0
                  breadcrumbs:
                    - id: 1
                      name: "Kampanie 2024"
                      type: "folder"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Drive
      summary: Aktualizuj element
      description: Aktualizuje dane elementu (nazwa, content, itp.)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DriveItemUpdate'
            example:
              name: "Zaktualizowana nazwa"
              content:
                body: "Nowa treść dokumentu"
              description: "Zaktualizowany opis"
      responses:
        '200':
          description: Element zaktualizowany
          content:
            application/json:
              example:
                success: true
                data:
                  id: 2
                  name: "Zaktualizowana nazwa"
                  type: "text"
                  content:
                    body: "Nowa treść dokumentu"
                  updated_at: "2024-03-15T10:00:00Z"
                message: "Item updated"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Drive
      summary: Usuń element
      description: |
        Przenosi element do kosza (soft delete).

        Użyj `/drive/trash/{id}/force` aby trwale usunąć.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '200':
          description: Element usunięty (przeniesiony do kosza)
          content:
            application/json:
              example:
                success: true
                data: null
                message: "Item deleted"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # AI ENDPOINTS
  # ==========================================================================
  /ai/generate-text:
    post:
      tags:
        - AI
      summary: Generuj tekst przez AI
      description: |
        Synchroniczne generowanie tekstu przez model AI.

        Rate limit: 20 żądań/minutę per workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AiTextGenerateRequest'
            example:
              prompt: "Napisz chwytliwy nagłówek reklamowy dla sklepu z elektroniką"
              system_prompt: "Jesteś ekspertem od marketingu cyfrowego. Pisz krótko i przekonująco."
              model: "gemini-3-pro-preview"
              max_tokens: 500
              temperature: 0.8
      responses:
        '200':
          description: Wygenerowany tekst
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/AiTextGenerateResponse'
              example:
                success: true
                data:
                  text: "Odkryj świat technologii w zasięgu ręki - najnowsze gadżety w najlepszych cenach!"
                  usage:
                    prompt_tokens: 45
                    completion_tokens: 18
                    total_tokens: 63
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/InsufficientCredits'
        '422':
          $ref: '#/components/responses/ValidationError'
        '500':
          description: Błąd generowania
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "AI generation failed: Model unavailable"

  /ai/generate-image:
    post:
      tags:
        - AI
      summary: Generuj obraz (synchronicznie)
      description: |
        Synchroniczne generowanie obrazu przez AI.

        **UWAGA:** Może zająć kilka sekund. Dla dłuższych operacji użyj `/ai/generate-image-async`.

        Rate limit: 10 żądań/minutę per workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AiImageGenerateRequest'
            example:
              prompt: "Nowoczesny baner reklamowy dla e-commerce, minimalistyczny styl, niebieskie odcienie"
              model: "nanobanana"
              size: "1024x1024"
              style: "photorealistic"
      responses:
        '200':
          description: Wygenerowany obraz
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/AiImageGenerateResponse'
              example:
                success: true
                data:
                  url: "https://storage.example.com/images/generated-abc123.png"
                  model: "nanobanana"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/InsufficientCredits'
        '422':
          $ref: '#/components/responses/ValidationError'
        '500':
          description: Błąd generowania obrazu
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "Image generation failed: Content policy violation"

  /ai/generate-image-async:
    post:
      tags:
        - AI
      summary: Generuj obraz (asynchronicznie)
      description: |
        Asynchroniczne generowanie obrazu. Zwraca `job_id` do sprawdzania statusu.

        Użyj `/ai/check-image-status/{jobId}` aby sprawdzić postęp.

        Rate limit: 10 żądań/minutę per workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - prompt
              properties:
                prompt:
                  type: string
                  maxLength: 5000
                model:
                  type: string
                  nullable: true
                reference_image:
                  type: string
                  description: URL obrazu referencyjnego
                  nullable: true
                item_id:
                  type: integer
                  description: ID elementu Drive do powiązania
                  nullable: true
            example:
              prompt: "Futurystyczna grafika produktowa dla smartwatcha"
              model: "gemini-3-pro-image-preview"
              reference_image: "https://example.com/reference.jpg"
      responses:
        '200':
          description: Zadanie uruchomione
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/AiImageAsyncResponse'
              example:
                success: true
                data:
                  job_id: "550e8400-e29b-41d4-a716-446655440000"
                  status: "pending"
                  model: "gemini-3-pro-image-preview"
                message: "Image generation started"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/InsufficientCredits'

  /ai/check-image-status/{jobId}:
    get:
      tags:
        - AI
      summary: Status generowania obrazu
      description: Sprawdza status asynchronicznego zadania generowania obrazu
      parameters:
        - name: jobId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          example: "550e8400-e29b-41d4-a716-446655440000"
      responses:
        '200':
          description: Status zadania
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/AiJobStatus'
              examples:
                pending:
                  summary: Zadanie w kolejce
                  value:
                    success: true
                    data:
                      job_id: "550e8400-e29b-41d4-a716-446655440000"
                      status: "pending"
                      progress: 0
                      stage: "W kolejce..."
                      image_url: null
                      error: null
                processing:
                  summary: Zadanie w trakcie
                  value:
                    success: true
                    data:
                      job_id: "550e8400-e29b-41d4-a716-446655440000"
                      status: "processing"
                      progress: 45
                      stage: "Generowanie obrazu..."
                      image_url: null
                      error: null
                completed:
                  summary: Zadanie zakończone
                  value:
                    success: true
                    data:
                      job_id: "550e8400-e29b-41d4-a716-446655440000"
                      status: "completed"
                      progress: 100
                      stage: "Zakończone"
                      image_url: "https://storage.example.com/images/generated-123.png"
                      error: null
                failed:
                  summary: Zadanie zakończone błędem
                  value:
                    success: true
                    data:
                      job_id: "550e8400-e29b-41d4-a716-446655440000"
                      status: "failed"
                      progress: 0
                      stage: null
                      image_url: null
                      error: "Content policy violation"
        '404':
          description: Zadanie nie znalezione lub wygasło
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "Job not found or expired"

  /ai/chat:
    post:
      tags:
        - AI
      summary: Chat z AI
      description: |
        Konwersacja z modelem AI. Pozwala na wieloturowy dialog.

        Rate limit: 20 żądań/minutę per workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AiChatRequest'
            example:
              messages:
                - role: "system"
                  content: "Jesteś kreatywnym copywriterem specjalizującym się w reklamach"
                - role: "user"
                  content: "Zaproponuj 3 hasła reklamowe dla kawiarni"
              model: "gemini-3-pro-preview"
              max_tokens: 500
              temperature: 0.9
      responses:
        '200':
          description: Odpowiedź AI
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/AiChatResponse'
              example:
                success: true
                data:
                  message:
                    role: "assistant"
                    content: |
                      Oto 3 propozycje haseł reklamowych dla kawiarni:

                      1. "Twoja przerwa na kawę, nasza pasja w każdej filiżance"
                      2. "Gdzie aromat spotyka się z chwilą relaksu"
                      3. "Kawa jak rytuał - znajdź swój smak dnia"
                  usage:
                    prompt_tokens: 35
                    completion_tokens: 62
                    total_tokens: 97
        '401':
          $ref: '#/components/responses/Unauthorized'
        '402':
          $ref: '#/components/responses/InsufficientCredits'
        '422':
          $ref: '#/components/responses/ValidationError'

  /ai/check-status/{jobId}:
    get:
      tags:
        - AI
      summary: Status ogólnego zadania AI
      description: Sprawdza status asynchronicznego zadania AI (tekst, pole formularza)
      parameters:
        - name: jobId
          in: path
          required: true
          schema:
            type: string
            format: uuid
          example: "550e8400-e29b-41d4-a716-446655440000"
      responses:
        '200':
          description: Status zadania
          content:
            application/json:
              example:
                success: true
                data:
                  job_id: "550e8400-e29b-41d4-a716-446655440000"
                  status: "completed"
                  result:
                    text: "Wygenerowana treść..."
                  error: null
                  started_at: "2024-03-15T10:00:00Z"
                  completed_at: "2024-03-15T10:00:05Z"
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # AGENT ENDPOINTS
  # ==========================================================================
  /agent/conversations:
    get:
      tags:
        - Agent
      summary: Lista konwersacji agenta
      description: |
        Zwraca listę konwersacji dla bieżącego projektu, posortowanych od najnowszej.

        Konwersacje są powiązane z projektem przez header `X-Project`.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/ProjectHeader'
        - name: limit
          in: query
          description: Limit wyników (domyślnie 20, max 100)
          schema:
            type: integer
            default: 20
            maximum: 100
      responses:
        '200':
          description: Lista konwersacji
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/AgentConversation'
              example:
                success: true
                data:
                  - id: 42
                    title: "Analiza strony internetowej"
                    status: "active"
                    agent_definition_id: 1
                    messages_count: 8
                    created_at: "2024-03-10T14:00:00Z"
                    updated_at: "2024-03-10T14:30:00Z"
                  - id: 41
                    title: "Generowanie treści SEO"
                    status: "active"
                    agent_definition_id: null
                    messages_count: 3
                    created_at: "2024-03-09T10:00:00Z"
                    updated_at: "2024-03-09T10:15:00Z"
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Agent
      summary: Utwórz nową konwersację
      description: |
        Tworzy nową konwersację z opcjonalnym przypisaniem do agenta
        (np. `site_auditor`, `general_assistant`) i niestandardowym tytułem.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                agent_definition_id:
                  type: integer
                  nullable: true
                  description: ID definicji agenta
                  example: 1
                title:
                  type: string
                  nullable: true
                  maxLength: 255
                  description: Tytuł konwersacji
                  example: "Nowa analiza SEO"
      responses:
        '201':
          description: Konwersacja utworzona
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          id:
                            type: integer
                            example: 43
                          title:
                            type: string
                            example: "Nowa analiza SEO"
                          messages:
                            type: array
                            items:
                              $ref: '#/components/schemas/AgentMessage'
                          status:
                            type: string
                            example: "active"
              example:
                success: true
                data:
                  id: 43
                  title: "Nowa analiza SEO"
                  messages: []
                  status: "active"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /agent/conversations/{id}:
    get:
      tags:
        - Agent
      summary: Szczegóły konwersacji
      description: |
        Zwraca pełne dane konwersacji wraz z wiadomościami, assetami
        i metadanymi agenta. Użyteczne do wyświetlenia pełnej historii rozmowy.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID konwersacji
          schema:
            type: integer
      responses:
        '200':
          description: Dane konwersacji z wiadomościami i assetami
          content:
            application/json:
              example:
                success: true
                data:
                  conversation:
                    id: 42
                    title: "Analiza strony internetowej"
                    status: "active"
                    agent_definition_id: 1
                  messages:
                    - role: "user"
                      content: "Przeanalizuj stronę example.com"
                    - role: "assistant"
                      content: "Analizuję stronę..."
                      tool_calls:
                        - name: "fetch_webpage"
                          arguments:
                            url: "https://example.com"
                  assets: []
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Agent
      summary: Aktualizuj konwersację
      description: |
        Aktualizuje tytuł, status lub metadane konwersacji.

        Dozwolone statusy: `active`, `archived`, `closed`.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID konwersacji
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  maxLength: 255
                  nullable: true
                  description: Nowy tytuł konwersacji
                  example: "Zaktualizowany tytuł"
                status:
                  type: string
                  enum: [active, archived, closed]
                  nullable: true
                  example: "archived"
                metadata:
                  type: object
                  nullable: true
                  description: Dowolne metadane konwersacji
      responses:
        '200':
          description: Konwersacja zaktualizowana
          content:
            application/json:
              example:
                success: true
                data:
                  id: 42
                  title: "Zaktualizowany tytuł"
                  status: "archived"
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Agent
      summary: Usuń konwersację
      description: |
        Usuwa konwersację wraz ze wszystkimi wiadomościami.

        **UWAGA:** Ta operacja jest nieodwracalna!
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID konwersacji
          schema:
            type: integer
      responses:
        '204':
          description: Konwersacja usunięta
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /agent/conversations/{id}/truncate:
    post:
      tags:
        - Agent
      summary: Przytnij wiadomości konwersacji
      description: |
        Usuwa wiadomości od podanego indeksu w górę.
        Używane do cofania historii konwersacji (np. po błędnej odpowiedzi agenta).

        Indeks jest 0-based — `from_index: 5` usunie wiadomości od 5. pozycji do końca.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID konwersacji
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - from_index
              properties:
                from_index:
                  type: integer
                  minimum: 0
                  description: Indeks od którego usunąć wiadomości (0-based)
                  example: 5
      responses:
        '200':
          description: Wiadomości przycięte
          content:
            application/json:
              example:
                success: true
                data:
                  messages_count: 5
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

  /agent/conversations/{id}/inspector:
    get:
      tags:
        - Agent
      summary: Dane inspektora narzędzi
      description: |
        Zwraca tool_calls z wiadomości asystenta w konwersacji.
        Używane do debugowania i podglądu wywołań narzędzi agenta.

        Filtruje wiadomości — zwraca tylko te z roli `assistant` zawierające `tool_calls`.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID konwersacji
          schema:
            type: integer
      responses:
        '200':
          description: Dane inspektora
          content:
            application/json:
              example:
                success: true
                data:
                  conversation_id: 42
                  entries:
                    - role: "assistant"
                      content: "Pobieram stronę..."
                      tool_calls:
                        - name: "fetch_webpage"
                          arguments:
                            url: "https://example.com"
                    - role: "assistant"
                      content: null
                      tool_calls:
                        - name: "generate_content"
                          arguments:
                            prompt: "Napisz podsumowanie"
        '404':
          $ref: '#/components/responses/NotFound'

  /agent/chat:
    post:
      tags:
        - Agent
      summary: Uproszczony chat z agentem
      description: |
        Uproszczony endpoint — automatycznie tworzy konwersację jeśli nie podano `conversation_id`.

        Zwraca `job_id` do śledzenia statusu odpowiedzi (asynchronicznie przez WebSocket
        lub polling GET `/agent/job-status/{jobId}`).

        Rate limit: 20 żądań/minutę per workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - message
              properties:
                message:
                  type: string
                  maxLength: 50000
                  description: Wiadomość do agenta
                  example: "Przeanalizuj stronę anthropic.com"
                agent:
                  type: string
                  nullable: true
                  description: Slug agenta (np. site_auditor, general_assistant, page_generator)
                  example: "site_auditor"
                conversation_id:
                  type: integer
                  nullable: true
                  description: ID istniejącej konwersacji (kontynuacja)
                  example: 42
                model:
                  type: string
                  nullable: true
                  description: Override modelu AI
                image_model:
                  type: string
                  nullable: true
                  description: Override modelu do generowania obrazów
      responses:
        '200':
          description: Job uruchomiony
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          job_id:
                            type: string
                            format: uuid
                          conversation_id:
                            type: integer
                          status:
                            type: string
                            enum: [pending]
                          message:
                            type: string
              example:
                success: true
                data:
                  job_id: "550e8400-e29b-41d4-a716-446655440000"
                  conversation_id: 43
                  status: "pending"
                  message: "Job uruchomiony. Sprawdź status: GET /api/v1/jobs/agent/550e8400.../status"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          description: Job już jest w trakcie przetwarzania
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "Job już jest w trakcie przetwarzania."
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          description: Zbyt wiele zapytań (rate limit)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "Zbyt wiele zapytań. Spróbuj za 30 sekund."

  /agent/conversations/{id}/message:
    post:
      tags:
        - Agent
      summary: Wyślij wiadomość do agenta
      description: |
        Wysyła wiadomość do istniejącej konwersacji.
        Uruchamia asynchroniczny job przetwarzający wiadomość.

        Zwraca `job_id` do śledzenia statusu odpowiedzi.

        Rate limit: 20 żądań/minutę per workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID konwersacji
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - message
              properties:
                message:
                  type: string
                  maxLength: 50000
                  description: Treść wiadomości do agenta
                  example: "Podaj więcej szczegółów o SEO tej strony"
                agent_definition_id:
                  type: integer
                  nullable: true
                  description: Override ID definicji agenta
      responses:
        '200':
          description: Wiadomość wysłana, job uruchomiony
          content:
            application/json:
              example:
                success: true
                data:
                  job_id: "550e8400-e29b-41d4-a716-446655440000"
                  status: "pending"
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          description: Job już jest w trakcie przetwarzania
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          description: Zbyt wiele zapytań (rate limit)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /agent/job-status/{jobId}:
    get:
      tags:
        - Agent
      summary: Sprawdź status zadania agenta
      description: |
        Sprawdza status asynchronicznego zadania agenta.

        Statusy: `pending`, `processing`, `completed`, `failed`.

        Wynik dostępny w polu `result` po zakończeniu.
      parameters:
        - name: jobId
          in: path
          required: true
          description: UUID zadania
          schema:
            type: string
            format: uuid
          example: "550e8400-e29b-41d4-a716-446655440000"
      responses:
        '200':
          description: Status zadania
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/AgentJobStatus'
              examples:
                completed:
                  summary: Zadanie zakończone
                  value:
                    success: true
                    data:
                      job_id: "550e8400-e29b-41d4-a716-446655440000"
                      status: "completed"
                      progress: 100
                      result:
                        response: "Analiza strony zakończona..."
                      error: null
                processing:
                  summary: Zadanie w trakcie
                  value:
                    success: true
                    data:
                      job_id: "550e8400-e29b-41d4-a716-446655440000"
                      status: "processing"
                      progress: 45
                      result: null
                      error: null
        '404':
          description: Zadanie nie istnieje lub wygasło
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "Job nie istnieje lub wygasł"

  # ==========================================================================
  # TEMPLATE ENDPOINTS
  # ==========================================================================
  /templates:
    get:
      tags:
        - Templates
      summary: Lista szablonów
      description: |
        Zwraca listę szablonów w bieżącym projekcie/workspace.

        Wspiera filtrowanie po typie i wyszukiwanie po nazwie.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/ProjectHeader'
        - name: type
          in: query
          description: Filtruj po typie szablonu
          schema:
            type: string
            example: "ad"
        - name: search
          in: query
          description: Szukaj po nazwie szablonu
          schema:
            type: string
            example: "banner"
      responses:
        '200':
          description: Lista szablonów
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Template'
              example:
                success: true
                data:
                  - id: 1
                    name: "Banner reklamowy"
                    code: "banner_reklamowy"
                    description: "Szablon dla banerów reklamowych"
                    type: "ad"
                    is_active: true
                    created_at: "2024-01-15T10:00:00Z"
                  - id: 2
                    name: "Post na social media"
                    code: "social_media_post"
                    type: "text"
                    is_active: true
                    created_at: "2024-02-01T14:00:00Z"
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      operationId: createTemplate
      tags:
        - Templates
      summary: Utwórz szablon
      description: |
        Tworzy nowy szablon z definicją schematu pól.

        Szablon definiuje strukturę formularza (pola, typy, walidacja)
        używaną do tworzenia elementów Drive.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/ProjectHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TemplateCreate'
            example:
              name: "Banner reklamowy"
              code: "banner_reklamowy"
              description: "Szablon dla banerów reklamowych"
              type: "ad"
              button_name: "Utwórz banner"
              button_icon: "🖼️"
              schema_definition:
                fields:
                  - type: "text"
                    label: "Nagłówek"
                    placeholder: "Wpisz nagłówek..."
                    required: true
                    ai_enabled: true
                    ai_system_prompt: "Napisz chwytliwy nagłówek reklamowy"
                  - type: "textarea"
                    label: "Opis"
                    placeholder: "Treść reklamy..."
                    limit: 500
                  - type: "image"
                    label: "Tło"
                    required: true
                show_assets: true
      responses:
        '201':
          description: Szablon utworzony
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Template'
              example:
                success: true
                data:
                  id: 5
                  name: "Banner reklamowy"
                  code: "banner_reklamowy"
                  type: "ad"
                message: "Szablon utworzony"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /templates/{id}:
    get:
      tags:
        - Templates
      summary: Szczegóły szablonu
      description: Zwraca pełne dane szablonu wraz z definicją schematu i polami
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID szablonu
          schema:
            type: integer
          example: 1
      responses:
        '200':
          description: Dane szablonu
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Template'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Templates
      summary: Aktualizuj szablon
      description: |
        Aktualizuje dane szablonu. Wszystkie pola są opcjonalne.

        Zmiana `schema_definition` nadpisuje całą definicję schematu.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID szablonu
          schema:
            type: integer
          example: 1
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 2
                  maxLength: 255
                code:
                  type: string
                  minLength: 2
                  maxLength: 100
                  pattern: "^[a-z0-9_]+$"
                description:
                  type: string
                  nullable: true
                  maxLength: 2000
                type:
                  type: string
                  nullable: true
                  maxLength: 100
                button_name:
                  type: string
                  nullable: true
                  maxLength: 100
                button_icon:
                  type: string
                  nullable: true
                  maxLength: 10
                schema_definition:
                  type: object
                  nullable: true
                is_active:
                  type: boolean
                show_in_types:
                  type: boolean
            example:
              name: "Banner reklamowy v2"
              description: "Zaktualizowany szablon banerów"
      responses:
        '200':
          description: Szablon zaktualizowany
          content:
            application/json:
              example:
                success: true
                data:
                  id: 5
                  name: "Banner reklamowy v2"
                  code: "banner_reklamowy"
                message: "Szablon zaktualizowany"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Templates
      summary: Usuń szablon
      description: |
        Soft-delete szablonu. Można przywrócić przez POST `/templates/{id}/restore`.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID szablonu
          schema:
            type: integer
          example: 1
      responses:
        '204':
          description: Szablon usunięty
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /templates/{id}/restore:
    post:
      tags:
        - Templates
      summary: Przywróć usunięty szablon
      description: Przywraca soft-deleted szablon
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID szablonu
          schema:
            type: integer
      responses:
        '200':
          description: Szablon przywrócony
          content:
            application/json:
              example:
                success: true
                data:
                  id: 5
                  name: "Banner reklamowy"
                message: "Szablon przywrócony"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /templates/{id}/duplicate:
    post:
      tags:
        - Templates
      summary: Duplikuj szablon
      description: Tworzy kopię szablonu z automatycznie wygenerowaną nazwą i kodem
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID szablonu do zduplikowania
          schema:
            type: integer
      responses:
        '201':
          description: Szablon zduplikowany
          content:
            application/json:
              example:
                success: true
                data:
                  id: 6
                  name: "Banner reklamowy (kopia)"
                  code: "banner_reklamowy_copy"
                message: "Szablon zduplikowany"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # WEBSITE PAGE ENDPOINTS
  # ==========================================================================
  /website/pages/{id}:
    get:
      tags:
        - Website Pages
      summary: Szczegóły strony
      description: |
        Zwraca dane strony wraz z HTML i wyekstrahowanymi sekcjami.

        Sekcje są rozpoznawane na podstawie atrybutów `data-section` i `data-id` w HTML.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID strony
          schema:
            type: integer
      responses:
        '200':
          description: Dane strony z sekcjami
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/WebsitePage'
              example:
                success: true
                data:
                  id: 1
                  name: "Strona główna"
                  slug: "strona-glowna"
                  html: "<section data-section='hero'>...</section>"
                  sections:
                    - id: "hero"
                      type: "hero"
                      html: "<h1>Witaj</h1><p>Opis...</p>"
                    - id: "features"
                      type: "features"
                      html: "<div class='grid'>...</div>"
                  show_in_menu: true
                  order: 0
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Website Pages
      summary: Aktualizuj stronę
      description: |
        Aktualizuje metadane strony: nazwę, slug, tagi meta (title, description),
        widoczność w menu i kolejność.

        Wszystkie pola są opcjonalne.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID strony
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 255
                  nullable: true
                  example: "Strona główna"
                title:
                  type: string
                  maxLength: 255
                  nullable: true
                  description: Meta tag title
                  example: "Strona główna - Moja Firma"
                description:
                  type: string
                  maxLength: 500
                  nullable: true
                  description: Meta tag description
                  example: "Opis strony dla SEO"
                slug:
                  type: string
                  maxLength: 100
                  nullable: true
                  example: "strona-glowna"
                show_in_menu:
                  type: boolean
                  nullable: true
                order:
                  type: integer
                  nullable: true
      responses:
        '200':
          description: Strona zaktualizowana
          content:
            application/json:
              example:
                success: true
                data:
                  id: 1
                  name: "Strona główna"
                  slug: "strona-glowna"
                message: "Page updated"
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Website Pages
      summary: Usuń stronę
      description: Usuwa stronę z projektu website
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID strony
          schema:
            type: integer
      responses:
        '204':
          description: Strona usunięta
        '404':
          $ref: '#/components/responses/NotFound'

  /website/{projectId}/pages:
    post:
      tags:
        - Website Pages
      summary: Utwórz nową stronę
      description: Dodaje nową stronę do projektu website
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: projectId
          in: path
          required: true
          description: ID projektu website
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: "O nas"
                slug:
                  type: string
                  maxLength: 100
                  nullable: true
                  example: "o-nas"
                html:
                  type: string
                  nullable: true
                  description: Początkowy HTML strony
                  example: "<section><h1>O nas</h1></section>"
      responses:
        '201':
          description: Strona utworzona
          content:
            application/json:
              example:
                success: true
                data:
                  id: 5
                  name: "O nas"
                  slug: "o-nas"
                message: "Page created"
        '404':
          description: Projekt nie znaleziony
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "Website project not found"
        '422':
          $ref: '#/components/responses/ValidationError'

  # ==========================================================================
  # PIPELINE ENDPOINTS
  # ==========================================================================
  /pipelines:
    get:
      tags:
        - Pipelines
      summary: Lista pipeline'ów
      description: |
        Zwraca listę pipeline'ów w bieżącym projekcie.

        Pipeline to wizualny workflow składający się z node'ów (węzłów)
        połączonych edge'ami (krawędziami).
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Lista pipeline'ów
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: '#/components/schemas/Pipeline'
              example:
                success: true
                data:
                  - id: 1
                    name: "Generowanie kampanii"
                    description: "Pipeline do automatycznego generowania materiałów"
                    nodes: []
                    edges: []
                    created_at: "2024-01-15T10:00:00Z"
                  - id: 2
                    name: "Analiza konkurencji"
                    description: null
                    created_at: "2024-02-01T14:00:00Z"
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Pipelines
      summary: Utwórz pipeline
      description: |
        Tworzy nowy pipeline z opcjonalnymi node'ami i edge'ami.

        Nazwa musi być unikalna w ramach projektu.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PipelineCreate'
            example:
              name: "Nowy pipeline"
              description: "Workflow do generowania treści"
              nodes:
                - id: "node_1"
                  type: "prompt"
                  position:
                    x: 100
                    y: 100
                  data:
                    prompt: "Napisz tekst reklamowy dla {{product}}"
                - id: "node_2"
                  type: "ai_text"
                  position:
                    x: 400
                    y: 100
                  data:
                    model: "gemini-3-pro-preview"
              edges:
                - id: "edge_1"
                  source: "node_1"
                  target: "node_2"
                  sourceHandle: "prompt"
                  targetHandle: "input"
      responses:
        '201':
          description: Pipeline utworzony
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Pipeline'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /pipelines/{pipeline}:
    get:
      tags:
        - Pipelines
      summary: Szczegóły pipeline
      description: Zwraca pełne dane pipeline z node'ami, edge'ami i viewportem
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: pipeline
          in: path
          required: true
          description: ID pipeline
          schema:
            type: integer
      responses:
        '200':
          description: Dane pipeline
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Pipeline'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Pipelines
      summary: Aktualizuj pipeline
      description: |
        Aktualizuje dane pipeline. Wszystkie pola są opcjonalne.

        Jeśli podano `nodes`, `edges` lub `viewport`, nadpisują one istniejące dane.
        Jeśli nie podano — pozostają bez zmian.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: pipeline
          in: path
          required: true
          description: ID pipeline
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 255
                description:
                  type: string
                  nullable: true
                  maxLength: 2000
                nodes:
                  type: array
                  items:
                    $ref: '#/components/schemas/PipelineNode'
                edges:
                  type: array
                  items:
                    $ref: '#/components/schemas/PipelineEdge'
                viewport:
                  type: object
                  properties:
                    x:
                      type: number
                    y:
                      type: number
                    zoom:
                      type: number
            example:
              name: "Zaktualizowany pipeline"
              description: "Nowy opis"
      responses:
        '200':
          description: Pipeline zaktualizowany
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/SuccessResponse'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/Pipeline'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Pipelines
      summary: Usuń pipeline
      description: |
        Usuwa pipeline wraz ze wszystkimi node'ami i edge'ami.

        **UWAGA:** Ta operacja jest nieodwracalna!
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: pipeline
          in: path
          required: true
          description: ID pipeline
          schema:
            type: integer
      responses:
        '204':
          description: Pipeline usunięty
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /pipelines/node-definitions:
    get:
      tags:
        - Pipelines
      summary: Definicje typów node'ów
      description: |
        Zwraca metadane wszystkich dostępnych typów node'ów: inputs/outputs,
        kategorie, kolory, ikony, flagi.

        Używane przez frontend Flow Editor do konfiguracji palety node'ów.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Definicje node'ów
          content:
            application/json:
              example:
                success: true
                data:
                  - type: "prompt"
                    label: "Prompt"
                    category: "input"
                    color: "#4CAF50"
                    icon: "chat"
                    inputs: []
                    outputs:
                      - handle: "prompt"
                        type: "string"
                  - type: "ai_text"
                    label: "AI Text"
                    category: "ai"
                    color: "#2196F3"
                    inputs:
                      - handle: "input"
                        type: "string"
                    outputs:
                      - handle: "text"
                        type: "string"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /pipelines/as-tools:
    get:
      tags:
        - Pipelines
      summary: Lista pipeline'ów jako narzędzia
      description: |
        Zwraca pipeline'y w formacie narzędzi dla agenta AI z ich inputami.

        Używane do dynamicznego udostępniania pipeline'ów jako narzędzi agentowi.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Lista pipeline'ów jako narzędzia
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 1
                    name: "Generowanie kampanii"
                    description: "Generuje materiały kampanii reklamowej"
                    inputs:
                      - name: "product"
                        type: "string"
                        required: true
                      - name: "target_audience"
                        type: "string"
                        required: false
        '401':
          $ref: '#/components/responses/Unauthorized'

  /pipelines/execute:
    post:
      tags:
        - Pipelines
      summary: Uruchom pipeline
      description: |
        Uruchamia pipeline po ID lub nazwie.

        Tryby:
        - **Asynchroniczny** (domyślny): zwraca `execution_id` do sprawdzania statusu
        - **Synchroniczny** (`sync: true`): czeka na wynik (max `timeout` sekund, domyślnie 60)

        Rate limit: 20 żądań/minutę per workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                id:
                  type: integer
                  nullable: true
                  description: ID pipeline (opcjonalne jeśli podano name)
                  example: 1
                name:
                  type: string
                  nullable: true
                  description: Nazwa pipeline (opcjonalne jeśli podano id)
                  example: "Generowanie kampanii"
                inputs:
                  type: object
                  description: Inputy dla workflow (klucz-wartość)
                  additionalProperties: true
                  example:
                    product: "Smartwatch XYZ"
                    target_audience: "Młodzi profesjonaliści"
                sync:
                  type: boolean
                  default: false
                  description: Czekaj na wynik synchronicznie
                timeout:
                  type: integer
                  minimum: 1
                  maximum: 120
                  default: 60
                  description: Timeout w sekundach (tylko dla sync=true)
      responses:
        '200':
          description: Workflow uruchomiony lub wykonany
          content:
            application/json:
              examples:
                async:
                  summary: Uruchomienie asynchroniczne
                  value:
                    success: true
                    data:
                      execution_id: "exec_550e8400"
                      status: "pending"
                      message: "Pipeline started"
                sync:
                  summary: Wykonanie synchroniczne
                  value:
                    success: true
                    data:
                      execution_id: "exec_550e8400"
                      status: "completed"
                      results:
                        node_1:
                          _meta:
                            nodeType: "prompt"
                            success: true
                          data:
                            prompt:
                              value: "Tekst prompta..."
                        node_2:
                          _meta:
                            nodeType: "ai_text"
                            success: true
                          data:
                            text:
                              value: "Wygenerowany tekst reklamowy..."
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Pipeline nie znaleziony
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: Pipeline już jest w trakcie wykonywania
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          description: Zbyt wiele zapytań (rate limit)

  /pipelines/workflow-status/{executionId}:
    get:
      tags:
        - Pipelines
      summary: Status wykonania workflow
      description: Sprawdza status asynchronicznego wykonania pipeline
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: executionId
          in: path
          required: true
          description: ID wykonania workflow
          schema:
            type: string
          example: "exec_550e8400"
      responses:
        '200':
          description: Status wykonania
          content:
            application/json:
              examples:
                running:
                  summary: W trakcie
                  value:
                    success: true
                    data:
                      execution_id: "exec_550e8400"
                      status: "processing"
                      completed_nodes: 2
                      total_nodes: 5
                      current_node: "node_3"
                completed:
                  summary: Zakończone
                  value:
                    success: true
                    data:
                      execution_id: "exec_550e8400"
                      status: "completed"
                      completed_nodes: 5
                      total_nodes: 5
                      results:
                        node_5:
                          _meta:
                            nodeType: "output"
                            success: true
                          data:
                            result:
                              value: "Finalny wynik pipeline..."
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # DRIVE ASSETS ENDPOINTS
  # ==========================================================================
  /drive/{id}/with-assets:
    get:
      tags:
        - Drive Assets
      summary: Element z assetami
      description: Zwraca element Drive wraz z powiązanymi assetami (obrazy, pliki kontekstowe)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID elementu Drive
          schema:
            type: integer
      responses:
        '200':
          description: Element z assetami
          content:
            application/json:
              example:
                success: true
                data:
                  item:
                    id: 123
                    name: "Kampania Q1"
                    type: "ad"
                  assets:
                    - id: 10
                      name: "Logo.png"
                      type: "image"
                      file_url: "https://storage.example.com/logo.png"
                    - id: 11
                      name: "Brief.txt"
                      type: "text"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/{id}/assets:
    get:
      tags:
        - Drive Assets
      summary: Lista assetów elementu
      description: Zwraca listę assetów powiązanych z elementem Drive
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID elementu Drive
          schema:
            type: integer
      responses:
        '200':
          description: Lista assetów
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 10
                    name: "Logo.png"
                    type: "image"
                  - id: 11
                    name: "Brief.txt"
                    type: "text"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/{id}/assets/sync:
    post:
      tags:
        - Drive Assets
      summary: Synchronizuj assety
      description: |
        Synchronizuje assety elementu — ustawia dokładnie te assety,
        które podano w tablicy `asset_ids`. Usunie niepodane i doda nowe.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          description: ID elementu Drive
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                asset_ids:
                  type: array
                  items:
                    type: integer
                  example: [10, 11, 15]
      responses:
        '200':
          description: Assety zsynchronizowane
          content:
            application/json:
              example:
                success: true
                data:
                  synced_count: 3
                message: "Assety zsynchronizowane"
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/{itemId}/assets/{assetId}:
    delete:
      tags:
        - Drive Assets
      summary: Odłącz asset od elementu
      description: Usuwa powiązanie assetu z elementem (nie kasuje samego assetu)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: itemId
          in: path
          required: true
          description: ID elementu Drive
          schema:
            type: integer
        - name: assetId
          in: path
          required: true
          description: ID assetu do odłączenia
          schema:
            type: integer
      responses:
        '200':
          description: Asset odłączony
          content:
            application/json:
              example:
                success: true
                message: "Asset odłączony"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/assets-for-picker:
    get:
      tags:
        - Drive Assets
      summary: Assety dla pickera
      description: |
        Zwraca listę assetów do wyświetlenia w asset picker modal.
        Filtruje elementy odpowiednie do użycia jako assety kontekstowe.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Lista assetów
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 10
                    name: "Logo.png"
                    type: "image"
                    thumbnail_url: "https://storage.example.com/thumb/logo.png"
                  - id: 11
                    name: "Brand guidelines"
                    type: "text"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /drive/items-by-ids:
    post:
      tags:
        - Drive Assets
      summary: Pobierz elementy po ID
      description: Zwraca elementy Drive o podanych ID. Przydatne do batch-owego pobierania danych.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ids
              properties:
                ids:
                  type: array
                  items:
                    type: integer
                  example: [10, 11, 15, 23]
      responses:
        '200':
          description: Lista elementów
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 10
                    name: "Logo.png"
                    type: "image"
                  - id: 11
                    name: "Brief.txt"
                    type: "text"
                  - id: 15
                    name: "Folder kampanii"
                    type: "folder"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /drive/stats:
    get:
      tags:
        - Drive
      summary: Statystyki elementów Drive
      description: Zwraca liczbę elementów pogrupowanych po typie dla bieżącego projektu
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Statystyki
          content:
            application/json:
              example:
                success: true
                data:
                  image: 45
                  text: 23
                  landing_page: 5
                  folder: 12
                  prompt: 8
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ==========================================================================
  # DRIVE BATCH OPERATIONS
  # ==========================================================================
  /drive/delete-many:
    post:
      tags:
        - Drive Batch
      operationId: driveBatchDeleteMany
      summary: Usuń wiele elementów
      description: |
        Przenosi wiele elementów do kosza (soft delete) w jednej operacji.

        Rate limit: drive-batch
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ids
              properties:
                ids:
                  type: array
                  items:
                    type: integer
                  example: [10, 11, 15]
      responses:
        '204':
          description: Elementy usunięte (przeniesione do kosza)
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/move-many:
    post:
      tags:
        - Drive Batch
      operationId: driveBatchMoveMany
      summary: Przenieś wiele elementów
      description: |
        Przenosi wiele elementów do wskazanego folderu docelowego.
        `parent_id: null` przenosi do roota.

        Rate limit: drive-batch
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ids
              properties:
                ids:
                  type: array
                  items:
                    type: integer
                  example: [10, 11, 15]
                parent_id:
                  type: integer
                  nullable: true
                  description: ID folderu docelowego (null = root)
                  example: 5
      responses:
        '200':
          description: Elementy przeniesione
          content:
            application/json:
              example:
                success: true
                data:
                  moved_count: 3
                message: "Przeniesiono 3 elementów"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/copy-many:
    post:
      tags:
        - Drive Batch
      operationId: driveBatchCopyMany
      summary: Kopiuj wiele elementów
      description: |
        Tworzy kopie wielu elementów w docelowym folderze.
        Zwraca listę nowo utworzonych elementów.

        Rate limit: drive-batch
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ids
              properties:
                ids:
                  type: array
                  items:
                    type: integer
                  example: [10, 11]
                parent_id:
                  type: integer
                  nullable: true
                  description: ID folderu docelowego (null = ten sam folder)
      responses:
        '201':
          description: Elementy skopiowane
          content:
            application/json:
              example:
                success: true
                data:
                  copied_count: 2
                  items:
                    - id: 50
                      name: "Logo (kopia)"
                    - id: 51
                      name: "Brief (kopia)"
                message: "Skopiowano 2 elementów"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/duplicate-many:
    post:
      tags:
        - Drive Batch
      operationId: driveBatchDuplicateMany
      summary: Duplikuj wiele elementów
      description: |
        Tworzy duplikaty wielu elementów (w tym samym folderze).
        Zwraca listę nowych ID.

        Rate limit: drive-batch
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ids
              properties:
                ids:
                  type: array
                  items:
                    type: integer
                  example: [10, 11]
                parent_id:
                  type: integer
                  nullable: true
      responses:
        '201':
          description: Elementy zduplikowane
          content:
            application/json:
              example:
                success: true
                data:
                  ids: [50, 51]
                  count: 2
                message: "Zduplikowano 2 elementów"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/{item}/move:
    post:
      tags:
        - Drive Batch
      operationId: driveMoveItem
      summary: Przenieś pojedynczy element
      description: Przenosi element do innego folderu z opcjonalną kolejnością
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: item
          in: path
          required: true
          description: ID elementu do przeniesienia
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                parent_id:
                  type: integer
                  nullable: true
                  description: ID folderu docelowego (null = root)
                order:
                  type: integer
                  nullable: true
                  description: Kolejność w folderze docelowym
      responses:
        '200':
          description: Element przeniesiony
          content:
            application/json:
              example:
                success: true
                data:
                  id: 10
                  parent_id: 5
                  order: 0
                message: "Element przeniesiony"
        '400':
          description: Nie można przenieść (np. do własnego podfolderu)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/{item}/duplicate:
    post:
      tags:
        - Drive Batch
      operationId: driveDuplicateItem
      summary: Duplikuj element
      description: Tworzy kopię elementu z automatycznie wygenerowaną nazwą
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: item
          in: path
          required: true
          description: ID elementu do zduplikowania
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                parent_id:
                  type: integer
                  nullable: true
                  description: ID folderu docelowego (null = ten sam folder)
      responses:
        '201':
          description: Element zduplikowany
          content:
            application/json:
              example:
                success: true
                data:
                  id: 50
                  name: "Kampania Q1 (kopia)"
                  type: "ad"
                message: "Element zduplikowany"
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # DRIVE FOLDER OPERATIONS
  # ==========================================================================
  /drive/folder/{folderId}:
    get:
      tags:
        - Drive Folders
      operationId: driveFolderContents
      summary: Zawartość folderu
      description: |
        Zwraca zawartość folderu (elementy) oraz breadcrumbs.
        Bez `folderId` zwraca root.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: false
          description: ID folderu (pominięcie = root)
          schema:
            type: integer
      responses:
        '200':
          description: Zawartość folderu z breadcrumbs
          content:
            application/json:
              example:
                success: true
                data:
                  folder_id: 5
                  breadcrumbs:
                    - id: 1
                      name: "Kampanie"
                      type: "folder"
                    - id: 5
                      name: "Q1 2024"
                      type: "folder"
                  items:
                    - id: 10
                      name: "Banner.jpg"
                      type: "image"
                    - id: 11
                      name: "Brief.txt"
                      type: "text"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/breadcrumbs/{folderId}:
    get:
      tags:
        - Drive Folders
      operationId: driveBreadcrumbs
      summary: Breadcrumbs dla folderu
      description: Zwraca tablicę breadcrumbs od roota do podanego folderu
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          description: ID folderu
          schema:
            type: integer
      responses:
        '200':
          description: Tablica breadcrumbs
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 1
                    name: "Kampanie"
                    type: "folder"
                  - id: 5
                    name: "Q1 2024"
                    type: "folder"
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # DRIVE SHARE & PUBLISH
  # ==========================================================================
  /drive/{item}/share:
    get:
      tags:
        - Drive Share
      operationId: driveGetShare
      summary: Pobierz ustawienia udostępniania
      description: Zwraca aktualny tryb udostępniania i listę uprawnionych e-maili
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: item
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Ustawienia udostępniania
          content:
            application/json:
              example:
                success: true
                data:
                  share_mode: "private"
                  share_emails: []
                  is_published: false
                  public_token: null
                  public_url: null
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Drive Share
      operationId: driveUpdateShare
      summary: Aktualizuj ustawienia udostępniania
      description: |
        Zmiana trybu udostępniania elementu.

        Tryby: `private`, `specific_emails`, `workspace`, `public`
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: item
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                share_mode:
                  type: string
                  enum: [private, specific_emails, workspace, public]
                  example: "specific_emails"
                share_emails:
                  type: array
                  items:
                    type: string
                    format: email
                  example: ["jan@example.com", "anna@example.com"]
      responses:
        '200':
          description: Ustawienia zaktualizowane
          content:
            application/json:
              example:
                success: true
                data:
                  share_mode: "specific_emails"
                  share_emails: ["jan@example.com", "anna@example.com"]
                message: "Ustawienia udostepniania zaktualizowane"
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/{item}/toggle-publish:
    post:
      tags:
        - Drive Share
      operationId: driveTogglePublish
      summary: Przełącz publikację
      description: |
        Przełącza status publikacji elementu.
        Opublikowany element jest dostępny po publicznym linku (public_token).
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: item
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Status publikacji zmieniony
          content:
            application/json:
              examples:
                published:
                  summary: Element opublikowany
                  value:
                    success: true
                    data:
                      is_published: true
                      public_token: "abc123xyz"
                      public_url: "https://app.example.com/public/abc123xyz"
                    message: "Opublikowano"
                unpublished:
                  summary: Element wycofany
                  value:
                    success: true
                    data:
                      is_published: false
                      public_token: null
                      public_url: null
                    message: "Wycofano z publikacji"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/access-requests:
    get:
      tags:
        - Drive Share
      operationId: driveAccessRequests
      summary: Lista oczekujących próśb o dostęp
      description: Zwraca listę próśb o dostęp do elementów w bieżącym projekcie
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Lista próśb o dostęp
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 1
                    user:
                      id: 5
                      name: "Jan Kowalski"
                      email: "jan@example.com"
                    knowledge_item:
                      id: 10
                      name: "Kampania Q1"
                    created_at: "2024-03-15T10:00:00Z"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /drive/access-requests/{requestId}/approve:
    post:
      tags:
        - Drive Share
      operationId: driveApproveAccess
      summary: Zatwierdź prośbę o dostęp
      description: Nadaje użytkownikowi dostęp do żądanego elementu
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: requestId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Dostęp zatwierdzony
          content:
            application/json:
              example:
                success: true
                message: "Dostep zatwierdzony"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/access-requests/{requestId}/reject:
    post:
      tags:
        - Drive Share
      operationId: driveRejectAccess
      summary: Odrzuć prośbę o dostęp
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: requestId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Dostęp odrzucony
          content:
            application/json:
              example:
                success: true
                message: "Dostep odrzucony"
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # DRIVE TRASH OPERATIONS
  # ==========================================================================
  /drive/trash:
    get:
      tags:
        - Drive Trash
      operationId: driveTrashList
      summary: Lista elementów w koszu
      description: Zwraca listę soft-deleted elementów w bieżącym projekcie
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Lista elementów w koszu
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 20
                    name: "Stary banner"
                    type: "image"
                    deleted_at: "2024-03-10T08:00:00Z"
                    file_path: "drive/images/old-banner.jpg"
                  - id: 21
                    name: "Szkic kampanii"
                    type: "text"
                    deleted_at: "2024-03-12T14:00:00Z"
                    file_path: null
        '401':
          $ref: '#/components/responses/Unauthorized'

  /drive/trash/{item}/restore:
    post:
      tags:
        - Drive Trash
      operationId: driveTrashRestore
      summary: Przywróć element z kosza
      description: Przywraca soft-deleted element do jego oryginalnej lokalizacji
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: item
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Element przywrócony
          content:
            application/json:
              example:
                success: true
                message: "Item restored"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/trash/restore-all:
    post:
      tags:
        - Drive Trash
      operationId: driveTrashRestoreAll
      summary: Przywróć wszystkie z kosza
      description: Przywraca wszystkie elementy z kosza w bieżącym projekcie
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Wszystkie elementy przywrócone
          content:
            application/json:
              example:
                success: true
                message: "All items restored"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /drive/trash/{item}/force:
    delete:
      tags:
        - Drive Trash
      operationId: driveTrashForceDelete
      summary: Trwale usuń element
      description: |
        Trwale usuwa element z kosza.

        **UWAGA:** Ta operacja jest nieodwracalna!
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: item
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: Element trwale usunięty
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/trash/empty:
    delete:
      tags:
        - Drive Trash
      operationId: driveTrashEmpty
      summary: Opróżnij kosz
      description: |
        Trwale usuwa wszystkie elementy z kosza w bieżącym projekcie.

        **UWAGA:** Ta operacja jest nieodwracalna!
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '204':
          description: Kosz opróżniony
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ==========================================================================
  # DRIVE COLLECTIONS
  # ==========================================================================
  /drive/collections:
    get:
      tags:
        - Drive Collections
      operationId: driveCollectionsList
      summary: Lista kolekcji
      description: Zwraca wszystkie kolekcje w bieżącym projekcie
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Lista kolekcji
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 1
                    name: "Materiały kampanii Q1"
                    items_count: 12
                    created_at: "2024-01-15T10:00:00Z"
                  - id: 2
                    name: "Brand assets"
                    items_count: 5
                    created_at: "2024-02-01T14:00:00Z"
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Drive Collections
      operationId: driveCollectionsCreate
      summary: Utwórz kolekcję
      description: Tworzy nową kolekcję w bieżącym projekcie
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  maxLength: 255
                  example: "Nowa kolekcja"
      responses:
        '201':
          description: Kolekcja utworzona
          content:
            application/json:
              example:
                success: true
                data:
                  id: 3
                  name: "Nowa kolekcja"
                message: "Kolekcja utworzona"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/collections/{id}:
    get:
      tags:
        - Drive Collections
      operationId: driveCollectionsShow
      summary: Szczegóły kolekcji
      description: Zwraca kolekcję z listą powiązanych elementów
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Dane kolekcji z elementami
          content:
            application/json:
              example:
                success: true
                data:
                  id: 1
                  name: "Materiały kampanii Q1"
                  items:
                    - id: 10
                      name: "Logo.png"
                      type: "image"
                    - id: 11
                      name: "Brief.txt"
                      type: "text"
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Drive Collections
      operationId: driveCollectionsDelete
      summary: Usuń kolekcję
      description: Usuwa kolekcję (nie usuwa elementów z kolekcji)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: Kolekcja usunięta
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/collections/{id}/items:
    post:
      tags:
        - Drive Collections
      operationId: driveCollectionsAddItems
      summary: Dodaj elementy do kolekcji
      description: Dodaje wiele elementów Drive do kolekcji
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - item_ids
              properties:
                item_ids:
                  type: array
                  items:
                    type: integer
                  example: [10, 11, 15]
      responses:
        '200':
          description: Elementy dodane do kolekcji
          content:
            application/json:
              example:
                success: true
                message: "Elementy dodane do kolekcji"
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Drive Collections
      operationId: driveCollectionsRemoveItems
      summary: Usuń elementy z kolekcji
      description: Usuwa powiązanie elementów z kolekcją (nie usuwa elementów)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - item_ids
              properties:
                item_ids:
                  type: array
                  items:
                    type: integer
                  example: [10, 11]
      responses:
        '200':
          description: Elementy usunięte z kolekcji
          content:
            application/json:
              example:
                success: true
                message: "Elementy usunięte z kolekcji"
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # DRIVE UPLOAD
  # ==========================================================================
  /drive/upload:
    post:
      tags:
        - Drive Upload
      operationId: driveUpload
      summary: Upload pliku
      description: |
        Wgrywa plik do Drive. Automatycznie wykrywa typ na podstawie MIME.

        Rate limit: 30 żądań/minutę per workspace

        Dozwolone typy: obrazy (JPEG, PNG, GIF, WebP), dokumenty (PDF, Word, Excel),
        pliki tekstowe (TXT, CSV), video (MP4, WebM), audio (MP3, WAV), archiwa (ZIP).

        Blokowane rozszerzenia: PHP, HTML, JS, SVG, EXE, i inne potencjalnie niebezpieczne.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                  description: Plik do wgrania
                parent_id:
                  type: integer
                  nullable: true
                  description: ID folderu docelowego
                name:
                  type: string
                  nullable: true
                  description: Opcjonalna nazwa (domyślnie nazwa pliku)
      responses:
        '201':
          description: Plik wgrany
          content:
            application/json:
              example:
                success: true
                data:
                  id: 50
                  name: "banner.jpg"
                  type: "image"
                  file_path: "drive/images/banner.jpg"
                  mime_type: "image/jpeg"
                  file_size: 1048576
                  url: "https://storage.example.com/drive/images/banner.jpg"
                message: "File uploaded"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          description: Typ pliku niedozwolony lub błąd walidacji
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              example:
                success: false
                message: "File type not allowed: php"

  # ==========================================================================
  # FOLDER GUIDELINES
  # ==========================================================================
  /drive/guidelines/root:
    get:
      tags:
        - Folder Guidelines
      operationId: guidelinesRoot
      summary: Pobierz wytyczne root (project-level)
      description: Zwraca wytyczne AI na poziomie projektu (korzenia drzewa folderów)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Root guidelines
          content:
            application/json:
              example:
                success: true
                data:
                  tone: "profesjonalny"
                  style: "zwięzły i jasny"
                  language: "pl"
                  instructions: "Pisz w sposób przystępny dla klienta B2B"
                  forbidden_rules: []
                  context_variables: {}
        '401':
          $ref: '#/components/responses/Unauthorized'

    put:
      tags:
        - Folder Guidelines
      operationId: guidelinesRootUpdate
      summary: Aktualizuj wytyczne root
      description: Aktualizuje wytyczne AI na poziomie projektu
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GuidelinesUpdate'
      responses:
        '200':
          description: Root guidelines zaktualizowane
          content:
            application/json:
              example:
                success: true
                message: "Root guidelines updated"
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/guidelines/templates:
    get:
      tags:
        - Folder Guidelines
      operationId: guidelinesTemplates
      summary: Lista szablonów wytycznych
      description: Zwraca dostępne szablony wytycznych do szybkiego zastosowania
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Lista szablonów
          content:
            application/json:
              example:
                success: true
                data:
                  - key: "marketing_agency"
                    name: "Agencja marketingowa"
                    description: "Wytyczne dla agencji marketingowej"
                  - key: "ecommerce"
                    name: "E-commerce"
                    description: "Wytyczne dla sklepu internetowego"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /drive/{folderId}/guidelines:
    get:
      tags:
        - Folder Guidelines
      operationId: guidelinesShow
      summary: Pobierz wytyczne folderu
      description: |
        Zwraca wytyczne lokalne folderu oraz wersję zmergowaną (z dziedziczeniem od rodziców).
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Guidelines folderu
          content:
            application/json:
              example:
                success: true
                data:
                  local:
                    tone: "kreatywny"
                    instructions: "Używaj metafor i porównań"
                    inheritance_mode: "extend"
                  merged:
                    tone: "kreatywny"
                    style: "zwięzły i jasny"
                    language: "pl"
                    instructions: "Pisz w sposób przystępny dla klienta B2B. Używaj metafor i porównań"
                  has_local: true
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Folder Guidelines
      operationId: guidelinesUpdate
      summary: Aktualizuj wytyczne folderu
      description: |
        Aktualizuje lokalne wytyczne folderu. Obsługuje tryby dziedziczenia:
        - `extend` - rozszerza wytyczne rodzica
        - `override` - nadpisuje wytyczne rodzica
        - `isolate` - ignoruje wytyczne rodzica
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GuidelinesUpdate'
      responses:
        '200':
          description: Guidelines zaktualizowane
          content:
            application/json:
              example:
                success: true
                message: "Guidelines updated"
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Folder Guidelines
      operationId: guidelinesDelete
      summary: Usuń wytyczne folderu
      description: Usuwa lokalne wytyczne (folder wraca do trybu dziedziczenia)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: Guidelines usunięte
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/{folderId}/guidelines/chain:
    get:
      tags:
        - Folder Guidelines
      operationId: guidelinesChain
      summary: Łańcuch dziedziczenia wytycznych
      description: |
        Zwraca pełny łańcuch dziedziczenia wytycznych od roota do folderu.
        Używane do wizualizacji kaskady.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Łańcuch wytycznych
          content:
            application/json:
              example:
                success: true
                data:
                  chain:
                    - level: "root"
                      folder_id: null
                      tone: "profesjonalny"
                      style: "zwięzły"
                    - level: "folder"
                      folder_id: 1
                      folder_name: "Kampanie"
                      tone: null
                      instructions: "Dodaj CTA"
                    - level: "folder"
                      folder_id: 5
                      folder_name: "Q1 2024"
                      tone: "kreatywny"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/{folderId}/guidelines/preview:
    post:
      tags:
        - Folder Guidelines
      operationId: guidelinesPreview
      summary: Podgląd zmergowanych wytycznych
      description: Podgląd jak będą wyglądać wytyczne po zapisaniu (bez faktycznego zapisu)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/GuidelinesUpdate'
      responses:
        '200':
          description: Podgląd wytycznych
          content:
            application/json:
              example:
                success: true
                data:
                  preview:
                    tone: "kreatywny"
                    style: "zwięzły i jasny"
                    language: "pl"
                    instructions: "Połączone instrukcje..."
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

  /drive/{folderId}/guidelines/from-template:
    post:
      tags:
        - Folder Guidelines
      operationId: guidelinesApplyTemplate
      summary: Zastosuj szablon wytycznych
      description: Aplikuje gotowy szablon wytycznych do folderu
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - template_key
              properties:
                template_key:
                  type: string
                  example: "marketing_agency"
                merge_mode:
                  type: string
                  enum: [replace, merge]
                  default: replace
                  description: Tryb aplikacji - replace nadpisuje, merge łączy
      responses:
        '200':
          description: Szablon zastosowany
          content:
            application/json:
              example:
                success: true
                data:
                  template_applied: "Agencja marketingowa"
                message: "Template 'Agencja marketingowa' applied"
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # FOLDER GUIDELINES RULES
  # ==========================================================================
  /drive/{folderId}/guidelines/forbidden:
    post:
      tags:
        - Folder Guidelines Rules
      operationId: guidelinesForbiddenAdd
      summary: Dodaj regułę zabronionych wyrażeń
      description: Dodaje regułę zabronionych wyrażeń do wytycznych folderu
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - rule
              properties:
                rule:
                  type: string
                  example: "Nie używaj słowa 'tani'"
                reason:
                  type: string
                  nullable: true
                  example: "Konotacja niskiej jakości"
      responses:
        '200':
          description: Reguła dodana
          content:
            application/json:
              example:
                success: true
                message: "Forbidden rule added"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/{folderId}/guidelines/forbidden/{ruleId}:
    delete:
      tags:
        - Folder Guidelines Rules
      operationId: guidelinesForbiddenRemove
      summary: Usuń regułę zabronionych wyrażeń
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
        - name: ruleId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Reguła usunięta
          content:
            application/json:
              example:
                success: true
                message: "Forbidden rule removed"
        '403':
          description: Nie można usunąć reguły systemowej
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/{folderId}/guidelines/context:
    post:
      tags:
        - Folder Guidelines Rules
      operationId: guidelinesContextSet
      summary: Ustaw zmienną kontekstową
      description: Ustawia zmienną kontekstową używaną w szablonach wytycznych
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - key
                - value
              properties:
                key:
                  type: string
                  example: "brand_name"
                value:
                  type: string
                  example: "Blitzly"
      responses:
        '200':
          description: Zmienna ustawiona
          content:
            application/json:
              example:
                success: true
                message: "Context variable set"
        '404':
          $ref: '#/components/responses/NotFound'

  /drive/{folderId}/guidelines/context/{key}:
    delete:
      tags:
        - Folder Guidelines Rules
      operationId: guidelinesContextRemove
      summary: Usuń zmienną kontekstową
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: folderId
          in: path
          required: true
          schema:
            type: integer
        - name: key
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Zmienna usunięta
          content:
            application/json:
              example:
                success: true
                message: "Context variable removed"
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # USER CONTEXT SWITCHING
  # ==========================================================================
  /user/switch-project:
    post:
      tags:
        - User
      operationId: userSwitchProject
      summary: Zmiana aktywnego projektu
      description: Przełącza użytkownika na inny projekt w bieżącym workspace
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - project_id
              properties:
                project_id:
                  type: integer
                  example: 2
      responses:
        '200':
          description: Projekt zmieniony
          content:
            application/json:
              example:
                success: true
                data:
                  current_project_id: 2
                  project:
                    id: 2
                    name: "Nowy projekt"
                    slug: "nowy-projekt"
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /user/switch-workspace:
    post:
      tags:
        - User
      operationId: userSwitchWorkspace
      summary: Zmiana aktywnego workspace
      description: Przełącza użytkownika na inny workspace (zmienia też bazę danych)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - workspace_id
              properties:
                workspace_id:
                  type: integer
                  example: 3
      responses:
        '200':
          description: Workspace zmieniony
          content:
            application/json:
              example:
                success: true
                data:
                  current_workspace_id: 3
                  current_project_id: 5
        '403':
          $ref: '#/components/responses/Forbidden'

  /user/workspaces-with-projects:
    get:
      tags:
        - User
      operationId: userWorkspacesWithProjects
      summary: Workspace'y z projektami
      description: Zwraca wszystkie workspace'y użytkownika z listą projektów w każdym
      responses:
        '200':
          description: Lista workspace'ów z projektami
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 1
                    name: "Moja Firma"
                    slug: "moja-firma"
                    role: "owner"
                    projects:
                      - id: 1
                        name: "Kampania Q1"
                        slug: "kampania-q1"
                      - id: 2
                        name: "Strona www"
                        slug: "strona-www"
                  - id: 2
                    name: "Klient ABC"
                    slug: "klient-abc"
                    role: "member"
                    projects:
                      - id: 3
                        name: "Rebranding"
                        slug: "rebranding"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /user/preferences:
    get:
      tags:
        - User
      operationId: userPreferencesGet
      summary: Pobierz preferencje użytkownika
      description: Zwraca preferencje (model AI, motyw, język, itp.)
      responses:
        '200':
          description: Preferencje użytkownika
          content:
            application/json:
              example:
                success: true
                data:
                  chat_model: "gemini-3-pro-preview"
                  image_model: "gemini-3-pro-image-preview"
                  theme: "default"
                  theme_accent: null
                  language: "pl"
                  onboarding_completed: true
        '401':
          $ref: '#/components/responses/Unauthorized'

    put:
      tags:
        - User
      operationId: userPreferencesUpdate
      summary: Zapisz preferencje użytkownika
      description: |
        Aktualizuje preferencje użytkownika. Wszystkie pola opcjonalne.

        Dozwolone klucze: `chat_model`, `image_model`, `theme`, `theme_accent`, `language`, `onboarding_completed`
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                chat_model:
                  type: string
                  nullable: true
                  example: "gemini-3-pro-preview"
                image_model:
                  type: string
                  nullable: true
                  example: "gemini-3-pro-image-preview"
                theme:
                  type: string
                  nullable: true
                  example: "dark"
                theme_accent:
                  type: string
                  nullable: true
                  example: "#4CAF50"
                language:
                  type: string
                  nullable: true
                  example: "pl"
                onboarding_completed:
                  type: boolean
                  nullable: true
      responses:
        '200':
          description: Preferencje zapisane
          content:
            application/json:
              example:
                success: true
                data:
                  chat_model: "gemini-3-pro-preview"
                  image_model: "gemini-3-pro-image-preview"
                  theme: "dark"
                  language: "pl"
                  onboarding_completed: true
                message: "Preferencje zapisane"
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ==========================================================================
  # BILLING ENDPOINTS
  # ==========================================================================
  /billing/plans:
    get:
      tags:
        - Billing
      operationId: billingPlans
      summary: Lista planów subskrypcyjnych
      description: Zwraca dostępne plany subskrypcyjne z cenami i funkcjami
      security: []
      responses:
        '200':
          description: Lista planów
          content:
            application/json:
              example:
                success: true
                data:
                  plans:
                    starter:
                      name: "Starter"
                      price: 49
                      credits: 500
                      features: ["Basic AI generation", "1 workspace", "3 projects"]
                    professional:
                      name: "Professional"
                      price: 149
                      credits: 2000
                      features: ["Advanced AI generation", "5 workspaces", "Unlimited projects"]

  /billing/packages:
    get:
      tags:
        - Billing
      operationId: billingPackages
      summary: Lista pakietów doładowań
      description: Zwraca dostępne pakiety jednorazowych doładowań kredytów
      security: []
      responses:
        '200':
          description: Lista pakietów
          content:
            application/json:
              example:
                success: true
                data:
                  packages:
                    - slug: "small"
                      name: "Mały pakiet"
                      credits: 100
                      price: 19
                    - slug: "medium"
                      name: "Średni pakiet"
                      credits: 500
                      price: 79

  /billing/usage:
    get:
      tags:
        - Billing
      operationId: billingUsage
      summary: Użycie kredytów workspace
      description: Zwraca statystyki użycia kredytów w bieżącym miesiącu
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Statystyki użycia
          content:
            application/json:
              example:
                success: true
                data:
                  current_balance: 150.50
                  this_month:
                    spent: 45.30
                    added: 100
                  subscription:
                    plan: "professional"
                    status: "active"
                    current_period_end: "2024-04-15T00:00:00Z"
        '400':
          description: Brak kontekstu workspace
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /billing/credits:
    get:
      tags:
        - Billing
      operationId: billingCredits
      summary: Podsumowanie kredytów
      description: Zwraca szczegółowy podział kredytów (subskrypcja, doładowania, bonus)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Stan kredytów
          content:
            application/json:
              example:
                success: true
                data:
                  total_credits: 250.50
                  bonus_credits: 50
                  subscription_credits: 100
                  topup_credits: 100.50
                  subscription:
                    plan: "professional"
                    status: "active"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /billing/transactions:
    get:
      tags:
        - Billing
      operationId: billingTransactions
      summary: Historia transakcji kredytowych
      description: Zwraca paginowaną historię transakcji kredytowych workspace
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/PerPageQuery'
      responses:
        '200':
          description: Lista transakcji
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 100
                    type: "usage"
                    amount: -2.50
                    description: "AI text generation"
                    created_at: "2024-03-15T10:00:00Z"
                  - id: 99
                    type: "topup"
                    amount: 100
                    description: "Medium package"
                    created_at: "2024-03-10T08:00:00Z"
                meta:
                  current_page: 1
                  per_page: 20
                  total: 50
                  last_page: 3
        '401':
          $ref: '#/components/responses/Unauthorized'

  /billing/checkout/subscription/{plan}:
    post:
      tags:
        - Billing
      operationId: billingSubscriptionCheckout
      summary: Checkout subskrypcji
      description: Tworzy sesję Stripe Checkout dla wybranego planu subskrypcyjnego
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: plan
          in: path
          required: true
          description: Slug planu subskrypcyjnego
          schema:
            type: string
          example: "professional"
      responses:
        '200':
          description: URL do Stripe Checkout
          content:
            application/json:
              example:
                success: true
                data:
                  checkout_url: "https://checkout.stripe.com/pay/cs_test_..."
        '404':
          description: Plan nie znaleziony
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Błąd tworzenia sesji Checkout
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /billing/checkout/topup/{package}:
    post:
      tags:
        - Billing
      operationId: billingTopupCheckout
      summary: Checkout doładowania kredytów
      description: Tworzy sesję Stripe Checkout dla pakietu doładowania
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: package
          in: path
          required: true
          description: Slug pakietu doładowania
          schema:
            type: string
          example: "medium"
      responses:
        '200':
          description: URL do Stripe Checkout
          content:
            application/json:
              example:
                success: true
                data:
                  checkout_url: "https://checkout.stripe.com/pay/cs_test_..."
        '404':
          description: Pakiet nie znaleziony
        '500':
          description: Błąd tworzenia sesji Checkout

  # ==========================================================================
  # AI USAGE ENDPOINTS
  # ==========================================================================
  /billing/ai-usage:
    get:
      tags:
        - AI Usage
      operationId: aiUsageStats
      summary: Statystyki użycia AI
      description: |
        Zwraca statystyki użycia AI dla bieżącego użytkownika.
        Opcjonalnie z podziałem na provider, model lub operację.
      parameters:
        - name: period
          in: query
          description: Okres statystyk
          schema:
            type: string
            enum: [today, week, month, all]
            default: today
        - name: breakdown
          in: query
          description: Podział statystyk
          schema:
            type: string
            enum: [provider, model, operation]
      responses:
        '200':
          description: Statystyki AI
          content:
            application/json:
              example:
                success: true
                data:
                  total_requests: 150
                  total_tokens: 450000
                  total_cost: 12.50
                  by_type:
                    text: 100
                    image: 30
                    chat: 20
        '401':
          $ref: '#/components/responses/Unauthorized'

  /billing/ai-usage/logs:
    get:
      tags:
        - AI Usage
      operationId: aiUsageLogs
      summary: Logi użycia AI (paginowane)
      description: Zwraca szczegółowe logi pojedynczych wywołań AI
      parameters:
        - name: period
          in: query
          schema:
            type: string
            default: today
        - name: provider
          in: query
          description: Filtruj po dostawcy AI
          schema:
            type: string
        - name: operation
          in: query
          description: Filtruj po typie operacji
          schema:
            type: string
      responses:
        '200':
          description: Lista logów
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 500
                    provider: "google"
                    model: "gemini-3-pro-preview"
                    operation: "text_generation"
                    tokens: 1500
                    cost: 0.08
                    created_at: "2024-03-15T10:30:00Z"
                meta:
                  current_page: 1
                  per_page: 15
                  total: 150
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ==========================================================================
  # VARIABLES CRUD
  # ==========================================================================
  /variables:
    get:
      tags:
        - Variables
      operationId: variablesList
      summary: Lista zmiennych
      description: Zwraca paginowaną listę zmiennych w bieżącym projekcie
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/PerPageQuery'
      responses:
        '200':
          description: Lista zmiennych
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 1
                    key: "company_name"
                    value: "Moja Firma Sp. z o.o."
                    description: "Nazwa firmy"
                  - id: 2
                    key: "primary_color"
                    value: "#4CAF50"
                    description: "Kolor główny"
                meta:
                  current_page: 1
                  per_page: 20
                  total: 10
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Variables
      operationId: variablesCreate
      summary: Utwórz zmienną
      description: Tworzy nową zmienną do użycia w promptach i szablonach
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - key
                - value
              properties:
                key:
                  type: string
                  example: "company_name"
                value:
                  type: string
                  example: "Moja Firma Sp. z o.o."
                description:
                  type: string
                  nullable: true
                  example: "Oficjalna nazwa firmy"
      responses:
        '201':
          description: Zmienna utworzona
          content:
            application/json:
              example:
                success: true
                data:
                  id: 5
                  key: "company_name"
                  value: "Moja Firma Sp. z o.o."
                message: "Zmienna utworzona"
        '422':
          $ref: '#/components/responses/ValidationError'

  /variables/{id}:
    get:
      tags:
        - Variables
      operationId: variablesShow
      summary: Szczegóły zmiennej
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '200':
          description: Dane zmiennej
          content:
            application/json:
              example:
                success: true
                data:
                  id: 1
                  key: "company_name"
                  value: "Moja Firma Sp. z o.o."
                  description: "Oficjalna nazwa firmy"
                  created_at: "2024-01-15T10:00:00Z"
                  updated_at: "2024-03-01T08:00:00Z"
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Variables
      operationId: variablesUpdate
      summary: Aktualizuj zmienną
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                key:
                  type: string
                value:
                  type: string
                description:
                  type: string
                  nullable: true
      responses:
        '200':
          description: Zmienna zaktualizowana
          content:
            application/json:
              example:
                success: true
                message: "Zmienna zaktualizowana"
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Variables
      operationId: variablesDelete
      summary: Usuń zmienną
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '204':
          description: Zmienna usunięta
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # VISUAL IDENTITIES CRUD
  # ==========================================================================
  /visual-identities:
    get:
      tags:
        - VisualIdentities
      operationId: visualIdentitiesList
      summary: Lista identyfikacji wizualnych
      description: Zwraca paginowaną listę identyfikacji wizualnych
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/PerPageQuery'
      responses:
        '200':
          description: Lista identyfikacji
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 1
                    name: "Moja Firma - Brand"
                    colors: ["#4CAF50", "#212121"]
                    fonts: ["Roboto", "Open Sans"]
                  - id: 2
                    name: "Klient ABC"
                    colors: ["#1976D2"]
                meta:
                  current_page: 1
                  per_page: 20
                  total: 5
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - VisualIdentities
      operationId: visualIdentitiesCreate
      summary: Utwórz identyfikację wizualną
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  example: "Nowa identyfikacja"
                colors:
                  type: array
                  items:
                    type: string
                  example: ["#4CAF50", "#212121"]
                fonts:
                  type: array
                  items:
                    type: string
                  example: ["Roboto", "Open Sans"]
                logo_url:
                  type: string
                  nullable: true
                description:
                  type: string
                  nullable: true
      responses:
        '201':
          description: Identyfikacja utworzona
          content:
            application/json:
              example:
                success: true
                data:
                  id: 3
                  name: "Nowa identyfikacja"
                message: "Identyfikacja wizualna utworzona"
        '422':
          $ref: '#/components/responses/ValidationError'

  /visual-identities/{id}:
    get:
      tags:
        - VisualIdentities
      operationId: visualIdentitiesShow
      summary: Szczegóły identyfikacji
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '200':
          description: Dane identyfikacji
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - VisualIdentities
      operationId: visualIdentitiesUpdate
      summary: Aktualizuj identyfikację
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                colors:
                  type: array
                  items:
                    type: string
                fonts:
                  type: array
                  items:
                    type: string
                logo_url:
                  type: string
                  nullable: true
                description:
                  type: string
                  nullable: true
      responses:
        '200':
          description: Identyfikacja zaktualizowana
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - VisualIdentities
      operationId: visualIdentitiesDelete
      summary: Usuń identyfikację
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '204':
          description: Identyfikacja usunięta
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # PROMPTS CRUD
  # ==========================================================================
  /prompts:
    get:
      tags:
        - Prompts
      operationId: promptsList
      summary: Lista promptów
      description: Zwraca paginowaną listę promptów, opcjonalnie filtrowanych po kategorii
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: category
          in: query
          description: Filtruj po kategorii
          schema:
            type: string
        - $ref: '#/components/parameters/PerPageQuery'
      responses:
        '200':
          description: Lista promptów
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 1
                    name: "Nagłówek reklamowy"
                    category: "copywriting"
                    content: "Napisz chwytliwy nagłówek dla {{product}}"
                  - id: 2
                    name: "Opis produktu"
                    category: "copywriting"
                meta:
                  current_page: 1
                  per_page: 20
                  total: 15
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Prompts
      operationId: promptsCreate
      summary: Utwórz prompt
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - content
              properties:
                name:
                  type: string
                  example: "Nagłówek reklamowy"
                content:
                  type: string
                  example: "Napisz chwytliwy nagłówek dla {{product}}"
                category:
                  type: string
                  nullable: true
                  example: "copywriting"
                description:
                  type: string
                  nullable: true
      responses:
        '201':
          description: Prompt utworzony
          content:
            application/json:
              example:
                success: true
                data:
                  id: 3
                  name: "Nagłówek reklamowy"
                message: "Prompt utworzony"
        '422':
          $ref: '#/components/responses/ValidationError'

  /prompts/{id}:
    get:
      tags:
        - Prompts
      operationId: promptsShow
      summary: Szczegóły promptu
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '200':
          description: Dane promptu
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Prompts
      operationId: promptsUpdate
      summary: Aktualizuj prompt
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                content:
                  type: string
                category:
                  type: string
                  nullable: true
                description:
                  type: string
                  nullable: true
      responses:
        '200':
          description: Prompt zaktualizowany
          content:
            application/json:
              example:
                success: true
                message: "Prompt zaktualizowany"
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Prompts
      operationId: promptsDelete
      summary: Usuń prompt
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '204':
          description: Prompt usunięty
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # FEATURE REQUESTS
  # ==========================================================================
  /feature-requests:
    get:
      tags:
        - FeatureRequests
      operationId: featureRequestsList
      summary: Lista zgłoszeń funkcjonalności
      description: Zwraca paginowaną listę zgłoszeń z opcjonalnym filtrowaniem
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [new, in_progress, planned, done, rejected, duplicate]
        - name: category
          in: query
          schema:
            type: string
        - name: search
          in: query
          schema:
            type: string
        - name: sort_by
          in: query
          schema:
            type: string
            default: priority
            enum: [priority, created_at, votes]
        - name: sort_dir
          in: query
          schema:
            type: string
            default: desc
            enum: [asc, desc]
        - $ref: '#/components/parameters/PerPageQuery'
      responses:
        '200':
          description: Lista zgłoszeń
          content:
            application/json:
              example:
                success: true
                data:
                  data:
                    - id: 1
                      title: "Eksport do PDF"
                      status: "planned"
                      category: "export"
                      priority: 3
                  meta:
                    current_page: 1
                    per_page: 20
                    total: 25
        '401':
          $ref: '#/components/responses/Unauthorized'

  /feature-requests/stats:
    get:
      tags:
        - FeatureRequests
      operationId: featureRequestsStats
      summary: Statystyki zgłoszeń
      description: Zwraca statystyki zgłoszeń pogrupowane po statusie
      responses:
        '200':
          description: Statystyki
          content:
            application/json:
              example:
                success: true
                data:
                  total: 25
                  by_status:
                    new: 10
                    planned: 5
                    in_progress: 3
                    done: 5
                    rejected: 2
        '401':
          $ref: '#/components/responses/Unauthorized'

  /feature-requests/{id}:
    get:
      tags:
        - FeatureRequests
      operationId: featureRequestsShow
      summary: Szczegóły zgłoszenia
      parameters:
        - $ref: '#/components/parameters/IdPath'
      responses:
        '200':
          description: Dane zgłoszenia
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - FeatureRequests
      operationId: featureRequestsUpdate
      summary: Aktualizuj zgłoszenie
      parameters:
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                description:
                  type: string
                category:
                  type: string
                priority:
                  type: integer
                status:
                  type: string
      responses:
        '200':
          description: Zgłoszenie zaktualizowane
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - FeatureRequests
      operationId: featureRequestsDelete
      summary: Usuń zgłoszenie
      parameters:
        - $ref: '#/components/parameters/IdPath'
      responses:
        '204':
          description: Zgłoszenie usunięte
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /feature-requests/{id}/quick-status:
    post:
      tags:
        - FeatureRequests
      operationId: featureRequestsQuickStatus
      summary: Szybka zmiana statusu
      parameters:
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
              properties:
                status:
                  type: string
                  enum: [new, in_progress, planned, done, rejected]
                  example: "in_progress"
      responses:
        '200':
          description: Status zmieniony
          content:
            application/json:
              example:
                success: true
                data:
                  id: 1
                  status: "in_progress"
                message: "Status updated"
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  /feature-requests/{id}/mark-duplicate:
    post:
      tags:
        - FeatureRequests
      operationId: featureRequestsMarkDuplicate
      summary: Oznacz jako duplikat
      parameters:
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - duplicate_of_id
              properties:
                duplicate_of_id:
                  type: integer
                  description: ID oryginalnego zgłoszenia
                  example: 5
      responses:
        '200':
          description: Oznaczono jako duplikat
          content:
            application/json:
              example:
                success: true
                message: "Marked as duplicate"
        '400':
          description: Nieprawidłowa operacja (np. samo-referencja)
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # DASHBOARD ENDPOINTS
  # ==========================================================================
  /dashboard/quick-actions:
    get:
      tags:
        - Dashboard
      operationId: dashboardQuickActions
      summary: Lista dostępnych szybkich akcji
      description: Zwraca wszystkie dostępne szybkie akcje z kategoriami
      responses:
        '200':
          description: Lista akcji
          content:
            application/json:
              example:
                success: true
                data:
                  actions:
                    - key: "create_text"
                      label: "Utwórz tekst"
                      icon: "document"
                      category: "create"
                    - key: "generate_image"
                      label: "Generuj obraz"
                      icon: "image"
                      category: "ai"
                  categories:
                    - key: "create"
                      label: "Tworzenie"
                    - key: "ai"
                      label: "AI"
        '401':
          $ref: '#/components/responses/Unauthorized'

  /dashboard/quick-actions/user:
    get:
      tags:
        - Dashboard
      operationId: dashboardUserQuickActions
      summary: Wybrane szybkie akcje użytkownika
      description: Zwraca szybkie akcje wybrane przez użytkownika
      responses:
        '200':
          description: Wybrane akcje
          content:
            application/json:
              example:
                success: true
                data:
                  selected_keys: ["create_text", "generate_image", "chat_agent"]
                  actions:
                    - key: "create_text"
                      label: "Utwórz tekst"
                    - key: "generate_image"
                      label: "Generuj obraz"
        '401':
          $ref: '#/components/responses/Unauthorized'

    put:
      tags:
        - Dashboard
      operationId: dashboardSaveUserQuickActions
      summary: Zapisz wybrane szybkie akcje
      description: Zapisuje listę wybranych szybkich akcji użytkownika
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - actions
              properties:
                actions:
                  type: array
                  items:
                    type: string
                  example: ["create_text", "generate_image"]
      responses:
        '200':
          description: Zapisano
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'

  /dashboard/widgets:
    get:
      tags:
        - Dashboard
      operationId: dashboardWidgets
      summary: Lista typów widgetów
      description: Zwraca listę dostępnych typów widgetów dashboardu
      responses:
        '200':
          description: Lista widgetów
        '401':
          $ref: '#/components/responses/Unauthorized'

  /dashboard/presets:
    get:
      tags:
        - Dashboard
      operationId: dashboardPresetsList
      summary: Lista presetów dashboardu
      description: Zwraca systemowe i niestandardowe presety dashboardu
      responses:
        '200':
          description: Lista presetów
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Dashboard
      operationId: dashboardPresetsCreate
      summary: Utwórz preset dashboardu
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - widgets
              properties:
                name:
                  type: string
                  example: "Mój układ"
                widgets:
                  type: array
                  items:
                    type: object
      responses:
        '201':
          description: Preset utworzony
        '422':
          $ref: '#/components/responses/ValidationError'

  /dashboard/presets/{id}:
    put:
      tags:
        - Dashboard
      operationId: dashboardPresetsUpdate
      summary: Edytuj preset
      parameters:
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                widgets:
                  type: array
                  items:
                    type: object
      responses:
        '200':
          description: Preset zaktualizowany
        '422':
          $ref: '#/components/responses/ValidationError'

    delete:
      tags:
        - Dashboard
      operationId: dashboardPresetsDelete
      summary: Usuń preset
      parameters:
        - $ref: '#/components/parameters/IdPath'
      responses:
        '204':
          description: Preset usunięty

  /dashboard/presets/active:
    put:
      tags:
        - Dashboard
      operationId: dashboardPresetsSetActive
      summary: Ustaw aktywny preset
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                preset_id:
                  type: integer
                  nullable: true
                  description: ID presetu (null = domyślny)
      responses:
        '200':
          description: Aktywny preset ustawiony
        '422':
          $ref: '#/components/responses/ValidationError'

  /dashboard/layout:
    put:
      tags:
        - Dashboard
      operationId: dashboardLayoutSave
      summary: Zapisz layout (drag & drop)
      description: Auto-save layoutu widgetów po przeciągnięciu
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - widgets
              properties:
                widgets:
                  type: array
                  items:
                    type: object
                  description: Tablica widgetów z pozycjami
      responses:
        '200':
          description: Layout zapisany
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ==========================================================================
  # JTBD ENDPOINTS
  # ==========================================================================
  /jtbd:
    get:
      tags:
        - JTBD
      operationId: jtbdList
      summary: Lista szablonów JTBD
      description: Zwraca szablony Jobs To Be Done, opcjonalnie filtrowane po domenie
      parameters:
        - name: domain
          in: query
          description: Filtruj po domenie
          schema:
            type: string
      responses:
        '200':
          description: Lista szablonów
          content:
            application/json:
              example:
                success: true
                data:
                  - slug: "create-ad-campaign"
                    title: "Stwórz kampanię reklamową"
                    description: "Zautomatyzuj tworzenie materiałów kampanii"
                    domain: "marketing"
                    steps: 5
        '401':
          $ref: '#/components/responses/Unauthorized'

  /jtbd/suggested:
    get:
      tags:
        - JTBD
      operationId: jtbdSuggested
      summary: Sugerowane szablony JTBD
      description: Zwraca szablony dopasowane do kontekstu użytkownika
      responses:
        '200':
          description: Sugerowane szablony
        '401':
          $ref: '#/components/responses/Unauthorized'

  /jtbd/favorites:
    get:
      tags:
        - JTBD
      operationId: jtbdFavorites
      summary: Ulubione szablony JTBD
      description: Zwraca szablony dodane do ulubionych przez użytkownika
      responses:
        '200':
          description: Lista ulubionych
        '401':
          $ref: '#/components/responses/Unauthorized'

  /jtbd/favorites/{slug}:
    post:
      tags:
        - JTBD
      operationId: jtbdFavoritesAdd
      summary: Dodaj do ulubionych
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Dodano do ulubionych
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - JTBD
      operationId: jtbdFavoritesRemove
      summary: Usuń z ulubionych
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Usunięto z ulubionych
        '404':
          $ref: '#/components/responses/NotFound'

  /jtbd/favorites/reorder:
    put:
      tags:
        - JTBD
      operationId: jtbdFavoritesReorder
      summary: Zmień kolejność ulubionych
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - order
              properties:
                order:
                  type: array
                  items:
                    type: string
                  description: Tablica slugów w żądanej kolejności
                  example: ["create-ad-campaign", "generate-content"]
      responses:
        '200':
          description: Kolejność zmieniona
        '401':
          $ref: '#/components/responses/Unauthorized'

  /jtbd/{slug}:
    get:
      tags:
        - JTBD
      operationId: jtbdShow
      summary: Szczegóły szablonu JTBD
      parameters:
        - name: slug
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Dane szablonu
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # SEARCH ENDPOINT
  # ==========================================================================
  /search:
    get:
      tags:
        - Search
      operationId: unifiedSearch
      summary: Wyszukiwanie globalne
      description: |
        Unified search across Drive, Agent conversations, Flow pipelines, Prompts.
        Wymaga kontekstu workspace.
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: query
          in: query
          required: true
          description: Fraza wyszukiwania (min. 2 znaki)
          schema:
            type: string
            minLength: 2
            example: "kampania"
      responses:
        '200':
          description: Wyniki wyszukiwania
          content:
            application/json:
              example:
                success: true
                data:
                  drive:
                    - id: 10
                      name: "Kampania Q1"
                      type: "folder"
                      score: 0.95
                  agent:
                    - id: 42
                      title: "Kampania reklamowa"
                      score: 0.80
                  pipelines:
                    - id: 1
                      name: "Pipeline kampanii"
                      score: 0.70
        '400':
          description: Wyszukiwanie nie powiodło się
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ==========================================================================
  # SLIDESHOW ENDPOINTS
  # ==========================================================================
  /slideshow:
    get:
      tags:
        - Slideshow
      operationId: slideshowList
      summary: Lista projektów slideshow
      description: Zwraca listę projektów prezentacji w bieżącym projekcie
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Lista prezentacji
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 1
                    name: "Prezentacja Q1"
                    aspect_ratio: "16:9"
                    slides_count: 10
                  - id: 2
                    name: "Pitch deck"
                    aspect_ratio: "16:9"
                    slides_count: 5
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Slideshow
      operationId: slideshowCreate
      summary: Utwórz prezentację
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                  example: "Nowa prezentacja"
                aspect_ratio:
                  type: string
                  enum: ["16:9", "4:3", "1:1"]
                  default: "16:9"
                parent_id:
                  type: integer
                  nullable: true
                  description: ID folderu Drive do powiązania
      responses:
        '201':
          description: Prezentacja utworzona
          content:
            application/json:
              example:
                success: true
                data:
                  project:
                    id: 3
                    name: "Nowa prezentacja"
                    aspect_ratio: "16:9"
                  slides:
                    - id: 10
                      name: "Slide 1"
                      page_order: 0
                message: "Slideshow project created"
        '422':
          $ref: '#/components/responses/ValidationError'

  /slideshow/{id}:
    get:
      tags:
        - Slideshow
      operationId: slideshowShow
      summary: Szczegóły prezentacji
      description: Zwraca projekt z listą slajdów
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '200':
          description: Dane prezentacji ze slajdami
          content:
            application/json:
              example:
                success: true
                data:
                  id: 1
                  name: "Prezentacja Q1"
                  aspect_ratio: "16:9"
                  theme: null
                  slides:
                    - id: 10
                      name: "Slide 1"
                      page_order: 0
                      slide_type: "content"
                      is_active: true
                      has_html: true
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Slideshow
      operationId: slideshowUpdate
      summary: Aktualizuj prezentację
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                aspect_ratio:
                  type: string
                theme:
                  type: object
                  nullable: true
      responses:
        '200':
          description: Prezentacja zaktualizowana
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Slideshow
      operationId: slideshowDelete
      summary: Usuń prezentację
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '204':
          description: Prezentacja usunięta
        '404':
          $ref: '#/components/responses/NotFound'

  /slideshow/{id}/slides:
    get:
      tags:
        - Slideshow
      operationId: slideshowSlidesList
      summary: Lista slajdów
      description: Zwraca wszystkie slajdy prezentacji z HTML i metadanymi
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      responses:
        '200':
          description: Lista slajdów
          content:
            application/json:
              example:
                success: true
                data:
                  - id: 10
                    name: "Slide 1"
                    page_order: 0
                    slide_type: "content"
                    is_active: true
                    has_html: true
                    html: "<div>Content...</div>"
                    speaker_notes: "Notatki prelegenta"
        '401':
          $ref: '#/components/responses/Unauthorized'

    post:
      tags:
        - Slideshow
      operationId: slideshowSlidesCreate
      summary: Dodaj slajd
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - html
              properties:
                html:
                  type: string
                  description: HTML slajdu
                slide_type:
                  type: string
                  enum: [content, title, image, blank]
                  default: content
                title:
                  type: string
                  nullable: true
                after_order:
                  type: integer
                  nullable: true
                  description: Wstaw po slajdzie o danej kolejności
      responses:
        '201':
          description: Slajd utworzony
          content:
            application/json:
              example:
                success: true
                data:
                  id: 15
                  name: "Slide 6"
                  page_order: 5
                  slide_type: "content"
                message: "Slide created"
        '404':
          $ref: '#/components/responses/NotFound'

  /slideshow/{id}/slides/reorder:
    post:
      tags:
        - Slideshow
      operationId: slideshowSlidesReorder
      summary: Zmień kolejność slajdów
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - $ref: '#/components/parameters/IdPath'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - slide_ids
              properties:
                slide_ids:
                  type: array
                  items:
                    type: integer
                  description: Tablica ID slajdów w żądanej kolejności
                  example: [12, 10, 11, 15, 13]
      responses:
        '200':
          description: Kolejność zmieniona
        '400':
          description: Nieprawidłowe dane

  /slideshow/slides/{slideId}:
    get:
      tags:
        - Slideshow
      operationId: slideshowSlideShow
      summary: Szczegóły slajdu
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: slideId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Dane slajdu
          content:
            application/json:
              example:
                success: true
                data:
                  id: 10
                  name: "Slide 1"
                  page_order: 0
                  slide_type: "content"
                  html: "<div>Content...</div>"
                  speaker_notes: "Notatki prelegenta"
                  transition: "fade"
                  is_active: true
        '404':
          $ref: '#/components/responses/NotFound'

    put:
      tags:
        - Slideshow
      operationId: slideshowSlideUpdate
      summary: Aktualizuj slajd
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: slideId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                html:
                  type: string
                name:
                  type: string
                speaker_notes:
                  type: string
                  nullable: true
                slide_type:
                  type: string
                transition:
                  type: string
                  nullable: true
      responses:
        '200':
          description: Slajd zaktualizowany
        '404':
          $ref: '#/components/responses/NotFound'

    delete:
      tags:
        - Slideshow
      operationId: slideshowSlideDelete
      summary: Usuń slajd
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: slideId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: Slajd usunięty
        '404':
          $ref: '#/components/responses/NotFound'

  /slideshow/slides/{slideId}/element:
    post:
      tags:
        - Slideshow
      operationId: slideshowSlideEditElement
      summary: Edytuj element na slajdzie
      description: Edytuje konkretny element HTML na slajdzie (np. tekst, obraz)
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
        - name: slideId
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - element_id
                - changes
              properties:
                element_id:
                  type: string
                  description: ID elementu na slajdzie
                  example: "heading-1"
                changes:
                  type: object
                  description: Zmiany do zastosowania
                  example:
                    text: "Nowy nagłówek"
                    style:
                      color: "#FF0000"
      responses:
        '200':
          description: Element zaktualizowany
        '404':
          $ref: '#/components/responses/NotFound'

  # ==========================================================================
  # UNIFIED JOB STATUS ENDPOINTS
  # ==========================================================================
  /jobs/types:
    get:
      tags:
        - Jobs
      operationId: jobsTypes
      summary: Lista typów zadań
      description: Zwraca wszystkie obsługiwane typy zadań z opisami
      responses:
        '200':
          description: Typy zadań
          content:
            application/json:
              example:
                success: true
                data:
                  types:
                    image: "Image generation"
                    text: "Text generation"
                    agent: "AI Agent messages"
                    workflow: "Pipeline workflows"
                    node: "Pipeline nodes"
                    website: "Website generation"
                    field: "Field generation"
                    creative: "Creative content generation"
                    layout: "Layout generation"
                    design: "Design generation"
                    analysis: "Site analysis"
                    cell: "Table cell generation"

  /jobs/active:
    get:
      tags:
        - Jobs
      operationId: jobsActive
      summary: Aktywne zadania użytkownika
      description: Zwraca wszystkie aktywne (pending/processing) zadania bieżącego użytkownika
      responses:
        '200':
          description: Lista aktywnych zadań
          content:
            application/json:
              example:
                success: true
                data:
                  jobs:
                    - job_id: "550e8400-e29b-41d4-a716-446655440000"
                      job_type: "image"
                      status: "processing"
                      progress: 45
                      stage: "Generowanie obrazu..."
                      job_label: "Banner kampanii"
                      started_at: "2024-03-15T10:00:00Z"
                    - job_id: "660f9500-f30c-52e5-b827-557766551111"
                      job_type: "agent"
                      status: "pending"
                      progress: 0
                      stage: "W kolejce..."
                      job_label: null
                      started_at: null
                  count: 2
        '401':
          $ref: '#/components/responses/Unauthorized'

  /jobs/metrics:
    get:
      tags:
        - Jobs
      operationId: jobsMetrics
      summary: Metryki zadań (admin)
      description: |
        Zwraca ogólne metryki zadań dla workspace.

        **Wymaga roli admin.**
      parameters:
        - $ref: '#/components/parameters/WorkspaceHeader'
      responses:
        '200':
          description: Metryki
        '403':
          description: Brak uprawnień admin
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /jobs/{type}/active:
    get:
      tags:
        - Jobs
      operationId: jobsActiveByType
      summary: Aktywne zadania danego typu
      parameters:
        - name: type
          in: path
          required: true
          description: "Typ zadania: image, text, agent, workflow, node, website, field, creative, layout, design, analysis, cell"
          schema:
            type: string
      responses:
        '200':
          description: Lista aktywnych zadań danego typu
          content:
            application/json:
              example:
                success: true
                data:
                  jobs: []
                  count: 0
        '400':
          description: Nieprawidłowy typ zadania
        '401':
          $ref: '#/components/responses/Unauthorized'

  /jobs/{type}/metrics:
    get:
      tags:
        - Jobs
      operationId: jobsMetricsByType
      summary: Metryki dla typu zadania
      description: Zwraca statystyki (counts, durations, errors, hourly) dla typu
      parameters:
        - name: type
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Metryki typu
          content:
            application/json:
              example:
                success: true
                data:
                  job_type: "image"
                  counts:
                    total: 500
                    completed: 480
                    failed: 20
                  durations:
                    avg_seconds: 12.5
                    p95_seconds: 25
                  recent_errors:
                    - error: "Content policy violation"
                      count: 5
                  hourly: []
        '400':
          description: Nieprawidłowy typ zadania

  /jobs/{type}/{id}/status:
    get:
      tags:
        - Jobs
      operationId: jobsStatus
      summary: Status zadania
      description: |
        Sprawdza status konkretnego zadania.
        Uniwersalny endpoint dla wszystkich typów zadań.
      parameters:
        - name: type
          in: path
          required: true
          description: Typ zadania
          schema:
            type: string
        - name: id
          in: path
          required: true
          description: ID zadania (UUID lub custom ID)
          schema:
            type: string
      responses:
        '200':
          description: Status zadania
          content:
            application/json:
              examples:
                completed:
                  summary: Zakończone
                  value:
                    success: true
                    data:
                      job_id: "550e8400"
                      job_type: "image"
                      status: "completed"
                      progress: 100
                      stage: "Zakończone"
                      result:
                        url: "https://storage.example.com/generated.png"
                      started_at: "2024-03-15T10:00:00Z"
                      completed_at: "2024-03-15T10:00:12Z"
                processing:
                  summary: W trakcie
                  value:
                    success: true
                    data:
                      job_id: "550e8400"
                      job_type: "image"
                      status: "processing"
                      progress: 45
                      stage: "Generowanie..."
                      result: null
        '400':
          description: Nieprawidłowy typ zadania
        '404':
          description: Zadanie nie znalezione

  /jobs/{type}/{id}/cancel:
    post:
      tags:
        - Jobs
      operationId: jobsCancel
      summary: Anuluj zadanie
      description: |
        Anuluje uruchomione zadanie. Zadanie musi należeć do bieżącego użytkownika
        i nie może być już zakończone.
      parameters:
        - name: type
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Zadanie anulowane
          content:
            application/json:
              example:
                success: true
                data:
                  job_id: "550e8400"
                  job_type: "image"
                  status: "cancelled"
                  message: "Job cancelled successfully"
        '400':
          description: Zadanie już zakończone
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: Zadanie nie znalezione

  # ==========================================================================
  # TUTORIAL ENDPOINT
  # ==========================================================================
  /tutorial/steps:
    get:
      tags:
        - User
      operationId: tutorialSteps
      summary: Kroki tutorialu
      description: Zwraca listę kroków onboardingu/tutorialu
      responses:
        '200':
          description: Lista kroków
        '401':
          $ref: '#/components/responses/Unauthorized'
