shivao-projeto/server
PontualTech / Karlão 24f6df3da7
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
fix(auth): login Google funciona em apps Capacitor (redirect+polling) v1.6.1
Problema: Google Sign-In popup (GSI) não funciona em WebView nativo do
Capacitor. FedCM bloqueia, popup não abre, ou retorna erro silenciosamente.

Solução: detectar Capacitor (window.Capacitor) ou WebView (UA com 'wv') e
usar OAuth redirect tradicional + polling em vez do popup GSI.

Backend (server/src/index.js):
- GET /api/auth/google/start — gera URL OAuth com state contendo
  session_id + flow:'login'. App chama isso e abre URL no browser externo.
- /api/google/callback adaptado — quando state.flow=='login', cria/loga
  user por email do Google, gera JWT, armazena em pendingGoogleSessions
  (Map em memória, TTL 10min) por session_id, mostra HTML "logado, volte
  pro app".
- GET /api/auth/google/poll?session=xxx — app faz polling 2s. Retorna
  204 se ainda esperando, 200 com tokens (one-shot, deleta após).

Frontend (app/diario-bordo.html):
- Detecta Capacitor/WebView, força fluxo redirect+polling
- Browser web: tenta GSI popup primeiro, fallback redirect se prompt
  for bloqueado (FedCM/popup blocker)
- window.open abre Custom Tabs no Android (ou nova aba no PC)
- Timeout de 4min (120 tries × 2s) pro polling

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:20:39 -03:00
..
public fix(auth): login Google funciona em apps Capacitor (redirect+polling) v1.6.1 2026-04-28 08:20:39 -03:00
src fix(auth): login Google funciona em apps Capacitor (redirect+polling) v1.6.1 2026-04-28 08:20:39 -03:00
.gitignore chore: initial commit + security hardening (4 runs squad shivao-melhoria) 2026-04-27 13:24:08 -03:00
docker-compose.yml chore: initial commit + security hardening (4 runs squad shivao-melhoria) 2026-04-27 13:24:08 -03:00
Dockerfile chore: initial commit + security hardening (4 runs squad shivao-melhoria) 2026-04-27 13:24:08 -03:00
package-lock.json feat(sync): WebSocket realtime + auto-push/pull entre PC e celular v1.5.0 2026-04-28 06:51:35 -03:00
package.json feat(sync): WebSocket realtime + auto-push/pull entre PC e celular v1.5.0 2026-04-28 06:51:35 -03:00
README.md chore: initial commit + security hardening (4 runs squad shivao-melhoria) 2026-04-27 13:24:08 -03:00

Shivao Cloud

Backend para o Diário de Bordo do Shivao com:

  • ☁️ Sincronização dos dados na nuvem (multi-dispositivo)
  • 📷 Mídia (fotos, áudios, vídeos) armazenada no servidor
  • 🚨 Notificações automáticas (Telegram, e-mail, SMS, WhatsApp, ntfy, webhook) — sem precisar tocar em botão
  • 🛡️ Dead-man switch: se o celular perde sinal/bateria enquanto fundeado, o servidor mesmo dispara o alarme

Deploy no Coolify (passo a passo)

1. Subir o código para um repositório Git

Crie um repo no GitHub/GitLab e envie esta pasta. Ou use o "Public Repository" do Coolify direto.

2. No painel Coolify

  1. + New ResourceApplicationPublic/Private Repository
  2. Cole a URL do seu repositório
  3. Build Pack: Dockerfile
  4. Port: 3000
  5. Domain: configure seu domínio (ex: shivao.seu-dominio.com) — Coolify gera SSL automático

3. Variáveis de ambiente

Em Environment Variables no Coolify, adicione (mínimo):

Variável Valor
BOAT_TOKEN string aleatória longa (ex: openssl rand -hex 32)
TELEGRAM_BOT_TOKEN seu token do BotFather
TELEGRAM_CHAT_IDS seu chat ID

Veja .env.example para todas as opções (e-mail, SMS, etc.). Configure pelo menos um canal.

4. Volume persistente

Em StoragesPersistent Storage:

  • Name: shivao-data
  • Mount Path: /data

Sem isso, ao reiniciar o container você perde o banco e as mídias.

5. Deploy

Clique em Deploy. Aguarde o build. Acesse https://shivao.seu-dominio.com — vai aparecer o app.


