Documentation J+SERVICES Guides Référence API

Contrat API — Bascule d’un client vers J+RADIUS

Le bouton « migrer ce client en mode RADIUS », et ce que le gérant voit pendant que ça se passe.

📱 Dev de l’application : le briefing d’intégration pas à pas — écrans, pièges, protocole de test des 7 routes — est sur /docs/CONTRAT-API-MIGRATION-RADIUS-APP. Ce document-ci reste la référence des champs.

Base : https://live.jmoai.net/api/v1/radius


1. Le fait qui rend cette bascule nécessaire

[!WARNING] Sur RouterOS, le hotspot consulte d’abord sa base locale et n’interroge RADIUS que si l’usager n’y figure pas.

Poser use-radius=yes en laissant les comptes locaux ne bascule donc rien : les clients continuent de s’authentifier en local, RADIUS n’est jamais appelé, et aucune erreur n’est levée.

Mesuré le 2026-08-29 : 8 707 comptes locaux sur le routeur de référence, et radacct à 874 lignes pour tout le parc, dont zéro authentification hotspot. Des déploiements avaient pourtant réussi. La bascule était inerte.

Le retrait des comptes locaux n’est donc pas un nettoyage de confort : c’est l’étape qui fait la bascule.


2. Les six étapes, dont une seule est irréversible

1. inventaire         on regarde avant de promettre
2. sauvegarde         rapatriée ET vérifiée, sinon on s'arrête
3. import vers RADIUS  et on COMPTE ce qui est arrivé
4. configuration      le routeur parle au serveur, la confirmation est armée
5. retrait du local   ← IRRÉVERSIBLE, exige trois preuves
6. première connexion  une vraie authentification, avec le nom de l'usager

Les étapes 1 à 4 se rejouent sans dommage. La 5 exige trois preuves :

Preuve Comment elle est obtenue
SAUVEGARDE_CONFIRMEE des octets rapatriés, pas un simple retour sans exception
IMPORT_RADIUS_CONFIRME inventaire paginé du serveur RADIUS, complete: true
ROUTEUR_JOIGNABLE l’inventaire a répondu

Et un import incomplet bloque le retrait : des comptes non importés puis retirés, ce sont des tickets vendus qui disparaissent.

Si le retrait est refusé, la bascule s’arrête proprement : le routeur reste en double (local + RADIUS), le gérant continue de vendre, personne ne perd rien.


3. GET /admin/migration/{allocationId}/inventaire

Lecture seule. Aucune écriture, aucun engagement.

{
  "allocation_id": "uuid",
  "nas_id": "uuid",
  "routeur": "HH40AF7YVNP",
  "licence_active": true,
  "tunnel_joignable": true,
  "comptes_locaux": 8707,
  "espace_flash_mo": 36,
  "autorise": true,
  "motif": null,
  "motif_texte": null,
  "avertissements": []
}
motif Sens
LICENCE_RADIUS_INACTIVE pas de licence J+RADIUS active
ROUTEUR_INJOIGNABLE le routeur ne répond pas
INVENTAIRE_ILLISIBLE comptes non lisibles — ce n’est pas zéro compte
TROP_DE_COMPTES_POUR_UNE_BASCULE_AUTOMATIQUE plus de 15 000 : lot par lot, pas en un clic
ESPACE_FLASH_INSUFFISANT moins de 25 Mo : la sauvegarde échouerait

comptes_locaux: null n’est pas 0. Le serveur refuse dans ce cas. Une application qui afficherait « rien à migrer » sur un inventaire illisible enverrait un administrateur basculer à l’aveugle un routeur qui porte huit mille comptes.


4. POST /admin/migration/{allocationId}

{ "retirer_local": true }

retirer_local: false fait tout sauf le retrait : utile pour préparer une migration, ou laisser un routeur en double le temps d’observer.

{
  "success": true,
  "allocation_id": "uuid",
  "nas_id": "uuid",
  "statut": "ARMEMENT",
  "etapes": [
    { "etape": "SAUVEGARDE", "etat": "OK", "comptes": 8707 },
    { "etape": "CONFIG", "etat": "OK" },
    { "etape": "IMPORT", "etat": "OK", "importes": 8707 },
    { "etape": "RETRAIT_LOCAL", "etat": "OK", "retires": 8706 },
    { "etape": "ARMEMENT", "etat": "OK" }
  ],
  "retires": 8706,
  "importes": 8707
}

RETRAIT_LOCAL peut valoir REFUSE avec un motif — la bascule s’est arrêtée là, et c’est un succès partiel, pas un échec : rien n’a été détruit.

Le compte default-trial est toujours épargné : il est créé par RouterOS et son retrait casse l’essai gratuit du hotspot.

Code d’erreur Sens
MIGRATION_BACKUP_FAILED / MIGRATION_BACKUP_EMPTY sauvegarde impossible ou vide — rien n’a été touché
MIGRATION_DEPLOY_FAILED configuration RADIUS refusée — rien n’a été supprimé
MIGRATION_COUNT_FAILED comptage impossible — retrait annulé
MIGRATION_REMOVE_STALLED le routeur ne retire plus rien — des comptes subsistent
MIGRATION_REMOVE_UNVERIFIED retrait effectué mais non vérifiable

Le retrait est vérifié par comptage avant/après, pas par le retour de la commande : un retrait partiel qui passerait pour complet laisserait des comptes locaux, et ce sont eux qui masquent RADIUS.


4 bis. POST /admin/migration/{allocationId}/retour — revenir en local

Le bouton inverse. Remet les comptes hotspot sur le routeur, puis coupe RADIUS.

{ "couper_radius": true }

couper_radius: false remet les comptes sans couper RADIUS : le routeur reste en double le temps de vérifier que tout répond avant de trancher.

