ADR 002: Segregação de Responsabilidades (CQRS) e Pipeline Linear (Pipe and Filter) no Worker NLP

Campo Valor
Data 21/05/2026
Status ✅ Aceito (Definido na Sprint 09)
Participantes @henriquemendeselias, @jot4-ge, @luizhtmoreira, @G2SBiell, @lucasaraujoszz, @matheus0346

1. Contexto e Problema

A arquitetura RAG (ADR 001) resolveu o problema de precisão semântica, mas manteve um acoplamento crítico na camada de execução: o backend principal (FastAPI) ainda atuava como orquestrador direto das requisições pesadas de IA, gerando três riscos estruturais:

1.1 Risco de Indisponibilidade (Timeouts e Out of Memory)

Manter a API web esperando ou gerenciando tarefas pesadas locais (Llama 3.1 8B e embeddings SBERT) abria margem para esgotamento de memória. Um travamento de madrugada derrubaria o portal de consulta dos usuários.

1.2 Sobrecarga de Abstração no Código

A equipe debateu a adoção da Arquitetura Hexagonal (Ports and Adapters). Para a realidade de prazos do projeto, essa abordagem introduziria complexidade desnecessária e dificultaria o rastreamento da lógica do Score.

1.3 Pontos Cegos na Modelagem de Dados

A estrutura relacional anterior não comportava regras críticas como a barreira temporal de discursos (RN05), a troca de partidos durante a legislatura e a exibição de metadados de atualização na interface.


2. Decisão Arquitetural

Para garantir resiliência absoluta e simplicidade de código, foram adotadas duas abordagens complementares.

2.1 Macroarquitetura: CQRS

O sistema foi dividido física e logicamente em dois serviços independentes, usando o Supabase (PostgreSQL + pgvector) como único meio de comunicação.

flowchart LR
    subgraph READ["Lado de Leitura (Query)"]
        NX["Next.js\nFront-end"]
        FA["FastAPI\nAPI REST"]
    end

    subgraph WRITE["Lado de Escrita (Command)"]
        WK["Worker NLP\nBackground"]
    end

    DB[("Supabase\nPostgreSQL + pgvector")]
    REDIS["Redis\nPub/Sub"]

    NX -->|HTTP| FA
    FA -->|Leitura| DB
    WK -->|Escrita| DB
    WK -->|Pub: cache invalidado| REDIS
    FA -->|Sub: limpa cache| REDIS
Lado Serviço Responsabilidades
Query (Leitura) FastAPI Ler dados consolidados, validar parâmetros, entregar JSONs ao Next.js, cache em memória.
Command (Escrita) Worker NLP Executar SBERT, rodar Llama 3 localmente, persistir vereditos e scores no banco.

2.2 Microarquitetura do Worker: Pipe and Filter

O fluxo interno abandona o modelo Hexagonal em favor de um pipeline procedural, determinístico e linear. O pacote de dados trafega de forma unidirecional por 6 filtros sequenciais:

flowchart TB
    F1["Filtro 1\nExtração de dados da API"]
    F2["Filtro 2\nResumo Executivo pelo Llama"]
    F3["Filtro 3\nGeração dos chunks dos discursos"]
    F4["Filtro 4\nVetorização via SBERT (BGE-M3)"]
    F5["Filtro 5\nRecuperação de Contexto RAG"]
    F6["Filtro 6\nVeredito Llama 3.1 + Cálculo do Score"]

    F1 ==> F2 ==> F3 ==> F4 ==> F5 ==> F6

3. Consequências

Pontos Positivos

  • Resiliência: Falha ou timeout no Worker fica restrita ao seu contêiner. A FastAPI continua servindo os dados da última execução bem-sucedida.
  • Manutenibilidade: O pipeline linear facilita o debug — se o score de um político divergir, a equipe isola o erro testando as funções sequencialmente, sem camadas de abstração.
  • Performance de Leitura: A FastAPI executa queries SQL diretas em tabelas indexadas. O tempo de resposta ao Next.js cai para milissegundos, pois nenhum cálculo vetorial ocorre em tempo de request do usuário.

Trade-offs

!!! warning "Consistência Eventual" Os dados do portal não são em tempo real. O Score de um político só é atualizado após o fechamento da esteira do Worker.

!!! note "Invalidação Ativa de Cache" Ao término do processamento, o Worker publica um sinal no Redis. A FastAPI (subscriber) limpa o cache em memória, garantindo que o Next.js receba os dados recém-processados no próximo request.