Files
2026-10-03 00:36:29 -03:00

13 KiB
Raw Permalink Blame History

P00 — Discovery técnico e auditoria do módulo existente

Data: 2026-10-02
Escopo auditado: c:\Users\Usuário\Documents\crm (package crm-2.0, Next.js 16.0.10).
Workspace desta sessão: gerador-contratos (repositório Gitea vazio, sem código de produto).
Cópia irmã Documents\CRM-2.0 existe e contém o mesmo módulo antigo de contratos, sem as migrations mais novas da calculadora. A fonte usada aqui é crm.

Nenhum código de produto, banco ou UI foi alterado.

Achado de localização

O Gerador de Contratos não pode nascer neste repositório. gerador-contratos só tem git e remote https://gitea.fatorxtech.com/cferraz/gerador-contratos.git. Auth, RLS, feature flag, AppShell, Sentry, Redis e Design System estão em crm.

A spec e a regra do módulo proíbem arquitetura paralela. DT-CTR-007 foi aprovado: implementar dentro de crm, preservando /dashboard/contracts.

Arquitetura atual

Sidebar (lib/nav.ts, flag contracts)
        |
        v
app/dashboard/contracts/layout.tsx
  requireFeature('contracts')  --> fail-closed, redirect /dashboard
        |
        +-- page.tsx            lista
        +-- new/page.tsx        ContractWizard (passos fixos)
        +-- [id]/page.tsx       ContractEditor
        +-- actions.ts          Server Actions (CRUD, PDF, deal)
        |
        v
Supabase Auth/SSR + getCurrentWorkspaceId()
  cookie active_workspace_id validado por membership
        |
        v
Postgres
  contracts + contract_commercial + contract_sla_items
  + contract_modules + contract_clauses
  + contract_sla_defaults + contract_clause_defaults
  RLS: is_workspace_member (qualquer papel)
        |
        v
PDF @react-pdf/renderer (utils/contractPdf.tsx)
  persistido no bucket privado Storage `contracts`
  caminho {workspace_id}/{contract_id}.pdf
  pdf_url gravado na linha

API externa paralela (Bearer API key, service role):
  POST/GET /api/v1/contracts
  /api/v1/contracts/defaults
  /api/v1/contracts/:id
  POST /api/v1/contracts/:id/generate-pdf

Fora deste fluxo, e não é o gerador:

  • calculator_contracts (migration 156) confirma uma versão imutável de proposta da calculadora. Dono, time e hash. Não usar essas tabelas para templates.

Inventário

