From edf3783fb520a1121f8ea275a2241c3b407fa347 Mon Sep 17 00:00:00 2001 From: Sylvain Bettinelli Date: Mon, 29 Jun 2026 05:05:14 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20analyse=20migration=20iOS=20natif=20vs?= =?UTF-8?q?=20hybride=20(aide=20=C3=A0=20la=20d=C3=A9cision,=20ancr=C3=A9e?= =?UTF-8?q?=20inventaire=20r=C3=A9el)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- docs/migration-native-analyse.md | 123 +++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 docs/migration-native-analyse.md diff --git a/docs/migration-native-analyse.md b/docs/migration-native-analyse.md new file mode 100644 index 0000000..f1b8493 --- /dev/null +++ b/docs/migration-native-analyse.md @@ -0,0 +1,123 @@ +# Analyse — migration « iOS pur et dur » (natif SwiftUI) vs hybride actuel + +**Date** : 2026-06-29 +**Statut** : aide à la décision (aucun code engagé) +**Demandé par** : Sylvain — « sinon on migre mon application iOS pur et dur » +**Méthode** : estimations ancrées sur l'inventaire réel du code (pas d'extrapolation). + +--- + +## 0. TL;DR + +- **Le backend ne bouge pas** dans aucun scénario : `coach_sportif` (~9 600 lignes Python) est déjà une API + des intégrations. Il sert aussi bien une WebView qu'une app native. +- **Ce qu'une migration native jette / réécrit** : tout le **front** — ~14 900 lignes de templates, ~10 000 lignes de CSS, ~2 800 lignes de JS séparé (+ beaucoup de JS inline dans les pages). Mature, itéré pendant des mois. +- **Coût réaliste d'un rewrite SwiftUI à parité** (dev solo) : **~5 à 8 mois** plein temps, **iOS seulement**. Atteindre la parité Android en plus = quasi le même effort en Compose, ou abandonner Android. +- **Recommandation** : **ne pas faire de big-bang natif.** Soit rester hybride avec des îlots natifs ciblés (déjà ta trajectoire), soit, si tu veux vraiment du natif, une **migration incrémentale page-par-page** (« strangler ») étalée — mais elle a un coût de complexité propre (cf. §6). + +--- + +## 1. Ce que tu as aujourd'hui (hybride Capacitor) + +| Brique | Volume | Sort en cas de rewrite natif | +|---|---|---| +| Backend FastAPI (`web/app.py` + `web/routers/`) | ~9 600 lignes | **Conservé** (devient l'API du natif) | +| Templates Jinja (pages) | 26 pages, ~14 900 lignes | **Réécrit en SwiftUI** | +| CSS design system (`style.css` + `critical.css`) | ~10 000 lignes | **Jeté** (refait en SwiftUI/tokens) | +| JS client (`web/static/*.js`) | ~2 800 lignes | **Réécrit en Swift** | +| JS inline dans les templates | gros (ex. `meals.html` ≈ 2 900 lignes dont bcp de JS) | **Réécrit en Swift** | +| Libs front (Chart.js, Leaflet) | vendor | Remplacé par **Swift Charts** / **MapKit** | +| Plugins natifs déjà écrits | 8 (HealthKit, WorkoutKit, Live Activity, watchOS, auth Apple/Google…) | **Conservés/réutilisés** | +| Wrapper Android + PWA Windows | partagé avec le web | **Perdu** (ou à maintenir à part) | + +**Atouts hybride** que la migration sacrifie : +- **1 base UI → 3 cibles** (iOS, Android, PWA) servies par le même web. +- **Déploiement instantané sans review Apple** (l'app charge la prod en direct) : ~95 % de tes itérations ne touchent pas le Mac. +- Déjà en TestFlight, déjà fonctionnel. + +--- + +## 2. Effort de réécriture, page par page (ancré sur le volume réel) + +Échelle indicative pour **un dev solo**, à parité fonctionnelle + tests device (charts = Swift Charts, cartes = MapKit, formulaires natifs) : + +### Pages lourdes (le gros du coût) +| Page | Lignes | Pourquoi c'est lourd | Estim. | +|---|---|---|---| +| `meals` | 2 878 | Scan code-barres, recherche FatSecret + Open Food Facts, fiche aliment, hydratation, analyse Coach IA, modales | **3–4 sem** | +| `calendar` | 2 610 | Modales séance, segments, rappels locaux, export ICS, vues semaine/jour, états « fait/auto » | **3–4 sem** | +| `workout` (détail) | 1 950 | Carte Leaflet (trace GPS), graphes FC/puissance/zones, laps, comparaison de trajets | **2–3 sem** | +| `body` | 1 084 | Graphes multi-métriques, Withings, saisie manuelle | **1.5–2 sem** | +| `settings` | 1 135 | Intégrations (connexions OAuth), debug plugins natifs, prefs | **1.5–2 sem** | +| `sleep` | 783 | Graphes sommeil, sources HealthKit | **1–1.5 sem** | +| `live_workout` | 323 | Temps réel (déjà fortement natif via CoachLive*) | **0.5–1 sem** | + +### Pages moyennes +`home` (286), `forme` (428), `workouts` (402), `hrv` (396), `week` (376), `profile` (395), `stats` (232), `reviews`+`review_detail` (283) — graphes, listes, navigation. **≈ 3–5 jours chacune** → ~**4–6 sem** cumulées. + +### Pages simples +`login`, `register`, `reset_password`, `privacy`, `usage`, `icons*`, `dashboard*` — **0.5–1 j chacune** → ~**1 sem**. + +### Transverse (à faire une fois, mais incompressible) +- **Design system SwiftUI** réimplémentant les tokens `--c-*`/`--radius-*` + composants `.ap-*` : **2–3 sem**. +- **Navigation / tab bar / TileManager** (perso. d'accueil) en SwiftUI : **1–2 sem**. +- **Couche réseau + modèles + auth** (consommer l'API, session JWT, gestion offline/cache) : **2–3 sem**. +- **Coach IA chat** (streaming SSE, outils) en natif : **1–2 sem**. + +**Total iOS seul (parité) : ≈ 5–8 mois** plein temps solo, hors imprévus device/App Store. C'est un ordre de grandeur, pas un devis. + +--- + +## 3. Ce qu'on garde / ce qu'on jette + +**On garde (déjà fait, réutilisable tel quel)** +- Tout le **backend** + intégrations (Polar/Bosch/Withings/TP/FatSecret), auth multi-user JWT, Coach IA serveur. +- Les **8 plugins natifs** : HealthKit (`CoachHealthRoute`), WorkoutKit, Live Activity, watchOS (`CoachWatch`/`CoachLiveBridge`), Sign in Apple/Google. En natif ils deviennent des services directs (plus besoin du pont Capacitor). + +**On jette / réécrit** +- 100 % du front web (HTML/CSS/JS), soit ~25 000 lignes cumulées de code mûr. +- L'avantage « déploiement sans review ». +- Le partage de code avec **Android** et la **PWA**. + +--- + +## 4. Impact Android / PWA (souvent l'angle mort) + +Aujourd'hui, iOS, **Android** (Health Connect) et **PWA Windows** partagent le même front web. Un rewrite **iOS natif** : +- **Casse la parité** : Android resterait sur le wrapper web → tu te retrouves avec **2 fronts** (SwiftUI + web) à maintenir en parallèle, divergents. +- Pour re-parité Android native, il faudrait **Jetpack Compose** = un second rewrite d'ampleur comparable. +- La **PWA** disparaît du périmètre natif. + +→ Le coût réel d'un « tout natif » multi-plateforme n'est pas « 1 rewrite » mais potentiellement « 2 rewrites + le web maintenu pour la PWA ». + +--- + +## 5. Risques + +- **Tunnel** : 5–8 mois sans valeur livrable visible pendant que le produit (pivot commercial FR) doit avancer. Risque #1 pour un solo. +- **Régressions** : tu réécris des comportements subtils déjà debuggés (Safari Date, caches SW, états calendar, footguns HealthKit…). Chaque page = re-tester sur device. +- **Dépendance Mac/review** sur chaque correctif (perte de vélocité). +- **Double maintenance** pendant la transition (le natif et le web coexistent forcément un moment). +- **Coût d'opportunité** : ces mois ne vont pas dans les features qui différencient (Coach IA, agrégateur, intégrations). + +--- + +## 6. Les 3 options, honnêtement + +### Option A — Rester hybride + îlots natifs (recommandé) +Garder la WebView, ajouter du natif **uniquement là où ça paie** : widgets, complications Watch, écrans temps réel (déjà fait pour le live), animations clés. **Coût : jours/semaines par îlot. Aucune perte.** C'est ta trajectoire actuelle. + +### Option B — Migration incrémentale « strangler » (si tu veux vraiment du natif) +Remplacer **page par page** : on garde la WebView comme coquille et on substitue une vue **native** pour une route donnée (le wrapper route vers du SwiftNav au lieu de la WebView). Tu commences par 1–2 pages à fort enjeu UX (ex. `home` + `live`), tu mesures le gain réel, tu décides de continuer ou non. **Avantage** : valeur livrable en continu, réversible, pas de big-bang. **Inconvénient** : période de cohabitation web/natif à gérer (navigation, auth, état partagé). + +### Option C — Big-bang « tout natif » +Le rewrite complet décrit ci-dessus. **5–8 mois iOS, Android/PWA sacrifiés ou doublés.** Justifié seulement si l'app devient le cœur du business ET que la WebView est un plafond de verre prouvé (perf/UX), ET que tu as le temps/les moyens. **Pour un solo en phase de pivot : déconseillé.** + +--- + +## 7. Recommandation + +1. **Ne pas lancer de big-bang (Option C) maintenant.** +2. Si l'envie de natif vient d'**irritants précis** (perf d'une page, feeling de scroll, bug WebView) → **Option A**, on cible l'îlot. Commençons par les **widgets** (déjà cadrés) puis l'îlot qui te gêne le plus. +3. Si tu veux *stratégiquement* tendre vers le natif sans tout risquer → **Option B**, on fait **1 page pilote** (je suggère `home` ou `live`) et on juge sur pièce avant d'investir plus. + +**Prochaine étape proposée** : tu choisis A ou B. En A, je reprends le scaffold des 2 widgets iPhone. En B, je scope la page pilote (archi de cohabitation WebView↔SwiftUI, auth/état partagés, routeur) avant de coder.