Plusieurs applications, un seul référentiel
La plateforme n’est pas une application unique, et ce n’est pas non plus une architecture microservices. C’est un ensemble d’applications autonomes — chacune avec son backend Node.js/Express et son interface Angular, son déploiement et sa propre authentification — construites autour d’une base de données partagée qui sert de point d’intégration.
- Backoffice fédéral — licences, transferts, clubs, personnes, documents.
- Compétitions — engagements, calendriers, matchs, résultats.
- CMS public — le site de la fédération, administré par la fédération elle-même.
- Actualités — une déclinaison réduite du CMS pour les fédérations qui n’ont besoin que de publier.
Le choix est assumé : aucun appel HTTP d’un backend vers un autre. Chaque interface ne parle qu’à son propre backend, et la cohérence vient du modèle de données, pas d’un maillage de services. On évite ainsi la latence en cascade, les transactions distribuées et les pannes en chaîne — au prix d’un couplage au schéma, que trois règles compensent : une seule chaîne de migrations pour tout l’ensemble, des conventions de requêtage identiques dans chaque projet, et aucune clé étrangère (l’intégrité référentielle est tenue par le code, ce qui laisse chaque application maîtresse de ses écritures).
Isolation des données : le point de départ, pas une option
Chaque fédération accède à la plateforme par son propre sous-domaine. La fédération courante est ensuite déduite du jeton d’authentification uniquement — jamais d’un paramètre d’URL, d’un corps de requête ou d’un champ de formulaire, qui sont tous falsifiables. Chaque lecture et chaque écriture est filtrée sur cette fédération, aucune requête ne joint deux fédérations, et un identifiant appartenant à une autre fédération répond 404 et non « accès refusé » : la seconde réponse confirmerait que la donnée existe.
Deux identifiants par enregistrement
Chaque objet métier porte deux clés : une clé interne, utilisée uniquement pour les jointures et jamais exposée, et un identifiant séquentiel propre à la fédération, attribué automatiquement par déclencheur à partir d’un compteur dédié. C’est ce second identifiant que voient les utilisateurs, les URLs et l’API — donc le licencié n° 1 042 de chaque fédération existe indépendamment, avec des numéros courts et sans trou, alors que la base reste unique. La règle est tenue partout : l’identifiant public n’apparaît qu’en sortie, jamais dans un filtre ni dans une jointure.
Des droits calculés, pas codés en dur
Cinq rôles fédéraux sont prédéfinis — administration générale, administration fédérale, lecture fédérale, gestion de club, lecture de club — mais les permissions attachées à chaque rôle sont paramétrables par fédération, et chaque utilisateur peut recevoir des autorisations ou des interdictions individuelles qui s’ajoutent à son rôle. L’ensemble est calculé à la connexion, embarqué dans le jeton, puis vérifié côté serveur sur chaque route et côté interface pour n’afficher que les actions réellement permises.
Le seul service partagé : les fichiers
Licences signées, pièces justificatives, photos, logos : tous les documents sont centralisés dans un service de fichiers unique, et c’est la seule dépendance qu’une application ait envers une autre. Il fonctionne à deux niveaux d’accès :
- les backends l’appellent avec des requêtes signées en HMAC ; le service n’a ni session ni compte utilisateur et ne fait confiance qu’à la signature ;
- les navigateurs accèdent aux documents privés par des URL signées à durée limitée, sans jeton d’authentification et sans jamais voir un chemin de stockage réel.
Trois détails qui font la différence à l’usage : le type MIME est validé d’après le contenu du fichier et non d’après l’en-tête déclaré ; le chemin de stockage contient obligatoirement la fédération, si bien qu’une erreur de code ne peut pas écrire dans le dossier d’une autre ; et l’envoi se fait en deux temps — dépôt temporaire puis confirmation — avec une tâche de nettoyage pour les fichiers jamais confirmés.
Six modules, activés au rythme de la fédération
Gestion de la fédération, licences et transferts, compétitions et matchs, formations/stages et diplômes, marketing et site web, finance et trésorerie. Les six partagent le même référentiel : un licencié saisi une fois est le même dans une feuille de match, dans une session de formation et dans une écriture comptable. Une fédération peut n’en activer que deux et ajouter les autres ensuite, sans reprise de données.