Files
convite-rael/instrucoes.md
2026-10-02 21:36:17 -03:00

18 KiB

Convite Safari 🦁 — Manual de Instruções

Este documento reúne tudo o que é preciso para instalar, publicar e usar o Convite Safari.

  • Parte 1 — Deploy: para quem vai instalar e manter a aplicação no servidor.
  • Parte 2 — Uso: para o organizador da festa e para os convidados.

Sumário

Parte 1 — Deploy

  1. Visão geral da arquitetura
  2. Pré-requisitos
  3. Copiar o projeto para o servidor
  4. Configurar as variáveis de ambiente
  5. Subir a aplicação
  6. Verificar se está tudo funcionando
  7. Publicar via Cloudflare
  8. Atualizar para uma nova versão
  9. Backup e restauração
  10. Operação do dia a dia
  11. Solução de problemas

Parte 2 — Uso

  1. Conceitos
  2. Área do organizador
  3. Experiência do convidado
  4. Perguntas frequentes

Parte 1 — Deploy

1. Visão geral da arquitetura

A aplicação roda em dois containers gerenciados pelo Docker Compose:

Serviço Imagem Função
app construída pelo Dockerfile do projeto Servidor Next.js (páginas, área do organizador, RSVP) na porta 3000
db postgres:17-alpine Banco de dados. Os dados ficam no volume pgdata
Convidado / Organizador
        │
        ▼
 Cloudflare (HTTPS)  ──►  Servidor :3000  ──►  container app  ──►  container db (Postgres)
                                                                     └─ volume pgdata

Pontos importantes:

  • O banco não fica exposto para fora do servidor; só o container app o acessa.
  • As migrations (criação/atualização das tabelas) são aplicadas automaticamente toda vez que o container app sobe.
  • Os dados ficam no volume Docker pgdata e sobrevivem a reinícios e rebuilds dos containers.

2. Pré-requisitos

No servidor (ex.: 192.168.18.97):

  • Docker com o plugin Compose. Para conferir:

    docker --version
    docker compose version
    
  • Acesso à internet durante o build — o build baixa as dependências npm e as fontes do Google.

  • Porta livre para a aplicação (padrão 3000; pode ser alterada em APP_PORT).


3. Copiar o projeto para o servidor

Copie a pasta do projeto para o servidor sem as pastas node_modules, .next e dist (elas são recriadas no build).

Exemplo com rsync, a partir da máquina onde está o código:

rsync -av --exclude node_modules --exclude .next --exclude dist ./ usuario@192.168.18.97:/opt/convite/

Troque usuario e /opt/convite/ pelo usuário e pela pasta usados nas outras aplicações do servidor.

Arquivos essenciais que precisam estar no servidor:

Dockerfile
compose.yml
.dockerignore
.env.example
package.json
package-lock.json
next.config.ts
tsconfig.json
postcss.config.mjs
drizzle.config.ts
drizzle/        (migrations SQL)
scripts/        (script de migration)
src/
public/

4. Configurar as variáveis de ambiente

No servidor, dentro da pasta do projeto:

cd /opt/convite
cp .env.example .env
nano .env

Variáveis

Variável Obrigatória Exemplo Descrição
POSTGRES_DB não convite Nome do banco
POSTGRES_USER não convite Usuário do banco
POSTGRES_PASSWORD sim Xk29fLq81 Senha do banco. Só letras e números
DATABASE_URL não* — Usada apenas fora do Docker. No compose é montada automaticamente
APP_PORT não 3000 Porta publicada no servidor
ORGANIZER_PASSWORD sim — Senha de acesso à área do organizador
SESSION_SECRET sim — Chave de 32+ caracteres para assinar a sessão
COOKIE_SECURE sim false false para acesso por http://IP; true atrás do Cloudflare (HTTPS)
RUN_MIGRATIONS não true false desliga a migration automática na subida

* Não precisa alterar para o deploy com Docker.

Gerar o SESSION_SECRET

Em qualquer máquina com Node.js:

node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"

Ou no próprio servidor, sem Node:

openssl rand -base64 32 | tr -d '/+=' 

Cole o resultado em SESSION_SECRET=.

Exemplo de .env preenchido

POSTGRES_DB=convite
POSTGRES_USER=convite
POSTGRES_PASSWORD=Xk29fLq81mPz

APP_PORT=3000

