Commit graph

6 commits

Author SHA1 Message Date
PontualTech / Karlão
85b60a800c feat(saas): multi-tenant com login/cadastro + JWT + planos free/pro/captain
BACKEND
- bcryptjs + jsonwebtoken adicionados (JS puro, sem build nativo)
- Schema users + licenses, migration adiciona user_id em todas tabelas (state, media, anchor_session, alarm_log, shares, audit_log)
- User default id=1 (karlao@outlook.com) com plano captain — preserva uso pessoal pré-multi-tenant
- Endpoints /api/auth/{signup,login,refresh,me} + /api/license
- Middleware requireAuth aceita JWT OU BOAT_TOKEN (fallback legado mapeia ao user 1)
- TODAS rotas autenticadas atualizadas pra usar req.user.id (state, media, anchor, share, alarm, audit)
- Dead-man switch agora itera todos anchor_sessions ativos (multi-user)
- 3 planos definidos em auth.js: free (Âncora), pro (R$19/mês), captain (R$39/mês)

FRONTEND
- state.auth + state.license persistidos em localStorage
- cloudFetch usa JWT preferencialmente, fallback BOAT_TOKEN; auto-refresh em 401
- Nova seção 'Conta' no painel Arquivo: tabs Entrar/Cadastrar + status de plano + Logout + botão upgrade
- Sincronizado em app/ e server/public/

Backward-compat 100% preservada: app legado com BOAT_TOKEN continua funcionando como user default.
Próximo: webhook Asaas pra ativar licenças após pagamento PIX.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 15:37:15 -03:00
PontualTech / Karlão
d1a2401048 feat(offline+sensors): Service Worker, bússola, barômetro, pré-cache de mapa
Implementa requisitos pra uso em áreas remotas:

OFFLINE REAL (Service Worker em server/public/sw.js)
- Pré-cache de shell (HTML, manifest, icon, Leaflet, fontes Google)
- Cache-first pra map tiles OSM (offline em alto-mar com tiles já visitados)
- Network-first pra Windy/Open-Meteo (com fallback ao cache)
- /api/* passa direto (não interferir em sync, heartbeat, auth)
- Skip-waiting + claim pra ativar imediatamente após install

SENSORES (sensor widget flutuante canto superior direito)
- Bússola via DeviceOrientationEvent (suporta iOS webkitCompassHeading + Android alpha)
- iOS: pede permission via gesture do usuário (botão 'Ativar bússola')
- Barômetro via Generic Sensor API (Android com sensor real, fallback gracioso)
- Tendência de pressão (subindo/caindo/estável) baseada em janela móvel
- Indicador de online/offline sempre visível

PRÉ-CACHE DE MAPA
- Botão 'Pré-cachear mapa' baixa tiles ~50km de raio (zooms 8-13, ~200 tiles)
- Comunicação page→SW via MessageChannel
- Limit 6 conexões paralelas (respeitando OSM tile policy)

DOCUMENTAÇÃO TERMÔMETRO: API web não tem termômetro de ambiente.
Solução: usar dado da Windy (já implementado) + cache offline via SW.

Sincronizado em app/ e server/public/ — single-file HTML preservado.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:55:39 -03:00
PontualTech / Karlão
f83ae389bc feat(twa): assetlinks.json pra verificar APK Android (remove barra URL) 2026-04-27 14:42:05 -03:00
PontualTech / Karlão
36ea8f006b feat(pwa): manifest.json + ícone SVG marítimo pra instalar como app
- Endpoint Express /manifest.json com name/short_name/icons/theme
- /icon.svg vetorial (veleiro estilizado em paleta marítima)
- Links manifest + apple-touch-icon nos 2 HTMLs (app/ e server/public/)

Habilita:
- Android Chrome: 'Add to Home Screen' com ícone bonito
- iOS Safari: ícone na tela inicial
- PWABuilder: pode gerar APK Android sideload-ready

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 14:35:01 -03:00
PontualTech / Karlão
78c6de538a feat(reliability): vigia reconnect (Wake Lock release + GPS retry exponencial)
Run 6 da squad shivao-melhoria — HANDOFF item 5 (Reconexão da vigia)
parcialmente resolvido sem Service Worker (decisão conservadora,
SW mal feito quebraria offline-first).

4 fixes em app/diario-bordo.html + server/public/index.html (sincronizados):

1. requestWakeLock (tracking, linha 1345) + requestAnchorWakeLock (anchor, 1831)
   - Adicionado wakeLock.addEventListener('release', ...) com auto-reacquire em 1s
   - Garante que sistema soltando o Wake Lock (background tab, low battery)
     não deixa a tela apagar permanentemente enquanto vigia/rastreio ativos

2. startGPS (tracking, linha 1347) + startAnchorGPS (anchor, 1901)
   - Retry exponencial: 1s, 2s, 4s, 8s, 16s, 30s (max)
   - PERMISSION_DENIED é fatal sem retry (com mensagem clara ao dono)
   - Outros erros (POSITION_UNAVAILABLE, TIMEOUT) → retry com backoff
   - Counter resetado a cada GPS update bem-sucedido (recuperação completa)

Combinado com visibilitychange listener existente (linha 1824) que re-acquire
Wake Lock quando tab volta foreground, cobre o cenário completo de:
- Tab em background no Android Chrome (GPS pausa, sistema solta Wake Lock)
- Tela apagada (Wake Lock soltada, GPS continua se permitido)
- Erro transitório de GPS (perda de sinal, recupera sozinho)
- App reaberto com vigia em andamento (loadAnchorState chama startAnchorGPS
  que agora tem retry built-in)

Service Worker real (push notifications + cache de tiles offline) fica
pra iteração futura com spec própria.

HANDOFF.md item 5 marcado como "parcialmente resolvido".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 13:28:09 -03:00
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