onmangekoi
- Durée
- 4 mois
- Date
- Avril 2026
- Site web
- www.onmangekoi.fr




Préambule
« On mange où ? » suivi de « je sais pas, comme tu veux » : dix minutes de conversation qui se répètent chaque jour dans chaque bureau. onmangekoi les transforme en un vote de deux minutes.
L'hôte choisit quelques restaurants, partage un lien, un QR code ou un code de six caractères qu'on peut dire à voix haute, et chaque participant vote sur chaque restaurant : bof, ça me va, coup de cœur ou veto. Quand tout le monde a voté, la session se ferme d'elle-même et le classement s'affiche. Aucun compte n'est nécessaire, un pseudo suffit.
Vous pouvez l'essayer ici : www.onmangekoi.fr. Le code est open source : onmangekoi sur GitHub.
Stack technique
- Next.js 16 (App Router, Cache Components) et React 19
- TypeScript, Tailwind CSS v4, shadcn/ui, Base UI
- Supabase : PostgreSQL 17, Row Level Security, Realtime, Auth, pg_cron
- Google Places API (New)
- PostHog (UE), conditionné au consentement
- Vitest, Testing Library, Playwright, GitHub Actions, Bun, Vercel
Fonctionnalités clés
- Sessions de vote avec quatre valeurs de vote et un joker chacun pour le coup de cœur et le veto
- Partage par code de 6 caractères à dicter, lien ou QR code, avec un scanner caméra pour rejoindre
- Listes de restaurants favoris, saisie manuelle et import depuis Google Places
- Salle de session en temps réel : participants et progression se mettent à jour en direct
- Compte email optionnel pour retrouver ses listes sur un autre appareil
- RGPD en libre-service : exporter toutes mes données, supprimer mon compte
En détail
Les règles du jeu vivent dans la base de données, pas dans l'interface. Chaque écriture passe par une fonction PostgreSQL transactionnelle : créer une session, la rejoindre, la lancer, voter, la fermer. Le Row Level Security est actif sur chaque table, les votes individuels ne sont jamais lisibles, seuls les agrégats le sont. Le front ne peut pas tricher, même s'il le voulait.
Les sessions et les listes sont adressées par des codes courts en Crockford base32, six caractères pour une session et dix pour une liste, si bien qu'aucun UUID n'apparaît jamais dans une URL et qu'un code peut se lire au téléphone. La saisie est tolérante : minuscules, espaces, tirets, un « O » confondu avec un « 0 » ou un lien collé en entier se résolvent tous.
L'application utilise les Cache Components de Next.js 16 : chaque route pré-rend une coquille statique et les données personnelles arrivent en streaming dans des frontières Suspense. Seul le catalogue public de restaurants est mis en cache, via un client sans cookie, pour que rien de personnel n'entre jamais dans un cache partagé.
Rôle
Projet solo, du schéma Supabase et des migrations à l'identité visuelle, en passant par le front, la CI et le déploiement. Le MVP a été monté en une journée, puis reconstruit sur un cœur base de données durci avec un nouveau design system.
Ce que j'ai construit
Le moteur de vote
- RPC transactionnelles en security definer pour chaque changement d'état
- Fermeture automatique quand le dernier participant termine, ou fermeture forcée par l'hôte
- Résultats agrégés uniquement ; les votes restent privés
Restaurants
- Catalogue de base, listes de favoris partageables et copiables
- Création manuelle de restaurant
- Import Google Places avec deux masques de champs (léger pour la recherche, complet seulement à l'import), un cache de 24 heures et des upserts idempotents par identifiant de lieu
- Moteur d'horaires d'ouverture qui gère les plages de nuit et les fuseaux horaires
- Mini-carte du gagnant sans clé d'API, construite à partir des tuiles OpenStreetMap
Temps réel et partage
- Supabase Realtime sur les sessions et les participants, avec un filet de polling léger et une resynchronisation au retour au premier plan
- Génération de QR code pour l'hôte, scan natif via BarcodeDetector avec repli paresseux sur jsQR pour les invités
- Image Open Graph dynamique par invitation pour les liens partagés
Exploitation et vie privée
- Maintenance nocturne pg_cron qui purge les comptes anonymes inactifs et les sessions périmées
- Export JSON et suppression du compte en une transaction, les classements survivant sous « participant supprimé »
- PostHog doublement verrouillé (pas de clé, pas de module ; pas de consentement, pas de SDK), URL masquées car le code dans l'URL est le secret d'accès
- Catalogue d'événements typé : une propriété analytics non prévue fait échouer la compilation
Qualité
- 31 fichiers de tests unitaires et de composants, un scénario end-to-end Playwright exécuté contre une vraie stack Supabase locale en CI
- Tests de scénarios SQL qui rejouent les parcours RGPD
- Un workflow base de données pilotable depuis GitHub sur un téléphone : check, types, pull, plan, push
Réalisations techniques
Des règles métier imposées par PostgreSQL
Sessions, participations, votes et fermeture sont toutes des fonctions en base avec leurs propres invariants. La couche applicative est mince et les garanties tiennent quoi que fasse le client.
Zéro friction, de vrais comptes en dessous
Un visiteur choisit un pseudo et il est déjà un utilisateur anonyme Supabase. Ajouter un email plus tard promeut le même compte : rien n'est perdu et aucune session n'est interrompue.
Cache partagé sans fuite
Les Cache Components ont permis de servir une coquille statique sur chaque route tout en tenant un invariant strict : rien de personnel dans un cache partagé.
En résumé
onmangekoi est un petit produit avec un cœur sérieux. Il règle un problème quotidien en deux minutes, sans compte, et l'ingénierie intéressante est sous la surface : règles imposées par la base, sessions en temps réel, analytics respectueux de la vie privée et RGPD dès la conception. Il est en ligne sur www.onmangekoi.fr.






