# 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.