# Guide d'utilisation — Système de licences saadikERP

Ce guide explique comment **utiliser et exploiter** le système de licences : activer
la licence, installer des modules, comprendre l'enforcement, administrer la
plateforme, et dépanner. Il s'adresse à l'exploitant (admin général) et au technicien.

---

## 1. Vue d'ensemble

Deux composants :

| Composant | Emplacement | Rôle |
|---|---|---|
| **Hub (client)** | `C:\wamp64\www\saadikERP` | L'ERP : tableau de bord, modules, vérification de licence, installation. Tourne sous **Apache/PHP 7.4**. |
| **Plateforme (serveur éditeur)** | `C:\wamp64\www\saadik-plateforme-serveur-specs\platform` | Génère/signe les licences, active, distribue les paquets modules. CodeIgniter 4, **PHP 8.1**. |

**Principe** : le hub est l'unique autorité de licence côté client. Il vérifie une
**licence signée** (Ed25519), n'active un module que s'il est **souscrit dans la
licence + installé (fichiers + BDD)**, et émet les jetons SSO vers les modules.

---

## 2. Démarrage (à faire à chaque session de dev)

### 2.1 Extension sodium (une fois)
La crypto exige l'extension **sodium**, activée dans les `php.ini` d'Apache et du CLI.
Si vous changez de version PHP, réactivez `extension=sodium` et **redémarrez Apache**.
Vérifier : `http://localhost/saadikERP/app/licence/ioncube.php` (indique aussi ionCube).

### 2.2 Lancer le serveur de la plateforme
Apache tourne en PHP 7.4 ; la plateforme exige PHP 8.1 → on la sert à part :
```
cd C:\wamp64\www\saadik-plateforme-serveur-specs\platform
C:\wamp64\bin\php\php8.1.0\php.exe spark serve --host localhost --port 8081
```
Laisser cette fenêtre **ouverte**. Le hub l'appelle pour l'activation, le heartbeat
et le téléchargement des paquets. (Le hub fonctionne hors-ligne entre deux
heartbeats grâce à la période de grâce.)

> En production : héberger la plateforme et changer `LICENCE_SERVER_URL` /
> `DISTRIBUTION_SERVER_URL` dans `licence/config.php`. Idéalement passer WAMP en
> PHP 8.1 pour tout servir via Apache.

---

## 3. Activer la licence (admin général)

1. Ouvrir `http://localhost/saadikERP/app/licence/activation.php`.
2. Saisir l'**identifiant de licence** (`license_id`) fourni.
3. Cliquer **Activer** : le hub appelle le serveur, lie la machine (empreinte) et
   récupère la licence signée (`storage/license.key`).

Après activation, `licence_state = active`. Les modules **souscrits** dans la
licence deviennent installables/activables.

> État consultable via le tableau de bord (bandeau/logs). En cas de blocage :
> `app/licence/bloque.php` (motif : invalide / expiré / révoqué).

---

## 4. Installer un module

Sur `http://localhost/saadikERP/app/index.php`, tout module **non installé**
(souscrit mais absent du disque) affiche un bouton **« Installer »**.

Le clic ouvre l'assistant qui déroule :
1. **Téléchargement** du paquet depuis la plateforme (barre de progression, SHA-256).
2. **Placement** des fichiers à la racine Apache (selon `install_root` du `module.json`).
3. **Provision BDD** : création de la base si absente + exécution de `sql/install.sql`.
4. **Activation** : le module est autorisé par la **licence** → il passe **actif**.

Le module bascule alors dans les modules actifs (bouton « Accéder » / SSO).

---

## 5. Règles d'activation (important)

Un module est **réellement actif** uniquement si **toutes** ces conditions sont réunies
(réévaluées à chaque chargement du hub **et** au heartbeat) :

1. La **licence est activée** et valide (signature, non expirée, non révoquée).
2. Le module est **souscrit** (`enabled`) dans la licence.
3. Les **fichiers** du module sont présents sur le disque.
4. La **base de données** du module est provisionnée (si dédiée).

Conséquences :
- Mettre `est_actif = 1` **à la main en base** ne suffit pas : à la réconciliation
  suivante, le module **repasse inactif** s'il n'est pas conforme.
