Pular para conteúdo

Fluxo de Dados: SafeStreets (Ingestão e Processamento)

Conforme definido na decisão de arquitetura, o sistema adota um pipeline estruturado de ETL (Extração, Tratamento e Transformação) focado especificamente em dados de segurança pública, acoplado a uma IA dedicada exclusivamente à sumarização dos relatos.

Estratégia de Extração: Pull Periódico + Cache

O sistema utiliza pull periódico (agendado a cada 1h) + sob demanda quando usuário interage: - Se TTL do cache não expirou: retorna dados do PostgreSQL/Redis - Se TTL expirou: refaz fetch do feed RSS, parseia, extrai localização, valida e persiste - Feed RSS: Não há scheduler batch continuamente; apenas a cada 1h + opcional sob ação do usuário


Pipeline de Entrada (Backend e Ingestão)

O FastAPI gerencia o ciclo de vida da ingestão de dados de forma assíncrona, garantindo que a comunicação com serviços externos não bloqueie a experiência do usuário ao navegar pelo mapa de criminalidade.

Resilience Patterns Aplicados

  • Rate Limiter: Protege contra timeouts ou indisponibilidade do feed RSS
  • Retry Exponencial: Backoff 1s → 2s → 4s → 8s em falhas temporárias
  • Circuit Breaker: Se feed ficar indisponível por >5 min, retorna cached fallback
  • Timeout: Máximo 30s por requisição ao feed; falência após
[API Aberta - RSS Portais de Nóticias]
           │
           ▼ (HTTPX / Requests Assíncronos + Parser XML)
[Camada de Ingestão (Python)] ──► Validação Inicial (Pydantic) + Extração de Localização
           │
           ▼
[Pipeline de Processamento (ETL)] ──► Enriquecimento (Extração de Localização + Geocodificação)
           │
           ▼
[Módulo de Inteligência Artificial] ──► Gemini (Geração de Resumos Concisos)
           │
           ▼
[Camada de Persistência] ──► Banco de Dados Relacional (PostgreSQL com histórico cacheado)

Passo a Passo do Fluxo de Ingestão

1. Extração de Feed RSS

O backend extrai notícias do feed RSS (Portal de Notícia Correio Braziliense) periodicamente (a cada 1h) ou sob demanda: - Check TTL: Se cache ainda é válido (< 24h), retorna imediatamente - Fetch com Resilience: Se TTL expirou, realiza nova requisição com rate limiting + retry (ex: 1s, 2s, 4s) - Parser XML/RSS: Extrai título, descrição, link, data de publicação - Extração de Localização: Identifica nomes de regiões/endereços no texto (NLP ou regex; ex: "Taguatinga" → RA-026) - Tratamento de Falha: Se feed indisponível, circuit breaker retorna últimos dados cacheados (stale) ou erro explícito - Validação Geográfica: Valida lat/long dentro de [-90, 90] e [-180, 180]; interpola se zona aproximada

2. Enriquecimento

Para cada notícia extraída do feed RSS, o sistema enriquece o conteúdo com dados estruturáveis — sem interpretar ou categorizar o crime: - Extração e normalização de localização do texto (ex: "Taguatinga" → RA-026 + lat/long centroide) - Limpeza de conteúdo (remoção de HTML, normalização de caracteres)

O sistema não classifica tipos de crime. Não há lógica de categorização semântica (ex: roubo, homicídio). O texto da notícia é repassado ao Gemini para resumo sem análise prévia de categoria criminal.

3. Tratamento e Transformação (Pydantic + ORM)

O JSON bruto é parseado, validado e transformado em entidade ORM: 1. Pydantic Validate: Tipagem forte, datas padronizadas, campos nulos, range geográfico 2. Criação de Ocorrência: Dado validado é convertido em modelo SQLAlchemy Ocorrencia (mapeado para tabela ocorrencias_criminais) 3. Link to Locais_Pin: A Ocorrência é associada ao registro em locais_pin (ponto geográfico único ou centroide de zona) 4. Persistência Intermediária: Registro é salvo em PostgreSQL antes da IA (garante falha não perde dado)

4. Processamento por IA

O texto validado é enviado via API para o Google Gemini. O modelo executa uma única ação: condensar o relato do crime em um resumo ágil e direto.

Fallback Strategy (Se Gemini Falhar)

  • Timeout/Rate Limit: Enfileira para retry assíncrono; retorna Ocorrência sem resumo imediatamente
  • Quota Excedida: Usa resumo genérico padrão ("Crime registrado em [LOCAL] em [DATA]")
  • Erro Permanente: Log error, marca Ocorrência com resumo_status='PENDING', tenta novamente em 1h
  • Timeout Circuit: Se Gemini indisponível > 5min, circuit breaker abre; todo card mostra aviso "Resumo indisponível"

5. Persistência Dupla (Cache Distribuido)

