
A história do Capivara — do hub bagunçado ao painel central com 396 testes
⚡ O hub que começou como bagunça financeira
A necessidade original não tinha nada de glamouroso: eu precisava entender pra onde meu dinheiro ia. O Capivara nasceu como um hub pessoal pra organizar minhas finanças — mas quem acompanha este blog sabe que ele virou muito mais que isso.
Hoje, o Capivara é o painel central do meu ecossistema: monitora Arachne, TatuEngine e serviços, mostra receita do Dogwalk, responde perguntas sobre meus projetos com RAG local, e mantém backup offsite em duas nuvens diferentes.
E o mais impressionante: 396 testes (131 backend + 248 frontend + 17 browser/E2E) garantindo que nada disso quebra.
🧠 Contexto — um painel que virou infraestrutura
O commit inicial veio com um nome honesto:
a4eef5d feat: capivara hub — FastAPI + React + Cloudflare Tunnel
FastAPI no backend, React no frontend, SQLite de banco, e um Cloudflare Tunnel pra expor tudo com HTTPS sem abrir porta. A primeira versão tinha um dashboard simples de status dos projetos — zero mock data, limpeza total (commit 35f411a).
O Capivara cresceu em ondas. Primeiro os convites temporários (1h-7d com permissões), depois o dashboard analytics com Umami, os proxies pras outras aplicações (Portifólio staging, Umami, Dogwalk), e a autenticação endurecida com JWT + refresh token rotation + blacklist.
🔧 A luta — segurança, RAG local e o backup que não existia
A autenticação que precisava crescer
No começo era um login simples. Mas um painel que controla infraestrutura não pode ter senha fraca. Então vieram:
# backend/auth.py — JWT + bcrypt + 2FA TOTP
def create_access_token(user_id: int) -> str:
expire = datetime.utcnow() + timedelta(hours=24)
return jwt.encode(
{"sub": str(user_id), "exp": expire},
settings.SECRET,
algorithm="HS256",
)
E o 2FA TOTP — o mesmo algoritmo do Google Authenticator. Cada login exige o código de 6 dígitos gerado no app. Já teve dia que eu tentei logar sem o celular por perto e fiquei travado na porta — sinal de que a segurança estava funcionando.
O Segundo Cérebro local
Aí veio a parte divertida: um chat RAG local no admin. ChromaDB como vector store + Ollama com qwen3.5:4b como LLM. As memórias são ingeridas automaticamente dos 6 projetos — hoje são 430 memórias no banco vetorial.
# backend/routers/chat.py — busca no ChromaDB
def search_memories(query: str, top_k: int = 5):
results = collection.query(
query_texts=[query],
n_results=top_k,
include=["documents", "metadatas", "distances"],
)
return results
O diferencial: um bot no Telegram conectado ao mesmo cérebro. Mando pergunta no chat, o webhook consulta o RAG e responde com as fontes. Meus projetos respondem perguntas sobre si mesmos 24/7.
O backup que quase me pegou
O momento mais tenso: descobri que o backup offsite não existia de verdade. De 14/07 a 31/07, o R2 estava desativado na conta — o script rodava, dizia que fazia backup, mas não subia nada. Se o WSL morresse naquele período, o banco inteiro sumia.
A correção teve duas frentes:
- Cloudflare R2 — bucket
capivara-backups, snapshot validado a cada 6h via cron no_agent - Cloudflare D1 disaster recovery — cópia do SQLite no edge Cloudflare, sync a cada 6h
# scripts/backup_to_r2.sh — o que salvou o banco
rclone copy backend/capivara.db r2:capivara-backups/$(date +%F)/ --progress
Tokens rotacionados, creds no Bitwarden SM, e o dump validado manualmente antes de dormir tranquilo de novo.
💡 Resolução — o painel que virou operação
O Capivara deixou de ser “meu painel” e virou parte da operação. Hoje ele:
- Expõe staging do Portifólio e proxy do Umami (porta 3001→3100 pra não conflitar)
- Mostra o Stripe dashboard do Dogwalk (receita, assinaturas, payouts, gráfico 12 meses)
- Monitora o WSL em tempo real (CPU, RAM, GPU, discos, Docker, serviços, processos)
- Manda push notifications com PWA offline completo (VAPID keys)
A refatoração do frontend foi brutal: Dashboard de 994→262 linhas (-74%), AdminPage de 1091→97 linhas (-91%), initial bundle de 668→238 kB (-64%) com code splitting.
📊 Métricas
| Métrica | Nascimento | Hoje |
|---|---|---|
| Commits | 1 | 107 |
| Testes backend (pytest) | 0 | 131 |
| Testes frontend (Vitest) | 0 | 248+ |
| Testes browser + E2E | 0 | 17 |
| Memórias no RAG (ChromaDB) | 0 | 430 |
| Backups offsite | 0 | 2 (R2 + D1) |
| Rate limit | ausente | IP + API key dual window |
🎯 Aprendizados
O Capivara me ensinou que painel pessoal também é produção. O dia que o backup “silencioso” falhou sem eu saber foi um alerta: se uma automação é crítica, ela precisa de validação, não só de execução. Foi isso que levou ao snapshot validado do R2 e ao sync no_agent — sistemas que se corrigem sozinhos.
E a segunda lição: RAG local com dados pessoais funciona muito bem. Ter meu Segundo Cérebro respondendo sobre meus próprios projetos, com fontes, mudou como eu trabalho — e virou um padrão que o Arachne depois levou ao extremo.