Triagem inteligente de atendimentos com IA — .NET 10, Blazor, MySQL e arquitetura orientada a eventos.
O TriageFlow recebe mensagens de clientes vindas de vários canais de venda (Mercado Livre, Amazon, Shopee, TikTok Shop, Magalu e e-commerce próprio), protege o conteúdo, classifica cada atendimento em segundo plano com IA e organiza tudo em um quadro priorizado para a equipe de SAC.
A IA não decide sozinha: ela devolve sinais estruturados e a prioridade é calculada por uma regra determinística, auditável e coberta por testes. O sistema também nunca responde ao cliente automaticamente — uma falha de IA não pode gerar uma resposta insegura.
Projeto de portfólio. Todas as mensagens exibidas no modo demonstração são fictícias.
Pré-requisito: .NET SDK 10. Não é necessário instalar banco de dados, criar conta na nuvem ou ter chave da OpenAI.
# Windows (PowerShell)
./run-demo.ps1# Linux / macOS
./run-demo.shDepois abra http://localhost:5131/classificacoes.
Windows: alguns arquivos têm nomes longos. Clone em uma pasta curta (por exemplo,
C:\dev\triageflow) ou habilite caminhos longos antes de clonar:git config --global core.longpaths true.
Prefere rodar manualmente? Use dois terminais:
dotnet run --project TriageFlow.Api --launch-profile demo
dotnet run --project TriageFlow.Web --launch-profile demo| Componente | Modo completo | Modo demonstração |
|---|---|---|
| Banco de dados | MySQL 8 com migrations e procedures | Banco em memória (Persistence:Provider=InMemory) |
| Dados | Mensagens reais dos canais | 35 mensagens fictícias embutidas na solução |
| Login | Microsoft Entra ID com roles | Visitante fictício (Authentication:Mode=Demo) |
| Classificador | OpenAI (Responses API) | Fake, baseado em palavras-chave |
| Processamento assíncrono | Worker separado lendo a Outbox | Despachante da Outbox dentro da API |
| Criptografia | Chave no Azure Key Vault | Chave AES-256 efêmera gerada na inicialização |
As mensagens fictícias não são gravadas direto como classificações: na inicialização, cada uma percorre o pipeline real — validação, criptografia, Outbox, sanitização de dados sensíveis, classificador, validação do resultado e cálculo da prioridade. Os dados são recriados a cada execução.
Por segurança, o banco em memória e o login fictício são rejeitados na
inicialização fora do ambiente Development.
Com a demonstração rodando, envie uma nova mensagem. Ela aparece classificada no quadro em cerca de dois segundos:
$agora = (Get-Date).ToUniversalTime().ToString('o')
Invoke-RestMethod -Method Post -Uri http://localhost:5213/api/v1/messages/inbound `
-ContentType 'application/json; charset=utf-8' -Body (@{
eventId = [guid]::NewGuid(); channel = 'shopee'; channelAccountId = 'loja-demo'
externalMessageId = "teste-$([guid]::NewGuid())"
content = 'Meu pedido está atrasado e a data prometida já passou.'
occurredAtUtc = $agora; receivedAtUtc = $agora
} | ConvertTo-Json)Também há exemplos prontos em
TriageFlow.Api/TriageFlow.Api.http.
- Transactional Outbox: ticket, mensagem cifrada e evento são gravados na mesma transação; o recebimento nunca espera a IA.
- Worker com reserva concorrente de lotes (
FOR UPDATE SKIP LOCKED), retry exponencial só para falhas transitórias, dead letter e fila de revisão humana. - Idempotência ponta a ponta: reenvios do mesmo evento devolvem o recibo existente, sem duplicar tickets ou classificações.
- Privacidade por padrão: AES-GCM no conteúdo, mascaramento de CPF, e-mail, telefone e cartão antes da IA, contratos de leitura sem texto do cliente e auditoria com identidades pseudonimizadas por SHA-256.
- Prioridade determinística calculada em C#, fora do modelo de IA.
- IA substituível atrás de
ITicketClassifier, com circuit breaker, saída estruturada por JSON Schema e proteção contra prompt injection. - Segurança operacional: Entra ID com roles por endpoint, rate limiting, TLS obrigatório no MySQL fora de Development e segredos no Key Vault.
- Observabilidade com OpenTelemetry: métricas de Outbox, latência, disponibilidade do classificador e consumo de tokens, sem dados sensíveis (catálogo).
- Arquitetura verificada por testes: a direção das dependências entre projetos é validada automaticamente.
- Integrações de marketplaces: OAuth do Mercado Livre, webhooks com idempotência e adaptadores para Shopee e Amazon.
Canal de venda
|
v
POST /api/v1/messages/inbound
|
+--> autentica, valida e normaliza
+--> cifra o conteúdo original (AES-GCM)
+--> grava ticket + mensagem + evento Outbox (mesma transação)
|
v
Worker consulta a Outbox
|
+--> reserva um lote de forma concorrente
+--> lê e decifra a mensagem
+--> sanitiza dados sensíveis
+--> chama ITicketClassifier
+--> valida, prioriza e grava a classificação
|
+--> sucesso: conclui o evento
+--> falha transitória: agenda retry
+--> falha definitiva: dead letter + revisão humana
|
v
GET /api/v1/tickets/classifications
|
v
TriageFlow.Web (quadro priorizado, somente leitura)
Uma explicação didática, com analogias e o fluxo classe a classe, está em docs/architecture.md.
A IA devolve sinais estruturados; a prioridade é calculada pela Application:
| Condição | Valor da API | Exibição no Web |
|---|---|---|
| existe flag de risco | critical |
Crítica |
| existe sinal de urgência | high |
Alta |
| existe contexto obrigatório pendente | medium |
Média |
| nenhuma condição anterior | normal |
Normal |
A taxonomia inicial ainda não define flags de risco, por isso a coluna "Crítica" permanece vazia na demonstração.
| Projeto | Responsabilidade |
|---|---|
TriageFlow.Domain |
Conceitos e regras puras, sem dependências técnicas |
TriageFlow.Application |
Casos de uso, validações, taxonomia e abstrações |
TriageFlow.Contracts |
Contratos HTTP e eventos de integração versionados |
TriageFlow.AI |
Classificadores Fake e OpenAI |
TriageFlow.Infrastructure |
MySQL, banco em memória, criptografia, Key Vault e Outbox |
TriageFlow.Integrations.* |
Adaptadores de Mercado Livre, Shopee e Amazon |
TriageFlow.Api |
Endpoints, autenticação, autorização e rate limiting |
TriageFlow.Worker |
Processamento da Outbox, retry e revisão humana |
TriageFlow.Web |
Dashboard Blazor somente leitura |
TriageFlow.Evaluation |
Avaliação do classificador com datasets sintéticos, incluindo prompt injection |
TriageFlow.*Tests |
Testes unitários, de integração, contrato e arquitetura |
Domain -> nenhuma dependência interna
Application -> Domain
Contracts -> nenhuma dependência interna
AI -> Application
Infrastructure -> Application, Domain e Contracts
Api -> Application, Contracts, Infrastructure e AI
Worker -> Application, Contracts, Infrastructure e AI
Web -> Contracts
Pré-requisitos: MySQL 8 com as migrations de
database/migrations aplicadas em ordem, um app
registrado no Microsoft Entra ID e, opcionalmente, uma chave da OpenAI.
Configure com User Secrets (nunca no repositório):
ConnectionStrings:SacDatabase
Security:MessageEncryption:Development:KeyId
Security:MessageEncryption:Development:KeyBase64
AzureAd:TenantId / AzureAd:ClientId
SacApi:BaseAddress / SacApi:Scopes
OPENAI_API_KEY (variável de ambiente, somente com o provedor OpenAI)
Execute API, Worker e Web com o perfil http ou https:
dotnet run --project TriageFlow.Api --launch-profile https
dotnet run --project TriageFlow.Worker
dotnet run --project TriageFlow.Web --launch-profile httpsConvenções de banco: tabelas TB_, chaves ID_ e procedures UP_SEL_,
UP_INS_ e UP_UPD_.
dotnet build .\TriageFlow.slnx --configuration Release -warnaserror
dotnet test .\TriageFlow.slnx --configuration Release --no-buildA suíte executa por padrão testes unitários, de integração (incluindo a API real em modo demonstração), de contrato para o JSON público V1 e de arquitetura. Os testes que exercitam um MySQL real são opt-in:
$env:TRIAGEFLOW_RUN_LOCAL_MYSQL_TESTS = "true"
dotnet test .\TriageFlow.IntegrationTests --filter "FullyQualifiedName~Database"- Classificar — centralizar, proteger, classificar, priorizar e exibir para triagem humana (implementado).
- Assistir — resumir conversas e sugerir respostas para aprovação.
- Automatizar com supervisão — responder casos autorizados e de baixo risco.
- Automatizar com controle — executar ações determinísticas, auditáveis e reversíveis, sempre com fallback humano.
© 2026 Ivan Massanares. Todos os direitos reservados.
O código está público somente para avaliação de portfólio: você pode ler e executar o projeto localmente para conhecer o trabalho. Copiar, modificar, redistribuir ou reutilizar qualquer parte exige autorização prévia por escrito. Veja LICENSE.
