ADR-002: SQLite como banco de dados principal
| Campo | Valor |
|---|---|
| Status | Aceito |
| Data | 2024 |
| Autor | Caio Fiori Martins |
Contexto
Com a decisão de operar local-first (ADR-001), foi necessário escolher um banco de dados que rodasse sem infraestrutura adicional na máquina do servidor local. A escolha do banco tem implicações diretas em:
- Portabilidade — o servidor precisa rodar em qualquer notebook
- Operação zero-config — a organização do evento não tem DBA
- Confiabilidade — o banco não pode corromper dados em caso de desligamento abrupto
- Performance — precisa responder em < 50ms para o volume esperado
Carga esperada
O dimensionamento é crítico para justificar a escolha. Um evento escolar típico tem:
- 10–30 lojas simultâneas
- 200–800 participantes
- Duração de 4–8 horas
- Pico estimado: ~5 transações/segundo
Esse volume é trivial para qualquer banco de dados relacional. É importante nomear isso explicitamente: a escolha não é "SQLite porque é o que aguenta" — é "SQLite porque é exatamente o que o problema pede".
Decisão
SQLite é o banco de dados principal do Ouroboros.
Justificativa
1. Zero infraestrutura
SQLite é uma biblioteca, não um servidor. Não há processo separado pra iniciar, porta pra abrir, autenticação pra configurar. O banco é um único arquivo .db no sistema de arquivos. Isso elimina uma classe inteira de problemas operacionais.
2. Durabilidade por design
SQLite é ACID compliant com WAL (Write-Ahead Logging) habilitado. Em caso de queda de energia ou desligamento abrupto, o banco recupera automaticamente o estado consistente na próxima abertura. Nenhuma transação confirmada é perdida.
3. Performance adequada
SQLite com WAL mode suporta facilmente 1.000+ writes/segundo em hardware moderno. Para 5 transações/segundo, há margem de 200x. A latência de escrita é determinada pelo disco local — tipicamente 1–5ms — comparado aos 100–400ms de um banco remoto.
4. Portabilidade
O banco inteiro é um arquivo. Backup = copiar o arquivo. Migração = mover o arquivo. Debug = abrir no DB Browser for SQLite. Não há abstração opaca entre o operador e os dados.
5. Adoção em produção real
SQLite é o banco de dados mais deployado do mundo. É usado em produção por WhatsApp (mensagens locais), browsers (IndexedDB), iOS e Android (armazenamento nativo), e aplicações Electron. A narrativa de que "SQLite é só pra desenvolvimento" é incorreta para casos de uso de baixa concorrência write.
Alternativas consideradas
PostgreSQL
Descartado: requer processo separado, instalação, configuração de autenticação. Aumenta o setup significativamente sem benefício para a carga esperada. Faz sentido quando você precisa de concorrência massiva de writes ou features avançadas (JSONB, full-text search, etc.).
MongoDB
Descartado: sem schema rígido é desvantagem aqui — o modelo de dados do Ouroboros é bem definido e relacional. Adiciona complexidade (processo separado, driver) sem vantagem.
Redis
Descartado: excelente como cache, não adequado como store primário persistente para event sourcing.
In-memory (dicionário Python)
Descartado: perde todo o estado em qualquer restart ou queda de energia. Inaceitável pelo plano de resiliência.
Consequências
Positivas:
- Setup em 30 segundos (literalmente)
- Backup trivial
- Debug direto no arquivo
- Zero custo de infraestrutura
- Comportamento previsível e bem documentado
Negativas e trade-offs aceitos:
- Writes são serializados — sem concorrência paralela de escrita. Aceitável para a carga esperada; inaceitável para sistemas com milhares de writes simultâneos
- Não adequado para deploy multi-servidor (cada servidor teria sua própria cópia)
Limite claro de escopo
SQLite é a escolha certa para esse problema específico. Se o Ouroboros evoluísse para um produto SaaS multi-tenant com milhares de eventos simultâneos, a migração para PostgreSQL seria necessária. Essa é uma decisão consciente de escopo, não uma limitação técnica ignorada.