Configurando o Telegram (5 minutos, recomendado)

  1. No Telegram, fale com @BotFather/newbot
  2. Escolha um nome e username → ele dá um token
  3. Inicie uma conversa com o bot que você criou (mande qualquer mensagem)
  4. Acesse https://api.telegram.org/bot<SEU_TOKEN>/getUpdates no navegador
  5. No JSON, procure "chat":{"id":123456789...} — esse é seu TELEGRAM_CHAT_IDS
  6. Cole no Coolify e redeploy

Para receber em grupo: adicione o bot ao grupo, mande uma mensagem, repita o passo 4 (chat ID será negativo).


Configurando ntfy.sh (sem cadastro, push grátis)

  1. Instale o app ntfy (Android / iOS)
  2. No app, Subscribe → invente um tópico único e secreto (ex: shivao-aljg29x71kqp)
  3. Coloque esse mesmo nome em NTFY_TOPIC no Coolify

⚠️ Como ntfy é público, qualquer pessoa que adivinhe o tópico vê suas notificações. Use algo aleatório e longo.


Configurando E-mail SMTP

Gmail (mais comum):

  1. Ative verificação em 2 etapas na conta Google
  2. Vá em Senhas de app
  3. Gere uma senha → use ela em SMTP_PASS
  4. Configure:
    SMTP_HOST=smtp.gmail.com
    SMTP_PORT=587
    SMTP_SECURE=false
    SMTP_USER=seu-email@gmail.com
    SMTP_PASS=senha-de-app-de-16-caracteres
    SMTP_FROM=Shivao Alertas <seu-email@gmail.com>
    SMTP_TO=destinatario@email.com,outro@email.com
    

Resend, SendGrid, Mailgun: similar, basta seguir o painel deles e usar SMTP.


Configurando Twilio (SMS / WhatsApp — pago)

Apenas se quiser SMS ou WhatsApp realmente automático.

  1. Crie conta em twilio.com
  2. Para SMS: compre um número (Brasil custa ~$1/mês + $0.05 por SMS)
  3. Para WhatsApp: ative o sandbox grátis OU peça aprovação Business
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=xxxxxxxxxxxxx
TWILIO_FROM_NUMBER=+15551234567
TWILIO_SMS_TO=+5521999998888
TWILIO_WHATSAPP_FROM=whatsapp:+14155238886
TWILIO_WHATSAPP_TO=whatsapp:+5521999998888

Como funciona o Dead-Man Switch

  1. Quando você toca em "Fundear" no app, ele avisa o servidor
  2. Enquanto a vigia está ativa, o app envia um heartbeat a cada 30 segundos: "estou vivo, GPS aqui"
  3. Se o servidor não receber heartbeat por 5 minutos (HEARTBEAT_TIMEOUT_SEC configurável), ele assume que algo deu errado (celular morreu, perdeu sinal, app fechou) e dispara o alarme remoto automaticamente para todos os contatos
  4. Quando você levanta âncora normalmente, o app avisa o servidor para parar a vigia

Isso garante que mesmo se você dormir e o celular morrer, alguém vai ser avisado.


Endpoints da API (referência)

Todas requerem header Authorization: Bearer <BOAT_TOKEN> (exceto /api/health).

Método Rota Função
GET /api/health Status público
GET /api/info Canais configurados
GET /api/data Baixar todo o estado
POST /api/data Enviar todo o estado
POST /api/media Upload de arquivo (multipart)
GET /api/media/list Lista de mídias
GET /api/media/:id Baixar mídia
DELETE /api/media/:id Apagar mídia
POST /api/anchor/start Iniciar vigia no servidor
POST /api/anchor/heartbeat Manter vivo
POST /api/anchor/alarm Disparar alarme imediato
POST /api/anchor/stop Encerrar vigia
GET /api/anchor/status Estado atual
POST /api/test Disparar mensagem de teste
GET /api/alarms Histórico de alarmes
POST /api/share/create Criar link público temporário
GET /api/share/list Listar shares ativos
DELETE /api/share/:token Revogar share
POST /api/share/position Postar posição (boat → server)
GET /share/:token Página pública do link (sem auth)
GET /api/share/:token/info Info do share (público)
GET /api/share/:token/positions Posições do share (público)

Rodando localmente (dev)

cp .env.example .env
# edite .env
npm install
npm start

Ou com Docker:

docker compose up --build

Acesse http://localhost:3000


Conectando o app

No app (Diário de Bordo), vá em Arquivo → Configurações da Nuvem, preencha:

  • Servidor: https://shivao.seu-dominio.com
  • Token: o mesmo BOAT_TOKEN que você definiu

Toque em Testar conexão → deve receber a mensagem de teste em todos os canais configurados.

A partir daí o app sincroniza automaticamente.