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

215 lines
9.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)
3. **Testes automatizados** — projeto não tem testes
- Backend: vitest ou jest para os endpoints
- Frontend: playwright para fluxos críticos (especialmente alarme e GPS)
4. **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
5. **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
6. **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
7. **TypeScript no backend**
- Hoje JavaScript puro com JSDoc
- Migração para TS deixaria mais robusto
### 🟢 Bom ter
8. **Service Worker / PWA real**
- Hoje usa apenas meta tags + "Adicionar à tela inicial"
- Service Worker permitiria offline real, push notifications
9. **Backup automático para S3/Backblaze**
- Hoje SQLite + filesystem em volume Coolify
- Schedule de backup off-site
10. **Multi-usuário / multi-barco**
- Hoje single-tenant (um BOAT_TOKEN)
- Para escalar: introduzir users + boats + permissions
11. **Histórico de tracks de cada vigia de fundeio**
- Hoje só salva resumo (max drift, alarms)
- Salvar também a poligonal de movimento
12. **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.