Runbook - Horários de atendimento do Sagazchat

Manual operacional para configurar Configurações Horários no Sagazchat. Horários sao configurados por canal (WhatsApp, Instagram, E-mail, Widget), nao por empresa nem por departame

8 min de leitura Atualizado em 14 de mai. de 2026

Manual operacional para configurar Configurações > Horários no Sagazchat. Horários sao configurados por canal (WhatsApp, Instagram, E-mail, Widget), nao por empresa nem por departamento.

Status: validado em 2026-05-11 na conta exemplo. Toggle “Ativar atendimento” e radio Mensagem/Fluxo nao disparam network — sao estado local ate clicar Salvar.

1. Onde fica

  • Sidebar: Configurações > Horários
  • URL: https://app.sagazchat.com/office-hours
  • Endpoint backend: a confirmar (provavelmente /office-hours ou /business-hours).

2. Estrutura da tela

Layout em duas colunas:

  • Esquerda: card Canais com descricao + lista de cards (um por canal conectado).
  • Direita: painel de configuracao do canal selecionado (vazio ate clicar num card).

Lista de canais

Cada card de canal mostra:

  • icone do tipo (WhatsApp, Instagram, etc);
  • nome do canal (ex: exemplo);
  • badge Atendimento ativo ou Atendimento inativo.

Card selecionado fica com fundo preto destacado.

3. Estado inicial de um canal

Quando o canal nao tem horarios configurados, o painel direito mostra:

  • titulo com o nome do canal;
  • icone de chat + label Atendimento inativo;
  • botao Ativar atendimento (azul).

Canal com atendimento inativo

Clicar Ativar atendimento muda o estado localmente (so persiste no Salvar) e revela os campos de configuracao.

4. Definicao de horarios

Apos ativar, abre a secao Definição de horários com 7 linhas — uma por dia da semana:

ColunaO que faz
Dia da semanaLabel fixo: Segunda-feira a Domingo.
StatusFechado (default) ou Aberto.
SwitchLiga o dia. Quando off, o dia fica fechado.
Hora inicialInput hh:mm (placeholder).
Hora finalInput hh:mm (placeholder).

Canal ativo com 7 dias da semana

Quirk: cada dia tem apenas UM intervalo (hora inicial + final). Nao existe campo para intervalo de almoco/almocos secundarios. Se o expediente for 08:00–12:00 e 13:00–18:00, e necessario:

  • usar 08:00–18:00 continuo e tratar o intervalo via IA/fluxo, OU
  • aceitar que o intervalo de almoco fica “dentro” do horario de atendimento.

5. Acao quando estiver fora do horario

Abaixo de Definição de horários aparece a secao Ação. Define o que fazer quando alguem manda mensagem fora do expediente.

Dois modos exclusivos (radio):

5.1 Mensagem (default)

Acao = Mensagem

  • Radio Mensagem selecionado.
  • Abre textarea para digitar a resposta automatica.
  • Mensagem e enviada para o cliente quando ele escreve fora do horario.

5.2 Fluxo

Acao = Fluxo

  • Radio Fluxo selecionado.
  • Substitui o textarea por combobox Escolha um fluxo (alimentado por /flowbuilder/all/get).
  • Quando alguem escreve fora do horario, o fluxo dispara automaticamente (pode coletar dados, dar opcoes, marcar etiquetas etc).

O radio config.type tem valores "msg" (Mensagem) e "flow" (Fluxo).

6. Salvar

Botao Salvar verde no final da pagina. So depois de clicar nele a configuracao e persistida no backend. Antes disso, mudancas sao apenas locais — recarregar a pagina volta tudo ao estado anterior.

6.1 Endpoint validado

POST https://backend.sagazchat.com/outOfHours
Authorization: Bearer <jwt>
Content-Type: application/json

Resposta: 200 + corpo "APPLY" (string literal entre aspas, nao objeto).

6.2 Payload completo (validado 2026-05-11)

{
  "config": {
    "whatsappId": 216,
    "waOficialId": 0,
    "type": "msg",
    "flowId": 0,
    "msg": "Estamos fechados, voltamos amanha as 9h",
    "active": true
  },
  "monday":    { "open": true,  "openTime": "2026-05-11T12:00:00.000Z", "closeTime": "2026-05-11T21:00:00.000Z" },
  "tuesday":   { "open": false, "openTime": null, "closeTime": null },
  "wednsday":  { "open": false, "openTime": null, "closeTime": null },
  "thursday":  { "open": false, "openTime": null, "closeTime": null },
  "friday":    { "open": false, "openTime": null, "closeTime": null },
  "saturday":  { "open": false, "openTime": null, "closeTime": null },
  "sunday":    { "open": false, "openTime": null, "closeTime": null }
}

6.3 Quirks do payload (importantes!)

