rotas.md 25 KB

Análise da Codebase e Contrato Backend → Frontend

Objetivo

Este documento resume a análise da codebase do projeto e define o que o backend precisa entregar para o frontend.

Hoje o backend tem apenas as rotas:

  • POST /login
  • POST /register

Mas o frontend já possui diversas telas prontas. Portanto, este arquivo serve como mapa de implementação do backend, indicando:

  • o estado atual do projeto;
  • o que cada tela do frontend precisa receber;
  • quais endpoints precisam existir;
  • quais formatos de payload e resposta são recomendados;
  • quais partes da modelagem atual já suportam isso e quais ainda não suportam.

1. Estrutura da codebase

Frontend

Pasta: nettown_frontend

Stack identificada:

  • SvelteKit
  • adapter-static
  • Svelte 5
  • Tailwind
  • layerchart
  • lucide-svelte

Achados principais do frontend

  • O frontend está visualmente completo para várias áreas do produto.
  • O frontend está quase 100% mockado.
  • Não existe client HTTP real no frontend hoje.
  • Não há fetch, axios, Authorization ou persistência de JWT implementados nas telas principais.
  • A tela de login ainda usa validação mockada:
    • e-mail: admin@nettown.com
    • senha: admin
  • Várias telas consomem dados de:
    • src/lib/core/models/mock-data.js
    • src/lib/features/sentiment/data/sentiment-dashboard.mock.js
  • Existem rotas duplicadas em PT/EN para algumas telas:
    • profile e perfil
    • subscription e assinatura
    • help e ajuda

Conclusão sobre o frontend

O frontend está pronto como produto visual e funcional local, mas não está integrado ao backend.

Ou seja:

  • a parte de layout/componentes está pronta;
  • a parte de contratos de API ainda precisa ser implementada.

Backend

Pasta: php_api

Stack identificada:

  • PHP
  • FrameworkX
  • Firebase JWT
  • PostgreSQL
  • PDO

Rotas atuais do backend

  • POST /login
  • POST /register
  • GET /jwthelloworld protegido por JWT

Padrão de resposta atual do backend

O backend hoje responde com envelope padrão:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {}
}

Em erro:

{
  "status": "failed",
  "msg": "mensagem de erro",
  "code": "E_VALIDATE",
  "data": {}
}

Autenticação atual

  • Login usa email + password.
  • JWT contém:
    • sub
    • email
    • company_id
    • role
  • Middleware JWT valida usuário ativo por user_deleted_at = 'infinity'.

Conclusão sobre o backend

O backend já está preparado para:

  • autenticação com JWT;
  • conexão PostgreSQL;
  • leitura do banco novo.

Mas a camada de API de produto ainda não foi construída.


2. Banco atual vs necessidade do frontend

Tabelas que já suportam bem o frontend

  • company
  • user
  • operator
  • operator_channel
  • sla_config
  • integration
  • client
  • conversation
  • message
  • message_attachment
  • message_reaction
  • conversation_participant
  • webhook_event
  • conversation_analysis
  • aspect_feedback
  • emotion_snapshot
  • public_opinion
  • alert
  • ai_action
  • persona
  • client_persona
  • best_action
  • volume_snapshot
  • sentiment_evolution
  • playbooks_monitor
  • operator_daily_stats
  • kpi_snapshot

Gaps entre frontend e schema atual

Estas são as principais lacunas identificadas:

  • Filtro de unidade

    • O frontend usa filtro de unidade em várias telas.
    • O schema atual não tem tabela explícita de unidade/loja/filial.
  • Configuração de alerta de SLA por percentual

    • A tela de SLA usa alertPct.
    • A tabela sla_config hoje guarda apenas:
    • sla_config_response_hours
    • sla_config_resolution_hours
    • Não existe coluna de percentual de alerta.
  • Configurações / notificações

    • O frontend de configurações mostra preferências e integrações.
    • O schema atual não tem tabela dedicada para preferências/notificações.
  • Assinatura / billing

    • O frontend possui telas de assinatura e planos.
    • O schema atual não tem modelagem de assinatura/plano/cobrança.
  • Ajuda / FAQ / suporte

    • O frontend tem tela pronta.
    • Isso pode ser estático, mas não existe modelagem específica hoje.

