Felipe Coutinho ea0b8618e0 feat: adição de novos ícones SVG e configuração do ambiente
- Adicionados ícones SVG para ChatGPT, Claude, Gemini e OpenRouter
- Implementados ícones para modos claro e escuro do ChatGPT
- Criado script de inicialização para PostgreSQL com extensão pgcrypto
- Adicionado script de configuração de ambiente que faz backup do .env
- Configurado tsconfig.json para TypeScript com opções de compilação
2025-11-15 15:49:36 -03:00

OpenSheets

Uma aplicação moderna e completa construída com Next.js 16, Better Auth, Drizzle ORM, PostgreSQL e shadcn/ui.

Next.js TypeScript PostgreSQL Docker


📖 Índice


🎯 Sobre o Projeto

OpenSheets é uma aplicação full-stack moderna projetada para controle de finanças pessoais. Construída com as melhores práticas de desenvolvimento e ferramentas de ponta, oferece uma base sólida e escalável para gestão financeira completa.

Por que usar o OpenSheets?

  • Pronto para Produção - Docker, health checks, migrations automáticas
  • TypeScript First - Type safety em toda a aplicação
  • Autenticação Completa - Better Auth com OAuth, email magic links
  • ORM Moderno - Drizzle com Drizzle Studio integrado
  • UI Components - shadcn/ui com design system completo
  • Developer Experience - Hot reload, Turbopack, ESLint configurado

Features

🔐 Autenticação

  • Better Auth integrado
  • OAuth (Google, GitHub)
  • Email magic links
  • Session management
  • Protected routes via middleware

🗄️ Banco de Dados

  • PostgreSQL 18 (última versão estável)
  • Drizzle ORM com TypeScript
  • Migrations automáticas
  • Drizzle Studio (UI visual para DB)
  • Suporte para banco local (Docker) ou remoto (Supabase, Neon, etc)

🎨 Interface

  • shadcn/ui components
  • Tailwind CSS v4
  • Dark mode suportado
  • Animações com Framer Motion

🐳 Docker

  • Multi-stage build otimizado
  • Health checks para app e banco
  • Volumes persistentes
  • Network isolada
  • Scripts npm facilitados

🧪 Desenvolvimento

  • Next.js 16 com App Router
  • Turbopack (fast refresh)
  • TypeScript 5.9
  • ESLint + Prettier
  • React 19

🛠️ Tech Stack

Frontend

  • Framework: Next.js 16 (App Router)
  • Linguagem: TypeScript 5.9
  • UI Library: React 19
  • Styling: Tailwind CSS v4
  • Components: shadcn/ui (Radix UI)
  • Icons: Lucide React, Remixicon
  • Animations: Framer Motion

Backend

  • Runtime: Node.js 22
  • Database: PostgreSQL 18
  • ORM: Drizzle ORM
  • Auth: Better Auth
  • Email: Resend

DevOps

  • Containerization: Docker + Docker Compose
  • Package Manager: pnpm
  • Build Tool: Turbopack

AI Integration (Opcional)

  • Anthropic (Claude)
  • OpenAI (GPT)
  • Google Gemini
  • OpenRouter

🚀 Início Rápido

Escolha a opção que melhor se adequa ao seu caso:

Cenário Quando usar Comando principal
Opção 1 Você vai desenvolver e alterar código docker compose up db -d + pnpm dev
Opção 2 Você só quer usar a aplicação pnpm docker:up
Opção 3 Você já tem um banco remoto docker compose up app --build

Opção 1: Desenvolvimento Local (Recomendado para Devs)

Esta é a melhor opção para desenvolvedores que vão modificar o código.

Pré-requisitos

  • Node.js 22+ instalado
  • pnpm instalado (ou npm/yarn)
  • Docker e Docker Compose instalados

