Portail client d’un magasin de vélo : suivi factures, parc vélos, réparations atelier, tickets support

Côté magasin, CRM Cycles est un outil de gestion riche — devis, atelier, stock, livre de police. Côté client, ce système doit aussi exister, mais sous une forme radicalement différente : un portail client autonome, accessible depuis n’importe quel navigateur, où l’acheteur d’un vélo peut consulter ses factures, suivre l’avancement de la réparation en cours à l’atelier, regarder son parc de vélos avec les dates de garantie restantes, et ouvrir un ticket de support sans téléphoner à 18h47 pendant que le commerçant ferme le magasin.

Le portail client est une application Yii2 séparée du back-office gestion, déployée sur un sous-domaine dédié (par exemple portail.magasin.fr). Une seule base de données partagée avec le back-office, mais deux applications avec leurs propres sessions, leurs propres layouts et leurs propres règles d’accès.

Pourquoi un portail client distinct, plutôt qu’un simple « espace client » dans le back-office

Beaucoup d’éditeurs CRM proposent un « espace client » comme module additionnel du logiciel principal — même base de code, même URL, juste un menu différent selon le profil connecté. Ce choix simplifie le développement mais crée trois problèmes concrets :

  • Surface d’attaque démultipliée : un même domaine expose le back-office (admin, gestion) et le frontend client. Une faille XSS ou une mauvaise configuration de cookie peut compromettre toute l’application.
  • UX confuse : le client se retrouve dans une interface conçue pour des commerçants, avec menus repliés ou cachés au lieu d’être pensés pour son usage.
  • Couplage technique : impossible de scaler indépendamment, de déployer une mise à jour critique côté client sans risquer le back-office, ou de personnaliser le frontend (couleurs magasin) sans intervenir dans le code admin.

Avec une architecture frontend séparée à la Yii2 — pattern common / backend / frontend — les modèles métier sont partagés (un client, une facture, un vélo sérialisé sont les mêmes objets en base) mais les contrôleurs, les vues, les sessions et les politiques d’accès sont indépendants. Le cookie d’identité du portail (_identity-frontend) n’a aucun rapport avec celui du back-office (_identity-backend). Un client connecté au portail ne peut accéder, même par URL forgée, à aucun écran admin.

Authentification : password, OAuth Google, OTP, 2FA

Quatre méthodes de connexion pour couvrir tous les usages :

  • Mot de passe classique — un identifiant (email du client) et un mot de passe créé à la première venue. Reset par email avec lien à durée limitée.
  • OAuth Google — login en un clic via le compte Google du client. Endpoint actionGoogleCallback côté Yii2 reçoit le token, le valide auprès de l’API Google, lie le compte au client (par adresse email) ou en crée un nouveau.
  • OTP par SMS ou email — code à 6 chiffres envoyé à usage unique. Utile pour les clients qui n’ont pas envie de mémoriser un mot de passe de plus.
  • 2FA TOTP — pour les clients pros (loueurs, équipes de course, comités d’entreprise) qui passent par le portail régulièrement et veulent une sécurité renforcée. Compatible Google Authenticator, Authy, Bitwarden.

Côté création de compte : les clients peuvent auto-s’inscrire (actionRegister) avec l’email utilisé en magasin, ou recevoir un lien d’activation envoyé par le commerçant depuis la fiche client du back-office (actionCreatePassword). Dans tous les cas, la fiche client est rapprochée automatiquement par l’email.

Dashboard : tout en un coup d’œil

Une fois connecté, le client arrive sur un tableau de bord qui résume ses interactions actives :

  • Sa dernière facture (avec lien de téléchargement PDF) et son solde — si crédit en banque chez le magasin ou facture impayée
  • Le statut en temps réel de ses ordres de réparation en cours (avec étape, technicien assigné, date estimée de retrait)
  • Ses vélos avec garantie active — date d’achat, durée restante par garantie vélo / garantie cadre
  • Ses tickets de support ouverts ou en cours, avec dernière réponse de l’équipe
  • Les relances atelier (entretien annuel approchant, vélo prêt mais pas retiré) — c’est aussi le canal de communication mou côté magasin, qui évite l’appel téléphonique

Le dashboard est volontairement plat — pas de hiérarchie de menus complexe. Chaque carte est cliquable et mène vers la vue détaillée correspondante.

Menu rétractable : profile, documents, parc, ateliers, tickets, correspondance, boutique

L’arborescence de navigation suit la même découpe que le back-office, vue côté client :

  • /portal/profile — modifier ses coordonnées, ses adresses, ses consentements (email marketing, SMS de service), son mot de passe
  • /portal/documents — historique complet des devis / commandes / factures / avoirs, avec téléchargement PDF par cliс
  • /portal/bikes — son parc de vélos sérialisés, avec photo, numéro de série, FNUCI, garanties restantes
  • /portal/repairs — ordres de réparation en cours et passés, avec leur statut (reçu, diagnostic, attente pièces, en cours, prêt à retirer, livré)
  • /portal/tickets — système de tickets de support avec fil de conversation, pièces jointes possibles
  • /portal/correspondence — historique des emails et SMS envoyés par le magasin (utile pour retrouver une promo, un devis, une notification atelier)
  • /portal/shop — lien vers la boutique e-commerce satellite si le magasin en exploite une (cf CRM Boutique)

