23 KiB
FightRate — Full Project Context for AI Successor
Author: Evandro
Stack: Android Native (Kotlin, Jetpack Compose, Material3)
1. DEV ENVIRONMENT
| Item | Value |
|---|---|
| Project root | D:/Documents/Github/HealthTracking |
| Package | com.healthtracking.fightrate |
| Gradle | Wrapper 8.11.1 |
| AGP | 8.9.1 |
| Kotlin | 2.3.21 |
| Compose BOM | 2024.12.01 |
| compileSdk | 36 |
| targetSdk | 36 |
| minSdk | 26 |
| Android SDK | C:\Users\Evandro\AppData\Local\Android\Sdk |
| Java | JDK 17 (jvmToolchain) |
| App name | FightRate |
| APK naming | FightRate-YYYY-MM-DD-HH-mm-ss-debug.apk |
| No git repo | Project directory is NOT a git repository |
Key dependencies
navigation-compose:2.8.5compose.material3icons-lucide-android:2.2.1(viacom.composables:icons-lucide-android)- IMPORTANT: Non-transitive R; access Lucide icons via
import com.composables.icons.lucide.R as LucideR
- IMPORTANT: Non-transitive R; access Lucide icons via
vico:compose:3.2.2+vico:compose-m3:3.2.2(charting)coil-compose:3.0.4lottie-compose:6.6.2fastexcel:0.18.4(XLSX export)junit:4.13.2(testing)
Build commands
# Full build + test
./gradlew :app:testDebugUnitTest :app:assembleDebug
# Quick compile
./gradlew :app:compileDebugKotlin
# Unit test focused
./gradlew :app:testDebugUnitTest --tests "*AthleteInsightsTest*"
# Install on device
./gradlew :app:installDebug
2. PROJECT VISION
FightRate is a native Android app for tracking heart rate during combat/fighting sports using a Magene H003 chest strap (BLE Heart Rate Service 0x180D).
Core pillars
- Real-time BLE heart rate tracking — even with screen off, even in background
- Workout sessions — start/pause/resume/finish with round timer
- Athlete profile & cardiac zones — personalized by age, sex, resting HR, measured max HR
- Data insights — readiness, effort, hydration, recovery, fight zone time
- Rich history & charts — time-based Vico charts with compaction, export (CSV/JSON/XLSX)
- Scientific cardiac analytics — statistical and clinical-grade metrics from raw HR data
UI conventions
- All visible text in PT-BR (Portuguese Brazilian)
- All code identifiers in English
- Dark theme with signature orange accent (
FightOrange = #FF5733) - Bottom navigation tabs: Ao vivo | Sensor | Histórico | Insights | Perfil
- Cards use
FightCardcomposable (dark panels with rounded corners)
3. FILE STRUCTURE
app/src/main/java/com/healthtracking/fightrate/
├── MainActivity.kt # Entry point, permission requests
├── ble/
│ ├── AndroidHeartRateBleClient.kt # Concrete BLE GATT client implementation
│ ├── AndroidHeartRateBleScanner.kt # Concrete BLE scanner implementation
│ ├── HeartRateBleClient.kt # BLE client interface
│ ├── HeartRateBleConstants.kt # BLE UUIDs (0x180D, 0x2A37, 0x2A38, 0x180F, 0x2A19)
│ ├── HeartRateBleScanner.kt # BLE scanner interface
│ ├── HeartRateBleStatus.kt # Status sealed class (Connecting/Connected/etc.)
│ ├── HeartRateDevice.kt # Device data class
│ ├── HeartRateParser.kt # BLE heart rate measurement parser
│ └── HeartRateSensorMetadata.kt # Battery level + body sensor location
├── data/
│ ├── HeartRateSampleStore.kt # SQLite DB (heart_rate_samples + workout_sessions)
│ └── HeartRateExporter.kt # CSV/JSON/XLSX export via FileProvider
├── domain/
│ ├── AthleteInsights.kt # BMI, Karvonen, readiness, effort, hydration, fight zone, alerts
│ ├── HeartRateAlertSettings.kt # Alert config + evaluator
│ ├── HeartRateStats.kt # Stats (avg/min/max/stdDev)
│ ├── HeartRateWindows.kt # Rolling time window filter
│ ├── HeartRateZones.kt # Zone calculation (6 zones by % max HR)
│ ├── RoundTimer.kt # Round/rest timer logic
│ ├── WorkoutSession.kt # Session + summary models + calculations
│ └── model/
│ ├── AthleteProfile.kt # Age, sex, height, weight, maxHR, restingHR, sport, class, goal
│ ├── FightSport.kt # Boxing, MuayThai, MMA, BJJ, Wrestling, FreeTraining
│ ├── HeartRateMeasurement.kt # Measurement model
│ └── HeartRateSample.kt # Core sample (timestampMillis, bpm, sport, source, deviceName, sessionId)
├── service/
│ └── HeartRateForegroundService.kt # Foreground BLE service with auto-reconnect + backoff
├── system/
│ ├── BackgroundRunPermission.kt # Battery optimization settings opener
│ └── HeartRateAlertNotifier.kt # Vibration + sound alert dispatcher
└── ui/
├── live/
│ ├── BleConnectionStatus.kt # Connection status enum
│ ├── HistoryPeriod.kt # Time window enum (Last10min/30min/1h/3h/6h/Today)
│ ├── LiveHeartRateUiState.kt # Single source of truth state data class
│ └── LiveHeartRateViewModel.kt # Central AndroidViewModel (~729 lines)
├── screens/
│ └── HomeScreen.kt # ALL UI in one file (~1700+ lines of Compose)
└── theme/
├── Color.kt # Dark theme color palette
└── FightRateTheme.kt # Material3 theme configuration
Tests:
app/src/test/java/com/healthtracking/fightrate/
├── ble/HeartRateParserTest.kt
├── domain/
│ ├── AthleteInsightsTest.kt
│ ├── HeartRateAlertEvaluatorTest.kt
│ ├── HeartRateStatsCalculatorTest.kt
│ ├── HeartRateWindowsTest.kt
│ ├── HeartRateZonesTest.kt
│ ├── RoundTimerTest.kt
│ └── WorkoutSessionSummaryTest.kt
4. DATABASE SCHEMA
Table: heart_rate_samples (version 4)
id INTEGER PRIMARY KEY AUTOINCREMENT
timestamp_millis INTEGER NOT NULL
day_key TEXT NOT NULL
bpm INTEGER NOT NULL
sport TEXT NOT NULL
source TEXT NOT NULL
device_name TEXT
session_id INTEGER
Indexed on day_key, timestamp_millis, (session_id, timestamp_millis).
Table: workout_sessions (created at v3, expanded at v4)
id INTEGER PRIMARY KEY AUTOINCREMENT
started_at_millis INTEGER NOT NULL
ended_at_millis INTEGER
status TEXT NOT NULL DEFAULT 'Active'
sport TEXT NOT NULL DEFAULT 'Treino livre'
round_duration_seconds INTEGER NOT NULL DEFAULT 180
rest_duration_seconds INTEGER NOT NULL DEFAULT 60
rounds INTEGER NOT NULL DEFAULT 3
accumulated_active_seconds INTEGER NOT NULL DEFAULT 0
last_resumed_at_millis INTEGER
-- v4 columns:
pre_workout_energy INTEGER
pre_workout_fatigue INTEGER
muscle_soreness INTEGER
sleep_hours REAL
sleep_quality INTEGER
pre_workout_weight_kg REAL
water_intake_ml INTEGER
symptoms_note TEXT NOT NULL DEFAULT ''
post_workout_rpe INTEGER
post_workout_fatigue INTEGER
post_workout_soreness INTEGER
post_workout_weight_kg REAL
post_workout_note TEXT NOT NULL DEFAULT ''
5. DATA FLOW
BLE → Service → ViewModel → UI
Magene H003 (BLE)
↓ Heart Rate Service 0x180D / Measurement 0x2A37
AndroidHeartRateBleClient (GATT)
↓ Flow<HeartRateMeasurement>
HeartRateForegroundService
↓ BroadcastReceiver (ActionSample, ActionStatus, ActionMetadata)
LiveHeartRateViewModel.handleServiceSample() / handleServiceStatus() / handleSensorMetadata()
↓ StateFlow<LiveHeartRateUiState>
HomeScreen.kt (@Composable)
Session lifecycle
- User fills Check-in (mandatory dialog) →
startWorkoutSessionWithCheckIn() - SQLite
workout_sessionsinserted, samplesession_idauto-assigned - Round timer runs in ViewModel ticker
- User can Pause / Resume
- User taps Finish → Post-workout dialog →
finishWorkoutSessionWithPostWorkout() - Session status = Finished,
ended_at_millisset
6. CARDIAC ZONES SYSTEM
Zone thresholds based on % of max heart rate
| Zone | % Max HR | Label (PT-BR) | Usage |
|---|---|---|---|
| Recovery | 1–59% | Recuperação | Recovery/active rest |
| Base | 60–69% | Base | Aerobic base |
| Vigorous | 70–85% | Vigorosa | Moderate-high intensity |
| Fight | 86–89% | Luta intensa | Fight zone specific |
| RedLine | 90–95% | Muito intensa | Very high intensity |
| Limit | 96–200% | Limite | Maximum effort |
Max HR formula
- Estimated:
208 - (0.7 × age)(Tanaka formula) - Overrideable with
measuredMaxHeartRate(campo: "limite cardíaco real")
Karvonen zones (reserve-based)
When resting HR is available, zones shift upward using:
TargetHR = RestingHR + Reserve × %Intensity
where Reserve = MaxHR - RestingHR
7. CURRENT METRICS / CALCULATIONS
Already implemented
- BMI — from weight + height, with category (abaixo do peso / peso adequado / sobrepeso / obesidade)
- Heart Rate Reserve (Karvonen) — MaxHR − RestingHR
- Zones by Karvonen — personalized zone ranges
- Readiness Score (0–100) — based on sleep hours, sleep quality, energy, fatigue, soreness
- Workout Effort Score (0–100) — based on avg%BPM, peak%BPM, duration, RPE, with session load (RPE×min)
- Hydration Estimate — pre/post weight difference + water intake, with fluid loss warning
- Fight Zone Time — seconds and % of session spent in Fight/RedLine/Limit zones
- Athlete Insights Alerts — combined warnings from readiness, hydration, effort, symptoms
- Heart Rate Stats — avg, min, max, standard deviation
- Zone Breakdown — % of session in each zone
- Rolling 60s average — main display; instant BPM shown as "Agora"
8. BLE RESILIENCE SYSTEM
Reconnection strategy
- Service runs as foreground with
foregroundServiceType="connectedDevice" START_STICKY— Android restarts if killed- On unexpected disconnect (distance/signal loss), auto-reconnect with backoff:
- 1st: 2s → 2nd: 5s → 3rd: 10s → 4th+: 30s
- Manual disconnect sets
manualDisconnect = trueflag in SharedPreferences - When
manualDisconnect = true, no auto-reconnect - Reconnection state persisted: last device ID, device name, manual flag
- On service restart (START_STICKY), reads persisted state and auto-reconnects if not manual
- No aggressive continuous scanning; reconnects by known device ID first
Battery optimization
- Single foreground service during session (no persistent background service when idle)
- Notification updates throttled: max every 15s OR >3 BPM delta
- No SQLite polling on every beat from service
- ViewModel polls DB at 5s intervals only when connected
- Rolling 60s average computed in-memory in service
- Guide user to battery optimization settings via
BackgroundRunPermission
9. CURRENT UI STRUCTURE (HomeScreen.kt)
Single massive file with all composable functions (~1700+ lines):
Screens (tabs)
- LiveScreen — rolling 10-min chart, instant BPM, 60s avg, zone, Muay Thai comparison
- SensorScreen — scan button, device list, battery chip, body sensor location, connection status, background toggle
- HistoryScreen — period selector, stats cards, zone breakdown, Vico chart (time-based) with empty state
- InsightsScreen — BMI, reserve, readiness, effort, hydration, fight zone, alerts
- ProfileScreen — expandable sections (básico, cardiovascular, luta), choice chips for sex/sport, save button
Key composables
FightCard— dark panel wrapperMetricTile— stat label+value pairLiveMetricPill— compact live stat pillHeartRateLineChart— Vico chart with time-based x-axisEmptyTimeWindowChart— placeholder when no dataRoundSessionCard— session controls + round timerExpandedSessionCard— session metricsAlertSettingsCard— alert configuration
10. WHAT DOCTORS CONSIDER FROM HEART RATE DATA (Scientific Foundation)
Below is a structured compilation of medical-grade metrics that can be calculated from the data types FightRate already collects (raw HR timestamps, profile data, session data, sleep, subjective scales). These are well-established in sports cardiology, exercise physiology, and clinical practice.
10.1 Resting Heart Rate (RHR)
- Clinical significance: Lower RHR = better cardiovascular fitness. Resting tachycardia (>100 bpm) flags medical concern.
- Can trend: Weekly RHR average from morning readings. Spike of +5-7 bpm signals possible illness, overtraining, or poor recovery.
- Calculation: Mean of lowest 5 readings during rest periods (early morning before rising is gold standard).
10.2 Heart Rate Recovery (HRR)
- Clinical gold standard: Drop in BPM 1-minute and 2-minutes post-exercise cessation.
- Normal: >22 bpm drop at 1 min (adults). Drop <12 bpm = elevated cardiovascular mortality risk (Cole et al., NEJM 1999).
- Athlete context: Faster recovery = better conditioning. Slowing recovery trend = functional overreaching or detraining.
- Can calculate from existing data: After session ends, look at first 60s and 120s of BPM decline.
10.3 Heart Rate Variability (HRV)
- Key clinical parameters:
- RMSSD (Root Mean Square of Successive Differences): Parasympathetic activity marker. Gold standard for daily monitoring.
- SDNN (Standard Deviation of NN intervals): Overall HRV. Clinical risk predictor.
- LF/HF Ratio: Sympathetic/parasympathetic balance.
- From our data: HRV requires beat-to-beat R-R intervals (ms). BLE HR Service 0x2A37 can provide RR intervals if the sensor sends them (Magene H003 does). We already have
HeartRateMeasurementwith potential RR data. - Clinical use: Low HRV = stress, illness risk, overtraining. High HRV = recovery, readiness.
- Training application: Morning HRV guides daily training intensity (Daneshvar, 2024).
10.4 Cardiac Drift (Cardiovascular Drift)
- Definition: Progressive rise in HR during steady-state exercise despite constant workload.
- Causes: Dehydration, electrolyte loss, thermoregulatory strain, blood volume shift.
- Clinical marker: Drift >10% of starting HR = significant heat/dehydration stress.
- Can calculate: Linear regression slope of HR over session duration at constant intensity.
10.5 Chronotropic Response / Chronotropic Incompetence
- Definition: Inability of HR to rise appropriately with exercise intensity.
- Calculation:
%HeartRateReserve achieved / %MetabolicReserve achieved - Clinical threshold: CI = failure to reach 85% of age-predicted max HR at peak exercise.
- Detection from data: Slope of HR increase in first 3 minutes of session.
10.6 Heart Rate Deflection Point (HRDP / Conconi Test)
- Definition: The point at which HR stops increasing linearly with running speed/workload.
- Use: Non-invasive anaerobic threshold estimation.
- Calculation: Piecewise linear regression of HR × workload curve.
10.7 TRIMP (Training Impulse)
- Banister's TRIMP:
duration × (ΔHR/ΔHRmax) × 0.64e^(1.92×ΔHR/ΔHRmax) - MICT TRIMP:
duration × %MaxHR - Edwards TRIMP (our approach): Sum of minutes in each zone × zone coefficient.
- Clinical use: Quantifies internal training load. Correlates with adaptation and injury risk.
10.8 Training Monotony & Strain (Foster, 1998)
- Monotony:
WeeklyMeanLoad / WeeklySDLoad. High monotony (>2.0) + high strain = overtraining risk. - Strain:
WeeklySumLoad × Monotony. - Data requirement: Daily session load over 7+ days.
10.9 Excess Post-Exercise Oxygen Consumption (EPOC) Estimate
- Correlation: Higher HR during session → higher EPOC → more post-workout calorie burn.
- Proxy metric: Time above 70% max HR correlates with EPOC duration.
10.10 Aerobic Efficiency / Cardiac Economy
- Metric: HR at a given perceived exertion level over time. If HR at same RPE decreases, athlete is fitter.
- Calculation: Match sessions with same RPE → compare average HR.
10.11 Relative VO2max Estimation
- Astrand-Ryhming nomogram: Based on HR at submaximal workload with age/sex correction.
- Uth-Sørensen-Overgaard formula:
VO2max = 15.3 × (MaxHR / RestingHR)(approximate).
10.12 Heart Rate Turbulence (HRT)
- Clinical: Post-premature-ventricular-contraction HR response. Not feasible without ECG.
10.13 Summary of actionable clinical-grade metrics from our data
| Metric | Data needed | Clinical value | Feasibility |
|---|---|---|---|
| Resting HR trend | Morning readings | Overtraining, illness | ✅ Already have |
| HR Recovery (1min, 2min) | Post-session BPM | CV risk, conditioning | ✅ Easy add |
| Cardiac Drift | Session BPM trend | Hydration, heat stress | ✅ Easy add |
| Chronotropic Response | Session onset BPM | CV fitness, beta-blocker effect | ✅ Easy add |
| TRIMP (Edwards) | Zone time | Training load | ✅ Already have zone breakdown |
| TRIMP (Banister) | Duration, avgHR, maxHR | Training load | ⚡ Medium effort |
| Weekly Monotony & Strain | 7d load history | Overtraining risk | ⚡ Need 7d history UI |
| VO2max estimation | MaxHR, RestingHR, sex | Aerobic fitness estimate | ✅ Ready (formula exists) |
| HRV RMSSD/SDNN | RR intervals | Recovery, readiness | ⚡ Need RR parser |
| HR Deflection Point | Incremental test BPM | Anaerobic threshold | ❌ Requires protocol |
| Fatigue slope | HR per minute over session | Pacing, fatigue onset | ✅ Easy add |
11. WHAT USER WANTS NOW (Pre-approved)
A. Charts improvement
Make charts more informative and interactive:
- Better tooltips/markers
- Zone-colored areas
- Callout for min/max/avg points
- Session overlay with round/rest phases
- Smoother pan/zoom
- Multiple time ranges
B. Session-based detailed report
A system that:
- User can start/stop a recording time window
- All HR samples within that window are collected
- At stop, a detailed report is generated with:
- Full session statistics
- Zone breakdown
- HR Recovery
- Cardiac drift analysis
- Chronotropic response
- TRIMP score
- Readiness context (from pre-session check-in)
- Hydration estimate
- Fight zone time
- Trend compared to past sessions
C. Scientific/clinical analytics
Research-backed metrics that doctors consider from HR data (section 10 above). This is now approved to implement:
- HR Recovery (1min, 2min)
- Cardiac Drift
- Chronotropic Response
- TRIMP (Banister + Edwards)
- VO2max estimation
- Weekly monotony & strain
- Fatigue slope
- HRV when RR data available
12. APPROVED DECISIONS (Perfil/Insights P0)
| Item | Decision |
|---|---|
| Check-in | Mandatory before starting session |
| Insights location | New tab in bottom navigation |
| Biological sex | Collected as Masculino/Feminino |
| Scale range | 0–10 for energy, fatigue, soreness, sleep quality |
| Advanced fields | Collapsible sections (expand/hide) |
13. IMPORTANT CODE PATTERNS & PITFALLS
Don'ts (from previous learnings)
- DON'T create custom Canvas charts — use Vico (
com.patrykandpatrick.vico) - DON'T move BLE ownership from foreground service to ViewModel
- DON'T add new dependencies without asking
- DON'T use
lineSeries— Vico API: uselineModelinstead - DON'T add fragil custom Canvas gauges
- DON'T mix business rules in Compose — keep domain pure Kotlin
- DON'T make destructive SQLite migrations without approval
- DON'T add unused code or placeholder features
Do's
- DO use
LucideR.drawable.lucide_ic_xxxfor Lucide icons - DO test domain with JUnit before UI
- DO implement in slices: domain → persistence → ViewModel/state → UI → BLE
- DO use
HeartRateForegroundService.ActionConnect/ActionDisconnectfor BLE control - DO preserve PT-BR in UI, English in code
- DO run
./gradlew :app:testDebugUnitTest :app:assembleDebugbefore claiming completion - DO save data locally first (SQLite source of truth)
- DO write
collectcalls with explicit{ }braces around the when-body in service - DO use
ChoiceChipButton,ExpandableSectionHeader,ProfileNumberFieldfor consistent UI
Known non-blocking warnings
lineSeriesdeprecated → uselineModel(low priority)- BLE
writeDescriptordeprecated in SDK 36 (non-blocking) - No LSP client for Kotlin in this environment; rely on
compileDebugKotlinoutput
14. IMMEDIATE NEXT TASK
Priority: Implement session-based detailed report + scientific analytics
- Enhance chart: Session overlay with round phases, zone colors, better tooltips
- Session report system:
- Start/stop recording independent of session (or same)
- Collect all samples in range
- Generate report at stop with medical-grade metrics
- Add new domain calculations:
- HR Recovery (1min, 2min)
- Cardiac Drift
- Chronotropic Response
- TRIMP (Banister + Edwards)
- VO2max estimation
- Report UI: Dedicated report screen or dialog with full metrics
- After done: send APK via Telegram
Workflow to follow
→ Search web if needed
→ Write/update spec
→ Audit existing code
→ Implement domain + tests (new calculations)
→ Implement persistence if needed
→ Implement ViewModel/state
→ Implement UI (chart + report)
→ Build & test
→ Send APK
→ Update Obsidian roadmap
15. WORKFLOW DOCUMENT
Path: D:/Documents/Github/HealthTracking/docs/FIGHTRATE_DEVELOPMENT_WORKFLOW.md
Project skill: fightrate-quality-loop
Scope: project:HealthTracking
Skill path
C:\Users\Evandro\.pi\agent\projects-memory\HealthTracking\skills\fightrate-quality-loop\SKILL.md
Obsidian vault
Path: D:\Documents\Obsidian Vault
Roadmap file: Projetos/FightRate - Auditoria e Roadmap.md
16. COMMANDS QUICK REFERENCE
# Full verification
./gradlew :app:testDebugUnitTest :app:assembleDebug
# Quick compile
./gradlew :app:compileDebugKotlin
# Domain tests
./gradlew :app:testDebugUnitTest --tests "*AthleteInsightsTest*"
./gradlew :app:testDebugUnitTest --tests "*WorkoutSessionSummary*"
./gradlew :app:testDebugUnitTest --tests "*HeartRateZonesTest*"
# Install APK
./gradlew :app:installDebug
# Latest APK path
app/build/outputs/apk/debug/FightRate-*-debug.apk
17. TELEGRAM CONTEXT
- User delivers messages via Telegram bridge
[telegram]prefix → deliver replies via Telegram- When sending APK: call
telegram_attach(localPath) - The user says: "Ao terminar me mande o apk no telegram"
18. FINAL NOTES
- This document was built by reading all source files, build files, specs, and tests
- Everything described here is already implemented unless marked as "new" or "next"
- The user has pre-approved the scientific analytics implementation + session report
- The user wants continuous improvement — no stop until done
- Focus on charts, session-based reporting, and scientific-grade metrics