Aller au contenu principal
StrivPath

Arrêtez d'accumuler des séances.
Suivez votre progression.

Une app web pour les athlètes qui veulent se fixer de vrais objectifs et mesurer leur progression après chaque session Strava — dashboards par sport, sync en temps réel et cycles d'objectifs récurrents.

7 moissoirs et week-ends
Solode l'archi à la prod
80%+couverture de tests
TypeScriptNestJSGraphQLNext.jsTailwind CSSPostgreSQL
strivpath.titouanauclair.com/dashboard
Dashboard global StrivPath
Genèse

Né d'un vrai besoin. Livré avec rigueur.

En Australie, à courir seul, je me heurtais toujours au même mur : Strava enregistre chaque sortie, mais ne me permet pas de me fixer de vrais objectifs et d'en suivre la progression. Régularité hebdomadaire, objectif de distance — rien de tout ça, sauf en payant une fonctionnalité à moitié faite. Je gérais tout dans un tableur.

Il y avait aussi une autre dimension : un an à l'étranger avec un GitHub quasi vide — mes meilleurs projets étaient privés, ma présence open-source inexistante. StrivPath a répondu aux deux : construire quelque chose que je voulais vraiment, et le construire comme je l'aurais fait en entreprise — stack complète, discipline complète, aucun raccourci.

Sept mois de soirées et de semaines de repos entre les shifts en mine plus tard : un SaaS entièrement déployé, 200+ tests, CI/CD automatisé du commit à la prod. Pas un prototype — un produit.

13 moisAustralie · Nouvelle-Zélande
StravaAPI tierce — OAuth · webhooks
v1.0en production
Fonctionnalités

Strava enregistre. StrivPath fait progresser.

Suivi d'objectifs

Progresser sans objectif, c'est avancer à l'aveugle : difficile de rester motivé sans savoir où l'on va. Strava enregistre tout, mais des données sans cap restent des données. StrivPath vous permet de définir des objectifs personnalisés et mesurables, suivis automatiquement après chaque sortie.

DistanceDuréeDéniveléFréquence

Sync temps réel

Dès que vous terminez une sortie, StrivPath la reçoit via webhook Strava et met à jour vos objectifs en quelques secondes. Aucune action requise. Historique complet importable jusqu'à 2 000 activités.

Dashboards par sport

Vue globale et tableaux de bord par sport : running, cyclisme, natation. Courbes d'évolution des performances, records personnels, heatmap et objectifs en cours.

Explorateur d'activités

L'intégralité de votre historique Strava importé, filtrable par sport et par période. La matière première derrière chaque objectif, consultable en un coup d'œil.

Accessibilité & qualité

Conçu pour être utilisable par tous : interface bilingue FR/EN, thèmes clair, sombre et système, navigation clavier, support lecteurs d'écran. Ce qui fait un vrai produit.

Architecture

Conçu comme un vrai SaaS.

Deux applications distinctes dans un monorepo Turborepo : un backend NestJS exposant une API GraphQL, un frontend Next.js la consommant exclusivement. Une stack 100% TypeScript : cohérente, robuste et production-grade. Le type d'architecture qu'une équipe sérieuse choisirait.

GraphQL plutôt que REST

Le modèle de données est naturellement imbriqué : activités, objectifs, progression, statistiques. REST multiplierait les endpoints et alourdirait chaque réponse : GraphQL résout ce que chaque vue demande. Les types frontend et backend sont auto-générés depuis le même schéma.

Un backend complet

Les API routes Next.js suffisent pour du CRUD simple, pas pour StrivPath : webhooks asynchrones, couche OAuth complète, recalcul de progression par activité. Un backend dédié, extensible à d'autres clients. NestJS impose la structure qu'Express laisse inventer.

Next.js : React en production

React est une librairie, Next.js est le framework de production : SSR, middleware auth, App Router. L'état de l'art React pour un SaaS. Jamais utilisé avant StrivPath : de la découverte à la mise en production.

Monorepo Turborepo

TypeScript des deux côtés : autant en tirer avantage. Un monorepo Turborepo partage la config, unifie les outils et élimine les doublons entre les deux apps. La structure qu'une équipe de 10 utiliserait, appliquée en solo.

Défis

Trois problèmes qui valaient la peine d'être résolus.

Sécurité

OAuth + JWT : les tokens Strava ne quittent jamais le backend

OAuth · JWT · httpOnly

Le problème

Après le callback OAuth, le backend reçoit les tokens Strava. Les transmettre au frontend reviendrait à exposer des credentials tiers à JavaScript, vulnérables à toute faille XSS. Authentifier le frontend sans jamais lui confier ce qu'il ne doit pas voir.

La solution

