7.3 KiB
Convite Safari 🦁
Convite digital de aniversário com confirmação de presença (RSVP) e área do organizador.
- Convidados acessam o convite pelo link
/r/<token>e confirmam a presença de cada pessoa. - Organizador acessa
/admincom senha, cadastra eventos e convites, compartilha os links (copiar / WhatsApp) e acompanha as respostas.
Stack: Next.js 16 (App Router) · React 19 · TypeScript · Tailwind CSS 4 · PostgreSQL 17 · Drizzle ORM · Docker Compose
Estrutura
src/
app/
page.tsx Página inicial pública (neutra)
r/[token]/ Página do convite + Server Action do RSVP
admin/login/ Login do organizador
admin/(painel)/ Área do organizador (eventos e convites)
admin/actions.ts Server Actions do organizador
components/
invitation/ Componentes do convite
admin/ Formulários e componentes do organizador
db/
schema.ts Tabelas (events, invitations, guests)
index.ts Conexão com o Postgres
seed.ts Dados de exemplo (convites abc123 e xyz789)
lib/
auth.ts Sessão do organizador (cookie assinado)
invitation.ts Consultas do convite público
organizer.ts Consultas da área do organizador
drizzle/ Migrations SQL geradas pelo drizzle-kit
scripts/migrate.ts Aplica as migrations (usado no container)
Dockerfile Imagem de produção (Next standalone)
compose.yml App + Postgres
Variáveis de ambiente
Copie .env.example para .env e preencha:
| Variável | Descrição |
|---|---|
POSTGRES_DB |
Nome do banco criado pelo compose (padrão convite) |
POSTGRES_USER |
Usuário do banco (padrão convite) |
POSTGRES_PASSWORD |
Senha do banco. Use só letras e números (ela entra na URL de conexão) |
DATABASE_URL |
Conexão usada fora do compose (npm run dev, db:migrate, db:seed). No compose é sobrescrita automaticamente para o serviço db |
APP_PORT |
Porta publicada no servidor (padrão 3000) |
ORGANIZER_PASSWORD |
Senha de acesso ao /admin |
SESSION_SECRET |
Chave para assinar o cookie de sessão (mínimo 32 caracteres) |
COOKIE_SECURE |
true quando servido via HTTPS (Cloudflare); false para acesso direto por http://IP |
Para gerar o SESSION_SECRET:
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
⚠️ Com
COOKIE_SECURE=trueo login não funciona em HTTP puro (ex.:http://192.168.18.97:3000). Só mude paratruequando o acesso for pelo domínio HTTPS do Cloudflare.
Deploy no servidor (Docker Compose)
Pré-requisitos
- Docker com o plugin Compose (
docker compose version) - Acesso à internet durante o build (o
next buildbaixa as fontes do Google)
1. Copiar o projeto para o servidor
Copie a pasta do projeto (sem node_modules, .next e dist) para o servidor, por exemplo:
rsync -av --exclude node_modules --exclude .next --exclude dist ./ usuario@192.168.18.97:/opt/convite/
2. Configurar o .env
No servidor, dentro da pasta do projeto:
cp .env.example .env
nano .env
Preencha POSTGRES_PASSWORD, ORGANIZER_PASSWORD e SESSION_SECRET. Deixe COOKIE_SECURE=false enquanto o acesso for por IP.
3. Subir
docker compose up -d --build
O que acontece:
- O Postgres sobe e o app espera ele ficar saudável (healthcheck).
- O container do app aplica as migrations pendentes (
drizzle/) automaticamente. - O servidor Next sobe na porta
APP_PORT(padrão3000).
Acompanhe os logs:
docker compose logs -f app
Deve aparecer Migrations aplicadas. seguido da inicialização do Next.
4. Primeiro acesso
- Abra
http://192.168.18.97:3000/admine entre com aORGANIZER_PASSWORD. - Cadastre o evento e os convites.
- Use Copiar link ou WhatsApp para enviar cada convite.
O banco começa vazio. Se quiser os convites de exemplo da POC, veja Seed.
Atualizar a aplicação
Depois de copiar a nova versão do código para o servidor:
docker compose up -d --build app
As migrations novas são aplicadas na subida. Os dados do banco ficam no volume pgdata e não são perdidos ao recriar os containers.
Para desligar a migration automática, defina
RUN_MIGRATIONS=falseno.env.
Publicação via Cloudflare
Quando o Cloudflare passar a apontar para o servidor (igual às outras aplicações):
-
Aponte o domínio/túnel para a porta
APP_PORTdo servidor. -
No
.env, altereCOOKIE_SECURE=true. -
Recrie o app para aplicar:
docker compose up -d app
Backup e restauração do banco
Backup:
docker compose exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > backup-$(date +%F).sql
Restauração (em um banco vazio):
docker compose exec -T db sh -c 'psql -U "$POSTGRES_USER" "$POSTGRES_DB"' < backup-AAAA-MM-DD.sql
⚠️
docker compose down -vapaga o volume do banco. Use apenasdocker compose downpara parar os serviços.
Comandos úteis
| Comando | O que faz |
|---|---|
docker compose ps |
Status dos containers |
docker compose logs -f app |
Logs do app |
docker compose restart app |
Reinicia o app |
docker compose down |
Para tudo (mantém os dados) |
docker compose exec db sh -c 'psql -U "$POSTGRES_USER" "$POSTGRES_DB"' |
Console SQL do banco |
Desenvolvimento local
Requer Node.js 20.9+ e um Postgres acessível (pode ser só o serviço db do compose, liberando a porta 127.0.0.1:5432 no compose.yml).
npm install
cp .env.example .env # ajuste DATABASE_URL
npm run db:migrate # cria as tabelas
npm run db:seed # opcional: convites de exemplo
npm run dev
Acesse http://localhost:3000. Para abrir pela rede local (ex.: celular), o IP precisa estar em allowedDevOrigins no next.config.ts.
Scripts do banco
| Script | O que faz |
|---|---|
npm run db:generate |
Gera uma nova migration após alterar src/db/schema.ts |
npm run db:migrate |
Aplica as migrations no banco do DATABASE_URL |
npm run db:seed |
Cria os convites de exemplo (abc123, xyz789) |
npm run db:studio |
Abre o Drizzle Studio para ver/editar os dados |
Seed (dados de exemplo)
O seed não faz parte da imagem Docker. Para rodá-lo contra o banco do compose, libere a porta do Postgres em 127.0.0.1:5432 no compose.yml e, na máquina com o código e as dependências instaladas:
npm run db:seed
Problemas comuns
| Sintoma | Causa provável |
|---|---|
Login do /admin volta para a tela de login |
COOKIE_SECURE=true com acesso por HTTP — use false |
SESSION_SECRET não definida nos logs |
Variável vazia ou com menos de 32 caracteres |
defina POSTGRES_PASSWORD no .env ao subir |
POSTGRES_PASSWORD ausente no .env |
| Erro de autenticação no Postgres após trocar a senha | A senha só é aplicada na primeira criação do volume; altere no banco ou recrie o volume (apaga os dados) |
Página em branco no npm run dev acessando por IP |
IP ausente em allowedDevOrigins no next.config.ts |