Passo a Passo

  1. Clone o repositório

    git clone https://github.com/felipegcoutinho/opensheets.git
    cd opensheets
    
  2. Instale as dependências

    pnpm install
    
  3. Configure as variáveis de ambiente

    cp .env.example .env
    

    Edite o .env e configure:

    # Banco de dados (usando Docker)
    DATABASE_URL=postgresql://opensheets:opensheets_dev_password@localhost:5432/opensheets_db
    DB_PROVIDER=local
    
    # Better Auth (gere com: openssl rand -base64 32)
    BETTER_AUTH_SECRET=seu-secret-aqui
    BETTER_AUTH_URL=http://localhost:3000
    
  4. Suba apenas o PostgreSQL em Docker

    docker compose up db -d
    

    Isso sobe apenas o banco de dados em container. A aplicação roda localmente.

  5. Execute as migrations

    pnpm db:push
    
  6. Inicie o servidor de desenvolvimento

    pnpm dev
    
  7. Acesse a aplicação

    http://localhost:3000
    

Por que esta opção?

  • Hot reload perfeito - Mudanças no código refletem instantaneamente
  • Debugger funciona - Use breakpoints normalmente
  • Menos recursos - Só o banco roda em Docker
  • Drizzle Studio - Acesse com pnpm db:studio
  • Melhor DX - Developer Experience otimizada

Opção 2: Docker Completo (Usuários Finais)

Ideal para quem quer apenas usar a aplicação sem mexer no código.

Pré-requisitos

  • Docker e Docker Compose instalados

Passo a Passo

  1. Clone o repositório

    git clone https://github.com/felipegcoutinho/opensheets.git
    cd opensheets
    
  2. Configure as variáveis de ambiente

    cp .env.example .env
    

    Edite o .env:

    # Use o host "db" (nome do serviço Docker)
    DATABASE_URL=postgresql://opensheets:opensheets_dev_password@db:5432/opensheets_db
    DB_PROVIDER=local
    
    # Better Auth
    BETTER_AUTH_SECRET=seu-secret-aqui
    BETTER_AUTH_URL=http://localhost:3000
    
  3. Suba tudo em Docker

    pnpm docker:up
    # ou: docker compose up --build
    

    Isso sobe aplicação + banco de dados em containers.

  4. Acesse a aplicação

    http://localhost:3000
    
  5. Para parar

    pnpm docker:down
    # ou: docker compose down
    

Dicas

  • Use pnpm docker:up:detached para rodar em background
  • Veja logs com pnpm docker:logs
  • Reinicie com pnpm docker:restart

Opção 3: Docker + Banco Remoto

Se você já tem PostgreSQL no Supabase, Neon, Railway, etc.

Passo a Passo

  1. Configure o .env com banco remoto

    DATABASE_URL=postgresql://user:password@host.region.provider.com:5432/database?sslmode=require
    DB_PROVIDER=remote
    
    BETTER_AUTH_SECRET=seu-secret-aqui
    BETTER_AUTH_URL=http://localhost:3000
    
  2. Suba apenas a aplicação

    docker compose up app --build
    
  3. Acesse a aplicação

    http://localhost:3000
    

📜 Scripts Disponíveis

Desenvolvimento

# Servidor de desenvolvimento (com Turbopack)
pnpm dev

# Build de produção
pnpm build

# Servidor de produção
pnpm start

# Linter
pnpm lint

Banco de Dados (Drizzle)

# Gerar migrations a partir do schema
pnpm db:generate

# Executar migrations
pnpm db:migrate

# Push schema direto para o banco (dev only)
pnpm db:push

# Abrir Drizzle Studio (UI visual do banco)
pnpm db:studio

Docker

# Subir todos os containers (app + banco)
pnpm docker:up

# Subir em background (detached mode)
pnpm docker:up:detached

# Parar todos os containers
pnpm docker:down

# Parar e REMOVER volumes (⚠️ apaga dados do banco!)
pnpm docker:down:volumes

# Ver logs em tempo real
pnpm docker:logs

# Logs apenas da aplicação
pnpm docker:logs:app

# Logs apenas do banco de dados
pnpm docker:logs:db

# Reiniciar containers
pnpm docker:restart

# Rebuild completo (força reconstrução)
pnpm docker:rebuild

Utilitários

# Setup automático de variáveis de ambiente
pnpm env:setup

🐳 Docker - Guia Detalhado

Arquitetura Docker