3. Mapa de telas do frontend

Públicas

  • /

    • landing page institucional
    • não depende de backend para funcionar
  • /login

    • hoje mockada
    • deve passar a consumir POST /login

Privadas

  • /dashboard
  • /dashboard/interactions
  • /dashboard/analytics
  • /dashboard/personas
  • /dashboard/evolucao
  • /dashboard/executive
  • /dashboard/agents
  • /dashboard/sla
  • /dashboard/settings
  • /dashboard/profile
  • /dashboard/subscription
  • /dashboard/help

Rotas duplicadas equivalentes:

  • /dashboard/perfil
  • /dashboard/assinatura
  • /dashboard/ajuda

4. Situação real por tela

4.1 Login

Estado atual

  • tela pronta;
  • autenticação ainda fake;
  • não salva token;
  • não consulta GET /me;
  • não protege navegação real por sessão.

Backend precisa entregar

  • POST /login
  • GET /me

Contrato recomendado

POST /login

Request:

{
  "email": "admin@empresa.com",
  "password": "12345678"
}

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "token": "jwt-token",
    "user": {
      "user_id": 1,
      "company_id": 1,
      "user_name": "Admin",
      "user_phone": "5511999999999",
      "user_email": "admin@empresa.com",
      "user_role": "admin",
      "user_created_at": "2026-05-25T10:00:00Z"
    }
  }
}

GET /me

Objetivo:

  • reidratar sessão no refresh da página;
  • preencher header do app;
  • popular perfil.

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "user_id": 1,
    "company_id": 1,
    "user_name": "Admin",
    "user_phone": "5511999999999",
    "user_email": "admin@empresa.com",
    "user_role": "admin",
    "company": {
      "company_id": 1,
      "company_name": "Empresa X",
      "company_cnpj": "12345678000199",
      "company_logo": "https://..."
    }
  }
}

4.2 Dashboard principal (/dashboard)

Estado atual

Hoje a tela usa mocks para:

  • KPIs do topo;
  • fila priorizada;
  • radar emocional;
  • volume por canal;
  • distribuição por aspectos;
  • drilldown por aspecto.

Backend precisa entregar

GET /dashboard/overview

Query params sugeridos:

  • period=today|yesterday|week
  • unit=all|flagship|franquias|pop-up|digital
  • area=all|atendimento|produto|logistica|marketing
  • sentiment=all|positive|neutral|negative
  • volume_view=hour|day

Response recomendada

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "kpis": {
      "registeredUsers": 55,
      "activeAgents": 4,
      "totalConversations": 418,
      "generalSentimentScore": 0.1,
      "unregisteredUsers": 149682
    },
    "priorityQueue": [
      {
        "id": 1,
        "customerName": "Carolina Ribeiro",
        "segment": "Elegante Estratégica",
        "status": "VENDEDORA NÃO RESPONDEU",
        "slaStatus": "SLA 12h estourado",
        "timeAgo": "há 18h",
        "sellerName": "Maria",
        "lastMessage": "Não tem no meu tamanho 40?",
        "motive": "Pediu tamanho indisponível — reservar/repor",
        "impact": 8639,
        "ticket": 879,
        "chance": 82,
        "optimumWindow": "6h",
        "score": 7084,
        "conversationId": 101,
        "clientId": 51,
        "operatorId": 7
      }
    ],
    "radarData": [
      { "name": "Confiança", "value": 45 },
      { "name": "Alegria", "value": 100 },
      { "name": "Antecipação", "value": 41 },
      { "name": "Medo", "value": 18 },
      { "name": "Tristeza", "value": 3 },
      { "name": "Raiva", "value": 13 }
    ],
    "volumeData": [
      { "date": "2026-05-02T11:00:00Z", "whatsapp": 10 },
      { "date": "2026-05-02T12:00:00Z", "whatsapp": 230 }
    ],
    "aspectsData": [
      { "aspect": "Atendimento", "positive": 350, "neutral": 50, "negative": 20 },
      { "aspect": "Produto", "positive": 130, "neutral": 30, "negative": 40 }
    ],
    "aspectsDrilldown": {
      "Atendimento": {
        "positive": [
          { "label": "Satisfação com atendimento", "value": 285 }
        ],
        "neutral": [],
        "negative": []
      }
    }
  }
}

