secubox-openwrt/docs-fr/luci-development-reference.md
CyberMind-FR ccfb58124c docs: Add trilingual documentation (French and Chinese translations)
Add complete French (fr) and Chinese (zh) translations for all documentation:

- Root files: README, CHANGELOG, SECURITY, BETA-RELEASE
- docs/: All 16 core documentation files
- DOCS/: All 19 deep-dive documents including embedded/ and archive/
- package/secubox/: All 123+ package READMEs
- Misc: secubox-tools/, scripts/, EXAMPLES/, config-backups/, streamlit-apps/

Total: 346 translation files created

Each file includes language switcher links for easy navigation between
English, French, and Chinese versions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-20 10:00:18 +01:00

1194 lines
32 KiB
Markdown

# Guide de Reference pour le Developpement LuCI
> **Langues:** [English](../docs/luci-development-reference.md) | Francais | [中文](../docs-zh/luci-development-reference.md)
**Version:** 1.0.0
**Derniere mise a jour:** 2025-12-28
**Statut:** Actif
**Base sur:** implementations luci-app-secubox et luci-app-system-hub
**Public cible:** Claude.ai et developpeurs travaillant sur des applications LuCI OpenWrt
---
## Voir aussi
- **Design et Standards:** [DEVELOPMENT-GUIDELINES.md](development-guidelines.md)
- **Commandes Rapides:** [QUICK-START.md](quick-start.md)
- **Briefing Automatisation:** [CODEX.md](codex.md)
- **Modeles de Code:** [CODE-TEMPLATES.md](code-templates.md)
Ce document capture les patterns critiques, bonnes pratiques et pieges courants decouverts lors du developpement des applications LuCI SecuBox. Utilisez-le comme reference de validation pour tout developpement futur d'applications LuCI.
---
## Table des matieres
1. [Fondamentaux ubus et RPC](#fondamentaux-ubus-et-rpc)
2. [Patterns Backend RPCD](#patterns-backend-rpcd)
3. [Patterns Module API LuCI](#patterns-module-api-luci)
4. [Patterns d'Import de Vues LuCI](#patterns-dimport-de-vues-luci)
5. [Structure des Permissions ACL](#structure-des-permissions-acl)
6. [Conventions de Structure de Donnees](#conventions-de-structure-de-donnees)
7. [Erreurs Courantes et Solutions](#erreurs-courantes-et-solutions)
8. [Checklist de Validation](#checklist-de-validation)
9. [Tests et Deploiement](#tests-et-deploiement)
---
## Fondamentaux ubus et RPC
### Qu'est-ce que ubus ?
**ubus** (architecture micro bus OpenWrt) est le systeme de communication inter-processus (IPC) d'OpenWrt. Il permet :
- RPC (Remote Procedure Call) entre processus
- Communication entre l'interface web (LuCI) et les services backend
- Interaction en ligne de commande via `ubus call`
### Convention de Nommage des Objets ubus
**REGLE CRITIQUE** : Tous les objets ubus des applications LuCI DOIVENT utiliser le prefixe `luci.`.
```javascript
// ✅ CORRECT
object: 'luci.system-hub'
object: 'luci.cdn-cache'
object: 'luci.wireguard-dashboard'
// ❌ INCORRECT
object: 'system-hub'
object: 'systemhub'
object: 'cdn-cache'
```
**Pourquoi ?** LuCI attend les objets sous l'espace de noms `luci.*` pour les applications web. Sans ce prefixe :
- Les permissions ACL ne correspondent pas
- RPCD ne route pas correctement les appels
- La console du navigateur affiche : `RPC call to system-hub/status failed with error -32000: Object not found`
### Le Nom du Script RPCD DOIT Correspondre a l'Objet ubus
Le nom du fichier script RPCD DOIT correspondre exactement au nom de l'objet ubus :
```bash
# Si JavaScript declare :
# object: 'luci.system-hub'
# Alors le script RPCD DOIT etre nomme :
/usr/libexec/rpcd/luci.system-hub
# PAS :
/usr/libexec/rpcd/system-hub
/usr/libexec/rpcd/luci-system-hub
```
**Commande de Validation** :
```bash
# Verifier les fichiers JavaScript pour les noms d'objets ubus
grep -r "object:" luci-app-*/htdocs --include="*.js"
# Verifier que le script RPCD existe avec le nom correspondant
ls luci-app-*/root/usr/libexec/rpcd/
```
### Types d'Appels ubus
**Operations de Lecture** (type GET) :
- `status` - Obtenir l'etat actuel
- `get_*` - Recuperer des donnees (ex: `get_health`, `get_settings`)
- `list_*` - Enumerer des elements (ex: `list_services`)
**Operations d'Ecriture** (type POST) :
- `save_*` - Persister la configuration (ex: `save_settings`)
- `*_action` - Effectuer des actions (ex: `service_action`)
- `backup`, `restore`, `reboot` - Modifications systeme
**Mapping ACL** :
- Operations de lecture → section `"read"` dans ACL
- Operations d'ecriture → section `"write"` dans ACL
---
## Patterns Backend RPCD
### Structure des Scripts Shell
Les backends RPCD sont des scripts shell executables qui :
1. Analysent `$1` pour l'action (`list` ou `call`)
2. Analysent `$2` pour le nom de la methode (si `call`)
3. Lisent l'entree JSON depuis stdin (pour les methodes avec parametres)
4. Produisent du JSON sur stdout
5. Se terminent avec le statut 0 en cas de succes, non-zero en cas d'erreur
### Modele Standard
```bash
#!/bin/sh
# Backend RPCD : luci.system-hub
# Version : 0.1.0
# Charger l'assistant JSON shell
. /usr/share/libubox/jshn.sh
case "$1" in
list)
# Lister toutes les methodes disponibles et leurs parametres
echo '{
"status": {},
"get_health": {},
"service_action": { "service": "string", "action": "string" },
"save_settings": {
"auto_refresh": 0,
"health_check": 0,
"refresh_interval": 0
}
}'
;;
call)
case "$2" in
status)
status
;;
get_health)
get_health
;;
service_action)
# Lire l'entree JSON depuis stdin
read -r input
json_load "$input"
json_get_var service service
json_get_var action action
service_action "$service" "$action"
;;
save_settings)
read -r input
json_load "$input"
json_get_var auto_refresh auto_refresh
json_get_var health_check health_check
json_get_var refresh_interval refresh_interval
save_settings "$auto_refresh" "$health_check" "$refresh_interval"
;;
*)
echo '{"error": "Method not found"}'
exit 1
;;
esac
;;
esac
```
### Sortie JSON avec jshn.sh
**jshn.sh** fournit des fonctions shell pour la manipulation JSON :
```bash
# Initialiser l'objet JSON
json_init
# Ajouter des valeurs simples
json_add_string "hostname" "openwrt"
json_add_int "uptime" 86400
json_add_boolean "running" 1
# Ajouter un objet imbrique
json_add_object "cpu"
json_add_int "usage" 25
json_add_string "status" "ok"
json_close_object
# Ajouter un tableau
json_add_array "services"
json_add_string "" "network"
json_add_string "" "firewall"
json_close_array
# Produire le JSON sur stdout
json_dump
```
**Fonctions Courantes** :
- `json_init` - Demarrer un nouvel objet JSON
- `json_add_string "key" "value"` - Ajouter une chaine
- `json_add_int "key" 123` - Ajouter un entier
- `json_add_boolean "key" 1` - Ajouter un booleen (0 ou 1)
- `json_add_object "key"` - Demarrer un objet imbrique
- `json_close_object` - Terminer l'objet imbrique
- `json_add_array "key"` - Demarrer un tableau
- `json_close_array` - Terminer le tableau
- `json_dump` - Produire le JSON sur stdout
### Gestion des Erreurs
Toujours valider les entrees et retourner des erreurs significatives :
```bash
service_action() {
local service="$1"
local action="$2"
# Valider le nom du service
if [ -z "$service" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Service name is required"
json_dump
return 1
fi
# Valider l'action
case "$action" in
start|stop|restart|enable|disable)
;;
*)
json_init
json_add_boolean "success" 0
json_add_string "error" "Invalid action: $action"
json_dump
return 1
;;
esac
# Executer l'action
/etc/init.d/"$service" "$action" >/dev/null 2>&1
if [ $? -eq 0 ]; then
json_init
json_add_boolean "success" 1
json_add_string "message" "Service $service $action successful"
json_dump
else
json_init
json_add_boolean "success" 0
json_add_string "error" "Service $service $action failed"
json_dump
return 1
fi
}
```
### Integration UCI
Pour la configuration persistante, utiliser UCI (Unified Configuration Interface) :
```bash
save_settings() {
local auto_refresh="$1"
local health_check="$2"
local refresh_interval="$3"
# Creer/mettre a jour la config UCI
uci set system-hub.general=general
uci set system-hub.general.auto_refresh="$auto_refresh"
uci set system-hub.general.health_check="$health_check"
uci set system-hub.general.refresh_interval="$refresh_interval"
uci commit system-hub
json_init
json_add_boolean "success" 1
json_add_string "message" "Settings saved successfully"
json_dump
}
get_settings() {
# Charger la config UCI
if [ -f "/etc/config/system-hub" ]; then
. /lib/functions.sh
config_load system-hub
fi
json_init
json_add_object "general"
# Obtenir la valeur ou utiliser la valeur par defaut
config_get auto_refresh general auto_refresh "1"
json_add_boolean "auto_refresh" "${auto_refresh:-1}"
config_get refresh_interval general refresh_interval "30"
json_add_int "refresh_interval" "${refresh_interval:-30}"
json_close_object
json_dump
}
```
### Conseils de Performance
1. **Mettre en cache les operations couteuses** : Ne pas relire les fichiers `/proc` plusieurs fois
2. **Utiliser efficacement la substitution de commande** :
```bash
# Bien
uptime=$(cat /proc/uptime | cut -d' ' -f1)
# Mieux
read uptime _ < /proc/uptime
uptime=${uptime%.*}
```
3. **Eviter les commandes externes quand possible** :
```bash
# Lent
count=$(ls /etc/init.d | wc -l)
# Rapide
count=0
for file in /etc/init.d/*; do
[ -f "$file" ] && count=$((count + 1))
done
```
---
## Patterns Module API LuCI
### CRITIQUE : Utiliser baseclass.extend()
**REGLE** : Les modules API LuCI DOIVENT utiliser le pattern `baseclass.extend()`.
```javascript
'use strict';
'require baseclass';
'require rpc';
// Declarer les methodes RPC
var callStatus = rpc.declare({
object: 'luci.system-hub',
method: 'status',
expect: {}
});
var callGetHealth = rpc.declare({
object: 'luci.system-hub',
method: 'get_health',
expect: {}
});
var callSaveSettings = rpc.declare({
object: 'luci.system-hub',
method: 'save_settings',
params: ['auto_refresh', 'health_check', 'refresh_interval'],
expect: {}
});
// ✅ CORRECT : Utiliser baseclass.extend()
return baseclass.extend({
getStatus: callStatus,
getHealth: callGetHealth,
saveSettings: callSaveSettings
});
// ❌ INCORRECT : Ne PAS utiliser ces patterns
return baseclass.singleton({...}); // Casse tout !
return {...}; // L'objet simple ne fonctionne pas
```
**Pourquoi baseclass.extend() ?**
- Le systeme de modules LuCI attend des modules bases sur des classes
- Les vues importent avec `'require module/api as API'` qui auto-instancie
- `baseclass.extend()` cree un constructeur de classe approprié
- `baseclass.singleton()` casse le mecanisme d'instanciation
- Les objets simples ne supportent pas le cycle de vie des modules LuCI
### Parametres rpc.declare()
```javascript
var callMethodName = rpc.declare({
object: 'luci.module-name', // nom objet ubus (DOIT commencer par luci.)
method: 'method_name', // nom methode RPCD
params: ['param1', 'param2'], // Optionnel : noms des parametres (l'ordre compte !)
expect: {} // Structure de retour attendue (ou { key: [] } pour les tableaux)
});
```
**L'Ordre des Parametres est Important** :
```javascript
// RPCD attend les parametres dans cet ordre exact
var callSaveSettings = rpc.declare({
object: 'luci.system-hub',
method: 'save_settings',
params: ['auto_refresh', 'health_check', 'debug_mode', 'refresh_interval'],
expect: {}
});
// L'appel JavaScript DOIT passer les parametres dans le meme ordre
API.saveSettings(1, 1, 0, 30); // auto_refresh=1, health_check=1, debug_mode=0, refresh_interval=30
```
### Patterns du Parametre expect
```javascript
// La methode retourne un objet unique
expect: {}
// La methode retourne un tableau au niveau superieur
expect: { services: [] }
// La methode retourne une structure specifique
expect: {
services: [],
count: 0
}
```
### Gestion des Erreurs dans le Module API
Les methodes API retournent des Promises. Gerer les erreurs dans les vues :
```javascript
return API.getHealth().then(function(data) {
if (!data || typeof data !== 'object') {
console.error('Invalid health data:', data);
return null;
}
return data;
}).catch(function(err) {
console.error('Failed to load health data:', err);
ui.addNotification(null, E('p', {}, 'Failed to load health data'), 'error');
return null;
});
```
---
## Patterns d'Import de Vues LuCI
### CRITIQUE : Utiliser 'require ... as VAR' pour les APIs
**REGLE** : Lors de l'import de modules API, utiliser le pattern `'require ... as VAR'` en haut du fichier.
```javascript
// ✅ CORRECT : Auto-instancie la classe
'require system-hub/api as API';
return L.view.extend({
load: function() {
return API.getHealth(); // API est deja instancie
}
});
// ❌ INCORRECT : Retourne le constructeur de classe, pas l'instance
var api = L.require('system-hub.api');
api.getHealth(); // ERREUR : api.getHealth is not a function
```
**Pourquoi ?**
- `'require module/path as VAR'` (avec des slashes) auto-instancie les classes
- `L.require('module.path')` (avec des points) retourne le constructeur de classe brut
- Les modules API etendent `baseclass`, qui necessite une instanciation
- Le chargeur de modules LuCI gere l'instanciation avec le pattern `as VAR`
### Structure de Vue Standard
```javascript
'use strict';
'require view';
'require form';
'require ui';
'require system-hub/api as API';
return L.view.extend({
load: function() {
// Charger les donnees necessaires au rendu
return Promise.all([
API.getHealth(),
API.getStatus()
]);
},
render: function(data) {
var health = data[0];
var status = data[1];
// Creer les elements UI
var container = E('div', { 'class': 'cbi-map' }, [
E('h2', {}, 'Dashboard'),
// ... plus d'elements
]);
return container;
},
handleSave: null, // Desactiver le bouton sauvegarder
handleSaveApply: null, // Desactiver le bouton sauvegarder et appliquer
handleReset: null // Desactiver le bouton reinitialiser
});
```
### Resume des Patterns d'Import
```javascript
// Modules core LuCI (toujours avec des guillemets)
'require view';
'require form';
'require ui';
'require rpc';
'require baseclass';
// Modules API personnalises (utiliser 'as VAR' pour l'auto-instanciation)
'require system-hub/api as API';
'require cdn-cache/api as CdnAPI';
// Acceder a l'objet global L (pas de require)
L.resolveDefault(...)
L.Poll.add(...)
L.ui.addNotification(...)
```
---
## Structure des Permissions ACL
### Emplacement du Fichier
Les fichiers ACL sont situes dans :
```
/usr/share/rpcd/acl.d/luci-app-<nom-module>.json
```
Dans l'arborescence source :
```
luci-app-<nom-module>/root/usr/share/rpcd/acl.d/luci-app-<nom-module>.json
```
### Modele ACL Standard
```json
{
"luci-app-module-name": {
"description": "Module Name - Description",
"read": {
"ubus": {
"luci.module-name": [
"status",
"get_system_info",
"get_health",
"list_services",
"get_logs",
"get_storage",
"get_settings"
]
}
},
"write": {
"ubus": {
"luci.module-name": [
"service_action",
"backup_config",
"restore_config",
"reboot",
"save_settings"
]
}
}
}
}
```
### Classification Lecture vs Ecriture
**Operations de Lecture** (pas de modification systeme) :
- `status` - Obtenir l'etat actuel
- `get_*` - Recuperer des donnees (info systeme, sante, parametres, logs, stockage)
- `list_*` - Enumerer des elements (services, interfaces, etc.)
**Operations d'Ecriture** (modifier l'etat systeme) :
- `*_action` - Effectuer des actions (demarrer/arreter services, etc.)
- `save_*` - Persister les changements de configuration
- `backup`, `restore` - Sauvegarde/restauration systeme
- `reboot`, `shutdown` - Controle systeme
### Erreurs ACL Courantes
**Erreur** : `Access denied` ou erreur RPC `-32002`
**Cause** : Methode non listee dans l'ACL, ou listee dans la mauvaise section (lecture vs ecriture)
**Solution** :
1. Identifier si la methode est une operation de lecture ou d'ecriture
2. Ajouter le nom de la methode a la section appropriee dans l'ACL
3. Redemarrer RPCD : `/etc/init.d/rpcd restart`
**Validation** :
```bash
# Verifier que le fichier ACL est du JSON valide
jsonlint /usr/share/rpcd/acl.d/luci-app-system-hub.json
# Lister tous les objets et methodes ubus
ubus list luci.system-hub
# Tester une methode avec ubus call
ubus call luci.system-hub get_health
```
---
## Conventions de Structure de Donnees
### Structure des Metriques de Sante (system-hub v0.1.0)
Basee sur des iterations extensives, cette structure fournit clarte et coherence :
```json
{
"cpu": {
"usage": 25,
"status": "ok",
"load_1m": "0.25",
"load_5m": "0.30",
"load_15m": "0.28",
"cores": 4
},
"memory": {
"total_kb": 4096000,
"free_kb": 2048000,
"available_kb": 3072000,
"used_kb": 1024000,
"buffers_kb": 512000,
"cached_kb": 1536000,
"usage": 25,
"status": "ok"
},
"disk": {
"total_kb": 30408704,
"used_kb": 5447680,
"free_kb": 24961024,
"usage": 19,
"status": "ok"
},
"temperature": {
"value": 45,
"status": "ok"
},
"network": {
"wan_up": true,
"status": "ok"
},
"services": {
"running": 35,
"failed": 2
},
"score": 92,
"timestamp": "2025-12-26 10:30:00",
"recommendations": [
"2 service(s) enabled but not running. Check service status."
]
}
```
**Principes Cles** :
1. **Objets imbriques** pour les metriques liees (cpu, memory, disk, etc.)
2. **Structure coherente** : Chaque metrique a `usage` (pourcentage) et `status` (ok/warning/critical)
3. **Valeurs brutes + calculees** : Fournir les deux (ex: `used_kb` ET `usage` en pourcentage)
4. **Seuils de statut** : ok (< warning), warning (warning-critical), critical (>= critical)
5. **Score global** : Score de sante unique 0-100 pour le tableau de bord
6. **Recommandations dynamiques** : Tableau d'alertes actionnables basees sur les seuils
### Valeurs de Statut
Utiliser des chaines de statut coherentes pour toutes les metriques :
- `"ok"` - Fonctionnement normal (vert)
- `"warning"` - Approche du seuil (orange)
- `"critical"` - Seuil depasse (rouge)
- `"error"` - Impossible de recuperer la metrique
- `"unknown"` - Metrique non disponible
### Format d'Horodatage
Utiliser ISO 8601 ou un format local coherent :
```bash
timestamp="$(date '+%Y-%m-%d %H:%M:%S')" # 2025-12-26 10:30:00
```
### Valeurs Booleennes en JSON
Dans les scripts shell utilisant jshn.sh :
```bash
json_add_boolean "wan_up" 1 # true
json_add_boolean "wan_up" 0 # false
```
En JavaScript :
```javascript
if (health.network.wan_up) {
// WAN est actif
}
```
### Tableau vs Valeur Unique
**Utiliser des tableaux pour** :
- Elements multiples du meme type (services, interfaces, points de montage)
- Donnees de longueur variable
**Utiliser des valeurs uniques pour** :
- Metriques systeme globales (CPU, memoire, disque)
- Valeurs primaires/agregees (temperature globale, uptime total)
**Exemple - Stockage** :
```json
// Points de montage multiples - utiliser un tableau
"storage": [
{
"mount": "/",
"total_kb": 30408704,
"used_kb": 5447680,
"usage": 19
},
{
"mount": "/mnt/usb",
"total_kb": 128000000,
"used_kb": 64000000,
"usage": 50
}
]
// Systeme de fichiers racine seulement - utiliser un objet
"disk": {
"total_kb": 30408704,
"used_kb": 5447680,
"usage": 19,
"status": "ok"
}
```
---
## Erreurs Courantes et Solutions
### 1. Erreur RPC : "Object not found" (-32000)
**Message d'Erreur** :
```
RPC call to system-hub/status failed with error -32000: Object not found
```
**Cause** : Le nom du script RPCD ne correspond pas au nom de l'objet ubus en JavaScript
**Solution** :
1. Verifier le nom de l'objet dans JavaScript :
```bash
grep -r "object:" luci-app-system-hub/htdocs --include="*.js"
```
Sortie : `object: 'luci.system-hub'`
2. Renommer le script RPCD pour correspondre exactement :
```bash
mv root/usr/libexec/rpcd/system-hub root/usr/libexec/rpcd/luci.system-hub
```
3. S'assurer que le script est executable :
```bash
chmod +x root/usr/libexec/rpcd/luci.system-hub
```
4. Redemarrer RPCD :
```bash
/etc/init.d/rpcd restart
```
### 2. Erreur JavaScript : "api.methodName is not a function"
**Message d'Erreur** :
```
Uncaught TypeError: api.getHealth is not a function
at view.load (health.js:12)
```
**Cause** : Mauvais pattern d'import - import du constructeur de classe au lieu de l'instance
**Solution** :
Changer de :
```javascript
var api = L.require('system-hub.api'); // ❌ Incorrect
```
A :
```javascript
'require system-hub/api as API'; // ✅ Correct
```
**Pourquoi** : `L.require('module.path')` retourne la classe brute, `'require module/path as VAR'` auto-instancie.
### 3. Erreur RPC : "Access denied" (-32002)
**Message d'Erreur** :
```
RPC call to luci.system-hub/get_settings failed with error -32002: Access denied
```
**Cause** : Methode non listee dans le fichier ACL, ou dans la mauvaise section (lecture vs ecriture)
**Solution** :
1. Ouvrir le fichier ACL : `root/usr/share/rpcd/acl.d/luci-app-system-hub.json`
2. Ajouter la methode a la section appropriee :
```json
"read": {
"ubus": {
"luci.system-hub": [
"get_settings"
]
}
}
```
3. Deployer et redemarrer RPCD :
```bash
scp luci-app-system-hub/root/usr/share/rpcd/acl.d/*.json router:/usr/share/rpcd/acl.d/
ssh router "/etc/init.d/rpcd restart"
```
### 4. Erreur d'Affichage : "NaN%" ou Valeurs Indefinies
**Erreur** : Le tableau de bord affiche "NaN%", "undefined", ou des valeurs vides
**Cause** : Le frontend utilise des cles de structure de donnees incorrectes (obsoletes apres des changements backend)
**Solution** :
1. Verifier la sortie backend :
```bash
ubus call luci.system-hub get_health
```
2. Mettre a jour le frontend pour correspondre a la structure :
```javascript
// ❌ Ancienne structure
var cpuPercent = health.load / health.cores * 100;
var memPercent = health.memory.percent;
// ✅ Nouvelle structure
var cpuPercent = health.cpu ? health.cpu.usage : 0;
var memPercent = health.memory ? health.memory.usage : 0;
```
3. Ajouter des verifications null/undefined :
```javascript
var temp = health.temperature?.value || 0;
var loadAvg = health.cpu?.load_1m || '0.00';
```
### 5. HTTP 404 : Fichier Vue Non Trouve
**Message d'Erreur** :
```
HTTP error 404 while loading class file '/luci-static/resources/view/netifyd/overview.js'
```
**Cause** : Le chemin du menu ne correspond pas a l'emplacement reel du fichier vue
**Solution** :
1. Verifier le JSON du menu :
```bash
cat root/usr/share/luci/menu.d/luci-app-netifyd-dashboard.json
```
Chercher : `"path": "netifyd/overview"`
2. Verifier l'emplacement reel du fichier :
```bash
ls htdocs/luci-static/resources/view/
```
Le fichier est a : `view/netifyd-dashboard/overview.js`
3. Corriger soit le chemin du menu SOIT l'emplacement du fichier :
```json
// Option 1 : Mettre a jour le chemin du menu pour correspondre au fichier
"path": "netifyd-dashboard/overview"
// Option 2 : Deplacer le fichier pour correspondre au menu
mv view/netifyd-dashboard/ view/netifyd/
```
### 6. Erreur de Build : "factory yields invalid constructor"
**Message d'Erreur** :
```
/luci-static/resources/system-hub/api.js: factory yields invalid constructor
```
**Cause** : Mauvais pattern utilise dans le module API (singleton, objet simple, etc.)
**Solution** :
Toujours utiliser `baseclass.extend()` :
```javascript
return baseclass.extend({
getStatus: callStatus,
getHealth: callGetHealth,
// ... plus de methodes
});
```
Ne PAS utiliser :
- `baseclass.singleton({...})`
- Objet simple : `return {...}`
- `baseclass.prototype`
### 7. RPCD Ne Repond Plus Apres des Changements
**Symptome** : Les changements au script RPCD ne prennent pas effet
**Solution** :
1. Verifier que le script est deploye :
```bash
ssh router "ls -la /usr/libexec/rpcd/"
```
2. Verifier que le script est executable :
```bash
ssh router "chmod +x /usr/libexec/rpcd/luci.system-hub"
```
3. Redemarrer RPCD :
```bash
ssh router "/etc/init.d/rpcd restart"
```
4. Vider le cache du navigateur (Ctrl+Shift+R)
5. Verifier les logs RPCD :
```bash
ssh router "logread | grep rpcd"
```
---
## Checklist de Validation
Utiliser cette checklist avant le deploiement :
### Structure des Fichiers
- [ ] Le script RPCD existe : `/usr/libexec/rpcd/luci.<nom-module>`
- [ ] Le script RPCD est executable : `chmod +x`
- [ ] Le JSON du menu existe : `/usr/share/luci/menu.d/luci-app-<module>.json`
- [ ] Le JSON ACL existe : `/usr/share/rpcd/acl.d/luci-app-<module>.json`
- [ ] Le module API existe : `htdocs/luci-static/resources/<module>/api.js`
- [ ] Les vues existent : `htdocs/luci-static/resources/view/<module>/*.js`
### Conventions de Nommage
- [ ] Le nom du script RPCD correspond a l'objet ubus en JavaScript (incluant le prefixe `luci.`)
- [ ] Les chemins du menu correspondent a la structure de repertoire des fichiers vue
- [ ] Tous les objets ubus commencent par `luci.`
- [ ] La cle ACL correspond au nom du package : `"luci-app-<module>"`
### Validation du Code
- [ ] Le module API utilise le pattern `baseclass.extend()`
- [ ] Les vues importent l'API avec le pattern `'require <module>/api as API'`
- [ ] Tous les appels rpc.declare() incluent `object`, `method`, `params`, `expect` corrects
- [ ] Le script RPCD produit du JSON valide (tester avec `ubus call`)
- [ ] Le JSON du menu est valide (tester avec `jsonlint`)
- [ ] Le JSON ACL est valide (tester avec `jsonlint`)
### Permissions
- [ ] Toutes les methodes de lecture dans la section ACL `"read"`
- [ ] Toutes les methodes d'ecriture dans la section ACL `"write"`
- [ ] Les methodes dans l'ACL correspondent exactement aux noms des methodes du script RPCD
### Tests
- [ ] Executer le script de validation : `./secubox-tools/validate-modules.sh`
- [ ] Tester chaque methode via ubus : `ubus call luci.<module> <method>`
- [ ] Tester le frontend dans le navigateur (verifier la console pour les erreurs)
- [ ] Vider le cache du navigateur apres le deploiement
- [ ] Verifier le redemarrage RPCD : `/etc/init.d/rpcd restart`
### Commande de Validation Automatisee
```bash
# Executer la validation complete
./secubox-tools/validate-modules.sh
# Valider un module specifique
./secubox-tools/validate-module-generation.sh luci-app-system-hub
# Verifier la syntaxe JSON
find luci-app-system-hub -name "*.json" -exec jsonlint {} \;
# Verifier les scripts shell
shellcheck luci-app-system-hub/root/usr/libexec/rpcd/*
```
---
## Tests et Deploiement
### Tests Locaux avec ubus
Avant de deployer sur le routeur, tester le script RPCD localement :
```bash
# Copier le script RPCD vers /tmp local
cp luci-app-system-hub/root/usr/libexec/rpcd/luci.system-hub /tmp/
# Rendre executable
chmod +x /tmp/luci.system-hub
# Tester l'action 'list'
/tmp/luci.system-hub list
# Tester l'action 'call' avec une methode
/tmp/luci.system-hub call status
# Tester une methode avec parametres
echo '{"service":"network","action":"restart"}' | /tmp/luci.system-hub call service_action
```
### Script de Deploiement
Utiliser un script de deploiement pour une iteration rapide :
```bash
#!/bin/bash
# deploy-system-hub.sh
ROUTER="root@192.168.8.191"
echo "Deploiement de system-hub vers $ROUTER"
# Deployer le module API
scp luci-app-system-hub/htdocs/luci-static/resources/system-hub/api.js \
"$ROUTER:/www/luci-static/resources/system-hub/"
# Deployer les vues
scp luci-app-system-hub/htdocs/luci-static/resources/view/system-hub/*.js \
"$ROUTER:/www/luci-static/resources/view/system-hub/"
# Deployer le backend RPCD
scp luci-app-system-hub/root/usr/libexec/rpcd/luci.system-hub \
"$ROUTER:/usr/libexec/rpcd/"
# Deployer l'ACL
scp luci-app-system-hub/root/usr/share/rpcd/acl.d/luci-app-system-hub.json \
"$ROUTER:/usr/share/rpcd/acl.d/"
# Definir les permissions et redemarrer
ssh "$ROUTER" "chmod +x /usr/libexec/rpcd/luci.system-hub && /etc/init.d/rpcd restart"
echo "Deploiement termine ! Videz le cache du navigateur (Ctrl+Shift+R)"
```
### Tests Navigateur
1. Ouvrir la console du navigateur (F12)
2. Naviguer vers la page du module
3. Verifier les erreurs :
- Erreurs RPC (object not found, method not found, access denied)
- Erreurs JavaScript (api.method is not a function)
- Erreurs 404 (fichiers vue non trouves)
4. Tester les fonctionnalites :
- Le chargement des donnees s'affiche correctement
- Les actions fonctionnent (demarrer/arreter services, sauvegarder parametres)
- Pas de "NaN", "undefined", ou valeurs vides
### Tests ubus a Distance
Tester les methodes RPCD sur le routeur :
```bash
# Lister toutes les methodes
ssh router "ubus list luci.system-hub"
# Appeler une methode sans parametres
ssh router "ubus call luci.system-hub status"
# Appeler une methode avec parametres
ssh router "ubus call luci.system-hub service_action '{\"service\":\"network\",\"action\":\"restart\"}'"
# Formater la sortie JSON
ssh router "ubus call luci.system-hub get_health | jsonlint"
```
### Conseils de Debogage
**Activer la journalisation de debogage RPCD** :
```bash
# Editer /etc/init.d/rpcd
# Ajouter le flag -v a la commande procd_set_param
procd_set_param command "$PROG" -v
# Redemarrer RPCD
/etc/init.d/rpcd restart
# Surveiller les logs
logread -f | grep rpcd
```
**Activer la journalisation console JavaScript** :
```javascript
// Ajouter a api.js
console.log('API v0.1.0 chargee a', new Date().toISOString());
// Ajouter aux vues
console.log('Chargement des donnees de sante...');
API.getHealth().then(function(data) {
console.log('Donnees de sante:', data);
});
```
**Tester la sortie JSON** :
```bash
# Sur le routeur
/usr/libexec/rpcd/luci.system-hub call get_health | jsonlint
# Verifier les erreurs courantes
# - Virgules manquantes
# - Virgules en fin de liste
# - Cles non quotees
# - Sequences d'echappement invalides
```
---
## Resume des Bonnes Pratiques
### A FAIRE :
- Utiliser le prefixe `luci.` pour tous les objets ubus
- Nommer les scripts RPCD pour correspondre exactement a l'objet ubus
- Utiliser `baseclass.extend()` pour les modules API
- Importer les APIs avec le pattern `'require module/api as API'`
- Ajouter des verifications null/undefined dans le frontend : `health.cpu?.usage || 0`
- Valider le JSON avec `jsonlint` avant de deployer
- Tester avec `ubus call` avant les tests navigateur
- Redemarrer RPCD apres les changements backend
- Vider le cache du navigateur apres les changements frontend
- Executer `./secubox-tools/validate-modules.sh` avant de commiter
### A NE PAS FAIRE :
- Utiliser des noms d'objets ubus sans le prefixe `luci.`
- Utiliser `baseclass.singleton()` ou des objets simples pour les modules API
- Importer les APIs avec `L.require('module.path')` (retourne la classe, pas l'instance)
- Oublier d'ajouter les methodes au fichier ACL
- Melanger les methodes lecture/ecriture dans les sections ACL
- Produire du non-JSON depuis les scripts RPCD
- Utiliser des structures de donnees incoherentes entre backend et frontend
- Deployer sans tester localement d'abord
- Supposer que les donnees existent - toujours verifier null/undefined
- Oublier de rendre les scripts RPCD executables (`chmod +x`)
---
## Historique des Versions
**v1.0** (2025-12-26)
- Guide de reference initial
- Base sur luci-app-secubox v1.0.0 et luci-app-system-hub v0.1.0
- Documentation de tous les patterns critiques et erreurs courantes
- Valide contre les defis d'implementation reels
---
## References
- **Documentation OpenWrt** : https://openwrt.org/docs/guide-developer/start
- **Documentation LuCI** : https://github.com/openwrt/luci/wiki
- **Documentation ubus** : https://openwrt.org/docs/techref/ubus
- **Documentation UCI** : https://openwrt.org/docs/guide-user/base-system/uci
- **Bibliotheque jshn.sh** : `/usr/share/libubox/jshn.sh` sur OpenWrt
---
## Contact
Pour des questions ou contributions a ce guide de reference :
- **Auteur** : CyberMind <contact@cybermind.fr>
- **Projet** : SecuBox OpenWrt
- **Depot** : https://github.com/cybermind-fr/secubox-openwrt
---
**FIN DU GUIDE DE REFERENCE**