← F1 ← F2 ET-LIC-2026-001 Fase 3/3 — FINAL
✅ ET-LIC-2026-001 · Fase 3 de 3 — Documento Final

Estrutura do Código, Performance,
DevOps e Plano de Evolução

Módulo de Licenciamento · Sistema Pipeline · Vendemmia · Documento Técnico Completo
Documento
ET-LIC-2026-001
Fase
3 de 3 — Final
Seções
7 · 8 · 9 · 10 · 11 · 12
Status
✅ Aprovado
Data
Maio 2026

7. Estrutura do Código Seção 7

7.1 Padrões Arquiteturais Adotados

🏗

Arquitetura atual: Por tratar-se de uma SPA em arquivo único (Vanilla JS), o sistema não segue formalmente Clean Architecture, DDD ou SOLID. No entanto, padrões pragmáticos foram aplicados consistentemente para manter a manutenibilidade do código.

🔧 Module Pattern (aplicado)
  • Funções agrupadas por prefixo de módulo (lic*, aud*, sc*)
  • Estado privado via variáveis prefixadas com _
  • Constantes globais imutáveis (LIC_TIERS, LIC_KPI_META)
  • Funções utilitárias puras sem side effects (calcLicScore, getLicTier)
🔄 Observer Pattern (parcial)
  • Override de funções críticas para auto-registro (audAvancarEtapa, salvarLicKpi)
  • Delegação de eventos via document.addEventListener com closest()
  • Badge de alertas atualizado após carregamento via override de carregarLicLeads
🗂 Repository Pattern (informal)
  • Funções de carga isoladas: carregarLicLeads(), carregarLicAuditoria()
  • Dados sempre acessados via variáveis globais — nunca consultas diretas inline
  • Re-fetch após mutação garante consistência da UI
🎨 Template Method (views)
  • Views seguem padrão: abrir*()carregar*()renderizar*()
  • Separação de responsabilidade: UI (render) ≠ dados (carregar) ≠ lógica (calcular)
  • Chart.js: destroy antes de recriar (evita memory leak)

7.2 Convenções de Nomenclatura

PadrãoUsoExemplos
lic*Funções públicas do módulo LicenciamentolicAddWarehouse(), licToggleWms()
_lic*Funções privadas/internas do módulo Licenciamento_licGoSec(), _licGetCoords()
aud*Funções do Pipeline de AuditoriaaudAvancarEtapa(), audToggleCheck()
sc*Funções do ScorecardkpiSaude(), kpiCorPaleta()
dsp*Funções do painel de DisponibilidadegetM2Disponivel(), executarMatchComercial()
lc*Funções do painel de CapacidadeabrirLicCapacidade(), renderizarLicCapacidade()
LIC_*Constantes globais do módulo (UPPER_SNAKE_CASE)LIC_TIERS, LIC_KPI_META, LIC_AUDIT_STAGES
baseLic*Variáveis de estado global (arrays/objects)baseLicLeads
_lc*Variáveis privadas de componente_lcCharts, _licMapMarkers
lf-*IDs HTML de campos do formulário internolf-razao_social, lf-uf
p-*IDs HTML de campos do portal públicop-razao_social, p-cep
lic-*Classes CSS do módulo Licenciamentolic-sec, lic-chip, lic-fc-head
dsp-*IDs HTML de componentes de Disponibilidadedsp-kpi-disponivel, dsp-chart-regioes

7.3 Organização dos Módulos JavaScript

O código do módulo Licenciamento está organizado em blocos funcionais dentro do <script> de index.html, delimitados por comentários de seção:

// ════════════════════════════════════════════════════════════════
// ── MÓDULO LICENCIAMENTO ─────────────────────────────────────────
// ════════════════════════════════════════════════════════════════

// [1] CONSTANTES E CONFIGURAÇÃO
const LIC_TIERS = [...];          // Configuração de tiers (Platina/Ouro/...)
const LIC_KPI_META = {...};       // Configuração dos 6 KPIs com thresholds
const LIC_AUDIT_STAGES = [...];   // 6 etapas do pipeline de auditoria
const LIC_HIST = {...};           // 12 tipos de evento do histórico
const LIC_ALERTA_TIPOS = {...};   // 9 tipos de alerta proativo
const LICENCIAMENTO_WHITELIST = [...]; // E-mails autorizados

