Aller au contenu
valentinbourreau

BRUT, le site d’un camion qui change d’adresse chaque semaine

Le site de BRUT, un food truck de bouchées à Tours : dire où trouver le camion, donner faim, récolter des inscrits et des avis. Et surtout, un site que son fondateur modifie seul, sans développeur, même quand je suis à l’autre bout du monde.

8 min de lecture

Accueil du site de BRUT : logo, accroche « C’est bon parce que c’est vrai » et bouton « Où on est cette semaine », sur l’image d’attente de la vidéo.
Le haut de l’accueil, sur son image d’attente : une vidéo plein écran prend le relais dès qu’elle peut jouer.
client
BRUT, « la bouchée française », food truck à Tours
rôle
Conception, développement, accompagnement du client.
période
20 sept. → 14 oct. 2026, au rythme des retours du client
stack
Next.js 16, Tailwind v4, shadcn/ui · Neon · Vercel, BotID, Web Analytics · Brevo · Tiptap
en chiffres
47 commits, ~14 000 lignes de TypeScript, 137 tests, 19 pages de documentation

01 · contexte

Un camion, cinq adresses

BRUT vend des bouchées frites, croustillantes dehors et fondantes dedans, trois recettes et une seule sauce, depuis un camion qui s’installe chaque semaine à un endroit différent de l’agglomération de Tours. La première question d’un client n’est pas « c’est quoi ? », c’est « vous êtes où cette semaine ? ».

Le brief tenait en quatre verbes : dire où trouver le camion, donner faim, récolter des inscrits pour annoncer les dates, récolter des avis. Une contrainte a tout organisé : je partais un an à l’étranger. Le fondateur devait pouvoir changer une date, un prix ou une photo sans moi, et sans rien casser.

02 · produit

Ce que voit le visiteur

Une page d’accueil qui se lit de haut en bas comme une visite au camion : une vidéo, le rituel (prends, trempe, croque), les trois recettes, la carte, les emplacements, la newsletter, le contact. Trois versions de cette page ont été montées côte à côte pour que le client choisisse ; la troisième a gagné.

Le rituel en trois étapes numérotées, puis les trois recettes et la sauce, chacune avec sa photo en gros plan.
Le rituel et les recettes. Au survol, ou au toucher sur téléphone, chaque photo montre l’intérieur de la bouchée.

Les emplacements, sans carte interactive

La première version utilisait une carte Leaflet. Elle a été remplacée par un plan illustré de l’agglomération, une simple image, avec des pastilles numérotées : plus léger, plus beau, et plus lisible pour cinq points. Chaque pastille ouvre une bulle avec la période, le lieu et les horaires.

Les dates sont saisies avec un début et une fin : les emplacements passés disparaissent seuls, sans que personne n’ait à les retirer. Et « Y aller » ne choisit pas à la place du visiteur : il propose Google Maps, Plans, ou de copier l’adresse.

Section « Où nous trouver » : plan illustré de l’agglomération de Tours avec cinq pastilles numérotées, et la liste des dates avec lieu, horaires et lien « Y aller ».
« Cinq dates, sept semaines, un camion. » Chaque numéro de la liste répond à une pastille du plan.

La page /menu reprend le visuel de la carte imprimée du camion, pour qu’on y retrouve en ligne exactement ce qu’on lit au comptoir.

Page /menu : les trois recettes avec leur couleur, les formules et les boissons, présentées comme la carte imprimée du camion.
La carte en ligne. Chaque prix se modifie dans l’admin.

03 · architecture

L’architecture

Un site vitrine, mais dont tout le contenu vit en base. L’équation à résoudre : des pages aussi rapides qu’un site statique, et modifiables comme un CMS, sans payer un CMS.

Architecture du site BRUT : le visiteur reçoit des pages pré-rendues depuis le cache du contenu, sans requête en base. Les formulaires passent par des routes d’API protégées par BotID et écrivent dans Neon, puis vers Brevo. Le fondateur modifie le contenu dans /admin ; « Publier » renouvelle le cache. Une tâche de nuit resynchronise Brevo.
Le visiteur ne touche jamais la base : il reçoit des pages pré-rendues. Seuls les formulaires écrivent, et seule une publication renouvelle le cache.

