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>
211 lines
8.4 KiB
Markdown
211 lines
8.4 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**
|
||
- Várias chamadas async fazem `.catch(()=>{})` silenciosamente
|
||
- Falhas de sync não são reportadas ao usuário
|
||
|
||
5. **Reconexão da vigia** após app dormir
|
||
- Wake Lock pode falhar; GPS pode pausar quando tab inativo
|
||
- Investigar Service Worker + Background Sync API
|
||
|
||
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.
|