Observatório INOVARE · Documentação técnica v2.0

Anatomia do Observatório

Como 18 indicadores oficiais de economia, finanças públicas e corrida eleitoral viram um semáforo de três cores — de onde vêm os dados, com que regras eles se atualizam e qual sistema visual sustenta tudo isso.

Verde — dentro da faixa ideal Amarelo — fora da faixa, convergindo Vermelho — fora da faixa, divergindo Neutro — sem faixa normativa (contexto)
01

Visão geral

O Observatório INOVARE é um painel público que traduz indicadores oficiais em linguagem clara. Cada indicador carrega três camadas ao mesmo tempo: o conceito técnico exato (como o BCB ou o IBGE definem a métrica), uma interpretação cidadã — o bloco "Na prática:" — e, quando existe referência normativa, uma faixa ideal calibrada que alimenta o semáforo.

Os 18 indicadores estão distribuídos em 4 blocos temáticos, mais um quarteto de destaque ("O Brasil em 4 números": IPCA, Desemprego, PIB e SELIC) e um módulo especial de acompanhamento das pesquisas presidenciais de 2026.

Bloco 1

Atividade e Trabalho

Crescimento econômico e mercado de trabalho

4 indicadores
Bloco 2

Preços e Juros

Inflação, taxa de juros, câmbio e cripto

6 indicadores
Bloco 3

Famílias e Empresas

Renda, endividamento, inadimplência e falências

4 indicadores
Bloco 4

Governo e Risco

Dívida pública, fiscal e percepção de risco

4 indicadores
Fora dos blocos: o módulo "Futuro do Brasil" agrega pesquisas eleitorais registradas no TSE para a corrida presidencial de 2026, coletadas automaticamente (com link para cada divulgação original); destaque para Datafolha, Quaest, PoderData e AtlasIntel.
02

Como os indicadores funcionam

Cada indicador é um objeto com campos fixos: conceito, interpretacao, fonte, uma série histórica (serie, anual, desde 2017) e, opcionalmente, uma faixa — o intervalo considerado saudável — e uma polaridade, que diz de que lado da faixa é bom ficar fora dela.

Nem todo indicador tem faixa. Câmbio, Bitcoin, INPC, custo da construção (m²) e falências não têm referência normativa oficial — entram em displayMode: 'contexto' e aparecem em cinza-neutro, com tendência, mas sem veredito de cor.

A lógica do semáforo (calcStatus)

Quatro perguntas em cascata decidem a cor de um indicador com faixa definida:

VALOR ATUAL DO INDICADOR tem faixa (min/max)? não NEUTRO modo contexto (câmbio, bitcoin…) sim dentro da faixa ideal? sim VERDE dentro da faixa não fora da faixa, lado bom da polaridade? sim VERDE ex.: desemprego abaixo do piso não tendência convergindo p/ a faixa? sim AMARELO convergindo não VERMELHO divergindo
Lógica de calcStatus(): a cor depende primeiro da faixa e da polaridade; só entra tendência quando o valor está do lado ruim da faixa, para distinguir "melhorando" (amarelo) de "piorando" (vermelho).
Tendência (calcTrend): compara os dois últimos pontos realizados (não projetados) da série. Variações menores que 0,5% relativo contam como "estável" — evita que ruído de arredondamento vire seta para cima ou para baixo.

Exceção: o quarteto "Brasil em 4 números"

Os quatro cards hero (IPCA, Desemprego, PIB, SELIC) não usam calcStatus — usam calcTrendStatus. A cor não mede distância da faixa, mede se o movimento mais recente foi bom ou ruim para o país. Um PIB subindo é sempre verde no hero, mesmo se o nível ainda estiver fora da faixa ideal; uma queda ≥ 2% relativo é vermelho, abaixo disso é amarelo.

03

Arquitetura e stack tecnológica

CamadaTecnologia
FrontendReact 19 + TypeScript + Vite 7 + Tailwind CSS + Radix UI + Lucide Icons
RoteamentoReact Router 7
GráficosRecharts — tooltips translúcidos, gradientes e marcação de mandatos presidenciais (1995–presente)
FormuláriosReact Hook Form + Zod
Banco de dadosSupabase (Postgres / PostgREST), schema observatorio, RLS somente-leitura
FallbackSnapshot local estático (src/data/indicators.ts, electionPolls.ts)
ColetaNode.js (scripts/coletar.mjs)
AutomaçãoGitHub Actions, execução agendada (cron)
HospedagemHostinger / Vercel / Cloudflare Pages — SPA com .htaccess para roteamento limpo
fetch SGS/SIDRA grava só o novo/revisado GET /rest/v1 (anon) FONTES OFICIAIS BCB · IBGE · TSE CNC · FGV · Tesouro COLETAR.MJS GitHub Actions seg & qui · 07h BRT SUPABASE Postgres · PostgREST schema observatorio REACT APP loader.ts renderiza os blocos SNAPSHOT LOCAL indicators.ts (no código) catch/vazio → fallback
A UI nunca fica sem dado: se a chamada ao Supabase falhar ou vier vazia, loader.ts recorre ao snapshot embutido no bundle e marca a origem como 'local'.
Governança visual sobre o banco: ordem de exibição, nomes, unidades, rótulos de faixa e polaridade de indicadores como SELIC e câmbio são fixados em indicators.ts e prevalecem mesmo quando os dados vêm do Supabase — garante consistência visual independente do que está cadastrado no banco.
04

