FoodQard — la carte du restaurant derrière un QR code
Plateforme de carte de restaurant sans contact déployée à l'été 2020 : QR codes à jetons imprimés sur sous-verre, carte multilingue avec allergènes, et un canal SMS pour qui n'a pas de smartphone.
Technologies employées
- PHP
- MySQL
- JavaScript
- Composer
- endroid/qr-code
- Python 3
- PyMySQL
- FFmpeg
- RaspiSMS
- Raspberry Pi
Résumé
À la réouverture des restaurants, en 2020, la carte papier est devenue un objet à désinfecter entre deux clients. FoodQard remplaçait ce papier par un QR code imprimé sur un sous-verre : le client scanne, la carte s’affiche sur son téléphone, avec les photos, les vidéos des plats, les allergènes et la traduction. Le restaurateur la met à jour depuis un back-office, sans appeler personne. Et le client qui n’a pas de smartphone envoie un SMS pour recevoir la même carte en texte. Mis en production en août 2020.
Contexte
L’été 2020 impose aux restaurants un protocole sanitaire dont la carte papier est le point faible : elle passe de main en main, et la désinfecter entre chaque service n’est pas tenable. La réponse immédiate du secteur a été le PDF derrière un QR code, collé sur la table.
Les restaurateurs visés n’avaient ni service informatique, ni budget, ni l’intention d’apprendre un outil de plus au milieu d’une réouverture.
Problème
Le PDF derrière un QR code règle la question sanitaire et rien d’autre. Il oblige à zoomer sur un document conçu pour du A4, ne se met à jour qu’en regénérant un fichier, ne dit rien des allergènes autrement qu’en petits caractères, n’existe que dans une langue, et laisse sur le carreau le client qui n’a pas de smartphone — les personnes âgées, en premier lieu, qui sont aussi une part importante de la clientèle d’un restaurant de quartier.
Objectifs
- Une carte lisible sur un téléphone, pas un document A4 réduit.
- Une mise à jour par le restaurateur lui-même, en quelques minutes.
- Les allergènes et les régimes visibles d’un coup d’œil, pas en note de bas de page.
- Un accès pour qui n’a ni smartphone, ni application, ni forfait data.
Contraintes
- Le support est imprimé. Un QR code sur un sous-verre ne se corrige pas : ce qu’il encode doit rester valable des mois.
- Le réseau en terrasse est mauvais. Une carte qui charge en trois secondes n’est pas consultée.
- L’utilisateur final n’est pas technicien, ni du côté du restaurateur, ni du côté du client.
- Aucune application à installer : personne ne télécharge une application pour lire une carte une fois.
Approche
Un même contenu, trois portes d’entrée, choisies selon ce dont le client dispose réellement au moment où il s’assoit :
| Canal | Ce qu’il faut au client | Ce qu’il reçoit | Limite assumée |
|---|---|---|---|
| QR sur sous-verre | Un appareil photo | La carte complète : photos, vidéos, allergènes, traduction | Suppose un smartphone |
| QR Wi-Fi | Un appareil photo | La connexion au Wi-Fi de la salle, sans saisir la clé | Utile en complément, pas seul |
| SMS | N’importe quel téléphone | La carte en texte, découpée en messages | Ni photo, ni mise en forme |
Le canal SMS n’est pas un repli dégradé qu’on ajoute pour la forme : c’est le seul des trois qui fonctionne sans smartphone, sans application et sans connexion de données.
Phases
| Période | Objectif | Travail réalisé | Résultat |
|---|---|---|---|
| Juin 2020 | Valider l’idée du jeton | Générateur de QR codes, essais d’insertion massive de jetons, premières vues client | Le modèle d’URL est figé avant toute impression |
| Juillet 2020 | Rendre la carte administrable | Back-office : établissement, catégories, sous-catégories, produits, menu du jour, profils | Le restaurateur devient autonome |
| Août 2020 | Mise en production | Sous-verres imprimés, QR Wi-Fi, canal SMS, traitements de nuit | Service ouvert en clientèle réelle |
| Octobre 2020 | Aller au-delà de la carte | Plan de salle et réservations | La table devient une entité, pas seulement un support de QR |
Architecture
Une seule base porte tout : la carte, ses catégories, ses produits, les jetons et les références de médias. Les trois voies y aboutissent, ce qui garantit qu’aucune ne peut afficher une carte périmée pendant qu’une autre affiche la bonne.
Les médias sont servis depuis un domaine distinct : les photos et les vidéos de plats ne partagent ni le cycle de vie ni le profil de charge des pages applicatives.
Un jeton, pas un identifiant
L’URL derrière le QR code ne contient jamais l’identifiant de la carte. Elle porte un jeton de 64 signes hexadécimaux, tiré au sort et stocké dans une table dédiée qui associe le jeton à la carte. La page ne lit que les 64 derniers caractères de ce qu’elle reçoit et cherche la correspondance ; sans elle, elle n’affiche rien.
Le stock de jetons a été pré-généré — deux cent mille d’un coup, par lots — plutôt que produit à la demande. C’était le bon choix : au moment d’imprimer une série de sous-verres, on tire des jetons déjà disponibles, sans dépendre de la disponibilité d’une machine, et la génération lente n’est jamais dans le chemin d’un client.
Le canal SMS
Un Raspberry Pi équipé d’une carte SIM et de RaspiSMS reçoit les messages. Un programme Python interroge en boucle les messages arrivés dans l’heure, récupère la carte de l’établissement au format JSON auprès de l’application, puis découpe la réponse en messages de 160 caractères — sans jamais couper un mot au milieu. Les numéros déjà servis sont mémorisés le temps d’un cycle, pour qu’un client qui envoie deux fois le même SMS ne reçoive pas deux fois la carte.
Réalisation

