# Spec: FightRate P0 — Perfil Avançado e Insights do Lutador ## Objective Criar a primeira versão do Perfil Avançado do Lutador para coletar dados pessoais, cardiovasculares, subjetivos e de recuperação suficientes para gerar insights úteis de treino sem deixar o app inchado. O objetivo não é diagnóstico médico. O objetivo é apoio esportivo: entender carga, recuperação, hidratação, intensidade e evolução do atleta usando os batimentos reais do sensor BLE somados a dados simples informados pelo usuário. Usuário principal: lutador ou praticante de treino de combate que usa o FightRate para acompanhar batimentos durante treinos, rounds e sessões. ## Scope P0 Implementar somente o núcleo inicial: 1. Perfil do Lutador. 2. Check-in pré-treino. 3. Registro pós-treino. 4. Insights básicos do treino e recuperação. Não implementar neste P0: - exames médicos avançados; - integração com wearable externo além do sensor BLE atual; - Health Connect; - prescrição médica; - VO2max avançado; - IA generativa para recomendação clínica; - dashboard muito complexo. ## Assumptions 1. O app continua Android nativo Kotlin + Jetpack Compose. 2. Textos visíveis continuam em PT-BR. 3. Identificadores de código continuam em inglês. 4. SQLite local-first continua como fonte de verdade. 5. O sensor BLE continua sendo fonte dos batimentos em tempo real. 6. Cálculos de saúde serão apresentados como estimativas esportivas, não diagnósticos. 7. O P0 deve priorizar campos que geram cálculos imediatos. ## Tech Stack - Kotlin - Jetpack Compose Material3 - SQLite via `SQLiteOpenHelper` existente em `HeartRateSampleStore` - Gradle Kotlin DSL - JUnit 4 para testes unitários - Vico para gráficos existentes - Lucide para ícones existentes ## Commands Build completo: ```bash ./gradlew :app:testDebugUnitTest :app:assembleDebug ``` Teste unitário focado: ```bash ./gradlew :app:testDebugUnitTest --tests "*AthleteInsights*" ``` Compilação rápida: ```bash ./gradlew :app:compileDebugKotlin ``` Instalação debug: ```bash ./gradlew :app:installDebug ``` ## Existing Code to Reuse Reaproveitar antes de criar novo: - `AthleteProfile.kt` - `HeartRateZones.kt` - `WorkoutSession.kt` - `HeartRateStats.kt` - `HeartRateSampleStore.kt` - `LiveHeartRateViewModel.kt` - `LiveHeartRateUiState.kt` - `HomeScreen.kt` - `FightCard` - `MetricTile` - `LiveMetricPill` - cards de Perfil existentes - SQLite `fightrate.db` ## Data Model — P0 Fields ### 1. Perfil básico Campos: - `age` - `biologicalSex` - `heightCm` - `weightKg` - `fightSport` - `weightClassKg` - `trainingGoal` Uso: - personalizar zonas; - calcular IMC; - acompanhar categoria de peso; - contextualizar insights. ### 2. Perfil cardiovascular Campos: - `restingHeartRate` - `measuredMaxHeartRate` Uso: - limite cardíaco personalizado; - zonas por percentual; - reserva cardíaca; - alertas de esforço. ### 3. Check-in pré-treino Campos por sessão: - `preWorkoutEnergy` escala 1–5 - `preWorkoutFatigue` escala 1–5 - `muscleSoreness` escala 1–5 - `sleepHours` - `sleepQuality` escala 1–5 - `preWorkoutWeightKg` - `waterIntakeMl` - `symptomsNote` Uso: - prontidão; - risco de fadiga; - contexto para batimentos altos; - hidratação estimada. ### 4. Pós-treino Campos por sessão: - `postWorkoutRpe` escala 1–10 - `postWorkoutFatigue` escala 1–5 - `postWorkoutSoreness` escala 1–5 - `postWorkoutWeightKg` - `postWorkoutNote` Uso: - carga subjetiva; - perda hídrica; - recuperação; - comparação entre percepção e batimentos. ## Calculations — P0 ### 1. IMC Entrada: - peso - altura Resultado: - `bmi` - faixa textual simples ### 2. Reserva cardíaca Entrada: - limite cardíaco real ou estimado - FC repouso Resultado: - `heartRateReserve` ### 3. Zonas por Karvonen Entrada: - limite cardíaco - FC repouso Resultado: - zonas mais personalizadas para o atleta. ### 4. Score de treino Entrada: - duração da sessão - BPM médio - BPM pico - tempo em zonas - RPE pós-treino Resultado: - score 0–100 - rótulo: leve, moderado, intenso, extremo ### 5. Carga subjetiva Entrada: - RPE pós-treino - duração em minutos Resultado: - `sessionLoad = RPE × durationMinutes` ### 6. Score de recuperação Entrada: - sono - qualidade do sono - energia antes - fadiga antes - dor muscular - FC repouso opcional Resultado: - score 0–100 - rótulo: baixa, ok, boa, excelente ### 7. Hidratação estimada Entrada: - peso antes - peso depois - água ingerida Resultado: - perda de peso no treino - perda hídrica estimada - alerta se perda relativa for alta ### 8. Tempo em zona de luta Entrada: - samples de BPM da sessão - zonas cardíacas Resultado: - tempo em zona alta/intensa - percentual do treino em zona de luta ### 9. Alertas de segurança esportiva Entrada: - sintomas - fadiga alta - sono ruim - dor alta - esforço cardíaco alto Resultado: - mensagens de atenção no app. Exemplos: - “Sono baixo + fadiga alta: considere treino técnico ou leve.” - “Perda de peso alta no treino: reponha líquidos.” - “Esforço muito alto para uma recuperação baixa.” ## UI/UX ### Tela Perfil Adicionar seções recolhíveis ou cards: 1. Básico 2. Cardiovascular 3. Luta Evitar formulário gigante em uma tela só. ### Tela Check-in Fluxo simples antes de iniciar sessão: - energia - fadiga - dor - sono - peso - água - sintomas Pode ser card ou bottom sheet antes de iniciar treino. ### Tela Pós-treino Após encerrar sessão: - RPE - fadiga - dor - peso pós - observação ### Tela Insights do Lutador Primeira versão com cards: - Score do treino - Recuperação - Hidratação - Tempo em zona de luta - Carga subjetiva - Alertas ## Project Structure Novos arquivos prováveis: ```text app/src/main/java/com/healthtracking/fightrate/domain/AthleteInsights.kt app/src/main/java/com/healthtracking/fightrate/domain/ReadinessScore.kt app/src/main/java/com/healthtracking/fightrate/domain/HydrationEstimate.kt app/src/test/java/com/healthtracking/fightrate/domain/AthleteInsightsTest.kt ``` Arquivos existentes a alterar: ```text AthleteProfile.kt WorkoutSession.kt HeartRateSampleStore.kt LiveHeartRateUiState.kt LiveHeartRateViewModel.kt HomeScreen.kt ``` A criação de novos arquivos deve ser mínima e justificada por responsabilidade clara. ## Code Style Exemplo esperado: ```kotlin data class ReadinessInput( val sleepHours: Double?, val sleepQuality: Int?, val energy: Int?, val fatigue: Int?, val soreness: Int?, ) object ReadinessScoreCalculator { fun calculate(input: ReadinessInput): ReadinessScore { val score = 100 .minus(input.fatigue.orDefaultPenalty(multiplier = 8)) .minus(input.soreness.orDefaultPenalty(multiplier = 6)) .plus(input.energy.orDefaultBonus(multiplier = 5)) .coerceIn(0, 100) return ReadinessScore(value = score) } } ``` Convenções: - código em inglês; - UI em PT-BR; - cálculo puro no domínio; - Compose apenas renderiza estado; - evitar mágica sem teste. ## Testing Strategy Testar com JUnit: - IMC - reserva cardíaca - Karvonen - score de recuperação - carga subjetiva - hidratação estimada - tempo em zona de luta - alertas esportivos Comandos: ```bash ./gradlew :app:testDebugUnitTest --tests "*AthleteInsights*" ./gradlew :app:testDebugUnitTest :app:assembleDebug ``` ## Boundaries ### Always - Criar cálculo no domínio antes da UI. - Usar testes para cálculo. - Manter campos opcionais quando possível. - Explicar que cálculos são estimativas esportivas. - Reaproveitar `AthleteProfile`, `WorkoutSession`, `HeartRateSampleStore`. - Salvar dados localmente. ### Ask first - Adicionar dependência nova. - Adicionar Health Connect. - Criar tela nova separada se puder ser card inicialmente. - Fazer alteração destrutiva no banco. - Criar cálculo médico sensível. - Coletar dados muito pessoais sem justificativa. ### Never - Apresentar diagnóstico médico. - Bloquear treino como decisão médica. - Criar formulário gigante difícil de usar. - Adicionar campos que não alimentam nenhum cálculo. - Criar código morto para métricas futuras. - Misturar todos os cálculos dentro da UI. ## Success Criteria - Usuário consegue preencher dados P0 sem fricção excessiva. - App calcula pelo menos: - IMC; - reserva cardíaca; - score de treino; - carga subjetiva; - score de recuperação; - hidratação estimada; - tempo em zona de luta. - Dados ficam persistidos localmente. - Insights aparecem em PT-BR. - Cálculos puros têm testes. - Build final passa. - Nenhuma dependência nova é adicionada sem aprovação. ## Decisions Approved 1. Check-in pré-treino será obrigatório antes de iniciar uma sessão. 2. Insights será uma nova aba no menu inferior. 3. Sexo biológico será coletado como `Masculino` ou `Feminino`. 4. Energia, fadiga, dor e sono usarão escala 0–10. 5. Campos avançados devem poder ficar ocultos/expandidos para manter a interface limpa. ## BLE Reliability and Battery Plan ### Objective A leitura do sensor deve continuar enquanto o app estiver em treino, inclusive com tela bloqueada, salvo quando: 1. o usuário desconectar manualmente; 2. o usuário encerrar o treino; 3. o Android remover o processo por condição extrema fora do controle do app. Quando houver queda por distância/sinal, o serviço deve tentar reconectar automaticamente quando o usuário se aproximar novamente. Se o usuário desconectar manualmente, o app não deve reconectar sozinho. ### BLE Rules - O `HeartRateForegroundService` continua sendo dono da conexão BLE. - O ViewModel não deve abrir conexão direta com o sensor. - Toda queda inesperada deve ser registrada como estado de conexão e mensagem visível. - Desconexão manual deve salvar uma flag `manualDisconnect = true`. - Queda inesperada deve salvar `manualDisconnect = false` e iniciar retry/backoff. - O último sensor selecionado deve ser preservado para reconexão automática. ### Reconnect Strategy Estados sugeridos: ```text Idle Connecting Connected LostSignal RetryWaiting ManualDisconnected Failed ``` Backoff conservador: ```text 1ª tentativa: 2s 2ª tentativa: 5s 3ª tentativa: 10s 4ª tentativa em diante: 30s ``` Regras: - Não tentar reconectar se `manualDisconnect = true`. - Não tentar reconectar se Bluetooth estiver desligado; aguardar próximo ciclo. - Não tentar reconectar sem permissão Bluetooth. - Não fazer scan agressivo contínuo. - Para sensor já conhecido, tentar reconectar por `deviceId` direto antes de scan. - Scan só deve ser usado quando não houver deviceId válido. ### Battery Strategy Para menor consumo: - Foreground service único durante sessão. - Sem polling pesado no ViewModel a cada batimento. - SQLite insert apenas por amostra recebida. - Notificação com throttle. - Reconexão com backoff, nunca loop apertado. - Metadata do sensor lida na conexão e depois em intervalo longo, não a cada amostra. - Gráficos atualizam pelo estado recebido, sem reconsultar o banco inteiro. - Evitar wake locks permanentes. Usar foreground service e orientação de ignorar otimização de bateria. ### Acceptance BLE - Tela bloqueada não interrompe leitura durante treino. - Distância/sinal perdido mostra status de sensor perdido. - Ao aproximar novamente, o app tenta reconectar sozinho. - Se usuário tocar em Desconectar, reconexão automática fica desativada. - Se usuário escolher o sensor/iniciar novamente, reconexão automática volta a valer. - Build passa. ## Recommended First Implementation Plan Após aprovação desta spec: 1. Criar domínio puro de insights e testes. 2. Expandir modelo de perfil e sessão com campos P0. 3. Adicionar migração SQLite aditiva. 4. Criar UI de Perfil Avançado com seções expansíveis. 5. Criar check-in pré-treino obrigatório antes de iniciar sessão. 6. Criar pós-treino ao encerrar sessão. 7. Criar nova aba Insights com cards básicos. 8. Melhorar BLE com desconexão manual vs queda inesperada, reconexão automática e backoff. 9. Rodar build/test completo. --- # Spec Expansion: Gráficos, Janela de Treino e Relatório Científico ## Objective Transformar a sessão do FightRate em uma janela de coleta confiável com relatório pós-treino detalhado, gráficos Vico mais legíveis/interativos e métricas esportivas fundamentadas em frequência cardíaca real do sensor BLE. O objetivo é interpretação esportiva para lutas, não diagnóstico médico. Toda métrica estimada deve ser rotulada como estimativa. ## Research Summary Fontes consultadas antes da implementação: 1. Cole et al., NEJM 1999, PubMed: `https://pubmed.ncbi.nlm.nih.gov/10536127/` - HR Recovery é queda da FC do pico para 1 minuto pós-exercício. - Queda <= 12 bpm em 1 min foi considerada anormal no estudo clínico. 2. Brubaker & Kitzman, Circulation review, PMC: `https://pmc.ncbi.nlm.nih.gov/articles/PMC3065291/` - Resposta cronotrópica é capacidade de aumentar FC com demanda. - Critérios clínicos exigem teste progressivo e contexto; no app usar só interpretação esportiva. - HRR 1 min < 12 bpm, 2 min < 42 bpm aparecem como thresholds de risco em contexto clínico, mas o app não diagnostica. 3. Uth et al., Eur J Appl Physiol 2004, PubMed: `https://pubmed.ncbi.nlm.nih.gov/14624296/` - VO2max estimado pode usar `15.3 * (HRmax / HRrest)` em população treinada. - Aplicabilidade fora desse perfil deve ser tratada como aproximação. 4. Boxing HR response, PMC: `https://pmc.ncbi.nlm.nih.gov/articles/PMC3871409/` - Boxe simulado passou grande parte acima de VT2; HR aumenta por round. - Reforça foco em tempo em zonas altas, recuperação entre rounds e drift. 5. Muay Thai physiological response, Ingenta: `https://www.ingentaconnect.com/content/uwic/ujpa/2012/00000012/00000003/art00004` - Muay Thai competitivo teve FC média próxima do máximo e alto estresse cardiovascular. 6. Edwards/TRIMP summaries: `https://www.trainingimpulse.com/edwards-trimp` e `https://journals.lww.com/nsca-scj/fulltext/2018/04000/quantification_of_training_load_in_endurance.12.aspx` - Edwards TRIMP é prático por zonas, mas coeficientes são arbitrários. - Banister usa reserva cardíaca e ponderação exponencial; ambos devem ser apresentados como carga interna estimada. 7. HRV em Muay Thai, PMC: `https://pmc.ncbi.nlm.nih.gov/articles/PMC12143277/` - RMSSD/SDNN exigem RR/NN intervals confiáveis. O app hoje coleta BPM, portanto HRV fica fora do escopo até o parser/persistência salvarem RR intervals. ## Implementable Metrics From Current Data Viáveis agora: - duração total da sessão; - duração ativa aproximada e pausada; - BPM inicial/final/mínimo/médio/máximo; - desvio padrão; - qualidade dos dados por densidade, gaps e duração; - tempo e percentual por zona; - tempo em zona de luta, RedLine e Limite; - maior sequência contínua em zona intensa; - picos e quedas relevantes; - HR Recovery 1min/2min quando houver amostras pós-pico; - drift primeira metade vs segunda metade; - slope de BPM por minuto; - resposta cronotrópica inicial aproximada; - tempo até zona vigorosa/luta; - Edwards TRIMP; - Banister TRIMP quando houver FC repouso e limite cardíaco; - carga subjetiva RPE x duração; - VO2max estimado quando houver FC repouso e limite cardíaco; - hidratação estimada com peso pré/pós e água; - interpretação cruzada com energy/fatigue/soreness/sleep/symptoms/RPE. Não viável agora sem novos dados: - HRV RMSSD/SDNN/pNN50 real; - diagnóstico de arritmia; - limiar ventilatório real; - VO2 real; - economia cardíaca precisa entre sessões sem normalizar tipo/duração/intensidade. ## Data Collection / Time Window Reaproveitar `workout_sessions`: - `startedAtMillis` define início do range. - `endedAtMillis` define fim do range. - `session_id` em `heart_rate_samples` associa amostra à sessão ativa. - Ao finalizar, buscar amostras por `session_id`; fallback por intervalo se necessário. - Foreground service continua dono do BLE. - ViewModel não assume BLE. - Migração SQLite só aditiva se relatório persistido exigir cache. ## Domain Design Criar ou expandir domínio puro para relatório: - `TrainingReportMetrics` - `SessionReportBuilder` - `DataQualityAnalyzer` - `ZoneDistributionCalculator` - `HeartRateRecoveryCalculator` - `CardiacDriftCalculator` - `ChronotropicResponseCalculator` - `TrainingLoadCalculator` - `HydrationTrainingInterpreter` Business rules fora do Compose. ## UI / Charts Reaproveitar `HeartRateLineChart`, `FightCard`, `MetricTile`. Adicionar: - chart summary pills de mínimo/médio/máximo; - legenda de zonas; - destaque textual para tempo em zona de luta/limite; - estados profissionais para poucos dados; - leitura de eixo X por tempo real; - relatório em seções expansíveis: 1. Resumo do treino; 2. Gráfico principal; 3. Zonas cardíacas; 4. Recuperação; 5. Carga de treino; 6. Drift e fadiga; 7. Hidratação; 8. Comparação com histórico; 9. Alertas e interpretação. Evitar Canvas customizado e dependências novas. ## Success Criteria - Spec atualizada antes do código. - Código existente auditado e reaproveitado. - Testes JUnit cobrem todos os cálculos de domínio novos. - Sessão finalizada gera relatório com amostras do range correto. - Histórico permite abrir relatório de sessão. - UI deixa claro estimativa esportiva vs dado medido. - BLE continua no foreground service. - Sem migração destrutiva. - `./gradlew :app:testDebugUnitTest :app:assembleDebug` termina com `BUILD SUCCESSFUL`. - APK gerado e tentativa de `telegram_attach(localPath)` realizada.