# TRAIL DPS 4.2 - LOT 11.11 - Correctif profond usage licence PLACE / OVH

Horodatage : 2026-05-28 12:38 UTC

## Constat repris

Les trois symptomes constates apres le LOT 11.10 etaient toujours presents :

1. `SMS 365 jours` restait affiche a 0 dans l'administration licence alors que la table `license_usage_stats` de `synolui94` contenait deja des snapshots SMS rattaches a `license_id = 1`.
2. `Courses comptabilisees (425j)`, `Evenements actifs` et `Runs actifs` ne remontaient pas apres l'ouverture de PLACE.
3. Les checks licence mettaient bien a jour `licenses.last_check_at` et ajoutaient des lignes `license_audit_log` de type `check`, mais aucune ligne `PLACE_LICENSE_CHECK` n'etait creee dans `license_usage_stats`.

## Analyse reelle effectuee

### 1. Les donnees SMS etaient presentes mais illisibles par l'admin

Le dump `license_usage_stats` fourni contient bien les lignes suivantes :

- id 1 : `sms_sent_count = 1`, source `OVH_SMS_RUNNER` ;
- id 2 : `sms_sent_count = 2`, source `OVH_SMS_RUNNER` ;
- id 3 : `sms_sent_count = 3`, source `OVH_SMS_RUNNER`.

La page `public/admin/license.php` appelait deja conditionnellement :

- `getCommercialUsageSummary()` ;
- `getLatestUsageStats()` ;
- `countBillableSmsRolling365()`.

Mais le fichier `SRC/LicenseRepository.php` present dans le code OVH actuel ne contenait toujours pas ces methodes. Le test `method_exists()` renvoyait donc `false`, puis l'interface utilisait les valeurs de repli : `0` et `-`.

### 2. Le check licence OVH ignorait encore `local_usage`

Le fichier `SRC/LicenseService.php` actuel executait uniquement :

- verification cle / empreinte ;
- `updateCheck()` ;
- ajout audit `check` ;
- retour de la licence signee.

Il ne lisait pas `local_usage` et n'inserait rien dans `license_usage_stats`. C'est pour cela que `last_check_at` etait coherent alors que la table d'usage ne recevait aucune ligne `PLACE_LICENSE_CHECK`.

### 3. Risque de non-application des correctifs OVH a cause de la casse `SRC` / `src`

Le depot OVH fourni utilise le dossier `ovh/SRC`. Plusieurs endpoints tracking utilisent deja explicitement `../../../SRC/...`.

En revanche, `config/bootstrap.php` chargeait encore les classes licence via `../src/...` en minuscules. Sur un hebergement Linux, `SRC` et `src` sont deux dossiers differents. Un correctif depose dans `ovh/SRC` peut donc ne pas etre execute par les APIs licence/admin si le bootstrap pointe vers un ancien dossier `src`.

Correction appliquee : `config/bootstrap.php` privilegie maintenant `../SRC`, avec fallback vers `../src` si `SRC` est absent.

### 4. Calcul PLACE renforce

Le code PLACE calculait deja un snapshot local, mais l'erreur eventuelle etait silencieuse cote client. Le calcul local a ete durci pour :

- detecter dynamiquement les colonnes SQLite disponibles ;
- eviter les erreurs de schema sur anciennes bases ;
- transmettre un diagnostic `local_usage_error` au serveur si le calcul echoue ;
- conserver le compteur SMS local a 0 afin que seuls les snapshots OVH fassent foi pour les SMS facturables.

Sur la base SQLite fournie, le calcul local donne :

- `rolling_365_course_count = 20` ;
- `active_events_count = 2` ;
- `active_runs_count = 2` ;
- `sms_sent_count = 0` cote PLACE, volontairement preserve par OVH avec le compteur serveur.

## Corrections realisees

### OVH - `config/bootstrap.php`

- Ajout d'une resolution robuste du dossier source.
- Priorite a `../SRC` pour correspondre aux ZIP incrementiels livres et aux endpoints tracking.
- Fallback vers `../src` pour compatibilite avec un ancien deploiement.

### OVH - `SRC/LicenseRepository.php`

Ajout des methodes effectives :

- `getLatestUsageStats()` ;
- `getLatestPlaceUsageStats()` ;
- `getLatestSmsUsageStats()` ;
- `countBillableSmsRolling365()` ;
- `getCommercialUsageSummary()` ;
- `recordUsageStats()` ;
- `recordUsageSnapshotFromClient()` ;
- `recordPlaceLicenseCheckUsage()` ;
- `tableExists()`.

