shivao-projeto/HANDOFF.md
PontualTech / Karlão 78c6de538a feat(reliability): vigia reconnect (Wake Lock release + GPS retry exponencial)
Run 6 da squad shivao-melhoria — HANDOFF item 5 (Reconexão da vigia)
parcialmente resolvido sem Service Worker (decisão conservadora,
SW mal feito quebraria offline-first).

4 fixes em app/diario-bordo.html + server/public/index.html (sincronizados):

1. requestWakeLock (tracking, linha 1345) + requestAnchorWakeLock (anchor, 1831)
   - Adicionado wakeLock.addEventListener('release', ...) com auto-reacquire em 1s
   - Garante que sistema soltando o Wake Lock (background tab, low battery)
     não deixa a tela apagar permanentemente enquanto vigia/rastreio ativos

2. startGPS (tracking, linha 1347) + startAnchorGPS (anchor, 1901)
   - Retry exponencial: 1s, 2s, 4s, 8s, 16s, 30s (max)
   - PERMISSION_DENIED é fatal sem retry (com mensagem clara ao dono)
   - Outros erros (POSITION_UNAVAILABLE, TIMEOUT) → retry com backoff
   - Counter resetado a cada GPS update bem-sucedido (recuperação completa)

Combinado com visibilitychange listener existente (linha 1824) que re-acquire
Wake Lock quando tab volta foreground, cobre o cenário completo de:
- Tab em background no Android Chrome (GPS pausa, sistema solta Wake Lock)
- Tela apagada (Wake Lock soltada, GPS continua se permitido)
- Erro transitório de GPS (perda de sinal, recupera sozinho)
- App reaberto com vigia em andamento (loadAnchorState chama startAnchorGPS
  que agora tem retry built-in)

Service Worker real (push notifications + cache de tiles offline) fica
pra iteração futura com spec própria.

HANDOFF.md item 5 marcado como "parcialmente resolvido".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:28:09 -03:00

9.1 KiB
Raw Permalink Blame History

HANDOFF — Estado do Projeto

Documento para a equipe que vai continuar o desenvolvimento.


O que está pronto e funcionando

Frontend (app/diario-bordo.html)

Arquivo único HTML standalone (~200 KB). Pode ser:

  • Aberto direto no navegador
  • Servido pelo backend (já é o caso — está em server/public/index.html)
  • "Instalado" no Android via "Adicionar à tela inicial"

Funcionalidades verificadas em desenvolvimento:

Recurso Status Observações
Persistência local (localStorage + IndexedDB) Robusto
Travessias / Reparos / Pendências CRUD Pronto
GPS + rastreio + mapa Leaflet + OSM tiles
Vigia de fundeio + alarme Web Audio + Vibration + Wake Lock
Swing circle + auto-recentro Implementado mas pouco testado em campo
Geofencing Apenas círculos (polígonos = futuro)
Mídia (foto/áudio/vídeo) IndexedDB, com viewer e download
Importar GPX Trk e Rte points
Exportar GPX Por travessia
Sync com nuvem Pull, push, auto-sync
Webhooks diretos (Telegram, Discord) Sem servidor
Compartilhamento de posição ao vivo Requer servidor
Checklists customizáveis 5 templates pré-cadastrados
Windy Point Forecast API Premium key + fallback Open-Meteo
Modo economia de energia Battery API (Chrome only)

Backend (server/)

Express + SQLite + Docker, deployável em Coolify ou qualquer VPS.

Recurso Status
Auth via Bearer Token
Endpoints de sync
Upload/download de mídia
Vigia + dead-man switch
Notificações fan-out (6 canais)
Compartilhamento público com mapa
Migração de schema Automática
Health check
Cleanup de shares expirados Diário

Pronto (recém-implementado)

  • Audit log de ações sensíveis (server/src/db.js + 6 endpoints instrumentados + GET /api/audit)
    • Nova tabela audit_log (id, ts, action, entity, entity_id, summary, ip) com índice em ts DESC
    • Funções db.audit(action, entity, entityId, summary, ip) e db.recentAudit(limit)
    • Eventos rastreados: state_set, media_insert, media_delete, share_create, share_revoke, share_zones_update
    • Endpoint GET /api/audit?limit=N (autenticado, max 500) pra consulta
    • Implementado pelo squad shivao-melhoria em 2026-04-27 (run 2026-04-27-131311 +audit step)
  • Validação Zod nos endpoints autenticados (server/src/schemas/index.js + middleware nos endpoints)
    • POST /api/data: schema permissivo z.object({data: z.record(z.string(), z.unknown())}) — aceita qualquer estrutura de objeto, rejeita payload sem data ou não-objeto
    • POST /api/share/:token/zones: schema com até 100 zonas, cada uma com lat/lng/radius validados
    • 400 com top 5 issues do Zod em caso de falha
    • Implementado pelo squad shivao-melhoria em 2026-04-27 (run 2026-04-27-131311 +zod step)
  • Tamanho de upload reduzido pra 50 MB (server/src/index.js linha 83)
    • Multer agora retorna 413 (Payload Too Large) acima de 50MB
    • Implementado pelo squad shivao-melhoria em 2026-04-27 (run 2026-04-27-131311)
  • Rate limiting nos 3 endpoints públicos de share (/api/share/:token/info, /api/share/:token/positions, /share/:token)
    • 60 req/min/IP via express-rate-limit v8 — cobre auto-refresh 15s da tripulação com margem 15×
    • Aplicado em server/src/index.js linhas 38 (limiter), 262, 271, 279 (middleware)
    • Implementado pelo squad shivao-melhoria em 2026-04-27 (run 2026-04-27-124638)

⚠️ O que precisa ser feito antes de produção

