Briefing d’intégration — Bascule RADIUS, côté application
Note pratique pour le développeur. Le détail des champs est dans
CONTRAT-API-MIGRATION-RADIUS ; ici, seulement quoi
afficher, dans quel ordre, et ce qu’il ne faut pas faire.
Base : https://live.jmoai.net/api/v1/radius
1. Deux écrans, deux publics
| Écran | Public | Routes |
|---|---|---|
| Migration | administrateur J+SERVICES | /admin/migration/* (rôle admin exigé) |
| Mon réseau | le gérant | /affluence (son propre client) |
Le gérant ne déclenche jamais la bascule lui-même. Il la subit et la constate — d’où les notifications. C’est un choix : le retrait des comptes locaux est irréversible, il ne doit pas tenir à un clic dans une poche.
2. Le parcours administrateur, écran par écran
1. GET /admin/migration/{allocationId}/inventaire ← AVANT de montrer le bouton
2. POST /admin/migration/{allocationId} ← le bouton
3. GET /admin/migration/{allocationId} ← suivi (toutes les 5 s)
4. POST /admin/migration/{allocationId}/retour ← le bouton inverse
Étape 1 — l’inventaire décide si le bouton est cliquable
N’affichez jamais le bouton avant d’avoir appelé l’inventaire. Il rend autorise et un
motif_texte déjà rédigé en français : affichez-le tel quel quand autorise vaut false.
{ "comptes_locaux": 8707, "espace_flash_mo": 36, "autorise": true, "motif_texte": null }
[!WARNING]
comptes_locaux: nulln’est pas0. C’est un inventaire illisible. Le serveur refuse déjà (INVENTAIRE_ILLISIBLE), mais si votre écran affiche « 0 compte à migrer » sur ce cas, l’administrateur croira le routeur vide alors qu’il porte peut-être huit mille comptes.
Affichez toujours comptes_locaux en gros à côté du bouton. C’est le nombre de comptes qui
vont être supprimés du routeur ; personne ne doit cliquer sans l’avoir vu.
Étape 2 — le bouton, et la case qui doit exister
{ "retirer_local": true }
Prévoyez une case « préparer sans supprimer » (retirer_local: false) : elle fait tout sauf
le retrait, et laisse le routeur en double. C’est le mode qu’un administrateur prudent utilisera
la première fois, et il doit pouvoir le choisir sans éditer une requête à la main.
Étape 3 — le suivi
La réponse porte déjà etapes[]. Affichez-les dans l’ordre, avec leur etat :
etat |
Affichage |
|---|---|
OK |
✅ |
IGNORE |
⏭️ avec le motif — ce n’est pas un échec |
REFUSE |
⚠️ la bascule s’est arrêtée proprement, rien n’a été détruit |
ECHEC |
❌ avec l’erreur |
RETRAIT_LOCAL: REFUSE est un succès partiel, pas un échec : le routeur est resté en
double, le gérant continue de vendre. Ne l’affichez pas en rouge alarmant.
Étape 4 — le retour
{ "couper_radius": true }
Même logique : prévoyez « remettre les comptes sans couper RADIUS » (false), pour vérifier
avant de trancher.
Affichez ecart_avec_radius.avertissement quand il n’est pas null. C’est le nombre de
tickets vendus depuis la bascule qui ne reviendront pas en local. L’administrateur doit le lire
avant de confirmer, pas le découvrir après.
3. Les cinq pièges à ne pas reproduire
1. Ne recalculez rien. autorise, motif_texte, les phrases d’étapes, l’avertissement
d’écart : tout vient du serveur. Deux versions de l’application les calculeraient différemment,
et l’une des deux mentirait.
2. IGNORE ≠ ECHEC. Un retrait ignoré parce qu’il n’y avait aucun compte local est un
déroulement normal.
3. N’offrez pas le retour si aucune bascule n’a eu lieu. Le serveur refuse
(RESTORE_NO_BACKUP), mais un bouton qui ne marche jamais use la confiance.
4. Le suivi n’est pas instantané. La sauvegarde d’un routeur à 8 700 comptes prend des dizaines de secondes. Prévoyez un état d’attente qui tient une minute sans donner l’impression d’un blocage.
5. Ne montrez pas la commande RouterOS. Contrairement à l’Anti-Restriction, ici c’est le backend qui écrit sur le routeur. L’application n’exécute rien.
4. Ce que le gérant reçoit — et ce que l’app en fait
| Type | Quand | Où l’appui doit mener |
|---|---|---|
RADIUS_MIGRATION |
à chaque étape | écran « Mon réseau » |
RADIUS_PREMIERE_AUTH |
les 5 premières connexions réelles, avec le nom de l’usager | écran « Mon réseau » |
RADIUS_AFFLUENCE |
chaque soir à 20 h UTC | écran « Mon réseau » |
RADIUS_READY |
service confirmé opérationnel | écran « Mon réseau » |
Les notifications RADIUS_PREMIERE_AUTH sont le moment qui compte. « TM-C4D835 vient de se
connecter via le serveur cloud » est la preuve que le gérant attend — un « service
opérationnel » sans nom d’usager ne prouve rien, et c’est exactement ce que l’ancien flux
affichait pendant que le hotspot continuait de répondre en local.
Montrez-les en évidence, avec le nom, pas comme une ligne de journal parmi d’autres.
5. L’écran « Mon réseau » du gérant — GET /affluence
{
"disponible": true,
"connexions": 128,
"clients": 34,
"refus": 3,
"pic": { "heure": 19, "connexions": 41 },
"connexions_par_client": 3.8,
"par_heure": [0, 0, "…"],
"boucles": []
}
Affichez connexions ET clients, jamais l’un pour l’autre. Un même usager se
réauthentifie plusieurs fois par session : les confondre gonfle le chiffre d’un facteur 3 à 10,
et le gérant croira à une affluence qu’il n’a pas.
par_heureest un tableau de 24 entiers — de quoi tracer l’histogramme de la journée.pic.heureest dans le fuseau du routeur. 23 h UTC, c’est minuit à Porto-Novo : un pic annoncé à la mauvaise heure ne sert à rien pour décider des horaires d’ouverture.bouclesliste les comptes qui se reconnectent plus de 200 fois par jour. Ce n’est pas de l’affluence, c’est une panne. Affichez-le comme une alerte, jamais dans le total mis en avant.disponible: false→ n’affichez pas un relevé à zéro. « 0 connexion » et « je ne sais pas » ne veulent pas dire la même chose.
6. Protocole de test — les 7 routes
Prérequis : un compte admin et une allocationId sur un routeur d’essai joignable.
API=https://live.jmoai.net/api/v1/radius
T="Bearer <jeton admin>"
A=<allocationId>
Phase 0 — les gardes
| # | Appel | Attendu |
|---|---|---|
| 0.1 | n’importe quelle route /admin/migration/* sans jeton |
401 |
| 0.2 | avec un jeton client (non admin) | 403 |
| 0.3 | POST /admin/migration/{A} 6 fois en une minute |
la 6ᵉ en 429 |
Phase 1 — l’inventaire, sans rien changer
| # | Vérifier |
|---|---|
| 1.1 | GET /admin/migration/{A}/inventaire rend comptes_locaux et espace_flash_mo |
| 1.2 | sur une allocation inconnue → 404 ALLOCATION_NOT_FOUND |
| 1.3 | sur un routeur éteint → autorise: false, motif: ROUTEUR_INJOIGNABLE |
| 1.4 | l’appel est rejouable : deux appels ne changent rien sur le routeur |
Phase 2 — la bascule en mode « préparer sans supprimer »
POST /admin/migration/{A} avec {"retirer_local": false}
| # | Vérifier |
|---|---|
| 2.1 | etapes contient SAUVEGARDE: OK avec un nombre de comptes |
| 2.2 | CONFIG: OK |
| 2.3 | RETRAIT_LOCAL: IGNORE, motif « demandé sans retrait » |
| 2.4 | sur le routeur : les comptes locaux sont toujours là |
| 2.5 | sur le routeur : /ip hotspot profile print → use-radius=yes |
| 2.6 | le gérant a reçu les notifications SAUVEGARDE et IMPORT |
Phase 3 — la bascule réelle
POST /admin/migration/{A} avec {"retirer_local": true}
| # | Vérifier |
|---|---|
| 3.1 | RETRAIT_LOCAL: OK avec retires proche de comptes_locaux |
| 3.2 | sur le routeur : /ip hotspot user print count-only → 1 (default-trial) |
| 3.3 | default-trial existe toujours |
| 3.4 | connectez un vrai client : il obtient son accès via RADIUS |
| 3.5 | dans les 3 min, notification RADIUS_PREMIERE_AUTH avec son nom |
| 3.6 | GET /affluence montre connexions ≥ 1 |
3.4 est le test qui compte. C’est lui qui prouve que la bascule n’est pas inerte — le défaut que tout ce chantier corrige.
Phase 4 — le retour
POST /admin/migration/{A}/retour avec {"couper_radius": true}
| # | Vérifier |
|---|---|
| 4.1 | LECTURE_SAUVEGARDE: OK avec datee_du |
| 4.2 | PROFILS: OK avant COMPTES: OK |
| 4.3 | VERIFICATION: OK avec un compte ≥ a_restaurer |
| 4.4 | RADIUS_COUPE: OK, et sur le routeur use-radius=no |
| 4.5 | les comptes locaux sont de retour |
| 4.6 | ecart_avec_radius.avertissement est affiché s’il n’est pas null |
| 4.7 | un client se connecte de nouveau en local |
Phase 5 — les refus
| # | Cas | Attendu |
|---|---|---|
| 5.1 | retour sur un routeur jamais basculé | 409 RESTORE_NO_BACKUP |
| 5.2 | bascule sur un client sans licence RADIUS | 409 LICENCE_RADIUS_INACTIVE |
| 5.3 | bascule sur un routeur avec < 25 Mo de flash | 409 ESPACE_FLASH_INSUFFISANT |
| 5.4 | bascule pendant que le routeur est éteint | 409 ROUTEUR_INJOIGNABLE, rien n’a été touché |
Ce qui doit rester vrai après toute la recette
- Aucune configuration hors hotspot n’a bougé : pare-feu, adresses, routes et peers WireGuard
sont identiques avant et après (
/exportcomparé). - Le tunnel de gestion répond toujours.
- Aucun
.backupbinaire n’a été rejoué.
7. À cocher avant publication
- [ ] Le bouton n’apparaît qu’après un inventaire
autorise: true. - [ ]
comptes_locauxest affiché en évidence avant le clic. - [ ]
comptes_locaux: nulln’affiche jamais « 0 compte ». - [ ] La case « préparer sans supprimer » existe.
- [ ]
RETRAIT_LOCAL: REFUSEn’est pas présenté comme un échec. - [ ] Le bouton retour existe et affiche
ecart_avec_radius.avertissement. - [ ] Les notifications
RADIUS_PREMIERE_AUTHsont mises en avant, avec le nom de l’usager. - [ ]
connexionsetclientssont affichés séparément. - [ ]
bouclesest présenté comme une alerte, pas comme de la fréquentation. - [ ]
disponible: falsen’affiche pas un relevé à zéro.