# 🎲 Paris entre potes

Plateforme de paris **privée** façon Polymarket pour un cercle fermé de **10 personnes max**.
Monnaie **virtuelle** (jetons), pour le fun.

**Technos : PHP 8 + HTML + CSS + SQLite.** Pas de framework, pas de Composer, pas de build, pas de Node.
~17 Mo de RAM par processus PHP. La base est un simple fichier.

---

## Le principe

- N'importe quel joueur **propose** un pari (*« À quelle heure Lucas va s'endormir samedi ? »*).
- L'admin **valide**, choisit l'**arbitre** et l'heure de fermeture des mises.
- Les joueurs **misent** ; à la clôture, l'arbitre **déclare le résultat** ; les gagnants se partagent le pot.
- **Grilles** façon Loto Foot : plusieurs paris d'un coup, tout juste = jackpot, sinon cagnotte reportée.

---

## Installer sur le VPS

Il faut **PHP 8.1+ avec l'extension SQLite** et un serveur web (nginx ou Apache).
Si tu as déjà des sites PHP sur le VPS, tu as presque tout.

### 1. Copier les fichiers

```bash
cd /var/www
sudo git clone https://github.com/timeo-grrd/plateforme-de-paris.git paris
sudo apt install -y php-sqlite3                 # si pas déjà installé
sudo chown -R www-data:www-data /var/www/paris/data
```

### 2. Brancher le site

**Le dossier à exposer est `public/`, et seulement lui** (`app/` et `data/` ne doivent pas être accessibles).

**nginx + php-fpm** (crée `/etc/nginx/sites-available/paris`) :

```nginx
server {
    server_name paris.ton-domaine.fr;
    root /var/www/paris/public;
    index index.php;

    location / { try_files $uri $uri/ =404; }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;   # adapte à ta version : ls /run/php/
    }
}
```

```bash
sudo ln -s /etc/nginx/sites-available/paris /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d paris.ton-domaine.fr        # HTTPS
```

**Apache** : `DocumentRoot /var/www/paris/public` dans ton VirtualHost, puis `sudo certbot --apache`.

**Pas de PHP sur le VPS ?** Utilise Docker (aucune compilation, image officielle) :

```bash
cd /var/www/paris
sudo chown 33:33 data
docker compose up -d          # le site écoute sur 127.0.0.1:8080 → fais pointer ton reverse proxy dessus
```

> Derrière un reverse proxy, ajoute `proxy_set_header X-Forwarded-Proto $scheme;` pour que les cookies
> soient bien marqués « sécurisés » en HTTPS.

### 3. Créer le compte admin

Ouvre le site : tu arrives sur **Installation**. Choisis ton pseudo et ton mot de passe : tu es admin.
Cette page disparaît dès que le compte existe.

⚠️ Fais-le **juste après la mise en ligne** : tant que l'admin n'existe pas, le premier visiteur peut le créer.

### 4. Inviter les joueurs

**Admin → Joueurs → Générer un code**, puis envoie le lien
`https://paris.ton-domaine.fr/inscription.php?code=XXXXXXXXXX`.

### Mettre à jour

```bash
cd /var/www/paris && sudo git pull
```

