154 lines
6.4 KiB
Markdown
154 lines
6.4 KiB
Markdown
# Plateforme centralisée de tryouts
|
|
|
|
Application interne du club e-sport de l'UdeS : inscriptions aux sélections,
|
|
évaluations, gestion des équipes, disponibilités, contrats, et notifications
|
|
Discord.
|
|
|
|
Le site est servi **en français**, l'anglais reste accessible par le sélecteur
|
|
de la barre latérale (voir `docs/translations.md`).
|
|
|
|
---
|
|
|
|
## Démarrer
|
|
|
|
```bash
|
|
python -m venv .venv
|
|
.venv/Scripts/pip install -r requirements.txt -r requirements-dev.txt
|
|
cp app/.env.example .env # puis remplir SECRET_KEY et DATABASE_URL
|
|
.venv/Scripts/python run.py # développement, http://127.0.0.1:5000
|
|
```
|
|
|
|
`SECRET_KEY` et `DATABASE_URL` sont **obligatoires** : `create_app()` refuse
|
|
de démarrer sans eux. `DATABASE_URL` doit pointer sur PostgreSQL ; le pilote
|
|
psycopg 3 est nommé automatiquement si l'URL n'en nomme pas.
|
|
|
|
Production : `python wsgi.py` (Waitress derrière nginx). Voir
|
|
`docs/deployment.md`.
|
|
|
|
Ce sont les **deux seuls** points d'entrée.
|
|
|
|
## Vérifier
|
|
|
|
```bash
|
|
.venv/Scripts/python -m pytest # suite complète
|
|
.venv/Scripts/python -m ruff check . # lint
|
|
.venv/Scripts/python -m ruff format --check .
|
|
```
|
|
|
|
Les trois tournent en CI et y sont bloquants.
|
|
|
|
---
|
|
|
|
## Ce que fait l'application
|
|
|
|
- **Comptes et rôles** — cinq rôles : président (`admin`), gérant
|
|
(`manager`), coach, joueur (`player`), recruteur (`scout`). Le président
|
|
attribue les rôles.
|
|
- **Sélections** — organisation des tryouts, trois formats de match
|
|
(équipe contre équipe, joueur contre joueur, scrim), évaluation des
|
|
joueurs sur dix critères.
|
|
- **Équipes** — effectifs de la saison, matchs et entraînements. Le
|
|
formulaire d'entraînement affiche les disponibilités des joueurs.
|
|
- **Disponibilités** — créneaux hebdomadaires des joueurs, créneaux
|
|
réservables des coachs.
|
|
- **Notes** — un coach écrit des notes d'équipe (visibles par l'équipe) et
|
|
des notes nominatives (visibles par le joueur concerné).
|
|
- **Un-à-un** — un joueur demande une séance à son coach ; le coach répond
|
|
depuis le site ou par une réaction sur le message privé Discord.
|
|
- **Contrats** — dépôt d'un contrat par le staff, signature par le joueur.
|
|
|
|
## Comment c'est construit
|
|
|
|
Backend Python 3.12 / Flask, rendu serveur en Jinja2, CSS et JavaScript
|
|
maison, sans framework front. Base PostgreSQL via SQLAlchemy. Bot Discord
|
|
(`discord.py`) dans un fil du même processus que le serveur web.
|
|
|
|
`docs/architecture.md` contient les diagrammes (classes, paquets, flux
|
|
d'une requête).
|
|
|
|
---
|
|
|
|
## Sécurité
|
|
|
|
En place et vérifié par des tests :
|
|
|
|
- **Limitation de débit** sur la connexion (10 requêtes/minute par IP).
|
|
- **Cookies de session** `HttpOnly`, `SameSite=Lax`, `Secure`, avec
|
|
expiration effective.
|
|
- **CSRF** sur tous les formulaires, y compris la déconnexion (en POST).
|
|
- **HTTPS** forcé en production, **HSTS**.
|
|
- **CSP sans `unsafe-inline`** sur `script-src` : aucun gestionnaire
|
|
d'événement en ligne, chaque bloc `<script>` porte un nonce par requête.
|
|
- **Redirections** validées (rien ne sort du site).
|
|
- **Validation** par schémas marshmallow sur les formulaires de compte, avec
|
|
politique de mot de passe.
|
|
- **Autorisation** centralisée dans `app/permissions.py`.
|
|
- **Journal d'authentification** (`logs/auth.log`) : connexions, échecs,
|
|
changements de rôle, suppressions de compte.
|
|
- **Téléversements** vérifiés par extension *et* par signature de fichier.
|
|
|
|
Ce qui **n'est pas** fait, pour que personne ne s'y fie :
|
|
|
|
- **Aucune migration de schéma.** `db.create_all()` crée les tables
|
|
manquantes et ne modifie jamais une table existante : une colonne ajoutée
|
|
à un modèle est absente de la production.
|
|
- **Les secrets de l'historique git ne sont pas révoqués** — jeton du bot,
|
|
mot de passe PostgreSQL, `SECRET_KEY`.
|
|
- **`trusted_proxy='*'`** reste le défaut : l'en-tête `X-Forwarded-For` est
|
|
accepté de n'importe quelle source, donc la limitation par IP est
|
|
contournable. C'est désormais la variable `TRUSTED_PROXY` plutôt qu'une
|
|
constante — `docs/deployment.md` donne la valeur pour chaque topologie.
|
|
- **Les comptes créés par le formulaire d'inscription sont actifs
|
|
immédiatement** : il n'y a pas d'étape de validation par le staff. Décision
|
|
de produit en attente, voir `docs/roles-and-permissions.md`.
|
|
- **L'unicité Discord n'est pas encore garantie par PostgreSQL.** L'identité
|
|
OAuth reste désormais côté serveur, le profil ne peut plus réécrire le
|
|
snowflake et l'application refuse les nouvelles collisions. Les doublons
|
|
historiques doivent être relevés puis corrigés avant la contrainte
|
|
`UNIQUE` (`schema_report.py --check-discord-identities`).
|
|
|
|
`docs/security-checklist.md` détaille la liste avant mise en production.
|
|
|
|
### Documentation
|
|
|
|
| Document | Pour |
|
|
|---|---|
|
|
| `docs/deployment.md` | Installer, déployer, revenir en arrière |
|
|
| `docs/roles-and-permissions.md` | Qui peut faire quoi, et où c'est décidé |
|
|
| `docs/database-restore.md` | Sauvegarder et restaurer |
|
|
| `docs/database-schema.md` | Sortir de `create_all()` : relevé, Alembic, migrations |
|
|
| `docs/incident-runbook.md` | Quand quelque chose ne va pas |
|
|
| `docs/architecture.md` | Diagrammes |
|
|
| `docs/translations.md` | Ajouter ou corriger une traduction |
|
|
| `docs/security-checklist.md` | Avant une mise en production |
|
|
|
|
---
|
|
|
|
## Intégration Discord
|
|
|
|
Messages privés au coach lors d'une demande d'un-à-un, aux joueurs à la
|
|
création d'un match ou d'un entraînement les concernant, et rappel 24 h
|
|
avant un match. Les réponses se font par réaction sur le message ou depuis
|
|
le site.
|
|
|
|
L'état des messages en attente de réponse est dans `discord_pending.json`,
|
|
**non versionné** : c'est de l'état d'exécution, propre à chaque serveur.
|
|
|
|
### Mise en place
|
|
|
|
Le bot du club existe déjà ; ce qui suit ne concerne qu'une nouvelle
|
|
installation.
|
|
|
|
1. Créer une application sur le [portail développeur
|
|
Discord](https://discord.com/developers/applications), puis un bot.
|
|
2. Copier le jeton dans `DISCORD_BOT_TOKEN`.
|
|
3. Activer **Message Content Intent** dans les *Privileged Gateway Intents*.
|
|
C'est le seul intent privilégié demandé : il sert à lire le motif d'un
|
|
refus écrit en réponse au message.
|
|
4. Chaque personne doit partager un serveur avec le bot (ou l'avoir en ami)
|
|
pour recevoir un message privé, et renseigner son identifiant Discord
|
|
dans son profil (Discord → Paramètres → Avancés → Mode développeur, puis
|
|
clic droit sur son profil → Copier l'identifiant).
|
|
|
|
`/health` indique si le bot tourne et s'il est connecté.
|