DEV Community

Matheus Cruvinel
Matheus Cruvinel

Posted on • Edited on

Como construí um Sistema de Controle Financeiro usando APENAS S3 (sem PostgreSQL!)

TL;DR: Construí um sistema completo de gestão financeira pessoal usando apenas Object Storage (S3). Sem PostgreSQL, sem MongoDB, sem Redis. Resultado: infraestrutura de ~R$1/mês com performance surpreendente.


A Provocação

Durante uma conversa com alguns amigos, surgiu a pergunta: "Você realmente precisa de um banco de dados para tudo?"

A resposta padrão seria: "Claro! Como você vai fazer queries? E as transações? E os índices?"

Mas e se... não precisássemos?

E se pudéssemos construir um sistema funcional de controle financeiro usando apenas Object Storage?

Spoiler: Funcionou. E funcionou bem.

Dashboard NimbusVault

O Problema Real

Como desenvolvedor, gerenciar finanças pessoais sempre foi caótico para mim:

  • 📂 Faturas de cartão espalhadas no email
  • 🧾 Comprovantes em pastas desorganizadas no Drive
  • 💼 Recibos de investimentos perdidos
  • 📊 Documentos do IR em diversos lugares
  • 🔍 Impossível encontrar algo quando precisa

Pior: tentei usar apps prontos, mas todos tinham problemas:

  • Apps mobile: Ótimos para registrar gastos, péssimos para documentos
  • Google Drive: Falta estrutura e automação
  • Planilhas: Funcionam até você ter 500 linhas
  • Apps de terceiros: Lock-in + custos recorrentes altos

Eu queria algo simples, barato e que EU controlasse.

Deploy: 1 Minuto

Usei Docker Compose para tornar o deploy trivial:

version: '3.8'

services:
  backend:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      - BUCKET=${BUCKET}
      - ACCESS_KEY=${ACCESS_KEY}
      - SECRET_KEY=${SECRET_KEY}

  frontend:
    build: ./frontend
    ports:
      - "3000:80"
    depends_on:
      - backend
Enter fullscreen mode Exit fullscreen mode

Deploy:

git clone https://github.com/mcruvinel/NimbusVault
cd NimbusVault
cp .env.example .env  # Configure suas credenciais
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Pronto. Sistema rodando.

A Ideia Maluca

"E se eu usar S3 como 'banco de dados'?"

Meu primeiro pensamento foi: "Isso é burrice, S3 não foi feito pra isso"

Mas então percebi algumas coisas:

  1. S3 tem estrutura hierárquica (categoria/arquivo.pdf)
  2. list_objects_v2 é como um SELECT com filtros
  3. URLs pré-assinadas eliminam proxy de arquivos
  4. Durabilidade de 99.999999999% (melhor que meu PostgreSQL caseiro)
  5. Custo ridiculamente baixo para uso pessoal

Decidi testar. O pior que poderia acontecer era perder um fim de semana.

A Solução: NimbusVault

Construí o NimbusVault em um fim de semana. O conceito é simples:

Object Storage organizado = Banco de dados funcional

Arquitetura

┌─────────────┐      ┌──────────────┐      ┌─────────────────┐
│   React     │─────▶│   FastAPI    │─────▶│  MagaluCloud    │
│  Frontend   │      │   Backend    │      │  Object Storage │
└─────────────┘      └──────────────┘      └─────────────────┘
  Tailwind UI          boto3 + S3            11 nines durability
Enter fullscreen mode Exit fullscreen mode

Estrutura "Tabelas"

Em vez de tabelas SQL, uso prefixos como categorias:

finance-bucket/
├── despesas-mensais/
│   ├── fatura-cartao-out-2025.pdf
│   ├── recibo-aluguel-out.pdf
│   └── recibo-energia-outubro.pdf
├── receitas/
│   ├── holerite-outubro-2025.pdf
│   └── freelance-projeto-x.pdf
├── investimentos/
│   ├── tesouro-direto-setembro.pdf
│   └── extrato-corretora-out.pdf
└── impostos/
    ├── darf-irpf-2024.pdf
    └── comprovante-iptu.pdf
Enter fullscreen mode Exit fullscreen mode

Simples. Óbvio. Funcional.

Implementação

Backend Minimalista (FastAPI)

O backend tem menos de 200 linhas. Não é exagero.

from fastapi import FastAPI, UploadFile, Form, File
import boto3

