shivao-projeto/CONTRIBUTING.md
PontualTech / Karlão 5b02feae50 chore: initial commit + security hardening (4 runs squad shivao-melhoria)
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>
2026-04-27 13:24:08 -03:00

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 routes
  • db.js — wrapper SQLite com queries prepared
  • notifications.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: r para response, c para 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/await em vez de promises encadeadas
  • Erros logados com console.warn ou console.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 em fix/...
  • PRs com descrição clara do que muda e por quê

Como adicionar uma nova funcionalidade

Exemplo: novo canal de notificação (Slack)

  1. 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 };
      }
    }
    
  2. Adicionar ao dispatchAlarm():

    const tasks = [
      // ...existentes
      ['slack', sendSlack(text)]
    ];
    
  3. Adicionar a listConfiguredChannels():

    if (env.SLACK_WEBHOOK_URL) channels.push('slack');
    
  4. Documentar — adicionar SLACK_WEBHOOK_URL= no .env.example

  5. Testar localmente:

    curl -X POST -H "Authorization: Bearer $TOKEN" \
         http://localhost:3000/api/test
    

Exemplo: novo campo na viagem

  1. Frontend — adicionar no modal de viagem (HTML)
  2. Adicionar no saveTrip() — incluir no objeto data
  3. Adicionar na renderização (renderTrips)
  4. Backup compatibility: viagens antigas não terão o campo, lembre de tratar undefined graciosamente

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 via docker logs)
  • Erros de fetch sem CORS são típicos quando se acessa file:// em vez de http://localhost

Application tab:

  • Local Storage — ver todo o estado
  • IndexedDB > 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:

  1. Adicionar version em package.json
  2. Tags Git para releases (v1.0.0)
  3. Changelog (CHANGELOG.md) com mudanças por versão
  4. 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:

  1. Conectividade incerta: o app é usado em alto-mar. Falhas de rede são normais. Tudo deve degradar graciosamente.

  2. Bateria é crítica: cada feature que ativa GPS/CPU contínuo precisa ser justificada. Sempre considerar o impacto em bateria.

  3. Tela ao sol: contraste alto, fontes grandes. A paleta atual já é bem legível ao sol.

  4. Mãos molhadas: tap targets grandes (mínimo 44x44 px).

  5. Sob estresse: alarmes, MOB, etc. devem ter UX MUITO simples — botões óbvios, pouco texto, ações irreversíveis sempre com confirmação.

  6. Dados são preciosos: nunca apagar sem dupla confirmação. Backup é fácil (aba Arquivo).

  7. Single-handed sailing: capitão pode estar sozinho no leme. Operação com uma mão deve ser viável onde possível.