ORGANIZER_PASSWORD=uma-senha-forte-para-o-admin
SESSION_SECRET=3qD0x9bN1pY7sKcVb2T8wM4rH6jLz5aEoUfGiQ
COOKIE_SECURE=false

🔒 O .env contém senhas. Não envie esse arquivo por e-mail/chat e restrinja o acesso: chmod 600 .env.


5. Subir a aplicação

docker compose up -d --build

O que acontece, em ordem:

  1. A imagem do app é construída (pode levar alguns minutos na primeira vez).
  2. O Postgres sobe; o app aguarda o banco ficar saudável.
  3. O app aplica as migrations pendentes.
  4. O servidor Next.js inicia na porta APP_PORT.

6. Verificar se está tudo funcionando

Status dos containers — ambos devem estar running (e o db como healthy):

docker compose ps

Logs do app:

docker compose logs -f app

Saída esperada (resumida):

Migrations aplicadas.
▲ Next.js 16.x
- Local: http://0.0.0.0:3000
✓ Ready

No navegador:

Endereço Deve mostrar
http://192.168.18.97:3000/ Página inicial "Convites Digitais de Aniversário"
http://192.168.18.97:3000/admin Tela de login do organizador

Entre com a ORGANIZER_PASSWORD. Se cair na lista de eventos (vazia), o deploy está concluído.


7. Publicar via Cloudflare

Quando o Cloudflare for apontar para a aplicação (mesmo padrão das outras aplicações do servidor):

  1. Configure o domínio/túnel no Cloudflare apontando para http://<servidor>:<APP_PORT>.

  2. No .env, altere:

    COOKIE_SECURE=true
    
  3. Recrie o container do app:

    docker compose up -d app
    
  4. Acesse https://<seu-domínio>/admin e faça login para confirmar.

⚠️ Depois de COOKIE_SECURE=true, o login pelo IP em HTTP deixa de funcionar — isso é esperado. Use sempre o domínio HTTPS.

Os links de convite são gerados a partir do endereço em que o organizador está navegando. Por isso, depois da publicação, gere/copie os links acessando o /admin pelo domínio, e não pelo IP.


8. Atualizar para uma nova versão

  1. Copie o código novo para o servidor (mesmo comando rsync do passo 3). O .env do servidor não é sobrescrito, pois não está na pasta de origem — confira antes.

  2. Faça um backup do banco (ver seção 9) — recomendado sempre que houver mudança no banco.

  3. Reconstrua e suba o app:

    docker compose up -d --build app
    
  4. Verifique os logs (docker compose logs -f app). Novas migrations são aplicadas automaticamente.

Os dados não são perdidos em atualizações.


9. Backup e restauração

Backup

docker compose exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > backup-$(date +%F).sql

Gera um arquivo como backup-2026-11-10.sql na pasta atual. Guarde uma cópia fora do servidor.

Backup automático diário (opcional) — adicione ao crontab -e do servidor:

0 3 * * * cd /opt/convite && docker compose exec -T db sh -c 'pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB"' > /opt/convite/backups/backup-$(date +\%F).sql

(crie a pasta antes: mkdir -p /opt/convite/backups)

Restauração

A restauração deve ser feita em um banco vazio. Para recriar o banco do zero:

docker compose down
docker volume rm convite_pgdata        # ⚠️ APAGA todos os dados atuais
docker compose up -d db
docker compose exec -T db sh -c 'psql -U "$POSTGRES_USER" "$POSTGRES_DB"' < backup-AAAA-MM-DD.sql
docker compose up -d app

⚠️ Nunca use docker compose down -v sem querer apagar o banco — o -v remove o volume pgdata.


10. Operação do dia a dia

Tarefa Comando
Ver status docker compose ps
Ver logs do app docker compose logs -f app
Ver logs do banco docker compose logs -f db
Reiniciar o app docker compose restart app
Parar tudo (mantém dados) docker compose down
Subir novamente docker compose up -d
Console SQL docker compose exec db sh -c 'psql -U "$POSTGRES_USER" "$POSTGRES_DB"'
Trocar a senha do organizador Edite ORGANIZER_PASSWORD no .env e rode docker compose up -d app
Derrubar todas as sessões abertas Troque o SESSION_SECRET no .env e rode docker compose up -d app

Os containers estão com restart: unless-stopped: voltam sozinhos se o servidor reiniciar.