La pièce centrale est une seule fonction de lecture, marquée "use cache" et étiquetée site-content grâce aux Cache Components de Next.js 16. Les pages publiques sont pré-rendues avec son résultat et servies depuis le CDN. Le bouton « Publier » de l’admin invalide cette étiquette : la visite suivante relit la base, puis tout le monde reçoit la nouvelle version. Le sitemap et les données structurées suivent le même cycle.

Si la base est injoignable, le site affiche les valeurs par défaut écrites dans le code et réessaie quelques minutes plus tard. Il ne tombe jamais en panne parce que Neon tousse.

04 · admin

Une admin pensée pour le camion

L’admin est la moitié du projet, et celle que le fondateur utilise chaque semaine. Elle tient en deux écrans : un tableau de bord pour savoir comment ça va, et l’édition du contenu pour changer ce que voient les visiteurs. Elle reprend la charte du site, pour qu’il s’y sente chez lui plutôt que dans un back-office.

Le tableau de bord : tout, en un coup d’œil

En haut, quatre chiffres avec leur tendance sur trente jours : inscrits à la newsletter, messages reçus, avis clients, note moyenne. Dessous, l’activité jour par jour, les trois formulaires empilés ; un clic sur un chiffre isole sa courbe. Tous les calculs sont faits par la base, en une requête par bloc : rien n’est recompté dans le navigateur.

Tableau de bord de l’admin : quatre chiffres clés avec leur tendance sur trente jours, puis un graphique en barres empilées de l’activité par jour.
Le haut du tableau de bord. Les données de ces captures sont fictives : la vraie admin reste privée.

Ce que disent les avis

Les avis du QR code ne finissent pas dans un tableur qu’on ne relit jamais. Le tableau de bord les lit pour lui : répartition des notes, part de clients qui reviendraient, prix, attente et accueil sur un même graphique, note de chaque recette, emplacements les plus cités. Une phrase repère le point faible du moment, « Point à surveiller : le prix », pour qu’il n’ait pas à le chercher.

Analyse des avis : répartition des notes, part de clients qui reviendraient, notes sur le prix, l’attente et l’accueil, note par recette et par emplacement.
L’analyse des avis : notes, retour, expérience, produits et emplacements. Les graphiques sont ceux de shadcn/ui, recolorés à la charte BRUT.

Plus bas, la provenance des inscrits et les motifs des messages, la fréquentation du site lue dans Vercel Web Analytics, puis le détail ligne par ligne : inscrits, messages et avis en onglets, avec ajout, modification, suppression et export CSV ou Excel. Un bouton resynchronise la newsletter avec Brevo à la demande.

L’édition du contenu : un schéma, des formulaires

Tous les textes, prix, dates et chemins de photos sont décrits une seule fois, dans un schéma. Ce schéma génère les dix-sept sections du formulaire, valide la saisie côté serveur et type le contenu que lisent les composants. Chaque champ porte une aide écrite pour le fondateur, pas pour un développeur : « L’emplacement disparaît du site le lendemain. » Ajouter un champ, c’est une ligne de schéma et une valeur par défaut ; le formulaire suit.

Édition du contenu, section du bandeau d’accueil : champs texte et éditeur limité au gras, bouton « Publier sur le site » en haut.
Édition du contenu, section des emplacements : chaque date avec début, fin, lieu, adresse et horaires, réordonnable.
Deux des dix-sept sections : le bandeau d’accueil, avec son éditeur limité au gras, et les emplacements, réordonnables. Le bouton « Publier sur le site » reste visible en haut de l’écran.
  • Enregistrer n’est pas publier.

    Le fondateur prépare plusieurs sections, les relit, et ne met en ligne qu’au moment voulu. Une ligne en haut de l’écran dit toujours si le site affiche la dernière version.

  • Du gras, et rien d’autre.

    Les accroches comme « C’est bon parce que c’est vrai. » passent par un éditeur Tiptap limité au gras, stocké en texte, jamais en HTML. Impossible de casser la mise en page.

  • Protégée deux fois.

    Un mot de passe à l’entrée, puis une vérification dans chaque page et chaque action : on ne compte jamais sur la seule porte d’entrée. Pages hors des moteurs, jamais mises en cache, aucune donnée d’inscrit dans les journaux.

