﻿openapi: 3.0.3
info:
  title: Sensor de Jornada API (leitura)
  version: 1.0.0
  description: |
    Leitura do Sensor de Jornada da BOOM, usada pelas tools `core_jornada_*` do conector.

    API **somente leitura** do Sensor de Jornada. Cobre exatamente os endpoints consumidos pelas
    tools `core_jornada_overview`, `core_jornada_triggers_list` e `core_jornada_disparos_list`
    do conector BOOM, mais o endpoint de respostas que sustenta o perfil do colaborador (ainda
    não exposto no conector).

    Nenhum endpoint de escrita é exposto aqui: criar, editar, duplicar ou excluir triggers,
    disparo manual, reenvio e envio de notificações pendentes **não fazem parte** deste contrato.

    ## Autenticação

    `Authorization: Bearer <token>`, com um destes tokens:

    | Token | Prefixo | Uso |
    |---|---|---|
    | JWT de usuário | `eyJ…` | Sessão do Core |
    | OAuth do conector | `mct_…` | Conector BOOM no Claude |

    O token de API V2 (`bvt_…`) **não** autentica esta API.
    Permissões exigidas: `employee:read` (overview) e `survey_template:read` (triggers, disparos e respostas).

    ## Escopo somente leitura

    Todas as operações aqui descritas apenas leem dados. O endpoint `POST /core/v1/employee/read-filter/journey-sensor`
    e o `POST /core/v1/journey-trigger-audience/answers` usam `POST` apenas porque recebem filtros no corpo.

    ## Comportamento por perfil

    | Perfil | Visão geral | Triggers | Disparos |
    |---|---|---|---|
    | Admin Cliente | Organização inteira | Todos da empresa | Toda a empresa |
    | RH Estratégico | Organização inteira | Todos da empresa | Toda a empresa |
    | RH Business Partner | Árvore de "reporta a" do Colaborador vinculado | Todos da empresa (configuração, sem dado individual) | Somente disparos do recorte |
    | Liderança | Árvore de "reporta a" do Colaborador vinculado | Todos da empresa (configuração, sem dado individual) | Somente disparos do recorte |
    | GPS Admin Cliente | Sem acesso | `403` | `403` |

    Todos os endpoints devolvem **dados individuais** (nome, e-mail, score por disparo). Não existe
    endpoint agregado, e estes endpoints não aplicam regra de anonimato mínimo.
    A resposta de acesso negado é `403` (nunca lista vazia para perfil sem acesso).
    Perfis de recorte (RH Business Partner e Liderança) enxergam apenas os registros do seu recorte.

    ## Papel: colaborador e líder

    Um disparo é do **líder** quando `onBehalfOfEmployeeId` está preenchido: o líder responde
    *em nome* daquele colaborador. Quando é `null`, o disparo é do próprio **colaborador**.

    ### "Líder não precisa responder" × "líder não respondeu"

    | Situação | Como aparece | Score |
    |---|---|---|
    | **Líder não precisa responder** | **Não existe** linha de disparo do líder para aquele colaborador e trigger | Só o score do colaborador conta |
    | **Líder não respondeu** | **Existe** linha com `onBehalfOfEmployeeId` preenchido e `status` diferente de `ANSWERED` (`PENDING`, `SENT`, `EXPIRED` ou `FAILED`) | `score` = `null` |

    O líder **não precisa** responder quando: o trigger tem `sendToManager = false` (exceto triggers de
    ciclo, em que é sempre `true`), o colaborador não tem gestor imediato ativo, ou o template não tem
    perguntas para a Liderança. Nesses casos a linha pendente do líder é removida e nenhuma nova é criada.
    Ausência de linha **não** é sinal de falta de resposta.

    ## Score

    - `score` é inteiro de **0 a 1000** (escala BOOM) e só existe em disparos `ANSWERED` com perguntas pontuáveis.
    - **O score por pergunta dos templates não é retornado.** A API devolve apenas o score final do disparo
      e, no endpoint de respostas, o **texto da resposta**, sem pontuação.
    - `countedForScore = false` indica que o trigger não conta para o score do colaborador.

    | Faixa | Intervalo | Etiqueta |
    |---|---|---|
    | `CRITICO` | 0 a 200 | Crítico |
    | `FRAGIL` | 201 a 400 | Frágil |
    | `ATENCAO` | 401 a 600 | Atenção |
    | `SAUDAVEL` | 601 a 800 | Saudável |
    | `FORTE` | 801 a 1000 | Forte |

    As faixas são uma **interpretação** usada pela plataforma; a API devolve só o número.

    ## Fases da jornada

    `ENTRY` (Entrada), `DEVELOPMENT` (Desenvolvimento) e `EXIT` (Saída). A fase pertence ao **tipo** de trigger
    e **não** é devolvida por estes endpoints. Veja a tabela tipo → fase na documentação.

    ## Paginação

    Só a visão geral é paginada (`page` 0-based e `size`). Triggers e disparos devolvem a lista completa
    da empresa, sem paginação.

    ## Rate limit

    A aplicação não impõe limite por requisição para JWT e `mct_` nestas rotas, e por isso não devolve `429` aqui.
    O limite de 120 requisições por 60 segundos por token vale apenas para tokens `bvt_`, que não são aceitos nesta API.
    A infraestrutura (proxy) pode aplicar um limite próprio que não faz parte deste contrato.
    Boa prática: no máximo 1 requisição por segundo por token e reutilize a lista de triggers, que muda raramente.

    ## Versionamento

    A versão está no prefixo do path (`/core/v1`). Campos novos opcionais podem surgir sem aviso: ignore campos
    desconhecidos. Remoção ou mudança de tipo de campo só ocorre em nova versão de path.
    `info.version` acompanha o contrato deste documento.

    ## Erros

    Não há código interno de erro. Identifique cada erro por `status` HTTP + `message`.
    Veja a tabela completa na documentação de referência.
  contact:
    name: BOOM Ops
    email: ops@deumboom.com
  license:
    name: Proprietary
    url: https://www.deumboom.com