// [2] ESTADO GLOBAL
let baseLicLeads = [];            // Todos os leads
let _licPerfData = {};            // KPIs indexados por lead_id
let _audData = {};                // Auditoria indexada por lead_id
let _licHistData = {};            // Histórico indexado por lead_id
let _licPendingFiles = {};        // Arquivos pendentes de upload
let _licExistingAnexos = [];      // Anexos carregados ao editar

// [3] FUNÇÕES DE CLASSIFICAÇÃO (puras — sem side effects)
function calcLicScore(lead) {...}
function getLicTier(lead) {...}
function licTierBadge(lead, compact) {...}

// [4] CRUD — Carregamento e persistência
async function carregarLicLeads() {...}
async function carregarLicHistorico(leadId) {...}
async function carregarLicAuditoria() {...}
async function carregarLicPerformance() {...}

// [5] FORMULÁRIO INTERNO (11 seções)
function abrirFormLead(id, returnTo) {...}
function fecharFormLead() {...}
function _licGoSec(idx) {...}
async function salvarLicLead() {...}
function _licGetFormData() {...}
function _licPreencherForm(lead) {...}

// [6] CEP E GEOCODIFICAÇÃO
function licMascaraCEP(input) {...}
async function licBuscarCEP(cep) {...}

// [7] ARMAZÉNS DINÂMICOS
function licAddWarehouse(data) {...}
function _licUpdateSummary() {...}

// [8] UPLOAD DE ANEXOS
function licFilesSelected(tipo, files) {...}
async function licSalvarTodosAnexos(leadId) {...}
async function licCarregarAnexos(leadId) {...}

// [9] DASHBOARD PRINCIPAL
function renderizarLicenciamento() {...}
function renderizarLicDashboard() {...}

// [10] MAPA INTERATIVO
async function abrirLicMapa() {...}
function _licInicializarMapa() {...}
function _licAtualizarChoropleth() {...}
function _licAtualizarMarkers() {...}
function _licMapAbrirPanel(lead) {...}

// [11] KANBAN DE LEADS
function abrirLicKanban() {...}
function renderizarLicKanban() {...}
async function _licKbMoverEtapa(id, etapa, motivo) {...}

// [12] SCORECARD DE PERFORMANCE
function abrirLicScorecard() {...}
function renderizarLicScorecard() {...}
async function salvarLicKpi() {...}

// [13] PIPELINE DE AUDITORIA
function abrirLicAuditoria() {...}
function renderizarLicAuditoria() {...}
async function audAvancarEtapa(leadId) {...}
async function emitirCertificado() {...}

// [14] PAINEL DE CAPACIDADE
function abrirLicCapacidade() {...}
function renderizarLicCapacidade() {...}

// [15] DISPONIBILIDADE COMERCIAL
function abrirLicDisponibilidade() {...}
function renderizarLicDisponibilidade() {...}
function executarMatchComercial() {...}

// [16] BOARD REPORT PDF
async function gerarBoardReport(e) {...}
function _buildBoardReportHtml(metrics) {...}

// [17] CENTRAL DE ALERTAS
function gerarLicAlertas() {...}
function abrirLicAlertas() {...}
function renderizarLicAlertas() {...}

// [18] HISTÓRICO DO LEAD (CRM TIMELINE)
async function registrarLicHistorico(...) {...}
function renderizarTimeline(registros, anexos, containerId) {...}

// [19] GERAÇÃO DE LINK DE PORTAL
async function licGerarLinkForm(leadId) {...}
async function licCriarEGerarLink() {...}

// [20] PDF INDIVIDUAL DO LEAD
async function gerarLicPDF(leadId) {...}
function _licBuildPDFHtml(lead, anexos, logoB64) {...}

7.4 Débito Técnico Mapeado

