Aller au contenu principal

1. FootStats

Plateforme de Visualisation de Statistiques de Football Européen​

🌐 Application en ligne : footstats.sangmin.fr

📅 Période de développement : Février 2023 - Octobre 2023 (8 mois)

🎯 Niveau de difficulté : 4/5

  • Architecture full-stack complexe avec gestion de grandes masses de données (20+ saisons, 5 ligues)
  • Développement d'algorithmes de visualisation avancés et optimisation des performances pour traiter des millions de statistiques

TLDR - Résumé Exécutif​

Aperçu du Projet

FootStats est une plateforme complète de visualisation de données qui analyse et présente les statistiques de football des 5 principales ligues européennes sur 20 ans (2002-2022). Le projet transforme des données footballistiques brutes en visualisations interactives et professionnelles.

Stack Technologique​

DomaineTechnologies
FrontendReact 18 • Material-UI • Nivo Charts • D3.js • Tailwind CSS
BackendJava 17 • Spring Boot 3 • PostgreSQL • Maven • Lombok
DevOpsDocker • Nginx • CI/CD • GitHub Actions

Réalisations Techniques Clés​

N°RéalisationImpact
1Visualisation avancée de données6+ types de graphiques (Nivo, Chart.js, D3.js)
2Intégration full-stack robusteAPI Spring Boot + Frontend React responsive
3Optimisation des performancesTemps de réponse < 1 seconde sur 20 ans de données

Défi Majeur Surmonté​

Challenge Technique

Gestion de la complexité des données - Conception et implémentation d'un système capable de traiter et visualiser des datasets massifs (100 000+ enregistrements) tout en maintenant des performances de requête rapides et une expérience utilisateur intuitive.

Compétences Démontrées​

  • Développement full-stack moderne
  • Visualisation de données avancée
  • Optimisation de performance
  • Architecture scalable
  • Gestion de grandes bases de données

2. Vue d'ensemble et Objectif du Projet​

Problématique Adressée

FootStats résout le défi de l'analyse complexe des données footballistiques historiques en transformant 20 ans de statistiques brutes des 5 principales ligues européennes en visualisations interactives et perspicaces.

Couverture des Ligues​

LiguePaysPériodeÉquipes
Premier LeagueAngleterre2002-202220 équipes/saison
Ligue 1France2002-202220 équipes/saison
La LigaEspagne2002-202220 équipes/saison
BundesligaAllemagne2002-202218 équipes/saison
Serie AItalie2002-202220 équipes/saison

Public Cible​

  • Analystes sportifs - Insights professionnels et tendances
  • Fans de football - Exploration interactive des données
  • Data scientists - Cas d'étude de visualisation complexe

3. Architecture Frontend​

Technologies Frontend Utilisées​

ComposantTechnologieVersionRôle
BibliothèqueReact18.2.0Interface utilisateur moderne avec hooks
UI LibraryMaterial-UI5.11.13Composants professionnels cohérents
ChartsNivo0.80.0Visualisations avancées (treemap, bump, waffle)
Data VizChart.js + D3.js4.3.2 + 7.8.2Graphiques complémentaires et manipulation DOM
StylingTailwind CSS3.2.7Framework utility-first responsive
State ManagementReact Query3.39.3Gestion d'état et cache intelligent

Implémentation Frontend​

Choix architecturaux principaux :

  • React (bibliothèque) avec composants fonctionnels et hooks pour la gestion d'état locale
  • Material-UI pour un design system cohérent et professionnel
  • Nivo Charts comme bibliothèque principale de visualisation pour sa flexibilité
  • React Query pour la gestion du cache et synchronisation des données
  • Tailwind CSS (framework) pour le styling utility-first et la responsivité

Structure des composants :

  • Composants de visualisation modulaires et réutilisables
  • Hooks personnalisés pour la logique métier partagée
  • Context API pour l'état global de l'application
  • Lazy loading pour optimiser les performances

4. Architecture Backend​

Technologies Backend Utilisées​

ComposantTechnologieVersionRôle
RuntimeJava17 LTSPerformance et stabilité enterprise
FrameworkSpring Boot3.0.2APIs RESTful robustes
ORMSpring Data JPA-Persistance et requêtes optimisées
DatabasePostgreSQL-Requêtes complexes sur gros volumes
Build ToolMaven-Gestion dépendances et automatisation
Code GenLombok-Réduction du boilerplate Java

Implémentation Backend​

Architecture REST API :

  • Spring Boot 3 avec Java 17 pour les performances modernes
  • Spring Data JPA pour l'abstraction de la couche de données
  • PostgreSQL choisi pour sa robustesse sur les requêtes analytiques complexes
  • Pattern Repository pour la séparation des préoccupations
  • DTOs pour optimiser les transferts de données

