đŸŽŸ

Projet Corpo Padel

Documentation complÚte pour votre projet pédagogique

Test et Sécurité - Qualité Logiciel - Polytech Tours

📄 Cahier des charges

Document complet avec toutes les spécifications fonctionnelles, techniques et de sécurité.

  • SpĂ©cifications fonctionnelles dĂ©taillĂ©es
  • Architecture technique complĂšte
  • Exigences de sĂ©curitĂ©
  • Guide des tests
  • CritĂšres d'Ă©valuation
Consulter →

đŸ’» Starter Kit

Kit de dĂ©marrage prĂȘt Ă  l'emploi avec backend FastAPI et frontend VueJS configurĂ©s.

  • Authentification JWT fonctionnelle
  • Anti-brute force implĂ©mentĂ©
  • Structure complĂšte backend/frontend
  • Tests unitaires et E2E
  • README multi-OS
Consulter →

🎯 Informations pratiques

Durée du projet : 12 heures (développement + tests + rapport)

Stack imposée : VueJS 3 + FastAPI + SQLite

Repository GitHub : https://github.com/AndreyPividori/PolytechTours-PadelStarterKit

Compte de test : admin@padel.com / Admin@2025!

📄 Cahier des Charges - Application Corpo Padel

CAHIER DES CHARGES

Application de Gestion de Tournois
Corpo Padel

Table des MatiĂšres

  • 1. Introduction
  • 1.1 Contexte du projet
  • 1.2 Objectifs pĂ©dagogiques
  • 1.3 Glossaire
  • 2. SpĂ©cifications Fonctionnelles
  • 2.1 Gestion des rĂŽles et authentification
  • 2.2 Page d'accueil
  • 2.3 Planning
  • 2.4 Matchs
  • 2.5 RĂ©sultats
  • 2.6 Administration
  • 2.7 Profil
  • 3. SpĂ©cifications Techniques
  • 3.1 Architecture systĂšme
  • 3.2 Stack technologique
  • 3.3 ModĂšle de donnĂ©es
  • 3.4 API REST
  • 3.5 Formats et contraintes
  • 4. Exigences de SĂ©curitĂ©
  • 4.1 Authentification et autorisation
  • 4.2 Protection contre les attaques
  • 4.3 Validation des donnĂ©es
  • 4.4 Gestion des mots de passe
  • 5. SpĂ©cifications des Tests
  • 5.1 Tests unitaires
  • 5.2 Tests End-to-End
  • 5.3 Tests de sĂ©curitĂ© OWASP
  • 6. Livrables et Évaluation
  • 6.1 Livrables attendus
  • 6.2 CritĂšres d'Ă©valuation
  • 7. Annexes

1. Introduction

1.1 Contexte du projet

Ce projet pédagogique s'inscrit dans le cadre d'un cours de test et sécurité pour étudiants ingénieurs. L'objectif est de développer une application web complÚte pour gérer les tournois de padel corporatifs d'une entreprise.

Durée totale : 12 heures (développement + tests + rapport)
Travail : De 4 Ă  6 personnes par groupe
Modalité : Projet noté avec rendu de code et rapport

L'application doit permettre aux administrateurs de gérer l'ensemble des tournois (planification, équipes, résultats) et aux joueurs de suivre leur progression et leurs prochains matchs.

1.2 Objectifs pédagogiques

Ce projet vous permettra de mettre en pratique les compétences suivantes :

1.3 Glossaire

Terme Définition
Padel Sport de raquette combinant des éléments du tennis et du squash, joué en double sur un court fermé
Corpo Abréviation de "corporatif", désigne un tournoi inter-entreprises
Poule Groupe de 6 équipes qui s'affrontent dans un systÚme de championnat
Équipe BinĂŽme de joueurs reprĂ©sentant une entreprise
ÉvĂ©nement CrĂ©neau de jeu regroupant 1 Ă  3 matchs Ă  une date et heure donnĂ©es
Piste Terrain de padel identifié par un numéro
Saison Période annuelle d'un tournoi (du 1er septembre au 31 août)
Licence NumĂ©ro d'identification unique d'un joueur (format : LXXXXXX oĂč X est un chiffre)

2. Spécifications Fonctionnelles

2.1 Gestion des rĂŽles et authentification

2.1.1 Les trois rĂŽles

RĂŽle Description AccĂšs
Visiteur Utilisateur non authentifié Page d'accueil uniquement
Joueur Joueur inscrit dans au moins une équipe Toutes les pages sauf Administration
Administrateur Bénévole gestionnaire du tournoi Toutes les pages avec droits d'édition

2.1.2 Processus d'authentification

Méthode : JWT (JSON Web Token)
Durée de validité du token : 24 heures
Stockage : localStorage cÎté client

Flux d'authentification :

  1. L'utilisateur saisit son email et mot de passe
  2. Le backend vérifie les credentials
  3. Si valides, un JWT est généré contenant : user_id, email, role, exp
  4. Le token est retourné au client et stocké
  5. Chaque requĂȘte ultĂ©rieure inclut le token dans le header Authorization

2.1.3 Mécanisme anti-brute force

OBLIGATOIRE : Implémentation d'une protection contre les attaques par force brute

RĂšgles :

Implémentation technique :

Table: login_attempts
- email (TEXT)
- attempts_count (INTEGER)
- last_attempt (DATETIME)
- locked_until (DATETIME nullable)

2.2 Page d'accueil

2.2.1 Objectif

Page d'atterrissage simple et accueillante présentant l'application.

2.2.2 Contenu

2.2.3 Comportement

RĂŽle Affichage
Visiteur Message de bienvenue + Bouton "Se connecter"
Joueur / Admin Message personnalisé "Bienvenue [Prénom]" + AccÚs au menu complet

2.3 Planning

2.3.1 Objectif

Visualiser tous les événements de la saison sous forme de calendrier.

2.3.2 Vue calendrier

Affichage :

2.3.3 Structure d'un événement

ÉvĂ©nement : CrĂ©neau de jeu contenant 1 Ă  3 matchs
Champ Type Format Obligatoire
Date DATE YYYY-MM-DD Oui
Heure TIME HH:MM (24h) Oui
Matchs Liste 1 Ă  3 matchs Oui (min 1)

2.3.4 Structure d'un match

Champ Type Format Obligatoire
Numéro de piste INTEGER 1-10 Oui
Équipe 1 RĂ©fĂ©rence ID Ă©quipe Oui
Équipe 2 RĂ©fĂ©rence ID Ă©quipe Oui
Statut ENUM A_VENIR, TERMINE, ANNULE Oui
Score équipe 1 TEXT Ex: "6-4, 6-3" Non
Score équipe 2 TEXT Ex: "4-6, 3-6" Non

2.3.5 Droits par rĂŽle

Joueur

Administrateur

RĂšgle mĂ©tier : Un Ă©vĂ©nement ne peut ĂȘtre supprimĂ© que s'il n'a pas encore eu lieu (statut A_VENIR)

2.3.6 Formulaire d'ajout d'événement (Admin)

Champs :

Validations :

2.4 Matchs

2.4.1 Objectif

Afficher la liste des matchs Ă  venir dans les 30 prochains jours sous forme de liste.

2.4.2 Affichage par défaut