La synthese admin combine desormais :

- le dernier snapshot PLACE pour les courses/evenements/runs ;
- le dernier snapshot SMS OVH positif sur 365 jours ;
- une protection contre l'ecrasement des SMS par un check PLACE a `sms_sent_count = 0`.

### OVH - `SRC/LicenseService.php`

Dans `check()` :

- lecture de `local_usage` ;
- insertion non bloquante d'une ligne `PLACE_LICENSE_CHECK` dans `license_usage_stats` ;
- audit enrichi avec :
  - `client_version` ;
  - `local_usage_received` ;
  - `local_usage_persisted` ;
  - `local_usage_error` ;
  - `local_usage_client_error` ;
  - liste des cles recues.

Dans la licence signee :

- ajout de `usage_window_days = 425` ;
- ajout de `commercial_usage` et `license_usage` ;
- ajout des champs commerciaux si presents dans `licenses`.

### PLACE - `SRC/Services/license_usage_service.py`

- Calcul schema-safe des courses/evenements/runs.
- Fermeture explicite des connexions SQLite.
- Fenetre commerciale conservee a 425 jours.
- Le calcul a ete valide sur la base SQLite fournie : 20 courses, 2 evenements actifs, 2 runs actifs.

### PLACE - `SRC/Services/license_api_client.py`

- Version client passee a `lot-11.11-place-usage-debug`.
- Ajout de `local_usage_error` dans le payload si le calcul local echoue.
- Conservation du payload `local_usage` lorsque le calcul reussit.

## Fichiers modifies dans ce ZIP incrementiel

- `ovh/config/bootstrap.php`
- `ovh/SRC/LicenseRepository.php`
- `ovh/SRC/LicenseService.php`
- `SRC/Services/license_usage_service.py`
- `SRC/Services/license_api_client.py`
- `ovh/docs/LOT_11_11_CORRECTIF_PROFOND_USAGE_LICENCE.md`

## Procedure de deploiement

1. Deployer le contenu du ZIP en respectant strictement l'arborescence.
2. Verifier que `ovh/config/bootstrap.php` est bien remplace : c'est indispensable si l'hebergement executait encore un ancien dossier `src`.
3. Remplacer les deux fichiers PHP licence dans `ovh/SRC`.
4. Remplacer les deux fichiers Python dans `SRC/Services` cote PLACE.
5. Relancer PLACE pour provoquer un check licence online.
6. Recharger la fiche administration licence.

## Validation attendue apres redeploiement

Dans `synolui94.license_usage_stats`, une nouvelle ligne doit apparaitre :

- `source = 'PLACE_LICENSE_CHECK'` ;
- `rolling_365_course_count = 20` avec la base fournie ;
- `active_events_count = 2` ;
- `active_runs_count = 2` ;
- `sms_sent_count = 3` si les trois SMS OVH deja presents restent les derniers snapshots facturables.

Dans `license_audit_log`, le prochain evenement `check` doit contenir :

- `client_version = lot-11.11-place-usage-debug` ;
- `local_usage_received = true` ;
- `local_usage_persisted = true`.

Dans l'administration licence :

- `SMS 365 jours` doit afficher le compteur consolide deja present en base ;
- `Courses comptabilisees (425j)` doit afficher la remontee PLACE ;
- `Evenements actifs` et `Runs actifs` doivent etre alimentes ;
- la source doit indiquer une origine `PLACE_LICENSE_CHECK` combinee avec le snapshot SMS OVH si les deux existent.

## Tests techniques effectues

- `php -l ovh/config/bootstrap.php` : OK.
- `php -l ovh/SRC/LicenseRepository.php` : OK.
- `php -l ovh/SRC/LicenseService.php` : OK.
- `python -m compileall -q SRC` : OK.
- Calcul local usage sur la base SQLite fournie : 20 / 2 / 2.

## Point de vigilance

Si apres deploiement le prochain audit `check` n'affiche pas `client_version = lot-11.11-place-usage-debug`, cela signifie que le poste PLACE n'execute pas les deux fichiers Python livres dans ce ZIP ou qu'un ancien build de l'application est encore lance.

Si `client_version` est correct mais `local_usage_persisted = false`, lire l'evenement `usage_persist_error` dans `license_audit_log` pour connaitre l'erreur SQL exacte.