05 · formulaires

Inscrits, avis, messages

Trois formulaires, un seul chemin. Chaque envoi passe par Vercel BotID, un champ piège invisible et un délai minimal de remplissage, puis s’écrit dans Neon avant toute autre chose. Les inscrits sont ensuite recopiés dans Brevo, après la réponse au visiteur ; les désinscriptions reviennent par webhook, et une tâche de nuit resynchronise le tout. Une seule liste d’inscrits existe, où qu’on s’inscrive.

Les avis arrivent par un QR code collé sur le camion. La page qu’il ouvre n’est ni dans la navigation ni dans les moteurs de recherche : deux minutes, une note, les recettes goûtées. Le bouton vers les avis Google s’affiche pour tout le monde, quelle que soit la note : c’est une exigence de Google, et c’est plus honnête.

Page /qr sur téléphone : liens vers le site, la page d’avis, la newsletter et Instagram.
Page /avis sur téléphone : note en étoiles, recettes goûtées et bouton vers les avis Google.
La page du QR code et la page d’avis, sur téléphone. Avis et messages partent aussi par mail au camion, avec une ligne dans son tableur.

06 · finitions

Les détails qui comptent

  • Une vidéo qui démarre vraiment.

    Deux encodages (HEVC pour les écrans Retina, H.264 en secours), une version tournée d’un quart de tour pour les téléphones en portrait, une image d’attente floutée. Et un bug iOS débusqué : un élément vidéo sans source dans le rendu serveur faisait apparaître le bouton de lecture natif.

  • Des photos préparées à la main.

    1 600 px de large pour les écrans denses, profil sRGB, compression mozjpeg : une vidéo source de 254 Mo est devenue une quinzaine de mégaoctets.

  • Les fonctions à Francfort,

    à côté de la base, plutôt qu’aux États-Unis par défaut.

  • Deux audits avant de dire « fini ».

    Performance et sécurité d’abord (une faille critique corrigée par une mise à jour de Next.js, des en-têtes de sécurité), puis un audit réglementaire : politique de confidentialité complète, médiateur de la consommation, prestataires nommés.

  • Un référencement local.

    Données structurées d’établissement de restauration et de carte, générées depuis le contenu, et un sitemap daté de la dernière publication.

07 · performances

Mesurer, puis alléger

Un site de food truck se consulte debout, sur un téléphone, avec la 4G qu’on trouve sur un parking. Je l’ai donc mesuré dans de mauvaises conditions : Lighthouse, un téléphone milieu de gamme émulé, une 4G lente simulée, trois passages par page en production, et la médiane. Puis j’ai allégé ce qui pesait, et mesuré de nouveau.

score mobile
87 → 98
lcp accueil
4,0 → 2,4 s
poids hors vidéo
−44 %
images
−55 %
ordinateur
100 / 100
Score de performance Lighthouse sur mobile, avant puis après : accueil 87 puis 98, /menu 92 puis 100, /avis 91 puis 100, /qr 92 puis 99. Sur ordinateur, 100 partout.
Les quatre pages publiques, avant et après la version 1.1.0. Sur ordinateur, le score était déjà de 100 partout, et il l’est resté.

Le point faible était le LCP, le temps d’affichage du plus grand élément visible : 4 secondes sur l’accueil, au-delà des 2,5 s que Google considère comme bonnes. Avec la version 1.1.0, les quatre pages passent sous la barre.

LCP mobile avant puis après : accueil 4,0 puis 2,4 s, /menu 3,3 puis 1,9 s, /avis 3,5 puis 1,8 s, /qr 3,3 puis 2,0 s. Les quatre pages passent sous le seuil de 2,5 s.
LCP mobile, médiane de trois passages. Sur l’accueil, l’élément mesuré est le titre du haut de page.

