Files
MeeJayandClaude Opus 5 93f0689c1e Initial import: LifeTrack v1 (santé, vape, finances)
Tracker de vie auto-hébergé : suivi poids/calories/sport avec planning de
pesées, sevrage tabac (vape) avec modèle de coût DIY et économies, et
finances personnelles avec import de relevés bancaires.

Architecture : FastAPI + SQLAlchemy 2.0 + PostgreSQL 16, React 18 + TS +
Vite + Tailwind + ECharts, déploiement Docker Compose. Modules
auto-découverts des deux côtés (pkgutil / import.meta.glob) et framework
de connecteurs à deux voies (importeurs de fichiers + ingestion JSON)
pour brancher de nouvelles sources sans toucher au noyau.

Validé : 292 tests pytest, tsc + vite build, contrat API/web vérifié
contre le schéma OpenAPI, et déploiement Docker réel sur PostgreSQL 16
(28 tables, SPA servie par nginx, wizard de premier démarrage).

Documentation : README.md, docs/GUIDE.md, CONVENTIONS.md, et les
documents de conception et de recherche dans docs/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 10:48:57 +02:00

33 KiB
Raw Permalink Blame History

Recherche : intégrer les données Android Health Connect dans LifeTrack (auto-hébergé)

Document de recherche — module Santé/Fitness de LifeTrack. Date : 2026-08-13. Public : agents d'implémentation (backend FastAPI, frontend React, app Android éventuelle). Langue : prose en français, identifiants de code en anglais (convention projet).


1. Résumé exécutif

Constat central : Health Connect est un magasin de données strictement local au téléphone ("on-device"). Il n'existe aucune API cloud officielle permettant à un serveur (auto-hébergé ou non) d'interroger les données Health Connect d'un utilisateur. Le seul moyen d'amener ces données sur le serveur LifeTrack est qu'une application Android installée sur le téléphone lise Health Connect localement puis pousse les données vers notre backend (ou exporte des fichiers que l'on importe).

L'API REST Google Fit est morte : inscriptions fermées depuis le 1er mai 2024, arrêt définitif courant 2026. Elle ne doit servir de base à rien dans LifeTrack.

Recommandation v1 (détaillée en section 8) :

  1. Construire côté LifeTrack un endpoint d'ingestion REST générique et authentifié (POST /api/v1/ingest/...), conçu pour recevoir des lots de mesures santé en JSON, avec stockage du payload brut + normalisation, idempotent (dédoublonnage par identifiant externe).
  2. Utiliser comme pont v1 l'application open-source health-connect-webhook (Android, AGPL-3.0, disponible sur le Play Store), qui lit Health Connect en tâche de fond (WorkManager) et POSTe du JSON vers des URLs de webhook configurables — c'est exactement le modèle "push vers endpoint custom" voulu par le brief. Alternative plus lourde : HCGateway (serveur Flask+MongoDB à héberger en plus, moins bien aligné avec notre stack).
  3. Prévoir en fallback un import de fichiers CSV : l'application payante Health Sync (licence unique ~4 €) exporte automatiquement les données Health Connect en CSV (et les séances en FIT/TCX/GPX) vers Google Drive ; LifeTrack fournit un importeur CSV correspondant via le framework de connecteurs.
  4. v2 : application companion Android minimale maison (Kotlin + Health Connect SDK + WorkManager) qui POSTe directement sur notre endpoint — fiabilité et contrôle maximum, effort modéré (3 à 10 jours). v2/v3 : enregistrement direct des séances de tapis via Web Bluetooth + FTMS dans le frontend React (Chrome/Edge uniquement, HTTPS requis), pour s'affranchir de l'app FitShow.

2. Health Connect : fonctionnement, capacités, limites

