DNG Consulting, retour à l'accueil

Dossardeur et Open Dossard, notre vitrine technique

Dossardeur est l'application mobile qui rassemble le calendrier des épreuves cyclistes en France (FSGT, FFC, UFOLEP, FFVélo, cyclosportives). Elle s'appuie sur Open Dossard, la plateforme de gestion d'épreuves développée par DNG Consulting : engagements, classements, palmarès et challenges multi-fédérations. Les deux produits sont conçus, développés et exploités par DNG, de l'application mobile jusqu'à la base de données.

La pile technique en un coup d'œil

Mobile
React Native (New Architecture), Expo, Expo Router, TypeScript, TanStack Query, Zustand, MMKV, FlashList, Reanimated, MapLibre
Sécurité
Firebase Authentication, JWT access et refresh tokens, Passport, RBAC par rôles et par club, Expo SecureStore (Keychain, Keystore), bcrypt
Backend
NestJS, TypeORM, DTO validés (class-validator), Swagger / OpenAPI, tâches planifiées, firebase-admin, Jest, Supertest, Testcontainers
Données
PostgreSQL, migrations TypeORM versionnées, index, recherche insensible aux accents (unaccent), fonctions de fenêtrage (ROW_NUMBER() OVER)
Web
React, Vite, Tailwind CSS, Radix UI, TanStack Query et TanStack Table, React Hook Form et Zod, PWA
DevOps
Docker Compose, Nginx et TLS Let's Encrypt, GitHub Actions, GitHub Container Registry, EAS Build, Fastlane, Firebase Crashlytics et Performance

Une application mobile React Native moderne

Dossardeur est développée en React Native avec Expo et la New Architecture (Fabric, TurboModules) activée. La navigation repose sur Expo Router, un routage déclaratif basé sur le système de fichiers, avec des liens profonds (Universal Links sur iOS, App Links sur Android) qui ouvrent directement une épreuve ou son parcours. Le code est intégralement écrit en TypeScript strict.

L'interface suit les conventions de chaque plateforme : effet Liquid Glass sur iOS (expo-glass-effect) et Material Design sur Android (React Native Paper). Les longues listes d'épreuves et de classements sont rendues avec FlashList pour rester fluides, et les animations s'exécutent sur le thread UI grâce à Reanimated et aux worklets.

Dossardeur : liste des épreuves avec recherche et filtres passées, toutes ou futures
Liste des épreuves
Dossardeur : carte des épreuves avec des marqueurs colorés par fédération
Carte MapLibre
Dossardeur : vue calendrier mensuelle des épreuves
Calendrier
Dossardeur : fiche d'une épreuve avec circuit, tarifs et inscription en ligne HelloAsso
Fiche épreuve et paiement

Données serveur : TanStack Query et Zustand

Toute la donnée issue de l'API est gérée par TanStack Query (React Query) : cache, déduplication des requêtes, revalidation en arrière-plan et pull-to-refresh. La fraîcheur est réglée écran par écran, avec un staleTime adapté à chaque usage : toujours à jour pour un classement en cours, en cache prolongé pour les référentiels qui changent peu. L'état local (filtres, onboarding, préférences) est porté par Zustand et persisté avec MMKV, un stockage clé-valeur natif bien plus rapide qu'AsyncStorage.

Les types TypeScript du client sont générés depuis la spécification OpenAPI de l'API (openapi-typescript) : un changement de contrat côté serveur est détecté dès la compilation de l'application mobile.

Sécurité : Firebase Authentication et JWT

L'identité des utilisateurs est confiée à Firebase Authentication. Le backend ne fait pas confiance au client : il vérifie l'ID token Firebase avec firebase-admin, puis l'échange contre ses propres JSON Web Tokens : un access token de courte durée (15 minutes) et un refresh token (7 jours), signés par @nestjs/jwt et vérifiés par des stratégies Passport (local, JWT, JWT refresh).

Sur le téléphone, les jetons sont rangés dans Expo SecureStore, c'est-à-dire dans le Keychain iOS et le Keystore Android, jamais en clair. Côté serveur, l'autorisation repose sur un RBAC : les rôles sont portés par le JWT et contrôlés par des guards NestJS, complétés par un contrôle d'accès au niveau du club pour les organisateurs. Les mots de passe des comptes du back-office sont hachés avec bcrypt.

Dossardeur : classement d'une épreuve par catégorie
Classements par catégorie
Dossardeur : palmarès d'un coureur, saison et résultats
Palmarès d'un coureur
Dossardeur : classement d'un challenge de saison avec les points
Challenges de la saison
Dossardeur : tracé GPX d'un circuit et profil altimétrique
Tracé GPX et dénivelé

Une API NestJS modulaire

Le backend d'Open Dossard est une API REST en NestJS, découpée en modules métier : compétitions, courses et engagements, licences, clubs, challenges, tableau de bord, notifications, traces GPX, paiements et rapports. Les DTO sont validés et transformés avec class-validator et class-transformer, et la documentation Swagger / OpenAPI est générée à partir du code. La compilation passe par SWC.

L'API pilote aussi les services transverses : notifications push Firebase Cloud Messaging envoyées via firebase-admin, tâches planifiées (@nestjs/schedule), exports PDF (jsPDF) et CSV des classements, fiches d'épreuve, licences et clubs, et intégration du paiement en ligne HelloAsso pour les inscriptions.

La qualité est garantie par des tests unitaires Jest et une suite de tests de bout en bout Supertest qui s'exécute contre une vraie base PostgreSQL démarrée à la volée par Testcontainers. Les règles d'autorisation, les cycles de vie des challenges ou le paiement en ligne sont ainsi vérifiés sur un environnement identique à la production.

La donnée avec PostgreSQL

Les données sont stockées dans PostgreSQL et accédées via TypeORM, avec un schéma qui n'évolue que par des migrations versionnées (la synchronisation automatique est désactivée). Le modèle couvre licenciés, clubs, épreuves, engagements et résultats de plusieurs fédérations, chacune avec ses propres catégories et barèmes.

Nous exploitons les capacités natives de PostgreSQL plutôt que de tout recalculer côté application :

  • une recherche insensible aux accents et à la casse sur les coureurs, clubs et épreuves, avec l'extension unaccent et ILIKE ;
  • des fonctions de fenêtrage (ROW_NUMBER() OVER) et DISTINCT ON pour calculer classements, palmarès et points de challenges directement en SQL ;
  • des index ciblés sur les requêtes les plus sollicitées, et des colonnes JSONB là où la structure est variable.

Le back-office web et l'exploitation

Les organisateurs gèrent leurs épreuves dans une application web en React et Vite, avec Tailwind CSS et Radix UI pour l'accessibilité, TanStack Query et TanStack Table pour les grilles de données, React Hook Form et Zod pour la validation des formulaires. Elle est installable en PWA.

L'ensemble est conteneurisé avec Docker Compose derrière un reverse proxy Nginx avec TLS Let's Encrypt. Un pipeline GitHub Actions enchaîne release, build, tests et déploiement, avec publication des images sur GitHub Container Registry. Côté mobile, les binaires sont produits avec EAS Build et publiés sur les stores avec Fastlane, tandis que Firebase Crashlytics et Firebase Performance surveillent la stabilité et les temps de réponse en production.

Un projet, une question technique ?

Décrivez-nous votre besoin en quelques lignes, nous revenons vers vous.

conseil@dng-consulting.com