Files
coach-ios/docs/migration-native-analyse.md
2026-06-29 05:05:14 +00:00

8.3 KiB
Raw Permalink Blame History

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 34 sem
calendar 2 610 Modales séance, segments, rappels locaux, export ICS, vues semaine/jour, états « fait/auto » 34 sem
workout (détail) 1 950 Carte Leaflet (trace GPS), graphes FC/puissance/zones, laps, comparaison de trajets 23 sem
body 1 084 Graphes multi-métriques, Withings, saisie manuelle 1.52 sem
settings 1 135 Intégrations (connexions OAuth), debug plugins natifs, prefs 1.52 sem
sleep 783 Graphes sommeil, sources HealthKit 11.5 sem
live_workout 323 Temps réel (déjà fortement natif via CoachLive*) 0.51 sem

Pages moyennes

home (286), forme (428), workouts (402), hrv (396), week (376), profile (395), stats (232), reviews+review_detail (283) — graphes, listes, navigation. ≈ 35 jours chacune → ~46 sem cumulées.

Pages simples

login, register, reset_password, privacy, usage, icons*, dashboard*0.51 j chacune → ~1 sem.

Transverse (à faire une fois, mais incompressible)

  • Design system SwiftUI réimplémentant les tokens --c-*/--radius-* + composants .ap-* : 23 sem.
  • Navigation / tab bar / TileManager (perso. d'accueil) en SwiftUI : 12 sem.
  • Couche réseau + modèles + auth (consommer l'API, session JWT, gestion offline/cache) : 23 sem.
  • Coach IA chat (streaming SSE, outils) en natif : 12 sem.

Total iOS seul (parité) : ≈ 58 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 : 58 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 12 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. 58 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.