Construis ta propre plateforme de tickets Wi-Fi avec Claude Code
Du nom de ta zone jusqu'au premier ticket vendu en Mobile Money : identité visuelle, outils, prompts prêts à copier, base de données, paiement, hébergement et routeur MikroTik. Chaque étape se coche ; ta progression reste enregistrée dans ce navigateur.
Ce que tu vas construire
Le fonctionnement complet, avant de toucher à quoi que ce soit.
Une Wi-Fi Zone vend l'accès internet par tickets : un identifiant et un mot de passe valables une durée donnée (1 h, 24 h, 7 jours…). Aujourd'hui beaucoup de gérants vendent ces tickets à la main, en papier. Ta plateforme automatise tout : le client paie en Mobile Money depuis son téléphone et reçoit son ticket en quelques secondes, sans que tu sois là.
Le parcours d'un client
Les briques du système
| Brique | Rôle | Outil utilisé |
|---|---|---|
| Frontend | Page d'accueil, page d'achat, tableau de bord du gérant | React + Vite + Tailwind, hébergé sur Vercel |
| Backend (API) | Paiements, attribution des tickets, comptabilité, sécurité | Node.js + Express, hébergé sur Render |
| Base de données | Zones, tarifs, tickets, paiements, retraits | Supabase (PostgreSQL) |
| Agrégateur de paiement | Encaisse le Mobile Money dans 6 pays | Moneroo |
| Routeur | Diffuse le Wi-Fi, bloque l'accès tant que le client n'a pas de ticket | MikroTik (Hotspot) |
| Développeur | Écrit tout le code à partir de tes instructions | Claude Code dans VS Code |
Les fonctionnalités finales
- Plusieurs zones Wi-Fi par compte, chacune avec son pays, son routeur et son numéro de gérant.
- Tarifs par zone (nom, prix, durée). Un tarif déjà vendu peut être supprimé sans casser l'historique.
- Import de tickets par fichier CSV, avec statuts libre / vendu / expiré et alerte de stock bas.
- Paiement Mobile Money multi-pays : Bénin, Côte d'Ivoire, Togo, Sénégal, Mali, Burkina Faso.
- Attribution atomique : impossible de vendre deux fois le même ticket, même avec 50 achats simultanés.
- Retrouver son ticket avec le numéro de téléphone utilisé pour payer.
- Comptabilité : chiffre d'affaires brut et net, ventes par jour, répartition par opérateur, export CSV.
- Générateur de portail captif : le gérant télécharge ses pages MikroTik déjà personnalisées.
- Option plateforme : ouvrir ton système à d'autres gérants, prendre une commission, gérer leurs retraits.
Prérequis et budget
Ce qu'il te faut avant de commencer.
Matériel
- Un ordinateur Windows 10/11 ou Mac, 8 Go de RAM minimum, connexion internet stable.
- Un routeur MikroTik (hAP ax lite, hAP ac², hEX + point d'accès…) avec RouterOS 7.
- Une source internet pour la zone : Starlink, fibre, 4G/5G.
- Un téléphone avec un compte Mobile Money pour tester un vrai paiement.
Comptes à ouvrir
| Service | Pour quoi | Coût indicatif |
|---|---|---|
| Nom de domaine (Namecheap, Hostinger, OVH…) | L'adresse de ta plateforme, ex. | 8 à 15 $ / an |
| Claude (plan Pro ou Max) | Claude Code, ton développeur | Pro ≈ 20 $ / mois |
| GitHub | Stocker ton code, relier Vercel et Render | Gratuit |
| Supabase | Base de données | Gratuit pour démarrer |
| Vercel | Héberger le frontend | Hobby gratuit · Pro ≈ 20 $ / mois |
| Render | Héberger l'API | Starter ≈ 7 $ / mois |
| Moneroo | Encaisser le Mobile Money | Commission par transaction |
Prix indicatifs relevés en 2026 : vérifie sur chaque site avant de payer.
Checklist du chapitre
Nom, logo et charte graphique
L'identité de ta zone. Tout le reste en découle.
Choisir le nom
- Court (2 syllabes idéalement), facile à dire au téléphone et à taper sur un clavier mobile.
- Le nom de domaine en
.com,.org,.netou ton extension pays (.bj,.ci…) doit être libre. Vérifie-le avant de t'attacher au nom. - Pas d'accents ni de tirets dans le domaine : « Fô-Zône » devient
fozone.org. - Vérifie que le nom n'est pas déjà une marque connue dans ton pays.
Le logo
Il te faut trois fichiers : le logo complet (symbole + nom), le symbole seul en carré (pour l'icône d'onglet et l'écran du téléphone), et une version blanche pour les fonds sombres. Format idéal : SVG, sinon PNG 1024 × 1024 sur fond transparent.
- Avec un graphiste : compte 15 000 à 50 000 F CFA. Demande les fichiers sources.
- Avec Claude : Claude peut dessiner un logo simple en SVG. Utilise le prompt ci-dessous sur claude.ai.
- Avec Canva : rapide, mais exporte en SVG ou PNG transparent.
La fiche de ton projet
Remplis ces champs. Tous les prompts et commandes de l'e-book se mettent à jour avec tes valeurs, et la fiche reste enregistrée dans ce navigateur.
Les valeurs par défaut sont celles de Fô-Zône, à titre d'exemple.
Prompt : créer le logo avec Claude
Sur claude.ai, dans une nouvelle conversation :
Je lance « {{NOM}} », une plateforme de vente de tickets Wi-Fi payés en Mobile Money ({{PAYS}}). Ambiance : {{STYLE}}. Couleurs : {{C1}} (principale) et {{C2}} (secondaire).
Propose-moi 4 pistes de logo, chacune en SVG autonome (viewBox 0 0 512 512, pas de police externe, formes vectorisées) :
1. un symbole seul, lisible à 32 px (icône d'onglet) ;
2. le symbole + le nom « {{NOM}} » à côté.
Évite les clichés (ondes Wi-Fi génériques seules, globe). Pour chaque piste, explique l'idée en une phrase.
Quand j'aurai choisi, donne-moi aussi la version blanche sur fond transparent.La charte en une page
Avant le code, fige ces décisions. Claude s'en servira pour la maquette.
- 2 couleurs de marque (codes hexadécimaux) + un gris foncé pour le texte.
- 2 polices Google Fonts : une pour les titres, une pour le texte. Exemples sûrs : Poppins / Inter, Sora / Nunito Sans, Outfit / DM Sans.
- Le ton : tutoiement ou vouvoiement des clients, phrases courtes.
- Thème sombre : oui ou non (Fô-Zône propose les deux avec une bascule).
Checklist du chapitre
Acheter le nom de domaine
À faire maintenant : la configuration DNS viendra au chapitre 11.
- Va sur un registraire : Namecheap, Hostinger ou OVH.
- Cherche . S'il est pris, essaie une autre extension ou une variante courte.
- Achète-le pour 1 an minimum. Active le renouvellement automatique : un domaine expiré coupe ta plateforme et les paiements.
- Refuse les options d'hébergement et d'e-mail proposées au panier : tu n'en as pas besoin.
- Garde l'onglet « DNS » ou « Gestion DNS » de ton registraire : tu y reviendras.
api est gratuit.Checklist du chapitre
S'abonner à Claude
Claude Code est inclus dans les plans payants de Claude.
- Va sur claude.ai et crée un compte avec l'e-mail du projet.
- Ouvre Paramètres → Abonnement (ou clique « Upgrade »).
- Choisis Pro pour commencer. Si tu atteins souvent la limite d'utilisation pendant le développement, passe à Max.
- Paie par carte bancaire (Visa/Mastercard, carte prépayée ou virtuelle acceptée selon ta banque).
Checklist du chapitre
Installer VS Code et Claude Code
Quatre logiciels, une seule fois.
1. Node.js
Le moteur qui fait tourner ton API et construit ton site. Télécharge la version LTS sur nodejs.org, puis installe en laissant les options par défaut.
2. Git
Il garde l'historique de chaque modification et permet de revenir en arrière si Claude casse quelque chose. Windows : git-scm.com/download/win, options par défaut. Mac : il est proposé automatiquement à la première utilisation.
3. Visual Studio Code
Ton éditeur. Télécharge-le sur code.visualstudio.com. Pendant l'installation Windows, coche « Ajouter l'action Ouvrir avec Code » et « Ajouter à PATH ».
4. L'extension Claude Code
- Ouvre VS Code, clique sur l'icône Extensions dans la barre de gauche (ou Ctrl+Shift+X).
- Cherche Claude Code, vérifie que l'éditeur est Anthropic, clique Installer.
- Une icône Claude apparaît en haut à droite de l'éditeur ou dans la barre latérale. Clique dessus.
- Choisis « Se connecter avec un compte Claude ». Le navigateur s'ouvre : autorise l'accès, reviens dans VS Code.
Vérifier que tout est en place
Dans VS Code, ouvre un terminal : menu Terminal → Nouveau terminal. Tape ces commandes une par une ; chacune doit afficher un numéro de version.
node -v npm -v git --version
Configure ensuite ton identité Git (une seule fois) :
git config --global user.name "Ton Nom" git config --global user.email "ton-email@exemple.com"
Réglages utiles de l'extension
- Mode de permissions : au début, laisse Claude demander avant chaque commande. Quand tu es à l'aise, autorise les commandes courantes (
npm install,git commit). - Mode plan : pour les grosses étapes, demande d'abord un plan (bouton ou Shift+Tab selon la version). Claude propose, tu valides, puis il code.
- Références de fichiers : tape
@puis un nom de fichier pour montrer un fichier précis à Claude.
Checklist du chapitre
Créer le dossier du projet
Un dossier vide, ouvert dans VS Code, avec ton logo dedans.
- Crée un dossier
Projetsà un endroit simple, par exempleD:\Projets(évite les chemins avec espaces ou accents). - Dedans, crée le dossier
. - Dans ce dossier, crée un sous-dossier
brandet copie-y ton logo :logo.svg,logo-icon.svg,logo-white.svg. - Dans VS Code : Fichier → Ouvrir le dossier… et choisis
. Accepte « Faire confiance aux auteurs ». - Ouvre le panneau Claude Code. Tu es prêt à envoyer le premier prompt.
Ou, depuis le terminal :
mkdir D:\Projets\{{DOSSIER}}
cd D:\Projets\{{DOSSIER}}
mkdir brand
code ..gitignore dès le départ. C'est ce fichier qui empêche tes clés secrètes de partir un jour sur GitHub.Checklist du chapitre
Le prompt de départ
Il pose le cadre de tout le projet. Copie-le tel quel dans Claude Code.
Ce prompt décrit le produit, impose la technique, fixe les règles de travail et lance seulement la phase 1 : la maquette. Claude s'arrête ensuite et attend ta validation. Ce découpage par phases est la clé : tu vérifies à chaque étape au lieu de découvrir 50 problèmes à la fin.
Tu es le développeur principal de « {{NOM}} », une plateforme de vente automatisée de tickets Wi-Fi payés en Mobile Money, reliée à des routeurs MikroTik (hotspot). Je ne suis pas développeur : explique simplement, et dis-moi toujours comment tester ce que tu as fait.
# Le produit
- Un gérant crée ses zones Wi-Fi (nom, pays, adresse, IP ou nom d'hôte du routeur, numéro du gérant, position GPS facultative).
- Pour chaque zone, il crée des tarifs (nom, prix en F CFA, durée en heures) et importe ses tickets MikroTik (identifiant + mot de passe + profil) par fichier CSV.
- Le client connecté au Wi-Fi ouvre la page d'achat de la zone, choisit un tarif, saisit son numéro, paie en Mobile Money via l'agrégateur Moneroo, et reçoit immédiatement un ticket du tarif payé.
- Le client peut retrouver un ticket déjà acheté avec son numéro de téléphone.
- Le gérant a un tableau de bord : ventes du jour, chiffre d'affaires brut et net de commission, tickets restants, alertes de stock bas, comptabilité par jour et par opérateur, export CSV.
- Le gérant génère depuis le tableau de bord ses pages de portail captif MikroTik (login.html, redirect.html) personnalisées pour sa zone.
# Identité
- Nom : {{NOM}} · domaine : {{DOMAINE}} (site) et {{API}} (API)
- Pays principal : {{PAYS}} · devise : XOF (F CFA, pas de centimes)
- Couleurs : principale {{C1}}, secondaire {{C2}} · ambiance : {{STYLE}}
- Logo : fichiers dans le dossier brand/
- Interface en français, pensée d'abord pour le téléphone (la page d'achat est ouverte depuis le Wi-Fi sur un mobile), thème clair et sombre avec bascule.
- WhatsApp d'assistance : {{WA}}
# Technique imposée
- Monorepo : dossier frontend/ (React 18 + Vite + Tailwind CSS + React Router, icônes lucide-react, graphiques recharts) et dossier backend/ (Node.js + Express, en CommonJS).
- Base de données : Supabase (PostgreSQL). Le backend y accède uniquement avec la clé service_role ; l'autorisation est vérifiée dans le code (chaque zone a un owner_id). Le frontend ne parle jamais directement à la base : il passe par l'API.
- Authentification : JWT + mots de passe hachés avec bcrypt.
- Paiement : Moneroo (API REST + webhooks signés).
- Hébergement prévu : frontend sur Vercel, backend sur Render.
# Règles de travail
1. Commence par : git init, un .gitignore (node_modules, .env, .env.*, sauf les fichiers .env.example, logs, dist), un README.md et un fichier CLAUDE.md qui résume ce brief et ces règles pour les sessions futures.
2. On avance par phases. À la fin de chaque phase : arrête-toi, résume ce qui a été fait, donne-moi les étapes exactes pour tester, et attends que j'écrive « validé ». Ne commence jamais la phase suivante sans mon accord.
3. Quand je valide une phase, fais un commit Git avec un message clair en français.
4. Aucun secret dans le code : tout passe par des variables d'environnement, documentées dans backend/.env.example et frontend/.env.example.
5. Si une décision te semble risquée ou ambiguë, pose-moi la question au lieu de deviner.
# Phase 1 : maquette (maintenant)
Construis uniquement le frontend, avec des données d'exemple en dur (aucun backend, aucune base) :
- Page d'accueil publique de {{NOM}} (présentation, comment ça marche en 3 étapes, bouton « Acheter un ticket », lien « Retrouver mon ticket »).
- Page d'achat d'une zone (/acheter/:zoneId) : liste des tarifs en cartes, champ numéro de téléphone avec indicatif du pays, bouton payer.
- Page de retour de paiement : état « paiement en cours », puis ticket affiché (identifiant + mot de passe en gros, bouton copier, rappel de la durée).
- Page « Retrouver mon ticket » par numéro.
- Connexion et inscription du gérant.
- Espace gérant avec menu latéral (repliable sur mobile) : Tableau de bord, Zones Wi-Fi, Tarifs, Tickets, Comptabilité, Portail captif, Profil.
Applique la charte : couleurs, logo, polices Google Fonts cohérentes avec l'ambiance. Lance le serveur de développement et donne-moi l'adresse à ouvrir.Ce qui va se passer
- Claude lit le dossier, puis propose de lancer des commandes (
git init,npm create vite,npm install…). Accepte-les. - Il crée les fichiers. Tu les vois apparaître dans l'explorateur à gauche.
- Il lance
npm run devet te donne une adresse du typehttp://localhost:5173. Ouvre-la dans ton navigateur. - Il s'arrête et attend ta validation.
Checklist du chapitre
Valider la maquette
C'est le moment le moins cher pour tout changer.
Avant d'écrire la moindre ligne de logique, l'apparence doit te plaire. Changer une couleur maintenant prend 30 secondes ; après la phase 5, ça touche 40 fichiers.
Ce qu'il faut vérifier
- Sur téléphone : dans le navigateur, F12 puis l'icône téléphone (mode responsive), largeur 375 px. La page d'achat doit être parfaite sur mobile : c'est là que tes clients paient.
- Couleurs : le texte reste lisible partout, en clair comme en sombre. Les boutons « Payer » se voient au premier coup d'œil.
- Logo : net, bien proportionné, présent dans l'onglet du navigateur.
- Textes : clairs pour quelqu'un qui n'a jamais acheté de ticket en ligne.
Prompts de retouche
Sois précis : une page, un problème, le résultat attendu. Tu peux aussi coller une capture d'écran dans la conversation.
Sur la page d'achat, les cartes de tarifs sont trop petites sur mobile : affiche-les en une colonne pleine largeur sous 480 px, prix en très gros, durée en dessous.
Le vert {{C1}} est trop clair sur fond blanc pour le texte : garde-le pour les boutons mais utilise une version plus foncée pour les liens.
En thème sombre, le tableau de bord manque de contraste entre les cartes et le fond. Corrige-le sans toucher au thème clair.Quand tout te plaît :
Validé. Fais le commit de la phase 1, puis décris-moi la phase 2 avant de la commencer.
Checklist du chapitre
Créer Supabase et Moneroo
Les deux services dont le code aura besoin pour fonctionner.
Supabase (base de données)
- Va sur supabase.com, connecte-toi avec GitHub (crée d'abord ton compte GitHub sur github.com).
- New project : nom
, mot de passe de base de données fort (garde-le dans un gestionnaire de mots de passe), région la plus proche (Europe, ex. Francfort ou Paris). - Attends 2 minutes la création, puis va dans Project Settings → API (ou « API Keys »).
- Note trois valeurs : Project URL, la clé anon / publishable et la clé service_role / secret.
backend/.env et dans les variables de Render. Jamais dans le frontend, jamais dans une capture d'écran, jamais dans un message.Moneroo (paiement)
- Crée un compte sur moneroo.io.
- Lance la vérification de ton entreprise (KYC) tout de suite : pièce d'identité, justificatif d'activité. Elle peut prendre plusieurs jours et elle est obligatoire pour encaisser de vrais paiements.
- En attendant, reste en mode test (sandbox) : dans Developers → API Keys, copie la clé secrète de test (elle commence par
test_). Une passerelle de démonstration permet de simuler des paiements. - Dans les réglages de paiement, active les méthodes de ton pays (MTN, Moov, Orange, Wave…). Une méthode non activée n'apparaît pas aux clients, même si ton code la demande.
- Le webhook se configure au chapitre 11, quand ton API aura une adresse publique.
Les méthodes par pays
| Pays | Indicatif | Codes Moneroo |
|---|---|---|
| Bénin | 229 | mtn_bj moov_bj celtiis_bj |
| Côte d'Ivoire | 225 | mtn_ci orange_ci moov_ci wave_ci |
| Togo | 228 | moov_tg togocel |
| Sénégal | 221 | orange_sn wave_sn freemoney_sn e_money_sn wizall_sn |
| Mali | 223 | orange_ml moov_ml |
| Burkina Faso | 226 | orange_bf moov_bf |
Checklist du chapitre
Construire les fonctions, phase par phase
Un prompt par phase. Teste, valide, puis passe à la suivante.
Chaque phase ci-dessous contient le prompt à envoyer et la façon de vérifier le résultat. Ne saute pas les tests : une erreur trouvée en phase 3 coûte une minute, la même trouvée après la mise en ligne coûte des clients.
Phase 2 Base de données
Phase 2 : la base de données Supabase. Écris backend/database/schema.sql, à exécuter dans le SQL Editor de Supabase, avec : - users : id uuid, email unique, mot de passe haché, nom, téléphone, rôle (admin, super_admin), dates. - wifi_zones : id, owner_id → users, nom, pays (code BJ, CI, TG, SN, ML, BF), adresse, router_ip (accepte une IP ou un nom d'hôte), téléphone du gérant, latitude/longitude facultatives, actif, dates. - pricings : id, wifi_zone_id, nom, montant (entier, F CFA, minimum 100), durée en heures, profil MikroTik associé, actif. - tickets : id, wifi_zone_id, pricing_id, username, password, profile, statut (free, reserved, sold, expired), payment_id, sold_at. Unicité (wifi_zone_id, username). - payments : id, moneroo_payment_id unique, wifi_zone_id, pricing_id, montant, téléphone normalisé, méthode réellement utilisée (code Moneroo), statut (pending, completed, failed, cancelled), ticket_id, et un instantané du tarif au moment de la vente (pricing_name, pricing_duration_hours) pour que supprimer un tarif ne casse jamais l'historique. - payment_idempotency : clé unique (événement + id de paiement), pour ne jamais traiter deux fois le même webhook. - Une fonction PostgreSQL assign_ticket_atomic(zone, tarif, paiement) qui choisit UN ticket libre de ce tarif avec FOR UPDATE SKIP LOCKED, le passe en sold, le lie au paiement, et ne renvoie rien s'il n'y en a plus. Jamais de ticket d'un autre tarif en remplacement. - Index utiles, triggers updated_at. Pour les évolutions futures, crée un dossier backend/database/migrations/ avec des fichiers numérotés (001_..., 002_...). Explique-moi ensuite, pas à pas, comment exécuter le script dans Supabase et comment vérifier que les tables existent.
Vérifier : dans Supabase, SQL Editor → New query, colle le contenu de schema.sql, clique Run. Puis Table Editor : les 6 tables doivent apparaître.
Phase 3 API, sécurité et connexion
Phase 3 : le backend Express et l'authentification.
- Structure backend/src : config/ (database, logger, countries), controllers/, routes/, middleware/ (auth, validator, errorHandler), services/, utils/. Point d'entrée src/server.js, scripts npm « dev » (nodemon) et « start ».
- Sécurité : helmet, CORS avec une liste d'origines séparées par des virgules (CORS_ORIGIN), limitation de débit, express-validator sur toutes les entrées, logs avec winston (jamais de mot de passe ni de clé dans les logs).
- Route GET /api/health qui répond { status: "ok" }.
- Auth : POST /api/auth/register, POST /api/auth/login, GET et PUT /api/auth/profile, PUT /api/auth/profile/password. JWT signé avec JWT_SECRET, expiration JWT_EXPIRES_IN.
- backend/.env.example complet et commenté (PORT, NODE_ENV, API_BASE_URL, FRONTEND_URL, SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY, JWT_SECRET, JWT_EXPIRES_IN, MONEROO_API_KEY, MONEROO_WEBHOOK_SECRET, MONEROO_BASE_URL, CORS_ORIGIN, LOG_LEVEL).
- Côté frontend : remplace les données d'exemple de connexion et d'inscription par les vrais appels (axios, VITE_API_URL), garde le jeton, protège les pages du gérant.
Dis-moi exactement quoi mettre dans backend/.env et frontend/.env.development.local (sans jamais me demander de coller mes clés dans la conversation), puis comment lancer les deux serveurs.Vérifier : crée ton backend/.env à partir de .env.example et remplis-le toi-même. Pour JWT_SECRET, génère une chaîne aléatoire (voir ci-dessous). Ouvre http://localhost:3000/api/health : tu dois voir "status":"ok". Inscris-toi, déconnecte-toi, reconnecte-toi.
-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 64 | % {[char]$_}).env toi-même dans l'éditeur. Claude n'a pas besoin de voir tes clés pour écrire le code qui les utilise.Phase 4 Zones, tarifs et tickets
Phase 4 : zones, tarifs et tickets. - CRUD des zones (/api/wifi-zones) : chaque requête vérifie que la zone appartient à l'utilisateur connecté (owner_id). Route publique GET /api/wifi-zones/public/:id qui ne renvoie que ce dont la page d'achat a besoin (nom, pays, actif). - CRUD des tarifs par zone (/api/pricings/zone/:zoneId), route publique des tarifs actifs. Refuse un montant sous 100 F CFA. Supprimer un tarif déjà vendu ne doit pas casser l'historique (instantané dans payments). - Tickets : import CSV (multer + csv-parser) qui accepte les colonnes Username/username, Password/password, Profile/profile, lie chaque ticket au tarif dont le profil correspond, ignore les doublons et renvoie un résumé (importés, doublons, erreurs). Liste paginée avec filtre par statut, statistiques par zone, alerte quand il reste moins de 10 tickets libres pour un tarif. Un ticket vendu ne peut être ni modifié ni supprimé. - Ajoute dans la page Tickets un générateur de lot : je choisis un tarif et une quantité, il produit des identifiants et mots de passe aléatoires lisibles (sans 0/O ni 1/l), puis me donne (a) le fichier CSV à importer et (b) le script RouterOS « /ip hotspot user add » à coller dans le terminal du routeur. - Branche les pages Zones, Tarifs et Tickets du frontend sur ces routes.
Vérifier : crée une zone, deux tarifs (ex. 200 F / 1 h et 500 F / 24 h), génère 20 tickets par tarif, importe le CSV. Le compteur de tickets libres doit afficher 20 par tarif. Importe le même fichier une deuxième fois : il doit annoncer 40 doublons et rien de plus.
Phase 5 Paiement Mobile Money
La phase la plus importante. Lis le prompt avant de l'envoyer : chaque ligne correspond à un problème réel rencontré en production.
Phase 5 : le paiement avec Moneroo. Lis la documentation officielle de Moneroo (initialisation de paiement, vérification, webhooks, méthodes disponibles) avant d'écrire le code. - backend/src/config/countries.js : pour chaque pays (BJ, CI, TG, SN, ML, BF), le nom, l'indicatif, un exemple de numéro et la liste des codes de méthodes Moneroo. Fonction normalizePhone qui ajoute l'indicatif sans retirer le zéro initial des numéros locaux (Bénin et Côte d'Ivoire ont des numéros à 10 chiffres). Le numéro stocké en base doit être exactement celui envoyé à Moneroo. - POST /api/payments/intent (public) : reçoit zoneId, pricingId, téléphone. Relit le montant depuis la base (jamais celui envoyé par le navigateur), vérifie qu'il reste au moins un ticket libre de ce tarif AVANT de faire payer, crée le paiement Moneroo avec les méthodes du pays de la zone, une return_url vers la page de retour du frontend, et des métadonnées (zone, tarif, paiement). Enregistre le paiement en pending avec l'instantané du tarif. - En mode test (clé commençant par « test_ »), ajoute la passerelle de démonstration Moneroo aux méthodes. - POST /api/payments/moneroo/webhook : vérifie la signature HMAC-SHA256 avec MONEROO_WEBHOOK_SECRET sur le corps BRUT de la requête (express.raw sur cette route uniquement, pas sur un JSON re-sérialisé). Rejette toute signature invalide. Idempotence sur événement + id. Sur succès : re-vérifie le statut auprès de l'API Moneroo, enregistre la méthode réellement utilisée, puis appelle assign_ticket_atomic. Le client reçoit un ticket du tarif payé, ou aucun ; jamais un autre tarif. S'il n'y en a plus, marque le paiement pour remboursement et journalise une alerte. - GET /api/payments/:id (public, données minimales) : la page de retour l'interroge toutes les 3 secondes pendant 2 minutes, puis affiche le ticket. - GET /api/payments/lookup/:phone (public, limité en débit) : retrouve les tickets achetés avec ce numéro, quelle que soit la façon dont le client l'écrit (avec ou sans indicatif). - Branche la page d'achat, la page de retour et « Retrouver mon ticket ». Explique-moi comment tester en local avec la passerelle de démonstration, sachant que Moneroo ne peut pas appeler mon localhost.
Vérifier : en local, Moneroo ne peut pas joindre ton ordinateur ; Claude te proposera soit un tunnel (ngrok, cloudflared), soit d'attendre la mise en ligne (chapitre 11) pour le test complet. Vérifie au minimum que la page de paiement Moneroo s'ouvre avec les bons opérateurs et le bon montant.
MONEROO_WEBHOOK_SECRET est vide ou faux, tous les webhooks sont rejetés : les clients paient et ne reçoivent rien. C'est la première chose à vérifier si un paiement réussi n'affiche pas de ticket.Phase 6 Tableau de bord et comptabilité
Phase 6 : tableau de bord et comptabilité. - Centralise le taux de commission de l'agrégateur dans backend/src/config/commission.js (je te donnerai le taux réel de mon contrat Moneroo ; mets 2 % par défaut). Arrondi au franc entier, ligne par ligne, jamais sur une somme. - GET /api/dashboard/stats : recettes du jour (brut et net), chiffre d'affaires total, tickets vendus, tickets restants, zones actives. Statistiques par zone et par période. - Comptabilité (/api/accounting) : ventes par jour (brut, commission, net), tickets vendus par tarif, répartition par opérateur (MTN, Moov, Orange…, avec leurs noms lisibles), historique paginé des paiements avec le ticket attribué, export CSV. - Frontend : graphiques recharts, filtres par zone et par période, chiffres alignés, tout lisible sur mobile. - Optimise : requêtes en parallèle, chargement page par page, squelettes de chargement.
Vérifier : la somme des lignes « net » doit être égale au total net affiché. Exporte le CSV et ouvre-le dans Excel.
Phase 7 Générateur de portail captif
Phase 7 : la page « Portail captif » du tableau de bord.
Le gérant choisit sa zone, un style parmi trois, le nom affiché, un pied de page et le numéro WhatsApp ({{WA}} par défaut), voit un aperçu, puis télécharge login.html et redirect.html déjà remplis.
- Gabarits dans frontend/src/templates/captivePortal.js.
- login.html : formulaire de connexion MikroTik standard (les variables RouterOS $(link-login-only), $(username), $(error), etc. doivent rester intactes, ainsi que l'usage de md5.js fourni par MikroTik), un gros bouton « Acheter un ticket » vers https://{{DOMAINE}}/acheter/ID_DE_LA_ZONE, un lien « Retrouver mon ticket », et le lien WhatsApp.
- redirect.html : redirection après connexion.
- Pas de dépendance externe dans les pages (styles en ligne), elles doivent fonctionner avant que le client ait internet.
- Fournis aussi, à copier, le bloc walled garden RouterOS qui autorise avant connexion : {{DOMAINE}}, www.{{DOMAINE}}, {{API}}, checkout.moneroo.io, api.moneroo.io, les domaines de la passerelle utilisée par Moneroo (ex. process.fedapay.com, api.fedapay.com), fonts.googleapis.com, fonts.gstatic.com, et wa.me + api.whatsapp.com si un WhatsApp est renseigné. Utilise « /ip hotspot walled-garden ip » (c'est lui qui laisse passer le HTTPS) en plus de « /ip hotspot walled-garden ».
- Ajoute la marche à suivre sur le routeur, en français simple.
- L'aperçu dans le navigateur remplace les variables $(...) par des valeurs d'exemple, mais le fichier téléchargé garde les variables brutes.Vérifier : télécharge les deux fichiers, ouvre login.html avec un éditeur de texte et cherche $(link-login-only) : il doit être présent tel quel.
Phase 8 · facultative Ouvrir la plateforme à d'autres gérants
Si tu veux vendre ton système à d'autres gérants plutôt que l'utiliser seul. C'est le modèle de Fô-Zône.
Phase 8 : mode plateforme multi-gérants.
- Rôle super_admin (moi) en plus des gérants. Inscription libre des gérants.
- Commission plateforme de 5 % sur chaque ticket vendu, commission de l'agrégateur INCLUSE dans ces 5 % (c'est mon coût, pas celui du gérant). Exemple : ticket 200 F → 10 F pour {{NOM}}, 190 F pour le gérant. Enregistre platform_fee sur chaque paiement, arrondi au franc par paiement. Affiche clairement ce taux au gérant.
- Portefeuille du gérant : solde disponible = ventes nettes − retraits. Demande de retrait vers un numéro Mobile Money.
- Le retrait n'est possible qu'après vérification d'identité du gérant (pièce + selfie), validée par le super-admin.
- Espace super-admin : liste des gérants (valider, suspendre), demandes de retrait (approuver, marquer payé, refuser avec motif), vue globale des ventes.
- Partage de compte : un gérant peut inviter un membre d'équipe avec un accès limité à ses zones.
Toutes ces règles d'argent doivent être vérifiées côté serveur.Phase 9 Préparer la mise en ligne
Phase 9 : préparation de la production.
- frontend/vercel.json avec une réécriture de toutes les routes vers /index.html (sinon un rafraîchissement sur /acheter/... donne une erreur 404).
- Vérifie que « npm run build » du frontend passe sans erreur et que le backend démarre avec « npm start ».
- Le backend doit lire le port fourni par l'hébergeur (process.env.PORT) et faire confiance au proxy (app.set('trust proxy', 1)) pour la limitation de débit.
- Relis tout le code à la recherche de secrets en dur, de routes sans vérification de propriétaire et de montants acceptés depuis le navigateur. Corrige ce que tu trouves.
- Mets à jour le README : installation, variables d'environnement, déploiement Vercel + Render, configuration du webhook Moneroo.
Puis donne-moi les commandes pour créer le dépôt GitHub privé et pousser le code.Checklist du chapitre
Mettre en ligne : Render, Vercel et DNS
L'API d'abord, le site ensuite, le webhook pour finir.
1. L'API sur Render
- Crée un compte sur render.com avec GitHub.
- New → Web Service, choisis ton dépôt.
- Réglages : Root Directory
backend· Build Commandnpm install· Start Commandnpm start· région Francfort · plan Starter. - Dans Environment, ajoute chaque variable de ton
backend/.envavec les valeurs de production :
NODE_ENV=production
API_BASE_URL=https://{{API}}
FRONTEND_URL=https://{{DOMAINE}}
CORS_ORIGIN=https://{{DOMAINE}},https://www.{{DOMAINE}}
SUPABASE_URL= (ta Project URL)
SUPABASE_SERVICE_ROLE_KEY= (ta clé service_role)
JWT_SECRET= (une NOUVELLE chaîne de 64 caractères)
JWT_EXPIRES_IN=7d
MONEROO_API_KEY= (test_... pour commencer)
MONEROO_WEBHOOK_SECRET= (rempli à l'étape 4)
MONEROO_BASE_URL=https://api.moneroo.io
LOG_LEVEL=info- Lance le déploiement. Quand il est vert, ouvre
https://ton-service.onrender.com/api/health. - Settings → Custom Domains : ajoute
. Render t'indique un enregistrement CNAME à créer.
2. Le site sur Vercel
- Crée un compte sur vercel.com avec GitHub.
- Add New → Project, importe ton dépôt.
- Root Directory :
frontend. Vercel détecte Vite tout seul (buildnpm run build, sortiedist). - Variables d'environnement :
VITE_API_URL=https://{{API}}/api
VITE_FRONTEND_URL=https://{{DOMAINE}}- Deploy. Puis Settings → Domains : ajoute
etwww.. Vercel affiche les enregistrements DNS à créer.
3. Les DNS chez ton registraire
Dans la gestion DNS de ton domaine, crée les enregistrements que Vercel et Render t'ont affichés. En général :
| Type | Nom / Hôte | Valeur | Pour |
|---|---|---|---|
| A | @ | l'adresse IP donnée par Vercel | le site |
| CNAME | www | la cible donnée par Vercel | le site avec www |
| CNAME | api | ton-service.onrender.com | l'API |
Supprime les anciens enregistrements A ou CNAME « parking » créés par le registraire sur @ et www. La propagation prend de 5 minutes à quelques heures ; le certificat HTTPS est ensuite créé automatiquement.
4. Le webhook Moneroo
- Dans Moneroo, Developers → Webhooks, ajoute l'URL :
https://{{API}}/api/payments/moneroo/webhook- Copie le secret de signature affiché et colle-le dans
MONEROO_WEBHOOK_SECRETsur Render. Render redéploie automatiquement. - Fais un achat de test avec la passerelle de démonstration : le ticket doit s'afficher sur la page de retour en quelques secondes.
5. Passer en production
- Quand le KYC Moneroo est validé, remplace la clé
test_par la clé de production sur Render. - Le webhook de production peut avoir son propre secret : vérifie-le.
- Achète un vrai ticket au tarif le plus bas avec ton propre Mobile Money. Vérifie qu'il apparaît dans la comptabilité avec le bon opérateur.
Checklist du chapitre
Configurer le routeur MikroTik
Le hotspot, les profils, les tickets et ton portail.
1. Activer le hotspot
- Installe Winbox (sur mikrotik.com/download) et connecte-toi au routeur.
- Mets RouterOS à jour : System → Packages → Check For Updates.
- IP → Hotspot → Hotspot Setup : choisis l'interface (le bridge Wi-Fi des clients), garde les plages d'adresses proposées, DNS name par exemple
login.wifi. Ne crée pas d'utilisateur à la fin.
2. Les profils (un par tarif)
Le nom du profil doit être exactement celui saisi dans le tarif sur ta plateforme : c'est lui qui relie un ticket à son tarif.
/ip hotspot user profile add name=1h shared-users=1 rate-limit=2M/5M session-timeout=1h add name=24h shared-users=1 rate-limit=3M/8M session-timeout=1d add name=7j shared-users=1 rate-limit=3M/8M
session-timeout limite une session continue. Pour un forfait qui expire au bout d'une durée totale, utilise la colonne limit-uptime des utilisateurs (le générateur de la phase 4 peut l'ajouter) ou le paquet User Manager. Demande à Claude d'adapter le script selon ton choix.3. Créer et importer les tickets
- Dans ton tableau de bord, page Tickets, générateur de lot : choisis le tarif et la quantité.
- Copie le script RouterOS et colle-le dans New Terminal de Winbox : les utilisateurs sont créés sur le routeur.
- Importe le CSV correspondant dans la même page : les mêmes tickets sont maintenant en vente.
4. Installer ton portail
- Dans le tableau de bord, page Portail captif : choisis la zone, le style, télécharge
login.htmletredirect.html. - Dans Winbox, Files : ouvre le dossier
hotspot(ouflash/hotspot) et glisse-dépose les deux fichiers pour remplacer ceux d'origine. Gardemd5.jset le dossierimg: sans eux, la connexion casse. - Copie le bloc walled garden fourni par la page et colle-le dans le terminal.
Le bloc ressemble à ceci, avec tes domaines :
/ip hotspot walled-garden ip
add action=accept dst-host={{DOMAINE}} comment="{{NOM}} portail"
add action=accept dst-host=www.{{DOMAINE}} comment="{{NOM}} portail"
add action=accept dst-host={{API}} comment="{{NOM}} API"
add action=accept dst-host=checkout.moneroo.io comment="Moneroo checkout"
add action=accept dst-host=api.moneroo.io comment="Moneroo API"
add action=accept dst-host=process.fedapay.com comment="Passerelle"
add action=accept dst-host=api.fedapay.com comment="Passerelle"
add action=accept dst-host=fonts.googleapis.com comment="Polices"
add action=accept dst-host=fonts.gstatic.com comment="Polices"
add action=accept dst-host=wa.me comment="Assistance WhatsApp"
add action=accept dst-host=api.whatsapp.com comment="Assistance WhatsApp"
/ip hotspot walled-garden
add action=allow dst-host={{DOMAINE}}
add action=allow dst-host=*.{{DOMAINE}}
add action=allow dst-host=*.moneroo.io
add action=allow dst-host=*.fedapay.comChecklist du chapitre
Le test complet, puis le lancement
Mets-toi dans la peau d'un client, sur un téléphone qui ne connaît pas ton système.
- Oublie le réseau Wi-Fi sur ton téléphone, reconnecte-toi : le portail doit s'afficher automatiquement.
- Touche « Acheter un ticket » : la page d'achat s'ouvre sans ticket ni connexion internet préalable.
- Choisis le tarif le moins cher, saisis ton numéro, paie.
- Le ticket s'affiche. Reviens au portail, connecte-toi avec : internet fonctionne.
- Ferme tout, utilise « Retrouver mon ticket » avec ton numéro : le ticket est retrouvé.
- Dans le tableau de bord : la vente apparaît, avec le bon opérateur, le stock a baissé de 1.
Avant d'ouvrir au public
Dépannage et entretien
Les pannes réellement rencontrées, et comment travailler avec Claude dans la durée.
Le client a payé mais aucun ticket ne s'affiche
Dans l'ordre : (1) MONEROO_WEBHOOK_SECRET correct sur Render ? (2) L'URL du webhook dans Moneroo pointe bien vers ? (3) Logs Render : cherche « signature ». (4) Reste-t-il des tickets libres de ce tarif ? Le paiement est alors marqué pour remboursement.
La page Moneroo n'affiche pas mon opérateur
La méthode n'est pas activée dans ton tableau de bord Moneroo, ou la zone n'a pas le bon pays. Vérifie les deux.
« The payment method … is invalid »
Un code de méthode n'est pas accepté par Moneroo. Retire-le de countries.js : un seul code invalide bloque tout le paiement.
Erreur CORS dans la console du navigateur
CORS_ORIGIN sur Render doit contenir l'adresse exacte du site, avec https et sans barre finale, et aussi la version www.
Erreur 404 quand on rafraîchit une page du site
Il manque frontend/vercel.json avec la réécriture vers /index.html.
« Colonne inconnue » après une mise à jour
Une migration n'a pas été exécutée dans Supabase. Exécute dans l'ordre les fichiers de backend/database/migrations/ qui manquent.
Le ticket est vendu mais refusé sur le portail
Il n'existe pas sur le routeur, ou son profil ne porte pas le même nom. Vérifie dans IP → Hotspot → Users.
Le portail affiche du texte comme $(username)
Tu ouvres le fichier en dehors du routeur. Sur le routeur, ces variables sont remplacées automatiquement. Ne les modifie jamais à la main.
Travailler avec Claude dans la durée
- Une demande = une conversation. Pour une nouvelle fonction, ouvre une nouvelle session : Claude relit
CLAUDE.mdet repart propre. - Décris le problème, pas la solution. « Les clients du Togo ne voient que Moov » vaut mieux que « modifie countries.js ».
- Colle les erreurs en entier, avec la page et l'action qui l'ont provoquée.
- Commit avant chaque gros changement. Si ça tourne mal : « annule tout depuis le dernier commit ».
- Demande une relecture avant chaque mise en ligne importante : « relis les changements depuis le dernier déploiement et cherche les bugs liés à l'argent ».
Un client de {{NOM}} a payé 500 F ce matin vers 9 h avec le numéro 01 XX XX XX XX, Moneroo indique « success », mais il n'a pas reçu de ticket. Explique-moi comment retrouver ce paiement, pourquoi le ticket n'a pas été attribué, et corrige la cause. Ne touche à aucun autre paiement.Mettre à jour la plateforme
- Demande la modification à Claude, teste en local.
- Valide ; Claude fait le commit et le
git push. - Vercel et Render redéploient automatiquement à chaque push sur la branche principale.
- Si la modification ajoute une migration SQL, exécute-la dans Supabase avant le push.
Sécurité : la liste à garder sous la main
- Le dépôt GitHub est privé.
- La clé
service_role, leJWT_SECRETet les clés Moneroo ne vivent que dans.env(local) et dans Render. - Si une clé a fuité (capture d'écran, message, commit) : régénère-la immédiatement chez le fournisseur et remplace-la sur Render.
- Le montant facturé est toujours relu depuis la base, la signature du webhook toujours vérifiée.
- Active la double authentification sur GitHub, Vercel, Render, Supabase, Moneroo et ton registraire.