11. Solução de problemas

Sintoma Causa provável Solução
defina POSTGRES_PASSWORD no .env ao subir Variável ausente Preencha POSTGRES_PASSWORD no .env
App reiniciando em loop; log com Falha ao aplicar migrations Banco inacessível ou senha errada Confira docker compose logs db e as variáveis POSTGRES_*
Erro de senha no Postgres após trocar POSTGRES_PASSWORD A senha só é definida na primeira criação do volume Volte a senha antiga no .env ou altere no banco: ALTER USER convite PASSWORD 'nova';
Login do /admin sempre volta para a tela de login COOKIE_SECURE=true com acesso via HTTP Use false no acesso por IP, ou acesse pelo domínio HTTPS
Erro SESSION_SECRET não definida no log Variável vazia ou curta Gere um valor de 32+ caracteres (seção 4)
"Senha incorreta." no login ORGANIZER_PASSWORD diferente da digitada Confira o .env e recrie o app após alterar
Build falha baixando fontes/pacotes Servidor sem internet no build Libere o acesso à internet durante o docker compose build
Porta 3000 em uso Outra aplicação na mesma porta Altere APP_PORT no .env
Link do convite abre com o IP em vez do domínio Link copiado acessando o admin pelo IP Acesse o /admin pelo domínio e copie de novo

Parte 2 — Uso

12. Conceitos

Termo Significado
Evento A festa: nome, data, horário, local e endereço. Ex.: "1º Aniversário do Arthur"
Convite Um link enviado para uma família/grupo. Tem um nome exibido (ex.: "Família Silva") e uma lista de convidados
Convidado Cada pessoa do convite, marcada como Adulto ou Criança
Token Código único no final do link (/r/Ab3xY9kL). Funciona como a "chave" do convite
RSVP / Status Resposta de cada convidado: ✓ Presente, ✗ Ausente ou ⏳ Pendente

Um evento pode ter vários convites; cada convite pode ter vários convidados.


13. Área do organizador

13.1 Entrar

  1. Acesse https://<seu-domínio>/admin (ou http://192.168.18.97:3000/admin antes da publicação). Também há o link discreto "Área do organizador" no rodapé da página inicial.
  2. Digite a senha do organizador e clique em Entrar.

A sessão dura 7 dias no mesmo navegador. Para sair, clique em Sair no topo da página.

13.2 Painel de eventos

A tela inicial do organizador lista todos os eventos com:

  • data, horário e local;
  • quantidade de convites;
  • resumo de presença: Presentes (com divisão adultos/crianças), Ausentes e Pendentes.

Clique em um evento para abrir os detalhes.

13.3 Criar um evento

  1. No painel, clique em + Novo evento.
  2. Preencha:
    • Nome da festa — ex.: "1º Aniversário do Arthur"
    • Data e Horário
    • Local — ex.: "Espaço Festa"
    • Endereço — ex.: "Rua das Flores, 100 - Belo Horizonte/MG"
  3. Clique em Criar evento. Você será levado à página do evento.

13.4 Criar um convite

  1. Na página do evento, clique em + Novo convite.
  2. Preencha o Nome exibido no convite — é o título grande que o convidado vê. Ex.: "Família Silva", "Tio João e Tia Ana".
  3. Adicione os convidados:
    • digite o nome na primeira linha e escolha Adulto ou Criança;
    • use + Adulto / + Criança para adicionar mais linhas;
    • use ✕ para remover uma linha. Linhas com o nome em branco são ignoradas.
  4. Clique em Criar convite.

O link do convite é gerado automaticamente.

💡 Dica: crie um convite por família/núcleo. Assim cada família responde por todos os seus membros de uma vez.

13.5 Enviar o convite

