shivao-projeto/server
PontualTech / Karlão f8e92f3c58
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
fix(auth): cloudConfigured() reconhece login Google/email (sem token) v1.7.1
Bug crítico: após login Google ou email, o app pedia pra logar
DE NOVO toda vez que abria/fechava. E sync nunca iniciava.

Causa: cloudConfigured() exigia state.cloud.token, mas no login
Google/email a auth fica em state.auth.accessToken (JWT), não em
state.cloud.token (que é o BOAT_TOKEN avançado).

Resultado: cloudConfigured() retornava false → welcome screen
sempre aparecia, rtConnect() nunca rodava, sync zero.

Fix:
- cloudConfigured() agora retorna true se tem state.auth.accessToken
  OU state.cloud.token (qualquer um dos dois)
- maybeShowWelcome() reescrito pra checar autenticação real
- Botão "Usar sem login (modo offline)" mais visível na welcome
  screen pra dar saída clara

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 09:13:37 -03:00
..
public fix(auth): cloudConfigured() reconhece login Google/email (sem token) v1.7.1 2026-04-28 09:13:37 -03:00
src fix(auth): cloudConfigured() reconhece login Google/email (sem token) v1.7.1 2026-04-28 09:13:37 -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.