Commit Graph

27 Commits

Author SHA1 Message Date
6cdb4c578e feat(infra): adiciona vw_metas ao schema SAR — metas do ERP (gestao.metavenda)
View sar.vw_metas expõe gestao.metavenda com joins descritivos:
- nome_vendedor (gestao.vendedor)
- desc_grupo / desc_subgrupo (gestao.grupo)
- nome_marca (gestao.marca)
- Campos calculados: ano e mes extraídos de mes_ano (date)

Campo tipo (char 2) controla o escopo da meta:
  G/GE=geral, GR=grupo, SG=subgrupo, MA=marca, PR=produto, AC=classe ABC

DashboardService usará tipo='G' (ou equivalente) para calcular %
atingido vs meta; os demais tipos ficam disponíveis para detalhamento
futuro. Taxas de comissão/flex vêm de vw_representantes (taxa_com),
não da tabela sar.meta_representante (que guarda apenas overrides SAR).

Renumera seções 4-16 → 5-17 para acomodar vw_metas como seção 4.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 11:45:55 +00:00
f363d22d90 feat(infra): adiciona vw_sarcfg ao schema SAR — regras de negócio por empresa
View sar.vw_sarcfg lê gestao.sarcfg + gestao.sarconfig e expõe:
- Flags booleanas decodificadas do bitmask bloq_preco_pedido (bits 0-5):
  blog_preco, blog_desconto, blog_limite_credito, blog_novo_cliente,
  blog_preco_promocional, blog_formapag_cliente
- Configurações gerais: ativar_prod_pauta, preco_padrao, preco_com_ipi,
  origem_descmax, cod_pauta1/2/3
- Configs sarconfig (key-value): bloq_pauta_preco, dias_bloq_credito,
  dias_bloq_comunicacao, tipo_bloq_comunicacao

