Commit graph

33 commits

Author SHA1 Message Date
PontualTech / Karlão
330d5aaa62 feat(ble): wake-up Xiaoxiang BMS — read inicial + 5A x4 v1.10.11
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Confirmado: BMS responde ao app oficial Xiaoxiang. Problema é técnica
de inicialização não implementada na nossa abordagem.

Adicionado wake-up sequence ANTES do probe de protocolos:
1. ble.read na notify char (acorda stack BLE)
2. delay 300ms
3. write 0x5A x4 (handshake hello observado em alguns Xiaoxiang)
4. delay 1500ms (BMS processa wake)
5. probe normal de protocolos

Cada step protegido por try/catch + timeout 2s — não trava loop.
Logs detalhados pra ver onde falha se acontecer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 08:21:41 -03:00
PontualTech / Karlão
24d0162397 fix(ble): write timeout 3s + log entry/exit + loop resiliente v1.10.10
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Log v1.10.9 mostrou que probe parou em '→ TX JBD-0x03' sem testar
próximos 3 protocolos (JK, Daly, JBD-wnr). Causa provável: write
trava mesmo com WNR no plugin v6.

Fix:
- bmsWriteCmd com Promise.race + timeout 3s — write nunca trava
  loop indefinidamente
- bmsTryProtocols agora loga '✔ write retornou' e '✗ sem RX em 2.5s'
  pra distinguir write OK + BMS mudo de write travado
- Try/catch interno no write — se falha, continua pro próximo
  protocolo em vez de abortar loop

Próximo log vai mostrar TODOS os 4 protocolos testados — daí saberemos
se é hardware mudo OU plugin travando.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 08:11:47 -03:00
PontualTech / Karlão
9f32428980 feat(ble): envia diag log direto pro servidor (evita crash WebView) v1.10.9
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Karlão reportou que app reinicia ao tentar copiar log (crash em
v1.10.8 também — modal grande + textarea com Unicode pode crashar
WebView Android skinned).

Solução: novo endpoint POST /api/bms/diag-log que aceita texto
do log + auth user, salva em /data/diag-logs/{userId}-{ts}.txt
no servidor. Frontend tem botão '📤 Enviar pro servidor' (verde)
que faz fetch POST. Resposta confirma recebimento.

Eu (Claude) leio o arquivo direto do servidor — sem dependência
de clipboard, share, modal HTML, ou copy manual.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 08:01:30 -03:00
PontualTech / Karlão
f3183b33d1 fix(ble): copyDiagLog usa modal + share em vez de clipboard API v1.10.8
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Bug v1.10.6/7: clicar 'Copiar log' fechava o app (crash WebView).
Causa: navigator.clipboard.writeText em alguns Android skinned
(Samsung One UI, Xiaomi MIUI) requer permissão extra que sem ela
gera SecurityException nativa não capturada.

Fix: substitui por modal full-screen com textarea readonly +
selectable + botão Compartilhar (navigator.share, mais robusto).
Removido document.execCommand (deprecado, também crashava).

Karlão pode agora: (1) selecionar texto manualmente segurando na
textarea, (2) tocar Compartilhar pra mandar via WhatsApp/email
escolhendo o app no share sheet do Android.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 07:50:45 -03:00
PontualTech / Karlão
6680f8b09b fix(ble): writeWithoutResponse forçado quando ff02 só tem wnr v1.10.7
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
DESCOBERTA crítica do log do Karlão: ff02 (write char) tem properties
[wnr,read] — SÓ writeWithoutResponse, sem write. Meu probe primeiro
tentava ble.write() (com response) que trava silenciosamente esperando
ACK que o BMS nunca envia. Por isso log para em '→ TX JBD-0x03' sem
testar próximos protocolos.

Fix:
- Probe detecta properties da writeChar e seta dev.bmsForceWnr=true
  quando char tem wnr mas não write
- Log mostra '(force-wnr)' ao lado do Write= no diagnóstico
- bmsWriteCmd respeita bmsForceWnr e usa writeWithoutResponse mesmo
  quando o protocol não pediu

