7.0 KiB
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:
- O gráfico tem espaço vazio demais e exige rolar horizontalmente por muito tempo até encontrar leituras.
- 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-systemeui-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/windowEndMillisgrandes, 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:
publishLiveSamplesalva, mas histórico não recarrega após cada nova amostra.selectedPeriodusa uma janela curta ou errada.- Sessão finalizada tem samples com
sessionIdnulo. finishCurrentSessionnão associa amostras sem sessão dentro da janela.- UI exibe
historySamples, mas dados reais ficam apenas emvisibleSamples/dailySamples.
Correções esperadas:
- Confirmar que
HeartRateSampleStore.saverecebesessionIdativo. - Confirmar que
samplesForSessionfunciona 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
HeartRateLineChartdeve 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
- Janela grande com dados no fim não gera domínio vazio gigante.
- Sem dados retorna Empty.
- Um ponto retorna SinglePoint.
- Dados fora de ordem são ordenados.
- Dados filtrados preservam timestamp real.
- Downsampling mantém primeiro e último ponto.
Store/persistência
Se for viável em teste local unitário:
- Salvar sample e recuperar por período.
- Salvar sample em sessão ativa e recuperar por session id.
- 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
HomeScreenchart/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
HeartRateLineChartpara 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.