{
  "success": true,
  "statut": "REVENU_EN_LOCAL",
  "comptes_restaures": 8706,
  "sauvegarde_datee_du": "2026-08-29T20:00:00Z",
  "ecart_avec_radius": {
    "connu": true,
    "ecart": 53,
    "avertissement": "Le serveur cloud porte 53 compte(s) de plus que la sauvegarde : ce sont des tickets vendus depuis la bascule. Ils ne seront PAS restaurés sur le routeur."
  },
  "etapes": [
    { "etape": "LECTURE_SAUVEGARDE", "etat": "OK", "comptes": 8707, "a_restaurer": 8706 },
    { "etape": "PROFILS", "etat": "OK", "profils": 18 },
    { "etape": "COMPTES", "etat": "OK", "poses": 8706 },
    { "etape": "VERIFICATION", "etat": "OK", "comptes": 8706 },
    { "etape": "RADIUS_COUPE", "etat": "OK" }
  ]
}

Ce qui n’est JAMAIS rejoué

[!WARNING] Le fichier .backup binaire n’est jamais restauré. Il porte toute la configuration — pare-feu, adresses, routes, peers WireGuard, tunnel de gestion. Le rejouer à distance rendrait le routeur muet une fois sur deux, et on perdrait le chemin d’accès en même temps que la possibilité de réparer.

Seuls les profils et les comptes hotspot sont remis. Rien d’autre n’est touché.

L’ordre, et pourquoi il ne s’inverse pas

  1. Profils d’abord — un compte dont le profil manque échoue, et fait tomber son lot entier.
  2. Comptes par lots de 40, commandes idempotentes : rejouer après un échec partiel ne lève pas « already have such name ».
  3. Vérification par comptage.
  4. use-radius=no en dernier. Couper RADIUS avant d’avoir remis les comptes laisserait le hotspot sans aucune base d’authentification — tous les clients dehors pendant la restauration. Si la restauration échoue ou reste incomplète, RADIUS n’est pas coupé : le hotspot garde une base qui répond.

L’entrée /radius n’est pas retirée : la laisser ne coûte rien et permet de rebasculer sans tout reconfigurer.

Ce que le retour ne peut pas rattraper — à afficher

La sauvegarde date d’avant la bascule. Les tickets vendus depuis vivent dans RADIUS et ne sont pas dans ce fichier : ecart_avec_radius.avertissement les compte. Inversement, les tickets déjà consommés depuis y figurent encore et redeviendront utilisables.

On ne corrige pas ça automatiquement — toute tentative ferait pire. On le dit, chiffre à l’appui, et l’administrateur tranche.

Code d’erreur Sens
RESTORE_NO_BACKUP aucune sauvegarde des comptes pour ce routeur
RESTORE_BACKUP_UNREADABLE sauvegarde illisible — refus, plutôt que restaurer zéro compte
RESTORE_BACKUP_EMPTY la sauvegarde ne contient aucun compte restaurable
RESTORE_USERS_FAILED restauration interrompue — RADIUS n’a pas été coupé
RESTORE_INCOMPLETE moins de comptes que prévu — RADIUS reste actif

5. Ce que le gérant reçoit, étape par étape

Notifications de type RADIUS_MIGRATION, une par étape :

Étape Message
SAUVEGARDE « Sauvegarde de votre configuration (8 707 comptes) — faite. »
IMPORT « Vos 8 707 comptes ont été copiés dans le serveur cloud. »
RETRAIT_LOCAL « 8 706 comptes locaux retirés — ils vivent maintenant dans le cloud. »
ARMEMENT « En attente de la première connexion d’un de vos clients. »
ECHEC « La bascule s’est arrêtée : … Rien n’a été supprimé sur votre routeur. »

Puis, type RADIUS_PREMIERE_AUTH, les cinq premières connexions réelles :

« Connexion 1/5 validée ✅ — TM-C4D835 vient de se connecter via le serveur cloud sur J+Pro Ax3. La bascule fonctionne. »

C’est la preuve que le gérant attend. Un « service opérationnel » sans nom d’usager ne prouve rien — c’est exactement ce qu’affichait l’ancien flux pendant que le hotspot continuait de répondre en local. Au-delà de cinq, le système se tait : il a compris qu’il a compris.

La confirmation est automatique depuis le 2026-08-29 (cron RADIUS_MIGRATION_WATCH, toutes les 3 min). Auparavant elle exigeait un clic d’administrateur, et personne ne le faisait.


6. GET /affluence — ce que le gérant lit sur son réseau

Lecture ouverte au client : c’est son réseau.

{
  "disponible": true,
  "connexions": 128,
  "clients": 34,
  "refus": 3,
  "pic": { "heure": 19, "connexions": 41 },
  "connexions_par_client": 3.8,
  "par_heure": [0, 0, "…"],
  "boucles": []
}

Le relevé de fin de journée

Chaque soir à 20 h UTC (21 h au Bénin), type RADIUS_AFFLUENCE :

« 128 connexion(s) réussie(s) aujourd’hui sur J+Pro Ax3, pour 34 client(s). Pic de fréquentation vers 19 h. 3 connexion(s) refusée(s). »

Seuls les clients qui ont eu de l’activité sont notifiés. Envoyer « 0 connexion » chaque soir à un gérant dont le routeur dort est le meilleur moyen de lui faire couper les notifications — et il ne verrait plus les vraies.


7. Réglages

Variable Défaut Effet
RADIUS_MIGRATION_WATCH_ENABLED true confirmation auto + premières connexions, toutes les 3 min
RADIUS_READY_AUTO_CONFIRM_ENABLED true (était false, et aucune cron ne l’appelait)
RADIUS_AFFLUENCE_REPORT_ENABLED true relevé de fin de journée à 20 h UTC