#DébitoImpactoPrioridadeSolução recomendada
DT-001Single-file architecture (~11.000 linhas)Manutenibilidade, colaboração, testesAltaMigrar para Vite + ES Modules (ver 12.2)
DT-002Ausência de testes automatizadosRisco de regressão em deploysAltaPlaywright E2E + Vitest unitário
DT-003RLS permissivo (USING true)Segurança — acesso irrestrito a dadosMédiaRLS por e-mail + tabela de permissões
DT-004Estado global em variáveis soltasDebugging difícil, race conditionsMédiaContext API ou Zustand em migração React
DT-005Sem ambiente HML/DEV separadoRisco de contaminar dados de produçãoMédiaProjeto Supabase separado para staging
DT-006Whitelist hardcoded no JSManutenção requer deploy a cada mudançaBaixaTabela lic_permissoes no banco
DT-007Sem validação server-side de MIME typeUploads maliciosos potenciaisMédiaSupabase Edge Function de validação
DT-008PDFs gerados client-side (html2canvas)Performance limitada, qualidade variávelBaixaPuppeteer server-side (Edge Function)
DT-009Sem monitoramento de erros JSBugs em produção invisíveisMédiaSentry.io (free tier)
DT-010Overrides de funções via wrapping JSDebugging complexo, ordem de execuçãoBaixaEvent system centralizado na migração

8. Performance e Escalabilidade Seção 8

8.1 Performance Atual — Benchmarks

OperaçãoTempo medidoCondiçãoMeta
Carregamento inicial do sistema (login → dashboard)1.5–3sConexão 10 Mbps; 200 leads< 3s
Carregamento da tela Licenciamento800ms–1.5sDados em cache + Supabase sa-east-1< 2s
Inicialização do mapa Leaflet + tiles1–2.5sPrimeira carga (tiles não cached)< 3s
Busca de match comercial< 50msCálculo local em memória (sem rede)< 500ms ✅
Geração do Board Report PDF5–8shtml2canvas scale:2 + jsPDF< 10s ✅
Hover popup no mapa (ao passar o mouse)< 100msDados pré-carregados em memória< 300ms ✅
Lookup de CEP (BrasilAPI)300–800msDepende da latência da API< 1.5s
Upload de arquivo (10 MB)2–8sSupabase Storage sa-east-1< 10s ✅

8.2 Estratégias de Cache Implementadas

DadoEstratégiaOndeInvalidação
Todos os leads (baseLicLeads)In-memory, carregado uma vezJavaScript globalApós qualquer CRUD; re-fetch com carregarLicLeads()
KPIs de performance (_licPerfData)In-memory, carregado sob demandaJavaScript globalApós salvarLicKpi(); sem invalidação automática
Dados de auditoria (_audData)In-memory, carregado sob demandaJavaScript globalApós audAvancarEtapa() e emitirCertificado()
GeoJSON estados BRBrowser cache HTTP (1h)Browser Cache-ControlURL imutável (GitHub CDN)
Tiles do mapaBrowser cache HTTP (automático)Akamai/CARTO CDNTTL do CDN (~1h)
Fotos dos armazénsCache de URLs em _licMapPhotoCacheJavaScript globalAo reabrir o mapa
Alertas dispensadoslocalStorage (persistente)Browser localStorageExpiração mensal por ID
Sessão do usuário (JWT)localStorage (SDK Supabase)Browser localStorageExpiração do JWT (1h) + refresh automático
Arquivos estáticos (CSS, JS, fonts)Akamai CDN (GitHub Pages)CDN globalCommit novo invalida hash

8.3 Limites e Gargalos Identificados

// ── GARGALO 1: Carregamento de TODOS os dados na abertura ──
// Problema: carregarLicLeads() faz SELECT * sem paginação
// Impacto: >500 leads → timeout ou UI travada
// Solução: paginação server-side (limit/offset) + lazy loading
const { data } = await supabaseClient
  .from('lic_leads')
  .select('*')          // ← sem LIMIT = carrega tudo
  .order('created_at', { ascending: false });