Esperado v1.10.7: TX JBD-0x03 com writeWithoutResponse → BMS responde
com pacote 0xDD ... 0x77 → dashboard mostra V/A/SoC/células reais.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 07:45:28 -03:00
PontualTech / Karlão
cd4aa9c753 feat(ble): botão Copiar log + Limpar + painel sempre aberto v1.10.6
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Karlão mandou log antigo achando que era novo (não dava pra distinguir
log v1.10.4 de v1.10.5 sem ler timestamps). Adicionado botão 📋 Copiar
log que copia texto puro pro clipboard com header 'Shivao vX.Y.Z · log
diagnóstico' — fica óbvio qual versão está rodando.

Mudanças:
- <details> agora abre por padrão (open attribute)
- Botão 📋 Copiar log (navigator.clipboard + fallback textarea)
- Botão 🗑 Limpar pra zerar histórico antes de novo teste
- Painel max-height 200→300px + font-family mono
- Toast confirma cópia OK

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 07:30:56 -03:00
PontualTech / Karlão
2fca191676 fix(ble): bmsManualRead reconecta GATT antes do probe v1.10.5
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Bug v1.10.4: clicar 🔄 Re-ler gerava 'getServices erro: Bluetooth LE
not initialized' porque Android desconecta GATT em background pra
economizar bateria, mas state.btDevices ainda mostra 'conectado'.

Fix: bmsManualRead agora faz 3 passos sequenciais com diagnóstico:
1. ensureBleNativeReady() — garante plugin inicializado
2. ble.connect({deviceId, timeout:15000}) — reconecta GATT (silent
   se 'already connected')
3. bmsProbeAndAttach() — probe completo

Cada passo emite log próprio: "Plugin init OK", "GATT reconectado"
ou "GATT já conectado", "🔍 Enumerando characteristics..."

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 07:18:44 -03:00
PontualTech / Karlão
840f0b0dc5 fix(ble): remove requestMtu/requestConnectionPriority — crash em plugin v6.x v1.10.4
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Bug crítico v1.10.3: app crashava ao parear ou clicar Re-ler.
Causa: chamadas a ble.requestConnectionPriority() e ble.requestMtu()
não existem no @capacitor-community/bluetooth-le v6.1.0 (foram
adicionadas em v7+). Sem o método, o plugin lança exception nativa
não-tratada que escapa do try/catch JS e derruba o WebView Capacitor.

Fix:
- Remove requestMtu + requestConnectionPriority
- getServices() chamado UMA vez (não no loop por vendor)
- Filtra services por prefixo vendor (ff00, fff0, ffe0, 0203)
- Lista todos chars descobertos com properties no diagnóstico
- Loga "getServices retornou N services" pra confirmar que enumeração rodou

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 06:59:35 -03:00
PontualTech / Karlão
bba53e4548 feat(bms): versão visível no diagnóstico + MTU bump + connection HIGH v1.10.3
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Karlão reportou log v1.10.1 quando deveria ser v1.10.2 — usuário não
sabia se atualização chegou. Adicionado:

- "Shivao v1.10.X" mostrado no card BMS (status line)
- Primeira linha do log: "📦 Shivao v1.10.3 · Probe iniciado"
- requestConnectionPriority=HIGH antes do probe (alguns BMS exigem)
- requestMtu(247) — Xiaoxiang BMS oficiais às vezes ignoram comandos
  enviados em MTU baixo (23 default), exigem 247 pra responder

Próximo passo: usuário atualiza pra v1.10.3, primeira linha do log
confirma versão. Se ainda zero RX, partiremos pra CCCD descriptor manual.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 18:04:59 -03:00
PontualTech / Karlão
ca3dd4d7b2 feat(bms): probe automático de protocolo BMS (JBD/JK/Daly) v1.10.2
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Bug v1.10.1: BMS bat2 do Karlão expõe service ff00 mas zero RX no log
após enviar comando JBD 0x03. Significa BMS usa firmware proprietário
não-JBD.