Les tokens Strava sont stockés en base dès le callback, jamais exposés au frontend. Le backend émet ses propres JWT, posés en cookies httpOnly : inaccessibles au JavaScript. Rotation avec suivi JTI : chaque refresh révoque le précédent, toute réutilisation d'un token révoqué déconnecte toutes les sessions. Rafraîchissement silencieux via Apollo Link.

Temps réel

Sync instantané via webhooks Strava

Webhooks · Async · Sécurité

Le problème

Strava envoie un POST à chaque nouvelle activité ou modification. L'app doit accuser réception en moins de 2 secondes. Passé ce délai, Strava relance la livraison. Mais recalculer la progression des objectifs actifs ne se fait pas en 2 secondes : répondre dans les temps et traiter correctement sont deux problèmes distincts.

La solution

Réponse 200 OK immédiate à Strava, traitement asynchrone en arrière-plan. Signature du webhook vérifiée à chaque réception pour rejeter toute requête non authentique. Progression des objectifs recalculée automatiquement après chaque nouvelle activité. Gestion des événements create, update, delete et révocation d'accès utilisateur.

Production

Conformité API Strava : de Stravanalytics à StrivPath

API · Conformité · Vie privée

Le problème

Déployer avec l'API Strava en production passe par un processus d'approbation non négociable : un refus signifie aucun accès. L'audit des CGU a révélé des exigences non anticipées, dont certaines imposaient des changements structurels dans l'app.

La solution

Le nom Strava étant protégé, le projet a été renommé de Stravanalytics en StrivPath. Les données GPS ont été supprimées de toutes les activités stockées. Un webhook de révocation d'accès a été implémenté pour supprimer les données utilisateur à la déconnexion. Rate limiting sur les appels sortants vers Strava avec coupure proactive.

Galerie
Dashboard global — heatmap, progression des objectifs, sessions récentes
Objectifs — suivi de progression et jalons
Dashboard sport — graphiques de progression, stats, records personnels
Détail d'activité — allure, FC, cadence, splits
Onboarding — assistant de sélection des sports
Qualité

Livré comme en équipe.

Tests

3 000+

Cas de test

15

Scénarios E2E

93 %

Couverture backend

82 %

Couverture front

Trois couches de tests couvrent le projet : des tests unitaires vérifient la logique métier et les composants React, des tests d'intégration valident les flows critiques sur une vraie PostgreSQL (auth, webhooks, sync, objectifs), et des tests E2E couvrent les parcours complets de l'API jusqu'au navigateur.

CI / CD

PR
Lint
Build
Unit
Integration
Release
E2E
Docker
Deploy

Aucun code n'atteint la production sans passer par trois paliers. Les PRs vers develop sont validées automatiquement, celles vers main ajoutent un filet E2E. Sur release, tout est re-validé, les images Docker multi-arch (amd64/arm64) buildées, puis le déploiement déclenché avec health checks bloquants.

Infrastructure

VPS · Dokploy
Traefik · Let's Encrypt
Web · Next.js
API · NestJS
PostgreSQL
Uptime Kumamonitoring
Umamianalytics

Aucun service managé. Conteneurs non-root, base de données sur réseau interne, TLS automatique. Monitoring et analytics sur la même machine, sans données tierces.

Rétrospective

Avec le recul.

Ce que j'ai appris

  • GraphQL en profondeur

    GraphQL n'était pas une découverte. Ce que StrivPath a ajouté : l'hydratation du cache Apollo en SSR, la discipline d'un pipeline codegen bout en bout, et les arbitrages de resolver que seul un projet complet fait émerger. C'est là que la maîtrise se distingue de la connaissance.

  • Next.js : un apprentissage par la pratique

    C'était ma première expérience avec Next.js. Le framework impose un choix pour chaque composant, chaque donnée : serveur ou client. Construire une auth SSR depuis zéro a rendu cette frontière concrète avant de l'avoir théorisée. C'est ce qui transforme Next.js d'un outil en un modèle mental.

  • Ownership complet, de bout en bout

    Architecture, API, frontend, DevOps, conformité, design. Construire seul force à la clarté : personne d'autre ne démêlera mes raccourcis.

Ce que je ferais différemment

  • Mode démo

    L'app a été conçue autant comme vitrine que comme produit. Mais sans compte Strava, impossible de voir ce qu'elle propose vraiment. Un compte pré-chargé avec des données fictives aurait dû être la première priorité après le MVP : c'est la décision la plus impactante pour l'objectif réel du projet.

  • GraphQL Subscriptions

    GraphQL Subscriptions est la seule partie du protocole que je n'ai jamais expérimentée. J'ai délibérément choisi le polling pour la progression de la sync : la complexité des souscriptions était disproportionnée au besoin. Ce que j'ajouterais malgré tout : les implémenter, pour l'apprentissage, pas pour le produit.