VAR
Documentação técnica · interna

Arquitetura
do projeto

Como está montado o VAR — Verificador de Apostas Reguladas, a campanha da APAJO contra a publicidade ao jogo online ilegal. Do documento de topo à base de dados, com o percurso de cada evidência. Domínio: var-mundial.com.

TanStack Start Vite + Bun Supabase Deploy / alojamento

1 · Visão geral

O projeto é uma aplicação TanStack Start (React) servida no domínio var-mundial.com. A stack escolhida prioriza simplicidade de deploy e uma landing 100% estática.

Stack

  • TanStack Start (React) — router, rotas de API server-side e SSR do documento de topo.
  • Vite — bundler / dev server.
  • Bun — runtime e gestor de pacotes.
  • Supabase — base de dados Postgres, storage de ficheiros e service_role para as APIs.
  • Plataforma de back office — deploy / alojamento.

Princípios

  • A landing é um único HTML estático (public/var.html) — fácil de editar e rápido a servir.
  • A escrita na base de dados passa sempre por APIs server-side (nunca diretamente do browser).
  • Ficheiros de evidência ficam em storage privado; o público só vê agregados.
  • O GTM é carregado uma única vez, no documento-pai.

2 · Frontend documento de topo + iframe

O documento de topo é uma página React mínima. A landing inteira vive dentro de um <iframe> que carrega um HTML estático.

Documento de topo · var-mundial.com React — src/routes/__root.tsx + src/routes/index.tsx Servido por TanStack Start. Trata do head/SEO (title, descrição, Open Graph, JSON-LD, canonical) e carrega o Google Tag Manager GTM-MDXFMS5W uma única vez. A rota / não renderiza conteúdo próprio — só o iframe.
Landing estática · /var.html HTML + CSS + JS, autocontido Todo o conteúdo visível e toda a interatividade (verificadores de operador, formulário-wizard de evidências, chat, contador, FAQ, partilha). É um ficheiro estático em public/ — sem React.
Porquê a landing dentro de um iframe? Mantém a landing como HTML estático puro — pode ser editada e publicada sem reconstruir a app React, é trivial de cachear e isola o JS pesado da página. O documento-pai fica reservado ao essencial: SEO e a etiqueta única do GTM. Como pai e iframe partilham a mesma origem (var-mundial.com), comunicam diretamente sem restrições cross-origin.

3 · Analytics / GTM dataLayer do pai

Como a landing está num iframe, os eventos não são empurrados para o seu próprio dataLayer — sobem para o dataLayer do documento-pai, onde o GTM já está montado.

Dentro do iframe · /var.html helper vmTrack(nome, params) Cada interação (ex.: verifier_use, evidence_submit, counter_loaded) chama vmTrack(). O helper acrescenta sempre vm_source:"var_mundial" e procura o dataLayer do window.parent.
Documento-pai · mesma origem window.parent.dataLayer.push(...) O GTM GTM-MDXFMS5W (carregado em __root.tsx) lê os eventos. Como há um único contexto GTM, não há pageviews duplicados nem perda do page_location.
Se o parent não estiver acessível cai para o dataLayer local do iframe O helper nunca rebenta a UI: se o acesso ao pai falhar (caso raro), empurra para o dataLayer local. O tracking degrada com elegância.

Catálogo completo de eventos, parâmetros e KPIs em Eventos de Tag Manager.

4 · Backend / Supabase Postgres + storage

A base de dados guarda as evidências e as listas de apoio. O acesso público é só de leitura a agregados; toda a escrita passa pelas APIs com service_role.

Tabelas e vistas

tabela · privada evidencias Núcleo da campanha. Pipeline de estados recebida → segura → validada_apajo → publicada (ou rejeitada). categoria multi-valor, operador, onde_encontrada, ficheiro em storage privado (ficheiro_path), flag seguro e numero sequencial. RLS sem políticas para anon — fechada.
tabela · pública (leitura) apajo_associados Operadores licenciados (com licença SRIJ) associados da APAJO: nome, slug, logo, site, ordem. Alimenta os verificadores e os redireccionamentos "joga com diversão".
tabela · pública (leitura) casas_ilegais Casas/sites sem licença, com contagem e portal de queixas. Apoia a identificação de operadores ilegais.
tabela · pública (leitura) ostentacao Itens de "ostentação" (valores/imagens) usados no conteúdo editorial da landing.
vista · pública (agregada) evidencias_contagem Só agregados: total_publicadas e total_validadas. Nunca devolve dados crus. Alimenta o contador público.
vista · pública (agregada) evidencias_por_operador Contagem de evidências publicadas por operador. Nunca expõe ficheiros nem contactos.

APIs (server-side, em src/routes/api/public/)

escrita POST /api/public/submit-evidence Recebe multipart (com ficheiro) ou JSON. Valida campos (Zod) e o ficheiro (tipo MIME + tamanho, máx. 25 MB), faz upload para o bucket privado evidencias e insere a linha com estado:'recebida' e seguro:false. Usa a chave service_role (a tabela está fechada a anon).
leitura GET /api/public/evidence-count Lê as vistas evidencias_contagem e evidencias_por_operador e devolve só agregados (com Cache-Control curto). É o que o contador da landing consome.

5 · Pipeline de uma evidência o coração do projeto

Percurso completo de uma prova de publicidade ilegal — desde a submissão pública até à publicação numerada. As caixas a dourado são tratadas no back office (/admin); a final, a verde, é pública.

recebida segura validada_apajo publicada (ourejeitadaem qualquer ponto)
1
Público envia a evidência Três canais para a mesma API: formulário-wizard (3 passos) na landing, chat da landing, ou DM de Instagram (fonte:'instagram'). Categoria multi-escolha + onde foi encontrada + ficheiro/print opcional.
2
API valida e guarda (estado: recebida) submit-evidence valida tipo/tamanho, guarda o ficheiro no storage privado e cria a linha com estado:'recebida', seguro:false e um numero sequencial.
3
Verificação de segurança back office → segura Antivírus e deteção de adulteração do ficheiro. Se passar, seguro:true e estado:'segura'; senão, rejeitada.
4
APAJO valida a marca back office → validada_apajo Confirma que o operador promovido não tem licença SRIJ (não consta dos apajo_associados). Confirmado, passa a validada_apajo; senão, rejeitada.
5
Tratamento gráfico back office Aplicação do selo / moldura VAR à prova, pronta para divulgação.
6
Publicação numerada nas redes → publicada estado:'publicada'. A evidência sai nas redes (Instagram) com o seu numero sequencial.
7
Contagem pública (agregada) Entra em evidencias_contagem / evidencias_por_operador e o contador da landing (via evidence-count) atualiza.
Onde entra o back office. Os passos 3 a 5 (segurança, validação APAJO e tratamento gráfico) são geridos em /admin.html. A API pública só faz o passo 1–2 (recebida); a moderação avança o estado a partir daí.

6 · Onde alterar o quê

Mapa rápido dos ficheiros-chave para cada tipo de mudança.

Quero alterar…Ficheiro / local
GTM, SEO, head, Open Graph, JSON-LDsrc/routes/__root.tsx
A rota raiz que renderiza o iframesrc/routes/index.tsx
Conteúdo, design e JS da landing (e o helper vmTrack)public/var.html
APIs públicas (submeter evidência / contador)src/routes/api/public/
Base de dados: tabelas, vistas, RLS, storage, seedssupabase/migrations/
Documentação interna (esta página, eventos, estratégia)public/*.html