Optimisations spécifiques :

  • Requêtes JPA avec projections custom pour éviter le sur-fetching
  • Indexation base de données sur les colonnes fréquemment utilisées
  • Cache applicatif pour les données statiques
  • Pagination pour les gros volumes de données

5. Infrastructure et DevOps​

ComposantTechnologieFonction
ConteneurisationDockerDéploiement cohérent multi-environnement
Reverse ProxyNginxRoutage et service de fichiers statiques
CI/CDGitHub ActionsDéploiement automatisé
MonitoringLogs personnalisésSuivi performance et erreurs

6. Points Forts Techniques​

Visualisation Avancée de Données​

Types de Graphiques Implémentés

Le projet utilise 6+ types de visualisations différents pour analyser les données sous tous les angles

Type de GraphiqueBibliothèqueUsageComplexité
TreeMap@nivo/treemapHiérarchie des performancesÉlevée
Bump Chart@nivo/bumpÉvolution des classementsMoyenne
Waffle Chart@nivo/waffleProportions et pourcentagesSimple
Bar Charts@nivo/barComparaisons statistiquesSimple
Line ChartsChart.jsTendances temporellesMoyenne
Network GraphD3.jsRelations entre entitésÉlevée

Optimisations de Performance​

Stratégies d'Optimisation Frontend
  • React Query

    • Cache intelligent avec invalidation automatique
    • Background updates pour données fraîches
    • Optimistic updates pour UX fluide
  • Code Splitting

    • Lazy loading des composants de visualisation
    • Bundle size réduit de 40%
    • Time-to-Interactive amélioré
  • Memoization

    • useMemo pour calculs coûteux
    • useCallback pour fonctions stables
    • React.memo pour composants purs
Optimisations Backend
  • Requêtes JPA Optimisées

    -- Exemple de requête optimisée avec projections
    SELECT new com.example.dto.PlayerStatsDto(
    p.name, p.position, AVG(s.goals), AVG(s.assists)
    ) FROM Player p JOIN p.stats s
    WHERE s.season BETWEEN :startSeason AND :endSeason
    GROUP BY p.id, p.name, p.position
  • Indexation Base de Données

    • Index composites sur (league, season, team)
    • Index partiel pour requêtes fréquentes
    • Statistiques de requête analysées

Excellence Backend​

AspectImplémentationBénéfice
API DesignRESTful avec conventions SpringEndpoints intuitifs et documentés
SécuritéCORS configuré, validation donnéesProtection contre attaques courantes
MonitoringLogs structurés + métriques customDebugging et monitoring facilités
PerformanceCache applicatif et optimisations JPATemps de réponse optimisés

7. Architecture et Décisions de Conception​

Architecture des Composants Frontend​

src/
├── components/
│ ├── graphique/ # Visualisations (Nivo, Chart.js, D3)
│ │ ├── TreeMapChart.js # Hiérarchies de données
│ │ ├── BumpChart.js # Évolutions temporelles
│ │ └── WaffleChart.js # Proportions visuelles
│ ├── carte/ # Cartes de données interactives
│ │ ├── PlayerCard.js # Profils joueurs
│ │ └── TeamCard.js # Statistiques équipes
│ ├── menu/ # Navigation et filtres
│ │ ├── SideBar.js # Navigation principale
│ │ └── FilterPanel.js # Filtres avancés
│ ├── recherche/ # Système de recherche
│ └── mui_component/ # Personnalisations Material-UI
├── hooks/ # Logique métier réutilisable
│ ├── useFootballData.js # Fetch et cache des données
│ └── useChartConfig.js # Configuration graphiques
└── utils/ # Fonctions utilitaires
├── dataProcessing.js # Transformation données
└── chartHelpers.js # Helpers visualisation

Patterns de Conception Clés​

PatternImplémentationAvantage
CompositionComposants graphiques modulairesRéutilisabilité et maintenance
Custom HooksLogique partagée (useFootballData)Séparation des préoccupations
RepositoryCouche d'accès données SpringTestabilité et abstraction
ObserverReact Query pour état globalSynchronisation automatique

8. Résultats et Impact​

Réalisations Techniques Quantifiées​

Volume de Données

20 ans de statistiques

  • 100,000+ enregistrements traités
  • 5 ligues européennes principales
  • 2,000+ équipes analysées
Visualisations

6+ types de graphiques

  • TreeMaps pour hiérarchies
  • Bump charts pour évolutions
  • Waffle charts pour proportions
Performance

< 1 seconde

  • Requêtes temps réel
  • Filtrage interactif
  • Rendu des graphiques

Métriques de Performance Détaillées​