C'est tout : pas de build, pas de redémarrage. La base n'est pas touchée (elle n'est pas dans Git).

### Sauvegarder

```bash
sudo -u www-data php /var/www/paris/sauvegarde.php     # → data/backups/ (garde 14 jours)
```

Automatique chaque nuit à 4 h : `sudo crontab -u www-data -e` puis ajoute
`0 4 * * * php /var/www/paris/sauvegarde.php`. Copie de temps en temps `data/backups/` hors du VPS.

---

## Réglages

Tout est dans **`app/config.php`** : nom du site, jetons de départ (1000), mise max par défaut (300),
nombre de joueurs max (10), fuseau horaire.

---

## Règles du jeu

### Rôles

| Rôle | Peut faire |
|---|---|
| **Joueur** | Proposer un pari, miser, jouer des grilles, voir le classement et son historique |
| **Arbitre** (désigné par pari) | Déclarer le résultat de **son** pari. Ne peut pas miser dessus. |
| **Admin** | Valider/refuser les propositions, annuler un pari, créer les grilles, inviter, gérer les soldes |

**Le sujet d'un pari** (la personne concernée) **ne peut pas miser** dessus : il contrôle le résultat.

### Cycle d'un pari

```
proposé ──(admin valide)──▶ ouvert ──(heure de clôture)──▶ fermé ──(arbitre)──▶ terminé
   │                          │                             │
   └─(admin refuse)▶ refusé   └─────(admin annule)──────────┴──▶ annulé (tout le monde remboursé)
```

### Calcul des gains : pari mutuel

- Toutes les mises vont dans un pot ; les gagnants se le partagent **au prorata de leur mise**.
- Personne n'a misé sur le bon résultat → **tout le monde est remboursé**.
- Les arrondis sont redistribués : la somme versée est **toujours exactement égale au pot**.
- La cote affichée (`×2,40`) = ce que rapporte 1 jeton si l'option gagne, avec les mises actuelles.

*Exemple* : pot de 300, 150 misés sur la bonne option dont 100 par toi → tu touches 200.

### Grilles

1. L'admin regroupe 2 à 8 paris ouverts, avec une mise fixe.
2. Chacun choisit une option par pari (les choix des autres sont cachés jusqu'à la fermeture).
3. Tout juste → on se partage le pot (mises + cagnotte). Personne → le pot va dans la **cagnotte** de la grille suivante.

---

## Organisation du code

```
├── public/                ← LE SEUL dossier exposé sur le web
│   ├── index.php          ← liste des paris
│   ├── pari.php           ← un pari : miser, résoudre, annuler
│   ├── proposer.php, grilles.php, grille.php, classement.php, portefeuille.php
│   ├── connexion.php, inscription.php, installation.php, deconnexion.php
│   ├── admin/             ← tableau de bord, joueurs, nouvelle grille
│   └── style.css          ← tout le design
├── app/                   ← le code PHP (inaccessible depuis le web)
│   ├── config.php         ← RÉGLAGES
│   ├── schema.sql         ← toutes les tables (commence par lire ça)
│   ├── db.php             ← connexion SQLite, création des tables, transactions
│   ├── auth.php           ← connexion, sessions, protection CSRF
│   ├── payout.php         ← calcul des gains (fonctions pures)
│   ├── markets.php        ← proposer, valider, miser, résoudre, annuler
│   ├── grids.php          ← grilles et cagnotte
│   ├── users.php          ← installation, invitations, comptes, soldes
│   ├── queries.php        ← lectures pour les pages
│   ├── layout.php         ← en-tête, pied de page, composants HTML
│   └── helpers.php        ← fonctions utilitaires
├── data/                  ← la base paris.db (créée toute seule, jamais dans Git)
├── tests/
│   ├── scenario.php       ← 12 vérifications de la logique :  php tests/scenario.php
│   └── http_test.py       ← test complet via HTTP (connexion, mises simultanées…)
└── sauvegarde.php
```

Chaque page suit le même schéma : `require bootstrap.php` → traitement du formulaire avec `handle_post()`
→ affichage. **Les pages ne touchent jamais directement aux jetons** : tout passe par `app/`.

### Lancer en local

```bash
php -S localhost:8000 -t public
```

Puis ouvre http://localhost:8000. Sur Windows, PHP s'installe avec `winget install PHP.PHP.8.3`.

---

## Sécurité

- **Ledger en ajout seul** : chaque mouvement de jetons est une ligne ; des triggers SQL refusent toute modification ou suppression. Le solde = la somme des lignes.
- **Pas de double dépense** : chaque opération d'argent se fait dans une transaction `BEGIN IMMEDIATE`. Testé : 20 mises envoyées en même temps sur 8 processus PHP → 6 acceptées (le solde le permettait), 14 refusées, solde jamais négatif.
- **Contrôle d'intégrité** sur le tableau de bord admin : si un jeton apparaît ou disparaît, ça s'affiche en rouge.
- Requêtes SQL **préparées** partout (pas d'injection SQL) ; tout l'affichage passe par `e()` (pas de XSS).
- **Jeton CSRF** sur chaque formulaire.
- Mots de passe hachés (`password_hash`) ; sessions par jeton aléatoire dont seul le SHA-256 est en base ; cookies `HttpOnly` + `SameSite`.
- **Limite de tentatives** : 5 essais / 15 min par pseudo, 20 par IP.
- Inscription **uniquement sur invitation** (code à usage unique, 7 jours), 10 joueurs max.
- Les règles (sujet/arbitre exclus, plafonds, statuts) sont vérifiées **côté serveur**, pas seulement en cachant des boutons.

---

## Plus tard

- [ ] Argent réel via cagnotte : passer `starting_balance` à 0, fixer un taux (ex. 1 € = 100 jetons), ajouter les demandes de retrait
- [ ] Notifications Discord (nouveau pari, clôture, résultat)
- [ ] Délai de contestation avant versement des gains
- [ ] Statistiques par joueur
