Importação inicial do projeto Shivão (Diário de Bordo do veleiro) em estado pronto pra produção, já incluindo as 5 mudanças de hardening implementadas pela squad shivao-melhoria em 2026-04-27. Mudanças de hardening (HANDOFF.md seção "✅ Pronto"): 1. **Rate limiting nos 3 endpoints públicos de share** - express-rate-limit ^8.4.1, 60 req/min/IP - server/src/index.js linhas 38, 262, 271, 279 2. **Tamanho de upload reduzido pra 50MB** (era 200MB) - multer linha 84 3. **Validação Zod nos endpoints autenticados** (POST /api/data e /zones) - novo arquivo server/src/schemas/index.js - middleware validate() retorna 400 com top 5 issues 4. **Audit log de ações sensíveis** - nova tabela audit_log + funções db.audit() e db.recentAudit() - 6 endpoints instrumentados (state_set, media_insert/delete, share_create/revoke/zones_update) - novo endpoint GET /api/audit (autenticado) 5. **Catch silencioso de webhook em zona PROIBIDA tratado** - app/diario-bordo.html + server/public/index.html linha 3280 - agora loga erro + exibe toast ao usuário Status final do HANDOFF: - 🔴 Críticos restantes: 1 (CORS — decisão consciente single-tenant, não-acionável) - 🟡 Importantes: 4 itens (testes, vigia reconnect, refator frontend, demais catches) - 🟢 Bom-ter: 5 itens Stack: Node 20 ESM + Express + better-sqlite3 + Docker (Coolify) Single-tenant pessoal · single-file frontend HTML · offline-first Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.4 KiB
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 emts DESC - Funções
db.audit(action, entity, entityId, summary, ip)edb.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-melhoriaem 2026-04-27 (run 2026-04-27-131311 +audit step)
- Nova tabela
- Validação Zod nos endpoints autenticados (
server/src/schemas/index.js+ middleware nos endpoints)POST /api/data: schema permissivoz.object({data: z.record(z.string(), z.unknown())})— aceita qualquer estrutura de objeto, rejeita payload semdataou não-objetoPOST /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-melhoriaem 2026-04-27 (run 2026-04-27-131311 +zod step)
- Tamanho de upload reduzido pra 50 MB (
server/src/index.jslinha 83)- Multer agora retorna 413 (Payload Too Large) acima de 50MB
- Implementado pelo squad
shivao-melhoriaem 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-limitv8 — cobre auto-refresh 15s da tripulação com margem 15× - Aplicado em
server/src/index.jslinhas 38 (limiter), 262, 271, 279 (middleware) - Implementado pelo squad
shivao-melhoriaem 2026-04-27 (run 2026-04-27-124638)
- 60 req/min/IP via
⚠️ O que precisa ser feito antes de produção
🔴 Crítico (segurança)
- 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.
- Status: decisão consciente de manter
🟡 Importante (qualidade)
-
Testes automatizados — projeto não tem testes
- Backend: vitest ou jest para os endpoints
- Frontend: playwright para fluxos críticos (especialmente alarme e GPS)
-
Tratamento de erros no frontend
- Várias chamadas async fazem
.catch(()=>{})silenciosamente - Falhas de sync não são reportadas ao usuário
- Várias chamadas async fazem
-
Reconexão da vigia após app dormir
- Wake Lock pode falhar; GPS pode pausar quando tab inativo
- Investigar Service Worker + Background Sync API
-
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
-
TypeScript no backend
- Hoje JavaScript puro com JSDoc
- Migração para TS deixaria mais robusto
🟢 Bom ter
-
Service Worker / PWA real
- Hoje usa apenas meta tags + "Adicionar à tela inicial"
- Service Worker permitiria offline real, push notifications
-
Backup automático para S3/Backblaze
- Hoje SQLite + filesystem em volume Coolify
- Schedule de backup off-site
-
Multi-usuário / multi-barco
- Hoje single-tenant (um BOAT_TOKEN)
- Para escalar: introduzir users + boats + permissions
-
Histórico de tracks de cada vigia de fundeio
- Hoje só salva resumo (max drift, alarms)
- Salvar também a poligonal de movimento
-
i18n
- Hoje hardcoded em português
- Estrutura permite extrair strings facilmente
🐛 Bugs/limitações conhecidas
-
iOS: Battery API não disponível → modo "auto" sempre cai em normal. Não é problema crítico, só não economiza bateria automaticamente.
-
iOS: Wake Lock funciona em Safari 16.4+. Em versões anteriores, a tela apaga e o GPS pode parar.
-
iOS: Modo silencioso pode silenciar o som do alarme. Vibração continua funcionando.
-
Android: Quando o navegador é fechado completamente, o GPS pára (limitação do browser). O dead-man switch do servidor cobre isso.
-
Modal de tracking abre como modal mas seria melhor full-screen real. Atualmente usa CSS hack com height:100vh.
-
Geofencing só suporta círculos, não polígonos. Para áreas irregulares (canal estreito, baía com formato complexo) é uma limitação.
-
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).
-
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).
-
A chave Windy fica em localStorage — se sincronizada via cloud, trafega entre dispositivos do dono (OK, mas vale documentar).
-
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:
- Ver DEPLOY.md — passo-a-passo do Coolify
- Configurar canais de notificação (mínimo: Telegram via .env)
- Criar bot do Telegram + obter chat_id (instruções em DEPLOY.md)
- Definir
BOAT_TOKEN(32 chars aleatórios) - Volume
/datapersistente - Deploy
Para desenvolver localmente:
- Ver CONTRIBUTING.md
cp .env.example .enve preenchernpm installnpm start- 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.