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>
6.6 KiB
CONTRIBUTING — Guia para devs
Setup inicial
Requisitos
- Node.js 20+
- npm
- (Opcional) Docker para teste do build de produção
Rodando o backend localmente
cd server
cp .env.example .env
# Edite .env com seus valores (BOAT_TOKEN obrigatório)
npm install
npm start
Acesse http://localhost:3000
Modo dev com auto-reload:
npm run dev
Rodando o frontend localmente
O HTML é standalone — pode abrir direto no navegador (file:///...), mas
algumas APIs do navegador (Geolocation, Wake Lock, MediaRecorder) só
funcionam em HTTPS ou localhost.
Recomendado: deixar o backend servindo o frontend:
cd server
npm start
# Acesse http://localhost:3000 — o backend serve public/index.html
Para iterar em mudanças do frontend:
- Edite
app/diario-bordo.html - Copie para
server/public/index.html - Recarregue o navegador (sem necessidade de rebuild)
Script de copy útil (para macOS/Linux):
cp app/diario-bordo.html server/public/index.html
Testando com Docker
cd server
docker compose up --build
Para testar o pipeline completo de produção (igual Coolify faria).
Estrutura do código
app/diario-bordo.html
Único arquivo HTML. Para navegar pelo código, use search:
| Comentário | Função |
|---|---|
============ STORAGE ============ |
Persistência local |
============ GPS Math ============ |
Haversine, conversões |
============ GPS Tracking ============ |
Rastreio de viagem |
============ ANCHOR WATCH ============ |
Vigia de fundeio |
============ ALARM ============ |
Sistema de alarme |
============ CONTACTS ============ |
Cadastro de contatos |
============ CLOUD SYNC ============ |
Integração com servidor |
============ WEBHOOKS ============ |
Telegram/Discord direto |
============ GEOFENCING / ZONES ============ |
Zonas de proibição/atenção |
============ CHECKLISTS ============ |
Listas de verificação |
============ GPX EXPORT ============ |
Export GPX |
============ BATTERY SAVER ============ |
Modo economia |
============ WEATHER ============ |
Windy + Open-Meteo |
server/src/
index.js— entry point Express, todos os routesdb.js— wrapper SQLite com queries preparednotifications.js— fan-out para todos os canais
Convenções
Estilo de código
- Sem build step no frontend — escrevemos JS direto que roda no navegador. Cuidado com features muito recentes (target ≥ Chrome 100, Safari 16).
- Zero dependências runtime no frontend exceto Leaflet e Google Fonts.
- Variáveis curtas em código compacto (ex:
rpara response,cpara content). Trade-off de legibilidade x tamanho do arquivo.
CSS
- Sistema de design baseado em variáveis CSS no
:root - Tipografia: 3 famílias (Fraunces, Manrope, JetBrains Mono)
- Paleta marítima editorial (ver ARCHITECTURE.md)
- Mobile-first, com
@media (min-width:560px)para desktop
Backend
- ESM modules (
"type": "module") async/awaitem vez de promises encadeadas- Erros logados com
console.warnouconsole.error - Status HTTP semânticos: 200 ok, 400 bad input, 401 unauth, 404 not found, 500 server
Commits e branches
main— sempre deployável- Features em branches
feat/..., fixes emfix/... - PRs com descrição clara do que muda e por quê
Como adicionar uma nova funcionalidade
Exemplo: novo canal de notificação (Slack)
-
Backend — em
server/src/notifications.js:async function sendSlack(text) { const url = process.env.SLACK_WEBHOOK_URL; if (!url) return null; try { const r = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ text }) }); return { ok: r.ok }; } catch (e) { return { ok: false, error: e.message }; } } -
Adicionar ao
dispatchAlarm():const tasks = [ // ...existentes ['slack', sendSlack(text)] ]; -
Adicionar a
listConfiguredChannels():if (env.SLACK_WEBHOOK_URL) channels.push('slack'); -
Documentar — adicionar
SLACK_WEBHOOK_URL=no.env.example -
Testar localmente:
curl -X POST -H "Authorization: Bearer $TOKEN" \ http://localhost:3000/api/test
Exemplo: novo campo na viagem
- Frontend — adicionar no modal de viagem (HTML)
- Adicionar no
saveTrip()— incluir no objeto data - Adicionar na renderização (
renderTrips) - Backup compatibility: viagens antigas não terão o campo, lembre de
tratar
undefinedgraciosamente
Não precisa mudar o backend — a API guarda JSON arbitrário em state.data.
Debugging
Frontend
Abrir DevTools no Chrome (F12 ou ⌥⌘I). Console mostra:
[zone]ao entrar/sair de zona[deadman]no servidor (acessível viadocker logs)- Erros de fetch sem CORS são típicos quando se acessa
file://em vez dehttp://localhost
Application tab:
Local Storage— ver todo o estadoIndexedDB > diario_bordo_db > media— ver mídias
Backend
# Logs em produção
docker logs <container>
# Em dev, vê no terminal direto
# Testar endpoint manualmente
curl -H "Authorization: Bearer abc..." http://localhost:3000/api/info
SQLite — abrir o .db direto:
sqlite3 server/data/shivao.db
> .tables
> SELECT * FROM alarm_log ORDER BY ts DESC LIMIT 10;
Releases
Atualmente não há versionamento formal. Sugestão para o time:
- Adicionar
versionempackage.json - Tags Git para releases (
v1.0.0) - Changelog (
CHANGELOG.md) com mudanças por versão - Coolify: configurar para deploy automático apenas em tags (não em todo push)
Boas práticas para o app de barco
Coisas a manter em mente ao desenvolver:
-
Conectividade incerta: o app é usado em alto-mar. Falhas de rede são normais. Tudo deve degradar graciosamente.
-
Bateria é crítica: cada feature que ativa GPS/CPU contínuo precisa ser justificada. Sempre considerar o impacto em bateria.
-
Tela ao sol: contraste alto, fontes grandes. A paleta atual já é bem legível ao sol.
-
Mãos molhadas: tap targets grandes (mínimo 44x44 px).
-
Sob estresse: alarmes, MOB, etc. devem ter UX MUITO simples — botões óbvios, pouco texto, ações irreversíveis sempre com confirmação.
-
Dados são preciosos: nunca apagar sem dupla confirmação. Backup é fácil (aba Arquivo).
-
Single-handed sailing: capitão pode estar sozinho no leme. Operação com uma mão deve ser viável onde possível.