- Si la licence est désactivée/expirée → **tous** les modules deviennent inactifs.
- La **définition des modules** (table `modules`) est protégée par un **instantané
  signé** : toute suppression/altération directe en base est **restaurée
  automatiquement**. Les modifications via l'application (édition admin, installation)
  re-signent l'instantané et sont donc conservées.

---

## 6. Administration de la plateforme

Back-office : `http://localhost:8081/admin` (compte créé via `spark admin:create`).

Commandes CLI (dans `platform/`, avec `php8.1.0\php.exe spark …`) :

| Commande | Rôle |
|---|---|
| `licgen --client <id> --module <key:spec> …` | Générer + signer une licence. |
| `package:publish <module> <version> --src <dir>` | Publier un paquet module. |
| `keys:generate` / `keys:module <m>` | Générer la paire A / une paire B module. |
| `admin:create --username … --email … --password …` | Créer un compte back-office. |

Format `--module` : `key:per_server:perpetual` · `key:per_seat:named:15:subscription:2027-01-01` · `key:disabled`.

---

## 7. Re-seed après réinitialisation de la plateforme

⚠️ En dev, la base de la plateforme peut être **réinitialisée** (licences/paquets/tokens
remis à zéro). Symptôme : l'installation échoue (« module non souscrit / non publié »)
ou le heartbeat renvoie une erreur.

**Restauration en une commande** (depuis `saadikERP`) :
```
bash licence/reseed-platform-dev.sh
```
Ce script régénère la licence des 16 modules, republie tous les paquets, met à jour
`LICENCE_INSTALL_TOKEN` dans la config et réactive le hub. **Le serveur `spark serve`
doit tourner** (étape 2.2) pour la réactivation finale.

---

## 8. Référence de configuration (`licence/config.php`)

| Constante | Valeur (dev) | Rôle |
|---|---|---|
| `LICENCE_SERVER_URL` | `http://localhost:8081/api/v1` | Serveur d'activation/heartbeat. |
| `DISTRIBUTION_SERVER_URL` | `http://localhost:8081` | Serveur des paquets. |
| `LICENCE_MOCK_SERVER` | `false` | `true` = activation simulée hors-ligne. |
| `LICENCE_MOCK_DISTRIBUTION` | `false` | `true` = paquets mock locaux. |
| `LICENCE_ENFORCE` | `true` | Applique le gating licence. |
| `LICENCE_ENFORCE_KEY` | `false` | Clé par module (mode mock uniquement). |
| `LICENCE_INSTALL_TOKEN` | *(généré)* | Autorise le téléchargement des paquets. |
| `LICENCE_BINDING_MODE/VALUE` | `domain` / `localhost` | Liaison licence↔machine. |

**Secrets** (hors dépôt, cf. `.gitignore`) : `licence/keys/priv_B/`, `licence/keys/dev/`,
`storage/license.key`. La clé publique A (`licence/keys/pubA.php`) doit correspondre à
la clé A1 du serveur.

---

## 9. Dépannage

| Symptôme | Cause probable | Solution |
|---|---|---|
| Redirection vers `bloque.php` | Licence invalide/expirée | Réactiver ; vérifier que `pubA.php` = clé A1 du serveur. |
| « sodium indisponible » (enforcement suspendu) | Extension sodium off | Activer `extension=sodium` + redémarrer Apache. |
| Installation : « module non souscrit / non publié » | Paquet absent / plateforme réinitialisée | Lancer `reseed-platform-dev.sh`. |
| Activation : « Failed to connect … 8081 » | `spark serve` arrêté | Relancer le serveur (étape 2.2). |
| Modules tous inactifs après un test | Licence désactivée en base | Réactiver la licence (section 3). |
| Un module réactivé « tout seul » repasse inactif | Non conforme (fichiers/BDD/souscription) | Installer via l'assistant. |

---

## 10. Passage en production (résumé)

1. Héberger la plateforme (HTTPS) ; passer WAMP client en PHP 8.1 (recommandé).
2. Mettre `LICENCE_SERVER_URL` / `DISTRIBUTION_SERVER_URL` sur l'URL hébergée.
3. Remplacer `licence/keys/pubA.php` par la clé publique A du serveur de prod.
4. Publier les vrais paquets modules (code réel + `module.json` + `sql/`).
5. Encoder les fichiers sensibles avec ionCube (`licence/build-dist.ps1`).
6. Distribuer à chaque client sa licence (`licgen`) + son `install_token`.
