docs: analyse migration iOS natif vs hybride (aide à la décision, ancrée inventaire réel)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
123
docs/migration-native-analyse.md
Normal file
123
docs/migration-native-analyse.md
Normal file
@@ -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.
|
||||
Reference in New Issue
Block a user