🔴 Crítico (segurança)

  1. CORS atualmente permissivo (*) — apropriado para single-tenant pessoal, mas se for evoluir para multi-usuário, precisa rever
    • Status: decisão consciente de manter * enquanto for single-tenant. Item documentado, não-acionável agora.

🟡 Importante (qualidade)

  1. Testes automatizados — projeto não tem testes

    • Backend: vitest ou jest para os endpoints
    • Frontend: playwright para fluxos críticos (especialmente alarme e GPS)
  2. Tratamento de erros no frontend (parcialmente resolvido)

    • Catch silencioso de dispatchWebhooks em zona PROIBIDA (linha 3280) agora loga + toast (run 2026-04-27-131311 +catch step)
    • Restantes: catches em fetches Windy/Open-Meteo (linhas 2712, 2733) — fallbacks intencionais, mantidos conscientemente
    • Restantes: catches }catch(e){} em Wake Lock e tracking state — best effort em iOS antigo, mantidos
    • Pendente futura: indicador visual de "última sync falhou" no painel cloud
  3. Reconexão da vigia (parcialmente resolvido)

    • Wake Lock auto-reacquire: wakeLock.addEventListener('release', ...) em tracking + anchor (run 2026-04-27-131311 +reconnect step)
    • GPS retry exponencial (1s→2s→4s→8s→16s→30s) com PERMISSION_DENIED fatal sem retry, em tracking + anchor
    • visibilitychange listener (já existia) re-acquire Wake Lock quando tab volta foreground
    • Pendente: Service Worker real (para push notifications + offline tile cache) — exige spec própria, deixar pra futuro
  4. Refatoração do frontend

    • HTML monolítico tem ~3500 linhas
    • Considerar quebrar em módulos (mas mantendo single-file deployment)
    • Avaliar migrar para Vite + Vue/Svelte mantendo build single-file
  5. TypeScript no backend

    • Hoje JavaScript puro com JSDoc
    • Migração para TS deixaria mais robusto

🟢 Bom ter

  1. Service Worker / PWA real

    • Hoje usa apenas meta tags + "Adicionar à tela inicial"
    • Service Worker permitiria offline real, push notifications
  2. Backup automático para S3/Backblaze

    • Hoje SQLite + filesystem em volume Coolify
    • Schedule de backup off-site
  3. Multi-usuário / multi-barco

    • Hoje single-tenant (um BOAT_TOKEN)
    • Para escalar: introduzir users + boats + permissions
  4. Histórico de tracks de cada vigia de fundeio

    • Hoje só salva resumo (max drift, alarms)
    • Salvar também a poligonal de movimento
  5. i18n

    • Hoje hardcoded em português
    • Estrutura permite extrair strings facilmente

🐛 Bugs/limitações conhecidas

  1. iOS: Battery API não disponível → modo "auto" sempre cai em normal. Não é problema crítico, só não economiza bateria automaticamente.

  2. iOS: Wake Lock funciona em Safari 16.4+. Em versões anteriores, a tela apaga e o GPS pode parar.

  3. iOS: Modo silencioso pode silenciar o som do alarme. Vibração continua funcionando.

  4. Android: Quando o navegador é fechado completamente, o GPS pára (limitação do browser). O dead-man switch do servidor cobre isso.

  5. Modal de tracking abre como modal mas seria melhor full-screen real. Atualmente usa CSS hack com height:100vh.

  6. Geofencing só suporta círculos, não polígonos. Para áreas irregulares (canal estreito, baía com formato complexo) é uma limitação.

  7. Map tiles vêm de tile.openstreetmap.org sem cache. Em viagem com dados móveis caros, pode consumir muito. Considerar cache ou tiles próprios (MapTiler, Mapbox).

  8. Não há sincronização incremental — sempre envia/baixa o estado todo. Para usuários com muito histórico, fica lento. Sugerimos versionar por entidade (CRDT ou last-write-wins por id+ts).

  9. A chave Windy fica em localStorage — se sincronizada via cloud, trafega entre dispositivos do dono (OK, mas vale documentar).

  10. Sem HTTPS local em desenvolvimento — a API do Geolocation só funciona em HTTPS ou localhost. Devs precisam usar localhost.


📋 Decisões técnicas relevantes

Detalhes em ARCHITECTURE.md, mas em resumo:

  • SQLite + filesystem em vez de Postgres + S3 → simplicidade, single-tenant, fácil backup
  • Single-file HTML → instalável no celular sem app store, deploy simples
  • Bearer Token simples em vez de OAuth → uso pessoal
  • Leaflet + OSM em vez de Google Maps/Mapbox → grátis, sem chaves
  • Web Audio API para alarme em vez de mp3 estático → mais alto e confiável
  • Open-Meteo como fallback → app funciona sem nenhuma chave de API
  • Windy como provedor premium → o dono já tem assinatura

🚀 Para começar

Para colocar em produção:

  1. Ver DEPLOY.md — passo-a-passo do Coolify
  2. Configurar canais de notificação (mínimo: Telegram via .env)
  3. Criar bot do Telegram + obter chat_id (instruções em DEPLOY.md)
  4. Definir BOAT_TOKEN (32 chars aleatórios)
  5. Volume /data persistente
  6. Deploy

Para desenvolver localmente:

  1. Ver CONTRIBUTING.md
  2. cp .env.example .env e preencher
  3. npm install
  4. npm start
  5. Acessar http://localhost:3000

Para o time do dono passar a chave Windy:

  • A chave premium é configurada no app (não no servidor) via Aba Arquivo → Meteorologia · Windy Point Forecast
  • Não cole no código nem em variáveis de ambiente

📞 Contato

Projeto pessoal do dono do veleiro Shivao. Equipe de devs deve coordenar diretamente com ele para credenciais de produção, domínios e orçamento.