app = FastAPI(title="NimbusVault")

s3 = boto3.client(
    "s3",
    endpoint_url=ENDPOINT_URL,
    aws_access_key_id=ACCESS_KEY,
    aws_secret_access_key=SECRET_KEY,
)

@app.post("/upload")
async def upload_file(category: str = Form(...), file: UploadFile = File(...)):
    """Upload de documento financeiro"""
    key = f"{category}/{file.filename}"
    content = await file.read()

    s3.put_object(
        Bucket=BUCKET,
        Key=key,
        Body=content,
        ContentType=file.content_type,
    )

    return {"status": "ok", "key": key}

@app.get("/files")
def list_files(category: str = None):
    """Lista documentos (opcionalmente filtrados por categoria)"""
    params = {"Bucket": BUCKET}
    if category:
        params["Prefix"] = f"{category}/"

    response = s3.list_objects_v2(**params)

    files = []
    for obj in response.get('Contents', []):
        # Gera URL pré-assinada (válida por 1 hora)
        url = s3.generate_presigned_url(
            'get_object',
            Params={'Bucket': BUCKET, 'Key': obj['Key']},
            ExpiresIn=3600
        )

        files.append({
            "key": obj["Key"],
            "size": obj["Size"],
            "modified": obj["LastModified"],
            "url": url
        })

    return {"files": files}
Enter fullscreen mode Exit fullscreen mode

Isso é tudo. Sério.

Frontend Responsivo (React + Tailwind)

Interface clean com drag-and-drop:

