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

246 lines
6.6 KiB
Markdown

# CONTRIBUTING — Guia para devs
## Setup inicial
### Requisitos
- Node.js 20+
- npm
- (Opcional) Docker para teste do build de produção
### Rodando o backend localmente
```bash
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:
```bash
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:
```bash
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):
```bash
cp app/diario-bordo.html server/public/index.html
```
### Testando com Docker
```bash
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`:
```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()`:
```js
const tasks = [
// ...existentes
['slack', sendSlack(text)]
];
```
3. Adicionar a `listConfiguredChannels()`:
```js
if (env.SLACK_WEBHOOK_URL) channels.push('slack');
```
4. **Documentar** — adicionar `SLACK_WEBHOOK_URL=` no `.env.example`
5. **Testar** localmente:
```bash
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
```bash
# 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:
```bash
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.