Back to Projects

VolleyxX— Conception et réalisation d’une application mobile de gestion et de notation de matchs de volley-ball

Application pour arbitres de volley déployée sur les Stores. Notation de match en temps réel, optimisation PostgreSQL, communauté d'utilisateurs actifs.

Mobile PostgreSQL Expo-SDK React-Native Firebase Prisma CI/CD
VolleyxX— Conception et réalisation d’une application mobile de gestion et de notation de matchs de volley-ball
Table des matières

Why

Les arbitres de volley amateur en région Centre-Val de Loire notent encore sur papier les performances des équipes et des joueurs sur toute une saison, sans outil numérique simple et traçable. Les solutions existantes sont trop complexes ou inadaptées à ce suivi saisonnier.

What

VolleyX est l’application mobile qui permet aux arbitres de noter les équipes tout au long d’une saison : évaluation technique, comportement sportif, notes par match, suivi global et statistiques saisonnières. Disponible sur App Store et Google Play.

How

Développée en React Native + Expo (cross-platform), Node js + PostgreSQL, authentification Firebase, hébergée sur Google Kubernetes Engine. Mode offline-first pour la saisie en match, UX conçue avec des arbitres pour une notation rapide et fiable.

Retour d’expérience technique – Decembre 2025

1. Contexte et origine du projet

Il y a quatre mois, un arbitre de volley-ball actif en ligue régionale Centre-Val de Loire m’a partagé un constat très répandu dans les clubs amateurs :

  • Notation des matchs réalisée sur papier ou tableau effaçable
  • Transmission des feuilles par photo ou ressaisie manuelle dans un tableur
  • Suivi des licences souvent approximatif (fichiers partagés + relances manuelles)
  • Absence de traçabilité fiable des évaluations individuelles des joueurs

L’objectif n’était pas de concevoir une solution nationale ou à vocation commerciale, mais de créer un outil réellement adopté par les acteurs du terrain : arbitres, entraîneurs, joueurs et responsables administratifs de club.

VolleyX

2. Fonctionnalités principales livrées (MVP – 2 mois)

  1. Inscription et connexion avec sélection de rôle (joueur – arbitre – entraîneur – administrateur de club)
  2. Consultation du statut de licence (valide / expirée / en attente) + alerte avant échéance
  3. Notation en temps réel pendant le match (scores + évaluation qualitative du joueur)
  4. Double grille d’évaluation : performance technique + comportement sportif
  5. Consultation sécurisée et filtrée des statistiques (selon le rôle de l’utilisateur)
  6. Suppression autonome et complète du compte utilisateur (exigence RGPD et App Store)

3. Architecture retenue

Type : application mobile cross-platform + backend API REST

CoucheTechnologie choisieJustification principale
Frontend mobileReact Native + Expo SDKDéveloppement rapide iOS/Android, OTA updates, build simplifié
BackendNode js + PrismaFlexibilité, typage fort, OpenAPI automatique
Base de donnéesPostgreSQL 16Contraintes d’intégrité, JSONB, performances solides
AuthentificationFirebase AuthenticationGestion déléguée des identités, JWT natif, support MFA
NotificationsExpo notificationsFiabilité cross-platform, intégration native avec Auth
HébergementGoogle Kubernetes Engine (GKE)Scalabilité horizontale, gestion automatisée, haute disponibilité

L’architecture sépare clairement :

  • la logique métier
  • le contrôle d’accès basé sur les rôles (RBAC)
  • la persistance des données

Les configurations sensibles (clés, credentials, variables d’environnement) sont gérées exclusivement via les mécanismes natifs de Google Cloud et Firebase, jamais codées en dur ni exposées dans les dépôts.

Diagramme d’architecture globale