servers:
  - url: https://api.deumboom.com
    description: Produção
  - url: https://apihomolog.deumboom.com
    description: Homologação (HML). Valide aqui antes de usar em produção.
tags:
  - name: Visão geral
    description: Colaboradores do Sensor de Jornada (`core_jornada_overview`).
  - name: Triggers
    description: Regras de jornada configuradas pela empresa (`core_jornada_triggers_list`).
  - name: Disparos
    description: Ocorrências agendadas, enviadas e respondidas (`core_jornada_disparos_list`).
  - name: Perfil do colaborador
    description: Respostas de um disparo. Ainda não exposto por uma tool do conector.
security:
  - bearerAuth: []
paths:
  /core/v1/employee/read-filter/journey-sensor:
    post:
      tags: [Visão geral]
      operationId: listJourneyOverview
      summary: Visão geral do Sensor de Jornada
      description: |
        Lista colaboradores da empresa, paginado. Tool: `core_jornada_overview`.

        **Filtros aceitos pelo conector:** `name`, `active`, `employeeClassificationList`, `departmentIdList`,
        `directorateIdList`, `businessUnitIdList`, `page`, `size`.

        **Aceitos pela API, mas não enviados pelo conector:** `allocationIdList`, `whiteLabelAIdList` … `whiteLabelEIdList`,
        `hierarchyList`, `immediateManagerIdList`.

        **Ignorados (aceitos sem erro, mas sem efeito):** `employmentStatusList` e `language`.

        Para RH Business Partner e Liderança o resultado é restrito à árvore de "reporta a" do Colaborador vinculado.
        Perfil sem Colaborador vinculado recebe página vazia.

        A resposta do conector **não** inclui CPF (hash), WhatsApp, observações nem contato alternativo.
      x-connector-tool: core_jornada_overview
      x-readonly: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JourneyOverviewRequest'
            example:
              companyId: 00000000-0000-7000-8000-00000000c001
              active: true
              employeeClassificationList: [COLABORADOR]
              page: 0
              size: 2
      responses:
        '200':
          description: Página de colaboradores.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JourneyOverviewPage'
              example:
                page: 0
                size: 2
                totalElements: 37
                totalPages: 19
                data:
                  - employeeId: 00000000-0000-7000-8000-00000000e001
                    companyId: 00000000-0000-7000-8000-00000000c001
                    name: Colaborador Exemplo A
                    email: colaborador.a@example.com
                    admissionDate: '2026-09-14'
                    language: pt-BR
                    businessUnitId: 00000000-0000-7000-8000-0000000000b1
                    businessUnitName: Unidade Exemplo
                    directorateId: 00000000-0000-7000-8000-0000000000d1
                    directorateName: Diretoria Exemplo
                    departmentId: 00000000-0000-7000-8000-0000000000a1
                    departmentName: Departamento Exemplo
                    allocationId: null
                    allocationName: null
                    teamClusterType: DEPARTMENT
                    teamId: 00000000-0000-7000-8000-0000000000a1
                    teamName: Departamento Exemplo
                    immediateManagerId: 00000000-0000-7000-8000-00000000e002
                    immediateManagerName: Líder Exemplo B
                    immediateManagerManuallySet: false
                    hierarchyLevel: NH3
                    employeeClassification: COLABORADOR
                    active: true
                    employmentStatus: ACTIVE
                    status: ONBOARDING
                    terminationDate: null
                    terminationType: null
                    createdAt: '2026-09-10T11:20:00'
                  - employeeId: 00000000-0000-7000-8000-00000000e003
                    companyId: 00000000-0000-7000-8000-00000000c001
                    name: Colaborador Exemplo C
                    email: colaborador.c@example.com
                    admissionDate: '2025-02-03'
                    language: pt-BR
                    businessUnitId: 00000000-0000-7000-8000-0000000000b1
                    businessUnitName: Unidade Exemplo
                    directorateId: 00000000-0000-7000-8000-0000000000d1
                    directorateName: Diretoria Exemplo
                    departmentId: 00000000-0000-7000-8000-0000000000a2
                    departmentName: Departamento Exemplo 2
                    allocationId: null
                    allocationName: null
                    teamClusterType: DEPARTMENT
                    teamId: 00000000-0000-7000-8000-0000000000a2
                    teamName: Departamento Exemplo 2
                    immediateManagerId: 00000000-0000-7000-8000-00000000e002
                    immediateManagerName: Líder Exemplo B
                    immediateManagerManuallySet: true
                    hierarchyLevel: NH4
                    employeeClassification: COLABORADOR
                    active: true
                    employmentStatus: ACTIVE
                    status: ACTIVE
                    terminationDate: null
                    terminationType: null
                    createdAt: '2025-01-28T09:05:00'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalError'
      x-codeSamples:
        - lang: cURL
          label: cURL
          source: |
            curl -s -X POST "https://apihomolog.deumboom.com/core/v1/employee/read-filter/journey-sensor" \
              -H "Authorization: Bearer ${BOOM_TOKEN}" \
              -H "Content-Type: application/json" \
              -d '{
                "companyId": "00000000-0000-7000-8000-00000000c001",
                "active": true,
                "employeeClassificationList": ["COLABORADOR"],
                "page": 0,
                "size": 2
              }'
        - lang: Python
          label: Python (requests)
          source: |
            import os
            import requests

            resp = requests.post(
                "https://apihomolog.deumboom.com/core/v1/employee/read-filter/journey-sensor",
                headers={"Authorization": f"Bearer {os.environ['BOOM_TOKEN']}"},
                json={
                    "companyId": "00000000-0000-7000-8000-00000000c001",
                    "active": True,
                    "employeeClassificationList": ["COLABORADOR"],
                    "page": 0,
                    "size": 2,
                },
                timeout=30,
            )
            resp.raise_for_status()
            print(resp.json()["totalElements"])
  /core/v1/journey-trigger/{companyId}:
    get:
      tags: [Triggers]
      operationId: listJourneyTriggers
      summary: Listar triggers da empresa
      description: |
        Lista todos os triggers (regras de jornada) da empresa, sem paginação. Tool: `core_jornada_triggers_list`.

        **Filtros:** nenhum. Qualquer query string é **ignorada**. O único parâmetro é o `companyId` no path.

        Triggers são **configuração**, não dado individual. Por isso RH Business Partner e Liderança
        recebem a lista completa da empresa (sem recorte de área).

        Este contrato expõe só `GET`. Criar, editar, duplicar e excluir triggers não fazem parte da API de leitura.
      x-connector-tool: core_jornada_triggers_list
      x-readonly: true
      parameters:
        - $ref: '#/components/parameters/CompanyId'
      responses:
        '200':
          description: Lista de triggers (pode ser vazia).
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/JourneyTrigger'
              example:
                - journeyTriggerId: 00000000-0000-7000-8000-0000000000f1
                  companyId: 00000000-0000-7000-8000-00000000c001
                  journeyTriggerTypeId: 00000000-0000-7000-8000-0000000001a1
                  surveyTemplateId: 00000000-0000-7000-8000-0000000002a1
                  name: Onboarding 30 dias · 30 dias
                  nameAuto: true
                  offsetDays: 30
                  milestoneQty: null
                  milestoneUnit: null
                  cycleMode: null
                  cycleDays: null
                  cycleExactDate: null
                  terminationType: null
                  responseWindowDays: 7
                  leaderResponseWindowDays: 7
                  leaderDeadlineMode: DAYS
                  reminderEveryDays: 2
                  config: null
                  active: true
                  sendToManager: true
                  countsForScore: true
                  createdAt: '2026-08-01T10:00:00'
                  effectiveFrom: '2026-08-01'
                  clusterTemplateRules: []
                - journeyTriggerId: 00000000-0000-7000-8000-0000000000f2
                  companyId: 00000000-0000-7000-8000-00000000c001
                  journeyTriggerTypeId: 00000000-0000-7000-8000-0000000001a2
                  surveyTemplateId: 00000000-0000-7000-8000-0000000002a2
                  name: Check-in periódico · 15 dias do ciclo
                  nameAuto: true
                  offsetDays: null
                  milestoneQty: null
                  milestoneUnit: null
                  cycleMode: OFFSET
                  cycleDays: 15
                  cycleExactDate: null
                  terminationType: null
                  responseWindowDays: 15
                  leaderResponseWindowDays: 15
                  leaderDeadlineMode: CYCLE_END
                  reminderEveryDays: 2
                  config: null
                  active: true
                  sendToManager: true
                  countsForScore: true
                  createdAt: '2026-08-01T10:05:00'
                  effectiveFrom: '2026-08-01'
                  clusterTemplateRules: []
                - journeyTriggerId: 00000000-0000-7000-8000-0000000000f3
                  companyId: 00000000-0000-7000-8000-00000000c001
                  journeyTriggerTypeId: 00000000-0000-7000-8000-0000000001a3
                  surveyTemplateId: 00000000-0000-7000-8000-0000000002a3
                  name: Offboarding · Voluntário
                  nameAuto: true
                  offsetDays: null
                  milestoneQty: null
                  milestoneUnit: null
                  cycleMode: null
                  cycleDays: null
                  cycleExactDate: null
                  terminationType: VOLUNTARY
                  responseWindowDays: 7
                  leaderResponseWindowDays: 7
                  leaderDeadlineMode: DAYS
                  reminderEveryDays: 2
                  config: null
                  active: false
                  sendToManager: false
                  countsForScore: false
                  createdAt: '2026-08-01T10:10:00'
                  effectiveFrom: '2026-08-01'
                  clusterTemplateRules: []
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalError'
      x-codeSamples:
        - lang: cURL
          label: cURL
          source: |
            curl -s "https://apihomolog.deumboom.com/core/v1/journey-trigger/00000000-0000-7000-8000-00000000c001" \
              -H "Authorization: Bearer ${BOOM_TOKEN}"
        - lang: Python
          label: Python (requests)
          source: |
            import os
            import requests

            company_id = "00000000-0000-7000-8000-00000000c001"
            resp = requests.get(
                f"https://apihomolog.deumboom.com/core/v1/journey-trigger/{company_id}",
                headers={"Authorization": f"Bearer {os.environ['BOOM_TOKEN']}"},
                timeout=30,
            )
            resp.raise_for_status()
            for trigger in resp.json():
                print(trigger["name"], "ativo" if trigger["active"] else "inativo")
  /core/v1/journey-dispatch/{companyId}:
    get:
      tags: [Disparos]
      operationId: listJourneyDispatches
      summary: Listar disparos da empresa
      description: |
        Lista os disparos (audiences) da empresa, sem paginação, do mais recente para o mais antigo.
        Tool: `core_jornada_disparos_list`.

        **Filtros:** nenhum. Qualquer query string é **ignorada**. O único parâmetro é o `companyId` no path.
        Filtre por colaborador, trigger, status ou período no cliente.

        Cada linha é uma ocorrência de **um** respondente. Para identificar o papel use `onBehalfOfEmployeeId`
        (preenchido = líder; `null` = colaborador).

        Registros removidos do cadastro não aparecem. Colaboradores desligados continuam aparecendo com o histórico.
        Para RH Business Partner e Liderança, só entram os disparos cujo colaborador-alvo está no recorte
        do perfil.

        Não inclui reenvio, disparo manual nem envio de notificações pendentes.
      x-connector-tool: core_jornada_disparos_list
      x-readonly: true
      parameters:
        - $ref: '#/components/parameters/CompanyId'
      responses:
        '200':
          description: Lista de disparos (pode ser vazia).
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/JourneyDispatch'
              example:
                - journeyTriggerAudienceId: 00000000-0000-7000-8000-000000000a01
                  companyId: 00000000-0000-7000-8000-00000000c001
                  companyName: Empresa Exemplo Ltda
                  employeeId: 00000000-0000-7000-8000-00000000e001
                  employeeName: Colaborador Exemplo A
                  employeeClusterName: Departamento Exemplo
                  onBehalfOfEmployeeId: null
                  onBehalfOfEmployeeName: null
                  journeyTriggerId: 00000000-0000-7000-8000-0000000000f1
                  journeyTriggerTypeId: 00000000-0000-7000-8000-0000000001a1
                  triggerName: Onboarding 30 dias · 30 dias
                  channel: EMAIL
                  channelPredicted: false
                  status: ANSWERED
                  scheduledSendAt: '2026-10-14T09:00:00'
                  sentAt: '2026-10-14T09:01:12'
                  createdAt: '2026-10-13T18:30:00'
                  secondCycleOccurrence: false
                  deadlineAt: '2026-10-21T09:00:00'
                  score: 720
                  manualDispatch: false
                  skipReason: null
                  resentAt: null
                  countedForScore: true
                - journeyTriggerAudienceId: 00000000-0000-7000-8000-000000000a02
                  companyId: 00000000-0000-7000-8000-00000000c001
                  companyName: Empresa Exemplo Ltda
                  employeeId: 00000000-0000-7000-8000-00000000e002
                  employeeName: Líder Exemplo B
                  employeeClusterName: Departamento Exemplo
                  onBehalfOfEmployeeId: 00000000-0000-7000-8000-00000000e001
                  onBehalfOfEmployeeName: Colaborador Exemplo A
                  journeyTriggerId: 00000000-0000-7000-8000-0000000000f1
                  journeyTriggerTypeId: 00000000-0000-7000-8000-0000000001a1
                  triggerName: Onboarding 30 dias · 30 dias
                  channel: EMAIL
                  channelPredicted: false
                  status: ANSWERED
                  scheduledSendAt: '2026-10-14T09:00:00'
                  sentAt: '2026-10-14T09:01:15'
                  createdAt: '2026-10-13T18:30:00'
                  secondCycleOccurrence: false
                  deadlineAt: '2026-10-21T09:00:00'
                  score: 640
                  manualDispatch: false
                  skipReason: null
                  resentAt: null
                  countedForScore: true
                - journeyTriggerAudienceId: 00000000-0000-7000-8000-000000000a03
                  companyId: 00000000-0000-7000-8000-00000000c001
                  companyName: Empresa Exemplo Ltda
                  employeeId: 00000000-0000-7000-8000-00000000e002
                  employeeName: Líder Exemplo B
                  employeeClusterName: Departamento Exemplo
                  onBehalfOfEmployeeId: 00000000-0000-7000-8000-00000000e003
                  onBehalfOfEmployeeName: Colaborador Exemplo C
                  journeyTriggerId: 00000000-0000-7000-8000-0000000000f2
                  journeyTriggerTypeId: 00000000-0000-7000-8000-0000000001a2
                  triggerName: Check-in periódico · 15 dias do ciclo
                  channel: EMAIL
                  channelPredicted: true
                  status: SENT
                  scheduledSendAt: '2026-10-05T09:00:00'
                  sentAt: null
                  createdAt: '2026-10-05T08:00:00'
                  secondCycleOccurrence: false
                  deadlineAt: '2026-12-31T23:59:59'
                  score: null
                  manualDispatch: false
                  skipReason: null
                  resentAt: null
                  countedForScore: null
                - journeyTriggerAudienceId: 00000000-0000-7000-8000-000000000a04
                  companyId: 00000000-0000-7000-8000-00000000c001
                  companyName: Empresa Exemplo Ltda
                  employeeId: 00000000-0000-7000-8000-00000000e003
                  employeeName: Colaborador Exemplo C
                  employeeClusterName: Departamento Exemplo 2
                  onBehalfOfEmployeeId: null
                  onBehalfOfEmployeeName: null
                  journeyTriggerId: 00000000-0000-7000-8000-0000000000f2
                  journeyTriggerTypeId: 00000000-0000-7000-8000-0000000001a2
                  triggerName: Check-in periódico · 15 dias do ciclo
                  channel: WHATSAPP
                  channelPredicted: false
                  status: EXPIRED
                  scheduledSendAt: '2026-09-01T09:00:00'
                  sentAt: '2026-09-01T09:02:40'
                  createdAt: '2026-09-01T08:00:00'
                  secondCycleOccurrence: false
                  deadlineAt: '2026-09-16T09:00:00'
                  score: null
                  manualDispatch: false
                  skipReason: null
                  resentAt: null
                  countedForScore: null
                - journeyTriggerAudienceId: 00000000-0000-7000-8000-000000000a05
                  companyId: 00000000-0000-7000-8000-00000000c001
                  companyName: Empresa Exemplo Ltda
                  employeeId: 00000000-0000-7000-8000-00000000e004
                  employeeName: Colaborador Exemplo D
                  employeeClusterName: Departamento Exemplo
                  onBehalfOfEmployeeId: null
                  onBehalfOfEmployeeName: null
                  journeyTriggerId: 00000000-0000-7000-8000-0000000000f3
                  journeyTriggerTypeId: 00000000-0000-7000-8000-0000000001a3
                  triggerName: Offboarding · Voluntário
                  channel: null
                  channelPredicted: false
                  status: SKIPPED
                  scheduledSendAt: '2026-10-02T09:00:00'
                  sentAt: null
                  createdAt: '2026-10-01T17:45:00'
                  secondCycleOccurrence: false
                  deadlineAt: null
                  score: null
                  manualDispatch: false
                  skipReason: TRIGGER_INACTIVE
                  resentAt: null
                  countedForScore: null
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalError'
      x-codeSamples:
        - lang: cURL
          label: cURL
          source: |
            curl -s "https://apihomolog.deumboom.com/core/v1/journey-dispatch/00000000-0000-7000-8000-00000000c001" \
              -H "Authorization: Bearer ${BOOM_TOKEN}"
        - lang: Python
          label: Python (requests)
          source: |
            import os
            import requests

            company_id = "00000000-0000-7000-8000-00000000c001"
            resp = requests.get(
                f"https://apihomolog.deumboom.com/core/v1/journey-dispatch/{company_id}",
                headers={"Authorization": f"Bearer {os.environ['BOOM_TOKEN']}"},
                timeout=30,
            )
            resp.raise_for_status()
            respondidos = [d for d in resp.json() if d["status"] == "ANSWERED"]
            print(len(respondidos), "disparos respondidos")
  /core/v1/journey-trigger-audience/answers:
    post:
      tags: [Perfil do colaborador]
      operationId: listJourneyAnswers
      summary: Respostas de disparos (perfil do colaborador)
      description: |
        Devolve as **respostas** dos disparos informados. **Ainda não exposto por uma tool do conector**: o
        conector bloqueia este path e a tool depende do card "perfil do colaborador".

        **O score por pergunta não é retornado.** Cada item traz o texto da pergunta e a resposta, nunca a pontuação.

        **Filtros:** `journeyTriggerAudienceIds` (obrigatório na prática; lista vazia devolve `[]`). Não há outros filtros.
        Disparos fora do recorte do perfil são omitidos silenciosamente (não há `403` por item).

        Use os `journeyTriggerAudienceId` obtidos em `GET /core/v1/journey-dispatch/{companyId}`.
      x-connector-tool: null
      x-readonly: true
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/JourneyAnswersRequest'
            example:
              journeyTriggerAudienceIds:
                - 00000000-0000-7000-8000-000000000a01
                - 00000000-0000-7000-8000-000000000a02
      responses:
        '200':
          description: Respostas dos disparos no recorte do perfil.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/JourneyAnswer'
              example:
                - journeyTriggerAudienceId: 00000000-0000-7000-8000-000000000a01
                  surveyQuestionId: 00000000-0000-7000-8000-0000000003a1
                  questionText: Como você avalia o acolhimento na sua chegada?
                  questionOrder: 1
                  answer: Muito bom
                - journeyTriggerAudienceId: 00000000-0000-7000-8000-000000000a01
                  surveyQuestionId: 00000000-0000-7000-8000-0000000003a2
                  questionText: Você sabe quais são suas prioridades para os próximos 30 dias?
                  questionOrder: 2
                  answer: Sim, com clareza
                - journeyTriggerAudienceId: 00000000-0000-7000-8000-000000000a02
                  surveyQuestionId: 00000000-0000-7000-8000-0000000003a3
                  questionText: Como você avalia a adaptação do colaborador?
                  questionOrder: 1
                  answer: Boa
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '500':
          $ref: '#/components/responses/InternalError'
      x-codeSamples:
        - lang: cURL
          label: cURL
          source: |
            curl -s -X POST "https://apihomolog.deumboom.com/core/v1/journey-trigger-audience/answers" \
              -H "Authorization: Bearer ${BOOM_TOKEN}" \
              -H "Content-Type: application/json" \
              -d '{"journeyTriggerAudienceIds": ["00000000-0000-7000-8000-000000000a01"]}'
        - lang: Python
          label: Python (requests)
          source: |
            import os
            import requests

            resp = requests.post(
                "https://apihomolog.deumboom.com/core/v1/journey-trigger-audience/answers",
                headers={"Authorization": f"Bearer {os.environ['BOOM_TOKEN']}"},
                json={"journeyTriggerAudienceIds": ["00000000-0000-7000-8000-000000000a01"]},
                timeout=30,
            )
            resp.raise_for_status()
            for item in resp.json():
                print(item["questionOrder"], item["answer"])
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: JWT de usuário (`eyJ…`) ou token OAuth do conector (`mct_…`). Tokens `bvt_…` não são aceitos.
  parameters:
    CompanyId:
      name: companyId
      in: path
      required: true
      description: UUID da empresa. Deve ser a empresa do usuário autenticado.
      schema:
        type: string
        format: uuid
      example: 00000000-0000-7000-8000-00000000c001
  responses:
    BadRequest:
      description: Corpo inválido ou ilegível (`Request body is invalid, verify!`) ou `Content-Type` diferente de JSON (`415`).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorBody'
          example:
            timestamp: '2026-10-16T14:55:00-03:00'
            status: 400
            error: Bad Request
            message: Request body is invalid, verify!
            path: /core/v1/employee/read-filter/journey-sensor
    Unauthorized:
      description: Token ausente, inválido ou expirado.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorBody'
          example:
            status: 401
            error: Unauthorized
            message: Token inválido ou ausente, verifique!
            path: /core/v1/journey-trigger/00000000-0000-7000-8000-00000000c001
    Forbidden:
      description: Perfil sem permissão, empresa de outra organização ou token sem contexto de usuário.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorBody'
          example:
            timestamp: '2026-10-16T14:55:00-03:00'
            status: 403
            error: Forbidden
            message: 'Access denied: No policy match'
            path: /core/v1/journey-trigger/00000000-0000-7000-8000-00000000c001
    NotFound:
      description: Rota inexistente.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorBody'
          example:
            timestamp: '2026-10-16T14:55:00-03:00'
            status: 404
            error: Not Found
            message: Resource not found, verify!
            path: /core/v1/journey-trigger
    InternalError:
      description: |
        Erro interno. **Atenção:** nestes endpoints, falhas de validação capturadas pelo controller (por exemplo
        `companyId` que não é UUID, `size` menor que 1) também voltam como `500`, com **corpo em texto simples**
        (somente a mensagem), e não no formato `ErrorBody`.
      content:
        text/plain:
          schema:
            type: string
          example: Company ID is not valid, verify!
  schemas:
    ErrorBody:
      type: object
      description: Envelope de erro. Não existe campo de código interno; identifique o erro por `status` + `message`.
      required: [status, error, message, path]
      properties:
        timestamp:
          type: string
          format: date-time
          description: Momento do erro. Pode não vir nos erros de autenticação (`401`).
        status:
          type: integer
          description: Código HTTP.
          example: 403
        error:
          type: string
          description: Descrição padrão do código HTTP.
          example: Forbidden
        message:
          type: string
          description: Mensagem do erro. É o identificador estável a usar em tratamento.
        path:
          type: string
          description: Path da requisição.
    JourneyOverviewRequest:
      type: object
      required: [companyId, page, size]
      properties:
        companyId:
          type: string
          format: uuid
          description: Empresa consultada. Deve ser a empresa do usuário.
        name:
          type: string
          description: Busca parcial, sem distinção de maiúsculas, pelo nome do colaborador.
        active:
          type: boolean
          description: '`true` = só ativos; `false` = só inativos; omitido = todos.'
        employeeClassificationList:
          type: array
          description: Classificações aceitas.
          items:
            $ref: '#/components/schemas/EmployeeClassification'
        businessUnitIdList:
          type: array
          description: UUIDs de unidades de negócio.
          items:
            type: string
            format: uuid
        directorateIdList:
          type: array
          description: UUIDs de diretorias.
          items:
            type: string
            format: uuid
        departmentIdList:
          type: array
          description: UUIDs de departamentos.
          items:
            type: string
            format: uuid
        allocationIdList:
          type: array
          description: UUIDs de alocações. Aceito pela API; o conector não envia.
          items:
            type: string
            format: uuid
        whiteLabelAIdList:
          type: array
          description: UUIDs de White Label A. Aceito pela API; o conector não envia. Vale o mesmo para `whiteLabelBIdList` … `whiteLabelEIdList`.
          items:
            type: string
            format: uuid
        hierarchyList:
          type: array
          description: Níveis hierárquicos (por exemplo, `NH3`). Aceito pela API; o conector não envia.
          items:
            type: string
        immediateManagerIdList:
          type: array
          description: UUIDs de gestores imediatos. Aceito pela API; o conector não envia.
          items:
            type: string
            format: uuid
        employmentStatusList:
          type: array
          description: '**Ignorado.** Aceito sem erro, mas não altera o resultado.'
          items:
            type: string
        language:
          type: string
          description: '**Ignorado.** Aceito sem erro, mas não altera o resultado.'
        page:
          type: integer
          minimum: 0
          default: 0
          description: Página, base 0. O conector usa `0` quando omitido.
        size:
          type: integer
          minimum: 1
          default: 20
          description: Itens por página (mínimo 1; `size` < 1 retorna `500` com a mensagem `Size is less than 1, verify!`). O conector usa `20` quando omitido. Não há teto imposto pela API.
    JourneyOverviewPage:
      type: object
      required: [page, size, totalElements, totalPages, data]
      properties:
        page:
          type: integer
          description: Página devolvida (base 0).
          example: 0
        size:
          type: integer
          description: Quantidade de itens **nesta página** (não o tamanho solicitado).
          example: 2
        totalElements:
          type: integer
          format: int64
          description: Total de colaboradores que atendem ao filtro e ao recorte do perfil.
          example: 37
        totalPages:
          type: integer
          description: Total de páginas para o `size` solicitado.
          example: 19
        data:
          type: array
          items:
            $ref: '#/components/schemas/JourneyEmployee'
    JourneyEmployee:
      type: object
      description: |
        Colaborador na visão geral. Campos de contato pessoal e dados sensíveis não fazem parte do contrato
        (CPF, WhatsApp, data de nascimento, observações, contato alternativo e canal de disparo).
      properties:
        employeeId:
          type: string
          format: uuid
          description: Identificador do colaborador.
        companyId:
          type: string
          format: uuid
          description: Empresa do colaborador.
        name:
          type: string
          description: Nome do colaborador.
        email:
          type: string
          nullable: true
          description: E-mail corporativo.
        admissionDate:
          type: string
          format: date
          nullable: true
          description: Data de admissão (`YYYY-MM-DD`).
        language:
          type: string
          nullable: true
          description: Idioma do colaborador (por exemplo, `pt-BR`).
        businessUnitId:
          type: string
          format: uuid
          nullable: true
          description: Unidade de negócio (UUID).
        businessUnitName:
          type: string
          nullable: true
          description: Unidade de negócio (nome).
        directorateId:
          type: string
          format: uuid
          nullable: true
          description: Diretoria (UUID).
        directorateName:
          type: string
          nullable: true
          description: Diretoria (nome).
        departmentId:
          type: string
          format: uuid
          nullable: true
          description: Departamento (UUID).
        departmentName:
          type: string
          nullable: true
          description: Departamento (nome).
        allocationId:
          type: string
          format: uuid
          nullable: true
          description: Alocação (UUID).
        allocationName:
          type: string
          nullable: true
          description: Alocação (nome).
        whiteLabelAId:
          type: string
          format: uuid
          nullable: true
          description: White Label A (UUID). Existem campos equivalentes `whiteLabelB…E` (Id e Name).
        whiteLabelAName:
          type: string
          nullable: true
          description: White Label A (nome).
        teamClusterType:
          $ref: '#/components/schemas/ClusterType'
        teamId:
          type: string
          format: uuid
          nullable: true
          description: Cluster mais específico do colaborador (UUID).
        teamName:
          type: string
          nullable: true
          description: Cluster mais específico do colaborador (nome).
        immediateManagerId:
          type: string
          format: uuid
          nullable: true
          description: Gestor imediato (UUID). É quem responde como líder.
        immediateManagerName:
          type: string
          nullable: true
          description: Gestor imediato (nome).
        immediateManagerManuallySet:
          type: boolean
          nullable: true
          description: '`true` se o gestor foi definido manualmente; `false` se foi calculado pela hierarquia.'
        hierarchyLevel:
          type: string
          nullable: true
          description: Nível hierárquico (por exemplo, `NH3`).
        employeeClassification:
          $ref: '#/components/schemas/EmployeeClassification'
        active:
          type: boolean
          description: Colaborador ativo na base.
        employmentStatus:
          type: string
          nullable: true
          description: Situação contratual (por exemplo, `ACTIVE`).
        status:
          $ref: '#/components/schemas/EmployeeStatus'
        leaveType:
          type: string
          nullable: true
          description: Tipo de afastamento, quando houver.
        leaveStartDate:
          type: string
          format: date
          nullable: true
          description: Início do afastamento.
        leaveExpectedReturnDate:
          type: string
          format: date
          nullable: true
          description: Retorno previsto do afastamento.
        leaveActualReturnDate:
          type: string
          format: date
          nullable: true
          description: Retorno efetivo do afastamento.
        terminationDate:
          type: string
          format: date
          nullable: true
          description: Data de desligamento, quando houver.
        terminationType:
          $ref: '#/components/schemas/TerminationType'
        createdAt:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$'
          description: Criação do cadastro (horário de Brasília, sem offset).
    JourneyTrigger:
      type: object
      description: Regra de jornada configurada pela empresa.
      properties:
        journeyTriggerId:
          type: string
          format: uuid
          description: Identificador do trigger.
        companyId:
          type: string
          format: uuid
          description: Empresa dona do trigger.
        journeyTriggerTypeId:
          type: string
          format: uuid
          description: Tipo do trigger (define a fase e o tipo de temporização). Veja a tabela tipo → fase.
        surveyTemplateId:
          type: string
          format: uuid
          nullable: true
          description: Template padrão do trigger.
        name:
          type: string
          nullable: true
          description: Nome do trigger. Quando `nameAuto` é `true` é o nome gerado a partir do tipo e da temporização.
        nameAuto:
          type: boolean
          description: '`true` = nome gerado automaticamente; `false` = nome definido pela empresa.'
        offsetDays:
          type: integer
          nullable: true
          description: Dias após a admissão (tipos de temporização `OFFSET_DAYS`, como Onboarding 30 e 75).
        milestoneQty:
          type: integer
          nullable: true
          description: Quantidade do marco (tipos `MILESTONE`, como Aniversário de admissão).
        milestoneUnit:
          type: string
          nullable: true
          enum: [DIAS, MESES, ANOS, null]
          description: Unidade do marco.
        cycleMode:
          type: string
          nullable: true
          enum: [OFFSET, EXACT, null]
          description: 'Tipos de ciclo: `OFFSET` = dias a partir do início do ciclo; `EXACT` = data exata.'
        cycleDays:
          type: integer
          nullable: true
          description: Dias do ciclo, quando `cycleMode = OFFSET`.
        cycleExactDate:
          type: string
          nullable: true
          description: Data exata, quando `cycleMode = EXACT`.
        terminationType:
          $ref: '#/components/schemas/TerminationType'
        responseWindowDays:
          type: integer
          description: Prazo de resposta do colaborador, em dias (mínimo 1; padrão 7).
        leaderResponseWindowDays:
          type: integer
          description: Prazo de resposta do líder, em dias. Igual ao do colaborador quando não definido.
        leaderDeadlineMode:
          type: string
          enum: [DAYS, CYCLE_END]
          description: '`DAYS` = prazo do líder em dias; `CYCLE_END` = prazo termina no fim do ciclo (só triggers de ciclo).'
        reminderEveryDays:
          type: integer
          description: Intervalo, em dias, entre lembretes. `0` = sem lembrete periódico.
        config:
          type: object
          nullable: true
          additionalProperties: true
          description: Filtro de público do trigger, com chaves `included` e `excluded` por tipo de cluster. `null` = todos.
        active:
          type: boolean
          description: |
            Estado do trigger. **Não existe enum de status de trigger**: `true` = gera disparos;
            `false` = não gera (disparos previstos aparecem como `SKIPPED` com `TRIGGER_INACTIVE`).
        sendToManager:
          type: boolean
          description: '`true` = o gestor imediato também responde (disparo do líder). Sempre `true` em triggers de ciclo.'
        countsForScore:
          type: boolean
          description: '`true` = as respostas deste trigger entram no score do colaborador.'
        createdAt:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$'
          description: Criação do trigger.
        effectiveFrom:
          type: string
          format: date
          nullable: true
          description: Data a partir da qual o trigger vale. Antes dela os disparos saem como `SKIPPED` com `BEFORE_EFFECTIVE_DATE`.
        clusterTemplateRules:
          type: array
          description: Regras que trocam o template por cluster.
          items:
            $ref: '#/components/schemas/JourneyTriggerClusterTemplateRule'
    JourneyTriggerClusterTemplateRule:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Identificador da regra.
        clusterType:
          $ref: '#/components/schemas/ClusterType'
        clusterValues:
          type: array
          nullable: true
          description: UUIDs dos clusters aos quais a regra se aplica.
          items:
            type: string
        surveyTemplateId:
          type: string
          format: uuid
          nullable: true
          description: Template usado nos clusters da regra.
    JourneyDispatch:
      type: object
      description: |
        Uma ocorrência de disparo para **um** respondente. O papel é derivado: `onBehalfOfEmployeeId` preenchido = líder;
        `null` = colaborador.
      properties:
        journeyTriggerAudienceId:
          type: string
          format: uuid
          description: Identificador do disparo.
        companyId:
          type: string
          format: uuid
          description: Empresa.
        companyName:
          type: string
          nullable: true
          description: Nome da empresa.
        employeeId:
          type: string
          format: uuid
          description: 'Quem **recebe e responde** este disparo (colaborador ou líder).'
        employeeName:
          type: string
          nullable: true
          description: Nome de quem recebe.
        employeeClusterName:
          type: string
          nullable: true
          description: Cluster mais específico de quem recebe.
        onBehalfOfEmployeeId:
          type: string
          format: uuid
          nullable: true
          description: Preenchido = disparo do **líder**, que responde em nome deste colaborador. `null` = disparo do próprio colaborador.
        onBehalfOfEmployeeName:
          type: string
          nullable: true
          description: Nome do colaborador avaliado pelo líder.
        journeyTriggerId:
          type: string
          format: uuid
          nullable: true
          description: Trigger de origem.
        journeyTriggerTypeId:
          type: string
          format: uuid
          nullable: true
          description: Tipo do trigger (define a fase).
        triggerName:
          type: string
          nullable: true
          description: Nome de exibição do trigger.
        channel:
          type: string
          nullable: true
          enum: [EMAIL, WHATSAPP, SLACK, TEAMS, null]
          description: Canal. `null` quando o disparo foi pulado ou nenhum canal pôde ser resolvido.
        channelPredicted:
          type: boolean
          description: '`true` = canal previsto (ainda não houve envio); `false` = canal do último envio.'
        status:
          $ref: '#/components/schemas/DispatchStatus'
        scheduledSendAt:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$'
          nullable: true
          description: Data e hora agendadas para o envio (horário de Brasília, sem offset). O envio ocorre a partir das 09:00 de dia útil.
        sentAt:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$'
          nullable: true
          description: Data e hora do último envio. `null` se nunca enviado.
        createdAt:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$'
          description: Criação do registro de disparo.
        secondCycleOccurrence:
          type: boolean
          description: '`true` = segunda rodada do Check-in periódico.'
        deadlineAt:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$'
          nullable: true
          description: Prazo de resposta. Pode ser `null` (por exemplo, disparo pulado ou sem prazo definido).
        score:
          type: integer
          nullable: true
          minimum: 0
          maximum: 1000
          description: Score BOOM do disparo (0 a 1000). `null` se não respondido ou sem perguntas pontuáveis. **Não é score por pergunta.**
        manualDispatch:
          type: boolean
          description: '`true` = disparo liberado por decisão manual do RH.'
        skipReason:
          $ref: '#/components/schemas/SkipReason'
        resentAt:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?$'
          nullable: true
          description: Data do último reenvio manual, quando houve.
        countedForScore:
          type: boolean
          nullable: true
          description: Definido quando o disparo é respondido. `false` = o trigger não conta para o score. `null` = ainda não respondido.
    JourneyAnswersRequest:
      type: object
      required: [journeyTriggerAudienceIds]
      properties:
        journeyTriggerAudienceIds:
          type: array
          description: Disparos cujas respostas serão lidas.
          items:
            type: string
            format: uuid
    JourneyAnswer:
      type: object
      description: Resposta a uma pergunta. **Não contém score.**
      properties:
        journeyTriggerAudienceId:
          type: string
          format: uuid
          description: Disparo ao qual a resposta pertence.
        surveyQuestionId:
          type: string
          format: uuid
          description: Pergunta respondida.
        questionText:
          type: string
          nullable: true
          description: Texto da pergunta.
        questionOrder:
          type: integer
          nullable: true
          description: Posição da pergunta no questionário.
        answer:
          type: string
          nullable: true
          description: Resposta registrada (texto, opção escolhida ou valor numérico em texto).
    DispatchStatus:
      type: string
      description: |
        Status do disparo.

        | Valor | Significado |
        |---|---|
        | `PENDING` | Agendado, ainda não enviado |
        | `SENT` | Enviado, aguardando resposta |
        | `ANSWERED` | Respondido (pode ter `score`) |
        | `EXPIRED` | Prazo vencido sem resposta |
        | `FAILED` | Falha no envio (o sistema tenta de novo) |
        | `SKIPPED` | Não enviado; veja `skipReason` |
      enum: [PENDING, SENT, ANSWERED, EXPIRED, FAILED, SKIPPED]
    SkipReason:
      type: string
      nullable: true
      description: |
        Motivo do `SKIPPED`. `null` nos demais status.

        | Valor | Significado |
        |---|---|
        | `OUTSIDE_WINDOW` | Fora da janela de envio do trigger |
        | `BEFORE_EFFECTIVE_DATE` | Anterior à data de vigência (`effectiveFrom`) |
        | `TRIGGER_INACTIVE` | Trigger inativo |
        | `HR_DECISION` | RH decidiu não enviar |
      enum: [OUTSIDE_WINDOW, BEFORE_EFFECTIVE_DATE, TRIGGER_INACTIVE, HR_DECISION, null]
    EmployeeClassification:
      type: string
      description: Papel do colaborador na hierarquia.
      enum: [LIDERANCA, COLABORADOR]
    EmployeeStatus:
      type: string
      description: Situação do colaborador na jornada.
      enum: [ONBOARDING, ACTIVE, AFASTADO, DESLIGADO, INATIVO_LEGADO]
    TerminationType:
      type: string
      nullable: true
      description: Tipo de desligamento.
      enum: [VOLUNTARY, INVOLUNTARY, END_OF_CONTRACT, RETIREMENT, null]
    ClusterType:
      type: string
      nullable: true
      description: Tipo de cluster.
      enum: [BUSINESS_UNIT, DIRECTORATE, DEPARTMENT, ALLOCATION, WHITE_LABEL_A, WHITE_LABEL_B, WHITE_LABEL_C, WHITE_LABEL_D, WHITE_LABEL_E, null]
