Le problème du SPA monolithique

La version initiale de TravelPlan était un seul fichier HTML de 800 lignes servi à /planner/. Fonctionnel, mais avec des limitations :

  • URL unique non bookmarkable par section
  • Impossible de lier directement vers “Réservations” ou “Budget”
  • Tout le JavaScript chargé d’un coup, même pour des sections non utilisées
  • Pas de séparation des préoccupations

La solution : cinq applications, un état partagé

Chaque onglet de la barre de navigation gauche est désormais une application web autonome à son propre URL :

AppURLRôle
Voyage/Formulaire de planification, entrée principale
Réservations/reservations/Gestionnaire de réservations + extraction IA
Budget/budget/Enveloppe totale, répartition par poste
Guide IA/ia/Génération de fiches depuis texte, liens, PDF
Mes Fiches/fiches/Collection de fiches voyage générées

État partagé via localStorage

Toutes les apps lisent et écrivent dans le même objet JSON sous la clé travelplan_v1 :

{
  title: "Mon Guide Voyage",
  blocs: [...],           // blocs générés par l'IA
  resas: [...],           // réservations
  budgetCats: {...},      // répartition budgétaire
  budgetCur: "€",
  budgetTotal: 3000,
  form: {                 // état du formulaire de voyage
    dest: "Malaisie...",
    from: "Koh Samui",
    pax: "4",
    ...
  }
}

L’avantage : naviguer entre les pages ne perd aucune donnée. L’IA génère une fiche dans /ia/, redirige vers /fiches/ — les données persistent.

Architecture Hugo

Chaque app utilise un layout Hugo dédié avec un partial partagé pour la navigation :

layouts/
  index.html              → App Voyage (homepage)
  reservations/list.html  → App Réservations
  budget/list.html        → App Budget
  ia/list.html            → App Guide IA
  blocs/list.html         → App Mes Fiches
  partials/
    planner-head.html     → <head> commun
    planner-topbar.html   → Barre du haut (logo, titre, actions)
    planner-sidenav.html  → Navigation latérale
    planner-modals.html   → Modales partagées (résumé IA, partage)

static/
  css/planner.css         → Styles partagés
  js/state.js             → État, API Claude, fonctions communes

Le fichier state.js centralise :

  • tpGet() / tpSet() — lecture/écriture localStorage
  • tpClaude() — appels à l’API Anthropic
  • tpExportPDF() — export depuis l’état complet
  • tpShare() — génération de lien de partage
  • tpSummary() — résumé IA du voyage
  • tpInitTopbar() — initialisation commune de la topbar

Topbar persistante : le titre de guide

Le titre du guide, visible dans la topbar sur chaque page, est synchronisé avec l’état. Modifier le titre sur n’importe quelle page le met à jour dans toutes les autres.

Blog intégré dans le même site Hugo

Le blog développeur coexiste avec les apps dans le même projet Hugo. Les pages /blog/* utilisent le thème PaperMod standard, les apps utilisent leurs propres layouts fullscreen. Les deux coexistent sans conflit grâce à l’organisation des layouts par section.

Prochaine étape — Semaine 3

  • Carte interactive dans la vue Blocs (Leaflet.js avec les coordonnées GPS des fiches)
  • Drag & drop pour réordonner les fiches
  • Export vers un format partageable lisible sans l’app (page HTML autonome)
  • Authentification optionnelle pour la synchronisation entre appareils

TravelPlan est open source — github.com/alx/travelPlan