UGO Cycle est un détaillant spécialisé en vélos électriques au Québec. Avec plusieurs succursales et un catalogue de plus de 476 produits, l'équipe avait besoin d'un système de point de vente (POS) qui dépasse les limites des solutions génériques. Leur défi : intégrer Lightspeed R-Series, supporter le financement Affirm Canada et offrir un système de trousses (kit builder) unique à l'industrie du vélo électrique.
Chez H1Site, nous avons conçu et développé cette application POS sur mesure avec Next.js 14, Supabase et l'API Lightspeed R-Series. Dans cette étude de cas, nous détaillons chaque aspect technique du projet — de l'architecture au déploiement — pour montrer comment une application web personnalisée peut transformer les opérations d'un commerce de détail.
Le défi : les limites de Lightspeed POS
Lightspeed R-Series est un excellent système POS pour le commerce de détail standard. Cependant, UGO Cycle n'est pas un commerce standard. La vente de vélos électriques implique un processus unique : chaque vélo peut être configuré avec une trousse de composantes (moteur, batterie, écran, contrôleur, etc.) qui doit être assemblée sur mesure.
Le POS standard de Lightspeed ne supportait pas :
- Le menu trousses automatique : l'ajout automatique de composantes (moteur, batterie, écran) lorsqu'un vélo électrique est ajouté au panier. Les employés devaient chercher manuellement chaque composante, ce qui ralentissait les transactions et causait des erreurs.
- Le financement Affirm Canada : Affirm permet aux clients de financer leur achat en plusieurs versements. L'intégration n'existait pas dans Lightspeed pour le marché canadien, forçant un processus manuel fastidieux.
- L'interface tactile optimisée : l'interface Lightspeed, bien que fonctionnelle, n'était pas optimisée pour le workflow spécifique d'UGO Cycle. Les employés perdaient du temps à naviguer entre les écrans.
- Les rabais flexibles : le système de rabais par item ET par facture avec des montants fixes ou des pourcentages n'était pas assez flexible pour les promotions d'UGO Cycle.
La solution ? Construire un POS sur mesure qui s'intègre avec Lightspeed via son API, tout en ajoutant les fonctionnalités manquantes. Le meilleur des deux mondes : la puissance de Lightspeed pour la gestion d'inventaire et les rapports, combinée à une interface personnalisée pour le point de vente.
Architecture technique
L'architecture du POS UGO Cycle repose sur un stack moderne optimisé pour la performance et la fiabilité :
- Next.js 14 (App Router) : déployé sur Vercel pour un rendu rapide et des Server Actions performantes. L'App Router nous permet de structurer l'application avec des layouts partagés (sidebar POS, header admin) et du rendu côté serveur pour les pages de gestion.
- Supabase (PostgreSQL) : la base de données centrale qui stocke les tokens OAuth Lightspeed, le cache des produits et catégories, la configuration des magasins, les utilisateurs et les sessions. PostgreSQL nous donne la puissance du SQL pour des requêtes complexes et les extensions comme pg_cron pour l'automatisation.
- Lightspeed R-Series API : connexion OAuth 2.0 pour la synchronisation bidirectionnelle des produits, la création de ventes et la gestion d'inventaire. L'API REST de Lightspeed est le pont entre notre POS et leur écosystème.
- Affirm Canada : intégration OAuth pour le financement à la consommation. Le flux de checkout redirige vers Affirm pour l'approbation, puis revient au POS pour compléter la vente.
- Framer Motion : animations fluides pour l'interface tactile — transitions de panneaux, apparition du menu trousses, feedback visuel des actions utilisateur.
Le système POS : une interface tactile plein écran
L'interface POS a été conçue pour être utilisée sur des tablettes et des écrans tactiles en mode plein écran. Chaque pixel est optimisé pour la vitesse et la clarté :
- Grille produits avec images : les produits sont affichés dans une grille visuelle avec leurs photos, prix et SKU. Un employé peut identifier et ajouter un produit en un seul tap, sans avoir à lire de longues listes de texte.
- Filtrage par catégorie : les catégories Lightspeed sont synchronisées et affichées sous forme de boutons de filtre en haut de la grille. Un tap sur « Vélos électriques » filtre instantanément les 476+ produits pour n'afficher que les vélos.
- Recherche par nom et SKU : un champ de recherche en temps réel filtre les produits pendant que l'employé tape. La recherche fonctionne sur le nom du produit ET le SKU pour une flexibilité maximale.
- Panier latéral avec quantités : le panier est toujours visible sur le côté droit de l'écran. Chaque item affiche son nom, son prix, sa quantité (ajustable avec + et -) et un bouton de suppression. Le sous-total, les taxes et le total sont calculés en temps réel.
- Calcul automatique des taxes : TPS 5% + TVQ 9.975% sont calculés automatiquement sur chaque item. Le total avec taxes est toujours visible dans le panier, donnant à l'employé et au client une vue claire du montant final.
- Multi-magasin : l'application supporte plusieurs succursales — UGO Cycle (magasin principal), Mascouche et Warehouse. L'employé sélectionne son magasin à la connexion, et les produits, prix et inventaires sont filtrés en conséquence.
Le Kit Builder (Menu Trousses) : l'innovation clé
Le menu trousses est la fonctionnalité qui justifie à elle seule le développement d'un POS sur mesure. C'est l'innovation qui distingue cette application de toute solution POS du marché.
Lorsqu'un employé ajoute un vélo électrique au panier, le menu trousses s'ouvre automatiquement. Ce panneau slide-in présente 12 catégories de composantes prédéfinies :
- Moteurs : moteurs moyeu arrière, moteurs pédalier, différentes puissances (250W, 500W, 750W).
- Batteries : batteries lithium-ion de différentes capacités (10Ah, 14Ah, 17Ah, 20Ah).
- Écrans : écrans LCD et LED avec différentes fonctionnalités (compteur de vitesse, niveau de batterie, assistance au pédalage).
- Contrôleurs : contrôleurs compatibles avec les différentes configurations moteur/batterie.
- Accessoires : capteurs de pédalage, câblage, throttles, freins régénératifs, et plus encore.
Chaque composante est ajoutée au panier en un seul tap grâce à un popup slide-in optimisé pour l'écran tactile. Un bouton orange « + Trousses » apparaît sous chaque vélo dans le panier, permettant de rouvrir le menu trousses à tout moment pour modifier la configuration.
Le résultat ? Ce qui prenait auparavant 5 à 10 minutes de recherche manuelle se fait maintenant en 30 secondes. Les erreurs de configuration sont pratiquement éliminées puisque les composantes compatibles sont prédéfinies et organisées logiquement.
Intégration Lightspeed : le défi technique majeur
L'intégration avec Lightspeed R-Series via OAuth 2.0 est le pilier technique de l'application. C'est aussi le composant qui a demandé le plus de travail d'ingénierie pour assurer la fiabilité.
OAuth 2.0 avec tokens dans Supabase
Lightspeed utilise le protocole OAuth 2.0 standard avec des access tokens à durée de vie limitée et des refresh tokens. Les tokens sont stockés de manière sécurisée dans Supabase avec chiffrement au repos. Le flux d'authentification complet (autorisation, échange de code, stockage de tokens) est géré par le panel admin.
Auto-refresh via pg_cron
Le défi principal avec OAuth dans un environnement serverless (Vercel) : les tokens expirent et doivent être rafraîchis régulièrement. Dans un serveur traditionnel, un processus en arrière-plan s'en chargerait. Sur Vercel, il n'y a pas de processus persistant.
Notre solution : utiliser pg_cron, l'extension PostgreSQL de Supabase qui permet de planifier des tâches directement dans la base de données. Toutes les 3 minutes, un job pg_cron vérifie si le token est proche de l'expiration et le rafraîchit automatiquement via un appel à l'API Lightspeed.
Lock distribué pour empêcher les refresh concurrents
Dans un environnement serverless, plusieurs instances de l'application peuvent tenter de rafraîchir le token simultanément. Si deux refresh utilisent le même refresh token, Lightspeed invalide les deux et l'application perd sa connexion.
Nous avons implémenté un système de lock distribué dans PostgreSQL : avant de rafraîchir un token, le processus acquiert un verrou exclusif dans la base de données. Si le verrou est déjà pris, il attend que le premier refresh se termine et utilise le nouveau token. Cette approche garantit qu'un seul refresh s'exécute à la fois, même avec des dizaines de requêtes concurrentes.
Synchronisation des données
Les produits, catégories et magasins sont synchronisés depuis Lightspeed vers Supabase. Les ventes créées dans le POS sont envoyées à Lightspeed comme « ventes en attente » (sans prise d'inventaire immédiate), ce qui permet au gestionnaire de réviser et compléter la vente dans Lightspeed selon leur workflow habituel.
Système de rabais flexible
Le système de rabais d'UGO Cycle devait être plus flexible que ce que Lightspeed offre nativement. Nous avons développé un système à deux niveaux :
- Rabais par item : chaque produit dans le panier peut avoir un rabais individuel — soit un pourcentage (ex. 10% de réduction), soit un montant fixe (ex. 50$ de réduction). Le prix original est affiché barré avec le nouveau prix en rouge, donnant une visibilité claire sur l'économie.
- Rabais global sur facture : un rabais peut être appliqué sur le total de la facture — encore une fois en pourcentage ou en montant fixe. Ce rabais est réparti proportionnellement sur chaque item lors de l'envoi à Lightspeed pour maintenir la cohérence des rapports.
Les deux types de rabais peuvent être combinés. Le calcul des taxes (TPS + TVQ) s'ajuste automatiquement après application des rabais. Tous les rabais sont correctement transmis à Lightspeed pour que les rapports de vente reflètent la réalité.
Checkout et financement Affirm
Le flux de checkout intègre un formulaire client et le financement Affirm Canada — deux fonctionnalités critiques pour un commerce de vélos électriques où le prix moyen d'un achat dépasse souvent les 2 000$.
- Formulaire client intégré : nom, courriel, téléphone et adresse sont collectés directement dans le POS. Les informations sont envoyées à Lightspeed avec la vente pour un suivi client complet.
- Sélection du magasin de cueillette : le client choisit dans quel magasin il récupérera son vélo — UGO Cycle principal ou Mascouche. Cette information est attachée à la vente dans Lightspeed.
- Flow OAuth Affirm Canada : lorsque le client choisit le financement, il est redirigé vers la plateforme Affirm en production pour compléter sa demande de financement. Affirm évalue le crédit, propose des modalités de paiement et renvoie le client au POS avec un statut d'approbation.
- Gestion des redirections : le POS gère correctement les trois scénarios de retour d'Affirm — confirmation (vente complétée), annulation (retour au panier) et erreur (message d'erreur avec option de réessayer ou de payer autrement).
Cache Supabase : performance et indépendance
Un POS qui dépend d'une API externe pour chaque action est un POS fragile. Si l'API Lightspeed est lente ou indisponible, les ventes sont bloquées. Notre stratégie de cache résout ce problème.
- 476+ produits cachés dans Supabase : tous les produits, avec leurs images, prix, SKU et catégories, sont stockés dans PostgreSQL. Le POS charge ses données depuis Supabase, pas depuis Lightspeed.
- Chargement instantané : le POS se charge et affiche les produits instantanément, sans attendre de réponse de l'API Lightspeed. L'expérience utilisateur est fluide même si Lightspeed est lent.
- Sync cron toutes les 15 minutes : un job pg_cron synchronise les produits et catégories depuis Lightspeed vers Supabase toutes les 15 minutes. Les nouveaux produits, les changements de prix et les mises à jour d'inventaire sont reflétés automatiquement.
- Token nécessaire uniquement pour les ventes : le token OAuth Lightspeed n'est requis que lorsqu'une vente est créée. La navigation, la recherche de produits et la construction du panier fonctionnent sans connexion API active.
Cette architecture découplée signifie que même si le token Lightspeed expire ou si l'API est temporairement indisponible, les employés peuvent continuer à utiliser le POS pour préparer des ventes. Seule la soumission finale nécessite une connexion active.
Panel Admin : gestion centralisée
Le panel d'administration est le centre de contrôle du POS. Il permet aux gestionnaires de configurer et surveiller tous les aspects de l'application.
- Connexion Lightspeed : affichage du statut de connexion OAuth (connecté/déconnecté), date du dernier refresh de token, bouton pour initier ou réinitialiser la connexion OAuth. Un indicateur visuel vert/rouge donne un aperçu instantané de la santé de l'intégration.
- Gestion des produits : liste des 476+ produits synchronisés avec possibilité de toggle la visibilité de chaque produit dans le POS. Les produits discontinués ou hors saison peuvent être masqués sans les supprimer de Lightspeed.
- Gestion des utilisateurs : création et gestion des comptes employés et administrateurs. Deux rôles distincts : les employés ont accès uniquement au POS, les admins ont accès au POS et au panel d'administration.
- Authentification sécurisée : les mots de passe sont hachés avec SHA-256 côté serveur. Les sessions sont gérées via des cookies HTTP-only sécurisés pour empêcher le vol de session par JavaScript côté client.
Résultats et impact business
L'application POS sur mesure a transformé les opérations quotidiennes d'UGO Cycle :
- Temps de transaction réduit : le menu trousses automatique a éliminé les 5 à 10 minutes de recherche manuelle de composantes par vélo vendu. Avec plusieurs vélos vendus par jour, le gain de temps est considérable.
- Erreurs de configuration éliminées : avant le POS sur mesure, les erreurs de composantes (mauvais moteur, batterie incompatible) causaient des retours et des réassemblages coûteux. Le menu trousses avec ses composantes prédéfinies a pratiquement éliminé ce problème.
- Interface adaptée au workflow : au lieu de forcer les employés à s'adapter à un POS générique, le POS s'adapte à leur façon de travailler. La grille visuelle, le panier toujours visible et le menu trousses reflètent exactement le processus de vente d'UGO Cycle.
- Financement Affirm intégré : l'intégration seamless d'Affirm Canada permet aux clients de financer leur achat directement au point de vente, sans processus parallèle ni paperasse supplémentaire. Cela augmente le taux de conversion pour les achats à prix élevé.
Pour découvrir d'autres projets que nous avons réalisés, consultez notre page clients.
Leçons apprises
Ce projet nous a enseigné plusieurs leçons précieuses que nous appliquons maintenant dans tous nos projets d'applications web sur mesure :
- pg_cron pour la fiabilité des tokens OAuth : dans un environnement serverless comme Vercel, il n'y a pas de processus en arrière-plan pour rafraîchir les tokens. Déplacer cette responsabilité dans la base de données via pg_cron de Supabase est une solution élégante et fiable. Le refresh se fait indépendamment des requêtes utilisateur, ce qui élimine les problèmes de tokens expirés au moment critique d'une vente.
- Cache Supabase pour l'indépendance : ne jamais dépendre d'une API externe pour les opérations critiques du quotidien. En cachant les données dans Supabase, le POS reste fonctionnel même quand l'API Lightspeed est lente ou indisponible. La synchronisation périodique maintient les données à jour sans affecter la performance en temps réel.
- Lock distribué pour les environnements serverless : les fonctions serverless sont stateless et peuvent s'exécuter en parallèle. Pour les opérations qui ne doivent s'exécuter qu'une seule fois (comme le refresh d'un token OAuth), un lock distribué dans PostgreSQL est essentiel. Sans ce mécanisme, les refresh concurrents auraient invalidé nos tokens régulièrement.
Ces patterns — cache local, refresh automatique et lock distribué — sont applicables à toute application qui intègre une API tierce dans un environnement serverless. Nous les avons documentés et réutilisés dans nos projets suivants, notamment pour les intégrations avec d'autres plateformes e-commerce et POS.
Si vous souhaitez en apprendre davantage sur les avantages de Next.js pour ce type de projet, consultez notre article Next.js vs WordPress qui explique pourquoi nous choisissons Next.js pour les applications web complexes. Vous pouvez également lire notre étude de cas sur la création d'un portail client pour une entreprise pour voir un autre exemple de notre approche.
H1Site
Agence Web Vaudreuil