Étude de cas · Application web full-stack

La Marée Malouine

J’ai conçu une application Click & Collect qui relie les commandes en ligne au quotidien d’une poissonnerie : du choix des produits à leur retrait en boutique.

  • Click & Collect
  • React
  • TanStack Start
  • PostgreSQL
  • Stripe
  • Brevo
  • GitLab CI/CD

Voir le site · Explorer le code

Le commerce de proximité, aussi en ligne.

  1. Choisir

    Composer son panier à partir du catalogue et des promotions.

  2. Réserver & payer

    Choisir son créneau de retrait, puis régler avec Stripe.

  3. Retirer

    Recevoir la confirmation, puis récupérer sa commande en boutique.

Mon rôle
Développement full-stack

Parcours client, administration, logique métier et intégration des services de paiement et d’email.

Le périmètre
Du site à l’outil de gestion

Catalogue, commande, retrait en boutique, stocks et suivi des clients dans une même application.

Le défi technique
Fiabiliser la commande

Réserver les stocks et les créneaux, confirmer le paiement et gérer les reprises sans doublon.

Côté commerçant : les outils du quotidien

Captures de l’application exécutée en local avec des données fictives. Les commandes de démonstration illustrent le paiement au retrait ; le parcours en ligne intègre Stripe Checkout.

Administration : compteurs, recherche, filtres par statut et commandes fictives à préparer ou prêtes.Agrandir la capture

Suivre chaque commande jusqu’au retrait

Les statuts et les actions de préparation sont réunis sur un seul écran. Le commerçant retrouve une commande, la marque prête, puis récupérée.

Administration : liste des produits, quantités en stock, disponibilité, visibilité et boutons de modification.Agrandir la capture

Garder la main sur le catalogue et les stocks

Prix, quantités, disponibilité et visibilité se pilotent depuis le catalogue. Une rupture de stock est immédiatement identifiable.

Le besoin : relier la vente en ligne à la boutique

La poissonnerie doit présenter ses arrivages et ses promotions, recevoir des commandes sur des créneaux définis et faire évoluer son catalogue au quotidien. J’ai organisé l’application autour de deux usages : commander simplement sur téléphone et préparer les retraits depuis l’espace commerçant.

  • Un catalogue consultable sans compte client.
  • Des créneaux dont la capacité tient compte de la préparation.
  • Un récapitulatif et un montant définitif avant le paiement.

Des sprints et une revue chaque semaine

Le développement a été organisé en sprints, avec une revue hebdomadaire pour présenter les fonctionnalités réalisées et faire le point sur l’avancement. Ces démonstrations rendaient le travail concret : nous pouvions parcourir les écrans, échanger sur leur fonctionnement et discuter des prochaines étapes. Un rythme régulier pour confronter l’application aux besoins de la poissonnerie tout au long du projet.

Un parcours client jusqu’au retrait

Le visiteur parcourt le catalogue et compose sa sélection. La commande se déroule en trois étapes : panier, créneau de retrait et coordonnées. Il règle ensuite par carte sur la page hébergée par Stripe. Après vérification du paiement côté serveur, la commande passe à préparer ; le commerçant la marque prête, puis récupérée.

  • Catalogue filtrable et promotions visibles sur les produits concernés.
  • Récapitulatif des quantités, des tarifs et du lieu de retrait.
  • Emails de confirmation du paiement, de commande prête et d’annulation via Brevo.

Une administration pensée pour l’activité

J’ai regroupé la gestion des produits, des commandes et des retraits dans un espace protégé. Les captures de l’administration montrent les deux écrans au cœur de cette gestion ; les autres modules complètent le suivi au quotidien.

  • Produits, photos, prix, promotions datées et historique des mouvements de stock.
  • Créneaux récurrents, capacités de retrait et suivi des commandes.
  • Annulations, remboursements Stripe et reprise des opérations en attente.
  • Historique client, messagerie et paramètres de la boutique.

Le point clé : coordonner stock et paiement

