Ir para o conteúdo

Portal do Cliente — Veggi Connect Hub (seller-share-vault)

Uso interno

Este documento contém referências à estrutura interna de sistemas. Não compartilhar externamente.

Versão: 1.1 · Atualizado: Abril 2026


Visão Geral

O seller-share-vault é o frontend React do Veggi Connect Hub — o portal onde o cliente visualiza e baixa as fotos dos produtos do seu pedido. O cliente acessa via link recebido por e-mail ou WhatsApp no formato:

https://hub.grupoveggi.com.br/?token={token}

O portal é estático (sem backend próprio) — toda a lógica de dados vem do Worker drive via API REST.


Stack Técnica

Item Tecnologia
Framework React 18 + TypeScript
Build Vite
Estilo Tailwind CSS + shadcn/ui (Radix UI)
Roteamento React Router DOM
Estado React Query (TanStack)
Virtualização @tanstack/react-virtual
Ícones Lucide React
Notificações Sonner
Geração de ZIP client-zip
Origem Criado no Lovable
Repositório veggidocs/seller-share-vault (GitHub)
Deploy Cloudflare Pages — branch main → automático
Domínio hub.grupoveggi.com.br

Estrutura de Componentes

src/
├── pages/
│   ├── Index.tsx          ← Página principal — lê o token e decide qual estado mostrar
│   └── NotFound.tsx       ← Página 404
├── components/
│   ├── DownloadPortal.tsx ← Galeria principal com seleção e download
│   ├── PortalHeader.tsx   ← Cabeçalho com nome do cliente, NF e validade
│   ├── FilterBar.tsx      ← Filtros por categoria (primeira palavra do nome do produto)
│   ├── SearchBar.tsx      ← Busca por nome de produto
│   ├── MediaCard.tsx      ← Card individual de cada foto
│   ├── Lightbox.tsx       ← Visualização em tela cheia ao clicar na foto
│   ├── ExpiredLink.tsx    ← Tela de link expirado com botão de WhatsApp
│   ├── LoadingState.tsx   ← Tela de carregamento
│   ├── ErrorState.tsx     ← Tela de erro genérico
│   └── ui/                ← Componentes shadcn/ui (não editar diretamente)
├── types/
│   └── portal.ts          ← Tipos TypeScript + constantes de URL + funções utilitárias
└── hooks/
    └── use-mobile.tsx     ← Hook para detectar mobile

Fluxo de Funcionamento

1. Cliente abre hub.grupoveggi.com.br/?token=abc123...
2. Index.tsx lê o ?token da URL
3. Faz GET https://drive.grupoveggi.com.br/api/token/{token}
        ├── 404 → token não existe ou expirou → mostra ExpiredLink
        ├── Erro de rede → mostra ErrorState
        └── 200 OK → recebe JSON com dados do pedido
4. Valida: expires_at no futuro? Tem arquivos?
        ├── Não → mostra ExpiredLink
        └── Sim → monta PortalData e renderiza DownloadPortal
5. Cliente vê galeria de fotos agrupadas por produto
        ├── Pode filtrar por categoria (primeira palavra do nome_produto)
        ├── Pode buscar por texto
        ├── Pode clicar em uma foto para ver em Lightbox
        ├── Pode baixar uma foto individualmente (ícone de download no card)
        └── Pode selecionar fotos e clicar "Baixar Seleção"
6. Ao clicar "Baixar Seleção":
   POST https://drive.grupoveggi.com.br/entrega
   Header: X-Drive-Secret: veggi-drive-2026-xpto
   Body: { token, numero_nf, selecionados: [{path, nome_produto}] }
7. Worker drive gera token temporário (30 min) e retorna download_url
8. Portal abre drive.grupoveggi.com.br/{token_temp}?download=1
   ZIP é gerado no browser do cliente via client-zip

Estados Possíveis da Página

Estado Quando acontece Componente exibido
loading Aguardando resposta da API LoadingState
no-token URL sem ?token= ErrorState com mensagem específica
error Falha de rede ou erro HTTP ErrorState genérico
expired Token expirado, inválido ou sem arquivos ExpiredLink — exibe botão de WhatsApp para solicitar novo acesso
ready Tudo OK DownloadPortal — galeria completa

Info

Na tela ExpiredLink, o cliente vê um botão "Solicitar novo acesso" que abre o WhatsApp com uma mensagem pré-preenchida informando o token expirado.


Constantes Importantes no Código

Estas constantes estão hardcoded no código e precisam ser atualizadas se os serviços mudarem:

Arquivo Constante Valor atual O que é
src/types/portal.ts ~~BACKBLAZE_BASE_URL~~ ~~https://f005.backblazeb2.com/file/drive-inteligente/~~ Removida em Abril/2026 — substituída por buildImageUrl via /file-proxy
src/types/portal.ts API_BASE_URL https://n8n.nerd2nerd.com.br/webhook/entrega URL legada — não está sendo usada pelo portal atual
src/components/DownloadPortal.tsx DOWNLOAD_ENDPOINT https://drive.grupoveggi.com.br/entrega Endpoint do Worker drive para gerar o ZIP
src/components/DownloadPortal.tsx DRIVE_SECRET veggi-drive-2026-xpto Segredo de autenticação enviado no header X-Drive-Secret

Warning

O DRIVE_SECRET está hardcoded no frontend — qualquer pessoa com acesso ao código-fonte pode ver esse valor. Para o contexto atual (portal restrito por token), o risco é baixo, mas idealmente esse segredo deveria ser tratado como uma variável de ambiente de build.

Warning

A constante API_BASE_URL em portal.ts aponta para um endereço n8n antigo (nerd2nerd.com.br) e não está sendo utilizada pelo fluxo atual. Pode ser removida ou atualizada em manutenção futura.


Como Fazer Deploy de Atualização

O deploy é 100% automático. Qualquer push no branch main do repositório veggidocs/seller-share-vault dispara um novo build no Cloudflare Pages.

Passos para atualizar:

  1. Editar o arquivo desejado no repositório
  2. Fazer commit e push no branch main
  3. Aguardar 1–2 minutos
  4. Verificar o resultado em Workers & Pages → connect-hub → aba Implantações

Para atualizações maiores (recomendado):

  1. Criar um branch separado (ex: fix/constante-url)
  2. Fazer as alterações e abrir um Pull Request
  3. O Cloudflare Pages cria automaticamente um preview URL para testar
  4. Após validar, fazer merge no main

Histórico de Mudanças

Abril 2026 — Otimizações de Performance (INP e LCP)

Contexto: Análise via Cloudflare Web Analytics e Chrome DevTools identificou INP de 2.600 ms e LCP de 4.287 ms no portal. As mudanças abaixo reduziram o INP para 45 ms (medido em janela anônima) e eliminaram o tráfego direto ao Backblaze B2 nos cards.

Arquivo Mudança Motivo
src/components/MediaCard.tsx Adicionado decoding="async" no <img> Evita bloqueio do thread principal durante decodificação de imagens
src/components/DownloadPortal.tsx Substituído let globalIndex = 0 solto no render por useMemo com indexedFiles globalIndex no render causava índices instáveis a cada re-render, quebrando o Lightbox
src/components/DownloadPortal.tsx Adicionada virtualização com @tanstack/react-virtual Com 66+ imagens, o DOM completo travava o browser no carregamento inicial. A virtualização renderiza apenas os cards visíveis na tela
src/types/portal.ts buildImageUrl alterado para usar /file-proxy do Worker drive em vez de f005.backblazeb2.com diretamente Ativa o cache Cloudflare já configurado no Worker (cacheTtl: 3600). Imagens passam a ser servidas do edge após a primeira visita
src/types/portal.ts Constante BACKBLAZE_BASE_URL removida Não é mais utilizada após mudança do buildImageUrl

Resultado medido (Chrome DevTools, janela anônima):

Métrica Antes Depois
INP ~98 ms (sessão normal) / 2.600 ms (Cloudflare Analytics) 45 ms
CLS 0.02 0
Origem das imagens nos cards f005.backblazeb2.com (sem cache) drive.grupoveggi.com.br/file-proxy (cache Cloudflare 1h)

Info

O INP de 2.600 ms registrado no Cloudflare Analytics era influenciado por extensões de browser (Coupert) instaladas na máquina de teste. A medição em janela anônima reflete o valor real do site.


Como Rodar Localmente

Para testar alterações antes de fazer deploy:

# Clonar o repositório
git clone https://github.com/veggidocs/seller-share-vault.git
cd seller-share-vault

# Instalar dependências
npm install

# Rodar em modo desenvolvimento
npm run dev

O portal abre em http://localhost:8080. Para testar com um token real, adicione na URL:

http://localhost:8080/?token={token_valido_do_kv}

Info

O portal em desenvolvimento faz chamadas reais para drive.grupoveggi.com.br — não há mock de API local.