2.1 Architecture : on-device uniquement, pas d'API cloud

  • Health Connect (HC) est une base de données chiffrée stockée sur le téléphone. Les apps santé (Samsung Health, Fitbit, Gadgetbridge, Foodvisor via Google Fit, etc.) y écrivent ; d'autres apps y lisent, uniquement depuis le device.
  • La documentation officielle Google est explicite : HC est prévu pour les données "on-device" Android ; la « Google Health API » (cloud) est un produit distinct, successeur de la Fitbit Web API uniquement (comptes Fitbit/Google, accès soumis à validation Google) — inutilisable pour un projet personnel auto-hébergé et hors périmètre.
  • Conséquence d'architecture pour LifeTrack : un intermédiaire Android est obligatoire. Le backend ne pourra jamais "aller chercher" les données ; il doit recevoir (push HTTP) ou importer (fichiers).
  • Depuis Android 14, HC est intégré au système (Réglages > Sécurité et confidentialité > Health Connect). Sur Android 913, c'est une app APK à installer depuis le Play Store. SDK minimum : API 28 (Android 9).

2.2 Types de données disponibles (Jetpack androidx.health.connect.client.records)

Tous les besoins du module Santé/Fitness de LifeTrack sont couverts par des types HC standards. Correspondance à utiliser telle quelle dans le modèle de données :

Besoin LifeTrack Record Health Connect Permission Android
Pas quotidiens StepsRecord android.permission.health.READ_STEPS
Distance DistanceRecord ...READ_DISTANCE
Calories actives brûlées ActiveCaloriesBurnedRecord ...READ_ACTIVE_CALORIES_BURNED
Calories totales brûlées (TDEE observé) TotalCaloriesBurnedRecord ...READ_TOTAL_CALORIES_BURNED
Métabolisme de base (BMR) BasalMetabolicRateRecord ...READ_BASAL_METABOLIC_RATE
Séances de sport (tapis, etc.) ExerciseSessionRecord (+ SpeedRecord, PowerRecord, ElevationGainedRecord associés) ...READ_EXERCISE (+ READ_SPEED, READ_POWER)
Poids WeightRecord ...READ_WEIGHT
Masse grasse BodyFatRecord ...READ_BODY_FAT
Masse maigre / osseuse / hydrique LeanBodyMassRecord, BoneMassRecord, BodyWaterMassRecord permissions dédiées
Taille HeightRecord ...READ_HEIGHT
Fréquence cardiaque HeartRateRecord, RestingHeartRateRecord, HeartRateVariabilityRmssdRecord ...READ_HEART_RATE, etc.
Sommeil SleepSessionRecord (avec stages) ...READ_SLEEP
Apport calorique / macros (Foodvisor) NutritionRecord ...READ_NUTRITION
Hydratation HydrationRecord ...READ_HYDRATION
VO2 max, étages montés, etc. Vo2MaxRecord, FloorsClimbedRecord, ... permissions dédiées