Fontes no banco

  • kpi_snapshot
  • alert
  • conversation
  • client
  • operator
  • emotion_snapshot
  • volume_snapshot
  • conversation_analysis

4.3 Interações (/dashboard/interactions)

Estado atual

Hoje a tela mostra:

  • listagem de conversas analisadas;
  • filtros rápidos;
  • modal com chat;
  • mini relatório lateral.

Backend precisa entregar

  • GET /interactions
  • GET /interactions/details

GET /interactions

Query params sugeridos:

  • page
  • per_page
  • search
  • filter=all|my_clients|new|unfinished
  • sentiment
  • operator_id
  • company_id

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "items": [
      {
        "conversationId": 201,
        "client": "554196690452",
        "agent": "Leticia",
        "sentiment": "CONTENTAMENTO",
        "score": 0.5,
        "aspect": "Atendimento",
        "subaspect": "Informativo",
        "datetime": "2026-05-02T19:59:00Z"
      }
    ],
    "pagination": {
      "page": 1,
      "per_page": 20,
      "total": 120,
      "total_pages": 6
    }
  }
}

GET /interactions/details

Query params sugeridos:

  • conversation_id

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "conversation": {
      "conversationId": 201,
      "client": "554196690452",
      "channel": "WhatsApp",
      "agent": "Leticia"
    },
    "thread": [
      {
        "id": "m1",
        "isAgent": false,
        "text": "Oi, queria saber se esse look chega na loja física.",
        "time": "19:58",
        "date": "2026-05-02"
      },
      {
        "id": "m2",
        "isAgent": true,
        "text": "Chega sim, posso te mostrar opções.",
        "time": "19:59",
        "date": "2026-05-02"
      }
    ],
    "report": {
      "avgResponse": "04:03",
      "totalDuration": "08:28",
      "avgAgent": "00:00",
      "avgClient": "08:05",
      "mainAspect": "Atendimento",
      "subAspect": "Informativo",
      "lastMessageAuthor": "Cliente",
      "consecutiveMessages": false,
      "sentiment": "CONTENTAMENTO",
      "score": 0.5
    }
  }
}

Fontes no banco

  • conversation
  • message
  • conversation_analysis
  • client
  • operator

4.4 Análise de sentimento (/dashboard/analytics)

Estado atual

Hoje a tela trabalha com um view model único contendo:

  • cards-resumo;
  • alertas;
  • linha temporal de ganhos/perdas;
  • lista de aspectos com frases reais.

Backend precisa entregar

GET /analytics/sentiment/dashboard

Query params sugeridos:

  • timeframe=day|week|month
  • company_id
  • aspect
  • sentiment

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "summaryCards": [
      {
        "id": "atRiskClients",
        "label": "Clientes em risco",
        "value": 23,
        "image": "/images/sentiment/risk.svg"
      },
      {
        "id": "opportunities",
        "label": "Oportunidades",
        "value": 41,
        "image": "/images/sentiment/opportunity.svg"
      }
    ],
    "alerts": [
      {
        "id": "alert-1",
        "clientId": 12,
        "clientName": "Grupo Horizonte",
        "title": "Grupo Horizonte com alta chance de churn",
        "description": "Queda de engajamento nas últimas 2 semanas.",
        "priority": "high",
        "priorityLabel": "Alta prioridade",
        "category": "churn_risk"
      }
    ],
    "timelineViews": {
      "day": [
        { "period": "Dia 1", "gains": 28, "losses": 12 }
      ],
      "week": [
        { "period": "Sem 1", "gains": 38, "losses": 16 }
      ],
      "month": [
        { "period": "Jan", "gains": 180, "losses": 75 }
      ]
    },
    "aspects": [
      {
        "id": "atendimento",
        "name": "Atendimento",
        "volume": 14,
        "positive": [
          { "text": "Fui respondida super rápido.", "client": "Maria Silva" }
        ],
        "neutral": [],
        "negative": []
      }
    ]
  }
}