Renumera seções de views: 1-15 → 1-16 (vw_sarcfg inserida como #1).
OrdersService usará esta view para aplicar restrições por empresa.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-29 11:38:55 +00:00
b0b60d7a14 refactor(erp): integração direta com banco ERP — schema sar
Revoga ADR 0006 (BD-por-workspace separado). O SAR agora conecta ao
banco PostgreSQL do ERP (módulo SIG) e usa o schema `sar` para tudo.

PRISMA
- Remove: Client, Product, Order, OrderItem, OrderStatusHistory,
  RepTarget, RepDiscountLimit, PushSubscription (modelos isolados)
- Adiciona: Pedido, PedidoItem, HistoricoPedido, AlcadaDesconto,
  MetaRepresentante, PushSubscription (mapeados para sar.*)
- IDs: id_cliente/cod_vendedor/id_empresa são INTEGER (ERP)
- situa: Int (1=Pendente 2=Aprovado 3=Cancelado 4=Faturado)
- JWT: workspace_id:string → id_empresa:number
- URL: inclui ?schema=sar para Prisma rotear ao schema ERP

SERVICES
- ClientsService: $queryRawUnsafe contra sar.vw_clientes + sar.pedidos
- CatalogService: $queryRawUnsafe contra sar.vw_produtos + sar.vw_estoque
- OrdersService: Prisma models Pedido/PedidoItem/HistoricoPedido/AlcadaDesconto
- DashboardService: MetaRepresentante + queries raw para inativos
- NotificationsService: PushSubscription com codVendedor + idEmpresa

CONTRATOS (api-interface)
- client.contract: campos ERP (idCliente, nome, cgcpf, cod_vendedor…)
- order.contract: PedidoSummary/PedidoDetail/CreatePedido + SITUA_LABEL
- product.contract: ProdutoSummary/ProdutoDetail (vw_produtos)
- auth.contract: workspaceId:string → idEmpresa:number

WEB
- Todos os cockpits e queries atualizados para os novos tipos

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-28 21:51:16 +00:00
246eb28bb1 feat(infra): schema SAR no banco do ERP — views SIG + tabelas de escrita
Cria scripts/sar-erp-schema.sql com tudo no schema sar:
- 15 views de leitura (vw_clientes, vw_produtos, vw_estoque, vw_pautas,
  vw_representantes, vw_empresas, vw_ctr, vw_pedidos_erp, etc.) que
  espelham gestao.* e sig.* sem modificar o ERP
- Tabelas de escrita SAR: pedidos, pedido_itens, historico_pedido,
  alcada_desconto, meta_representante, push_subscription
- Índices e grants comentados prontos para prod

Arquitetura: SAR on-prem no mesmo PostgreSQL do ERP (módulo SIG).
Substitui ADR 0006 (BD-por-workspace separado) — workspace = id_empresa.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-05-28 20:51:24 +00:00
a1a852c44d feat(c6): notificações e push — Web Push VAPID, badge dinâmico, Share API
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>
2026-05-28 12:31:13 +00:00
e3587e680a feat(infra): script de provisionamento de workspace — C9
pnpm workspace:provision --id <id> [--name <nome>] [--with-seed]
Cria banco sar_workspace_{id}, habilita extensões, aplica todas as
migrations e opcionalmente popula dados demo. Sem master DB necessário
— JwtAuthGuard resolve a URL pela convenção de nome (ADR 0006).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 01:06:43 +00:00
da2f1020d1 fix(web): remove prefixos /api/v1 hardcoded nas queries ping e clients
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 01:00:45 +00:00
56ca650962 fix(web): remove prefixo duplicado /api/v1 no DevLogin
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 00:57:22 +00:00
acab5b8a55 fix(web): adiciona prefixo /api/v1 no apiFetch — proxy Vite não roteava
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 00:55:42 +00:00
a9c15ac4ec fix(api): mapeia campos completos de OrderSummary no DashboardService
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 00:46:32 +00:00
93bf906eec fix(api): adiciona guard prisma CLS no DashboardService
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-28 00:45:04 +00:00
36103eaa87 feat(dashboard): painel Sandra — aprovações, pedidos do dia, inativos por rep (C8)
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>
2026-05-28 00:40:08 +00:00
6028bf1ba9 feat(dashboard): painel Rafael — meta, comissão, inativos, pedidos recentes (C7)
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>
2026-05-28 00:29:31 +00:00
356c8e3c2c feat(orders): fluxo de aprovação — approve/reject endpoints + UIs (C5)
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>
2026-05-28 00:01:14 +00:00
6769a0d82a feat(c4): lançamento de pedido — catálogo, alçada por linha, POST /orders
- Prisma: Product + RepDiscountLimit + productCategory em OrderItem + migration
- Seed: 28 produtos (5 categorias) + alçadas user-001 (default 10%, bebidas 8%, perecíveis 5%)
- @sar/api-interface: ProductSummarySchema, ProductDetailSchema, ProductSyncRequestSchema, CreateOrderSchema
- API: CatalogModule (GET /catalog, GET /catalog/:id, POST /catalog/sync)
- API: POST /orders — valida alçada por linha/produto (OQ-2), idempotency-key (FR-4.3), desnorm cliente
- Web: NewOrderPage (3 steps: catálogo → desconto/obs → confirmação)
- Web: botão Novo Pedido na ClientDetailPage (desabilitado se financialStatus=blocked)
- Web: rota /pedidos/novo com search param clientId

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 23:45:11 +00:00
c36451dd33 feat(c3): consulta de pedidos — schema, api, web (OrdersModule + ClientDetailPage)
- Prisma: Order, OrderItem, OrderStatusHistory + migration
- Seed: 17 pedidos em 7 clientes com itens, histórico e desnorm de clientes
- @sar/api-interface: contratos Zod (OrderSummary, OrderDetail, OrderListQuery, etc.)
- API: GET /orders, GET /orders/:id, GET /clients/:id/orders (últimos 10)
- Web: OrdersPage (lista + filtro status/número + pending_approval highlighted)
- Web: ClientDetailPage (ficha completa + últimos 10 pedidos)
- Web: /pedidos e /pedidos/$id adicionados ao router; ClientDetailPage substitui placeholder

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 23:31:18 +00:00
14c8350216 feat(api,web): c2 consulta de clientes — list + search + auth flow
prisma: modelo Client + migração 20260527225728_add_client + seed dev (10 clientes)
api: GET /clients (list, busca, filtro atividade/financeiro, paginação) + GET /clients/:id
     rep vê carteira própria; supervisor/admin vê tudo; activityStatus calculado de lastOrderAt
@sar/api-interface: ClientSummarySchema, ClientDetailSchema, ClientListResponseSchema
web: ClientsPage (tabela AntD, busca, filtro), DevLogin (token dev), authStore, Bearer no apiFetch
oq-4 resolvida: creditLimit gerenciado no SAR

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 23:08:57 +00:00
2a8be3fd82 feat(api): master-login stub + WorkspacePrismaPool (Frente E)
- Prisma 7: prisma.config.ts com datasource.url (API correta); schema gerado em CJS
- WorkspacePrismaPool: LRU cache (max 10) de PrismaClient por workspace (ADR 0006)
  PrismaPg adapter + pg.Pool por workspace; getOrCreate/health/onModuleDestroy
- JwtAuthGuard: global APP_GUARD, jose HS256, popula CLS com workspace_id/userId/prisma
  @Public() decorator marca ping/health/dev-auth como rotas abertas
- DevAuthController: POST /auth/dev/token — emite JWT dev (404 em produção)
- AuthTokenResponseSchema + DevTokenRequestSchema em @sar/api-interface
- WorkspacePoolHealthIndicator: health/ready reporta amostra LRU top-3 (nunca O(N))
- .npmrc: hoist @prisma/client-runtime-utils (requerido pelo Prisma 7 isolated mode)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 22:36:00 +00:00
bca2e3ebb3 docs(docs): prd MVP SAR finalizado — Rafael + Sandra (C1–C9, 45 FRs)
Fast path sobre Phase 1+2. Escopo: consulta de clientes, histórico de
pedidos, lançamento offline com Idempotency-Key e aprovação de desconto.
Reviewer gate aplicado: 3 fixes (offline/crédito, falha de sync, OQ-2).
6 OQs abertas; OQ-1/OQ-4 bloqueiam C2/C4 até primeiro cliente confirmar.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 21:07:53 +00:00
70ecfdc927 docs(config): atualiza design log com Frente D
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 19:55:28 +00:00
fdbf40cd1a chore(config): frente D — ESLint boundaries + Husky + commitlint + gitleaks
Higiene de PR antes da primeira feature de domínio.

- Tags Nx canônicas (scope/type/domain) em todos os 5 projetos, incluindo e2e
- depConstraints ESLint: scope:api|web|shared + type:app|e2e|feature|util|data
- Husky 9 + lint-staged: eslint --max-warnings=0 + prettier --check em pre-commit
- commitlint @conventional: tipo obrigatório, scope enum warn, body ilimitado
- gitleaks via Docker: zero leaks no tree completo; allowlist .agents/,.claude/,tmp/
- tmp/ adicionado ao .gitignore (relatórios de scan locais)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-27 19:52:05 +00:00
29321f54c0 feat(web): ping API ponta-a-ponta via TanStack Query + Zod contract
Fecha loop B+C — Web consome @sar/api-interface em runtime, não só build.

- Vite proxy /api → localhost:3000 (zero CORS em dev, mesma URL em prod via Nginx)
- api-client.ts: fetch wrapper parseando RFC 9457 problem+json em ApiError
- useApiPing: TanStack Query + PingResponseSchema.parse — drift servidor falha alto
- FoundationStatus pill na Topbar (verde/vermelho/cinza + Tooltip com requestId)

Validado via curl proxy:4200 → 200 ok contratual; /nope → 404 problem+json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 19:14:40 +00:00
4649289213 fix(infra): mount Postgres 18+ canon (/var/lib/postgresql)
Postgres 18 mudou o layout do mount canônico — dados ficam em subdir por
major-version (18/main) pra suportar pg_upgrade --link sem boundary
issues. Ref: docker-library/postgres#1259.

Antes: container subia em loop com "in 18+, these Docker images are
configured to store database data in a format compatible with
pg_ctlcluster" e "there appears to be PostgreSQL data in:
/var/lib/postgresql/data (unused mount/volume)".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 18:51:46 +00:00
ce5494aa8b feat(shared): contrato Zod PingResponse em @sar/api-interface (Frente C)
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>
2026-05-27 18:51:35 +00:00
055f9f98f0 feat(api): foundation canon JCS — Pino+CLS+RFC9457+health+ping (Frente A)
Estabelece a fundação operacional de apps/api conforme STACK.md v2.2 e
CODING-RULES.md v2.0, substituindo o hello-world scaffolded.

- tracing.ts primeiro import (PGD-OBS-001) — stub OTel ativável por env
- EnvSchema Zod 4 com fail-fast (superRefine guarda prod) + EnvModule global
- nestjs-pino com redact LGPD (*.cpf|*.cardNumber|*.password|auth|cookie)
- main.ts hardenizado: helmet, CORS por env, compression, versionamento URI
  /api/v1, graceful shutdown
- ProblemDetailsFilter global (RFC 9457 application/problem+json), Zod -> 422
- Health endpoints /api/v1/health/{live,ready} com memory.checkHeap(350MB)
  (ready skeleton documenta K=3 LRU pool conforme PGD-OBS-003)
- WorkspaceModule via ClsModule.forRootAsync — requestId+workspaceId no CLS,
  idGenerator alinhado com pino-http para mesmo UUID em header e body
- GET /api/v1/ping retornando workspaceId+requestId (alvo de smoke test e
  futuro healthcheck do docker compose)
- ZodValidationPipe (nestjs-zod) como APP_PIPE global
- tsconfig.app.json target ES2023 (alinhado ao base)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 17:50:42 +00:00
3a42723c71 feat(web): foundation com brand JCS + AntD theme + Rafael painel placeholder
- Design tokens (CSS variables) espelhando brand.md v1.0:
  - Paleta JCS Blue #004a99 + estados funcionais
  - Plus Jakarta Sans Variable self-host (LGPD + perf)
  - Radius 12/20, sombra 0 4px 25px rgba(0,0,0,0.05)
  - Layout topbar 80 + sidebar 260 (brand.md canon)
- AntD ConfigProvider com tema JCS (cores, fonts, radius, shadow, motion)
- TanStack Router + Query setup com defaults conservadores
- AppShell desktop (Topbar + Sidebar) com tom canônico
- RafaelPainel placeholder com vocabulário canônico:
  meta de maio, clientes esfriando (OPENFRIOS 47 dias), próxima visita,
  comissão+FLEX, copy direta apple-inspired
- Logos copiadas para apps/web/public/
- Limpeza: removidos placeholders Nx (app.tsx, nx-welcome.tsx, styles.css)
- pt-BR locale (dayjs + AntD)
- Build OK: 878KB JS (vai code-splitar pós cockpits separados)

Refs: brand.md, design-artifacts/A-Product-Brief/03-visual-direction.md,
      design-artifacts/B-Trigger-Map/personas/02-rafael-representante.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 17:12:34 +00:00
17c08e6392 chore: initial monorepo scaffold + WDS Phase 1+2 artifacts
- Nx 22.7 monorepo (pnpm 11.1, TypeScript 5.9, Node 24)
- apps/api: NestJS 11 (CJS conforme CODING-RULES.md PGD-DB-004)
- apps/web: React 19 + Vite 8 (ESM)
- libs/shared/api-interface: Zod contract base
- Docker Compose dev: Postgres 18, Valkey 8, MinIO, Mailpit
- WDS artifacts:
  - design-artifacts/A-Product-Brief/ (5 docs canônicos + 16 dialogs)
  - design-artifacts/B-Trigger-Map/ (hub + 4 personas + feature impact)
- Stack canon: STACK.md v2.2 + CODING-RULES.md v2.0 + brand.md
- AGENTS.md + README.md como entrada para devs/agentes

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 14:34:20 +00:00