Aprenda a projetar e construir um aplicativo web que rastreia conformidade de SLA: defina métricas, colete eventos, calcule resultados, alerte sobre violações e gere relatórios auditáveis.

Conformidade de SLA significa cumprir as promessas mensuráveis de um Service Level Agreement (SLA) — um contrato entre um provedor e um cliente. O trabalho do seu app é responder a uma pergunta simples com evidência: Cumprimos o que prometemos, para este cliente, durante este período?
Ajuda separar três termos relacionados:
A maioria dos apps de rastreamento de SLA começa com um conjunto pequeno de métricas que se mapeiam a dados operacionais reais:
Diferentes usuários querem a mesma verdade, apresentada de formas distintas:
Este produto trata de rastrear, provar e reportar: coletar sinais, aplicar regras acordadas e gerar resultados auditáveis. Não garante desempenho; mede — com precisão, consistência e de forma defensável futuramente.
Antes de projetar tabelas ou escrever código, fique claramente ciente do que “conformidade” significa para o seu negócio. A maioria dos problemas de rastreamento de SLA não é técnica — são problemas de requisitos.
Comece coletando as fontes da verdade:
Escreva essas regras de forma explícita. Se uma regra não pode ser declarada claramente, ela não pode ser calculada de forma confiável.
Liste as “coisas” do mundo real que podem afetar um número de SLA:
Também identifique quem precisa do quê: suporte quer risco de violação em tempo real, gerentes querem rollups semanais, clientes querem resumos simples (frequentemente para uma página de status).
Mantenha o escopo pequeno. Escolha o conjunto mínimo que prove o sistema ponta a ponta, como:
Crie uma checklist de uma página que você possa testar depois:
Sucesso é quando duas pessoas calculam manualmente o mesmo mês de amostra e seu app bate exatamente com o resultado.
Um rastreador de SLA correto começa com um modelo de dados que consiga explicar por que um número é o que é. Se você não consegue rastrear um valor mensal de disponibilidade até os eventos e regras exatas usadas, terá disputas com clientes e incerteza interna.
No mínimo, modele:
Uma relação útil é: customer → service → SLA policy (possivelmente via plan). Incidentes e eventos referenciam serviço e cliente.
Erros de tempo são a causa nº1 de matemática de SLA errada. Armazene:
occurred_at como UTC (timestamp com semântica de fuso horário)received_at (quando seu sistema viu o evento)source (nome do monitor, integração, manual)external_id (para deduplicar retries)payload (JSON bruto para debug futuro)Também armazene customer.timezone (string IANA como America/New_York) para exibição e lógica de horário comercial, mas não use para reescrever o tempo do evento.
Se SLAs de tempo de resposta pausam fora do horário comercial, modele calendários explicitamente:
working_hours por cliente (ou por região/serviço): dia da semana + horários de início/fimholiday_calendar ligado a uma região ou cliente, com intervalos de datas e rótulosMantenha as regras dirigidas por dados para que ops possam atualizar um feriado sem fazer deploy.
Armazene eventos brutos em uma tabela append-only e armazene resultados calculados separadamente (ex.: sla_period_result). Cada linha de resultado deve incluir: limites do período, versão das entradas (versão da política + versão do motor) e referências aos IDs de eventos usados. Isso torna recomputações seguras e fornece trilha de auditoria quando clientes perguntam “Quais minutos de outage vocês contaram?”.
Seus números de SLA são tão confiáveis quanto os eventos que você ingere. O objetivo é simples: capturar toda mudança que importa (início de outage, incidente reconhecido, serviço restaurado) com timestamps consistentes e contexto suficiente para calcular conformidade depois.
A maioria das equipes puxa de uma mistura de sistemas:
Webhooks geralmente são a melhor opção para precisão em tempo real e menor carga: o sistema origem empurra eventos para seu endpoint.
Polling é um fallback quando webhooks não estão disponíveis: seu app busca periodicamente mudanças desde o último cursor. Você precisará de tratamento de rate-limit e lógica “since” cuidadosa.
Importação CSV ajuda com backfills e migrações. Trate-a como caminho de ingestão de primeira classe para reprocessar períodos históricos sem hacks.
Normalize tudo em um único formato interno de “evento”, mesmo que os payloads upstream variem:
event_id (obrigatório): único e estável entre retries. Prefira o GUID do fonte; caso contrário gere um hash determinístico.source (obrigatório): ex.: datadog, servicenow, manual.event_type (obrigatório): ex.: incident_opened, incident_acknowledged, service_down, service_up.occurred_at (obrigatório): quando o evento aconteceu (não quando você o recebeu), com fuso horário.received_at (sistema): quando seu app ingeriu o evento.service_id (obrigatório): o serviço relevante ao SLA que o evento afeta.incident_id (opcional, mas recomendado): liga múltiplos eventos a um incidente.attributes (opcional): prioridade, região, segmento de cliente, etc.Armazene event_id com restrição única para fazer a ingestão idempotente: retries não criam duplicatas.
Rejeite ou coloque em quarentena eventos que:
occurred_at muito no futuro.service_id conhecido (ou requeira workflow explícito de “não mapeado”).event_id existente.Essa disciplina evita discussões sobre relatórios de SLA depois — porque você poderá apontar para entradas limpas e rastreáveis.
Seu motor de cálculo é onde “eventos brutos” se transformam em resultados de SLA que você pode defender. A chave é tratá-lo como contabilidade: regras determinísticas, entradas claras e trilha reexecutável.
Converta tudo em um único stream ordenado por incidente (ou por impacto de serviço):
A partir dessa linha do tempo, compute durações somando intervalos, não subtraindo duas timestamps cegamente.
Defina TTFR como o tempo decorrido “cobrável” entre incident_start e first_agent_response (ou acknowledged, dependendo da redação do SLA). Defina TTR como o tempo decorrido “cobrável” entre incident_start e resolved.
“Cobrável” significa remover intervalos que não devem contar:
Detalhe de implementação: armazene uma função de calendário (horário comercial, feriados) e uma função de regras que recebe uma linha do tempo e retorna intervalos cobrados.
Decida antecipadamente se você calcula:
Para quedas parciais, aplique ponderação por impacto apenas se o contrato exigir; caso contrário trate “degradado” como uma categoria separada de violação.
Cada cálculo deve ser reprodutível. Persista:
Quando regras mudam, você pode reexecutar cálculos por versão sem reescrever histórico — crucial para auditorias e disputas com clientes.
Relatórios é onde o rastreamento de SLA ganha ou perde confiança. Seu app deve deixar claro qual intervalo de tempo está sendo medido, quais minutos contam e como os números finais foram derivados.
Dê suporte aos períodos de relatório que os clientes realmente usam:
Armazene períodos como timestamps explícitos de início/fim (não “mês = 3”) para poder reproduzir cálculos depois e explicar resultados.
Uma fonte frequente de confusão é se o denominador é o período todo ou apenas o tempo “elegível”.
Defina dois valores por período:
Então calcule:
availability_percent = 100 * (eligible_minutes - downtime_minutes) / eligible_minutes
Se eligible_minutes puder ser zero (por exemplo, um serviço monitorado apenas em horário comercial e o período não conter nenhum), defina a regra antecipadamente: “N/A” ou trate como 100% — mas seja consistente e documente.
A maioria dos SLAs precisa de porcentagem e um resultado binário.
Também mantenha a “distância até a violação” (orçamento de downtime restante) para que dashboards possam alertar antes do limite ser cruzado.
Por fim, mantenha as entradas brutas (eventos incluídos/excluídos e ajustes) para que cada relatório responda “por que esse número é o que é?” sem rodeios.
Seu motor de cálculo pode ser perfeito e ainda falhar com os usuários se a UI não responder à pergunta básica: “Estamos cumprindo o SLA agora, e por quê?” Projete o app para que cada tela comece com um status claro, depois permita que as pessoas investiguem números e eventos brutos que os produziram.
Dashboard de visão geral (para operadores e gerentes). Comece com um pequeno conjunto de tiles: conformidade do período atual, disponibilidade, conformidade de tempo de resposta e “tempo restante antes da violação”, quando aplicável. Prefira rótulos explícitos (ex.: “Disponibilidade (este mês)” em vez de apenas “Uptime”). Se você suportar múltiplos SLAs por cliente, mostre primeiro o pior status e permita expandir.
Detalhe do cliente (para times de conta e relatórios ao cliente). Uma página do cliente deve resumir todos os serviços e tiers de SLA para aquele cliente, com um estado simples de passa/aviso/falha e uma explicação curta (“2 incidentes contados; 18m de downtime contabilizados”). Adicione links para /status (se você fornecer uma página de status pública) e para exportar o relatório.
Detalhe do serviço (para investigação profunda). Mostre aqui as regras exatas de SLA, a janela de cálculo e a decomposição de como o número de conformidade foi formado. Inclua um gráfico de disponibilidade ao longo do tempo e uma lista de incidentes que contaram para o SLA.
Linha do tempo de incidente (para auditorias). Uma visão única de incidente deve mostrar uma linha do tempo dos eventos (detectado, reconhecido, mitigado, resolvido) e quais timestamps foram usados para métricas de “resposta” e “resolução”.
Faça os filtros consistentes entre telas: intervalo de datas, cliente, serviço, tier e severidade. Use as mesmas unidades em todos os lugares (minutos vs segundos; porcentagens com os mesmos decimais). Quando o usuário muda o intervalo de datas, atualize todas as métricas na página para não haver desencontro.
Cada métrica resumo deve ter um caminho “Por quê?”:
Use tooltips com moderação para definir termos como “Downtime excluído” ou “Horário comercial”, e mostre o texto exato da regra na página do serviço para evitar suposições.
Prefira linguagem simples em vez de abreviações (“Tempo de resposta” em vez de “MTTA” a menos que seu público espere). Para status, combine cor com rótulo textual (“Em risco: 92% do orçamento de erro usado”) para evitar ambiguidade. Se o app suportar logs de auditoria, adicione uma pequena caixa “Última mudança” nas regras de SLA com link para /settings/audit-log para que usuários verifiquem quando definições mudaram.
Alertas é onde seu app de rastreamento de SLA passa de relatório passivo a auxiliar times a evitar penalidades. Os melhores alertas são oportunos, específicos e acionáveis — ou seja, dizem o que fazer a seguir, não apenas que algo “está ruim”.
Comece com três tipos de gatilho:
Torne os gatilhos configuráveis por cliente/serviço/SLA, já que contratos diferentes toleram limites diferentes.
Envie alertas para onde as pessoas realmente respondem:
Todo alerta deve incluir deep links como /alerts, /customers/{id}, /services/{id} e a página de detalhe do incidente para que os respondedores verifiquem números rapidamente.
Implemente deduplicação agrupando alertas com a mesma chave (customer + service + SLA + period) e suprimindo repetições por uma janela de cooldown.
Adicione horas de silêncio (por time zone da equipe) para que alertas não críticos de “aproximação de violação” aguardem o horário comercial, enquanto “violação ocorrida” pode ignorar horas de silêncio se a severidade for alta.
Por fim, suporte regras de escalonamento (ex.: notificar on-call após 10 minutos, escalar para um gerente após 30) para evitar que alertas fiquem presos em uma caixa de entrada.
Dados de SLA são sensíveis porque expõem desempenho interno e direitos específicos de clientes. Trate controle de acesso como parte da “matemática” do SLA: o mesmo incidente pode produzir resultados diferentes dependendo de qual SLA é aplicado.
Mantenha papéis simples e depois refine para permissões mais granulares.
Um padrão prático é RBAC + escopo por tenant:
Seja explícito sobre dados específicos do cliente:
Comece com email/senha e exija MFA para papéis internos. Planeje SSO (SAML/OIDC) separando identidade (quem é) de autorização (o que pode acessar). Para integrações, emita API keys vinculadas a contas de serviço com escopos estreitos e suporte a rotação.
Adicione entradas de auditoria imutáveis para:
Armazene quem, o que mudou (antes/depois), quando, onde (IP/user agent) e um ID de correlação. Torne logs de auditoria pesquisáveis e exportáveis (ex.: /settings/audit-log).
Um app de rastreamento de SLA raramente é uma ilha. Você precisará de uma API que permita que ferramentas de monitoramento, ticketing e workflows internos criem incidentes, enviem eventos e puxem relatórios sem trabalho manual.
Use um path versionado (por exemplo, /api/v1/...) para evoluir payloads sem quebrar integrações existentes.
EndPoints essenciais para cobrir a maioria dos casos:
POST /api/v1/events para ingerir mudanças de estado (up/down, amostras de latência, janelas de manutenção). GET /api/v1/events para auditoria e debug.POST /api/v1/incidents, PATCH /api/v1/incidents/{id} (acknowledge, resolve, assign), GET /api/v1/incidents.GET /api/v1/slas, POST /api/v1/slas, PUT /api/v1/slas/{id} para gerenciar contratos e limiares.GET /api/v1/reports/sla?service_id=...&from=...&to=... para resumos de conformidade.POST /api/v1/alerts/subscriptions para gerenciar webhooks/alvos de email; GET /api/v1/alerts para histórico de alertas.Escolha uma convenção e use em todo lugar. Por exemplo: paginação por limit + cursor, mais filtros padrão como service_id, sla_id, status, from e to. Mantenha ordenação previsível (ex.: sort=-created_at).
Retorne erros estruturados com campos estáveis:
{ "error": { "code": "VALIDATION_ERROR", "message": "service_id is required", "fields": { "service_id": "missing" } } }
Use status HTTP claros (400 validação, 401/403 auth, 404 not found, 409 conflict, 429 rate limit). Para ingestão de eventos, considere idempotência (Idempotency-Key) para que retries não dupliquem incidentes.
Aplique rate limits razoáveis por token (e limites mais estritos para endpoints de ingestão), sanitize inputs e valide timestamps/fusos. Prefira tokens de API com escopo (somente leitura vs escrita em incidents) e sempre logue quem chamou qual endpoint para rastreabilidade (detalhes na seção de logs de auditoria em /blog/audit-logs).
Números de SLA só são úteis se as pessoas confiarem neles. Testes para um app de rastreamento de SLA devem focar menos em “a página carrega” e mais em “a matemática do tempo se comporta exatamente como o contrato diz.” Trate suas regras de cálculo como um recurso do produto com sua própria suíte de testes.
Comece testando unitariamente seu motor de cálculo com inputs determinísticos: uma linha do tempo de eventos (incidente aberto, reconhecido, mitigado, resolvido) e um conjunto de regras de SLA claramente definido.
Use timestamps fixos e “congele o tempo” para que seus testes nunca dependam do relógio. Cubra casos de contorno que frequentemente quebram relatórios de SLA:
Adicione um pequeno conjunto de testes E2E que rodem o fluxo completo: ingerir eventos → calcular conformidade → gerar relatório → renderizar UI. Isso detecta desencontros entre “o que o motor calculou” e “o que o dashboard mostra”. Mantenha os cenários poucos, mas de alto valor, e asserte nos números finais (%, violação sim/não, tempo para ack).
Crie fixtures de teste para horários comerciais, feriados e fusos. Você quer casos repetíveis como “incidente ocorre sexta 17:55 horário local” e “feriado desloca a contagem do tempo de resposta”.
Testes não terminam no deploy. Adicione monitoramento para falhas de jobs, tamanho da fila/backlog, duração de recalculo e taxas de erro. Se ingestão atrasar ou um job noturno falhar, seu relatório pode ficar errado mesmo com código correto.
Lançar um app de rastreamento de SLA é menos sobre infraestrutura sofisticada e mais sobre operações previsíveis: seus cálculos devem rodar a tempo, dados precisam estar seguros e relatórios reproduzíveis.
Comece com serviços gerenciados para focar na correção:
Mantenha ambientes mínimos: dev → staging → prod, cada um com seu BD e secrets.
Rastreamento de SLA não é puro request/response; depende de trabalho agendado.
Rode jobs via processo worker + fila, ou um scheduler gerenciado invocando endpoints internos. Faça jobs idempotentes (seguros para retry) e registre cada execução para auditoria.
Defina retenção por tipo de dado: mantenha resultados derivados por mais tempo que eventos brutos. Para exports, ofereça CSV primeiro (rápido, transparente), depois templates PDF. Seja claro: exports são “formatos best-effort”, enquanto o banco é a fonte da verdade.
Se quiser validar seu modelo de dados, fluxo de ingestão e UI de relatórios rapidamente, uma plataforma de vibe-coding como Koder.ai pode ajudar a chegar a um protótipo ponta a ponta sem comprometer um ciclo de engenharia completo. Como o Koder.ai gera aplicações completas via chat (UI web + backend), é uma forma prática de montar:
Uma vez comprovados requisitos e cálculos (a parte difícil), você pode iterar, exportar o código-fonte e entrar em um fluxo de build-and-operate tradicional — mantendo funcionalidades como snapshots e rollback durante a iteração rápida.
Um rastreador de SLA responde a uma pergunta com evidência: nós cumprimos os compromissos contratuais para um cliente e período de tempo específicos?
Na prática, isso significa ingerir sinais brutos (monitoramento, tickets, atualizações manuais), aplicar as regras do cliente (horário comercial, exclusões) e produzir um resultado auditável com status de aprovação/fracasso e detalhes de suporte.
Use:
Modele-os separadamente para que você possa melhorar a confiabilidade (SLO) sem alterar inadvertidamente os relatórios contratuais (SLA).
Um MVP forte normalmente rastreia 1–3 métricas de ponta a ponta:
Essas métricas mapeiam bem para fontes de dados reais e forçam a implementação das partes mais difíceis (períodos, calendários, exclusões) desde cedo.
Falhas de requisitos geralmente vêm de regras não explicitadas. Colete e documente:
Se uma regra não puder ser expressa claramente, não a “invente” no código — marque-a e esclareça com o responsável.
Comece com entidades simples e explícitas:
Priorize rastreabilidade: todo número reportado deve ligar de volta a e .
Armazene o tempo corretamente e de forma consistente:
occurred_at em UTC com semântica de fuso horárioreceived_at (quando foi ingerido)Depois, torne períodos explícitos (timestamps de início/fim) para reproduzir relatórios — mesmo através de mudanças de DST.
Normalize tudo em uma única forma de evento interno com um ID estável:
event_id (único, estável entre retries)source, event_type, , Calcule durações somando intervalos em uma linha do tempo, não subtraindo dois timestamps sem contexto.
Defina explicitamente o “tempo cobrável” removendo intervalos que não contam, como:
Persista os intervalos derivados e os códigos de motivo para poder explicar exatamente o que foi contado.
Rastreie dois denominadores explicitamente:
Então calcule:
availability_percent = 100 * (eligible_minutes - downtime_minutes) / eligible_minutes
Também decida o que acontece se for zero (por exemplo, mostre ). Documente essa regra e aplique consistentemente.
Faça a UI responder “estamos cumprindo o SLA, e por quê?” num relance:
Para alertas, priorize gatilhos acionáveis: aproximação de violação, violação ocorrida e violações repetidas — cada um linkando para páginas relevantes como ou .
occurred_atservice_idincident_id e attributesAplique idempotência com uma restrição única em event_id. Para mapeamentos ausentes ou chegadas fora de ordem, coloque em quarentena/flag — não “corrija” silenciosamente os dados.
eligible_minutes/customers/{id}/services/{id}