Fontes no banco

  • alert
  • public_opinion
  • aspect_feedback
  • conversation_analysis
  • client
  • conversation

4.5 Personas (/dashboard/personas)

Estado atual

A tela precisa de:

  • KPIs de personas;
  • estatísticas gerais;
  • cards de personas;
  • detalhes da persona selecionada;
  • next best action.

Backend precisa entregar

GET /personas/overview

Query params sugeridos:

  • period=week|month|quarter
  • unit
  • area
  • sentiment=all|positive|neutral|negative

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "kpis": {
      "active": 5,
      "churn": 60.1,
      "loss": 7521.27,
      "potentialLabel": "Neutro"
    },
    "stats": {
      "identified": 28,
      "messages": 1840,
      "aspects": 18,
      "subaspects": 56
    },
    "personas": [
      {
        "id": "1",
        "nome": "Cliente Tristeza Invisível",
        "tipo": "O PERFIL",
        "descricao": "Sem conexão com CRM",
        "detalhes": "Cliente antigo, compras esporádicas.",
        "expansao": "Oferecer atendimento personalizado.",
        "engajamento": "Acionar contato humano imediato.",
        "risco": "Alto"
      }
    ]
  }
}

Fontes no banco

  • persona
  • client_persona
  • best_action
  • conversation_analysis
  • message

4.6 Evolução (/dashboard/evolucao)

Estado atual

A tela precisa de:

  • KPIs de evolução;
  • série de evolução dos sentimentos;
  • série de monitoramento de playbooks;
  • totais do período.

Backend precisa entregar

GET /evolution/overview

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "kpis": {
      "churnEvitado": 85000,
      "roiUpsell": 3.1,
      "scoreMedio": 74,
      "taxaEvolucao": 21.0,
      "conversaoEmocao": 47
    },
    "sentimentSeries": [
      { "date": "2024-04-19", "value": 0.05 },
      { "date": "2024-04-20", "value": 0.08 }
    ],
    "playbooksSeries": [
      { "date": "2024-04-19", "novos": 5, "convertidos": 1 },
      { "date": "2024-04-20", "novos": 15, "convertidos": 3 }
    ],
    "playbooksTotals": {
      "novos": 20,
      "convertidos": 4
    }
  }
}

Fontes no banco

  • sentiment_evolution
  • playbooks_monitor
  • kpi_snapshot

4.7 Executive Dashboard (/dashboard/executive)

Estado atual

A tela precisa de:

  • KPIs executivos;
  • distribuição de churn;
  • LTV em risco;
  • status de SLA;
  • emoção geral da base;
  • acessos rápidos.

Backend precisa entregar

GET /executive/dashboard

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "topKpis": [
      {
        "title": "Venda Atual",
        "value": "R$ 879",
        "trendLabel": "↑ +12% vs ontem",
        "danger": false
      }
    ],
    "churnDistribution": [
      { "label": "Baixo", "value": 45, "color": "#10b981" },
      { "label": "Crítico", "value": 10, "color": "#ef4444" }
    ],
    "ltvRisk": {
      "ltvTotal": 285000,
      "ltvAtRisk": 34556,
      "ltvRiskPct": 12,
      "criticalClients": 34,
      "avgTicket": 1016,
      "trendText": "+3 clientes entraram em risco crítico desde ontem"
    },
    "sla": {
      "withinPct": 78,
      "breachPct": 22,
      "byDepartment": [
        { "department": "SAC", "value": 72 },
        { "department": "Vendas", "value": 85 },
        { "department": "Suporte", "value": 91 }
      ]
    },
    "emotions": {
      "items": [
        { "label": "Alegria", "value": 38, "count": 1524, "color": "#10b981" }
      ],
      "avgSentimentScore": 0.28
    },
    "quickAccess": {
      "conversationsToday": 418,
      "activePersonas": 5,
      "activeAgents": 12,
      "activePlaybooks": 3,
      "pendingSettings": 2,
      "evolutionDelta": "+12%"
    }
  }
}