const NimbusVault = () => {
  const [category, setCategory] = useState('despesas-mensais');
  const [files, setFiles] = useState([]);

  const handleUpload = async (e) => {
    const formData = new FormData();
    formData.append('category', category);
    formData.append('file', e.target.files[0]);

    await fetch('/api/upload', {
      method: 'POST',
      body: formData,
    });

    loadFiles();
  };

  return (
    <div>
      <CategorySelector value={category} onChange={setCategory} />
      <UploadZone onUpload={handleUpload} />
      <FileList files={files} />
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Features Surpreendentes

1. URLs Pré-assinadas (Game Changer)

Em vez de fazer o backend servir arquivos (gastando banda e CPU), gero URLs temporárias que apontam direto pro S3:

presigned_url = s3.generate_presigned_url(
    'get_object',
    Params={'Bucket': BUCKET, 'Key': 'receitas/holerite.pdf'},
    ExpiresIn=3600  # 1 hora
)
Enter fullscreen mode Exit fullscreen mode

Vantagens:

  • ✅ Download direto do S3 (super rápido)
  • ✅ Backend não processa tráfego
  • ✅ Segurança: URLs expiram automaticamente
  • ✅ Funciona com <a download> nativamente

2. Busca "Good Enough"

Não tenho Elasticsearch, mas funciona:

# Backend lista TODOS os arquivos (rápido até ~10k objetos)
all_files = s3.list_objects_v2(Bucket=BUCKET)

# Frontend filtra com JavaScript
const filteredFiles = files.filter(f => 
  f.key.toLowerCase().includes(searchQuery.toLowerCase())
);
Enter fullscreen mode Exit fullscreen mode

Para 99% dos casos de uso pessoal (< 5000 documentos), isso é mais que suficiente.

3. "Particionamento" Natural

Usar prefixos como categorias é essencialmente particionamento:

# Lista APENAS despesas (rápido)
s3.list_objects_v2(Bucket=BUCKET, Prefix="despesas-mensais/")

# Lista APENAS investimentos (rápido)
s3.list_objects_v2(Bucket=BUCKET, Prefix="investimentos/")
Enter fullscreen mode Exit fullscreen mode

Mesmo com 10.000 arquivos, listar uma categoria específica é instantâneo.

4. Versionamento Grátis

S3 tem versionamento nativo. Ativei e agora tenho audit trail de graça:

aws s3api list-object-versions \
  --bucket finance-bucket \
  --prefix despesas-mensais/fatura.pdf
Enter fullscreen mode Exit fullscreen mode

Alguém deletou um documento importante? s3.get_object(VersionId=...) e recuperei.

Por que MagaluCloud?

Testei AWS S3, mas os custos no Brasil são altos (transferência de dados internacional).

MagaluCloud foi uma revelação:

Vantagens

  1. Datacenters no Brasil → latência <50ms (vs 150ms+ AWS EUA)
  2. Preços acessíveis → R$0,06/GiB/mês de storage (Cold Instant)
  3. API S3-compatível → boto3 funciona sem alteração
  4. Transferência barata → R$0,20/GiB de saída, R$0,01/GiB de entrada
  5. Suporte em português → respondem em minutos

Custos Reais (3 meses de uso)

Meu uso pessoal:

  • 5 GB de documentos (≈4,66 GiB)
  • ~1000 requisições/mês

Fatura mensal: ≈R$0,50/mês 🤯

Compare com:

  • PostgreSQL gerenciado: R$50-200/mês
  • MongoDB Atlas: R$80+/mês
  • Heroku Postgres: $50/mês (~R$250)

Quando Usar

Storage de documentos/comprovantes/arquivos

Logs e eventos (time-series)

Prototipagem rápida

Side projects (custos baixos)

Sistemas WORM (Write Once, Read Many)

Dados não-relacionais (não precisa de joins)

Basicamente: se você está pensando em "salvar arquivos no servidor", considere S3 diretamente.

Lições Aprendidas

1. Simplicidade Vence

Gastei 5 horas construindo isso. Gastaria 5 semanas com PostgreSQL + migrations + ORM + backups + monitoramento.

2. Object Storage é Subestimado

Desenvolvedores pensam "S3 = arquivos grandes". Errado. S3 é key-value store distribuído com storage barato.

3. Nem Tudo Precisa de ACID

95% das minhas queries são:

  • "Me dá esse arquivo"
  • "Lista arquivos dessa categoria"
  • "Deleta isso"

Nada disso precisa de transações complexas.

4. Prefixos = Índices Grátis

Organizar por categoria/subcategoria/arquivo é essencialmente criar índices.

despesas-mensais/2024/10/fatura.pdf
Enter fullscreen mode Exit fullscreen mode

Isso me permite:

  • Listar tudo de outubro: Prefix="despesas-mensais/2024/10/"
  • Listar tudo de 2024: Prefix="despesas-mensais/2024/"
  • Listar todas despesas: Prefix="despesas-mensais/"

5. Infraestrutura Brasileira Importa

MagaluCloud com datacenter em SP = <50ms de latência.

AWS US East = 180ms de latência.

Para usuário final, isso é perceptível.

Conclusão

Construir NimbusVault me ensinou que nem sempre precisamos da solução mais complexa.

Antes:

  • PostgreSQL (R$80/mês)
  • Redis para cache (R$40/mês)
  • VM com 2GB RAM (R$60/mês)
  • Total: R$180/mês

Agora:

  • MagaluCloud Object Storage (~R$1/mês)
  • Total: R$1/mês

Economia: R$2.148/ano 💰

E o melhor: menos coisas para quebrar.

Não preciso me preocupar com:

  • Backups (S3 é 11 noves de durabilidade)
  • Escalabilidade (S3 escala infinito)
  • Manutenção (zero administração)
  • Atualizações (API não muda)

Código Aberto

Todo o código está no GitHub:
github.com/mcruvinel/NimbusVault

Sinta-se livre para:

  • ⭐ Dar uma estrela
  • 🍴 Fazer fork
  • 🐛 Reportar bugs
  • 💡 Sugerir features

Experimente Você Mesmo

# 1. Clone
git clone https://github.com/mcruvinel/NimbusVault
cd NimbusVault

# 2. Configure
cp .env.example .env
# Edite .env com suas credenciais MagaluCloud

# 3. Run
docker compose up -d

# 4. Acesse
open http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Como obter credenciais:

  1. Acesse console.magalu.cloud
  2. Crie um bucket em Object Storage
  3. Gere um par de chaves de acesso

Pensamentos Finais

Este projeto começou como um experimento de fim de semana e virou minha solução real de gestão financeira.

Prova que ferramentas simples, usadas criativamente, resolvem problemas complexos.

Às vezes, você só precisa de um bucket bem organizado.


Gostou? Compartilhe este post!

Documentação MagaluCloud ObjectStorage

Tags: #Python #FastAPI #React #S3 #MagaluCloud #ObjectStorage #CloudStorage #FinTech #OpenSource #Serverless

Top comments (1)

Collapse
 
fellype_silva_2c4f18ceef1 profile image
Fellype Silva

Ideia incrivel, vou testar em breve!!