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>
215 lines
9.1 KiB
Markdown
215 lines
9.1 KiB
Markdown
# 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.
|