Le serveur recalcule les prix et promotions, puis réserve le stock et une place de retrait dans une transaction PostgreSQL pour environ 30 minutes. Le paiement est confirmé par les événements Stripe signés ou par une vérification périodique côté serveur. Une expiration vérifiée libère les réservations ; les reprises évitent de créer une seconde commande ou de répéter une opération de paiement.

  • Vérification de la signature des webhooks et traitement des événements reçus plusieurs fois.
  • Suivi des remboursements et reprise automatique des opérations en attente.
  • Notifications enregistrées avec la commande, envoyées en arrière-plan via Brevo, avec nouvelles tentatives et suivi des envois.

Sécurité : protéger l’accès à l’administration

L’espace commerçant donne accès aux commandes et aux données clients. J’ai intégré une authentification à deux étapes : le mot de passe, puis un code temporaire d’application Authenticator (TOTP) ou une clé d’accès WebAuthn. La session administrateur n’est créée qu’après validation du parcours complet.

  • Protection contre la réutilisation d’un code TOTP et limitation des tentatives de connexion par compte et par adresse IP.
  • Gestion des méthodes de connexion et codes de secours à usage unique, dont seuls les condensats sont conservés en base.
  • Confirmation de l’identité avant une modification de sécurité, révocation des autres sessions et journalisation des changements.
  • Validation des entrées et contrôle des autorisations côté serveur, mots de passe hachés avec scrypt et cookies de session HttpOnly.

Mes choix d’architecture et de livraison

J’ai retenu React, TypeScript et TanStack Start pour réunir l’interface et le rendu serveur dans une seule application à déployer. Les routes composent les pages, les services portent les règles métier et les modules d’accès aux données utilisent Drizzle ORM et PostgreSQL. Cette séparation permet de faire évoluer la gestion sans mêler affichage et persistance.

  • Tailwind CSS pour une interface adaptée au mobile et au bureau.
  • Métadonnées, URL canoniques, sitemap et données structurées pour les pages publiques.
  • Pipeline GitLab CI/CD : tests automatisés, construction et analyse de l’image Docker avec Trivy, puis déploiement sur VPS pour les tags protégés.
  • Mode maintenance activable depuis l’administration, avec maintien de l’accès commerçant.

Tests : vérifier les scénarios qui peuvent faire défaut

La suite associe tests unitaires, tests d’intégration sur PostgreSQL et un parcours navigateur avec Playwright. Elle cible les règles métier, les accès et les reprises après échec, avec des cas comme deux commandes qui tentent de réserver la dernière place d’un créneau.

  • Règles métier : quantités, frais, créneaux et transitions de commande.
  • Intégration PostgreSQL : commandes concurrentes, stock, capacité de retrait et absence de doublons. Les tests de paiement utilisent la vraie base avec les échanges Stripe simulés : confirmation, expiration, reprise et remboursement.
  • Sécurité et navigateur : accès refusé avant le second facteur, configuration TOTP, rejet d’un code déjà utilisé, clés d’accès WebAuthn et gestion de la sécurité du compte.
  • Livraison : la CI GitLab prépare des bases de test dédiées, exécute les migrations, les tests, la compilation et les contrôles TypeScript et HTML/SEO. Le parcours Playwright dispose d’une commande séparée.

La livraison et la prise en main

Le site est en ligne et les outils de gestion permettent au commerçant d’alimenter son catalogue et d’organiser ses retraits. Un guide de prise en main documente les opérations courantes. Le projet comprend aussi un historique des actions, un export de sauvegarde et une procédure de restauration réservée à l’exploitant.

  • Guide commerçant pour les opérations du quotidien.
  • Export de sauvegarde et procédure de restauration, avec un test d’intégration dédié.

Voir le site · Explorer le code

Pour aller plus loin

Commençons par votre besoin.

Votre objectif, votre échéance, les outils que vous utilisez : quelques lignes suffisent pour engager la discussion.

Décrire mon projet