Note Foodvisor : Foodvisor (Android) se synchronise avec Google Fit (réglage « connexion aux données de santé ») ; Google Fit écrit/lit la nutrition via Health Connect. La chaîne Foodvisor → Google Fit → Health Connect → pont → LifeTrack est donc possible en théorie pour les calories ingérées (NutritionRecord), mais fragile (dépend du maintien de l'app Google Fit, en fin de vie côté API ; des utilisateurs signalent des synchronisations Foodvisor→Fit capricieuses). À tester en priorité une fois le pont en place ; sinon, saisie manuelle / export Foodvisor en fallback.

2.3 Permissions et restrictions importantes (impact direct sur la conception)

  • Fenêtre historique de 30 jours : par défaut, une app ne peut lire que les données datant d'au plus 30 jours avant la première autorisation. Pour lire plus ancien, permission additionnelle android.permission.health.READ_HEALTH_DATA_HISTORY (PERMISSION_READ_HEALTH_DATA_HISTORY), disponible depuis les mises à jour 2025 du SDK (Jetpack en bêta depuis mars 2025). Conséquence : installer/configurer le pont tôt ; l'historique antérieur profond passera plutôt par des exports CSV.
  • Lecture en arrière-plan : permission dédiée android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND, indispensable pour un pont qui synchronise sans que l'app soit ouverte. Les apps pont citées la gèrent déjà ; une app maison doit la déclarer et la demander.
  • Rate limiting : HC impose des quotas de lecture (par app, différents premier plan / arrière-plan). Conception à base de sync incrémentale obligatoire, pas de relecture complète à chaque cycle.
  • API de changements (differential changes) : getChanges(token) fournit ajouts/modifications/suppressions depuis le dernier token — c'est le mécanisme officiel de sync incrémentale. Les tokens expirent (~30 jours) ; prévoir une resynchronisation de rattrapage si token expiré.
  • Distribution hors Play Store : la validation Google (formulaire de déclaration des permissions santé) est une exigence de publication sur le Play Store, pas un prérequis technique de l'API. Une app companion sideloadée (APK debug/release signé localement) déclarant correctement ses permissions dans le manifest et l'intent de justification (androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE sur Android 13-, android.intent.action.VIEW_PERMISSION_USAGE + catégorie android.intent.category.HEALTH_PERMISSIONS sur 14+) fonctionne : l'utilisateur accorde les permissions dans l'UI Health Connect. Preuve empirique : HCGateway et d'autres ponts open-source se distribuent en APK GitHub et fonctionnent. Point de vigilance : certains guides tiers évoquent des contrôles d'app ID pour les apps Play ; pour un usage personnel sideloadé, aucun blocage connu, mais à valider sur l'appareil cible dès le début du développement v2.

2.4 Ce que ça implique pour LifeTrack

  • Le backend doit exposer une API d'ingestion push (section 8) — jamais de « pull » possible.
  • Les données arrivent par lots hétérogènes, avec doublons possibles (re-synchronisations) : l'ingestion doit être idempotente.
  • Chaque record HC porte des métadonnées utiles à conserver : metadata.id (UUID unique HC), clientRecordId, dataOrigin (package de l'app source, ex. com.sec.android.app.shealth), horodatages début/fin avec offset de zone. LifeTrack stocke en UTC (convention projet) + source_app.

3. API REST Google Fit : statut (chemin non viable)

  • Dépréciation annoncée avec Health Connect comme successeur ; inscriptions fermées depuis le 1er mai 2024 (aucun nouveau projet ne peut obtenir l'accès OAuth aux scopes Fitness).
  • Arrêt de service courant 2026 ("supported until the end of 2026" selon la FAQ de migration ; la page officielle developers.google.com/fit dit "will be deprecated in 2026" sans jour précis).
  • L'app mobile Google Fit elle-même est en fin de vie au profit de l'app Fitbit ; ne pas en faire une dépendance.
  • Verdict : à exclure totalement. Même si un projet OAuth existant fonctionnait encore quelques mois, tout investissement serait perdu. Aucune ligne de code LifeTrack ne doit cibler l'API Google Fit.

4. Applications pont existantes (Health Connect → serveur/fichier)

4.1 health-connect-webhook (mcnaveen) — candidat recommandé v1

  • Dépôt : https://github.com/mcnaveen/health-connect-webhook — Kotlin / Jetpack Compose / Material 3, licence AGPL-3.0 (+ addendum commercial pour la redistribution en store). ~141 stars, ~161 commits, activement maintenu, distribué sur le Play Store (et App Store côté iOS).
  • Fonction : lit Health Connect et POSTe un JSON vers une ou plusieurs URLs de webhook configurées par l'utilisateur. Exactement le modèle "push vers endpoint REST custom" du brief.
  • Mécanismes de sync : (a) périodique via WorkManager (minimum 15 min, réglable), (b) horaires fixes via AlarmManager (défaut 08:00 et 21:00), (c) sync manuelle, (d) serveur HTTP local optionnel sur le téléphone (port 8787 par défaut) exposant un snapshot JSON en pull sur le LAN.
  • Payload : POST avec Content-Type: application/json; charset=utf-8. Objet JSON unique : timestamp (génération du payload), app_version, puis un tableau par type de données en snake_case (ex. steps, heart_rate, weight, exercise_sessions, sleep_sessions, nutrition, active_calories_burned, total_calories_burned, distance...), tableaux omis si vides. Schémas de champs détaillés dans les fichiers docs/webhook.md et docs/local-http.md du dépôt (les récupérer au moment de l'implémentation de l'adaptateur pour figer le mapping exact).
  • Couverture : 31 types de données, incluant tout ce dont LifeTrack a besoin (steps, distance, calories actives/totales, exercise sessions, poids, masse grasse, BMR, FC, sommeil avec stages, nutrition, hydratation, VO2 max).
  • Fenêtre de lecture : fenêtre glissante de 48 h ; les syncs en arrière-plan sont incrémentales (données nouvelles depuis la dernière sync réussie). Retries : 3 tentatives avec backoff exponentiel, puis nouvelle tentative à la sync suivante. Limite : si le téléphone/app est inactif plus de 48 h, trou possible → couvert par le fallback CSV et par la réconciliation côté serveur.
  • Limite importante : pas d'en-tête d'authentification configurable. La sécurité repose sur l'URL. Mitigation LifeTrack : jeton secret dans l'URL (ex. https://lifetrack.example/api/v1/ingest/hc-webhook/<ingest_token>), token révocable, endpoint accessible uniquement en HTTPS (et idéalement seulement via VPN/LAN — déploiement domestique). Vérifier à l'implémentation si des en-têtes custom ont été ajoutés depuis.

4.2 HCGateway (ShuchirJ) — alternative complète mais lourde

  • Dépôt : https://github.com/ShuchirJ/HCGateway — licence GPL-3.0, ~414 stars, développement actif ("API stability not guaranteed").
  • Architecture : app mobile React Native (Android 8+) + serveur Python Flask + MongoDB auto-hébergeable (Docker Compose fourni) + Firebase (notifications push, nécessaire seulement pour déclencher des écritures serveur→téléphone ; il faut alors builder l'APK soi-même avec son google-services.json).
  • Fonction : sync bidirectionnelle — l'app envoie ~34/35 types de données HC vers le serveur toutes les 2 h (réglable, service foreground persistant, sync ~15 min) ; API REST (login/signup, fetch par type — méthodes nommées steps, heartRate, sleepSession, activeCaloriesBurned, weight, exerciseSession, etc. — et push vers HC). Docs API : https://hcgateway.shuchir.dev/.
  • Sécurité : mots de passe Argon2 ; données chiffrées Fernet au repos dans MongoDB (clé dérivée du hash utilisateur), déchiffrées à la volée lors des requêtes API. Collections hcgateway_[user_id] avec données chiffrées, horodatages début/fin, package d'origine, id unique.
  • Historique : limité aussi par la fenêtre HC de 30 jours (issue GitHub #38 ouverte à ce sujet).
  • Évaluation pour LifeTrack : fonctionne, mais impose un deuxième backend + MongoDB + éventuellement Firebase à côté de notre stack Postgres/FastAPI, et LifeTrack devrait poller l'API HCGateway (au lieu de recevoir un push). Intéressant seulement si health-connect-webhook s'avère défaillant. Une instance publique existe (https://api.hcgateway.shuchir.dev/) mais envoie les données santé chez un tiers — contraire à l'esprit auto-hébergé.

4.3 Health Sync (appyhapps.nl) — le fallback fichiers de référence

  • App Android commerciale mature (https://healthsync.app) : essai 1 semaine, puis licence à vie en achat unique (~4 €) ou abonnement 6 mois (Withings seul nécessite un abonnement dédié).
  • Synchronise entre plateformes (sources : Health Connect, Samsung Health, Fitbit, Garmin, Polar, Suunto, Huawei, Oura, Strava, fatsecret... ; destinations : Health Connect, Strava, Google Drive, etc.).
  • Fonction clé pour LifeTrack : export automatique vers Google Drive — données santé (pas, FC, poids...) en CSV (fichiers jour courant / 7 jours / mois / 30 jours glissants), séances d'activité en FIT, TCX, GPX, KML, CSV. Tourne en arrière-plan sans intervention.
  • Usage LifeTrack : l'utilisateur dépose les CSV dans l'UI d'import (ou un dossier synchronisé sur le serveur) ; le framework d'importeurs LifeTrack fournit un parseur health_sync_csv. Sert aussi à rattraper l'historique profond (au-delà des 30 jours HC) et les trous de sync.
  • Fermé/propriétaire : formats CSV à rétro-ingénierer sur échantillons réels (colonnes stables, une ligne par mesure horodatée ; prévoir l'importeur tolérant : détection d'en-têtes + mapping configurable).

4.4 Health Data Export (teqxnology / healthdataexport.com)

  • App d'export manuel/planifié : Apple Health, Health Connect, Google Fit → CSV, JSON, PDF, Excel. Utile ponctuellement pour un dump massif initial ; moins adaptée à une sync continue. Second choix derrière Health Sync pour le fallback fichiers.

4.5 Home Assistant (app companion Android)

  • Depuis la version 2025.5, l'app companion Home Assistant expose des capteurs Health Connect (pas, calories actives/totales, distance, sommeil, poids, FC... ; liste élargie par vagues de 6 capteurs, cf. release notes github.com/home-assistant/android). Flux : app santé → HC → capteurs HA.
  • Limites : capteurs = valeurs instantanées/agrégats du moment, pas des séries historiques propres ; il faudrait ensuite extraire du recorder HA vers LifeTrack (REST API HA + long-lived token). Convoluté, granularité pauvre (pas de séances détaillées, pas de nutrition complète). Pertinent uniquement si l'utilisateur exploite déjà Home Assistant et seulement pour des métriques simples (pas quotidiens). Non retenu comme chemin principal.

4.6 Gadgetbridge

  • Gadgetbridge (app FLOSS pour montres/bracelets) est une source Health Connect, pas un exporteur : depuis la 0.89.0, Réglages > External Integrations > Health Connect permet de pousser Steps et Heartbeat (types supportés à ce jour) vers HC, localement, sans cloud constructeur.
  • Intérêt LifeTrack : si l'utilisateur passe un jour à une montre supportée par Gadgetbridge, ses données rejoignent HC puis LifeTrack via le pont existant — aucun travail supplémentaire côté LifeTrack. Gadgetbridge offre aussi ses propres exports (base SQLite, auto-export) mais ce n'est pas le sujet v1.

4.7 Tableau comparatif des ponts

Solution Type Push vers REST custom ? Auth Types couverts Coût Maintenance/risque
health-connect-webhook App open-source (AGPL) Oui (webhooks POST JSON) Token dans URL seulement 31 Gratuit Actif ; projet jeune
HCGateway App + serveur open-source (GPL) Non (LifeTrack pollerait son API) Login + tokens ~34 Gratuit Actif ; stack Flask/MongoDB/Firebase en plus
Health Sync App commerciale Non (fichiers vers Drive) n/a Large ~4 € une fois Très mature
Health Data Export App commerciale Non (fichiers) n/a Large Freemium OK
Home Assistant companion App open-source Indirect (via HA) Token HA Partiel (capteurs) Gratuit Actif
Gadgetbridge App open-source Non (c'est une source HC) n/a Steps, FC Gratuit Très actif

5. FitShow (tapis de course) et la piste FTMS

5.1 L'app FitShow : capacités et limites

  • FitShow (com.fitshow sur le Play Store) est l'app officielle des équipements embarquant le module Bluetooth FitShow SmartBTM (tapis, vélos, elliptiques, rameurs — marques low-cost/moyennes très répandues). Modes cartes, programmes, objectifs, podomètre.
  • iOS : écrit pas et distance dans Apple Health (HealthKit) — sans objet pour nous.
  • Android : aucune intégration Health Connect ni Google Fit documentée, pas d'export Strava (demandé par les utilisateurs, non implémenté), pas d'export de fichiers (TCX/GPX/FIT) connu. Compte cloud FitShow sans API publique.
  • Verdict : ne pas compter sur FitShow comme source de données. Les séances tapis faites dans FitShow resteront enfermées. Trois contournements : (a) saisie manuelle de la séance dans LifeTrack (v1), (b) enregistrer la séance via une app qui écrit dans HC (ex. app de sport compatible FTMS, ou QZ ci-dessous), (c) capter le tapis directement en BLE (v2/v3, ci-dessous).

5.2 Protocoles BLE : FS (propriétaire) vs FTMS (standard)

  • FTMS (Fitness Machine Service, Bluetooth SIG) est le standard BLE des machines de fitness : service 0x1826, caractéristique Treadmill Data 0x2ACD (notifications : vitesse instantanée en 0,01 km/h, distance totale, inclinaison en 0,1 %, calories, temps écoulé, FC si dispo — champs présents selon un bitfield de flags), Fitness Machine Control Point 0x2AD9 (contrôle vitesse/inclinaison), Fitness Machine Feature 0x2ACC. Supporté par Zwift, Kinomap, Wahoo, Polar, etc.
  • Les machines équipées FitShow parlent le protocole propriétaire "FS" ; beaucoup de modèles récents exposent aussi FTMS (les compatibilités Zwift/Kinomap l'attestent). À vérifier sur le tapis de l'utilisateur avec un scanner BLE (nRF Connect : chercher le service 0x1826). Attention : le tapis n'accepte en général qu'une connexion BLE à la fois (FitShow app OU LifeTrack, pas les deux).
  • QZ (qdomyos-zwift), open-source (https://github.com/cagnulein/qdomyos-zwift), sait parler le protocole FS propriétaire de nombreux tapis et re-exposer un device FTMS virtuel ; il pousse aussi vers Strava/Peloton/Garmin. C'est le plan B si le tapis n'expose pas FTMS nativement.

5.3 Web Bluetooth dans le frontend LifeTrack : faisable

  • Oui, un frontend web peut enregistrer une séance de tapis en direct via Web Bluetooth + FTMS. Des simulateurs de vélo open-source dans le navigateur le font déjà avec des trainers FTMS ; l'API navigator.bluetooth.requestDevice({ filters: [{ services: [0x1826] }] }) puis abonnement aux notifications de 0x2ACD suffit pour un tapis.
  • Contraintes :
    • Navigateurs : Chrome/Edge (desktop et Android) uniquement — pas Firefox ni Safari. Acceptable pour un outil personnel ; à documenter dans l'UI.
    • Contexte sécurisé requis : HTTPS (ou localhost). Le déploiement domestique nginx devra servir en HTTPS (mkcert / CA locale / certificat Let's Encrypt si domaine) pour que le bouton "Connecter le tapis" fonctionne depuis un autre appareil que le serveur.
    • Geste utilisateur requis pour l'appairage (pas de connexion silencieuse au chargement) ; reconnexion à gérer.
  • Design proposé (v2/v3) : composant React TreadmillRecorder — connexion FTMS, échantillonnage ~1 Hz (vitesse, distance cumulée, inclinaison, kcal), graphe live ECharts, à l'arrêt POST de la séance vers /api/v1/workouts (durée, distance, vitesse moy/max, kcal, série de points). Valeur : remplace complètement FitShow pour le tapis et alimente directement le bilan énergétique. Effort : ~1-2 semaines avec l'UI.

6. App companion Android maison (chemin v2 privilégié)

6.1 Faisabilité et briques techniques

  • SDK : Jetpack androidx.health.connect:connect-client (bêta depuis mars 2025, stable pour les usages courants). Kotlin, minSdk 28 (HC APK requis sur Android 9-13 ; natif sur 14+).
  • Manifest : déclarer chaque permission android.permission.health.READ_* nécessaire + READ_HEALTH_DATA_IN_BACKGROUND + READ_HEALTH_DATA_HISTORY ; intent de justification : activité gérant androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE (Android 13-) et alias avec android.intent.action.VIEW_PERMISSION_USAGE + catégorie android.intent.category.HEALTH_PERMISSIONS (Android 14+), affichant la politique de confidentialité (une page statique en français suffit pour un usage personnel).
  • Sync : PeriodicWorkRequest WorkManager (minimum Android : 15 min ; 30-60 min suffisent pour LifeTrack), avec contrainte réseau. Première exécution : lecture complète 30 jours (ou plus avec la permission history) par readRecords paginé ; ensuite sync incrémentale via getChangesToken / getChanges (gère ajouts/modifs/suppressions, économise le quota de rate limiting). Stocker le token ; si expiré (~30 jours), refaire un rattrapage borné.
  • Envoi : POST JSON (OkHttp/Ktor) vers l'endpoint d'ingestion LifeTrack avec Bearer token (vraie authentification, contrairement à health-connect-webhook) ; file de retry persistée (Room ou fichier) pour tolérer serveur éteint / hors LAN ; option "sync seulement en Wi-Fi domestique".
  • Distribution : APK signé localement, sideloadé — pas de compte développeur Google ni de revue Play nécessaire pour un usage personnel (cf. 2.3, à valider sur l'appareil cible en tout début de v2).

6.2 Estimation d'effort

Poste Estimation
Squelette app (Compose, 2 écrans : config serveur/token, état de sync) 1 jour
Intégration HC : permissions + lecture des ~10 types utiles 1-2 jours
WorkManager + changes API + file de retry 1-2 jours
Client HTTP + mapping JSON vers le schéma d'ingestion 0,5-1 jour
Tests sur device réel, edge cases (Doze, OEM battery killers), polish 1-3 jours
Total ~3-5 jours (dev Android expérimenté) à ~2 semaines (montée en compétence incluse)

Risques spécifiques Android : optimisations batterie agressives des OEM (Xiaomi/Huawei/Samsung) pouvant tuer WorkManager → documenter l'exclusion de l'optimisation batterie ; quotas HC en arrière-plan → rester sur la changes API.


7. Classement des chemins d'intégration (effort vs valeur)

# Chemin Effort Valeur Fiabilité Version cible
1 Endpoint d'ingestion REST générique LifeTrack (prérequis de tout le reste) Moyen (backend pur) Très élevée n/a v1
2 health-connect-webhook → endpoint LifeTrack Faible (adaptateur de payload) Élevée (sync auto ~15 min, 31 types) Moyenne+ (fenêtre 48 h, pas d'auth header) v1
3 Import CSV Health Sync (fallback + historique) Faible-moyen (parseurs CSV/TCX) Élevée (rattrapage, robustesse) Élevée v1
4 Saisie manuelle poids/séances/nutrition Déjà prévu (UI) Élevée Élevée v1
5 App companion maison (HC SDK + WorkManager + Bearer) Moyen (3-10 j) Très élevée (contrôle total, auth propre, >48 h, history) Élevée v2
6 Web Bluetooth FTMS (enregistrement tapis dans le navigateur) Moyen (1-2 sem.) Élevée (remplace FitShow, données riches) Moyenne (Chrome/Edge + HTTPS + FTMS dispo sur le tapis) v2/v3
7 HCGateway auto-hébergé Moyen-élevé (2e stack serveur) Moyenne (doublonne #2/#5) Moyenne plan B uniquement
8 Home Assistant companion → HA → LifeTrack Moyen Faible (granularité pauvre) Moyenne non retenu
9 Gadgetbridge (source HC si montre compatible) Nul côté LifeTrack Bonus Élevée opportuniste
10 Google Fit REST API Nulle (arrêt 2026, inscriptions fermées) exclu

8. Recommandation v1 détaillée + contrat d'ingestion proposé

8.1 Périmètre v1

  1. API d'ingestion générique (ci-dessous) + table de payloads bruts + normalisation vers les tables métier (weight_measurements, daily_activity, workouts, nutrition_entries, ...).
  2. Adaptateur health-connect-webhook : endpoint dédié acceptant le format de cette app, token dans l'URL.
  3. Importeurs fichiers via le framework de connecteurs : health_sync_csv (pas, poids, FC, calories), tcx/gpx (séances). Réutilisables pour tout autre export.
  4. Documentation utilisateur (français) : installer health-connect-webhook depuis le Play Store, coller l'URL d'ingestion générée par LifeTrack (avec token), cocher les types de données, régler l'intervalle ; configurer Health Sync en secours.

8.2 Contrat API d'ingestion (à implémenter tel quel)

Principes : push only, idempotent, tolérant, brut d'abord.

  • POST /api/v1/ingest/health — endpoint canonique (utilisé par la future app companion v2 et tout client "propre").
    • Auth : Authorization: Bearer <ingest_token> (token d'ingestion par device, distinct du JWT de session, révocable, stocké haché).
    • Corps : { "source": "companion-app", "device_id": "...", "records": [ { "type": "steps", "external_id": "<hc metadata.id>", "start_time": "...Z", "end_time": "...Z", "value": {...}, "unit": "...", "origin_app": "com.sec.android.app.shealth" }, ... ] }.
    • Réponse : { "accepted": n, "duplicates": m, "rejected": [...] } ; 207-like sémantique, jamais d'échec global pour un record invalide.
  • POST /api/v1/ingest/hc-webhook/{ingest_token}adaptateur health-connect-webhook (l'app ne sait pas poser d'en-tête d'auth → token dans le chemin, transmis en HTTPS uniquement). Accepte le payload natif de l'app (objet avec timestamp, app_version, tableaux snake_case par type), le stocke brut, puis mappe les types connus vers le pipeline canonique.
  • Stockage brut systématique : table raw_ingest_payloads (id, token/device, received_at UTC, source, payload JSONB, processing_status, error). Permet de rejouer la normalisation quand le mapping s'affine — crucial car le schéma exact des ponts tiers peut évoluer.
  • Idempotence / dédoublonnage : contrainte unique (user_id, record_type, external_id) quand un id externe existe (UUID metadata.id HC, transmis par les ponts) ; sinon clé de repli = hash SHA-256 de (record_type, start_time, end_time, origin_app, valeur canonique). Les re-syncs (fenêtre 48 h de health-connect-webhook, ré-imports CSV) deviennent inoffensives.
  • Fuseaux : entrées horodatées ISO-8601 avec offset ; conversion et stockage UTC ; agrégats journaliers calculés en Europe/Paris côté requêtes/vues.
  • Sécurité déploiement domestique : HTTPS obligatoire (nginx), rate limit simple sur les endpoints d'ingestion, tokens révocables depuis l'UI (page « Sources de données »), logs d'ingestion visibles dans l'UI pour diagnostiquer les trous de sync.

8.3 Ordre de vérification à l'implémentation (sans nouvelle recherche produit)

  1. Figer le mapping exact des champs de health-connect-webhook depuis docs/webhook.md du dépôt (et/ou capturer un payload réel avec l'app pointée vers un endpoint de debug).
  2. Générer des exports Health Sync réels (CSV jour/semaine/mois + un TCX de séance) et figer les parseurs sur ces échantillons.
  3. Tester la chaîne Foodvisor → Google Fit → Health Connect → pont pour NutritionRecord ; si KO, la saisie calories reste manuelle en v1.
  4. Scanner le tapis avec nRF Connect pour confirmer la présence du service FTMS 0x1826 (décide la faisabilité du chemin Web Bluetooth v2/v3 sans QZ).

9. Risques et inconnues

  • health-connect-webhook : projet jeune ; schéma de payload non contractuel (d'où le stockage brut + adaptateur isolé) ; absence d'auth par en-tête (token en URL + HTTPS/VPN en mitigation) ; fenêtre 48 h (trous possibles, couverts par CSV).
  • Comportement OEM Android (Doze, battery killers) : peut espacer les syncs de n'importe quel pont ou de l'app maison ; documenter l'exclusion d'optimisation batterie.
  • Fenêtre historique HC de 30 jours : l'historique profond ne viendra jamais de HC sans READ_HEALTH_DATA_HISTORY (et jamais au-delà de ce que les apps sources ont écrit dans HC) → import CSV pour le passé.
  • Sideload + permissions HC sur l'appareil cible : à valider empiriquement en tout début de v2 (aucun blocage connu, mais politique Google mouvante en 2025-2026).
  • FitShow : silo confirmé côté Android ; la valeur du chemin FTMS dépend du matériel réel de l'utilisateur (présence du service 0x1826).
  • Foodvisor → HC : chaîne indirecte via Google Fit, app Google Fit en fin de vie ; fiabilité incertaine.
  • Écosystème mouvant : Google migre l'écosystème (Fit → Health Connect / Google Health API) ; revalider les politiques HC (permissions, quotas) au démarrage de la v2 companion.

10. Sources