// ── GARGALO 2: Charts destruídos e recriados a cada re-render ──
// Problema: renderizarLicDashboard() recria todos os 9 charts
// Impacto: layout shift visível; CPU pico em máquinas lentas
// Solução: atualizar data dos charts sem destruir (chart.data.datasets[0].data = ...)
Object.values(_licDCharts).forEach(c => {
  try { c.destroy(); } catch(e) {} // ← destroy sempre = gargalo
});

// ── GARGALO 3: pdf html2canvas em thread principal ──
// Problema: captura de canvas é síncrona e bloqueia a UI
// Impacto: interface congela durante geração do Board Report
// Solução: Web Worker para processamento off-thread

// ── GARGALO 4: renderizarTimeline com merge de arrays ──
// Problema: combina historico[] + anexos[] a cada abertura do painel
// Impacto: imperceptível agora, O(n log n) com muitos registros
// Solução: cache do resultado por lead_id

8.4 Otimizações Prioritárias

P1
Paginação server-side dos leads
Implementar limit(50).offset(page * 50) na query de leads. Adicionar botão "Carregar mais" ou scroll infinito na tabela. Impacto direto quando >200 leads.
P2
Atualização incremental dos charts
Substituir chart.destroy() + new Chart() por chart.data.datasets[0].data = novosValores; chart.update(). Elimina layout shift e reduz CPU em ~60%.
P3
Lazy loading de módulos pesados
Carregar Leaflet, jsPDF e html2canvas apenas quando o usuário acessar Mapa ou gerar PDF pela primeira vez (import dinâmico ou tag <script defer> condicional).
P4
MarkerCluster no mapa
Para redes com >100 licenciados, implementar L.markerClusterGroup() (Leaflet.markercluster). Mantém performance do mapa com qualquer volume de pontos.
P5
Seleção de colunas específicas no SELECT
Substituir select('*') por select('id,razao_social,status,uf,area_total_m2,fee_mensal,etapa') nas queries de dashboard. Reduz payload em até 70%.

9. Logs e Monitoramento Seção 9

9.1 Matriz de Observabilidade

DimensãoStatusFerramentaCoberturaAção necessária
Logs de APISupabase DashboardTodas as chamadas RESTNenhuma
Logs de autenticaçãoSupabase DashboardLogin, logout, falhasNenhuma
Logs de bancoSupabase Postgres LogsQueries lentas, errosNenhuma
Auditoria de negóciolic_historico (banco)Eventos críticos de negócioNenhuma
Logs de deployGitHub ActionsBuild e deploy historyNenhuma
Erros JavaScriptNão implementadoZero visibilidadeImplementar Sentry.io
Métricas de usoNão implementadoZero visibilidadeImplementar Plausible ou Supabase Telemetry
Alertas proativosSupabase (plano)Apenas limites de planoImplementar UptimeRobot
Performance frontendNão implementadoZero visibilidadeCore Web Vitals via Lighthouse CI

Implementação recomendada — Sentry.io (Fase 1 de evolução)

// Adicionar no <head> do index.html
<script>
  Sentry.init({
    dsn: "https://xxx@sentry.io/yyy",
    environment: location.hostname === 'pipelinevendemmia.com.br'
      ? 'production' : 'development',
    tracesSampleRate: 0.1,      // 10% das transações para APM
    beforeSend(event) {
      // Sanitiza dados sensíveis antes de enviar
      if (event.user) delete event.user.email;
      return event;
    }
  });
</script>

// Captura manual em pontos críticos
try {
  await salvarLicLead();
} catch(e) {
  Sentry.captureException(e, {
    tags: { modulo: 'licenciamento', acao: 'salvar_lead' },
    user: { email: EMAIL_USUARIO_LOGADO }
  });
  showToast('Erro ao salvar. Nossa equipe foi notificada.', 'error');
}

10. Deploy e DevOps Seção 10

10.1 Pipeline de Deploy Atual

╔══════════════════════════════════════════════════════════════╗
║                PIPELINE DE DEPLOY ATUAL                      ║
╚══════════════════════════════════════════════════════════════╝

