Auditoria de segurança + robustez da área do representante antes de produção.
API (autorização e injeção):
- IDOR em clients: endpoints de detalhe (findOne, notas, ctr, top-produtos,
histórico, contatos) validam carteira do rep via assertClienteDaCarteira;
cliente alheio retorna 404. orders.create idem antes de aceitar idCliente.
- Role guard em dashboards supervisor/manager e ger/chamados (rep -> 403).
- Datas em $queryRawUnsafe agora exigem YYYY-MM-DD (DateOnlySchema + revalidação);
dtAniversario de contato validado e escapado.
- id_empresa de CTR/NF usa matrizEmpresa() em vez de 1/9001 hardcoded.
- Alçada de desconto: transmit valida desconto efetivo por item (preço vs tabela
pauta>promo>base + promoção ativa), não só o desconto global.
- Idempotency-Key escopado a empresa+vendedor; unsubscribe com DTO e dono.
Web (erros nunca silenciosos):
- Remove dupla serialização (apiFetch já faz JSON.stringify) em funil, sac e
politicas — corrige criar oportunidade, abrir chamado e editar políticas.
- Handler global de erro no QueryClient (query e mutation viram toast).
- Error boundary por rota (payload divergente não derruba o app em branco).
- Alert usa message= em vez de title= (AntD 6); sw.js usa globalThis.
Qualidade:
- Corrige ping.contract.spec (idEmpresa) e zera erros de lint.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Na ficha do cliente, o card de titulos em aberto se esticava para o lado e
empurrava a secao de NF-e para fora da tela.
Causa: um track `1fr` de CSS Grid carrega `min-width: auto` implicito e se
recusa a encolher abaixo da largura intrinseca do conteudo. Como as tabelas
usam `scroll={{ x: 'max-content' }}`, a largura intrinseca delas e a soma de
todas as colunas — com titulos suficientes, a coluna estourava os 50% e
comia a vizinha. O `maxWidth: '100%'` ja presente nas tabelas nao ajudava,
porque quem crescia era o track, nao a tabela.
`minWidth: 0` nos filhos do grid desarma o `min-width: auto` e devolve o
scroll horizontal para dentro da tabela, que era o comportamento desejado.
Aplicado tambem em ClientsPage: o `<Col>` que hospeda a tabela de clientes
e estruturalmente identico (Col e flex item, mesmo `min-width: auto`) e so
nao quebrava porque a tabela tem `overflow: 'hidden'` no style — uma linha
que se le como puramente cosmetica (arredondar canto) e que, se removida
num refactor, reintroduziria o bug. A protecao vai para o lugar canonico.
Inclui ainda o span responsivo do campo Endereco na ficha.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Tela dedicada que abre pelo botao "Detalhar carteira" na listagem de
clientes, com leitura acionavel da carteira em vez de so uma tabela.
- `/reports/carteira` passa a devolver `faturamentoTotal`,
`participacaoPct` e `faturamentoRepTotal`, permitindo medir o peso de
cada cliente no faturamento do rep.
- `CarteirePage`: cards de resumo (ativos / em risco / inativos / sem
pedido), faturamento total e InsightCards que apontam concentracao em
poucos clientes, maior cliente em risco, maior inativo e clientes nunca
positivados.
- Clientes classificados por dias sem comprar (30d em risco, 60d inativo),
com navegacao direta para a ficha.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## API
- GET /dashboard/manager: KPIs agregados (faturamento, pedidos, ticket médio,
promoções ativas), meta total do período, ranking top 10 com clientes
atendidos e % meta, positivação por representante, venda necessária/dia
- Parâmetros opcionais ?mes&ano para filtrar período
- GET /equipe: lista de reps com pedidos, faturamento, ticket médio e % meta
(deduplicação de vw_representantes)
- GET/POST /politicas/descontos: alçada de desconto por rep (AlcadaDesconto)
- GET/POST/PATCH/DELETE /politicas/promocoes: CRUD de promoções com validade
- Metas lidas de sar.vw_metas (tipo=GR), não de vw_metas do ERP
## Schema
- Novo model Promocao (sar.promocoes) criado via prisma db execute
## Frontend
- Cockpit /ger: GerPainel, EquipePage, PoliticasPage
- GerPainel: filtro mes/ano, cards KPI, cards de meta vs realizado
(atingimento, falta, venda/dia), ranking com clientes atendidos,
positivação de clientes por representante (paginada)
- Sidebar e BottomNav role-aware: rep / supervisor / gerente (manager+admin)
- Clientes acessível ao gerente (carteira completa de todos os reps)
- Rotas: HomeRoute redireciona por role; /ger, /ger/equipe, /ger/politicas
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Catálogo: modal de detalhe centralizado (1100px) com identificação, estoque,
preços base e lista de preços por pauta do representante (DISTINCT para evitar duplicatas)
- Contrato: loteMulVenda promovido para ProdutoSummarySchema; PautaPrecoSchema adicionado
- Pedido novo: valida lote múltiplo de venda — qtd inicial = lote, step = lote,
InputNumber em erro quando inválido, alerta e bloqueio do submit
- Consulta ERP: tela OrdersErpPage com listagem de pedidos do ERP (P/E), contrato
PedidoErpConsulta, endpoint no orders.controller, rota e sidebar
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clicar no nome do cliente na lista navega direto para /clientes/:id (ficha completa
com contatos e pedidos). Botão 'Abrir ficha' adicionado no footer do drawer de preview.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adiciona useNavigate() no corpo de ClientsPage (faltava; sub-componentes já tinham).
Substitui Space direction→orientation (4 ocorrências) e Progress trailColor→railColor.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Web (NewClientPage):
- Segmentado PJ/CPF com campos específicos por categoria
- PJ: razão social, nome fantasia, CNPJ, IE, indicador IE, consumidor final
- PF: nome completo, CPF
- Endereço com auto-preenchimento via ViaCEP (CEP → rua/bairro/município)
- Município: Select com busca server-side (/catalog/municipios)
- Contato: DDD, telefone, email
- Comercial: forma pagamento, tabela de preços, limite crédito
- Feedback: código ERP exibido no sucesso; alerta de erro de sync sem bloquear
API:
- GET /catalog/municipios?q= — busca municipios da vw_municipios
- POST /clients/novo — INSERT em sar.clientes_novos; trigger sincroniza para sig.corrent
- Retorna { id, idCorrentErp, sincronizado, erroSync } após o trigger disparar
- Fix trigger fn_sync_cliente_to_erp: NULLIF para cgcpf vazio (evita violação
do unique index key_corrent_cgcpf quando cliente não tem CPF/CNPJ)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Web — ClientsPage:
- Redesign completo: métricas reais via usePortfolioStats (4 queries count),
donut Chart.js com totais reais, tabela sem ellipsis, coluna Cliente com
nome fantasia/razão/CNPJ completos, drawer de detalhes e análise comercial,
cards mobile, filtros de status/busca em tempo real.
- Dados reais: substitui mock por useClientList/useClientDetail/useClientOrders;
remove tipos fictícios (prospect/lead, cidade, totalComprado).
Web — OrdersPage:
- Métricas reais via useOrderStats (contagens por situa, não da página atual).
- Coluna Cliente sem truncamento (minWidth: 240).
- Cabeçalho, filtros e layout alinhados ao padrão da ClientsPage.
API — orders.service.ts:
- Normalização situa SIG→SAR: SIG usa 5=Cancelado; SAR usa 3=Cancelado.
sigToSar(5→3) no mapper; sarToSig(3→5) no filtro SQL.
API — clients.service.ts:
- dt_ultima_compra corrigida: JOIN duplo (vw_pedidos_erp + sar.pedidos) com
GREATEST() — clientes com histórico ERP mas sem pedido SAR deixam de
aparecer todos como Inativo.
- Filtro de activityStatus movido para SQL — total e paginação corretos.
- findOne() atualizado com o mesmo JOIN duplo.
Infra — .env:
- DEV_EMPRESA_ID: 1 → 9001 — API aponta para dados reais da empresa SIG.
Ex: pedido nº 141022 passa de R$1.765,48 para R$2.454,90.
Docs — sarweb_views.sql:
- Documenta as views reais em schema sar; remove schema sarweb inexistente.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- GET /api/v1/auth/me retorna perfil real do ERP (vw_representantes)
- Contrato UserProfile adicionado ao shared api-interface
- Hook useCurrentUser() no frontend consome o endpoint
- Cockpit rafael → rep, sandra → supervisor (pastas e componentes)
- Topbar exibe iniciais do usuário e dropdown com nome, role e "Sair"
- Logout limpa token e recarrega para voltar ao DevLogin
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>