Fontes no banco

  • kpi_snapshot
  • emotion_snapshot
  • operator_daily_stats
  • alert
  • sla_config

4.8 Agentes (/dashboard/agents)

Estado atual

A tela precisa de:

  • listagem de agentes;
  • filtros;
  • KPIs resumidos;
  • criação de agente;
  • edição;
  • ativação/desativação;
  • toggle de escalonamento.

Backend precisa entregar

  • GET /agents
  • POST /agents
  • POST /agents/status
  • POST /agents/escalation

GET /agents

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "items": [
      {
        "id": 1,
        "name": "Maria Santos",
        "email": "maria@empresa.com",
        "initials": "MS",
        "department": "SAC",
        "channels": ["whatsapp"],
        "status": "Ativo",
        "availableForEscalation": true,
        "todayAttendances": 24,
        "avgResponseTime": "3m 12s",
        "responseTimeTrend": "down",
        "slaPct": 94
      }
    ],
    "stats": {
      "total": 8,
      "active": 6,
      "inAttendance": 2,
      "availableForEscalation": 5
    }
  }
}

POST /agents

Request:

{
  "name": "Carolina Ribeiro",
  "email": "carolina@empresa.com",
  "department": "SAC",
  "channels": ["whatsapp", "instagram"],
  "status": "Ativo",
  "availableForEscalation": true
}

Para editar um agente existente, usar POST /agents novamente enviando o id no payload.

Para alterar status, usar POST /agents/status enviando o id no payload.

Para alterar escalonamento, usar POST /agents/escalation enviando o id no payload.

Fontes no banco

  • operator
  • operator_channel
  • operator_daily_stats

4.9 SLA (/dashboard/sla)

Estado atual

A tela precisa de:

  • lista de departamentos configurados;
  • edição inline;
  • criação de departamento/configuração;
  • status em tempo real por departamento.

Backend precisa entregar

  • GET /sla/configs
  • POST /sla/configs
  • GET /sla/live-status

GET /sla/configs

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "items": [
      {
        "id": "sac",
        "name": "SAC",
        "firstResponseH": 1,
        "firstResponseM": 30,
        "resolutionH": 24,
        "alertPct": 80,
        "liveStatus": "breach",
        "liveDetail": "14h estourado",
        "lastUpdated": "há 8 minutos"
      }
    ]
  }
}

Para editar uma configuração existente, usar POST /sla/configs novamente enviando o id no payload.

Observação importante

O banco atual não possui alertPct na tabela sla_config.

Então existem duas opções:

  • Opção A: adicionar uma coluna nova na tabela sla_config;
  • Opção B: manter esse percentual em configuração de aplicação.

Fontes no banco

  • sla_config
  • conversation
  • operator

4.10 Configurações (/dashboard/settings)

Estado atual

A tela é estática e mostra:

  • integrações;
  • notificações;
  • suporte.

Backend precisa entregar

GET /settings/overview

Response:

{
  "status": "ok",
  "msg": "[100] Request ok.",
  "code": "S_OK",
  "data": {
    "integrations": [
      {
        "title": "WhatsApp Business",
        "description": "Configure sua conta do WhatsApp Business para comunicação",
        "status": "connected",
        "action": "gerenciar"
      },
      {
        "title": "WhatsApp dos Vendedores",
        "description": "Adicione os números de WhatsApp da equipe de vendas",
        "status": "partial",
        "action": "configurar",
        "count": "3 de 5 configurados"
      }
    ],
    "notifications": [
      {
        "title": "Alertas de Sentimento",
        "description": "Receba alertas sobre mudanças no sentimento dos clientes",
        "status": "enabled",
        "action": "configurar"
      }
    ],
    "support": [
      {
        "title": "Central de Ajuda",
        "description": "Acesse nossa documentação e tutoriais",
        "status": "available",
        "action": "acessar"
      }
    ]
  }
}

