- 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>
DB:
- sar.vw_contatos: view sobre gestao.contato com join sig.corrent
(id_entidade CHAR20 = id_corrent; cod_vendedor para filtro por rep)
- sar.contatos_novos: staging com nome, cargo, departamento, telefone,
celular, whatsapp, email, dt_aniversario, anotacoes
- trg_contato_novo: AFTER INSERT → gestao.contato; grava id_contato_erp
API:
- GET /clients/:id/contacts — lista contatos ativos do cliente
- POST /clients/:id/contacts — cria via staging; retorna { idContatoErp, sincronizado }
Web:
- ClientContacts: tabela de contatos no detalhe do cliente
- Links diretos WhatsApp (wa.me) + mailto por contato
- Modal "Novo Contato" com todos os campos; feedback de código ERP no sucesso
- whatsapp é o campo principal para envio futuro via ChatWoot
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>
- JOIN de vw_pedidos_erp com vw_clientes pelo id_cliente + id_empresa
- Campos nomeCliente e razaoCliente adicionados ao PedidoSummary (contrato)
- Tabela, cards mobile e drawer exibem razão social (fallback para nome)
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>
- Catálogo só mostra produtos com preço preenchido (vl_preco1 > 0) por default
- Novo endpoint GET /catalog/pautas — retorna as 6 pautas do representante logado
- GET /catalog?idPauta=N — usa preço da pauta selecionada (vw_pauta_produtos)
- CatalogPage: dropdown "Selecionar pauta de preços" com as pautas do rep
- product.contract: adiciona PautaSchema e idPauta no ProdutoListQuerySchema
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- OrdersService.list: substitui sar.pedidos por vw_pedidos_erp — 44k pedidos
históricos do rep 29 visíveis; sar.pedidos continua sendo a tabela de escrita
para novos pedidos SAR que serão integrados ao ERP
- DashboardService: atingido/pedidosMes/recentes/inativos todos via vw_pedidos_erp;
supervisor usa vw_pedidos_erp para pedidosDia
- PedidoSummarySchema: id relaxado de uuid() para string(); adiciona numero,
statusDescr e fonte ('sar'|'erp')
- orders.ts: corrige bug — apiFetch retorna JSON diretamente, não Response;
remove res.ok/res.json() incorretos
- OrdersPage: coluna Nº mostra numero do ERP; statusDescr no badge
- DevLogin: atualiza para PAVEI COMERCIO cod 29
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
FR-6.1/6.2: Sandra recebe push quando pedido entra em pending_approval;
Rafael recebe quando pedido é aprovado ou recusado. Service worker registrado
em background (PWA-ready via public/sw.js).
FR-6.3: Badge na Topbar busca GET /notifications/pending-count (supervisores
veem count de pending_approval; reps veem 0). Intervalo de 30s.
FR-6.4: Botão Compartilhar no OrderDetailPage para pedidos approved/invoiced
(apenas reps). Usa navigator.share() com texto formatado para WhatsApp.
Infra: modelo PushSubscription (Prisma), NotificationsModule (subscribe/
unsubscribe/pending-count + PushService VAPID), VAPID keys em .env,
integração no OrdersService (create → supervisores, approve/reject → repId).
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
GET /dashboard/supervisor com fila de aprovações, KPIs do dia vs semana
anterior e top 3 reps com mais clientes inativos. SandraPainel com polling
30s. Rota / role-aware: rep → RafaelPainel, supervisor/manager → SandraPainel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GET /dashboard/rep retorna meta mensal, comissão (fixa + FLEX), clientes
inativos >30 dias e pedidos dos últimos 7 dias. RepTarget model com migration.
RafaelPainel conectado à API real via useRepDashboard().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PATCH /orders/:id/approve e /reject com alçada role-gated; OrderDetailPage
com modais de aprovação e recusa; ApprovalQueuePage para Sandra; badge de
pendências na Sidebar; DevLogin com 4 perfis (rep, supervisor, gerente).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Primeiro contrato compartilhado API↔Web. Lib stays framework-free:
nestjs-zod (createZodDto) fica fora — Web vai consumir esta mesma lib
e não pode arrastar dependência backend.
- PingResponseSchema + type PingResponse (z.infer) em ping.contract.ts
- 6 testes vitest (1 happy + 5 rejeições: status, uuid, uptime, datetime, workspaceId)
- ping.controller importa PingResponse via @sar/api-interface
- placeholders Nx api-interface.{ts,spec.ts} removidos
- design-log atualizado com decisão arquitetural e pegadinhas da sessão
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>