Implementação probe automático:
- Enumera characteristics de cada vendor service (ff00, fff0, ffe0, 0203)
- Lista UUIDs + propriedades (notify/indicate/write/wnr/read) no diagnóstico
- Auto-detecta notify char (com property notify ou indicate)
- Auto-detecta write char (com property write ou writeWithoutResponse)
- Salva config em dev.bmsService/Notify/WriteChar pra reuso
- Subscribe na notify char + listener com hex dump dos chunks RX
- Tenta 4 protocolos sequencialmente (espera 2.5s entre cada):
  1. JBD-0x03 (DD A5 03 00 FF FD 77)
  2. JK-getInfo (AA 55 90 EB 96 00 ... — 20 bytes)
  3. Daly-getInfo (A5 80 90 08 00 00 ... — 13 bytes)
  4. JBD writeWithoutResponse fallback
- Detecta resposta por byte de início (0xDD=JBD, 0xAA=JK, 0xA5=Daly)
- Salva bmsProtocol no device pra usar no poll periódico
- Stubs JK/Daly handlers (parsers específicos virão se BMS responder)

Botão Re-ler agora re-roda probe completo (não só re-envia mesmo comando).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 17:24:00 -03:00
PontualTech / Karlão
578793d097 feat(bms): dashboard visual + RX log bytes + writeWithoutResponse fallback v1.10.1
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
3 problemas atacados após teste de Karlão:

1) BMS conectou mas não respondeu o comando 0x03:
   - Log mostra "← RX X bytes: hex" pra cada notification recebida
   - Listener registrado ANTES de startNotifications (fix de race condition)
   - Wait 500ms entre subscribe e primeiro write (alguns BMS precisam wake)
   - Após 5s sem resposta, tenta writeWithoutResponse automaticamente
   - Botão 🔄 Re-ler manual no card pra forçar query

2) Karlão pediu "monitor visual humano":
   - Modal full-screen " Monitor da Bateria" com:
     * Círculo SoC grande SVG (ring chart 160x160) com cor por nível
     * Status flow grande:  CARREGANDO / ↓ DESCARGA / — REPOUSO
     * Tempo restante calculado (descarga = remainCap/current)
     * Tempo até cheia (carga = (totalCap-remainCap)/current)
     * 4 cards: Tensão · Corrente · Potência · Capacidade
     * Linha info: ciclos · temperaturas · firmware version
     * Grid de células coloridas por health (vermelho <3.0V, verde >3.6V)
     * Auto-refresh 10s enquanto modal aberto
   - Botão 📊 Monitor no card BMS abre dashboard

3) Estado de erro mais claro:
   - Dashboard mostra "Aguardando dados..." se b.voltage ainda não chegou
   - Diagnóstico log destaca chunks RX em azul

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 17:06:44 -03:00
PontualTech / Karlão
8f3870412d feat(bms): parser JBD/LLT Power BMS — voltagem, corrente, SOC, células, temps v1.10.0
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Identificado pelo diagnóstico: BMS do Karlão (bat2) usa protocolo JBD
(Jiabaida) — service ff00, notify ff01, write ff02. Padrão de mercado
para BMS chineses (Overkill Solar, Hankzor, JBD oficial, LLT Power,
Xiaoxiang) — cobre ~80% dos BMS BLE de lítio.

Implementação:
- Auto-detect: ao parear, se device tem service ff00 → ativa parser JBD
- bmsAttachJBD() subscribe na char ff01 (notify) + envia comando 0x03
- Comando: DD A5 03 00 FF FD 77 (Read Basic Info)
- Reassembly de chunks BLE (max 20 bytes/chunk) até receber 0x77 (end)
- Parser decodifica: voltage (uint16/100), current (int16/100, signed),
  remaining/total capacity (Ah), cycle count, protection bitfield,
  SoC (%), FET status, cell count, temperatures (kelvin*10 → °C)
- Re-poll a cada 30s pra atualizar dados em tempo real
- Auto-sync lastBattery com BMS soc pra card resumido