Caminho Papel Classe
lib/nav.ts Item Contratos, flag contracts REUTILIZAR
utils/featureFlags.ts isFeatureEnabled / requireFeature, sem linha = desligado REUTILIZAR
app/dashboard/contracts/layout.tsx Guard da flag REUTILIZAR
utils/supabase/server.ts, utils/supabase/user.ts Auth SSR REUTILIZAR
utils/workspace.ts getCurrentWorkspaceId, isWorkspaceAdmin, isWorkspaceManager, getManagedTeamIds REUTILIZAR
utils/workspaceAdmin.ts Decisões puras de papel REUTILIZAR
migrations/038_contracts.sql Schema do contrato comercial Fly Apex MANTER como legado; não é o gerador
app/dashboard/contracts/actions.ts CRUD do contrato fixo ADAPTAR só depois do DT-CTR-007; hoje qualquer membro edita
components/Contracts/ContractWizard.tsx Wizard de campos fixos + hex antigo ADAPTAR ou conviver; não é wizard de template
components/Contracts/ContractEditor.tsx Editor de cláusulas/SLA/módulos idem
components/Contracts/DealContractsTab.tsx Contratos no card do deal REUTILIZAR o gancho de deal; domínio novo é outro
components/Contracts/ContractStatusBadge.tsx Badge de status comercial REUTILIZAR se o status legado permanecer
utils/contractPdf.tsx PDF do schema fixo + persistência ADAPTAR o renderer; o modelo de documento é CRIAR
app/api/v1/contracts/** API externa do schema antigo MANTER para o legado; API nova só se DT-CTR-006 exigir
utils/sanitize.ts stripHtml / sanitizeText (remove tags) ADAPTAR; não é sanitizador HTML com allowlist
utils/auditLog.ts Auditoria de plataforma (workspace/user/org) ADAPTAR o padrão; eventos de contrato são CRIAR
utils/rateLimit.ts, utils/cache.ts Redis/ioredis, rate limit fail-open REUTILIZAR
sentry.*.config.ts, instrumentation-client.ts Sentry, sendDefaultPii: false, replay em erro ADAPTAR (falta scrub de conteúdo contratual)
app/globals.css tokens --bc-* Traxion DS implementado no app REUTILIZAR; ver conflito visual abaixo
scripts/db/migrate.ts + migrations/*.sql Migrations numeradas, npm run migrate REUTILIZAR
.github/workflows/ci.yml npm ci, Node 20, tsc, build REUTILIZAR
Famílias/versões de template, placeholders, drafts 24 h, Contract Document Model inexistentes CRIAR

Não há parser DOCX, upload de .docx/.txt de modelo, autosave de rascunho de formulário, nem cota de 10 modelos.

Schema encontrado

Migration 038_contracts.sql:

  • contracts: workspace, deal opcional, título, cliente, status rascunho|enviado|assinado|ativo|expirado|cancelado, pdf_url.
  • contract_commercial: limites, setup, mensalidade, vencimento, pagamento.
  • contract_sla_items, contract_modules, contract_clauses.
  • contract_sla_defaults e contract_clause_defaults: seed global (workspace_id nulo) ou por workspace. Escrita de global exige is_superadmin().
  • Flag contracts inserida com enabled_globally = false.
  • RLS de membro em todas as tabelas de contrato. Sem divisão owner/admin vs gestor/agent.
  • Nenhuma migration posterior altera public.contracts.

calculator_contracts é outro bounded context (proposta da calculadora).

Feature flag e guards

  • Flag contracts, default global desligado. Override por workspace vence o global (utils/featureFlags.ts).
  • Ausência da linha retorna false (fail-closed).
  • Layout chama requireFeature('contracts') e redireciona para /dashboard.
  • Server Actions repetem guardFeature().
  • API v1 repete a checagem e devolve 403.
  • Sidebar só mostra o item com a flag ligada.
  • Não há guard de papel nas actions de contrato. isWorkspaceAdmin() não é usado em app/dashboard/contracts.

Tenant: getCurrentWorkspaceId() lê o cookie active_workspace_id e confirma membership. As queries filtram workspace_id no servidor. A API v1 usa o workspace da API key, não um id solto do body.

Gaps contra o Gerador de Contratos

Requisito Estado
Famílias e versões; mesmo nome cria versão; sem overwrite Inexistente. Defaults globais são seed fixo.
Upload .docx/.txt, 5 MB, 50 {{chave}} Inexistente.
Tipos data_* date, valor_*/preco_* number, resto text Inexistente. Campos comerciais são colunas fixas.
Todos os campos obrigatórios Wizard só exige título.
Máx. 10 modelos-base ativos; versões não contam Inexistente.
Draft autosave ~15 s, TTL 24 h Inexistente. Status rascunho é o contrato persistido.
Draft ativo bloqueia exclusão da versão Delete bloqueia só status assinado e ativo.
Preview e PDF no mesmo Contract Document Model PDF lê o schema relacional direto. Não há preview compartilhado.
PDF não é repositório permanente no MVP O fluxo atual grava o PDF no Storage e pdf_url.
owner/admin gerenciam templates; gestor/agent operam Qualquer membro do workspace faz CRUD.
Superadmin não edita documento privado no fluxo comum Superadmin entra em isWorkspaceAdmin (plataforma). Defaults globais usam is_superadmin(). Não misturar com o fluxo operacional novo.
Sentry sem conteúdo contratual sendDefaultPii: false. Sem beforeSend que raspe corpo de contrato, formulário, token ou cookie. Replay de erro está ligado no client (replaysOnErrorSampleRate: 1).
UI no Design System, sem tokens do protocolo antigo Wizard/editor usam hex #001A3B, #00478F, #00AEEF. O app vivo usa --bc-* (Traxion).

Conflitos que não devem ser resolvidos em silêncio:

  1. O módulo em produção é um contrato comercial de plataforma (SLA, módulos, cláusulas markdown), ligado a deal e funil (proposal_created / proposal_sent). O gerador novo é template com placeholders. Substituir o schema atual quebra deal, API v1 e PDF armazenado.
  2. A spec chama o visual de EloPro Design System V2.1. No crm o handoff implementado é Traxion DS, tokens --bc-* em app/globals.css e docs/design/redesign-traxion-ds1.md. Não há artefato nomeado V2.1 neste repo. Os hex do wizard são o visual antigo e não devem ser copiados.
  3. audit_log da plataforma não tem ações de contrato e o target_type não inclui contrato. A calculadora tem calculator_audit_log próprio. O gerador precisa de trilha nova, no mesmo estilo, sem enfiar conteúdo do documento no meta.

Estratégia recomendada