Le logo au centre et le libellé sous le code ne sont pas décoratifs. Un QR code nu sur une table ne dit pas ce qu’il fait, et personne ne scanne un carré noir sans savoir ce qu’il déclenche. Les deux ajoutés, la correction d’erreur a été poussée à son niveau maximal : le logo masque une partie des modules, et le support finira taché, rayé ou mouillé — c’est un sous-verre.

Côté restaurateur, le back-office couvre l’établissement, les catégories et sous-catégories, les produits — avec description, ingrédients, prix, photo, vidéo, et les marqueurs végétalien et sans gluten —, le menu du jour daté, les sous-verres, le QR Wi-Fi, puis le plan de salle et les réservations. Un mode dégradé était prévu pour ceux qui ne voulaient rien saisir : une simple image de leur carte existante, servie derrière le même QR code.
La vidéo, le coût caché
Laisser un restaurateur téléverser une vidéo de son plat depuis son téléphone,
c’est accepter des fichiers de plusieurs centaines de mégaoctets filmés en
.mov. Sur une terrasse mal couverte, cette vidéo ne s’ouvrira jamais.
Deux traitements de nuit s’en chargent. Le premier ré-encode ce qui a été déposé dans la journée, en H.265 à qualité constante, après conversion préalable des formats issus des téléphones. Le second compare les dossiers présents sur le disque aux médias réellement référencés en base, et supprime les orphelins — ceux qu’un produit supprimé ou remplacé a laissés derrière lui.
Résultats
- Mise en production en août 2020, en clientèle réelle, avec une démonstration vidéo publiée à l’appui.
- Trois canaux d’accès à la même carte, dont un qui ne demande aucun smartphone.
- Un stock de deux cent mille jetons, soit de quoi imprimer des séries de sous-verres pendant des années sans jamais réutiliser une URL.
- Des vidéos de plats consultables en terrasse, grâce au ré-encodage de nuit.
- Le périmètre étendu en octobre 2020 au plan de salle et aux réservations, sans toucher au modèle des jetons — signe que la fondation tenait.
Enseignements
C’est un projet de 2020, écrit vite, pendant une réouverture. Avec cinq ans de recul, la partie conception a bien vieilli ; la partie mise en œuvre, beaucoup moins.
| Choix de 2020 | Ce que je ferais aujourd’hui | Pourquoi |
|---|---|---|
| Identifiants de base dans les fichiers du dépôt | Variables d’environnement, secrets hors dépôt | Un secret commité reste dans l’historique, même effacé |
| Requêtes SQL construites par concaténation | Requêtes préparées, systématiquement | La seule protection qui ne dépend pas de la vigilance du développeur |
Traitements de nuit lancés par os.system | Appels de processus explicites, sans passer par un shell | Un nom de fichier hostile ne doit pas pouvoir devenir une commande |
| Aucun test automatisé | Au moins les fonctions pures : découpage SMS, résolution de jeton | Ce sont celles dont la panne est silencieuse |
Ce qui, en revanche, mérite d’être gardé : le jeton plutôt que l’identifiant, la pré-génération du stock, la purge écrite en même temps que l’envoi, et surtout le canal SMS — la seule fonctionnalité que personne ne demandait et que les clients âgés ont réellement utilisée.
Conclusion
- Le problème n’était pas d’afficher une carte, mais de la rendre atteignable par tout le monde, y compris sans smartphone.
- Le support imprimé impose ses contraintes à l’URL : jeton stable, stock pré-généré, correction d’erreur maximale.
- Un média téléversé coûte deux fois : à l’envoi, puis chaque fois qu’on oublie de le supprimer.
- Les décisions de conception ont mieux vieilli que la mise en œuvre : ce sont les secrets en dur et le SQL concaténé que je reprendrais d’abord.