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>
246 lines
6.6 KiB
Markdown
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.
|