Frontend e Interface
Este documento detalha a arquitetura da interface de usuário do ContraDito, desenvolvida para atender às demandas de jornalistas investigativos e cidadãos engajados. O objetivo central é entregar um painel rápido, responsivo e de alta legibilidade para o cruzamento e análise de dados governamentais das duas casas legislativas (Câmara dos Deputados e Senado Federal).
1. Arquitetura e Roteamento (App Router)
O front-end é construído sobre a fundação do Next.js 15 (v15.5.19) utilizando o paradigma do App Router, em conjunto com React 19 e Tailwind CSS v4. A arquitetura tira proveito estratégico da separação entre renderização no servidor e no cliente para equilibrar a performance de SEO e a velocidade de entrega inicial com interatividade em tempo real no lado do cliente.
1.1. Páginas e Renderização
- A Home (
app/page.tsx): Server Component com renderização dinâmica (force-dynamic). Exibe a foto do Congresso Nacional com transição suave de tema, números gerais do projeto (PROJECT_STATS), uma seção informativa de apresentação e a seção de pré-visualização rápida do diretório (DiretorioPreview), que recebe a lista de parlamentares previamente carregada no servidor. - Diretório de Parlamentares (
app/diretorio/page.tsx): Server Component (force-dynamic) que executa a estratégia de fetch-all-once (ADR 003). Busca todos os parlamentares de ambas as casas em paralelo no servidor e repassa os dados para oDiretorioClient. No lado do cliente, a lista é unificada, filtrada (busca textual, partido, estado e casa) e paginada instantaneamente, permitindo interatividade imediata e sem novos acessos à rede. - Dossiê do Político (
app/politico/[id]/page.tsx): Server Component (force-dynamic). Utiliza a funçãogenerateMetadatano servidor para injetar metadados dinâmicos e tags Open Graph (contendo nome, partido, cargo, estado e url da foto). Renderiza o cabeçalho no servidor e delega os painéis interativos de votações nominais, afinidades políticas, fidelidade e discursos aoDossieClient. - O Ringue de Comparação (
app/comparacao/page.tsx): Server Component (force-dynamic) que carrega a listagem de todos os parlamentares no servidor para alimentar os seletores de comparação de forma instantânea. O cálculo de afinidade mútua, timelines e cruzamento de votos nominais são processados de forma assíncrona no componente clienteComparacaoClient. - Discursos (
app/discursos/page.tsx): Server Component (force-dynamic) que gerencia a paginação e busca textual de discursos no servidor via parâmetros de URL (searchParams). Carrega os discursos e a listagem de parlamentares em paralelo viaPromise.allpara exibição noDiscursosClient. - Coesão Partidária (
app/partidos/page.tsx): Server Component (force-dynamic) que busca os índices de coesão partidária da Câmara e do Senado em paralelo com o diretório completo e passa os dados para oPartidosClient, exibindo o nível de união dos partidos nas votações. - Painel de Proposições (
app/proposicoes/page.tsx): Server Component (force-dynamic). Executa paginação e filtros de proposições no servidor baseado nos parâmetros da URL (ano, tipo de matéria, busca textual e filtragem de analisadas), otimizando a exibição de ementas longas noProposicoesClient. - Detalhe da Proposição (
app/proposicoes/[casa]/[id]/page.tsx): Server Component (force-dynamic). Busca os metadados da proposição e os dados de polarização e distribuição de votos em paralelo no servidor. Provê metadados dinâmicos e renderiza os detalhes por meio doProposicaoDetalheClient.
2. Comunicação Assíncrona e CQRS
Respeitando a macroarquitetura do sistema, o front-end atua estritamente como consumidor do Lado de Leitura (Query), interagindo exclusivamente com a API FastAPI por meio de requisições HTTP GET. Não existem rotas de escrita ou submissão direta de dados, mantendo a integridade das informações extraídas e geradas pelos pipelines de ETL e processamentos do Worker NLP.
Para viabilizar o desenvolvimento local desacoplado e a resiliência do sistema:
* Cache em Camadas: As requisições no servidor utilizam o mecanismo de cache nativo do fetch do Next.js. Dados estáticos ou com baixa taxa de alteração (como diretórios e coesão de partidos) possuem tempo de revalidação de 1 hora (revalidate: 3600), enquanto detalhes de políticos e proposições possuem cache de 60 segundos (revalidate: 60). Discursos utilizam cache: 'no-store' para pesquisas textuais e paginação dinâmica sempre atualizadas.
* Mock System de Desenvolvimento: Através da variável de ambiente NEXT_PUBLIC_USE_MOCK === "true", o frontend pode ser executado em modo de simulação offline (usando dados definidos em lib/mock.ts), isolando o desenvolvimento da interface das dependências da API ou do banco de dados.
3. Padrões de Resiliência e Prevenção de Falhas
Para garantir uma navegação fluida e confiável mesmo em cenários de instabilidade na rede ou nos serviços do governo, o frontend adota estratégias ativas de prevenção e indicação de estados do sistema:
* Skeleton Loaders: Componentes visuais dedicados, como o Skeleton (components/ui/Skeleton.tsx) e a CongressoSilhueta (components/CongressoSilhueta.tsx), simulam a anatomia da interface final com transições de pulsação suave durante o tempo de tráfego HTTP.
* Tratamento de Exceções de Rede (Error Boundaries): Envelopamento e tratamentos de exceções nas chamadas de dados que evitam o travamento total da interface. Caso a API apresente falha, mensagens claras e empáticas são exibidas, oferecendo opções de recarregamento sem expor logs técnicos brutos.
* Empty States (Buscas Vazias): Telas e avisos orientadores são apresentados sempre que a combinação de termos de busca e filtros (ex: um partido específico em determinado estado) não retornar registros, ajudando o usuário a redefinir seus parâmetros de busca.
* Sinalização de Nulidade e Ausência de Dados: Em conformidade com a remoção do Score de Coerência (ADR 003), parlamentares recém-empossados ou sem discursos e votações suficientes têm seus índices analíticos omitidos proativamente, exibindo sinalizações amigáveis de "Ausência de Dados" para evitar falsas métricas ou relatórios incorretos.
4. Design System e Acessibilidade Visual (WCAG AA)
O frontend implementa um Design System Modular e consistente, construído com base em componentes atômicos (como Avatar.tsx, ScoreBadge.tsx, Skeleton.tsx e MembroCard.tsx) e componentes estruturais (Navbar.tsx, SiteFooter.tsx e VotosTable.tsx). O desenvolvimento segue estritamente a filosofia Mobile First, garantindo usabilidade em qualquer resolução.
A aplicação conta com um alternador de temas (ThemeToggle.tsx) que permite a navegação entre os modos Claro e Escuro, salvando a preferência do usuário no armazenamento local (localStorage).
4.1. Estética e Paleta Semântica
A interface adota a estética de Dark Glassmorphism no modo escuro, caracterizada por fundos profundos contrastados com painéis translúcidos e desfoque de fundo (backdrop-blur), e um tema claro polido que preserva a identidade visual da aplicação.
As cores da paleta foram mapeadas e registradas no bloco @theme do Tailwind CSS v4 para manter a consistência semântica:
| Token / Variável | Cor (Hex/Tipo) | Justificativa e Aplicação Visual |
|---|---|---|
--color-canvas |
#05080f (Escuro) / #eef1f7 (Claro) |
Fundo primário da aplicação. Evita fadiga visual e destaca elementos em primeiro plano. |
--color-card |
#0c1220 (Escuro) / #e4e9f2 (Claro) |
Fundo de painéis e blocos de conteúdo com desfoque translúcido (glass). |
--color-rim |
#1a2435 (Escuro) / #bdc8d8 (Claro) |
Bordas finas de delimitação que garantem separação e profundidade visual. |
--color-coherent |
#10b981 (Verde) |
Escala positiva para notas de coesão, afinidade e fidelidade partidária. |
--color-incoherent |
#f43f5e (Vermelho) |
Escala de alerta visual para taxas de discordância e ausência de fidelidade. |
--color-pulse |
#5e88ff (Azul) |
Cor de identidade visual da Câmara dos Deputados (sem juízo de valor). |
--color-aurum |
#f59e0b (Âmbar) |
Cor de identidade visual do Senado Federal (sem juízo de valor). |
--color-serie-a / *-b |
#6366f1 (Índigo) / #14b8a6 (Teal) |
Séries neutras para diferenciar os dois parlamentares comparados no Ringue. |
--color-voto-sim |
#a78bfa (Violeta) |
Diferenciação semântica NEUTRA para o voto Sim em proposições. |
--color-voto-nao |
#22d3ee (Ciano) |
Diferenciação semântica NEUTRA para o voto Não em proposições. |
--color-voto-outro |
#64748b (Ardósia) |
Votos nulos, abstenções, obstruções ou ausências no plenário. |
[!NOTE] A diferenciação de votos por cores neutras (violeta/ciano) foi implementada especificamente para evitar julgamento de valor político (como associar verde a "bom" e vermelho a "ruim" para votações de matérias de lei), focando na exibição imparcial dos fatos.
4.2. Estratégias de Otimização e Inclusão
- Otimização de Mídia (Avatares): A renderização de fotos de centenas de parlamentares usa o componente
<Image/>nativo do Next.js com preenchimento responsivo (fill) e controle de largura (sizes), realizando lazy loading e conversão automática para formatos modernos (WebP/AVIF). Caso a foto não exista, o componente renderiza uma silhueta contendo as iniciais do parlamentar. - Navegação Acessível e Teclado: A interatividade dos componentes respeita as diretrizes WCAG Nível AA de contraste e navegação. Menus, tabelas, modais e seletores são estruturados com marcações semânticas do HTML5 e atributos ARIA, garantindo usabilidade total por meio do teclado (tecla
Tabe atalhos) e leitura fidedigna em leitores de tela para usuários com deficiência visual.