Pular para o conteúdo
Voltar aos projetos

Estudo de caso · projeto autoral

EcoHub

App para cidadãos denunciarem problemas ambientais na Paraíba — que nasceu como trabalho de disciplina e virou produto.

Papel
Autor principal · 33 dos 36 commits
Plataforma
Android e iOS, em Flutter
Situação
Inscrito no Prêmio de Inovação CSED 2026 · piloto com um escritório de advocacia
No repositório
EcoJP (Eco_JP no GitHub)
  • Flutter
  • Dart
  • Firebase
  • Riverpod
  • Google Maps
  • Cloudinary
  • GitHub Actions
testes unitários
149
testes unitários
testes de regras do Firestore
24
testes de regras do Firestore
jobs no CI
3
jobs no CI
meus commits
33/36
meus commits

01 /

O projeto que sobreviveu à nota

O EcoHub nasceu como projeto de disciplina no Unipê e deixou de ser exercício: está inscrito no Prêmio de Inovação CSED 2026 e em fase de piloto com um escritório de advocacia.

O cidadão fotografa o problema — lixo, queimada, buraco, enchente, esgoto, falta de iluminação —, marca no mapa e acompanha o status oficial. Do outro lado, a autoridade verifica, encaminha e resolve.

02 /

O app

  • Mapa de ocorrências: Denúncias sobre o mapa de João Pessoa, com filtro por status.

    Mapa de ocorrências

    Denúncias sobre o mapa de João Pessoa, com filtro por status.

  • Nova denúncia: Até 3 fotos, vídeo de 30 s, categoria e localização.

    Nova denúncia

    Até 3 fotos, vídeo de 30 s, categoria e localização.

  • Panorama da cidade: Tipos mais reportados e bairros mais afetados.

    Panorama da cidade

    Tipos mais reportados e bairros mais afetados.

  • Fila de verificação: A autoridade confirma as denúncias, da mais antiga para a mais nova.

    Fila de verificação

    A autoridade confirma as denúncias, da mais antiga para a mais nova.

  • Painel da autoridade: Funil de triagem, tempos médios e relatório em PDF.

    Painel da autoridade

    Funil de triagem, tempos médios e relatório em PDF.

03 /

LGPD e segurança desde a primeira versão

Um app de denúncia lida com gente que pode sofrer retaliação. Por isso a privacidade não ficou para depois: ela está nas regras do banco, no tratamento das fotos e nos testes.

Denúncia anônima de verdade

O documento público da denúncia anônima não guarda o UID de quem denunciou — e um teste de regra garante isso.

Fotos sem metadados EXIF

Os metadados saem da imagem para que a localização e o aparelho gravados nela não reidentifiquem o denunciante.

Exclusão de conta

A pessoa apaga a conta e os dados; o consentimento vai junto.

Quem decide é o servidor

As regras do Firestore validam toda escrita, com negação por padrão. Denunciar exige e-mail verificado, e o App Check barra scripts.

Moderação só pela autoridade

Ocultar conteúdo e mudar o status oficial são ações exclusivas da autoridade, e usuário comum não consegue se dar esse papel.

Trilha de auditoria imutável

Cada ação da autoridade entra numa linha do tempo que não aceita edição nem exclusão.

04 /

Qualidade que roda a cada push

Os testes unitários cobrem models, services, utils, widgets e controllers. As regras do Firestore são testadas contra o emulador, com testes que tentam burlá-las: forjar o autor, se dar papel de autoridade, vazar o UID numa denúncia anônima.

.github/workflows/ci.yml · a cada push e pull request

Análise e testes

  • Verificar formatação
  • Análise estática (flutter analyze)
  • 149 testes unitários (flutter test)

Regras de segurança do Firestore

  • Sobe o emulador do Firestore
  • 24 testes de regras com Jest

Build Android (APK)

roda depois de “Análise e testes”

  • flutter build apk --release

alguns dos testes em test/firestore_rules/firestore.rules.test.js

  • ✓ usuario nao autenticado NAO le ocorrencias
  • ✓ NAO cria ocorrencia forjando outro autor (usuarioId != uid)
  • ✓ denuncia anonima NAO pode gravar usuarioId no documento publico (S2)
  • ✓ usuario NAO consegue autoconceder papel de autoridade (roles/)
  • ✓ evento de auditoria e imutavel (sem update/delete)

05 /

Decisão registrada: manter o Firebase

Diante de uma proposta de migrar para Supabase e Postgres, com meta declarada de 30 mil usuários, registrei a decisão num ADR (docs/adr/0001): o app continua no Firebase, com Cloud Functions em TypeScript como a camada de servidor que ainda falta.

Offline decide

Ganho

O caso de uso é fotografar descarte irregular na rua, às vezes sem sinal. O Firestore já entrega fila de escrita e cache offline sem código extra.

Custo

No Supabase, recuperar isso exigiria PowerSync ou ElectricSQL — custo e complexidade novos para algo que já funciona.

Reescrever não se paga

Ganho

Ficar evita reescrever as 694 linhas de regras como RLS, além de serviços, repositórios, login e testes.

Custo

Perco PostGIS (busca por raio sai de graça) e JOIN nos relatórios. Contornos aceitos: geohash no mapa e export para o BigQuery no analítico.

Comparação de custo mensal estimado entre Firebase, Supabase e backend próprio
ItemFirebase BlazeSupabase ProBackend próprio
Backend / computeFunctions Gen2 ~$10Pro $25 + compute2 servidores $60–80
BancoFirestore ~$20incluso (8 GB)Postgres gerenciado $60–120
Auth$0 até 50 mil MAUinclusopróprio ou Clerk
Crash / analyticsCrashlytics $0Sentry ~$26~$26
Total por mês~$65–90~$70–150~$200–400

Estimativa do ADR para 30 mil usuários (~10 mil ativos por dia). No piloto de 500 usuários, o Firebase fica em ~$9/mês — só as lojas — contra ~$34/mês do Supabase, que cobra o plano mesmo sem uso.

Dívidas medidas, não achadas

  • O teste de carga aceitou 150 denúncias em 30 segundos de um único usuário: o limite de envio existia só no cliente. A correção leva a regra para o servidor.
  • Curtidas guardadas num array dentro da denúncia saturam em cerca de uma escrita por segundo por documento. A correção é uma subcoleção de reações com contador mantido por Function.
  • O ADR conclui que o que pesava era o padrão de leitura, não o banco: as mesmas telas caem de ~1.000 para ~60 leituras por usuário por dia sem trocar de tecnologia.