Information Description
Date et heure Format : "Lundi 15 janvier 2025 Ă  19:30"
Piste Numéro de piste
Équipes Nom entreprise Ă©quipe 1 vs Nom entreprise Ă©quipe 2
Joueurs Prénom Nom de chaque joueur des 2 équipes
Statut Badge colorĂ© : À venir (bleu), AnnulĂ© (rouge)

2.4.3 Filtre

Pour les joueurs

Pour les administrateurs

2.4.4 Actions administrateur

Ajouter un match

Formulaire avec les champs suivants :

Validation : VĂ©rifier qu'aucun autre match n'utilise la mĂȘme piste au mĂȘme crĂ©neau (date + heure)

Modifier un match

Supprimer un match

2.5 Résultats

2.5.1 Objectif

Consulter les résultats des matchs terminés et le classement général.

2.5.2 Vue des résultats personnels (Joueur)

Affichage :

Informations par match :

Champ Format
Date DD/MM/YYYY
Adversaires Prénom Nom (Entreprise)
Score 6-4, 6-3 (victoire en vert, défaite en rouge)
Piste Numéro

2.5.3 Classement général des entreprises

SystĂšme de points :
- Victoire : 3 points
- Défaite : 0 point
- Match annulé : ne compte pas

RĂšgles de classement :

  1. Total de points
  2. En cas d'égalité : nombre de victoires
  3. En cas d'égalité : différence de sets gagnés/perdus
  4. En cas d'égalité : ordre alphabétique
Position Entreprise Matchs joués Victoires Défaites Points
1 Entreprise A 10 8 2 24
2 Entreprise B 10 6 4 18

2.5.4 Format des scores

Format attendu : "X-Y, X-Y" ou "X-Y, X-Y, X-Y" pour un match en 3 sets
Exemple : "6-4, 3-6, 7-5"

RĂšgles de validation :

2.6 Administration

ACCÈS RÉSERVÉ : Cette page est accessible uniquement aux administrateurs. Redirection automatique vers l'accueil pour les autres rîles.

2.6.1 Gestion des joueurs

Ajouter un joueur

Formulaire :

Champ Type Validation Obligatoire
Nom TEXT 2-50 caractĂšres, lettres et espaces uniquement Oui
Prénom TEXT 2-50 caractÚres, lettres et espaces uniquement Oui
Entreprise TEXT 2-100 caractĂšres Oui
N° de licence TEXT Format : LXXXXXX (L suivi de 6 chiffres) Oui
Email EMAIL Format email valide, unique dans la base Oui
RÚgle métier : Si un des champs obligatoires est manquant ou invalide, la création est refusée avec un message d'erreur explicite.

Modifier un joueur

Supprimer un joueur

2.6.2 Gestion des équipes

Structure d'une équipe

Champ Type Description
Entreprise TEXT Nom de l'entreprise représentée
Joueur 1 Référence ID du premier joueur
Joueur 2 Référence ID du second joueur
Poule Référence ID de la poule (nullable)

RĂšgles de validation

Actions

2.6.3 Gestion des poules

Structure d'une poule

Champ Type Description
Identifiant TEXT Ex: "Poule A", "Poule B"
Équipes Liste Exactement 6 Ă©quipes
RÈGLE STRICTE : Une poule doit contenir exactement 6 équipes. La création/modification est impossible avec un nombre différent.

Actions

2.6.4 Gestion des comptes

Créer un compte pour un joueur

Prérequis : Le joueur doit déjà exister dans la base

Processus :

  1. Sélectionner un joueur existant sans compte
  2. Le systÚme génÚre automatiquement :
    • Email : celui du joueur
    • Mot de passe temporaire : gĂ©nĂ©rĂ© alĂ©atoirement
    • RĂŽle : JOUEUR par dĂ©faut
  3. Afficher le mot de passe temporaire (une seule fois)
  4. L'utilisateur devra changer son mot de passe Ă  la premiĂšre connexion
Sécurité : Le mot de passe temporaire doit contenir au minimum 12 caractÚres avec majuscules, minuscules, chiffres et caractÚres spéciaux.

Réinitialiser un mot de passe

2.7 Profil

2.7.1 Objectif

Permettre Ă  chaque utilisateur de consulter et modifier ses informations personnelles.

2.7.2 Informations affichées

Champ Modifiable Supprimable Format
Nom Oui Non 2-50 caractĂšres
Prénom Oui Non 2-50 caractÚres
Photo de profil Oui Oui JPG/PNG, max 2MB
Date de naissance Oui Oui YYYY-MM-DD
Email Oui Non Format email valide
N° de licence Non Non Lecture seule

2.7.3 RĂšgles de validation

2.7.4 Changement de mot de passe

Formulaire :

RĂšgles de validation :

3. Spécifications Techniques

3.1 Architecture systĂšme

3.1.1 Architecture globale

┌─────────────────────────────────────────────┐
│           CLIENT (Browser)                   │
│                                              │
│  ┌────────────────────────────────────┐    │
│  │         VueJS 3.x                   │    │
│  │  - Vue Router                       │    │
│  │  - Axios (HTTP client)              │    │
│  │  - TailwindCSS                      │    │
│  └────────────────────────────────────┘    │
└──────────────────┬──────────────────────────┘
                   │ HTTP/HTTPS
                   │ REST API
┌──────────────────▌──────────────────────────┐
│           SERVER                             │
│                                              │
│  ┌────────────────────────────────────┐    │
│  │       FastAPI (Python 3.11+)        │    │
│  │  - JWT Authentication               │    │
│  │  - Pydantic Validation              │    │
│  │  - SQLAlchemy ORM                   │    │
│  │  - Password Hashing (bcrypt)        │    │
│  └────────────────┬───────────────────┘    │
│                   │                          │
│  ┌────────────────▌───────────────────┐    │
│  │       SQLite Database               │    │
│  │  - File: padel_corpo.db             │    │
│  └────────────────────────────────────┘    │
└─────────────────────────────────────────────┘

3.1.2 Stack technologique imposée

Composant Technologie Version minimale
Frontend VueJS 3.3.x
Routing Vue Router 4.x
HTTP Client Axios 1.x
CSS Framework TailwindCSS 3.x
Backend FastAPI 0.104.x
Python Python 3.11+
ORM SQLAlchemy 2.x
Database SQLite 3.x
Tests Backend Pytest 7.x
Tests E2E Cypress 13.x

3.2 ModÚle de données

3.2.1 Diagramme ERD

┌──────────────────┐         ┌──────────────────┐
│   users          │         │   players        │
├───────────────────         ├───────────────────
│ id (PK)          │────────▶│ id (PK)          │
│ email (UNIQUE)   │         │ first_name       │
│ password_hash    │         │ last_name        │
│ role             │         │ company          │
│ is_active        │         │ license_number   │
│ created_at       │         │ birth_date       │
└──────────────────┘         │ photo_url        │
                              │ user_id (FK)     │
                              └─────┬────────────┘
                                    │
                         ┌──────────┮──────────┐
                         │                      │
                         ▌                      ▌
              ┌──────────────────┐   ┌──────────────────┐
              │   teams          │   │   matches        │
              ├───────────────────   ├───────────────────
              │ id (PK)          │   │ id (PK)          │
              │ company          │───│ team1_id (FK)    │
              │ player1_id (FK)  │   │ team2_id (FK)    │
              │ player2_id (FK)  │   │ event_id (FK)    │
              │ pool_id (FK)     │   │ court_number     │
              └──────┬───────────┘   │ status           │
                     │                │ score_team1      │
                     │                │ score_team2      │
                     │                └──────────────────┘
                     ▌
              ┌──────────────────┐         ┌──────────────────┐
              │   pools          │         │   events         │
              ├───────────────────         ├───────────────────
              │ id (PK)          │         │ id (PK)          │
              │ name (UNIQUE)    │         │ event_date       │
              │ created_at       │         │ event_time       │
              └──────────────────┘         │ created_at       │
                                            └──────────────────┘

