openapi: 3.0.3
info:
  title: Relationships Platform API
  version: 1.0.0
  description: |
    API de resolução de identidade visual (avatar) e rotinas de housekeeping.

    Observação sobre rate limit: os limites atualmente são definidos por endpoint
    no contrato Broker (`api/broker_actions.json`) e aplicados por IP + endpoint.
servers:
  - url: https://api.rp.laniway.com.br
    description: Produção (BR)
  - url: https://api.rp.laniway.com
    description: Produção (global)
tags:
  - name: Avatar
    description: Resolução de avatar com cache local e fallback.
  - name: Housekeeping
    description: Manutenção do storage de avatar.
paths:
  /avatar/get-1.0:
    get:
      tags: [Avatar]
      summary: Resolve avatar por e-mails codificados
      description: |
        Fluxo de resolução:
        1) cache em disco,
        2) Gravatar com `d=404`,
        3) favicon por domínio,
        4) Gravatar identicon,
        5) fallback SVG.

        Série local de erro: 1001xxxx.
        Série global da API: 1000xxxx.
        Códigos nativos do BrokerNG permanecem <1000.
      operationId: avatarGetV10
      x-error-series:
        global_api: 1000xxxx
        broker_native: <1000
        local: 1001xxxx
      x-error-codes:
        broker_native:
          - 1
          - 2
          - 3
          - 4
          - 5
          - 6
          - 7
          - 8
          - 9
          - 100
          - 102
          - 103
          - 104
          - 105
          - 106
          - 107
          - 110
          - 111
          - 112
          - 113
          - 114
          - 115
        global_api:
          - 10000001
        local:
          - 10010001
      x-rate-limit:
        strategy: ip_endpoint
        enabled: true
        max_requests: 120
        window_seconds: 60
        key: user_ip + endpoint
      parameters:
        - in: query
          name: source_email_encoded
          required: true
          description: E-mail de origem codificado.
          schema:
            type: string
            minLength: 1
            maxLength: 1024
        - in: query
          name: target_email_encoded
          required: true
          description: E-mail alvo codificado para resolução do avatar.
          schema:
            type: string
            minLength: 1
            maxLength: 1024
        - in: query
          name: size
          required: false
          description: Tamanho desejado em px. Se omitido, usa default interno.
          schema:
            type: integer
            minimum: 1
      responses:
        '200':
          description: Avatar resolvido.
          content:
            image/png:
              schema:
                type: string
                format: binary
            image/jpeg:
              schema:
                type: string
                format: binary
            image/webp:
              schema:
                type: string
                format: binary
            image/svg+xml:
              schema:
                type: string
                format: binary
        '400':
          description: Entrada inválida (ex.: body JSON inválido em métodos que usam body).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '401':
          description: Falha de autenticação/autorização de rede/token no Broker.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '403':
          description: Acesso negado (ACL/regras de acesso).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '405':
          description: Método HTTP não suportado para a ação.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '406':
          description: Erro de validação (BrokerNG 107) ou global API (`10000001`). O código local `10010001` está reservado para uso exclusivo futuro do endpoint.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '429':
          description: Limite de requisições atingido para IP + endpoint.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/BrokerError'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/RateLimitData'
        '500':
          description: Erro interno inesperado da aplicação.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '501':
          description: Erro de configuração/contrato da ação no Broker.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '503':
          description: Serviço indisponível (falhas internas de setup/execução).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'

  /keepalive-1.0:
    post:
      tags: [Housekeeping]
      summary: Executa housekeeping e observabilidade do storage
      description: |
        Executa limpeza de metadados/arquivos antigos e retorna snapshot de observabilidade.
        Endpoint protegido por regra de rede (não público).

        Série local de erro: 1002xxxx.
        Série global da API: 1000xxxx.
        Códigos nativos do BrokerNG permanecem <1000.
      operationId: keepaliveV10
      x-error-series:
        global_api: 1000xxxx
        broker_native: <1000
        local: 1002xxxx
      x-error-codes:
        broker_native:
          - 1
          - 2
          - 3
          - 4
          - 5
          - 6
          - 7
          - 8
          - 9
          - 100
          - 102
          - 103
          - 104
          - 105
          - 106
          - 107
          - 110
          - 111
          - 112
          - 113
          - 114
          - 115
        global_api:
          - 10000001
        local:
          - 10020001
      x-rate-limit:
        strategy: ip_endpoint
        enabled: true
        max_requests: 20
        window_seconds: 60
        key: user_ip + endpoint
      responses:
        '200':
          description: Housekeeping concluído.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status_code:
                    type: integer
                    example: 0
                  started_at:
                    type: string
                    format: date-time
                  housekeeping:
                    $ref: '#/components/schemas/HousekeepingData'
                  observability:
                    $ref: '#/components/schemas/ObservabilityData'
        '403':
          description: Bloqueado por regra de rede.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '400':
          description: Entrada inválida (JSON/parâmetros).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '401':
          description: Falha de autenticação/autorização de rede/token no Broker.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '405':
          description: Método HTTP não suportado para a ação.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '406':
          description: Erro de validação de parâmetro/processamento.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '429':
          description: Limite de requisições atingido para IP + endpoint.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/BrokerError'
                  - type: object
                    properties:
                      data:
                        $ref: '#/components/schemas/RateLimitData'
        '500':
          description: Erro local do endpoint (`10020001`) ou erro interno inesperado.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '501':
          description: Erro de configuração/contrato da ação no Broker.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'
        '503':
          description: Serviço indisponível (falhas internas de setup/execução).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BrokerError'

components:
  schemas:
    BrokerError:
      type: object
      properties:
        code:
          type: integer
          description: Código retornado pela API (BrokerNG nativo <1000 ou séries da aplicação 1000xxxx/1001xxxx/1002xxxx).
        message:
          oneOf:
            - type: string
            - type: object
          description: Mensagem resumida do erro (texto ou mapa por idioma).
        data:
          type: object
          nullable: true
      additionalProperties: true
    RateLimitData:
      type: object
      properties:
        strategy:
          type: string
          example: ip_endpoint
        max_requests:
          type: integer
          example: 120
        window_seconds:
          type: integer
          example: 60
        retry_after_seconds:
          type: integer
          example: 12
        remaining:
          type: integer
          example: 0
    HousekeepingData:
      type: object
      properties:
        removed_meta_entries:
          type: integer
        removed_files:
          type: integer
        normalized_file_paths:
          type: integer
        remaining_meta_entries:
          type: integer
    ObservabilityData:
      type: object
      properties:
        storage_dir:
          type: string
        meta_entries:
          type: integer
        files_count:
          type: integer
        total_size_bytes:
          type: integer
        source_counts:
          type: object
          additionalProperties:
            type: integer