Documents commerciaux : PDF natifs avec NF525 / Factur-X

Pour chaque ligne de la liste documents, deux téléchargements possibles côté client : le PDF classique (lisible par humain) et — si la facture est validée et le client est un professionnel assujetti à la TVA — la facture électronique Factur-X PDF/A-3 (lisible humain ET machine, conforme à la réforme française 2026-2027 et à la norme européenne EN 16931).

Côté workflow : le client professionnel peut récupérer la facture en PDF/A-3, l’envoyer à son comptable qui l’importe dans son ERP sans ressaisie. Plus de demande « vous pouvez me renvoyer la facture en format machine ? » par mail.

Statut des réparations en temps réel

Le module Réparations du portail est probablement le plus utilisé. Quand un client a déposé son vélo à l’atelier le mardi matin et qu’il appelle le jeudi pour savoir « où ça en est », le commerçant doit interrompre une vente, ouvrir le CRM, retrouver l’OR du client, lire le statut, raccrocher. Trois fois par jour. Avec le portail : le client se connecte, voit le statut « en attente pièces » ou « prêt à retirer », sait à quoi s’en tenir.

Les statuts côté client sont volontairement simplifiés par rapport aux 10 statuts du back-office : Reçu, Diagnostic en cours, Pièces commandées, En cours de réparation, Prêt à retirer, Livré. Pas besoin de connaître la nuance entre « Non affecté » et « Planifié » — c’est de la cuisine interne du planning atelier.

Tickets de support : SAV asynchrone

Le client ouvre un ticket depuis le portail : catégorie (Général, Atelier, Vente, Facturation), vélo concerné (sélection dans son parc), sujet, description. Le ticket reçoit un numéro TK-AAAAMM-XXXX et apparaît côté back-office dans la file des tickets, assignable à un membre de l’équipe.

La conversation suit un format de chat : chaque message du client ou de l’équipe forme une bulle, avec date et auteur. Le client est notifié par email à chaque réponse. Les notes internes de l’équipe (visibles uniquement côté back-office) permettent de communiquer entre collègues sans bruit côté client.

Cycle de vie : OuvertEn cours (auto à la première réponse de l’équipe) → Résolu. Si le client répond à un ticket résolu, il le réouvre automatiquement — utile pour les pannes intermittentes ou les questions de garantie qui reviennent un mois plus tard.

Sous le capot

  • App Yii2 frontend séparée, dans le dossier frontend/ du projet, avec son propre config/main.php, ses propres controllers (PortalController, SiteController), ses propres layouts (portal.php pour la zone authentifiée, portal-auth.php pour login/register).
  • Modèles partagés via le dossier common/Customer, CustomerDocument, WorkOrder, Ticket, CustomerBike sont les mêmes objets que côté back-office. Pas de duplication de logique métier.
  • Sessions isolées — cookie d’identité _identity-frontend distinct du _identity-backend. Les rôles RBAC sont aussi différents : un client n’a pas de permission « modifier », il peut juste lire ses propres données via des scopes appliqués sur chaque requête (filtre WHERE customer_id = $current_user_id).
  • OAuth Google via la lib league/oauth2-google. Callback dans actionGoogleCallback qui vérifie le token côté Google, rapproche par email, crée ou met à jour le compte.
  • 2FA TOTP : même implémentation que côté back-office (cf article sécurité), avec spomky-labs/otphp.
  • Sécurité : HTTPS only via redirect HSTS, rate limiting sur les endpoints d’auth (5 tentatives login / IP / 15 min), CAPTCHA invisible à partir de la 3ème tentative ratée. Plus le scope automatique côté backend qui rend impossible (par construction) d’accéder à un document qui n’appartient pas au client connecté.
  • Déploiement : deux vhosts Apache distincts avec deux DocumentRoot différents (le backend/web et le frontend/web). Un seul code à maintenir, deux URLs publiques : magasin.fr (back-office) et portail.magasin.fr (client).

Ce qu’on gagne au quotidien

  • Moins d’appels au magasin pour « où en est ma réparation » — le client a la réponse en deux clics, à son rythme.
  • Factures et avoirs accessibles 24/7 — fini les « vous pouvez me renvoyer la facture du 14 mars ? » trois mois après.
  • SAV asynchrone par tickets — moins de pression téléphonique, traçabilité écrite, équipe qui répond quand elle peut.
  • Sécurité par construction — sessions isolées, scopes automatiques côté backend, impossible pour un client de voir les données d’un autre même via URL manipulée.
  • Image de modernité — un magasin qui propose un portail client en 2026 envoie un signal fort aux clients pros qui choisissent leur vélociste sur la qualité du suivi, pas juste sur le prix.
Retour en haut