UI expandida:
- Card BMS com 3 stats grandes: TENSÃO (V) · CORRENTE (A) · POTÊNCIA (W)
- Cor dinâmica: verde se carregando (current>0), amarelo se descarregando
- Linha extra: status flow + capacidade (remain/total Ah) + ciclos + temps
- Block de células individuais (4S/8S/16S detectado automaticamente)
- Border-left do card colorido conforme estado de fluxo

Protocolo de referência: gitlab.com/bms-tools/bms-tools

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:56:48 -03:00
PontualTech / Karlão
5dd3362469 feat(ble): diagnóstico verboso pra debugar pareamento BLE v1.9.2
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Karlão reportou: "localiza mas não pareia" (picker abre, seleciona
device, mas conexão falha silenciosa). Sem ver onde trava, impossível fix.

Adicionado:
- setBleDiag() exibe cada step com timestamp + cor (info/ok/warn/err)
- Painel <details> expansível "📋 Diagnóstico" no card BLE
- Logs em cada operação: backend, init, picker, connect, getServices,
  battery read, notifications, device info
- Timeout do connect aumentado: 15s → 30s (BMS podem demorar)
- getServices() lista UUIDs descobertos no device — descobre se BMS
  expõe Battery Service padrão ou só protocolo proprietário
- Mensagens explícitas de erro em cada catch (e.message ou errorMessage)

Próximo passo: Karlão testa, abre painel diagnóstico, me passa screenshot
ou copia o log. Daí descubro exatamente onde trava (timeout, sem service,
permissão negada, etc).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:39:41 -03:00
PontualTech / Karlão
52ee668879 fix(ble): plugin nativo @capacitor-community/bluetooth-le pra APK Android v1.9.1
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Bug v1.9.0: APK Android mostrava "Web Bluetooth não suportado" porque
Android System WebView desabilita Web Bluetooth API por padrão (segurança).

Fix: instala plugin @capacitor-community/bluetooth-le@^6.1.0 (compatível
com Capacitor 6) que expõe API nativa Android/iOS. JS detecta backend:
- Capacitor (APK): usa window.Capacitor.Plugins.BluetoothLe
- Browser web: usa navigator.bluetooth (Chrome PC continua funcionando)

Mudanças:
- mobile/package.json: nova dep @capacitor-community/bluetooth-le ^6.1.0
- AndroidManifest.xml: BLUETOOTH_SCAN (neverForLocation), BLUETOOTH_CONNECT,
  BLUETOOTH/BLUETOOTH_ADMIN (Android ≤30), uses-feature bluetooth_le
- bleBackend() detecta runtime, ensureBleNativeReady() inicializa plugin
- pairBluetoothDevice + connectAndRead + reconnect + remove abstraem backend
- UUIDs em formato 128-bit (compatível com ambos)
- parseDataView helper: plugin envia value como base64, web envia DataView

iOS: plugin suporta nativamente — quando build iOS for feito, funciona.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:24:50 -03:00
PontualTech / Karlão
a6a35c6d6f feat(ble): Web Bluetooth (Battery Service genérico) + slot Raymarine NMEA gateway v1.9.0
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Bluetooth & Acessórios (aba Mais):
- Pareamento Web Bluetooth API (acceptAllDevices)
- Lê Battery Service padrão (UUID 0x180F) + characteristic 0x2A19
- Subscribe pra notificações em tempo real (battery_level changes)
- Lê Device Info Service (manufacturer + model)
- Lista persistente de devices pareados (state.btDevices)
- Reconexão via navigator.bluetooth.getDevices() (Chrome ≥85)
- Status visual: 🪫/🔋 + cor por nível (verde >50, amarelo 20-50, vermelho <20)
- Cleanup ao remover device (disconnect GATT + remove do state)

Raymarine Gateway (slot, parser em v1.10):
- Card config com IP + porta TCP/UDP do gateway NMEA 2000→WiFi
- Sugere Yacht Devices YDWG-02 / Actisense W2K-1
- Salva em state.nmeaGateway pra parser futuro
- Sem gateway físico ainda, só persiste config