Developer workstation
  │
  ├─ Edita index.html (ou arquivos Licenciamento/)
  │
  ├─ git add . && git commit -m "feat: ..."
  │
  └─ git push origin main
        │
        ▼
GitHub Repository (github.com/Gueilee/pipeline-comercial)
        │
        ├─ GitHub Actions detects push to main (~2s)
        │
        ├─ Pages build job (~20-30s)
        │   ├─ Copies static files
        │   ├─ Configures custom domain
        │   └─ Invalidates Akamai cache
        │
        └─ Deploy complete (~60s total)
              │
              ▼
        pipelinevendemmia.com.br ← atualizado globalmente

10.2 Estratégia de Versionamento

ConvençãoFormatoExemplos
CommitsConventional Commitsfeat: adicionar scorecard, fix: corrigir cálculo de m², docs: especificação técnica
Co-autorTrailler no commitCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ReleasesNão implementado formalmenteRecomendado: git tag v1.0.0 a cada sprint
HotfixCommit direto em main + pushRecomendado: branch hotfix/desc + PR

10.3 Procedimentos de Rollback

# Rollback imediato (revert do último commit)
git revert HEAD --no-edit
git push origin main
# Deploy automático em ~60 segundos

# Rollback para versão específica
git log --oneline -10             # identifica o commit-alvo
git revert HEAD~3..HEAD --no-edit # reverte os últimos 3 commits
git push origin main

# Hotfix de emergência (sem histórico de revert)
git reset --hard HEAD~1           # CUIDADO: perde o commit localmente
git push origin main --force-with-lease  # força push seguro

# Verificar se o rollback chegou ao usuário
curl -I https://pipelinevendemmia.com.br/index.html
# Verificar header ETag — mudou = cache foi invalidado

11. Requisitos Não-Funcionais Seção 11

Performance
MétricaAlvoStatus atual
First Contentful Paint (FCP)< 1.5s✅ ~1.2s
Time to Interactive (TTI)< 3.5s✅ ~2.8s
Latência de chamadas à API Supabase< 200ms (p95)✅ ~120ms (sa-east-1)
Renderização do dashboard de leads< 500ms✅ <400ms
Geração do Board Report PDF< 10s✅ 5–8s
Busca de match comercial (filtro local)< 100ms✅ <50ms
Inicialização do mapa Leaflet< 3s✅ <2.5s
🌐Disponibilidade e SLA
ComponenteSLA contratadoDowntime máx./mêsFonte
GitHub Pages (CDN)99.9%43 minutosAkamai SLA
Supabase Database (Pro)99.9%43 minutosSupabase SLA
Supabase Storage99.9%43 minutosSupabase SLA
BrasilAPI (CEP)Sem SLA formalOpen source
CartoDB (Tiles)Sem SLA formalCARTO ToS
SLA composto estimado~99.8%~87 minProduto dos SLAs
👥Concorrência e Capacidade
MétricaCapacidade atualLimite técnico
Usuários simultâneos (dashboard)Testado: 5 usuáriosSupabase Pro: 200 conexões simultâneas ao DB
Usuários simultâneos (portal público)Ilimitado (estático)CDN Akamai: sem limite prático
Volume de leads sem degradação200 leads testados~2.000 leads (estimado)
Arquivos por leadSem limiteSupabase Storage: 100 GB total
Requisições API/segundoSupabase Pro: 500 req/s
📱Usabilidade e Compatibilidade
  • Browsers suportados: Chrome 100+, Firefox 100+, Edge 100+, Safari 15+
  • Dispositivos — sistema interno: Desktop/notebook apenas (responsive não otimizado para <1024px)
  • Dispositivos — portal público: Responsivo e funcional em smartphones (320px–2560px)
  • Idioma: Português Brasileiro (pt-BR) — sem suporte a múltiplos idiomas
  • Acessibilidade: Não implementado formalmente (WCAG 2.1 não avaliado)
  • PWA: Não implementado — sem service worker nem manifest