Cinq changements, rien de visible

  • Des images en AVIF,

    avec le WebP en secours : la photo de La Bête passe de 210 à 83 Ko.

  • Une seule image d’attente pour la vidéo,

    dans une balise picture qui choisit le paysage ou le portrait, au lieu de deux images préchargées.

  • Des logos à la bonne taille.

    Faute d’attribut sizes, ils partaient en 1 920 px de large pour 72 à 360 px affichés.

  • La vidéo après la page.

    Elle n’est posée qu’une fois la page chargée, et jamais en mode économie de données, en 2G, ni quand le visiteur demande de réduire les animations.

  • La police italique n’est plus préchargée :

    le navigateur ne télécharge que ce qui s’affiche.

Poids de l’accueil sur mobile hors vidéo : 1 557 Ko avant, 870 Ko après, soit −44 %. Images 989 puis 447 Ko, polices 292 puis 148 Ko, JavaScript 226 Ko inchangé.
Hors vidéo, l’accueil passe de 1 557 à 870 Ko. Le JavaScript n’a pas bougé : tout le gain vient des images et des polices.
Requêtes réseau de l’accueil sur un passage de chaque version. Avant, la vidéo démarre à 0,37 s, pendant le chargement des images. Après, elle démarre à 2,39 s, une fois les images chargées.
Un passage de chaque version, requêtes réseau observées. Avant, la vidéo de 10 Mo partait pendant le chargement des images ; avec la 1.1.0, elle attend la fin du chargement et ne dispute plus la bande passante à ce qui s’affiche.

Ce que j’ai essayé, puis écarté

  • La CSS dans le HTML.

    Un aller-retour réseau gagné, mais la CSS était recopiée dans la charge RSC : le HTML compressé de l’accueil passait de 17 à 65 Ko.

  • La vidéo réencodée.

    10 Mo devenaient 4, au prix de blocs visibles sur les bulles de friture. Un réencodage se fait depuis l’original 4K, pas depuis le fichier publié.

  • Une police allégée.

    Retirer l’axe de taille optique de Newsreader divisait la police par deux, mais changeait le dessin des grands titres. Le choix typographique l’a emporté.

méthode

Lighthouse 13.5, trois passages par page en production, médiane retenue. Mobile : Moto G Power émulé, 4G lente simulée, processeur ralenti quatre fois. Aucun décalage de mise en page (CLS 0), un serveur qui répond en 5 à 16 ms grâce aux pages pré-rendues, accessibilité de 96 à 100, bonnes pratiques et référencement à 100 sur les pages indexées.

08 · passation

Passer la main

Pour ce qui dépasse l’admin, j’ai préparé une passation à quelqu’un qui ne code pas. Un fichier de consignes pour un assistant de code : parler sans jargon, annoncer avant d’agir, une question à la fois, toujours proposer l’admin avant de toucher au code, et ne jamais mettre en ligne sans un « oui » explicite. Il suffit d’ouvrir le dossier et d’écrire « mets en ligne » ou « change le prix de la boîte de 5 ».

Derrière, le filet de sécurité : une documentation d’une page par sujet, un journal où chaque demande tient sur une ligne, et 137 tests (unitaires, puis parcours sur ordinateur et téléphone) relancés à chaque push, plus des tests de fumée sur le site en ligne après chaque mise en production.

Mon objectif : rendre mes clients autonomes.
durée
3 semaines
commits
47
lignes de ts
~14 000
tests
137
pages de doc
19

09 · bilan

Ce que j’en retiens

  • Montrer plutôt que décrire.

    Trois versions en ligne côte à côte ont tranché en une journée ce qu’une réunion n’aurait pas tranché.

  • Le plus simple gagne souvent.

    Une image à la place d’une carte interactive, du gras à la place d’un éditeur riche.

  • Les retours du client sont la roadmap.

    Le journal en compte des dizaines, chacun consigné sur une ligne avec les fichiers qu’il a touchés.

  • La documentation fait partie du livrable.

    C’est elle qui rend le site autonome, bien plus que le code.

  • Mesurer avant d’optimiser.

    Trois passages, un téléphone lent simulé, et des pistes écartées quand le gain coûtait plus qu’il ne rapportait.

Photos, vidéo et plan : leurs auteurs, crédités sur le site de BRUT.