Limitações documentadas no UI:
- iOS Safari não suporta Web Bluetooth (precisa @capacitor/community/bluetooth-le em v1.10)
- Reconexão automática varia por device (Web Bluetooth não persiste connections)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 16:07:37 -03:00
PontualTech / Karlão
0921d98ef3 feat(charts): cartas náuticas OpenSeaMap (grátis) + slot Navionics + export OpenCPN v1.8.0
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Cartas náuticas nos mapas (rastreio, fundeio, zonas, viagens):
- OpenSeaMap como overlay padrão grátis (sondas, faróis, bóias, marcas)
- Slot Navionics ativável via chave (após aprovação Garmin)
  - Dynamic load do JNC.Leaflet.NavionicsOverlay quando chave preenchida
- Layer switcher no canto direito do mapa: OSM Padrão / Satélite Esri,
  overlay OpenSeaMap / Navionics
- Helper addMapLayers() centraliza configuração — substituiu 5 usages
  manuais de L.tileLayer espalhados (tracking, trip view, anchor,
  anchor history, zone editor)

Settings (Mais → Cartas Náuticas):
- Dropdown provedor: OpenSeaMap/Navionics/só OSM
- Campo chave Navionics (password) com link pro form Garmin
- Status visual do provedor ativo

Integração OpenCPN (Mais → Exportar para OpenCPN):
- Botão gera GPX consolidado de todo o diário:
  - Tracks: cada viagem com pontos GPS sequenciais
  - Waypoints: cada fundeio histórico com símbolo Anchor
  - Routes: cada zona (forbidden/attention) como polígono fechado
  - Aproximação círculo→polígono 16 pontos pra zonas circulares
- Compatível com OpenCPN, Garmin, Raymarine, B&G, qualquer plotter
  GPX-compliant
- Download direto via Blob URL, sem servidor

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 14:34:24 -03:00
PontualTech / Karlão
f8e92f3c58 fix(auth): cloudConfigured() reconhece login Google/email (sem token) v1.7.1
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Bug crítico: após login Google ou email, o app pedia pra logar
DE NOVO toda vez que abria/fechava. E sync nunca iniciava.

Causa: cloudConfigured() exigia state.cloud.token, mas no login
Google/email a auth fica em state.auth.accessToken (JWT), não em
state.cloud.token (que é o BOAT_TOKEN avançado).

Resultado: cloudConfigured() retornava false → welcome screen
sempre aparecia, rtConnect() nunca rodava, sync zero.

Fix:
- cloudConfigured() agora retorna true se tem state.auth.accessToken
  OU state.cloud.token (qualquer um dos dois)
- maybeShowWelcome() reescrito pra checar autenticação real
- Botão "Usar sem login (modo offline)" mais visível na welcome
  screen pra dar saída clara

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 09:13:37 -03:00
PontualTech / Karlão
c7994167be feat(ui): redesign Marine Pro Dark — bottom nav + dark navy + Inter v1.7.0
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Reskin completo baseado em pesquisa de Navionics/Windy/PredictWind/Garmin
ActiveCaptain. Mata o feel "magazine editorial vintage" e adota padrões
mobile-app modernos.