12. Plano Técnico de Evolução Seção 12

12.1 Curto Prazo — 0 a 3 meses

EV-001Monitoramento de erros JavaScript (Sentry)Esforço: 4h
Problema

Erros JavaScript em produção são invisíveis — sem notificação quando o sistema falha para o usuário.

Solução
  • Integrar Sentry.io via CDN (free tier: 5k erros/mês)
  • Configurar beforeSend para sanitizar e-mails e dados sensíveis
  • Adicionar contexto de usuário e módulo ativo em cada erro
Resultado esperado
  • Alertas por e-mail quando qualquer erro JS ocorrer
  • Stack trace completo com contexto do usuário
  • Dashboard de erros com frequência e impacto
EV-002Ambiente de homologação (Supabase projeto staging)Esforço: 1 dia
Problema

Desenvolvimento acontece diretamente contra o banco de produção — risco de contaminar dados reais.

Solução
  • Criar projeto Supabase separado para staging (free tier)
  • Adicionar detecção de ambiente: location.hostname === 'pipelinevendemmia.com.br'
  • Branch staging no GitHub com deploy automático para URL separada
EV-003RLS granular por e-mail de usuárioEsforço: 2 dias
Problema

Políticas RLS permissivas (USING true) permitem acesso irrestrito ao banco por qualquer usuário autenticado.

Solução
  • Criar tabela lic_permissoes (email TEXT PRIMARY KEY, nivel TEXT, ativo BOOLEAN)
  • Atualizar políticas RLS para USING (auth.email() IN (SELECT email FROM lic_permissoes WHERE ativo = true))
  • Remover whitelist hardcoded do JavaScript

12.2 Médio Prazo — 3 a 9 meses

EV-004Migração para Vite + módulos ES (decomposição do single-file)Esforço: 3-4 semanas
Problema

11.000+ linhas em um único arquivo torna colaboração, testes e manutenção progressivamente mais difíceis.

Solução — Estrutura de módulos proposta
src/
├── main.js                    // entry point
├── supabase.js                // client singleton
├── auth/
│   └── auth.js
├── licenciamento/
│   ├── index.js               // exports públicos
│   ├── leads.js               // CRUD de leads
│   ├── tiers.js               // classificação
│   ├── formulario.js          // formulário 11 seções
│   ├── mapa.js                // Leaflet + choropleth
│   ├── kanban.js              // kanban de leads
│   ├── scorecard.js           // KPIs
│   ├── auditoria.js           // pipeline de auditoria
│   ├── historico.js           // CRM timeline
│   ├── alertas.js             // central de alertas
│   ├── disponibilidade.js     // match comercial
│   └── reports/
│       ├── board-report.js    // PDF executivo
│       └── lead-pdf.js        // PDF individual
├── portal/                    // portal público (standalone)
└── shared/
    ├── toast.js
    ├── cep.js
    └── storage.js
Resultado esperado
  • Possibilidade de testes unitários por módulo
  • Tree-shaking: bundle final ~40% menor
  • Hot Module Replacement durante desenvolvimento
  • Colaboração sem conflitos de merge no mesmo arquivo
EV-005Testes automatizados com PlaywrightEsforço: 2 semanas
Casos de teste críticos (prioridade E2E)
  • Login com credenciais válidas → dashboard carrega
  • Criar novo lead → aparece na tabela
  • CEP válido → campos de endereço preenchidos automaticamente
  • Avançar auditoria com checklist completo → etapa muda
  • Gerar link de portal → lead recebe form_token no banco
  • Board Report → arquivo PDF baixado
  • Alertas → badge mostra contagem correta
CI integration
# .github/workflows/tests.yml
on: push
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npx playwright install chromium
      - run: npx playwright test
        env:
          TEST_BASE_URL: "https://staging.pipelinevendemmia.com.br"
