Files
HealthTracking/docs/superpowers/plans/2026-06-09-fightrate-data-first-charts-history-redesign.md
T

208 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# FightRate — Plano Data-First para histórico, gráficos e UI profissional
## Situação crítica
O feedback atual mostra dois bugs de produto, não apenas problema visual:
1. O gráfico tem espaço vazio demais e exige rolar horizontalmente por muito tempo até encontrar leituras.
2. O histórico não está confiável: dados parecem não salvar ou não ficam acessíveis depois.
Conclusão: dados e persistência devem voltar a ser prioridade absoluta antes de polimento visual.
## Objetivo
Transformar o FightRate em um app data-first:
- Cada batimento recebido deve ser persistido localmente.
- Cada treino deve ter uma janela temporal confiável.
- Histórico deve mostrar dados reais recuperáveis.
- Gráficos devem usar domínio baseado apenas nas amostras reais disponíveis.
- Não pode existir scroll infinito/área vazia até achar leitura.
- Interface deve priorizar dados e navegação histórica, seguindo o design system Combat Lab.
## Skills aplicadas
- `fightrate-quality-loop`: spec → auditoria → implementação em fatias → build.
- `systematic-debugging`: encontrar causa raiz antes de corrigir.
- `test-driven-development`: criar testes de regressão para domínio de gráfico/histórico.
- `design-system` e `ui-ux-pro-max`: estado vazio útil, chart/data UX, consistência visual.
## Hipóteses a investigar
### H1 — Domínio X do Vico está incluindo janela cheia, não amostras reais
Sintoma: usuário rola para a direita “para sempre” até encontrar leituras.
Possível causa:
- O gráfico usa `windowStartMillis`/`windowEndMillis` grandes, mas as amostras estão concentradas em pequeno trecho.
- O X é calculado relativo à janela selecionada, então se a leitura está no fim da janela, sobra um enorme vazio à esquerda/direita.
- O scroll/zoom inicial pode estar mostrando início/fim errado.
Correção esperada:
- Domínio padrão do gráfico deve ser `min(sample.timestamp)` → `max(sample.timestamp)`.
- A janela selecionada filtra dados, mas não força o domínio visual a incluir todo o período vazio.
- Exibir texto com a janela consultada e o intervalo real encontrado.
### H2 — Histórico busca janela errada ou estado não atualiza após persistência
Sintoma: dados históricos não aparecem/salvam.
Possíveis causas:
- `publishLiveSample` salva, mas histórico não recarrega após cada nova amostra.
- `selectedPeriod` usa uma janela curta ou errada.
- Sessão finalizada tem samples com `sessionId` nulo.
- `finishCurrentSession` não associa amostras sem sessão dentro da janela.
- UI exibe `historySamples`, mas dados reais ficam apenas em `visibleSamples`/`dailySamples`.
Correções esperadas:
- Confirmar que `HeartRateSampleStore.save` recebe `sessionId` ativo.
- Confirmar que `samplesForSession` funciona depois do finish.
- Confirmar que `samplesBetween(start, end)` recupera dados persistidos.
- Atualizar estado de histórico depois de salvar amostra e depois de finalizar treino.
### H3 — UI não oferece navegação histórica suficiente
Sintoma: “os dados devem poder ser vistos de qualquer maneira”.
Correção esperada:
- Histórico com modos claros:
- Últimos 10 min
- Última hora
- Hoje
- Sessão atual/finalizada
- Se janela consultada não tem dados, mostrar “nenhum dado nessa janela” e sugerir janela que tem dados.
- Se existe sessão finalizada, exibir relatório e gráfico daquela sessão.
## Arquitetura desejada
### Domínio puro novo/revisado
Criar `ChartDataWindow.kt` se necessário.
Responsabilidades:
- Receber samples + janela consultada.
- Retornar:
- `visibleSamples`: somente amostras reais e úteis.
- `dataStartMillis` / `dataEndMillis`: domínio real do gráfico.
- `queryStartMillis` / `queryEndMillis`: janela consultada.
- `status`: Empty, SinglePoint, Ready.
- resumo: duração real, média, min, max, densidade.
- Não depender de Compose/Vico/Android.
### Persistência
Reutilizar `HeartRateSampleStore`.
Necessário auditar/corrigir:
- insert de samples;
- active session id;
- associação de sample com session id;
- queries por sessão;
- queries por período;
- refresh após write.
Não fazer migração destrutiva.
### ViewModel
- Não mover BLE para ViewModel.
- Garantir que o estado de histórico seja atualizado após persistência.
- Expor chart windows já preparados para UI.
- Evitar que UI calcule regras complexas.
### UI / Gráfico
- `HeartRateLineChart` deve receber domínio real de dados.
- X deve ser relativo a `dataStartMillis`, não ao começo da janela vazia.
- Se `samples.size < 2`, não chamar Vico.
- Mostrar estado vazio editorial.
- Mostrar uma linha de contexto:
- “Consultado: Hoje”
- “Dados encontrados: 14:03–14:17”
- Zoom/scroll habilitado, mas sem espaço fantasma.
- Não usar Canvas custom chart.
## Testes obrigatórios
### `ChartDataWindowTest`
1. Janela grande com dados no fim não gera domínio vazio gigante.
2. Sem dados retorna Empty.
3. Um ponto retorna SinglePoint.
4. Dados fora de ordem são ordenados.
5. Dados filtrados preservam timestamp real.
6. Downsampling mantém primeiro e último ponto.
### Store/persistência
Se for viável em teste local unitário:
1. Salvar sample e recuperar por período.
2. Salvar sample em sessão ativa e recuperar por session id.
3. Finalizar sessão e recuperar samples da sessão.
Se não for viável sem Robolectric/instrumented test, adicionar diagnóstico via código e validar pelo fluxo ViewModel/build.
## Implementação em fatias
### Fase 1 — Auditoria e causa raiz
- Ler `HeartRateSampleStore`.
- Ler `LiveHeartRateViewModel`.
- Ler `LiveHeartRateUiState`.
- Ler `HomeScreen` chart/history.
- Localizar onde sample é salvo.
- Localizar onde `historySamples` é atualizado.
- Localizar como Vico define X/domain.
### Fase 2 — Domínio de janela de gráfico
- Criar `ChartDataWindow.kt`.
- Criar `ChartDataWindowTest.kt`.
- Garantir domínio real `dataStartMillis`→`dataEndMillis`.
- Garantir estado Empty/SinglePoint/Ready.
### Fase 3 — Persistência e refresh
- Corrigir sample/session association se necessário.
- Corrigir reload de histórico depois de salvar/finalizar.
- Adicionar método de query se faltar.
### Fase 4 — Gráfico profissional
- Atualizar `HeartRateLineChart` para usar domínio real.
- Remover scroll fantasma.
- Adicionar zoom/scroll Vico com domínio real.
- Remover render de gráfico vazio.
- Mostrar resumo consultado vs encontrado.
### Fase 5 — Interface data-first
- Histórico como centro de dados, não card secundário.
- Sessões e dados recentes com hierarquia clara.
- Evitar dezenas de cards iguais.
- Estados vazios úteis e específicos.
### Fase 6 — Validação final
- `./gradlew :app:testDebugUnitTest :app:assembleDebug`
- Atualizar Obsidian roadmap.
- Enviar APK Telegram.
## Critérios de sucesso
- Usuário abre Histórico e vê dados reais sem procurar em espaço vazio.
- O gráfico começa/termina no intervalo real dos dados encontrados.
- Sem dados: nenhum gráfico é desenhado.
- Dados salvos são recuperáveis por período e por sessão.
- Testes de domínio passam.
- Build completo passa.
- APK enviado.