Mudanças visuais (CSS overlay v3 sem alterar HTML/JS de business):
- Paleta dark navy (#0d2538) + cyan accent (#06b6d4) + reservado red pra alarme
- Inter (sans-serif) substitui Fraunces (italic editorial)
- Tabular nums em todas as métricas (lat/lon/depth/speed)
- Cards modernos: border-radius 14px + shadows sutis + bg dark
- Header 50% mais compacto (sem compass mark, avatar maior + accent cyan)
- FAB reposicionado acima da bottom nav, gradient cyan
- Modais: bottom sheet no mobile com top corners rounded
- Form fields dark com focus glow cyan
- Buttons com border-radius modernos, primary = cyan filled

Novos componentes:
- Bottom navigation: 5 tabs com line icons (Início/Travessias/Pendências/
  Zonas/Mais), backdrop-filter blur, badge vermelho em pendências overdue
- Safety status bar (sticky abaixo do header): GPS dot + Anchor watch +
  Bateria. Pulsa amarelo se warn, vermelho se danger
- switchPanel() unifica top tabs (legacy) + bottom nav

Service worker bumped pra invalidar cache antigo automaticamente.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 09:00:29 -03:00
PontualTech / Karlão
b57ba0da37 fix(auth): persiste session_id pra OAuth sobreviver app-kill v1.6.2
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Bug: ao clicar "Entrar com Google" no APK Capacitor, app abria Chrome,
user logava OK ("Logado, volte pro app"), mas ao voltar pro app o login
não completava — ficava em loop pedindo pra logar de novo.

Causa: Android matava o WebView do app quando ele ia pra background
(usuario indo pro Chrome). Ao reabrir o app, _googleAuthPolling interval
estava perdido e o session_id (em variável JS) também.

Fix: persiste session_id em localStorage com timestamp. Adiciona
resumePollingIfPending() chamado em:
- Bootstrap (sempre, 500ms após init)
- visibilitychange visible (volta do background)

Também faz uma chamada imediata de poll antes de iniciar interval —
caso os tokens já estejam prontos quando o app reabre.

TTL de 10min no localStorage (mesmo TTL do Map no servidor) — após
isso considera expirado e limpa.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:30:32 -03:00
PontualTech / Karlão
24f6df3da7 fix(auth): login Google funciona em apps Capacitor (redirect+polling) v1.6.1
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Problema: Google Sign-In popup (GSI) não funciona em WebView nativo do
Capacitor. FedCM bloqueia, popup não abre, ou retorna erro silenciosamente.

Solução: detectar Capacitor (window.Capacitor) ou WebView (UA com 'wv') e
usar OAuth redirect tradicional + polling em vez do popup GSI.

Backend (server/src/index.js):
- GET /api/auth/google/start — gera URL OAuth com state contendo
  session_id + flow:'login'. App chama isso e abre URL no browser externo.
- /api/google/callback adaptado — quando state.flow=='login', cria/loga
  user por email do Google, gera JWT, armazena em pendingGoogleSessions
  (Map em memória, TTL 10min) por session_id, mostra HTML "logado, volte
  pro app".
- GET /api/auth/google/poll?session=xxx — app faz polling 2s. Retorna
  204 se ainda esperando, 200 com tokens (one-shot, deleta após).

Frontend (app/diario-bordo.html):
- Detecta Capacitor/WebView, força fluxo redirect+polling
- Browser web: tenta GSI popup primeiro, fallback redirect se prompt
  for bloqueado (FedCM/popup blocker)
- window.open abre Custom Tabs no Android (ou nova aba no PC)
- Timeout de 4min (120 tries × 2s) pro polling

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:20:39 -03:00
PontualTech / Karlão
b48afaa84f feat(welcome): tela de boas-vindas com login Google/Email + URL hardcoded v1.6.0
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
UX simplificada drasticamente — usuário não precisa mais saber URL/token:
- Tela de boas-vindas full-screen quando não logado
- 3 botões grandes: Google, Email, Servidor próprio (avançado)
- URL hardcoded https://shivao.pontualtech.work como padrão
- Auto-conecta WebSocket + Google Calendar status após login
- Pull inicial automático pra puxar dados existentes da conta

Backend (server/src/index.js):
- Endpoint POST /api/auth/google: recebe credential (Google ID token),
  valida via tokeninfo do Google, confere aud == GOOGLE_CLIENT_ID,
  cria user automático com email do Google se não existe,
  retorna JWT access+refresh tokens
- Reusa GOOGLE_CLIENT_ID/SECRET já configurados no Coolify

Frontend (app/diario-bordo.html):
- Modal welcome com Google Sign-In via @google/gsi/client (script async)
- Tabs Login/Signup pro fluxo email
- Form avançado pra power users self-hosters
- Skip pra modo offline
- Once dismissed, fica oculto (localStorage flag)

Service Worker bumped pra v1.6.0 (invalida cache antigo).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:00:54 -03:00
PontualTech / Karlão
21b91b3522 feat(sync): WebSocket realtime + auto-push/pull entre PC e celular v1.5.0
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Backend (server/src/realtime.js):
- WebSocket server em /ws via lib `ws`
- Auth por JWT ou BOAT_TOKEN (mesmo middleware do REST)
- Broadcast de notificações state:changed por user (skip device origem)
- Heartbeat ping/pong + cleanup de conexões mortas
- Presença: avisa todos os devices do user quantos estão online
- POST /api/data agora dispara broadcast pra outros devices em tempo real

Frontend (app/diario-bordo.html):
- Cliente WS com reconnect exponencial (1s→2s→5s→15s→30s→60s)
- deviceId persistente em localStorage (gerado no primeiro boot)
- Heartbeat 25s pra manter NAT/proxy abertos
- Auto-push debounced 2.5s no saveState (acumula edições rápidas)
- Auto-pull debounced 300ms no recebimento de state:changed
- Reconnect ao voltar pro foreground + ao recuperar conexão
- Indicador visual no header: 🟢 online · 🟡 syncing · 🔴 offline ·  disabled · ⚠️ erro

Echo prevention em 3 camadas:
1) Server skip por originDeviceId (header X-Device-Id)
2) Cliente ignora notif do próprio device
3) Guard temporal: pull rejeita se updated_at < lastPushAt

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 06:51:35 -03:00
PontualTech / Karlão
5833efcc48 feat(fleet): foto da embarcação + horímetro + cadastro + matrícula v1.4.1
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Novos campos por embarcação:
- Foto (capture câmera ou galeria, resize automático max 1280px JPEG q=0.85)
- Horímetro inicial do motor
- Data de cadastro (defaulta hoje em novas)
- Matrícula / TIE (Capitania)
- Notas livres