Observação importante

Esta parte do produto não está coberta pelo schema atual de forma completa.

Existe suporte parcial em:

  • integration
  • operator_channel

Mas não há modelagem explícita para preferências de notificação e configurações gerais.


4.11 Perfil (/dashboard/profile e /dashboard/perfil)

Backend precisa entregar

  • POST /me/change-password

POST /me/change-password

Request:

{
  "currentPassword": "senha-atual",
  "newPassword": "senha-nova",
  "confirmPassword": "senha-nova"
}

Fontes no banco

  • user
  • company

4.13 Ajuda (/dashboard/help e /dashboard/ajuda)

Backend precisa entregar

Opcionalmente:

  • GET /support/faq
  • GET /support/channels

Observação

Essa tela pode continuar 100% estática no frontend, se preferir.


5. Rotas recomendadas para o backend

Prioridade 0 — obrigatórias para integrar o app

  • POST /login X
  • POST /me/change-password

Prioridade 1 — telas mais centrais do produto

  • GET /dashboard/overview
  • GET /interactions
  • GET /interactions/details
  • GET /analytics/sentiment/dashboard

Prioridade 2 — gestão e inteligência

  • GET /personas/overview
  • GET /evolution/overview
  • GET /executive/dashboard
  • GET /agents
  • POST /agents
  • POST /agents/status
  • POST /agents/escalation
  • GET /sla/configs
  • POST /sla/configs
  • GET /sla/live-status

Prioridade 3 — configurações e módulos acessórios

  • GET /settings/overview
  • GET /billing/subscription
  • GET /billing/plans
  • POST /billing/change-plan
  • POST /billing/cancel
  • GET /support/faq
  • GET /support/channels

6. Padrão de implementação recomendado

Envelope de resposta

Manter o padrão já existente no backend:

{
  "status": "ok|failed",
  "msg": "mensagem",
  "code": "S_OK|E_VALIDATE|...",
  "data": {}
}

Autorização

Todas as rotas privadas devem exigir:

Authorization: Bearer <jwt>

Convenção prática para o frontend

Como o frontend atual está em Svelte e usa muitos objetos de tela prontos, o caminho mais simples é:

  • backend responder com objetos já próximos do formato consumido pelas telas;
  • frontend fazer apenas adaptação leve, se necessário.

7. Observações importantes da análise

  • O frontend não está chamando API nenhuma hoje.
  • Portanto, além de criar as rotas do backend, será necessário integrar o frontend com:
    • fetch/client HTTP;
    • persistência de token;
    • carregamento inicial a partir do JWT já recebido no login;
    • tratamento de 401.
  • Como o frontend usa adapter-static, o consumo da API será client-side.
  • Isso significa que o backend provavelmente precisará de:
    • CORS habilitado;
    • URL pública configurável por ambiente.

8. Resumo executivo

O que já existe

  • frontend pronto visualmente;
  • banco PostgreSQL bem modelado para analytics/atendimento;
  • login e registro no backend;
  • JWT funcionando;
  • migration pronta.

O que falta

  • praticamente toda a API de produto;
  • integração real do frontend com backend;
  • endpoints agregadores para dashboards;
  • CRUD de agentes;
  • endpoints de SLA;
  • endpoint de perfil;
  • eventualmente modelagem extra para billing/settings.

Melhor ordem de implementação

  1. autenticação real no frontend;
  2. dashboard principal;
  3. interações;
  4. analytics/sentiment;
  5. agentes;
  6. SLA;
  7. personas/evolução/executivo;
  8. settings/billing/help.

9. Conclusão

O projeto está em um ponto muito bom para integração:

  • o frontend já mostra claramente o produto final;
  • o banco já cobre boa parte do domínio;
  • o backend já tem base de auth pronta.

O principal trabalho agora é transformar os mocks do frontend em contratos reais de API.

Este arquivo pode ser usado como backlog técnico para construir o backend na ordem correta.