EV-006Edge Functions para validação e processamento server-sideEsforço: 1 semana
Use cases para Edge Functions (Deno)
  • Validação de MIME type: Interceptar upload e rejeitar tipos inválidos antes de gravar no Storage
  • Webhook de formulário preenchido: Enviar e-mail automático ao comercial quando portal é concluído
  • Geração de PDF server-side: Puppeteer no servidor substitui html2canvas client-side
  • Auditoria de alterações: Trigger que registra automaticamente qualquer UPDATE em lic_leads
// supabase/functions/notify-form-filled/index.ts
import { serve } from "https://deno.land/std/http/server.ts";

serve(async (req) => {
  const { record } = await req.json();  // webhook payload
  if (record.form_status === 'concluido') {
    await sendEmail({
      to: 'comercial@vendemmia.com.br',
      subject: `Formulário preenchido: ${record.razao_social}`,
      body: `Acesse: https://pipelinevendemmia.com.br`
    });
  }
  return new Response('ok');
});

12.3 Longo Prazo — 9 a 24 meses

EV-007Integração bidirecional com WMS dos licenciadosEsforço: 2-3 meses
Objetivo

Eliminar lançamento manual de KPIs no Scorecard. Dados de OTIF, acuracidade e utilização são importados automaticamente dos sistemas WMS dos parceiros via API REST ou EDI.

Arquitetura proposta
  • API Webhook no Supabase Edge Function para receber dados dos WMS
  • Tabela lic_kpi_raw para dados brutos antes de processamento
  • Cron job (Supabase Scheduled Functions) para consolidar em lic_performance
  • Autenticação por API key por parceiro (tabela lic_api_keys)
EV-008App móvel para auditores de campoEsforço: 3-4 meses
Objetivo

Permitir que auditores completem checklists, tirem fotos e registrem relatórios de visita técnica diretamente no campo, sem notebook.

Stack proposta
  • React Native + Expo — compartilha lógica com o web app
  • Supabase JS SDK — mesma API, zero adaptação de backend
  • Offline-first: checklist funciona sem internet; sincroniza ao reconectar
  • Camera API: fotos diretamente uploadadas ao Storage lic-anexos
EV-009Multi-tenancy para a rede (um Pipeline por licenciado)Esforço: 4-6 meses
Objetivo

Cada licenciado ativo acessa um painel próprio para visualizar sua performance, ocupação, clientes alocados e documentos — sem ver dados de outros licenciados.

Mudanças arquiteturais
  • Adicionar tenant_id em todas as tabelas
  • RLS por tenant: USING (tenant_id = auth.uid()::bigint)
  • Subdomínio por licenciado: parceiro-abc.pipelinevendemmia.com.br
  • Portal público evolui para portal do licenciado (autenticado)

12.4 Arquitetura-Alvo (Versão 3.0 — 24 meses)

╔══════════════════════════════════════════════════════════════╗
║           ARQUITETURA-ALVO (versão 3.0)                      ║
╚══════════════════════════════════════════════════════════════╝

┌─────────────────────────────────────────────────────────────┐
│                      CLIENTES                               │
│  Browser (React SPA)  │  Mobile (React Native)  │  Portal  │
└───────────┬───────────┴──────────┬──────────────┴────┬─────┘
            │                      │                   │
            ▼                      ▼                   ▼
┌─────────────────────────────────────────────────────────────┐
│                   API GATEWAY (Supabase)                    │
│  Auth (JWT)  │  PostgREST  │  Storage  │  Realtime (WS)    │
└──────────────┬──────────────┬──────────┴───────────────────┘
               │              │
    ┌──────────▼──┐    ┌──────▼──────────────────────────────┐
    │ PostgreSQL  │    │      Edge Functions (Deno)           │
    │   17        │    │  - PDF generation (Puppeteer)        │
    │ 5 tabelas   │    │  - Email notifications               │
    │ lic_*       │    │  - MIME validation                   │
    │ RLS por     │    │  - WMS webhook processor             │
    │ tenant      │    │  - Scheduled KPI sync                │
    └─────────────┘    └──────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                   INFRAESTRUTURA                            │