graph TD
    A[Mobile - React Native + Expo] -->|HTTPS + JWT Firebase| B[API FastAPI]
    B -->|Vérification JWT + RBAC| C[PostgreSQL]

    subgraph Backend
        B
        D[Middleware RBAC]
        E[Service Notation]
        F[Service Licences]
        B --> D
        D --> E
        D --> F
    end

    subgraph Database
        C --> G[Users + Roles]
        C --> H[Matches]
        C --> I[Ratings - perf + behavior]
        C --> J[Licenses]
    end

    K[FCM - Notifications] -->|push| B
    B -->|push| K

    L[Club Admin] -->|licence management| B
    B -->|licence management| L

    M[GKE - Kubernetes] -->|Orchestration| B

    N[Firebase Auth] -->|Authentication| A
    A -->|Authentication| N

4. Points techniques clés traités

4.1 Modèle relationnel (extrait simplifié et anonymisé)

Le schéma est conçu pour garantir l’intégrité référentielle et permettre une évolution future sans refactor majeur.

-- Tables principales (extrait anonymisé)
CREATE TABLE users (
    id              uuid          PRIMARY KEY DEFAULT gen_random_uuid(),
    email           text          UNIQUE NOT NULL,
    role            text          NOT NULL CHECK (role IN ('joueur','arbitre','entraineur','administrateur')),
    club_id         uuid,
    created_at      timestamptz   DEFAULT now()
);

CREATE TABLE licenses (
    id              uuid          PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         uuid          REFERENCES users(id) ON DELETE CASCADE,
    status          text          NOT NULL,
    expires_at      date          NOT NULL
);

CREATE TABLE matches (
    id              uuid          PRIMARY KEY DEFAULT gen_random_uuid(),
    date            timestamptz   NOT NULL,
    club_id         uuid
);

CREATE TABLE ratings (
    id              uuid          PRIMARY KEY DEFAULT gen_random_uuid(),
    match_id        uuid          REFERENCES matches(id),
    player_id       uuid          REFERENCES users(id),
    score_technique integer       CHECK (score_technique BETWEEN 1 AND 5),
    score_comportement integer    CHECK (score_comportement BETWEEN 1 AND 5),
    created_by      uuid          REFERENCES users(id)
);

4.2 Contrôle d’accès basé sur les rôles (extrait conceptuel)

// middleware/requireRole.js

const requireRole = (...allowedRoles) => {
  return (req, res, next) => {
    const user = req.user

    if (!user || !user.role) {
      return res.status(401).json({ error: 'Non authentifié' })
    }

    if (!allowedRoles.includes(user.role)) {
      return res.status(403).json({ error: 'Accès interdit pour ce rôle' })
    }

    next()
  }
}

module.exports = requireRole

5. Principaux défis rencontrés et solutions mises en place

  • Saisie concurrente sur un même match → verrou léger + contrôle de version
  • Friction UX pour les arbitres en match → maximum 3 écrans, feedback visuel immédiat
  • Gestion fine des permissions → RBAC centralisé + tests exhaustifs
  • Fiabilité des notifications push → combinaison FCM + fallback email
  • Conformité RGPD / App Review → flow de suppression autonome + anonymisation

6. Enseignements tirés (point de vue ingénieur)

  • Une mauvaise modélisation relationnelle coûte beaucoup plus cher à corriger qu’à faire correctement dès le départ
  • La gestion des rôles semble simple → elle devient rapidement le composant le plus complexe
  • Un arbitre en plein match tolère zéro latence et zéro friction
  • Les notifications push cross-platform restent un point faible récurrent
  • Penser traçabilité et audit dès le début évite des crises de confiance

7. État actuel & perspectives

Statut : version 1.0 soumise à l’App Store (décembre 2025)
Clubs pilotes : 21 clubs en Centre-Val de Loire (~25 utilisateurs actifs)

Prochaines étapes envisagées :

  • Export PDF / CSV des rapports de match
  • Support multi-clubs pour les comités départementaux
  • Synchronisation temps réel collaborative (optionnel via Firebase ou PostgreSQL LISTEN/NOTIFY)

Je vous remercie pour votre lecture.

Technologies & Tools

Commentaires