Em cada convite, na página do evento:

  • Copiar link — copia o endereço completo (ex.: https://seu-dominio/r/Ab3xY9kL) para colar onde quiser.
  • WhatsApp — abre o WhatsApp com uma mensagem pronta contendo o nome da família, o nome da festa e o link. Basta escolher o contato e enviar.
  • Abrir convite — abre o convite em outra aba, exatamente como o convidado verá.

🔒 Cada link dá acesso àquele convite e permite responder por ele. Envie apenas para a família correspondente e não publique em grupos abertos ou redes sociais.

13.6 Acompanhar as respostas

Na página do evento:

  • O Resumo de presença mostra o total de presentes (adultos e crianças), ausentes e pendentes de todo o evento — útil para fechar números com buffet e decoração.
  • Cada convite mostra seus convidados com o status colorido:
    • 🟢 ✓ Presente
    • 🔴 ✗ Ausente
    • 🟡 ⏳ Pendente
  • Quando a família responde, aparece "respondeu em dd/mm/aaaa hh:mm" abaixo do nome.

Recarregue a página para ver respostas novas.

13.7 Editar um convite

  1. No convite, clique em Editar.
  2. Altere o nome exibido, renomeie convidados, troque o tipo, adicione ou remova pessoas.
  3. Clique em Salvar alterações.

O link não muda ao editar. O status de cada convidado aparece ao lado do nome durante a edição.

⚠️ Remover um convidado apaga também a resposta dele. Convidados mantidos ou apenas renomeados preservam a resposta.

13.8 Zerar as respostas de um convite

Se uma família respondeu por engano e quer começar de novo:

  1. No convite, clique em Zerar respostas (só aparece se já houve resposta).
  2. Confirme.

Todos os convidados daquele convite voltam para Pendente. O link continua o mesmo.

13.9 Excluir um convite

  1. No convite, clique em Excluir e confirme.

O link deixa de funcionar imediatamente (o convidado verá "Convite não encontrado"). Não é possível desfazer.

13.10 Editar ou excluir um evento

  1. Na página do evento, clique em Editar evento.
  2. Altere os dados e clique em Salvar alterações — as mudanças aparecem na hora em todos os convites do evento.
  3. Para excluir, use Excluir evento no final da página e confirme.

⚠️ Excluir um evento apaga todos os convites e respostas dele. Não é possível desfazer.


14. Experiência do convidado

O convidado não precisa de cadastro nem senha — só do link recebido.

14.1 Abrir o convite

Ao abrir o link, o convidado vê:

  1. O nome do convite em destaque (ex.: "Família Silva — esperamos vocês para celebrar!").
  2. Os detalhes da festa: data, horário, local e endereço.
  3. A lista de convidados daquele convite, cada um com seu status atual.
  4. O quadro de Confirmação de Presença, com a contagem de presentes, ausentes e pendentes.

14.2 Responder

  1. Para cada pessoa da lista, toque em:
    • ✓ para confirmar presença, ou
    • ✗ para informar ausência. Para mudar de ideia antes de enviar, basta tocar no outro botão.
  2. Toque em Confirmar Presença.
  3. Aparece a tela "Presença Confirmada!" com o resumo de quem vai e quem não vai. Toque em Fechar.

Não é obrigatório responder por todos de uma vez: quem ficar como pendente pode ser respondido depois.

14.3 Mudar a resposta

O convidado pode abrir o mesmo link a qualquer momento. As respostas já enviadas aparecem marcadas; basta trocar (ex.: de ✓ para ✗) e tocar em Confirmar Presença novamente.

14.4 Mensagens possíveis

Mensagem Significado
Convite não encontrado Link digitado errado, incompleto ou convite excluído pelo organizador
Não foi possível enviar sua resposta. Tente novamente. Falha de conexão ou o convite foi alterado no meio do caminho. Recarregue a página e responda de novo

15. Perguntas frequentes

O convidado precisa instalar algum aplicativo? Não. Funciona no navegador do celular ou do computador.

Posso usar o mesmo sistema para várias festas? Sim. Crie um evento para cada festa; cada um tem seus próprios convites e totais.

Duas pessoas da mesma família podem responder pelo mesmo link? Sim. Vale a última resposta enviada para cada convidado.

Um convidado novo apareceu depois que a família já respondeu. O que faço? Edite o convite e adicione a pessoa. Ela aparece como Pendente e as respostas anteriores dos outros são mantidas. Peça para a família abrir o link de novo e responder por ela.

Enviei o link errado para uma família. Como invalido? Exclua o convite e crie outro — o novo convite terá um link diferente.

Esqueci a senha do organizador. Quem administra o servidor consulta/altera ORGANIZER_PASSWORD no .env e recria o app (docker compose up -d app).

Os dados ficam salvos se o servidor reiniciar? Sim. Os dados ficam no banco Postgres, em um volume persistente. Mesmo assim, mantenha backups (seção 9).