UI:
- Preview circular no editor com botões câmera/galeria/remover
- Avatar circular no header (foto se houver, ícone do tipo senão)
- Avatar 44x44 na lista da frota
- Foto guardada no IndexedDB (mesma store das mídias de viagem/manutenção)
- Lifecycle pareado: remover barco apaga foto, trocar foto apaga antiga
- /apk redirect aponta pra v1.4.1

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 06:37:10 -03:00
PontualTech / Karlão
21af0f00b7 build: bump v1.4.0 + /apk redirect aponta pra release nova
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 06:25:31 -03:00
PontualTech / Karlão
7ccaa18bfa feat(fleet): sistema multi-embarcação + calculadora de fundeio v1.4.0
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
— Frota: gerencia múltiplas embarcações (veleiro/motor/cata/RIB/outro)
— Selector de barco ativo no header, modal de gerência completo
— Campos por barco: nome, tipo, modelo, comprimento, boca, calado, amarra, ano
— Toggle global de unidades (metros/pés) com conversão em todos displays
— Calculadora de fundeio: scope ratio, raio de giro, raio sugerido p/ alarme
— Dicas adaptativas por vento (auto-fetch Windy/OpenMeteo) + tipo de embarcação
— Migration automática state.boat → state.boats[] (compat retroativa)
— Storage interno sempre em metros (ISO), conversão só no boundary

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 06:21:29 -03:00
PontualTech / Karlão
c700a1a600 docs(ci): SETUP-RUNNER.md com token pré-gerado + instruções 5min
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
2026-04-28 05:26:57 -03:00
PontualTech / Karlão
539fd3e157 docs(store): screenshots v1.3.0 com novo visual premium (home + arquivo)
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
2026-04-28 05:03:05 -03:00
PontualTech / Karlão
3a4d3a5e07 build(mobile): bump versionCode 3 + versionName 1.3.0 (UI premium refresh)
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
2026-04-27 21:59:48 -03:00
PontualTech / Karlão
af85d9d118 feat(store): screenshot 5 (termos de uso) capturado
Some checks are pending
Build Android (APK + AAB) / build-android (push) Waiting to run
2026-04-27 18:58:51 -03:00
PontualTech / Karlão
43b6cc0d5d feat(store): screenshot 4 (política) capturado 2026-04-27 18:17:06 -03:00
PontualTech / Karlão
ad0e65b735 feat(legal+store): política de privacidade LGPD/GDPR + Play Store assets
- GET /politica — HTML com todas as 12 seções LGPD/GDPR + DPO
- mobile/play-store-listing.md: nome, descrições curta+completa PT-BR (4000 chars), categoria, tags, justificativas de permissions
- mobile/play-store-assets/icon-512.png — gerado via Playwright (renderiza icon.svg em 512x512)
- mobile/play-store-assets/feature-graphic.png — banner 1024x500 com logo + slogan + features
- mobile/play-store-assets/screenshots/ — telas reais do app (home, arquivo, upgrade modal)
2026-04-27 18:14:49 -03:00
PontualTech / Karlão
4202547d8e feat(mobile): Capacitor Android pronto — APK + AAB v1.2.0 buildados
PIPELINE COMPLETO QUE RODOU:
1. JDK 17 instalado em ~/jdk17 (portátil, sem admin)
2. Android SDK cmdline-tools + platform-34 + build-tools-34 + platform-tools instalados em ~/android-sdk
3. JAVA_HOME e ANDROID_HOME setados no PATH user
4. npm install + npx cap add android (estrutura Android gerada)
5. AndroidManifest.xml com 10 permissions (location background, vibrate, wake_lock, foreground service, post_notifications)
6. Keystore PERMANENTE shivao-release.keystore gerado via keytool (validade 10000d, RSA 2048)
7. build.gradle: signingConfigs.release + applicationId br.com.pontualtech.shivao + versionCode 2 + versionName 1.2.0
8. local.properties: sdk.dir=C:/Users/pontu/android-sdk (forward slashes — Java properties NÃO aceitam \)
9. ./gradlew bundleRelease assembleRelease — primeira build em 1m39s
10. APK 3.4MB + AAB 3.1MB — ambos signed com keystore permanente