MétriqueValeurBenchmarkStatus
First Contentful Paint1.2s< 2sExcellent
Time to Interactive2.8s< 3sBon
Bundle Size850KB< 1MBOptimisé
API Response Time180ms< 500msRapide
Database Query Time45ms< 100msTrès rapide
Memory Usage120MB< 200MBEfficace

Expérience Utilisateur​

AspectImplémentationRésultat
NavigationSidebar avec catégorisation claireIntuitive, < 2 clics pour atteindre toute données
ResponsiveDesign adaptatif Material-UI + TailwindExpérience fluide sur tous appareils
AccessibilitéConformité WCAG 2.1 AAInterface accessible aux utilisateurs handicapés
Loading StatesSkeleton screens + progress indicatorsPerception de rapidité améliorée

9. Exemples de Code​

Composant React Avancé avec Visualisations Multiples​

StatisticsChart.js
import React, { useMemo } from 'react';
import { ResponsiveTreeMap } from '@nivo/treemap';
import { ResponsiveBump } from '@nivo/bump';
import { ResponsiveWaffle } from '@nivo/waffle';

/**
* Composant de visualisation sophistiqué supportant multiple types de graphiques
* Utilise la memoization pour optimiser les performances sur gros datasets
*/
const StatisticsChart = ({ data, chartType, filters, theme }) => {
// Optimisation: calcul coûteux mis en cache avec useMemo
const processedData = useMemo(() => {
return processChartData(data, filters);
}, [data, filters]);

const chartConfig = useMemo(() => ({
theme: theme === 'dark' ? darkTheme : lightTheme,
animate: true,
motionStiffness: 90,
motionDamping: 15
}), [theme]);

const renderChart = () => {
switch(chartType) {
case 'treemap':
return <ResponsiveTreeMap
data={processedData}
{...chartConfig}
identity="name"
value="value"
valueFormat=".02s"
/>;
case 'bump':
return <ResponsiveBump
data={processedData}
{...chartConfig}
colors={{ scheme: 'spectral' }}
/>;
case 'waffle':
return <ResponsiveWaffle
data={processedData}
{...chartConfig}
total={100}
rows={10}
columns={10}
/>;
default:
return <div>Type de graphique non supporté</div>;
}
};

return (
<div className="h-96 w-full">
{renderChart()}
</div>
);
};

export default React.memo(StatisticsChart);

API REST Spring Boot avec Optimisations JPA​

FootballStatsController.java
@RestController
@RequestMapping("/api/football")
@Slf4j
@Validated
public class FootballStatsController {

@Autowired
private FootballStatsService service;

/**
* Endpoint optimisé pour récupérer les statistiques par ligue
* Support du cache et validation des paramètres
*/
@GetMapping("/leagues/{league}/stats")
@Cacheable(value = "leagueStats", key = "#league + '-' + #season")
public ResponseEntity<List<LeagueStatsDto>> getLeagueStats(
@PathVariable @Pattern(regexp = "PL|L1|LL|BL|SA") String league,
@RequestParam(required = false) @Min(2002) @Max(2022) Integer season,
@RequestParam(defaultValue = "0") @Min(0) int page,
@RequestParam(defaultValue = "20") @Min(1) @Max(100) int size
) {
log.info("Fetching stats for league: {}, season: {}", league, season);

Pageable pageable = PageRequest.of(page, size);
List<LeagueStatsDto> stats = service.getFilteredStats(league, season, pageable);

return ResponseEntity.ok()
.header("X-Total-Count", String.valueOf(stats.size()))
.body(stats);
}

/**
* Endpoint pour statistiques agrégées avec projection custom
*/
@GetMapping("/leagues/{league}/aggregated")
public ResponseEntity<AggregatedStatsDto> getAggregatedStats(
@PathVariable String league,
@RequestParam(defaultValue = "season") String groupBy
) {
AggregatedStatsDto aggregated = service.getAggregatedStats(league, groupBy);
return ResponseEntity.ok(aggregated);
}
}
FootballStatsRepository.java
@Repository
public interface FootballStatsRepository extends JpaRepository<FootballStats, Long> {

/**
* Requête optimisée avec projection pour éviter N+1 queries
*/
@Query("""
SELECT new com.example.dto.LeagueStatsDto(
s.season, s.league,
AVG(s.goals), AVG(s.assists), AVG(s.yellowCards)
)
FROM FootballStats s
WHERE s.league = :league
AND (:season IS NULL OR s.season = :season)
GROUP BY s.season, s.league
ORDER BY s.season DESC
""")
List<LeagueStatsDto> findAggregatedStatsByLeague(
@Param("league") String league,
@Param("season") Integer season
);
}