┌──────────────────────┐
│   login_attempts     │
├───────────────────────
│ id (PK)              │
│ email                │
│ attempts_count       │
│ last_attempt         │
│ locked_until         │
└──────────────────────┘

3.2.2 Schéma SQL détaillé

-- Table users
CREATE TABLE users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    email TEXT NOT NULL UNIQUE,
    password_hash TEXT NOT NULL,
    role TEXT NOT NULL CHECK(role IN ('JOUEUR', 'ADMINISTRATEUR')),
    is_active BOOLEAN DEFAULT TRUE,
    must_change_password BOOLEAN DEFAULT FALSE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Table players
CREATE TABLE players (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    first_name TEXT NOT NULL,
    last_name TEXT NOT NULL,
    company TEXT NOT NULL,
    license_number TEXT NOT NULL UNIQUE,
    birth_date DATE,
    photo_url TEXT,
    user_id INTEGER UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL,
    CONSTRAINT chk_license_format CHECK(license_number GLOB 'L[0-9][0-9][0-9][0-9][0-9][0-9]')
);

-- Table pools
CREATE TABLE pools (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Table teams
CREATE TABLE teams (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    company TEXT NOT NULL,
    player1_id INTEGER NOT NULL,
    player2_id INTEGER NOT NULL,
    pool_id INTEGER,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (player1_id) REFERENCES players(id) ON DELETE CASCADE,
    FOREIGN KEY (player2_id) REFERENCES players(id) ON DELETE CASCADE,
    FOREIGN KEY (pool_id) REFERENCES pools(id) ON DELETE SET NULL,
    CONSTRAINT chk_different_players CHECK(player1_id != player2_id)
);

-- Table events
CREATE TABLE events (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    event_date DATE NOT NULL,
    event_time TIME NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Table matches
CREATE TABLE matches (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    event_id INTEGER NOT NULL,
    team1_id INTEGER NOT NULL,
    team2_id INTEGER NOT NULL,
    court_number INTEGER NOT NULL CHECK(court_number BETWEEN 1 AND 10),
    status TEXT NOT NULL DEFAULT 'A_VENIR' CHECK(status IN ('A_VENIR', 'TERMINE', 'ANNULE')),
    score_team1 TEXT,
    score_team2 TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (event_id) REFERENCES events(id) ON DELETE CASCADE,
    FOREIGN KEY (team1_id) REFERENCES teams(id) ON DELETE CASCADE,
    FOREIGN KEY (team2_id) REFERENCES teams(id) ON DELETE CASCADE,
    CONSTRAINT chk_different_teams CHECK(team1_id != team2_id)
);

-- Table login_attempts
CREATE TABLE login_attempts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    email TEXT NOT NULL,
    attempts_count INTEGER DEFAULT 0,
    last_attempt TIMESTAMP,
    locked_until TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Indexes pour performances
CREATE INDEX idx_players_user_id ON players(user_id);
CREATE INDEX idx_teams_players ON teams(player1_id, player2_id);
CREATE INDEX idx_teams_pool ON teams(pool_id);
CREATE INDEX idx_matches_event ON matches(event_id);
CREATE INDEX idx_matches_teams ON matches(team1_id, team2_id);
CREATE INDEX idx_matches_status ON matches(status);
CREATE INDEX idx_events_date ON events(event_date);
CREATE INDEX idx_login_attempts_email ON login_attempts(email);

3.3 API REST

3.3.1 Convention de nommage

3.3.2 Endpoints - Authentification

POST /auth/login

Description : Authentifier un utilisateur

Request Body :

{
  "email": "john.doe@example.com",
  "password": "SecureP@ssw0rd"
}

Response Success (200) :

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "user": {
    "id": 1,
    "email": "john.doe@example.com",
    "role": "JOUEUR",
    "must_change_password": false
  }
}

Response Error (401) :

{
  "detail": "Email ou mot de passe incorrect",
  "attempts_remaining": 3
}

Response Locked (403) :

{
  "detail": "Compte bloqué",
  "locked_until": "2025-10-18T15:30:00",
  "minutes_remaining": 28
}

POST /auth/change-password

Description : Changer son mot de passe

Authentification : Requise

Request Body :

{
  "current_password": "OldP@ssw0rd",
  "new_password": "NewSecureP@ssw0rd123!",
  "confirm_password": "NewSecureP@ssw0rd123!"
}

Response Success (200) :

{
  "message": "Mot de passe modifié avec succÚs"
}

POST /auth/logout

Description : Déconnecter l'utilisateur

Authentification : Requise

3.3.3 Endpoints - Joueurs

GET /players

Description : Liste tous les joueurs (Admin uniquement)

Authentification : Admin

Response (200) :

{
  "players": [
    {
      "id": 1,
      "first_name": "John",
      "last_name": "Doe",
      "company": "Tech Corp",
      "license_number": "L123456",
      "birth_date": "1990-05-15",
      "photo_url": null,
      "has_account": true
    }
  ],
  "total": 1
}

GET /players/{id}

Description : Détails d'un joueur

Authentification : Requise

POST /players

Description : Créer un joueur (Admin uniquement)

Authentification : Admin

Request Body :

{
  "first_name": "John",
  "last_name": "Doe",
  "company": "Tech Corp",
  "license_number": "L123456",
  "email": "john.doe@example.com"
}

Validation :

PUT /players/{id}

Description : Modifier un joueur (Admin uniquement)

DELETE /players/{id}

Description : Supprimer un joueur (Admin uniquement)

Condition : Le joueur ne doit appartenir à aucune équipe active

3.3.4 Endpoints - Équipes

GET /teams

Description : Liste toutes les équipes

Query Params :

Response (200) :

{
  "teams": [
    {
      "id": 1,
      "company": "Tech Corp",
      "players": [
        {
          "id": 1,
          "first_name": "John",
          "last_name": "Doe"
        },
        {
          "id": 2,
          "first_name": "Jane",
          "last_name": "Smith"
        }
      ],
      "pool": {
        "id": 1,
        "name": "Poule A"
      }
    }
  ],
  "total": 1
}

POST /teams

Description : Créer une équipe (Admin uniquement)

Request Body :

{
  "company": "Tech Corp",
  "player1_id": 1,
  "player2_id": 2,
  "pool_id": 1
}

Validations :

PUT /teams/{id}

Description : Modifier une équipe (Admin uniquement)

Condition : Aucun match joué

DELETE /teams/{id}

Description : Supprimer une équipe (Admin uniquement)

Condition : Aucun match joué

3.3.5 Endpoints - Poules

GET /pools

Description : Liste toutes les poules

Response (200) :

{
  "pools": [
    {
      "id": 1,
      "name": "Poule A",
      "teams_count": 6,
      "teams": [...]
    }
  ]
}

POST /pools

Description : Créer une poule (Admin uniquement)

Request Body :

{
  "name": "Poule A",
  "team_ids": [1, 2, 3, 4, 5, 6]
}

Validation :

PUT /pools/{id}

Description : Modifier une poule (Admin uniquement)

Condition : Aucun match joué dans la poule

DELETE /pools/{id}

Description : Supprimer une poule (Admin uniquement)

Condition : Aucun match joué dans la poule

3.3.6 Endpoints - ÉvĂ©nements

GET /events

Description : Liste tous les événements

Query Params :

Response (200) :

{
  "events": [
    {
      "id": 1,
      "event_date": "2025-11-15",
      "event_time": "19:30",
      "matches": [
        {
          "id": 1,
          "court_number": 1,
          "team1": {...},
          "team2": {...},
          "status": "A_VENIR"
        }
      ]
    }
  ]
}

POST /events

Description : Créer un événement (Admin uniquement)

Request Body :

{
  "event_date": "2025-11-15",
  "event_time": "19:30",
  "matches": [
    {
      "court_number": 1,
      "team1_id": 1,
      "team2_id": 2
    },
    {
      "court_number": 2,
      "team1_id": 3,
      "team2_id": 4
    }
  ]
}

Validations :

PUT /events/{id}

Description : Modifier un événement (Admin uniquement)

DELETE /events/{id}

Description : Supprimer un événement (Admin uniquement)

Condition : Tous les matchs doivent avoir le statut A_VENIR

3.3.7 Endpoints - Matchs

GET /matches

Description : Liste des matchs

Query Params :

Response (200) :

{
  "matches": [
    {
      "id": 1,
      "event": {
        "date": "2025-11-15",
        "time": "19:30"
      },
      "court_number": 1,
      "team1": {
        "id": 1,
        "company": "Tech Corp",
        "players": [...]
      },
      "team2": {
        "id": 2,
        "company": "Innov Ltd",
        "players": [...]
      },
      "status": "A_VENIR",
      "score_team1": null,
      "score_team2": null
    }
  ],
  "total": 1
}

POST /matches

Description : Créer un match (Admin uniquement)

PUT /matches/{id}

Description : Modifier un match (Admin uniquement)

Request Body (exemple - mise Ă  jour du score) :

{
  "status": "TERMINE",
  "score_team1": "6-4, 6-3",
  "score_team2": "4-6, 3-6"
}

Validation du score :

DELETE /matches/{id}

Description : Supprimer un match (Admin uniquement)

Condition : Statut = A_VENIR

3.3.8 Endpoints - Résultats

GET /results/my-results

Description : Résultats de l'utilisateur connecté

Authentification : Joueur

Response (200) :

{
  "results": [
    {
      "match_id": 1,
      "date": "2025-10-15",
      "opponents": {
        "company": "Innov Ltd",
        "players": ["Alice Martin", "Bob Dupont"]
      },
      "score": "6-4, 6-3",
      "result": "VICTOIRE",
      "court_number": 1
    }
  ],
  "statistics": {
    "total_matches": 10,
    "wins": 7,
    "losses": 3,
    "win_rate": 70.0
  }
}

GET /results/rankings

Description : Classement général des entreprises

Response (200) :

{
  "rankings": [
    {
      "position": 1,
      "company": "Tech Corp",
      "matches_played": 10,
      "wins": 8,
      "losses": 2,
      "points": 24,
      "sets_won": 18,
      "sets_lost": 6
    }
  ]
}

3.3.9 Endpoints - Profil

GET /profile/me

Description : Profil de l'utilisateur connecté

Authentification : Requise

Response (200) :

{
  "user": {
    "id": 1,
    "email": "john.doe@example.com",
    "role": "JOUEUR"
  },
  "player": {
    "id": 1,
    "first_name": "John",
    "last_name": "Doe",
    "company": "Tech Corp",
    "license_number": "L123456",
    "birth_date": "1990-05-15",
    "photo_url": "/uploads/profile_1.jpg"
  }
}

PUT /profile/me

Description : Modifier son profil

Request Body :

{
  "first_name": "John",
  "last_name": "Doe",
  "birth_date": "1990-05-15",
  "email": "john.doe@newemail.com"
}

POST /profile/me/photo

Description : Upload photo de profil

Content-Type : multipart/form-data

Max size : 2MB

Formats : .jpg, .jpeg, .png

DELETE /profile/me/photo

Description : Supprimer la photo de profil

3.3.10 Endpoints - Administration

POST /admin/accounts/create

Description : Créer un compte pour un joueur

Authentification : Admin

Request Body :

{
  "player_id": 1,
  "role": "JOUEUR"
}

Response (201) :

{
  "message": "Compte créé avec succÚs",
  "email": "john.doe@example.com",
  "temporary_password": "T3mp@ryP@ss2025!Xy",
  "warning": "Ce mot de passe ne sera affiché qu'une seule fois"
}

POST /admin/accounts/{user_id}/reset-password

Description : Réinitialiser le mot de passe d'un utilisateur

Authentification : Admin

Response (200) :

{
  "message": "Mot de passe réinitialisé",
  "temporary_password": "N3wT3mp@ryP@ss!",
  "warning": "Ce mot de passe ne sera affiché qu'une seule fois"
}

3.4 Formats et Contraintes

3.4.1 Formats de dates et heures

Type Format Exemple Regex
Date YYYY-MM-DD 2025-11-15 ^\d{4}-\d{2}-\d{2}$
Heure HH:MM 19:30 ^([01]\d|2[0-3]):([0-5]\d)$
Timestamp ISO 8601 2025-11-15T19:30:00Z -

3.4.2 Formats de validation

Champ Regex / RĂšgle Message d'erreur
Email ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ "Format d'email invalide"
Licence ^L\d{6}$ "Le numĂ©ro de licence doit ĂȘtre au format LXXXXXX"
Nom/PrĂ©nom ^[a-zA-ZÀ-Ăż\s'-]{2,50}$ "2 Ă  50 caractĂšres, lettres uniquement"
Score ^(\d+-\d+)(,\s*\d+-\d+){1,2}$ "Format de score invalide (ex: 6-4, 6-3)"
Court 1 <= n <= 10 "Le numĂ©ro de piste doit ĂȘtre entre 1 et 10"

3.4.3 Codes de statut HTTP

Code Signification Utilisation
200 OK RequĂȘte rĂ©ussie (GET, PUT)
201 Created Ressource créée (POST)
204 No Content Suppression réussie (DELETE)
400 Bad Request Données invalides
401 Unauthorized Non authentifié
403 Forbidden AccÚs interdit (rÎle insuffisant ou compte bloqué)
404 Not Found Ressource inexistante
409 Conflict Conflit (email/licence déjà utilisé)
422 Unprocessable Entity Validation Pydantic échouée
500 Internal Server Error Erreur serveur

4. Exigences de Sécurité

PRIORITÉ MAXIMALE : La sĂ©curitĂ© est un critĂšre d'Ă©valuation majeur de ce projet. Toutes les exigences de cette section sont obligatoires.

4.1 Authentification et Autorisation

4.1.1 JWT (JSON Web Tokens)

Configuration obligatoire :

Implémentation :

# Exemple Python avec PyJWT
import jwt
from datetime import datetime, timedelta

def create_access_token(user_id: int, email: str, role: str) -> str:
    payload = {
        "sub": user_id,
        "email": email,
        "role": role,
        "exp": datetime.utcnow() + timedelta(hours=24)
    }
    return jwt.encode(payload, SECRET_KEY, algorithm="HS256")

4.1.2 Protection des routes

Middleware d'authentification :

Middleware d'autorisation :

Route Authentification RĂŽle requis
/api/v1/auth/login Non -
/api/v1/profile/* Oui Tous
/api/v1/players (GET) Oui Admin
/api/v1/admin/* Oui Admin
/api/v1/matches (POST/PUT/DELETE) Oui Admin

4.2 Protection contre les attaques

4.2.1 Injection SQL

OBLIGATOIRE : Utilisation exclusive de l'ORM SQLAlchemy. Aucune requĂȘte SQL brute n'est autorisĂ©e.

Exemple correct :

# ✅ CORRECT - Utilisation de l'ORM
user = db.query(User).filter(User.email == email).first()

# ❌ INTERDIT - RequĂȘte SQL brute
user = db.execute(f"SELECT * FROM users WHERE email = '{email}'")

4.2.2 XSS (Cross-Site Scripting)

Protection cÎté backend :

Protection cÎté frontend :

Exemple de sanitization :

import bleach

def sanitize_input(text: str) -> str:
    # Supprime tous les tags HTML
    return bleach.clean(text, tags=[], strip=True)

4.2.3 CSRF (Cross-Site Request Forgery)

Protection :

4.2.4 Brute Force (Anti-bot)

IMPLÉMENTATION REQUISE : MĂ©canisme de blocage aprĂšs 5 tentatives Ă©chouĂ©es

Algorithme :

    CREATE TABLE login_attempts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    email TEXT NOT NULL,
    attempts_count INTEGER DEFAULT 0,
    last_attempt TIMESTAMP,
    locked_until TIMESTAMP NULL
);
1. Tentative de connexion reçue
2. Vérifier dans login_attempts si l'email est bloqué
   - Si locked_until > maintenant : retourner 403 avec temps restant
3. Vérifier les credentials
   - Si invalides :
     * Incrémenter attempts_count
     * Si attempts_count >= 5 :
       - Définir locked_until = maintenant + 30 minutes
     * Retourner 401 avec tentatives restantes
   - Si valides :
     * Réinitialiser attempts_count à 0
     * Retourner le token
Protection SQL Injection 0.5 Utilisation ORM uniquement Headers de sĂ©curitĂ© 0.5 X-Content-Type-Options, etc. TESTS (4 points) Tests unitaires backend 2 Couverture >= 70%, scĂ©narios complets Tests E2E Cypress 2 Parcours visiteur, joueur, admin QUALITÉ DU CODE (2 points) Organisation et structure 0.5 SĂ©paration des responsabilitĂ©s Respect des conventions 0.5 PEP8 (Python), style VueJS Gestion des erreurs 0.5 Messages clairs, logging Documentation (README) 0.5 Installation, configuration, utilisation RAPPORT (1 point) QualitĂ© du rapport 1 ClartĂ©, structure, screenshots BONUS (max +2 points) Tests OWASP +1 Tests de sĂ©curitĂ© avancĂ©s FonctionnalitĂ©s supplĂ©mentaires +0.5 Export PDF, statistiques avancĂ©es Interface exceptionnelle +0.5 UX/UI trĂšs soignĂ©e

5. Spécifications des Tests

5.1 Tests Unitaires (Backend Python)

5.1.1 Framework et organisation

Framework : Pytest

Structure :

tests/
├── conftest.py              # Fixtures globales
├── test_auth.py             # Tests authentification
├── test_players.py          # Tests joueurs
├── test_teams.py            # Tests Ă©quipes
├── test_matches.py          # Tests matchs
├── test_events.py           # Tests Ă©vĂ©nements
├── test_security.py         # Tests sĂ©curitĂ©
└── test_validation.py       # Tests validation

5.1.2 Couverture minimale requise

OBJECTIF : Couverture minimale de 70% du code backend

Commande pour mesurer la couverture :

pytest --cov=app --cov-report=html --cov-report=term

5.1.3 Exemple de test

# tests/test_auth.py
import pytest
from fastapi.testclient import TestClient
from app.main import app

client = TestClient(app)

def test_login_success(test_db, test_user):
    """Test connexion avec credentials valides"""
    response = client.post("/api/v1/auth/login", json={
        "email": "test@example.com",
        "password": "ValidP@ssw0rd123"
    })
    
    assert response.status_code == 200
    data = response.json()
    assert "access_token" in data
    assert data["user"]["email"] == "test@example.com"
    assert data["user"]["role"] == "JOUEUR"

def test_login_invalid_password(test_db, test_user):
    """Test connexion avec mot de passe invalide"""
    response = client.post("/api/v1/auth/login", json={
        "email": "test@example.com",
        "password": "WrongPassword"
    })
    
    assert response.status_code == 401
    data = response.json()
    assert "attempts_remaining" in data

def test_brute_force_protection(test_db, test_user):
    """Test blocage aprÚs 5 tentatives échouées"""
    # Faire 5 tentatives échouées
    for i in range(5):
        response = client.post("/api/v1/auth/login", json={
            "email": "test@example.com",
            "password": "WrongPassword"
        })
        assert response.status_code == 401
    
    # La 6Ăšme tentative doit ĂȘtre bloquĂ©e
    response = client.post("/api/v1/auth/login", json={
        "email": "test@example.com",
        "password": "ValidP@ssw0rd123"
    })
    
    assert response.status_code == 403
    data = response.json()
    assert "locked_until" in data
    assert "minutes_remaining" in data

5.2 Tests End-to-End (Cypress ou autre)

5.2.1 Exemple Configuration Cypress

Installation :

npm install --save-dev cypress

Structure :

cypress/
├── e2e/
│   ├── auth.cy.js           # Tests authentification
│   ├── player.cy.js         # Tests joueur
│   ├── admin.cy.js          # Tests admin
│   └── navigation.cy.js     # Tests navigation
├── fixtures/
│   └── users.json           # DonnĂ©es de test
└── support/
    └── commands.js          # Commandes custom

5.2.2 Exemple de test Cypress

// cypress/e2e/auth.cy.js

describe('Authentification', () => {
  beforeEach(() => {
    cy.visit('http://localhost:5173')
  })

  it('Affiche la page de login', () => {
    cy.contains('Se connecter').should('be.visible')
    cy.get('input[type="email"]').should('be.visible')
    cy.get('input[type="password"]').should('be.visible')
  })

  it('Connexion avec credentials valides', () => {
    cy.get('input[type="email"]').type('joueur@example.com')
    cy.get('input[type="password"]').type('ValidP@ssw0rd123')
    cy.get('button[type="submit"]').click()
    
    // Vérifier la redirection
    cy.url().should('include', '/dashboard')
    cy.contains('Bienvenue').should('be.visible')
  })

  it('Connexion échoue avec mauvais mot de passe', () => {
    cy.get('input[type="email"]').type('joueur@example.com')
    cy.get('input[type="password"]').type('WrongPassword')
    cy.get('button[type="submit"]').click()
    
    // Vérifier le message d'erreur
    cy.contains('Email ou mot de passe incorrect').should('be.visible')
    cy.contains('tentatives restantes').should('be.visible')
  })

  it('Bloque le compte aprÚs 5 tentatives échouées', () => {
    // Faire 5 tentatives
    for (let i = 0; i < 5; i++) {
      cy.get('input[type="email"]').clear().type('joueur@example.com')
      cy.get('input[type="password"]').clear().type('WrongPassword')
      cy.get('button[type="submit"]').click()
      cy.wait(500)
    }
    
    // Vérifier le blocage
    cy.contains('Compte bloqué').should('be.visible')
    cy.contains('minutes').should('be.visible')
  })
})

5.3 Tests de Sécurité OWASP (Bonus)

BONUS : Ces tests ne sont pas obligatoires mais rapportent des points supplémentaires

5.3.1 OWASP Top 10

Tests recommandés :

Vulnérabilité Test Outil
Injection SQL Tentatives d'injection dans les formulaires sqlmap, manuel
Authentification cassée Brute force, session hijacking Burp Suite
XSS Injection de scripts dans les champs texte XSStrike
Exposition de données Vérifier les réponses API Manuel
ContrĂŽle d'accĂšs AccĂšs aux ressources sans autorisation Manuel

5.3.2 Checklist de sécurité

□ Les mots de passe sont-ils hashĂ©s avec bcrypt?
□ Les tokens JWT expirent-ils correctement?
□ Les entrĂ©es utilisateur sont-elles sanitizĂ©es?
□ Le mĂ©canisme anti-brute force fonctionne-t-il?
□ Les rĂŽles sont-ils correctement vĂ©rifiĂ©s?
□ Les messages d'erreur ne divulguent-ils pas d'informations sensibles?
□ Les fichiers uploadĂ©s sont-ils validĂ©s?
□ Les headers de sĂ©curitĂ© sont-ils prĂ©sents?
□ HTTPS est-il forcĂ© en production?
□ Les secrets sont-ils dans des variables d'environnement?

6. Livrables et Évaluation

6.1 Livrables attendus

6.1.1 Code source

Format : Archive ZIP ou repository Git
Date limite : 31/12/2025

Contenu obligatoire :

6.1.2 Rapport

Format :

Structure du rapport :

  1. Introduction
    • PrĂ©sentation du projet
    • Objectifs
  2. Architecture
    • SchĂ©ma d'architecture
    • Choix technologiques
    • ModĂšle de donnĂ©es
  3. Fonctionnalités implémentées
    • Description dĂ©taillĂ©e
    • Screenshots
  4. Sécurité
    • Mesures implĂ©mentĂ©es
    • Tests de sĂ©curitĂ©
    • VulnĂ©rabilitĂ©s identifiĂ©es et corrigĂ©es
  5. Tests
    • StratĂ©gie de test
    • Couverture
    • RĂ©sultats
  6. Difficultés rencontrées
  7. Améliorations possibles
  8. Conclusion

7. Annexes

7.1 Kit de démarrage

Un kit de démarrage est fourni avec ce cahier des charges. Il contient :

Important : Le kit de dĂ©marrage fournit uniquement la base. Toutes les autres fonctionnalitĂ©s doivent ĂȘtre dĂ©veloppĂ©es par vous.

7.2 Commandes utiles

7.2.1 Backend

# Installation
cd backend
python -m venv venv
source venv/bin/activate  # Linux/Mac
venv\Scripts\activate     # Windows
pip install -r requirements.txt

# Lancement
uvicorn app.main:app --reload --port 8000

# Tests
pytest
pytest --cov=app --cov-report=html

# Migrations (si Alembic utilisé)
alembic revision --autogenerate -m "description"
alembic upgrade head

7.2.2 Frontend

# Installation
cd frontend
npm install

# Lancement dev
npm run dev

# Build production
npm run build

# Tests E2E
npx cypress open
npx cypress run

7.3 Variables d'environnement

Fichier backend/.env :

# Database
DATABASE_URL=sqlite:///./padel_corpo.db

# Security
SECRET_KEY=your-secret-key-here-change-in-production
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=1440

# CORS
ALLOWED_ORIGINS=http://localhost:5173

# Upload
UPLOAD_DIR=./uploads
MAX_UPLOAD_SIZE=2097152

Fichier frontend/.env :

VITE_API_BASE_URL=http://localhost:8000/api/v1

7.4 Ressources recommandées

7.4.1 Documentation officielle

7.4.2 Tutoriels utiles

7.5 Exemples de wireframes

7.5.1 Page de login

┌─────────────────────────────────────────┐
│                                         │
│           đŸŽŸ CORPO PADEL                │
│                                         │
│     ┌─────────────────────────────┐    │
│     │  Email                      │    │
│     │  ________________________   │    │
│     │                             │    │
│     │  Mot de passe               │    │
│     │  ________________________   │    │
│     │                             │    │
│     │      [ Se connecter ]       │    │
│     │                             │    │
│     │  Tentatives restantes: 5    │    │
│     └─────────────────────────────┘    │
│                                         │
└─────────────────────────────────────────┘

7.5.2 Planning (vue joueur)

┌─────────────────────────────────────────┐
│  🏠 Accueil | 📅 Planning | âšœ Matchs   │
│  📊 RĂ©sultats | đŸ‘€ Profil               │
├──────────────────────────────────────────
│                                         │
│  PLANNING NOVEMBRE 2025                 │
│                                         │
│  [<]  NOVEMBRE 2025  [>]                │
│                                         │
│  L  M  M  J  V  S  D                    │
│              1  2  3                    │
│  4  5  6  7  8 [9] 10                   │
│  11 12 13 14 ●15 16 17                  │
│  18 19 20 ●22 23 24                     │
│  25 26 27 28 29 30                      │
│                                         │
│  ● = ÉvĂ©nements planifiĂ©s               │
│                                         │
│  DÉTAILS DU 15 NOVEMBRE                 │
│  ┌───────────────────────────────────┐ │
│  │ 19:30 - Piste 1                   │ │
│  │ Tech Corp vs Innov Ltd            │ │
│  └───────────────────────────────────┘ │
│                                         │
└─────────────────────────────────────────┘

7.5.3 Administration

┌─────────────────────────────────────────┐
│  ADMINISTRATION                         │
├──────────────────────────────────────────
│                                         │
│  [Joueurs] [Équipes] [Poules] [Comptes]│
│                                         │
│  GESTION DES JOUEURS                    │
│                                         │
│  [+ Nouveau joueur]        🔍 Recherche │
│                                         │
│  ┌─────────────────────────────────────┐│
│  │ Nom      PrĂ©nom   Entreprise  📝 🗑 ││
│  ├──────────────────────────────────────│
│  │ Dupont   Jean     Tech Corp   ✏ ❌ ││
│  │ Martin   Alice    Innov Ltd   ✏ ❌ ││
│  │ Durand   Bob      StartCo     ✏ ❌ ││
│  └─────────────────────────────────────┘│
│                                         │
│  Total: 3 joueurs                       │
│                                         │
└─────────────────────────────────────────┘

7.6 RÚgles métier récapitulatives

Entité RÚgle
Joueur Tous les champs obligatoires doivent ĂȘtre renseignĂ©s
Joueur Numéro de licence unique au format LXXXXXX
Joueur Email unique
Joueur Suppression impossible si dans une équipe
Équipe Les 2 joueurs doivent ĂȘtre de la mĂȘme entreprise
Équipe Un joueur ne peut ĂȘtre que dans une Ă©quipe par saison
Équipe Modification/suppression impossible si matchs jouĂ©s
Poule Exactement 6 équipes obligatoires
Poule Nom unique
ÉvĂ©nement Date >= aujourd'hui
ÉvĂ©nement 1 Ă  3 matchs par Ă©vĂ©nement
ÉvĂ©nement Suppression impossible si matchs terminĂ©s
Match Une piste ne peut accueillir qu'un match par créneau
Match Une équipe ne peut jouer qu'un match par événement
Match Suppression uniquement si statut A_VENIR
Score Format "X-Y, X-Y" ou "X-Y, X-Y, X-Y"
Classement Victoire = 3 points, Défaite = 0 point
Login Blocage 30 min aprÚs 5 tentatives échouées
Mot de passe Min 12 caractÚres, maj, min, chiffre, spécial
    # Application Corpo Padel
    
    ## Description
    Application de gestion de tournois corporatifs de padel.
    
    ## Prérequis
    - Python 3.11+
    - Node.js 18+
    - SQLite 3
    
    ## Installation
    
    ### Backend
    ```bash
    cd backend
    python -m venv venv
    
    # Linux/Mac
    source venv/bin/activate
    
    # Windows
    venv\Scripts\activate
    
    pip install -r requirements.txt
    ```
    
    ### Frontend
    ```bash
    cd frontend
    npm install
    ```
    
    ## Configuration
    
    ### Backend
    Créer un fichier `.env` dans le dossier backend :
    ```
    DATABASE_URL=sqlite:///./padel_corpo.db
    SECRET_KEY=votre-cle-secrete-ici
    ```
    
    ### Frontend
    Créer un fichier `.env` dans le dossier frontend :
    ```
    VITE_API_BASE_URL=http://localhost:8000/api/v1
    ```
    
    ## Lancement
    
    ### Backend
    ```bash
    cd backend
    uvicorn app.main:app --reload --port 8000
    ```
    
    Le backend sera accessible sur http://localhost:8000
    
    ### Frontend
    ```bash
    cd frontend
    npm run dev
    ```
    
    Le frontend sera accessible sur http://localhost:5173
    
    ## Comptes de test
    
    ### Administrateur
    - Email: admin@padel.com
    - Mot de passe: Admin@2025!
    
    ### Joueur
    - Email: joueur@padel.com
    - Mot de passe: Joueur@2025!
    
    ## Tests
    
    ### Tests unitaires backend
    ```bash
    cd backend
    pytest
    pytest --cov=app --cov-report=html
    ```
    
    ### Tests E2E
    ```bash
    cd frontend
    npx cypress open
    ```
    
    ## Structure du projet
    
    ```
    .
    ├── backend/
    │   ├── app/
    │   │   ├── api/          # Routes API
    │   │   ├── models/       # Modùles SQLAlchemy
    │   │   ├── schemas/      # SchĂ©mas Pydantic
    │   │   ├── services/     # Logique mĂ©tier
    │   │   └── main.py       # Point d'entrĂ©e
    │   └── tests/
    ├── frontend/
    │   ├── src/
    │   │   ├── components/   # Composants Vue
    │   │   ├── views/        # Pages
    │   │   ├── router/       # Configuration routing
    │   │   └── App.vue
    │   └── cypress/
    └── README.md
    ```
    
    ## Fonctionnalités implémentées
    
    - ✅ Authentification JWT avec anti-brute force
    - ✅ Gestion des joueurs, Ă©quipes, poules
    - ✅ Planning et matchs
    - ✅ RĂ©sultats et classements
    - ✅ Administration
    - ✅ Profils utilisateurs
    
    ## Sécurité
    
    - Hashing des mots de passe avec bcrypt
    - Protection anti-brute force (5 tentatives max)
    - Validation des entrées (Pydantic + frontend)
    - Protection XSS
    - Utilisation exclusive de l'ORM (pas de SQL brut)
    - Headers de sécurité
    
    ## Auteurs
    [Vos noms]
    
    ## Licence
    Projet pédagogique - Formation Ingénieur
    ```
    

7.9 Checklist avant rendu

Vérifiez ces points avant de rendre votre projet :
    □ L'application dĂ©marre correctement en suivant le README
    □ Tous les comptes de test fonctionnent
    □ Le mĂ©canisme anti-brute force est opĂ©rationnel
    □ Les mots de passe sont hashĂ©s dans la base
    □ Toutes les validations sont en place
    □ Les tests unitaires passent (couverture >= 70%)
    □ Les tests E2E passent
    □ Le rapport PDF est complet (10-15 pages)
    □ Le code est commentĂ© et propre
    □ Les fichiers .env ne contiennent pas de vraies valeurs sensibles
    □ Le fichier .gitignore exclut venv/, node_modules/, .env
    □ Les requirements.txt et package.json sont à jour
    □ Aucune erreur console dans le frontend
    □ Aucune erreur dans les logs backend
    □ Les messages d'erreur sont clairs pour l'utilisateur
    □ La navigation entre les pages fonctionne
    □ Les rĂŽles sont correctement vĂ©rifiĂ©s
    □ Les routes protĂ©gĂ©es ne sont pas accessibles sans auth
    □ Le classement se calcule correctement
    □ Les filtres de matchs fonctionnent
    □ Les formulaires ont une validation temps rĂ©el
    

7.10 Calendrier suggéré (12h)

Heure TĂąche
H0-H1 Prise en main du kit de démarrage, compréhension du CDC
H1-H3 ModÚle de données + API joueurs/équipes/poules
H3-H5 API événements/matchs + Frontend (composants de base)
H5-H7 Pages Planning, Matchs, Résultats (frontend + backend)
H7-H8 Page Administration + Gestion des comptes
H8-H9 Profil utilisateur + Upload photo
H9-H10 Tests unitaires (backend) + Tests E2E
H10-H11 Corrections bugs, améliorations sécurité, tests complémentaires
H11-H12 Rédaction du rapport technique
Conseil : Faites des commits réguliers pour ne pas perdre votre travail. Testez au fur et à mesure plutÎt que tout à la fin.
---

Bon courage !

N'hésitez pas à consulter la documentation officielle des frameworks utilisés.

Version 1.0 - Octobre 2025
Cahier des charges - Projet pédagogique Test & Sécurité

đŸ’» Starter Kit - Corpo Padel

Kit de dĂ©marrage prĂȘt Ă  l'emploi pour votre projet pĂ©dagogique

📩 Contenu du Kit

Backend (FastAPI)

backend/
├── app/
│   ├── api/
│   │   ├── auth.py          ✅ Routes d'authentification
│   │   └── deps.py          ✅ DĂ©pendances (get_current_user)
│   ├── core/
│   │   ├── config.py        ✅ Configuration
│   │   └── security.py      ✅ JWT + hashing
│   ├── models/
│   │   └── models.py        ✅ User + LoginAttempt
│   ├── schemas/
│   │   └── auth.py          ✅ SchĂ©mas Pydantic
│   ├── database.py          ✅ Configuration SQLAlchemy
│   └── main.py              ✅ Application FastAPI
├── tests/
│   ├── conftest.py          ✅ Fixtures
│   ├── test_auth.py         ✅ Tests authentification
│   ├── test_security.py     ✅ Tests sĂ©curitĂ©
│   └── test_validation.py   ✅ Tests validation
├── .env.example
├── requirements.txt
└── README.md
            

Frontend (VueJS)

frontend/
├── src/
│   ├── components/
│   │   └── NavBar.vue       ✅ Barre de navigation
│   ├── router/
│   │   └── index.js         ✅ Routing avec guards
│   ├── services/
│   │   └── api.js           ✅ Client Axios + intercepteurs
│   ├── stores/
│   │   └── auth.js          ✅ Store Pinia authentification
│   ├── views/
│   │   ├── HomePage.vue     ✅ Page d'accueil
│   │   └── LoginPage.vue    ✅ Page de connexion
│   ├── App.vue
│   └── main.js
├── cypress/
│   ├── e2e/
│   │   ├── auth.cy.js       ✅ Tests E2E auth
│   │   └── navigation.cy.js ✅ Tests navigation
│   └── support/
│       └── commands.js      ✅ Commandes custom
├── .env.example
├── package.json
└── README.md
            

🚀 Installation Rapide

1. Cloner le repository

git clone https://github.com/AndreyPividori/PolytechTours-PadelStarterKit.git
cd PolytechTours-PadelStarterKit

2. Installation Backend

cd backend

# Créer l'environnement virtuel
python -m venv venv

# Activer l'environnement
source venv/bin/activate  # Linux/Mac
venv\Scripts\activate     # Windows

# Installer les dépendances
pip install -r requirements.txt

# Configuration
cp .env.example .env

# Générer une SECRET_KEY
python -c "import secrets; print(secrets.token_urlsafe(32))"
# Copier la clé générée dans le fichier .env

# Initialiser la base de données
python -c "from app.database import init_db; init_db()"

# Lancer le serveur
uvicorn app.main:app --reload --port 8000
✅ Backend prĂȘt !
API : http://localhost:8000
Documentation : http://localhost:8000/docs

3. Installation Frontend (nouveau terminal)

cd frontend

# Installer les dépendances
npm install

# Configuration
cp .env.example .env

# Lancer le serveur de développement
npm run dev
✅ Frontend prĂȘt !
Application : http://localhost:5173

🔐 Compte de Test

Email : admin@padel.com

Mot de passe : Admin@2025!

Ce compte administrateur est créé automatiquement lors de l'initialisation de la base de données.

✅ FonctionnalitĂ©s ImplĂ©mentĂ©es

  • ✅ Authentification JWT : SystĂšme complet avec gĂ©nĂ©ration et validation de tokens
  • ✅ Anti-brute force : Blocage automatique aprĂšs 5 tentatives Ă©chouĂ©es pendant 30 minutes
  • ✅ Hashing des mots de passe : Utilisation de bcrypt pour sĂ©curiser les mots de passe
  • ✅ Page d'accueil : Interface d'accueil responsive avec message de bienvenue
  • ✅ Page de login : Formulaire de connexion avec validation et gestion des erreurs
  • ✅ Navigation protĂ©gĂ©e : Vue Router avec guards pour protĂ©ger les routes
  • ✅ Store d'authentification : Gestion d'Ă©tat avec Pinia
  • ✅ Client API : Axios configurĂ© avec intercepteurs pour les tokens
  • ✅ Tests unitaires : Exemples de tests avec Pytest
  • ✅ Tests E2E : Exemples de tests avec Cypress

📝 À DĂ©velopper

Les fonctionnalitĂ©s suivantes doivent ĂȘtre dĂ©veloppĂ©es selon le cahier des charges :

  • đŸ”Č Gestion des joueurs (CRUD complet)
  • đŸ”Č Gestion des Ă©quipes (crĂ©ation, modification, suppression)
  • đŸ”Č Gestion des poules (6 Ă©quipes par poule)
  • đŸ”Č Planning avec calendrier mensuel
  • đŸ”Č Gestion des Ă©vĂ©nements (1 Ă  3 matchs par Ă©vĂ©nement)
  • đŸ”Č Liste des matchs Ă  venir (30 prochains jours)
  • đŸ”Č Saisie et affichage des rĂ©sultats
  • đŸ”Č Classement gĂ©nĂ©ral des entreprises
  • đŸ”Č Interface d'administration complĂšte
  • đŸ”Č Profil utilisateur avec upload de photo
  • đŸ”Č Tests complets (couverture ≄ 70%)

đŸ§Ș Lancer les Tests

Tests Backend (Pytest)

cd backend
source venv/bin/activate  # ou venv\Scripts\activate

# Lancer tous les tests
pytest

# Avec couverture de code
pytest --cov=app --cov-report=html

# Ouvrir le rapport de couverture
# Le fichier htmlcov/index.html contient le rapport détaillé

Tests E2E (Cypress)

cd frontend

# Mode interactif (recommandé pour le développement)
npx cypress open

# Mode headless (pour CI/CD)
npx cypress run

🔧 DĂ©pannage

Erreur : "Port 8000 already in use"

# Linux/Mac
lsof -ti:8000 | xargs kill -9

# Windows
netstat -ano | findstr :8000
taskkill /PID <PID> /F

Erreur : "Module not found" (Backend)

# Vérifier que l'environnement virtuel est activé
# Vous devriez voir (venv) dans votre terminal

pip install -r requirements.txt

Erreur : CORS

Vérifiez que ALLOWED_ORIGINS dans backend/.env correspond à l'URL du frontend :

ALLOWED_ORIGINS=http://localhost:5173

Erreur : "Cannot find module" (Frontend)

cd frontend
rm -rf node_modules package-lock.json
npm install

🌿 Workflow Git RecommandĂ©

Créer votre propre repository

# AprÚs avoir cloné le starter kit
cd PolytechTours-PadelStarterKit

# Supprimer le remote d'origine
git remote remove origin

# Ajouter votre remote
git remote add origin <url-de-votre-nouveau-repo>

# Créer une branche develop
git checkout -b develop

# Pousser sur votre repository
git push -u origin main
git push -u origin develop

Workflow de développement

# Créer une branche pour chaque fonctionnalité
git checkout develop
git checkout -b feature/gestion-joueurs

# Développer, tester, commiter
git add .
git commit -m "feat: ajout CRUD joueurs"

# Pousser la branche
git push origin feature/gestion-joueurs

# Merger dans develop aprĂšs validation
git checkout develop
git merge feature/gestion-joueurs

📚 Structure des Commits

Utilisez des messages de commit clairs avec préfixes :

  • feat: nouvelle fonctionnalitĂ©
  • fix: correction de bug
  • test: ajout/modification de tests
  • docs: documentation
  • refactor: refactoring
  • style: formatage
git commit -m "feat: ajout de la gestion des équipes"
git commit -m "fix: correction bug anti-brute force"
git commit -m "test: ajout tests pour les matchs"

🏆 Conseils pour RĂ©ussir

💡 Recommandations importantes

  • Commencez par le modĂšle de donnĂ©es : CrĂ©ez d'abord toutes les tables nĂ©cessaires
  • DĂ©veloppez par itĂ©ration : ImplĂ©mentez une fonctionnalitĂ© complĂšte (backend + frontend + tests) avant de passer Ă  la suivante
  • Testez continuellement : Ne laissez pas les tests pour la fin, Ă©crivez-les au fur et Ă  mesure
  • Commits rĂ©guliers : Faites des commits frĂ©quents avec des messages clairs
  • Lisez la documentation : FastAPI et Vue ont d'excellentes documentations officielles
  • RĂ©utilisez le code existant : Le pattern d'authentification peut ĂȘtre rĂ©utilisĂ© pour d'autres endpoints
  • Validez partout : Backend ET frontend pour une meilleure expĂ©rience utilisateur

📞 Ressources Utiles

🎉 Vous ĂȘtes prĂȘt !

Tout le nĂ©cessaire est en place pour commencer votre projet. Bon dĂ©veloppement ! đŸŽŸ