Não apagar o módulo atual nesta fase.

  1. Implementar o gerador dentro de crm, na flag contracts já existente.
  2. Conviver com o contrato comercial legado até uma decisão de produto (aba, rota irmã ou substituição). Não reutilizar contracts / contract_clauses como tabela de template.
  3. Criar tabelas novas de família, versão, campo, draft e auditoria do gerador, com RLS por workspace_id e checagem de papel no servidor (isWorkspaceAdmin para gestão).
  4. Reusar Auth SSR, getCurrentWorkspaceId, feature flag, nav, Redis, @react-pdf/renderer, runner de migration e CI.
  5. PDF novo: gerar sob demanda com o Contract Document Model e não gravar como acervo. O bucket contracts continua válido para o PDF legado.
  6. UI nova com tokens --bc-* já presentes, até alguém apontar o arquivo V2.1 se ele for diferente do Traxion.

Decisões aprovadas em 2026-10-02 (encerram o P00)

  1. Implementar dentro de Documents\crm, ao lado do módulo antigo. Não substituir, migrar nem alterar o contrato comercial ligado ao deal.
  2. Parser DOCX: Mammoth. Sanitização HTML: sanitize-html no servidor, obrigatória antes de persistir ou renderizar, preservando {{chave}}. Sem troca de biblioteca; Mammoth fica no Node (não no client e não no Edge). Cabeçalho, rodapé e caixa de texto seguem fora até a matriz DT-CTR-003.
  3. Sem endpoint público /api/v1 para o gerador. A API antiga permanece só no domínio legado.

Os dez achados deste relatório continuam vinculantes. workspace_id não vem do browser. Tabela do módulo antigo não é reaproveitada por semelhança de nome.

Decision gates

Gate Status Evidência
DT-CTR-001 parser DOCX RESOLVIDO Mammoth 1.13 no crm. Conversão do upload fica no P03. Roda só no Node.
DT-CTR-002 sanitização HTML RESOLVIDO sanitize-html no servidor (lib/gerador-contratos/sanitize.ts), antes de persistir ou renderizar. {{chave}} é preservado fora de tag removida.
DT-CTR-003 matriz DOCX PENDENTE Cabeçalho, rodapé, caixa de texto e estilo não estão prometidos.
DT-CTR-004 Storage RESOLVIDO POR EVIDÊNCIA Supabase Storage. Bucket privado contracts, service role, URL assinada. Templates devem usar esse mecanismo; o path/bucket exato do arquivo-fonte fica para a implementação, sem trocar de produto.
DT-CTR-005 deploy/CI/package RESOLVIDO POR EVIDÊNCIA npm (package-lock.json), Node 20, npm run migrate via postgres+tsx, CI em .github/workflows/ci.yml (tsc + build; lint não bloqueia).
DT-CTR-006 API /api/v1 RESOLVIDO Sem API pública nova no gerador. /api/v1/contracts permanece só no legado.
DT-CTR-007 migração de /dashboard/contracts RESOLVIDO Convive. Gerador em /dashboard/gerador-contratos. Contrato comercial do deal intocado.

Plano P01–P12 (só depois do DT-CTR-007)

Trabalho no repo crm, branch dedicada. Este repo gerador-contratos não recebe o app.

  1. P01 Fundação: tipos de domínio, guards de flag e de admin, esqueleto de telas (lista, novo, modelos admin, histórico) sem parser nem PDF novo.
  2. P02 Migrations novas (próximo número após a última em crm/migrations), RLS por workspace e papel, índices. Não alterar o significado das tabelas da 038.
  3. P03 Upload e parser com Mammoth e sanitizeContractHtml. Validação 5 MB, 50 chaves, tipos por prefixo, cota de 10 bases, versão por nome. A matriz DT-CTR-003 continua em aberto.
  4. P04 Wizard operacional: escolha, revisão, formulário dinâmico, tudo obrigatório.
  5. P05 Draft autosave ~15 s, TTL 24 h. Redis só como apoio; Postgres é a fonte se o draft precisar sobreviver. Bloqueio de exclusão com draft ativo.
  6. P06 Contract Document Model único para preview e PDF. @react-pdf/renderer. Sem persistir o PDF novo.
  7. P07 Admin de templates, versões, exclusão protegida, auditoria sem conteúdo sensível no log.
  8. P08 Trocar hex do fluxo novo pelos tokens --bc-*. Não criar design system.
  9. P09 Hardening: papel no servidor, scrub Sentry (corpo, formulário, token, cookie, replay), upload, XSS, rate limit reusando utils/rateLimit.ts.
  10. P10 Vitest + critérios de aceite. E2E no Playwright já existente se o fluxo estiver estável.
  11. P11 Performance, WCAG AA, responsivo.
  12. P12 Rollout pela flag contracts (continua fail-closed, default desligada).

P13 e P14 ficam para revisão e correção, fora deste plano de construção.