┌─────────────────────────────────────────────────┐
│              docker-compose.yml                 │
├─────────────────────────────────────────────────┤
│                                                 │
│  ┌──────────────────┐      ┌─────────────────┐ │
│  │   app            │      │      db         │ │
│  │   (Next.js 16)   │◄─────┤  (PostgreSQL 18)│ │
│  │   Port: 3000     │      │  Port: 5432     │ │
│  │   Node.js 22     │      │  Alpine Linux   │ │
│  └──────────────────┘      └─────────────────┘ │
│                                                 │
│  Network: opensheets_network (bridge)                │
│  Volume: opensheets_postgres_data (persistent)       │
│                                                 │
└─────────────────────────────────────────────────┘

Multi-Stage Build

O Dockerfile usa 3 stages para otimização:

  1. deps - Instala dependências
  2. builder - Builda a aplicação (Next.js standalone)
  3. runner - Imagem final mínima (apenas produção)

Benefícios:

  • Imagem final muito menor (~200MB vs ~1GB)
  • Build cache eficiente
  • Apenas dependências de produção no final
  • Security: roda como usuário não-root

Health Checks

Ambos os serviços têm health checks:

PostgreSQL:

  • Comando: pg_isready
  • Intervalo: 10s
  • Timeout: 5s

Next.js App:

  • Endpoint: http://localhost:3000/api/health
  • Intervalo: 30s
  • Start period: 40s (aguarda build)

Volumes e Persistência

volumes:
  postgres_data:
    name: opensheets_postgres_data
    driver: local
  • Os dados do PostgreSQL persistem entre restarts
  • Para apagar dados: pnpm docker:down:volumes
  • Para backup: docker compose exec db pg_dump...

Network Isolada

networks:
  opensheets_network:
    name: opensheets_network
    driver: bridge
  • App e banco se comunicam via network interna
  • Isolamento de segurança
  • DNS automático (app acessa db:5432)

Comandos Docker Avançados

# Entrar no container da aplicação
docker compose exec app sh

# Entrar no container do banco
docker compose exec db psql -U opensheets -d opensheets_db

# Ver status dos containers
docker compose ps

# Ver uso de recursos
docker stats opensheets_app opensheets_postgres

# Backup do banco
docker compose exec db pg_dump -U opensheets opensheets_db > backup.sql

# Restaurar backup
docker compose exec -T db psql -U opensheets -d opensheets_db < backup.sql

# Limpar tudo (containers, volumes, images)
docker compose down -v
docker system prune -a

Customizando Portas

No arquivo .env:

# Porta da aplicação (padrão: 3000)
APP_PORT=3001

# Porta do banco de dados (padrão: 5432)
DB_PORT=5433

🔐 Configuração de Variáveis de Ambiente

Copie o .env.example para .env e configure:

Variáveis Obrigatórias

# === Database ===
DATABASE_URL=postgresql://opensheets:opensheets_dev_password@localhost:5432/opensheets_db
DB_PROVIDER=local  # ou "remote"

# === Better Auth ===
# Gere com: openssl rand -base64 32
BETTER_AUTH_SECRET=seu-secret-super-secreto-aqui
BETTER_AUTH_URL=http://localhost:3000

Variáveis Opcionais

PostgreSQL (customização)

POSTGRES_USER=opensheets
POSTGRES_PASSWORD=opensheets_dev_password
POSTGRES_DB=opensheets_db

Portas (customização)

APP_PORT=3000
DB_PORT=5432

OAuth Providers

GOOGLE_CLIENT_ID=seu-google-client-id
GOOGLE_CLIENT_SECRET=seu-google-client-secret

GITHUB_CLIENT_ID=seu-github-client-id
GITHUB_CLIENT_SECRET=seu-github-client-secret

Email (Resend)

RESEND_API_KEY=re_seu_api_key
EMAIL_FROM=noreply@seudominio.com

AI Providers

ANTHROPIC_API_KEY=sk-ant-...
OPENAI_API_KEY=sk-...
GOOGLE_GENERATIVE_AI_API_KEY=...
OPENROUTER_API_KEY=sk-or-...

Gerando Secrets

# BETTER_AUTH_SECRET
openssl rand -base64 32