QuirkDetalhe
Nome do endpoint/outOfHours (camelCase, sem hifen). NAO e /office-hours como a rota UI sugere.
TYPO wednsdayA chave de quarta-feira no payload e wednsday (faltando o e antes do s). Quem chamar a API via codigo precisa enviar exatamente como o backend espera, com o typo. As outras chaves estao corretas: monday, tuesday, thursday, friday, saturday, sunday.
Horarios em ISO UTCopenTime/closeTime sao ISO 8601 UTC. O frontend converte o hh:mm local para UTC ao enviar (ex: 09:00 BRT2026-05-11T12:00:00.000Z). Quem chamar a API direta precisa fazer a mesma conversao.
Data no horarioA data da string ISO e o “dia atual” — o backend ignora a data e usa so o time. Mas o frontend sempre envia uma data valida.
config.typeStrings literais: "msg" (Mensagem) ou "flow" (Fluxo).
config.activeToggle “Ativar atendimento” / “Desativar atendimento”. false mantem o resto do payload salvo mas inativa a regra.
config.whatsappIdID do canal — vem de /whatsapp ou similar. No teste lab: 216.
config.waOficialIdPara canais WA Oficial; senao 0.
config.flowIdID do fluxo selecionado quando type=flow. 0 quando type=msg.
Resposta "APPLY"String literal entre aspas, nao um objeto JSON. Frontend nao usa nada do corpo, so o status 200.

6.4 Payload com Fluxo (type=flow)

Quando config.type === "flow", os campos mudam:

"config": {
  "whatsappId": 216,
  "waOficialId": 0,
  "type": "flow",
  "flowId": 540,
  "msg": "",
  "active": true
}
CampoComportamento
type"flow" em vez de "msg".
flowIdID inteiro do fluxo selecionado no combobox. Quando type=msg, fica 0.
msgString vazia (frontend nao envia o texto da textarea quando o radio esta em Fluxo).

Lista de fluxos vem de GET /flowbuilder/all/get (o mesmo endpoint usado pelo combobox em Remarketing e Acao do Flowbuilder).

6.5 Comportamento ao desativar

Quando o usuario clica Desativar atendimento + Salvar, o payload ainda inclui toda a configuracao previa — apenas config.active vai a false. Significa que a config fica memorizada e e reativada se clicar Ativar de novo (sem precisar reconfigurar dias/horarios/mensagem).

Para “esquecer” config previa, e preciso ativar, desligar todos os dias, limpar mensagem, e so depois desativar + salvar.

7. Acoes seguras e perigosas

AcaoImpactoRegra
Abrir /office-hoursLeituraSeguro.
Selecionar canalCarrega painelSeguro.
Toggle Ativar atendimentoApenas localSeguro (so persiste no Salvar).
Toggle dia da semanaApenas localSeguro.
Trocar radio Mensagem ↔ FluxoApenas localSeguro.
Clicar SalvarPersiste no backendCuidado: afeta atendimento real imediatamente — clientes fora do horario passam a receber a mensagem/fluxo configurado.
Clicar Desativar atendimento + SalvarTira horario do canalDestrutivo: clientes fora do horario voltam a nao receber ausencia.

8. Quirks descobertos

  • Endpoint /outOfHours (camelCase) — nome diverge da rota UI /office-hours.
  • TYPO wednsday no payload — sem e entre wedn e sday. Outras chaves de dias estao corretas.
  • Horarios em ISO UTC: o frontend converte hh:mm local pra UTC ao enviar. API direta precisa fazer o mesmo.
  • Resposta "APPLY" (string literal, nao JSON object).
  • Desativar nao limpa a config — apenas marca active: false. Reativar traz tudo de volta.
  • Horarios sao por canal, nao por departamento. Departamentos tem schedules no payload do POST /queue (ver runbook departamentos) com defaults Seg-Sex 08-18, mas nao foi achada UI para edita-los. Hipoteses: ou e configurado via API, ou ha uma area secundaria nao mapeada.
  • Toggle “Ativar atendimento” e estado local; so persiste com Salvar.
  • Cada dia tem 1 intervalo apenas (sem horarios partidos para almoco).
  • Card do canal selecionado fica com fundo preto (nao laranja/azul como em outros modulos MUI).
  • Sem botao Cancelar: para descartar mudancas, sair da pagina antes de Salvar. Recarregar volta ao estado salvo.

9. Snippets

9.1 Listar canais e estado

// /office-hours alimenta a UI a partir de /whatsapp, /waoficial, /instagram, /email etc.
// O estado "Atendimento ativo/inativo" provavelmente vem de um campo `officeHoursActive`
// ou similar dentro de cada canal. Verificar com:
const v = localStorage.getItem('token');
const token = v?.startsWith('"') ? JSON.parse(v) : v;
const res = await fetch('https://backend.sagazchat.com/whatsapp', {
  headers: { Authorization: `Bearer ${token}` },
});
console.log(await res.json());

[a validar] endpoint exato e nome dos campos.

9.2 Salvar horarios via API

[a validar] — capturar quando rodar Salvar uma vez.

10. Pendencias

  • Endpoint exato do Salvar e payload.
  • Onde ficam os schedules de departamento (visiveis no POST /queue mas sem UI obvia).
  • Comportamento se canal tem multiplos numeros vinculados.
  • Validar diferenca entre WhatsApp QR e WhatsApp Oficial.

11. Imagens

  • public/media/nova-ui/horarios-lista-canais.png
  • public/media/nova-ui/horarios-canal-inativo.png
  • public/media/nova-ui/horarios-canal-ativo.png
  • public/media/nova-ui/horarios-acao-mensagem.png
  • public/media/nova-ui/horarios-acao-fluxo.png

12. Scripts validados

node scripts/sagaz-horarios-mapear.mjs            # lista de canais
node scripts/sagaz-horarios-canal-v3.mjs          # abrir canal inativo
node scripts/sagaz-horarios-ativar.mjs            # ativar atendimento (local)
node scripts/sagaz-horarios-acao-fluxo.mjs        # toggle radio Mensagem/Fluxo