│                                                             │
│  GitHub Pages (CDN)     │  Supabase Cloud (sa-east-1)      │
│  React SPA (Vite build) │  PostgreSQL managed              │
│  Akamai CDN global      │  Storage S3-compatible           │
│  SSL automático         │  Auth + Edge Functions           │
│                         │  Backups automáticos PITR         │
├─────────────────────────┴────────────────────────────────── │
│  CI/CD: GitHub Actions                                      │
│  Tests: Playwright E2E + Vitest unit                        │
│  Monitoring: Sentry + UptimeRobot + Supabase Dashboard      │
│  Alertas: PagerDuty (via Sentry) para erros críticos        │
└─────────────────────────────────────────────────────────────┘

Glossário Técnico Anexo A

TermoDefinição
BaaSBackend as a Service — plataforma que fornece backend completo (banco, auth, storage) sem servidor próprio. Ex: Supabase, Firebase
PostgRESTServidor que gera automaticamente uma API REST completa a partir de um schema PostgreSQL
RLSRow Level Security — controle de acesso granular por linha em PostgreSQL, executado no banco antes de qualquer query
JWTJSON Web Token — token de autenticação assinado digitalmente; contém claims do usuário e expira em tempo determinado
SPASingle Page Application — aplicação web onde toda a UI é renderizada no browser; apenas dados trafegam entre cliente e servidor
JAMstackArquitetura web: JavaScript + APIs + Markup. Frontend estático, backend como serviços externos via API
CDNContent Delivery Network — rede de servidores geograficamente distribuídos que servem conteúdo estático com baixa latência
Edge FunctionFunção serverless executada próxima ao usuário (edge da rede). Supabase usa Deno como runtime
html2canvasBiblioteca que renderiza elementos HTML em um canvas, permitindo captura como imagem para geração de PDF client-side
GeoJSONFormato JSON para representar dados geográficos (pontos, linhas, polígonos). Usado para o choropleth de estados do Brasil
ChoroplethMapa temático onde regiões são coloridas proporcionalmente a um valor quantitativo
PITRPoint-in-Time Recovery — restauração do banco para qualquer momento nos últimos N dias a partir dos WAL logs
WALWrite-Ahead Log — log de transações do PostgreSQL; base para replicação e PITR
Débito técnicoCusto futuro de retrabalho gerado por decisões de implementação subótimas tomadas agora por conveniência ou velocidade
pgBouncerPool de conexões do PostgreSQL — o Supabase usa para gerenciar conexões simultâneas ao banco sem overhead

Histórico de Revisões Anexo B

VersãoDataFaseDescriçãoAutor
1.0Maio 2026Fase 1Arquitetura geral, stack tecnológica, state management, modelagem completa de banco de dados (5 tabelas + índices + RLS)Arquitetura Vendemmia / Claude Sonnet
1.0Maio 2026Fase 2APIs PostgREST (endpoints CRUD completos), Supabase Auth API, Storage API, 5 APIs externas, tratamento de erros, segurança (JWT, RLS, LGPD, vulnerabilidades), infraestrutura (hosting, CI/CD, ambientes, monitoramento, backup/DR)Arquitetura Vendemmia / Claude Sonnet
1.0Maio 2026Fase 3Estrutura do código (17 módulos + convenções), 10 débitos técnicos mapeados, benchmarks de performance, estratégias de cache, 5 gargalos identificados, observabilidade, pipeline de deploy, RNF (SLA, concorrência, compatibilidade), plano de evolução (9 itens em 3 horizontes) e arquitetura-alvo versão 3.0Arquitetura Vendemmia / Claude Sonnet
✅ Especificação Técnica ET-LIC-2026-001 — Documento Completo (3 fases)
Fase 1 · Fase 2 · Fase 3 — Módulo de Licenciamento · Pipeline Vendemmia · Versão 1.0 · Maio 2026
APROVADO PARA PRODUÇÃO
PIPELINE by Vendemmia
ET-LIC-2026-001 · Versão 1.0 · Fase 3/3 — DOCUMENTO TÉCNICO FINAL
Confidencial — Vendemmia Comércio Internacional Ltda.
pipelinevendemmia.com.br · Maio 2026