Regras de atualização

A coleta roda via GitHub Actions com o cron 0 10 * * 1,4 — segundas e quintas às 07h (Brasília) — mais um gatilho manual (workflow_dispatch). O coletor é config-driven: lê da própria tabela observatorio.fonte_series quais indicadores têm fonte de API ativa, em vez de ter os códigos hardcoded no script.

Hoje só BCB/SGS e IBGE/SIDRA estão automatizados de ponta a ponta. O restante (CAGED, Peic, FGV IBRE, CBIC, Boa Vista, IPEAData) é curadoria-manual ou api-inativa, e entra por curadoria manual periódica.

O modelo é append-only

Nunca há UPDATE ou DELETE em observatorio.series. Uma revisão de dado é sempre uma linha nova, com created_at mais recente. A view series_atuais faz DISTINCT ON (indicador_id, ano) ORDER BY created_at DESC — serve sempre o valor mais atual, mas nenhuma revisão histórica se perde.

OBSERVATORIO.SERIES (APPEND-ONLY) ipca · 2026 · valor 4,30 created_at 10/jul — substituída ipca · 2026 · valor 4,10 created_at 07/ago — revisão, substituída ipca · 2026 · valor 4,00 created_at 21/ago — revisão mais recente SERIES_ATUAIS (view) ipca · 2026 → 4,00 DISTINCT ON (indicador_id, ano)
Três gravações para o mesmo indicador_id + ano; a view sempre resolve para a última por created_at, sem apagar as anteriores.
SalvaguardaComo funciona
IdempotênciaAntes de gravar, o coletor compara com series_atuais; só insere se o ano é novo ou o valor mudou mais que 0,005.
Modo testenode scripts/coletar.mjs --dry-run mostra o que seria gravado, sem tocar no banco.
Falha isoladaSe uma fonte quebrar, o erro é logado e o script segue para as demais — nada é alterado para o indicador que falhou.
Chave de escritaSUPABASE_SECRET_KEY (service role) só existe como secret do GitHub Actions ou em .env.local — nunca no bundle do frontend.
RLSO papel anon só tem SELECT; escrita é bloqueada no Postgres independentemente do que o frontend tente fazer.
05

Modelo de dados

Seis tabelas/views no schema observatorio, todas com leitura pública via RLS (anon + authenticated) e escrita restrita ao service_role.

fontes id (PK), nome tipo (api-publica / curadoria-manual) frequencia_coleta 1:N fonte_series indicador_id (FK) fonte_id (FK) codigo_externo transformacao ativo → liga/desliga coleta N:1 indicadores id (PK), bloco_id nome, unidade faixa_min, faixa_max display_mode hero, ordem catálogo, sem histórico 1:N series id (PK), indicador_id (FK) ano, valor projetado, fonte_coleta created_at append-only — nunca UPDATE/DELETE view series_atuais DISTINCT ON (indicador_id, ano) ORDER BY created_at DESC "a linha que vale" 1:N insights indicador_id (FK) texto, modelo created_at textos gerados por IA (Gemini)
indicadores é o catálogo; series guarda o histórico completo, revisável; series_atuais é a view que qualquer leitor de fora usa.
06

Sistema de design — Antigravity Spatial

O nome do sistema visual é Antigravity Spatial & Motion Design: cards com sensação de leveza (elevação sutil no hover, translateY(-3px) scale(1.004)), sombras difusas em múltiplas camadas e glassmorphism com uma borda especular de 1px no topo — um reflexo de luz simulando vidro.

Tipografia: Inter (300–800), com font-variant-numeric: tabular-nums aplicado globalmente para que números alinhem em coluna nos cards e tabelas.

TokenEscuro (padrão)Claro (.light)
Fundo#07070d#f6f8fb
Cartão#12121a / #16162abranco translúcido
Acentohsl(239 84% 67%) — índigoíndigo mais escuro p/ contraste
Raio de borda0.75rem (constante nos dois temas)
Semáforo4 estados × 4 variantes cada: bg, text, dot, glow
Tema claro não é um filtro: a classe .light na raiz remapeia individualmente cada utilitário Tailwind em uso (fundos, textos, bordas, gradientes, sombras) em index.css — uma segunda paleta com contraste dedicado, não uma inversão automática.

Componentes-chave

ComponentePapel
StatusDotPonto pulsante com glow na cor do status + seta de tendência (up/down/stable)
IndicatorCardCard recolhível: cabeçalho sempre visível (valor, faixa, status); painel expandido com "Na prática", gráfico e nota metodológica
IndicatorChartLinha (Recharts) com marcação dos mandatos presidenciais desde 1995 e série secundária opcional (ex.: SELIC Real ao lado da Meta)
HeroSummaryQuarteto "Brasil em 4 números" — usa calcTrendStatus, não calcStatus

Toda animação (float-slow, pulse-subtle, fade-in) é desativada sob prefers-reduced-motion: reduce.