Skip to content

Site Web

Ilan Amzallag edited this page Sep 29, 2026 · 2 revisions

Site web

Statut : 🟢 Architecture validée par Ilan le 2026-09-28 · Tickets : epic #235 (#233 socle, #236 à #243, #234) · Maquette : E-21

Le site sert trois choses : faire installer l'app (landing), ouvrir un parcours partagé (/r/:id, repli des liens universels) et publier les textes légaux. Il n'y a pas de version web d'un parcours. Modèle de départ : la landing Inprogress (inprogress-landing-v2), dont on garde la structure et le référencement, en retirant ce qui alourdit ou ne tient pas sur Cloud Run (voir « Écarts avec le modèle »).

Stack

Couche Choix Pourquoi
Framework Next.js (App Router), TypeScript strict, React Server Components par défaut rendu serveur pour l'aperçu des liens et le référencement ; même langage et mêmes types que l'API
Emplacement apps/web du monorepo pnpm ; types et libellés partagés via packages/shared un seul dépôt, une seule CI, pas de copie de types
Style Tailwind uniquement, thème généré depuis tokens.json (même source que NativeWind dans l'app) ; clsx pour les classes conditionnelles zéro coût à l'exécution, compatible avec les composants serveur ; aucune couleur en dur
Langues français et anglais dans l'URL (/fr/…, /en/…, / redirige selon Accept-Language), traductions chargées côté serveur, hreflang et canonical sur chaque page chaque langue est indexée ; rien ne dépend d'un cookie ni du JavaScript
Animation CSS et Web Animations (tracé en stroke-dashoffset, apparitions), prefers-reduced-motion respecté ; pas de GSAP ni de framer-motion aucune bibliothèque d'animation dans le bundle de la landing
Données API Widoo en lecture (#239), appelée côté serveur uniquement, jamais depuis le navigateur pas de clé ni de CORS côté client, cache maîtrisé
Hébergement Cloud Run (europe-west9), image Docker output: 'standalone', instance minimale 1 en prod ; Cloud CDN (load balancer) devant pour /_next/static, images et pages mises en cache même plateforme que l'API, pas de démarrage à froid sur la landing, montée en charge horizontale
Mesure clics vers les stores et ouvertures /r/ comptés sans cookie (événement serveur vers PostHog, sans identifiant persistant) ; pas de GTM, pas de bannière de consentement décision d'Ilan du 2026-09-28
Erreurs Sentry (projet web) ; error.tsx dessiné (#187) ; not-found.tsx : page introuvable légère (E-21, D-074), statut 404, noindex

Rendu et cache

  • Landing : générée statiquement par langue ; blocs de données (parcours d'exemple, notes, avis) revalidés toutes les heures (ISR) et à la demande par l'API quand l'équipe change la sélection.
  • /r/:id : rendu serveur, mis en cache 5 minutes ; revalidation à la demande quand le parcours est modifié, dépublié ou retiré ; Cache-Control public pour les parcours publics, private, no-store pour un lien privé (share_token). Un identifiant inconnu rend l'encart « Ce parcours n'est plus disponible » puis la landing, avec un statut 404 (E-21, D-068) ; toute autre adresse inconnue rend la page introuvable (not-found.tsx, D-074). Parcours Premium : pastille et ligne Premium, étapes 2 à 4 sans leur nom (l'API du site ne les envoie pas, #239).
  • Pages légales : statiques, revalidées quand GET /legal/:doc change de version.
  • Images : next/image (AVIF, WebP, tailles adaptées), photos des parcours servies depuis Cloud Storage via le CDN ; images décoratives en SVG en ligne.
  • Polices : Plus Jakarta Sans via next/font (auto-hébergée, sous-ensembles latins, display: swap), deux graisses (500, 800).

Référencement

  • lib/seo.ts : un constructeur de métadonnées (titre 50 à 60 caractères, description 110 à 160, canonical, alternates.languages, Open Graph, Twitter), repris du modèle.
  • Données structurées JSON-LD : Organization (Inprogress Agency, éditeur), WebSite, MobileApplication (iOS et Android, liens des stores) ; sur /r/:id public, TouristTrip ou ItemList des étapes sans leur détail (parcours Premium : départ seul nommé, D-074).
  • sitemap.ts (landing, pages légales, /r/ des parcours publics, par langue) et robots.ts ; /r/ d'un parcours privé en noindex.
  • Image Open Graph de /r/:id générée à la volée (ImageResponse) : photo, titre, durée, budget, logo.
  • Middleware : domaine canonique (redirige www et l'ancien domaine en 308), redirection de langue sur /, en-têtes de sécurité (CSP stricte, HSTS, X-Content-Type-Options, Referrer-Policy).

Liens universels et redirections

  • /.well-known/apple-app-site-association et /.well-known/assetlinks.json servis par le site (#241), sans redirection et en application/json.
  • /app : redirige vers l'App Store ou Google Play selon le téléphone, vers la landing sur ordinateur.
  • Paramètre src conservé de /r/ jusqu'au store pour la mesure et le lien différé (#234).

Architecture des fichiers (reprise du modèle)

  • app/[locale]/ : routes seulement (pages fines, métadonnées) ; app/r/[id]/, app/app/, app/.well-known/.
  • containers/ : assemblage d'une page ; components/ : blocs réutilisables (sections/, ui/) ; lib/ : seo, api, analytics, i18n ; config/ : constantes du site (domaine, liens des stores, par variable d'environnement) ; messages/fr, messages/en : textes.
  • Règles (à reprendre dans apps/web/AGENTS.md) : composants serveur par défaut, 'use client' seulement pour l'interactif (questions, sélecteur de langue) ; aucun texte en dur, clés de traduction en notation pointée ; aucune couleur en dur ; alias @/ ; aucune requête réseau depuis un composant client.

Budgets et contrôles de qualité

  • Landing au téléphone (4G simulée) : LCP < 2,5 s, CLS < 0,1, INP < 200 ms ; JavaScript envoyé < 100 Ko compressés ; Lighthouse ≥ 90 en performance, accessibilité, bonnes pratiques et référencement.
  • CI : lint, typecheck, build, Lighthouse CI sur la landing et un /r/ de démonstration, test des fichiers .well-known, vérification qu'aucun cookie n'est déposé.
  • Préversion par PR (déploiement Cloud Run étiqueté) pour relire sur téléphone.

Écarts avec le modèle (inprogress-landing-v2)

  • Retirés : Redux, RTK Query et redux-persist (inutiles pour un site sans état) ; styled-components (coût à l'exécution, incompatible avec les composants serveur) ; GTM et Axeptio (pas de cookie) ; @vercel/speed-insights et réglages propres à Vercel (hébergement Cloud Run) ; langue par cookie et i18next côté client (remplacés par la langue dans l'URL) ; JavaScript (TypeScript strict).
  • Gardés : App Router, découpage routes / containers / components / config / lib, constructeur de métadonnées et JSON-LD, sitemap, robots, middleware de domaine canonique, pages d'erreur, formats d'image AVIF et WebP, fichier AGENTS.md de règles et contrôles de qualité avant fusion.

Montée en charge

Cloud Run monte en instances selon le trafic, la landing et les /r/ publics sont servis par le CDN, et l'API n'est appelée qu'à la revalidation : un pic de trafic (article, QR codes) touche le cache, pas la base. Pour une nouvelle ville, les pages /r/ et la landing ne changent pas ; une page par ville (/fr/lyon) s'ajoute avec le même gabarit.

Clone this wiki locally