# Ou use o script automático
pnpm env:setup

🗄️ Banco de Dados

Escolhendo entre Local e Remoto

Modo Quando usar Como configurar
Local Desenvolvimento, testes, prototipagem DB_PROVIDER=local + Docker
Remoto Produção, deploy, banco gerenciado DB_PROVIDER=remote + URL do provider

Drizzle ORM

Schema Definition

Os schemas ficam em /db/schema.ts:

import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";

export const users = pgTable("users", {
  id: serial("id").primaryKey(),
  email: text("email").notNull().unique(),
  name: text("name"),
  createdAt: timestamp("created_at").defaultNow(),
});

Gerando Migrations

# Após alterar /db/schema.ts
pnpm db:generate

# Aplica migrations
pnpm db:migrate

# Ou push direto (dev only)
pnpm db:push

Drizzle Studio

Interface visual para explorar e editar dados:

pnpm db:studio

Abre em: https://local.drizzle.studio

Migrations Automáticas (Docker)

No docker-compose.yml, migrations rodam automaticamente:

command:
  - |
    echo "📦 Rodando migrations..."
    pnpm db:push

    echo "✅ Iniciando aplicação..."
    node server.js

Backup e Restore

# Backup (banco local Docker)
docker compose exec db pg_dump -U opensheets opensheets_db > backup_$(date +%Y%m%d).sql

# Backup (banco remoto)
pg_dump $DATABASE_URL > backup.sql

# Restore (Docker)
docker compose exec -T db psql -U opensheets -d opensheets_db < backup.sql

# Restore (remoto)
psql $DATABASE_URL < backup.sql

🏗️ Arquitetura

Estrutura de Pastas

opensheets/
├── app/                      # Next.js App Router
│   ├── api/                  # API Routes
│   │   ├── auth/            # Better Auth endpoints
│   │   └── health/          # Health check
│   ├── (dashboard)/         # Protected routes (com auth)
│   └── layout.tsx           # Root layout
│
├── components/              # React Components
│   ├── ui/                  # shadcn/ui components
│   └── ...                  # Feature components
│
├── lib/                     # Shared utilities
│   ├── db.ts               # Drizzle client
│   ├── auth.ts             # Better Auth server
│   └── auth-client.ts      # Better Auth client
│
├── db/                      # Drizzle schema
│   └── schema.ts           # Database schema
│
├── drizzle/                 # Generated migrations
│   └── migrations/
│
├── hooks/                   # Custom React hooks
├── public/                  # Static assets
├── scripts/                 # Utility scripts
│   ├── setup-env.sh        # Env setup automation
│   └── postgres/init.sql   # PostgreSQL init script
│
├── docker/                  # Docker configs
│   └── postgres/init.sql
│
├── Dockerfile              # Production build
├── docker-compose.yml      # Docker orchestration
├── next.config.ts          # Next.js config
├── drizzle.config.ts       # Drizzle ORM config
├── tailwind.config.ts      # Tailwind config
└── tsconfig.json           # TypeScript config

Fluxo de Autenticação

1. Usuário acessa rota protegida
   ↓
2. middleware.ts verifica sessão (Better Auth)
   ↓
3. Se não autenticado → redirect /auth
   ↓
4. Usuário faz login (OAuth ou email)
   ↓
5. Better Auth valida e cria sessão
   ↓
6. Cookie de sessão é salvo
   ↓
7. Usuário acessa rota protegida ✅

Fluxo de Build (Docker)

1. Stage deps: Instala dependências
   ↓
2. Stage builder: Builda Next.js (standalone)
   ↓
3. Stage runner: Copia apenas build + deps prod
   ↓
4. Container final: ~200MB (otimizado)

🆘 Troubleshooting

Erro: "DATABASE_URL env variable is not set"

Causa: Arquivo .env não existe ou DATABASE_URL não configurado

Solução:

cp .env.example .env
# Edite .env e configure DATABASE_URL

Container do app não conecta ao banco

Causa: DATABASE_URL usa localhost em vez de db

Solução:

Para Docker, use o nome do serviço:

# ❌ Errado (localhost não funciona dentro do container)
DATABASE_URL=postgresql://opensheets:senha@localhost:5432/opensheets_db

# ✅ Correto (usa nome do serviço Docker)
DATABASE_URL=postgresql://opensheets:senha@db:5432/opensheets_db

Para desenvolvimento local (sem Docker app):

# ✅ Correto (app roda local, banco em Docker)
DATABASE_URL=postgresql://opensheets:senha@localhost:5432/opensheets_db

Verifique o status do banco:

docker compose ps
docker compose logs db

Porta 3000 ou 5432 já está em uso

Solução:

Edite o .env:

APP_PORT=3001
DB_PORT=5433

Ou pare o processo que está usando:

# Descobrir quem usa a porta
lsof -i :3000
lsof -i :5432

# Matar processo
kill -9 <PID>

Migrations não rodam

Com Docker:

Migrations rodam automaticamente no startup. Veja logs:

pnpm docker:logs:app

Se falharem, rode manualmente:

docker compose exec app pnpm db:push

Sem Docker:

pnpm db:push

Erro: "server.js not found"

Causa: Next.js não gerou standalone build

Solução:

  1. Verifique next.config.ts:
const nextConfig: NextConfig = {
  output: "standalone", // ← Deve estar presente
};
  1. Rebuild:
docker compose down
docker compose up --build

Erro ao atualizar PostgreSQL 16 → 18

Causa: Volumes antigos são incompatíveis

Solução:

# ⚠️ ATENÇÃO: Isso apaga dados do banco local!
docker compose down -v

# Suba novamente com PostgreSQL 18
docker compose up --build

Para preservar dados:

# 1. Backup
docker compose exec db pg_dumpall -U opensheets > backup.sql

# 2. Limpa volumes
docker compose down -v

# 3. Sobe PG 18
docker compose up -d db

# 4. Aguarda (15s)
sleep 15

# 5. Restaura
docker compose exec -T db psql -U opensheets -d opensheets_db < backup.sql

Drizzle Studio não abre

Solução:

  1. Verifique se o banco está rodando:
docker compose ps
  1. Teste conexão:
psql $DATABASE_URL
  1. Abra Drizzle Studio:
pnpm db:studio

Build do Docker muito lento

Causa: Cache não está sendo aproveitado

Solução:

  1. Use BuildKit:
export DOCKER_BUILDKIT=1
docker compose build
  1. Limpe cache antigo:
docker builder prune
  1. Multi-stage build já otimiza camadas

"Permission denied" ao rodar Docker

Causa: Usuário não está no grupo docker

Solução (Linux):

sudo usermod -aG docker $USER
newgrp docker

Solução (Mac/Windows):

  • Docker Desktop deve estar rodando
  • Verifique configurações de permissão

Limpar tudo e começar do zero

# Para containers e remove volumes
docker compose down -v

# Remove images não usadas
docker system prune -a

# Remove TUDO do Docker (cuidado!)
docker system prune -a --volumes

# Rebuild do zero
pnpm docker:up

🤝 Contribuindo

Contribuições são muito bem-vindas!

Como contribuir

  1. Fork o projeto
  2. Clone seu fork
    git clone https://github.com/seu-usuario/opensheets.git
    
  3. Crie uma branch para sua feature
    git checkout -b feature/minha-feature
    
  4. Commit suas mudanças
    git commit -m 'feat: adiciona minha feature'
    
  5. Push para a branch
    git push origin feature/minha-feature
    
  6. Abra um Pull Request

Padrões

  • Use TypeScript
  • Siga o ESLint configurado
  • Documente features novas
  • Use commits semânticos (feat, fix, docs, etc)

📄 Licença

Este projeto é open source e está disponível sob a Licença MIT.


🙏 Agradecimentos


📞 Contato

Desenvolvido por: Felipe Coutinho GitHub: @felipegcoutinho Repositório: opensheets


Se este projeto foi útil, considere dar uma estrela!

Desenvolvido com ❤️ para a comunidade open source

Description
No description provided
Readme 29 MiB
Languages
TypeScript 99.1%
CSS 0.6%
Dockerfile 0.2%