ARTEFATOS:
- C:/Users/pontu/Downloads/Shivao-v1.2.0-capacitor.apk (3.4MB)
- C:/Users/pontu/Downloads/Shivao-v1.2.0-capacitor.aab (3.1MB) — pronto pra Play Store
- mobile/android/app/shivao-release.keystore (NÃO commitado, .gitignore protege)
- C:/Users/pontu/Downloads/Shivao-keystore-backup/shivao-release-CAPACITOR.keystore (BACKUP)

Release Forgejo v1.2.0 publicada com APK + AAB anexados.

Próximo: criar conta Google Play ($25 1×) e submeter o AAB.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 17:34:19 -03:00
PontualTech / Karlão
7a523b8873 feat(mobile): scaffold Capacitor pra Android Play Store + adapter nativo
ESTRUTURA NOVA: mobile/ + scripts/sync-html.mjs

- mobile/package.json: Capacitor 6 + plugins (geolocation, local-notifications, network, preferences, status-bar)
- mobile/capacitor.config.json: appId br.com.pontualtech.shivao, allowNavigation pra OSM/Windy/CDNs
- mobile/.gitignore: protege keystore (NUNCA commitar chaves privadas)
- mobile/README.md: setup completo (JDK + Android Studio + keystore + build APK/AAB + Play Store submission + iOS futuro + troubleshooting)
- scripts/sync-html.mjs: copia app/diario-bordo.html → server/public + mobile/www (1 fonte da verdade)

ADAPTER NATIVO no HTML (sincronizado app/ + server/public/):
- isNative() / nativePlatform() detecta Capacitor
- nativeWatchPosition() usa Capacitor.Geolocation (background-capable) com fallback navigator.geolocation
- nativeNotify() usa Capacitor.LocalNotifications com fallback toast
- initServiceWorker() pula registro no Capacitor (WebView nativo já tem cache próprio)

NÃO INCLUI (ainda):
- Build local: precisa JDK 17 + Android Studio (~3GB) — instruções no README
- Keystore: gerar 1 vez via keytool (script no README)
- AAB pra Play Store: comandos no README
- Conta Google Play Developer: $25 1× pelo dono

Próximo passo manual: instalar JDK + Android Studio, rodar 'npm install && npx cap add android'.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 16:02:34 -03:00