# Installation

## 1. Pré-requis

- hébergement mutualisé PHP 8.2+ ;
- MariaDB/MySQL ;
- extensions PHP PDO/MySQL, cURL, Sodium ;
- HTTPS ;
- SMTP sortant ;
- HTTPS sortant vers l'API OVHcloud ;
- pour le webmail : Roundcube 1.7.x et accès IMAP/SMTP OVH.

## 2. Installer le portail

1. Importer `sql/schema.sql`.
2. `cp config/config.example.php config/config.php`
3. Renseigner DB, SMTP, OVH, domaines.
4. Générer la clé :
   `php -r 'echo base64_encode(random_bytes(32)), PHP_EOL;'`
5. `composer install --no-dev --optimize-autoloader`
6. Le DocumentRoot doit être `public/`, jamais la racine du projet.
7. `display_errors=Off`, `log_errors=On`.

## 3. Premier administrateur

Générer :
`php -r "echo password_hash('UN-MOT-DE-PASSE-FORT', PASSWORD_DEFAULT), PHP_EOL;"`

Puis :
`INSERT INTO users(login,display_name,password_hash,role) VALUES('admin','Administrateur','HASH','ADMIN');`

## 4. Roundcube : boîtes personnelles

Installation classique Roundcube. L'utilisateur entre son adresse complète et son mot de passe OVH.
Le portail ne reçoit pas ce secret.

## 5. Roundcube : boîtes partagées

Copier `roundcube-plugin/portal_shared` dans `plugins/portal_shared`.

Copier :
`config.inc.php.dist` -> `config.inc.php`

Renseigner la même BDD et la même clé Sodium que le portail, puis ajouter `portal_shared`
dans `$config['plugins']`.

Le portail crée un jeton à usage unique d'environ 90 secondes. Le plugin le consomme,
décrypte le secret côté serveur et fournit les credentials via le hook `authenticate`.

Ne jamais allonger fortement la durée du jeton.

## 6. API OVH

Créer des credentials API dédiés et les limiter au strict nécessaire.
Le code utilise l'opération MX Plan :
`POST /email/domain/{domain}/account/{account}/changePassword`.

Tester cette opération sur un compte non critique avant la mise en production, car
les produits de messagerie OVHcloud et leurs API peuvent évoluer.

## 7. Tâche cron

Une fois par jour, nettoyer les jetons :
`DELETE FROM recovery_tokens WHERE expires_at < NOW() - INTERVAL 1 DAY;`
`DELETE FROM webmail_bridge_tokens WHERE expires_at < NOW() - INTERVAL 1 DAY;`
`DELETE FROM rate_limit_events WHERE created_at < NOW() - INTERVAL 2 DAY;`