A ocorrência, agora com seu resumo gerado pela IA e suas coordenadas exatas, é persistida em: 1. PostgreSQL (principal): Tabela ocorrencias_criminais com índices em locais_pin_id, data_criacao 2. Redis/In-Memory (cache): TTL de 24h; respostas ultra-rápidas para queries frequentes (top crimes, region X)

Isso evita: - Chamadas redundantes à API de segurança - Reprocessamento no Gemini (economia de tokens) - Consultas lentas ao banco em picos de tráfego

Pipeline de Saída (Do Banco à Tela do Usuário)

O consumo de dados é otimizado para que a interface cartográfica responda de forma fluida e instantânea aos cliques do usuário, focando na exibição clara dos incidentes.

Etapa Responsável Descrição Técnica
1. Disparo Frontend (Next.js / Leaflet) O usuário clica em um ponto do mapa interativo. O Next.js captura Latitude/Longitude e dispara um GET tipado em TypeScript.
2. Recepção Backend (FastAPI) O backend recebe a requisição. O Pydantic valida o formato numérico das coordenadas.
3. Consulta Banco (PostgreSQL) O backend verifica se há dados de crimes cacheados para aquele raio espacial.
4. Resposta Backend (FastAPI) O FastAPI consolida os crimes da região em um OcorrenciasLocalResponse.
5. Exibição Frontend (Next.js) O Next.js recebe o JSON e o Leaflet renderiza um PIN interativo no mapa.

Estrutura de Dados Espaciais e Conteúdo (Modelo Relacional)

O sistema adota um modelo relacional simplificado no PostgreSQL, focado na ligação direta entre coordenadas geográficas e ocorrências criminais resumidas.

Semântica de locais_pin

locais_pin representa um ponto geográfico único ou centroide de zona: - Se coordenada é precisa: um ponto (lat, long) específico - Se coordenada é aproximada (zona): centroide da zona (ex: região administrativa) - Relação 1:0..* com ocorrências: Um local pode ter múltiplos crimes históricos (série temporal) - Índice espacial: PostgreSQL GiST index em (latitude, longitude) para queries rápidas por bbox

Validação de Versionamento de Schema

Se o feed RSS do Correio Braziliense mudar sua estrutura XML (e.g., novo campo, campo renomeado): 1. Backward Compatibility: Pydantic ignora campos desconhecidos (configurável) 2. New Required Fields: Tratadas com default fallback para não quebrar pipeline 3. Schema Migration: Se mudança crítica, ADR deve documentar e preparar migration script 4. Test Coverage: Testes em fixtures com velhas e novas versões de payload

Modelagem de Dados no Backend (FastAPI + Pydantic/ORM)

As relações são mapeadas conectando os locais físicos diretamente às ocorrências criminais já processadas.

[locais_pin] 1 ──── 0..* [ocorrencias_criminais]
      │                                                   
      │ 1                                               
      └──────── 0..* [historico_consultas]

Detalhes das Interações de Fluxo

Associação Crime-Local

O FastAPI garante que toda nova ocorrência criminal obtida da API externa seja vinculada ao id da tabela locais_pin. Um mesmo local perigoso pode concentrar múltiplos registros de crimes ao longo do tempo.

Geração de Cache Espacial com TTL

A tabela historico_consultas registra: - timestamp_ultima_atualizacao: Quando dados foram fetched pela última vez - raio_geografico: Bbox ou zona consultada - ttl_expiracao: timestamp + 24h

O FastAPI utiliza essas informações para decidir: - Se TTL ainda é válido (< agora): retorna dados do PostgreSQL/Redis sem nova API call - Se TTL expirou: realiza novo fetch com resilience pattern (rate limiter + retry + circuit breaker) - Se fetch falha: circuit breaker retorna dados stale do cache ou erro expl'icito ao usuário

Benefícios Arquiteturais da Stack Selecionada

Casamento de Tipos (PydanticTypeScript)

A definição do retorno das ocorrências no FastAPI garante um contrato OpenAPI previsível. O frontend em Next.js gera interfaces TypeScript automaticamente, reduzindo bugs de integração.

Otimização Extrema de Custos

Ao delegar ao Gemini apenas a função de resumo, o sistema reduz drasticamente o tamanho dos prompts e o consumo de tokens. O PostgreSQL atua como camada de cache para evitar reprocessamentos.

Confiabilidade e Testabilidade Rigorosa

A arquitetura modular do FastAPI facilita testes automatizados utilizando Pytest, garantindo validação contínua dos endpoints e funcionamento correto da rota /health.


Decisões Arquiteturais Pendentes (Deve Resultar em ADRs)

Decisão Impacto Status
Fallback Gemini: Resumo genérico vs Enfileira retry? UX: usuário vê card incompleto vs vazio ⏳ Aguardando ADR
TTL do Cache: 24h ou variável por tipo de crime? Performance vs Consistência ⏳ Aguardando ADR
Redis obrigatório ou apenas in-memory? Custo de infraestrutura, escalabilidade ⏳ Aguardando ADR
Versionamento de schema: Backward compat automática vs Migration manual? Resiliência vs Controle ⏳ Aguardando ADR