secubox-openwrt/docs/development-guidelines.md
2026-01-04 19:50:25 +01:00

1889 lines
49 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SecuBox & System Hub - Development Guidelines
**Version:** 1.0.0
**Last Updated:** 2025-12-28
**Status:** Active
**Audience:** Développeurs, IA assistants, mainteneurs
Ce document définit les standards, bonnes pratiques et validations obligatoires pour le développement de modules SecuBox et System Hub dans l'écosystème OpenWrt LuCI.
---
## Table des matières
1. [Design System & UI Guidelines](#design-system-ui-guidelines)
2. [Architecture & Naming Conventions](#architecture-naming-conventions)
3. [RPCD & ubus Best Practices](#rpcd-ubus-best-practices)
4. [ACL & Permissions](#acl-permissions)
5. [JavaScript Patterns](#javascript-patterns)
6. [CSS/Styling Standards](#cssstyling-standards)
7. [Common Errors & Solutions](#common-errors-solutions)
8. [Validation Checklist](#validation-checklist)
9. [Deployment Procedures](#deployment-procedures)
10. [AI Assistant Context Files](#ai-assistant-context-files)
---
## Design System & UI Guidelines
### Color Palette (Demo-inspired)
**IMPORTANT:** Toujours utiliser la palette définie dans `system-hub/common.css`
#### Dark Mode (Primary - Recommended)
```css
--sh-text-primary: #fafafa;
--sh-text-secondary: #a0a0b0;
--sh-bg-primary: #0a0a0f; /* Fond principal (noir profond) */
--sh-bg-secondary: #12121a; /* Fond cartes/sections */
--sh-bg-tertiary: #1a1a24; /* Fond hover/actif */
--sh-bg-card: #12121a;
--sh-border: #2a2a35;
--sh-primary: #6366f1; /* Indigo */
--sh-primary-end: #8b5cf6; /* Violet (pour dégradés) */
--sh-success: #22c55e; /* Vert */
--sh-danger: #ef4444; /* Rouge */
--sh-warning: #f59e0b; /* Orange */
```
#### Light Mode (Secondary)
```css
--sh-text-primary: #0f172a;
--sh-text-secondary: #475569;
--sh-bg-primary: #ffffff;
--sh-bg-secondary: #f8fafc;
--sh-bg-tertiary: #f1f5f9;
--sh-bg-card: #ffffff;
--sh-border: #e2e8f0;
```
**✅ TOUJOURS utiliser les CSS variables** - Ne JAMAIS hardcoder les couleurs.
### Typography
#### Fonts Stack
```css
/* Texte général */
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
/* Valeurs numériques, IDs, code */
font-family: 'JetBrains Mono', 'Courier New', monospace;
```
**Import requis** (ajouté dans common.css):
```css
@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Inter:wght@400;500;600;700&display=swap');
```
#### Font Sizes
```css
/* Titres */
--sh-title-xl: 28px; /* Page titles */
--sh-title-lg: 20px; /* Card titles */
--sh-title-md: 16px; /* Section headers */
/* Texte */
--sh-text-base: 14px; /* Body text */
--sh-text-sm: 13px; /* Labels, meta */
--sh-text-xs: 11px; /* Uppercase labels */
/* Valeurs */
--sh-value-xl: 40px; /* Large metrics */
--sh-value-lg: 32px; /* Stats overview */
--sh-value-md: 28px; /* Badges */
```
### Component Patterns
#### Component Hierarchy
The following diagram shows the standard page structure and component relationships:
```mermaid
graph TB
PAGE[Page Container<br/>.module-dashboard] --> HEADER[sh-page-header]
PAGE --> CONTENT[sh-content]
HEADER --> TITLE_SECTION[Title Section<br/>div]
HEADER --> STATS[sh-stats-grid]
TITLE_SECTION --> TITLE[sh-page-title<br/>gradient text]
TITLE_SECTION --> SUBTITLE[sh-page-subtitle]
STATS --> BADGE1[sh-stat-badge]
STATS --> BADGE2[sh-stat-badge]
STATS --> BADGE3[...]
BADGE1 --> VALUE1[sh-stat-value<br/>monospace font]
BADGE1 --> LABEL1[sh-stat-label<br/>uppercase]
CONTENT --> TABS[sh-filter-tabs]
CONTENT --> CARD_GRID[Card Grid<br/>grid layout]
TABS --> TAB1[sh-filter-tab<br/>active]
TABS --> TAB2[sh-filter-tab]
CARD_GRID --> CARD1[sh-card]
CARD_GRID --> CARD2[sh-card-success]
CARD_GRID --> CARD3[sh-card-danger]
CARD1 --> CH1[sh-card-header]
CARD1 --> CB1[sh-card-body]
CH1 --> CT1[sh-card-title]
CT1 --> ICON1[sh-card-title-icon]
CB1 --> BUTTONS[Button Group]
CB1 --> INFO[Info Rows]
BUTTONS --> BTN1[sh-btn<br/>sh-btn-primary]
BUTTONS --> BTN2[sh-btn<br/>sh-btn-secondary]
style PAGE fill:#0a0a0f,color:#fafafa,stroke:#6366f1,stroke-width:3px
style HEADER fill:#12121a,color:#fafafa,stroke:#6366f1,stroke-width:2px
style CONTENT fill:#12121a,color:#fafafa,stroke:#6366f1,stroke-width:2px
style CARD1 fill:#12121a,color:#fafafa,stroke:#6366f1,stroke-width:2px
style CARD2 fill:#12121a,color:#fafafa,stroke:#22c55e,stroke-width:2px
style CARD3 fill:#12121a,color:#fafafa,stroke:#ef4444,stroke-width:2px
style TITLE fill:#6366f1,color:#fff
style BTN1 fill:#6366f1,color:#fff
style VALUE1 fill:#8b5cf6,color:#fff
```
**Component Categories:**
1. **Layout Containers:** Page wrapper, header, content sections
2. **Typography:** Titles with gradient effects, subtitles, labels
3. **Data Display:** Stat badges with monospace values, cards with borders
4. **Navigation:** Filter tabs, nav tabs (sticky)
5. **Interactive:** Buttons with gradients and hover effects
**Styling Rules:**
- **Cards:** 3px top border (gradient on hover, or colored for status)
- **Stat Badges:** Minimum 130px width, monospace font for values
- **Buttons:** Gradient backgrounds, shadow on hover, smooth transitions
- **Tabs:** Active state with gradient background and glow
- **Grid Layouts:** Auto-fit with minimums (130px, 240px, or 300px)
---
#### 1. Page Header (Standard)
**REQUIREMENT:** Every module view MUST begin with this compact `.sh-page-header`. Do not introduce bespoke hero sections or oversized banners; the header keeps height predictable (title + subtitle on the left, stats on the right) and guarantees consistency across SecuBox dashboards. If no stats are needed, keep the container but supply an empty `.sh-stats-grid` for future metrics.
**Slim variant:** When the page only needs 23 metrics, use `.sh-page-header-lite` + `.sh-header-chip` (see `luci-app-vhost-manager` and `luci-app-secubox` settings). Chips carry an emoji/icon, a tiny label, and the value; colors (`.success`, `.danger`, `.warn`) communicate state. This variant replaces the bulky hero blocks from older demos.
**Version chip:** Always expose the package version from the RPC backend (read from `/usr/lib/opkg/info/<pkg>.control`) and display it as the first chip (`icon: 🏷️`). That keeps the UI and `PKG_VERSION` in sync without hunting for hard-coded strings.
**HTML Structure:**
```javascript
E('div', { 'class': 'sh-page-header' }, [
E('div', {}, [
E('h2', { 'class': 'sh-page-title' }, [
E('span', { 'class': 'sh-page-title-icon' }, '🎯'),
'Page Title'
]),
E('p', { 'class': 'sh-page-subtitle' }, 'Description of the page')
]),
E('div', { 'class': 'sh-stats-grid' }, [
// Stats badges here
])
])
```
**CSS Classes:**
- `.sh-page-header` - Container with flex layout
- `.sh-page-title` - Gradient text effect
- `.sh-page-title-icon` - Icon (no gradient)
- `.sh-page-subtitle` - Secondary text
- `.sh-stats-grid` - Grid pour badges (130px min)
#### 2. Stats Badges
**RÈGLE:** Minimum 130px, police monospace pour valeurs
```javascript
E('div', { 'class': 'sh-stat-badge' }, [
E('div', { 'class': 'sh-stat-value' }, '92'),
E('div', { 'class': 'sh-stat-label' }, 'CPU %')
])
```
**Grid Layout:**
```css
.sh-stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
gap: 12px;
}
```
#### 3. Cards avec bordure colorée
**OBLIGATOIRE:** Toutes les cards doivent avoir une bordure top de 3px
```javascript
E('div', { 'class': 'sh-card sh-card-success' }, [
E('div', { 'class': 'sh-card-header' }, [
E('h3', { 'class': 'sh-card-title' }, [
E('span', { 'class': 'sh-card-title-icon' }, '⚙️'),
'Card Title'
])
]),
E('div', { 'class': 'sh-card-body' }, [
// Content
])
])
```
**Variants de bordure:**
- `.sh-card` - Bordure gradient (visible au hover)
- `.sh-card-success` - Bordure verte permanente
- `.sh-card-danger` - Bordure rouge permanente
- `.sh-card-warning` - Bordure orange permanente
#### 4. Buttons
**Gradient buttons (preferred):**
```javascript
E('button', { 'class': 'sh-btn sh-btn-primary' }, 'Primary Action')
E('button', { 'class': 'sh-btn sh-btn-success' }, 'Success Action')
E('button', { 'class': 'sh-btn sh-btn-danger' }, 'Danger Action')
E('button', { 'class': 'sh-btn sh-btn-secondary' }, 'Secondary Action')
```
**Tous les buttons doivent avoir:**
- Shadow effect (déjà dans CSS)
- Hover animation (translateY(-2px))
- Transition smooth (0.3s cubic-bezier)
#### 5. Filter Tabs
```javascript
E('div', { 'class': 'sh-filter-tabs' }, [
E('div', {
'class': 'sh-filter-tab active',
'data-filter': 'all'
}, [
E('span', { 'class': 'sh-tab-icon' }, '📋'),
E('span', { 'class': 'sh-tab-label' }, 'All')
])
])
```
**Active tab styling:**
- Background: gradient indigo-violet
- Color: white
- Box-shadow avec glow
### Grid Systems
#### Stats Overview (Compact)
```css
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
gap: 16px;
```
#### Metric Cards (Medium)
```css
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 20px;
```
#### Info Cards (Large)
```css
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
```
### Gradient Effects
#### Gradient Text (Titles)
```css
background: linear-gradient(135deg, var(--sh-primary), var(--sh-primary-end));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
```
**Utiliser:** `.sh-gradient-text` class ou `.sh-page-title`
#### Gradient Backgrounds (Buttons, Badges)
```css
background: linear-gradient(135deg, var(--sh-primary), var(--sh-primary-end));
```
#### Gradient Borders (Top)
```css
/* 3px top border avec dégradé */
.element::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 3px;
background: linear-gradient(90deg, var(--sh-primary), var(--sh-primary-end));
}
```
### Animation Standards
#### Hover Effects
```css
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
transform: translateY(-3px); /* Cards */
transform: translateY(-2px); /* Buttons, badges */
```
#### Shadow Progression
```css
/* Default */
box-shadow: none;
/* Hover - Subtle */
box-shadow: 0 8px 20px var(--sh-shadow);
/* Hover - Pronounced */
box-shadow: 0 12px 28px var(--sh-hover-shadow);
/* Button Hover */
box-shadow: 0 8px 20px rgba(99, 102, 241, 0.5);
```
---
## Architecture & Naming Conventions
### System Architecture Overview
The following diagram illustrates the complete data flow from browser JavaScript to system backend:
```mermaid
graph TB
subgraph "Browser"
UI[JavaScript View<br/>view/module/overview.js]
API[API Module<br/>module/api.js]
end
subgraph "LuCI Framework"
RPC[RPC Layer<br/>L.rpc.declare]
UHTTPD[uhttpd<br/>Web Server]
end
subgraph "Backend Services"
RPCD[RPCD Daemon]
SCRIPT[RPCD Script<br/>/usr/libexec/rpcd/luci.module-name]
UBUS[ubus Message Bus]
end
subgraph "System Layer"
UCI[UCI Configuration]
SYS[System Services<br/>init.d scripts]
FS[Filesystem<br/>proc, sys, etc]
end
UI -->|"API.getStatus()"| API
API -->|"rpc.declare({ object: 'luci.module' })"| RPC
RPC -->|"HTTP POST /ubus"| UHTTPD
UHTTPD -->|"call method"| RPCD
RPCD -->|"execute script"| SCRIPT
SCRIPT -->|"ubus call"| UBUS
UBUS -->|"read/write"| UCI
UBUS -->|"control"| SYS
SCRIPT -->|"read metrics"| FS
style UI fill:#6366f1,color:#fff,stroke:#4f46e5
style API fill:#8b5cf6,color:#fff,stroke:#7c3aed
style SCRIPT fill:#22c55e,color:#fff,stroke:#16a34a
style RPCD fill:#f59e0b,color:#fff,stroke:#d97706
style UCI fill:#ef4444,color:#fff,stroke:#dc2626
```
**Key Components:**
1. **Browser Layer:** JavaScript views and API modules handle UI and data requests
2. **LuCI Framework:** RPC layer translates JavaScript calls to ubus protocol
3. **Backend Services:** RPCD executes shell scripts via ubus message bus
4. **System Layer:** UCI configs, system services, and filesystem provide data
**Critical Naming Rule:** The RPCD script name **MUST** match the `object` parameter in JavaScript's `rpc.declare()`.
---
### CRITICAL: RPCD Script Naming
**RÈGLE ABSOLUE:** Le nom du fichier RPCD DOIT correspondre EXACTEMENT au nom de l'objet ubus dans JavaScript.
#### ✅ CORRECT:
**JavaScript:**
```javascript
var callStatus = rpc.declare({
object: 'luci.system-hub', // ← Nom objet
method: 'getHealth'
});
```
**Fichier RPCD:**
```bash
root/usr/libexec/rpcd/luci.system-hub # ← EXACT MATCH
```
#### ❌ INCORRECT (Causes d'erreur -32000):
```bash
# Mauvais - manque le préfixe
root/usr/libexec/rpcd/system-hub
# Mauvais - underscore au lieu de tiret
root/usr/libexec/rpcd/luci.system_hub
# Mauvais - nom différent
root/usr/libexec/rpcd/systemhub
```
### Menu Path Conventions
**RÈGLE:** Les chemins dans menu.d/*.json doivent correspondre EXACTEMENT aux fichiers de vue.
#### ✅ CORRECT:
**Menu JSON:**
```json
{
"action": {
"type": "view",
"path": "system-hub/overview"
}
}
```
**Fichier de vue:**
```bash
htdocs/luci-static/resources/view/system-hub/overview.js
```
#### ❌ INCORRECT (Causes 404):
Menu: `"path": "system-hub/overview"` mais fichier: `view/systemhub/overview.js`
### Prefixes Standards
| Type | Prefix | Exemple |
|------|--------|---------|
| ubus objects | `luci.` | `luci.system-hub` |
| CSS classes | `sh-` (System Hub) ou `sb-` (SecuBox) | `.sh-page-header` |
| CSS variables | `--sh-` | `--sh-primary` |
| JavaScript modules | Nom du module | `system-hub/api.js` |
### File Structure Template
```
luci-app-<module-name>/
├── Makefile
├── README.md
├── htdocs/luci-static/resources/
│ ├── view/<module-name>/
│ │ ├── overview.js # Page principale
│ │ ├── settings.js # Configuration
│ │ └── *.js # Autres vues
│ └── <module-name>/
│ ├── api.js # RPC client
│ ├── theme.js # Theme helpers (optionnel)
│ ├── common.css # Styles partagés
│ └── *.css # Styles spécifiques
└── root/
├── usr/
│ ├── libexec/rpcd/
│ │ └── luci.<module-name> # ⚠️ MUST match ubus object
│ └── share/
│ ├── luci/menu.d/
│ │ └── luci-app-<module-name>.json
│ └── rpcd/acl.d/
│ └── luci-app-<module-name>.json
└── etc/config/<module-name> (optionnel)
```
---
## RPCD & ubus Best Practices
### RPCD Script Template (Shell)
**Fichier:** `root/usr/libexec/rpcd/luci.<module-name>`
```bash
#!/bin/sh
# RPCD backend for <module-name>
# ubus object: luci.<module-name>
case "$1" in
list)
# Liste des méthodes disponibles
echo '{
"getStatus": {},
"getHealth": {},
"getServices": {}
}'
;;
call)
case "$2" in
getStatus)
# TOUJOURS retourner du JSON valide
printf '{"enabled": true, "version": "1.0.0"}\n'
;;
getHealth)
# Lire les métriques système
cpu_usage=$(top -bn1 | grep "CPU:" | awk '{print $2}' | sed 's/%//')
mem_total=$(free | grep Mem | awk '{print $2}')
mem_used=$(free | grep Mem | awk '{print $3}')
printf '{
"cpu": {"usage": %s},
"memory": {"total_kb": %s, "used_kb": %s}
}\n' "$cpu_usage" "$mem_total" "$mem_used"
;;
getServices)
# Exemple avec services
services='[]'
for service in /etc/init.d/*; do
# Build JSON array
:
done
echo "$services"
;;
*)
echo '{"error": "Method not found"}'
exit 1
;;
esac
;;
esac
```
### RPCD Script Validation
**CHECKLIST OBLIGATOIRE:**
1. ✅ Fichier exécutable: `chmod +x root/usr/libexec/rpcd/luci.<module-name>`
2. ✅ Shebang présent: `#!/bin/sh`
3. ✅ Structure case/esac correcte
4. ✅ Méthode `list` retourne JSON avec toutes les méthodes
5. ✅ Méthode `call` gère tous les cas
6. ✅ Toujours retourner du JSON valide
7. ✅ Pas de `echo` de debug (commentés en prod)
8. ✅ Gestion d'erreur pour méthodes inconnues
### Testing RPCD Scripts
**Sur le routeur:**
```bash
# Test direct
/usr/libexec/rpcd/luci.system-hub list
# Via ubus
ubus list luci.system-hub
ubus call luci.system-hub getStatus
# Restart RPCD après modification
/etc/init.d/rpcd restart
```
### Common RPCD Errors
#### Error: "Object not found" (-32000)
**Cause:** Nom du fichier RPCD ne correspond pas à l'objet ubus
**Solution:**
```bash
# Vérifier le nom dans JS
grep -r "object:" htdocs/luci-static/resources/view/ --include="*.js"
# Renommer le fichier RPCD pour correspondre
mv root/usr/libexec/rpcd/wrong-name root/usr/libexec/rpcd/luci.correct-name
```
#### Error: "Method not found" (-32601)
**Cause:** Méthode non déclarée dans `list` ou non implémentée dans `call`
**Solution:**
```bash
# Vérifier que la méthode est dans les deux blocs
grep "getStatus" root/usr/libexec/rpcd/luci.*
```
#### Error: Invalid JSON returned
**Cause:** Output RPCD n'est pas du JSON valide
**Solution:**
```bash
# Tester le JSON
/usr/libexec/rpcd/luci.module-name call getStatus | jsonlint
# Utiliser printf au lieu de echo pour le JSON
printf '{"key": "%s"}\n' "$value"
```
---
## ACL & Permissions
### ACL File Template
**Fichier:** `root/usr/share/rpcd/acl.d/luci-app-<module-name>.json`
```json
{
"luci-app-<module-name>": {
"description": "Grant access to <Module Name>",
"read": {
"ubus": {
"luci.<module-name>": [
"getStatus",
"getHealth",
"getServices"
]
},
"uci": [
"<module-name>"
]
},
"write": {
"ubus": {
"luci.<module-name>": [
"setConfig",
"restartService"
]
},
"uci": [
"<module-name>"
]
}
}
}
```
### ACL Best Practices
1. **Séparation read/write:** Ne donnez que les permissions nécessaires
2. **Liste explicite:** Listez toutes les méthodes ubus utilisées
3. **UCI access:** Ajoutez les configs UCI dans `read` et `write`
4. **Validation JSON:** Toujours valider avec `jsonlint`
### Common ACL Errors
#### Error: "Access denied"
**Cause:** Méthode ubus pas dans ACL
**Solution:**
```json
{
"read": {
"ubus": {
"luci.system-hub": [
"getHealth" // ← Ajouter la méthode manquante
]
}
}
}
```
#### Error: "UCI config not accessible"
**Cause:** Config UCI pas dans ACL
**Solution:**
```json
{
"read": {
"uci": [
"system-hub" // ← Ajouter le config
]
}
}
```
---
## JavaScript Patterns
### API Module Template
**Fichier:** `htdocs/luci-static/resources/<module-name>/api.js`
```javascript
'use strict';
'require rpc';
'require uci';
return L.Class.extend({
// Déclarer les appels RPC
callGetStatus: rpc.declare({
object: 'luci.<module-name>',
method: 'getStatus',
expect: { }
}),
callGetHealth: rpc.declare({
object: 'luci.<module-name>',
method: 'getHealth',
expect: { }
}),
// Méthodes wrapper avec gestion d'erreur
getStatus: function() {
return this.callGetStatus().catch(function(err) {
console.error('Failed to get status:', err);
return { enabled: false, error: err.message };
});
},
getHealth: function() {
return this.callGetHealth().catch(function(err) {
console.error('Failed to get health:', err);
return {
cpu: { usage: 0 },
memory: { usage: 0 },
error: err.message
};
});
},
// Utilitaires
formatBytes: function(bytes) {
if (bytes === 0) return '0 B';
var k = 1024;
var sizes = ['B', 'KB', 'MB', 'GB'];
var i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
});
```
### View Template
**Fichier:** `htdocs/luci-static/resources/view/<module-name>/overview.js`
```javascript
'use strict';
'require view';
'require ui';
'require dom';
'require poll';
'require <module-name>/api as API';
return view.extend({
// State
healthData: null,
sysInfo: null,
// Load data
load: function() {
return Promise.all([
API.getStatus(),
API.getHealth()
]);
},
// Render UI
render: function(data) {
var self = this;
this.sysInfo = data[0] || {};
this.healthData = data[1] || {};
var container = E('div', { 'class': '<module>-dashboard' }, [
// Link CSS files
E('link', { 'rel': 'stylesheet', 'href': L.resource('<module>/common.css') }),
E('link', { 'rel': 'stylesheet', 'href': L.resource('<module>/overview.css') }),
// Header
this.renderHeader(),
// Content
this.renderContent()
]);
// Setup auto-refresh
poll.add(L.bind(function() {
return Promise.all([
API.getStatus(),
API.getHealth()
]).then(L.bind(function(refreshData) {
this.sysInfo = refreshData[0] || {};
this.healthData = refreshData[1] || {};
this.updateDashboard();
}, this));
}, this), 30); // Refresh every 30s
return container;
},
renderHeader: function() {
return E('div', { 'class': 'sh-page-header' }, [
// Header content
]);
},
renderContent: function() {
return E('div', { 'class': 'sh-content' }, [
// Main content
]);
},
updateDashboard: function() {
// Update existing DOM elements
var element = document.querySelector('.my-element');
if (element) {
dom.content(element, this.renderContent());
}
},
// Required stubs for LuCI
handleSaveApply: null,
handleSave: null,
handleReset: null
});
```
### Event Handling Pattern
```javascript
// ✅ CORRECT: Bind events après render
render: function(data) {
var container = E('div', {}, [
E('button', {
'id': 'my-button',
'class': 'sh-btn sh-btn-primary'
}, 'Click Me')
]);
// Ajouter l'événement après le container est créé
container.addEventListener('click', function(ev) {
if (ev.target && ev.target.id === 'my-button') {
self.handleButtonClick();
}
});
return container;
},
handleButtonClick: function() {
ui.addNotification(null, E('p', 'Button clicked!'), 'info');
}
```
### Common JavaScript Errors
#### Error: "[object HTMLButtonElement]" affiché
**Cause:** Array imbriqué quand E() attend un array simple
```javascript
// ❌ INCORRECT
E('div', {}, [
this.renderButtons() // renderButtons retourne déjà un array
])
// ✅ CORRECT
E('div', {},
this.renderButtons() // Pas de [ ] supplémentaire
)
```
#### Error: "Cannot read property of undefined"
**Cause:** Données API non disponibles
```javascript
// ❌ INCORRECT
var cpuUsage = this.healthData.cpu.usage;
// ✅ CORRECT (avec optional chaining)
var cpuUsage = (this.healthData.cpu && this.healthData.cpu.usage) || 0;
// ou
var cpuUsage = this.healthData.cpu?.usage || 0; // ES2020
```
#### Error: "poll callback failed"
**Cause:** Promise non retournée dans poll.add
```javascript
// ❌ INCORRECT
poll.add(function() {
API.getHealth(); // Pas de return!
}, 30);
// ✅ CORRECT
poll.add(function() {
return API.getHealth().then(function(data) {
// Update UI
});
}, 30);
```
---
## CSS/Styling Standards
### File Organization
```
<module-name>/
├── common.css # Shared components (headers, buttons, cards, tabs)
├── overview.css # Overview page specific
├── services.css # Services page specific
└── *.css # Other page-specific styles
```
### CSS File Template
```css
/**
* Module Name - Page/Component Styles
* Description of what this file styles
* Version: X.Y.Z
*/
/* === Import shared styles (if needed) === */
/* Not required if loaded in HTML */
/* === Page-specific variables (if needed) === */
:root {
--page-specific-var: value;
}
/* === Layout === */
.module-page-container {
/* Layout styles */
}
/* === Components === */
.module-component {
/* Component styles */
}
/* === Responsive === */
@media (max-width: 768px) {
/* Mobile styles */
}
/* === Dark Mode Overrides === */
[data-theme="dark"] .module-component {
/* Dark mode specific */
}
```
### CSS Best Practices
#### 1. TOUJOURS utiliser les variables CSS
```css
/* ❌ INCORRECT */
.my-card {
background: #12121a;
color: #fafafa;
}
/* ✅ CORRECT */
.my-card {
background: var(--sh-bg-card);
color: var(--sh-text-primary);
}
```
#### 2. Prefix classes par module
```css
/* System Hub */
.sh-page-header { }
.sh-card { }
.sh-btn { }
/* SecuBox */
.sb-module-grid { }
.sb-dashboard { }
/* Module spécifique */
.netdata-chart { }
.crowdsec-alert { }
```
#### 3. Transitions cohérentes
```css
/* Standard transition */
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
/* Quick transition (hover states) */
transition: all 0.2s ease;
/* Smooth transition (large movements) */
transition: all 0.5s ease;
```
#### 4. Responsive breakpoints
```css
/* Mobile */
@media (max-width: 768px) {
.sh-stats-grid {
grid-template-columns: repeat(2, 1fr);
}
}
/* Tablet */
@media (min-width: 769px) and (max-width: 1024px) {
/* Tablet specific */
}
/* Desktop */
@media (min-width: 1025px) {
/* Desktop specific */
}
```
#### 5. Dark mode OBLIGATOIRE
**Toujours fournir des styles dark mode:**
```css
/* Light mode (default) */
.my-component {
background: var(--sh-bg-card);
border: 1px solid var(--sh-border);
}
/* Dark mode override */
[data-theme="dark"] .my-component {
background: var(--sh-bg-card);
border-color: var(--sh-border);
}
```
### Z-index Scale
**Respecter cette échelle:**
```css
--z-base: 0;
--z-dropdown: 100;
--z-sticky: 200;
--z-fixed: 300;
--z-modal-backdrop: 400;
--z-modal: 500;
--z-popover: 600;
--z-tooltip: 700;
```
---
## Common Errors & Solutions
### 1. RPCD Object Not Found (-32000)
**Erreur complète:**
```
RPC call to luci.system-hub/getHealth failed with error -32000: Object not found
```
**Diagnostic:**
```bash
# 1. Vérifier que le fichier RPCD existe
ls -la /usr/libexec/rpcd/luci.system-hub
# 2. Vérifier qu'il est exécutable
chmod +x /usr/libexec/rpcd/luci.system-hub
# 3. Lister les objets ubus
ubus list | grep system-hub
# 4. Si absent, redémarrer RPCD
/etc/init.d/rpcd restart
ubus list | grep system-hub
```
**Solutions:**
1. Renommer le fichier RPCD pour correspondre exactement
2. Vérifier permissions (755 ou rwxr-xr-x)
3. Redémarrer rpcd
### 2. View Not Found (404)
**Erreur:**
```
HTTP error 404 while loading class file '/luci-static/resources/view/system-hub/overview.js'
```
**Diagnostic:**
```bash
# 1. Vérifier que le fichier existe
ls -la /www/luci-static/resources/view/system-hub/overview.js
# 2. Vérifier le chemin dans menu.d
grep "path" /usr/share/luci/menu.d/luci-app-system-hub.json
```
**Solutions:**
1. Vérifier que le path dans menu JSON correspond au fichier
2. Vérifier permissions du fichier (644)
3. Nettoyer cache: `rm -f /tmp/luci-indexcache /tmp/luci-modulecache/*`
### 3. CSS Not Loading (403 Forbidden)
**Erreur:**
```
GET /luci-static/resources/system-hub/common.css 403 Forbidden
```
**Diagnostic:**
```bash
# Vérifier permissions
ls -la /www/luci-static/resources/system-hub/common.css
```
**Solution:**
```bash
# Corriger permissions
chmod 644 /www/luci-static/resources/system-hub/*.css
```
### 4. Invalid JSON from RPCD
**Erreur dans browser console:**
```
SyntaxError: Unexpected token in JSON at position X
```
**Diagnostic:**
```bash
# Tester le JSON directement
/usr/libexec/rpcd/luci.system-hub call getHealth | jsonlint
# Ou avec jq
/usr/libexec/rpcd/luci.system-hub call getHealth | jq .
```
**Solutions courantes:**
```bash
# ❌ INCORRECT - Quote simple non échappée
echo '{"error": "can't process"}'
# ✅ CORRECT - Utiliser printf et doubles quotes
printf '{"error": "cannot process"}\n'
# ❌ INCORRECT - Variable non quotée
echo "{\"value\": $var}"
# ✅ CORRECT - Variable quotée
printf '{"value": "%s"}\n' "$var"
```
### 5. Browser Cache Issues
**Symptômes:**
- Changements CSS/JS non visibles
- Anciennes données affichées
- Code mis à jour mais interface identique
**Solutions:**
```bash
# 1. Côté serveur - nettoyer cache LuCI
ssh root@router "rm -f /tmp/luci-indexcache /tmp/luci-modulecache/* && /etc/init.d/uhttpd restart"
# 2. Côté client - hard refresh
Ctrl + Shift + R (Chrome/Firefox)
Ctrl + F5 (Windows)
Cmd + Shift + R (Mac)
# 3. Mode privé/incognito pour test
Ctrl + Shift + N (Chrome)
Ctrl + Shift + P (Firefox)
```
### 6. ACL Access Denied
**Erreur:**
```
Access to path '/admin/secubox/system/system-hub' denied
```
**Diagnostic:**
```bash
# Vérifier ACL
cat /usr/share/rpcd/acl.d/luci-app-system-hub.json | jq .
# Vérifier que méthodes ubus sont listées
grep "getHealth" /usr/share/rpcd/acl.d/luci-app-system-hub.json
```
**Solution:**
Ajouter la méthode manquante dans ACL et redémarrer rpcd.
---
## Validation Checklist
### Pre-Commit Checklist
Avant chaque commit, vérifier:
- [ ] **RPCD Script:**
- [ ] Nom fichier correspond à objet ubus
- [ ] Exécutable (chmod +x)
- [ ] Structure list/call correcte
- [ ] Retourne JSON valide
- [ ] Toutes méthodes implémentées
- [ ] **Menu & ACL:**
- [ ] Path menu correspond au fichier vue
- [ ] ACL liste toutes les méthodes ubus
- [ ] JSON valide (jsonlint)
- [ ] **JavaScript:**
- [ ] 'use strict' en première ligne
- [ ] Imports requis présents
- [ ] Pas de console.log en prod
- [ ] Gestion d'erreur sur API calls
- [ ] Event handlers bindés correctement
- [ ] **CSS:**
- [ ] Variables CSS utilisées (pas de hardcode)
- [ ] Classes prefixées (sh-, sb-, module-)
- [ ] Dark mode supporté
- [ ] Responsive (max-width: 768px)
- [ ] Transitions cohérentes
- [ ] **Makefile:**
- [ ] PKG_VERSION incrémenté
- [ ] LUCI_DEPENDS correct
- [ ] Include path correct (../../luci.mk)
### Pre-Deploy Checklist
Avant déploiement sur routeur:
- [ ] **Validation scripts:**
```bash
./secubox-tools/validate-modules.sh
```
- [ ] **Test RPCD local:**
```bash
/usr/libexec/rpcd/luci.module-name list
/usr/libexec/rpcd/luci.module-name call getStatus
```
- [ ] **Test JSON:**
```bash
find . -name "*.json" -exec jsonlint {} \;
```
- [ ] **Shellcheck:**
```bash
shellcheck root/usr/libexec/rpcd/*
```
- [ ] **Permissions:**
```bash
# RPCD scripts
chmod 755 root/usr/libexec/rpcd/*
# CSS/JS files
chmod 644 htdocs/luci-static/resources/**/*
```
### Post-Deploy Checklist
Après déploiement:
- [ ] **Services:**
```bash
/etc/init.d/rpcd status
/etc/init.d/uhttpd status
```
- [ ] **ubus objects:**
```bash
ubus list | grep luci.module-name
```
- [ ] **Fichiers présents:**
```bash
ls -la /www/luci-static/resources/view/module-name/
ls -la /www/luci-static/resources/module-name/
```
- [ ] **Permissions correctes:**
```bash
ls -la /usr/libexec/rpcd/luci.module-name
ls -la /www/luci-static/resources/module-name/*.css
```
- [ ] **Test navigateur:**
- [ ] Ouvrir en mode privé
- [ ] Vérifier console (F12) - pas d'erreurs
- [ ] Vérifier Network tab - tous les fichiers chargent (200)
- [ ] Tester dark/light mode
- [ ] Tester responsive (mobile view)
---
## Deployment Procedures
### Deployment Workflow
The following flowchart illustrates the complete deployment process with validation checkpoints:
```mermaid
flowchart TD
START([Start Deployment]) --> LOCAL_VAL{Local Validation<br/>Passed?}
LOCAL_VAL -->|No| FIX_LOCAL[Fix Issues Locally]
FIX_LOCAL --> LOCAL_VAL
LOCAL_VAL -->|Yes| CHECK_DISK{Disk Space<br/>< 90%?}
CHECK_DISK -->|No| CLEAN_DISK[Clean Temp Files<br/>& Old Backups]
CLEAN_DISK --> CHECK_DISK
CHECK_DISK -->|Yes| FIX_PERM_LOCAL[Fix Permissions<br/>Local Source]
FIX_PERM_LOCAL --> COPY[Copy Files to Router<br/>scp JS/CSS/RPCD]
COPY --> FIX_PERM_REMOTE[Fix Permissions<br/>Remote Files<br/>755 RPCD / 644 CSS-JS]
FIX_PERM_REMOTE --> CLEAR[Clear LuCI Cache<br/>/tmp/luci-*]
CLEAR --> RESTART[Restart Services<br/>rpcd + uhttpd]
RESTART --> V1{ubus Object<br/>Available?}
V1 -->|No| DEBUG1[Debug RPCD Script<br/>Check naming & permissions]
DEBUG1 --> FIX_PERM_REMOTE
V1 -->|Yes| V2{Files<br/>Accessible?}
V2 -->|403 Error| DEBUG2[Fix File Permissions<br/>chmod 644]
DEBUG2 --> FIX_PERM_REMOTE
V2 -->|Yes| V3{Menu Path<br/>Matches View?}
V3 -->|404 Error| DEBUG3[Fix Menu JSON Path]
DEBUG3 --> COPY
V3 -->|Yes| V4{UI Loads<br/>Correctly?}
V4 -->|Errors| DEBUG4[Check Browser Console<br/>Fix JavaScript Errors]
DEBUG4 --> COPY
V4 -->|Yes| TEST[Browser Testing<br/>Private Mode<br/>Dark/Light Mode<br/>Responsive]
TEST --> SUCCESS([✅ Deployment Success])
style START fill:#6366f1,color:#fff,stroke:#4f46e5
style SUCCESS fill:#22c55e,color:#fff,stroke:#16a34a
style DEBUG1 fill:#ef4444,color:#fff,stroke:#dc2626
style DEBUG2 fill:#ef4444,color:#fff,stroke:#dc2626
style DEBUG3 fill:#ef4444,color:#fff,stroke:#dc2626
style DEBUG4 fill:#ef4444,color:#fff,stroke:#dc2626
style CHECK_DISK fill:#f59e0b,color:#fff,stroke:#d97706
style LOCAL_VAL fill:#8b5cf6,color:#fff,stroke:#7c3aed
```
**Deployment Stages:**
1. **Local Validation:** Run `validate-modules.sh` and `fix-permissions.sh --local`
2. **Pre-Flight Checks:** Disk space and permission verification
3. **File Transfer:** Copy JavaScript, CSS, and RPCD scripts
4. **Remote Setup:** Fix permissions and clear caches
5. **Service Restart:** Reload rpcd and uhttpd daemons
6. **Validation:** Multi-stage verification (ubus, files, menu, UI)
7. **Testing:** Browser testing in private mode
**Common Error Recovery Paths:**
- **Object not found (-32000):** Check RPCD script naming and permissions
- **403 Forbidden:** Fix file permissions to 644 for CSS/JS
- **404 Not Found:** Verify menu path matches view file location
- **JavaScript errors:** Check browser console and fix code issues
---
### ⚠️ Pre-Deployment Checks (CRITICAL)
**TOUJOURS exécuter ces vérifications AVANT tout déploiement:**
#### 1. Vérification de l'Espace Disque
```bash
# Sur le routeur cible
ssh root@192.168.8.191 "df -h | grep overlay"
# Vérifier que l'utilisation est < 90%
# Exemple OK:
# /dev/loop0 98.8M 45.2M 53.6M 46% /overlay
# Exemple CRITIQUE (STOP deployment):
# /dev/loop0 98.8M 98.8M 0 100% /overlay ← PLEIN!
```
**Si l'overlay est plein (≥95%):**
```bash
# Libérer de l'espace avant déploiement
ssh root@192.168.8.191 << 'EOF'
# Supprimer fichiers temporaires
rm -rf /tmp/*.ipk /tmp/luci-* 2>/dev/null
# Supprimer anciens backups (>7 jours)
find /root -name '*.backup-*' -type f -mtime +7 -delete 2>/dev/null
# Vérifier packages inutilisés
opkg list-installed | grep -E 'netdata|unused'
# Après nettoyage, vérifier l'espace libéré
df -h | grep overlay
EOF
```
**Tailles typiques à surveiller:**
- Netdata web UI: ~22MB (considérer suppression si non utilisé)
- Modules LuCI: ~1-2MB chacun
- Fichiers CSS/JS: ~10-50KB chacun
#### 2. Vérification des Permissions (Critique pour Éviter Erreurs 403)
**Permissions OBLIGATOIRES:**
| Type | Permission | Octal | Raison |
|------|-----------|-------|--------|
| **RPCD scripts** | `rwxr-xr-x` | `755` | Exécutable par system |
| **CSS files** | `rw-r--r--` | `644` | Lecture web server |
| **JS files** | `rw-r--r--` | `644` | Lecture web server |
| **JSON files** | `rw-r--r--` | `644` | Lecture rpcd |
**Erreur commune:** Fichiers créés avec `600` (rw-------) au lieu de `644`
**Symptôme:** HTTP 403 Forbidden lors du chargement de fichiers JS/CSS
**Exemple d'erreur:**
```
NetworkError: HTTP error 403 while loading class file
"/luci-static/resources/view/netdata-dashboard/dashboard.js"
```
**Diagnostic rapide:**
```bash
# Vérifier permissions des fichiers déployés
ssh root@192.168.8.191 "ls -la /www/luci-static/resources/view/MODULE_NAME/"
# Chercher fichiers avec permissions incorrectes (600)
ssh root@192.168.8.191 "find /www/luci-static/resources/view/ -type f -name '*.js' -perm 600"
# MAUVAIS (cause 403):
# -rw------- 1 root root 9763 dashboard.js ← 600 = pas lisible par web!
# BON:
# -rw-r--r-- 1 root root 9763 dashboard.js ← 644 = OK
```
**Correction immédiate:**
```bash
# Corriger TOUS les fichiers CSS/JS
ssh root@192.168.8.191 << 'EOF'
find /www/luci-static/resources/ -name '*.css' -exec chmod 644 {} \;
find /www/luci-static/resources/ -name '*.js' -exec chmod 644 {} \;
find /usr/libexec/rpcd/ -name 'luci.*' -exec chmod 755 {} \;
EOF
```
**⚡ Correction Automatique (Recommandé):**
Utiliser le script automatique qui vérifie et corrige toutes les permissions:
```bash
# Corriger permissions locales (source code)
./secubox-tools/fix-permissions.sh --local
# Corriger permissions sur routeur
./secubox-tools/fix-permissions.sh --remote
# Corriger les deux (local + remote)
./secubox-tools/fix-permissions.sh
```
Le script `fix-permissions.sh` effectue automatiquement:
- ✅ Fixe tous les RPCD scripts à 755
- ✅ Fixe tous les CSS à 644
- ✅ Fixe tous les JS à 644
- ✅ Vérifie qu'aucun fichier 600 ne reste
- ✅ Clear cache et restart services (remote mode)
- ✅ Affiche un rapport complet des changements
**🔍 Validation Automatique des Permissions:**
Le script `validate-modules.sh` inclut maintenant un Check 7 qui vérifie automatiquement les permissions:
```bash
./secubox-tools/validate-modules.sh
# Check 7 validera:
# ✓ Tous les RPCD sont 755
# ✓ Tous les CSS sont 644
# ✓ Tous les JS sont 644
# ❌ Affichera erreurs si permissions incorrectes
```
**Workflow recommandé:**
1. Développer/modifier code
2. `./secubox-tools/fix-permissions.sh --local` (avant commit)
3. `./secubox-tools/validate-modules.sh` (vérifier tout)
4. Commit & push
5. Deploy sur routeur
6. `./secubox-tools/fix-permissions.sh --remote` (après deploy)
#### 3. Post-Deployment Verification
**Checklist après déploiement:**
```bash
#!/bin/bash
ROUTER="root@192.168.8.191"
MODULE="module-name"
echo "🔍 Post-Deployment Verification"
echo ""
# 1. Vérifier espace disque
echo "1. Espace disque restant:"
ssh "$ROUTER" "df -h | grep overlay | awk '{print \$5}'" || echo "❌ FAIL"
# 2. Vérifier permissions CSS/JS
echo "2. Permissions CSS/JS:"
ssh "$ROUTER" "find /www/luci-static/resources/$MODULE -type f \( -name '*.css' -o -name '*.js' \) ! -perm 644" | \
if [ -z "$(cat)" ]; then echo "✅ OK"; else echo "❌ FAIL - Permissions incorrectes"; fi
# 3. Vérifier permissions RPCD
echo "3. Permissions RPCD:"
ssh "$ROUTER" "ls -l /usr/libexec/rpcd/luci.$MODULE | grep -q rwxr-xr-x" && echo "✅ OK" || echo "❌ FAIL"
# 4. Vérifier ubus object
echo "4. ubus object disponible:"
ssh "$ROUTER" "ubus list | grep -q luci.$MODULE" && echo "✅ OK" || echo "❌ FAIL"
# 5. Vérifier fichiers accessibles (HTTP)
echo "5. Fichiers web accessibles:"
ssh "$ROUTER" "test -r /www/luci-static/resources/$MODULE/common.css" && echo "✅ OK" || echo "⚠️ common.css non trouvé"
# 6. Vérifier cache cleared
echo "6. Cache LuCI cleared:"
ssh "$ROUTER" "test ! -f /tmp/luci-indexcache" && echo "✅ OK" || echo "⚠️ Cache encore présent"
echo ""
echo "✅ Vérification terminée"
```
#### 4. Common Deployment Errors
| Erreur | Cause | Solution Rapide |
|--------|-------|----------------|
| **HTTP 403 Forbidden** | Permissions 600 au lieu de 644 | `chmod 644 *.js *.css` |
| **No space left on device** | Overlay plein | Nettoyer /tmp, supprimer anciens backups |
| **Object not found -32000** | RPCD pas exécutable ou mal nommé | `chmod 755 rpcd/luci.*` + vérifier nom |
| **Module not appearing** | Cache LuCI pas cleared | `rm /tmp/luci-*` + restart services |
| **Changes not visible** | Cache navigateur | Mode privé + Ctrl+Shift+R |
#### 5. Emergency Disk Space Recovery
**Si le déploiement échoue avec "No space left on device":**
```bash
#!/bin/bash
ROUTER="root@192.168.8.191"
echo "🚨 Emergency Disk Space Recovery"
echo ""
# 1. Analyser l'utilisation
echo "Top 10 consumers:"
ssh "$ROUTER" "du -k /overlay/upper 2>/dev/null | sort -rn | head -10"
# 2. Nettoyer temporaires
echo ""
echo "Cleaning temp files..."
ssh "$ROUTER" "rm -rf /tmp/*.ipk /tmp/luci-* /root/*.ipk 2>/dev/null"
# 3. Supprimer anciens backups
echo "Removing old backups (>7 days)..."
ssh "$ROUTER" "find /root -name '*.backup-*' -mtime +7 -delete 2>/dev/null"
# 4. Option: Supprimer Netdata Web UI (libère ~22MB)
echo ""
echo "⚠️ Option: Remove Netdata Web UI (saves ~22MB)?"
read -p "Continue? (y/N) " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]; then
ssh "$ROUTER" "opkg remove netdata-web 2>/dev/null || rm -rf /usr/share/netdata/web/*"
fi
# 5. Vérifier espace libéré
echo ""
echo "Space after cleanup:"
ssh "$ROUTER" "df -h | grep overlay"
```
### Standard Deployment Script Template
```bash
#!/bin/bash
# Deploy <Module Name>
ROUTER="root@192.168.8.191"
MODULE="<module-name>"
LOCAL_DIR="/path/to/luci-app-$MODULE/htdocs/luci-static/resources"
REMOTE_DIR="/www/luci-static/resources"
echo "📦 Déploiement $MODULE"
echo ""
# 1. Deploy JS files
echo "1. Copie des fichiers JS..."
scp "$LOCAL_DIR/view/$MODULE/"*.js "$ROUTER:$REMOTE_DIR/view/$MODULE/"
scp "$LOCAL_DIR/$MODULE/api.js" "$ROUTER:$REMOTE_DIR/$MODULE/"
# 2. Deploy CSS files
echo "2. Copie des fichiers CSS..."
scp "$LOCAL_DIR/$MODULE/"*.css "$ROUTER:$REMOTE_DIR/$MODULE/"
# 3. Deploy RPCD backend
echo "3. Copie du backend RPCD..."
scp "root/usr/libexec/rpcd/luci.$MODULE" "$ROUTER:/usr/libexec/rpcd/"
# 4. Fix permissions
echo "4. Correction des permissions..."
ssh "$ROUTER" "chmod 755 /usr/libexec/rpcd/luci.$MODULE"
ssh "$ROUTER" "chmod 644 $REMOTE_DIR/$MODULE/*.css"
ssh "$ROUTER" "chmod 644 $REMOTE_DIR/view/$MODULE/*.js"
# 5. Clear cache
echo "5. Nettoyage du cache..."
ssh "$ROUTER" "rm -f /tmp/luci-indexcache /tmp/luci-modulecache/* 2>/dev/null"
# 6. Restart services
echo "6. Redémarrage des services..."
ssh "$ROUTER" "/etc/init.d/rpcd restart"
ssh "$ROUTER" "/etc/init.d/uhttpd restart"
# 7. Verify
echo ""
echo "7. Vérification..."
ssh "$ROUTER" "ubus list | grep luci.$MODULE"
echo ""
echo "✅ Déploiement terminé!"
echo ""
echo "🌐 Testez (mode privé):"
echo " https://192.168.8.191/cgi-bin/luci/admin/secubox/path/to/$MODULE"
```
### Rollback Procedure
En cas de problème:
```bash
#!/bin/bash
# Rollback to previous version
ROUTER="root@192.168.8.191"
BACKUP_DIR="/root/luci-backups/$(date +%Y%m%d)"
# 1. Créer backup avant deploy
ssh "$ROUTER" "mkdir -p $BACKUP_DIR"
ssh "$ROUTER" "cp -r /www/luci-static/resources/module-name $BACKUP_DIR/"
ssh "$ROUTER" "cp /usr/libexec/rpcd/luci.module-name $BACKUP_DIR/"
# 2. En cas de problème, restore
ssh "$ROUTER" "cp -r $BACKUP_DIR/module-name /www/luci-static/resources/"
ssh "$ROUTER" "cp $BACKUP_DIR/luci.module-name /usr/libexec/rpcd/"
ssh "$ROUTER" "/etc/init.d/rpcd restart && /etc/init.d/uhttpd restart"
```
### Version Control
**Toujours incrémenter les versions:**
```makefile
# Makefile
PKG_VERSION:=0.3.0
PKG_RELEASE:=1
```
```css
/* CSS files */
/**
* Module - Styles
* Version: 0.3.0
*/
```
```javascript
// JavaScript
// Version: 0.3.0
```
**Semantic Versioning:**
- MAJOR.MINOR.PATCH (1.2.3)
- MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes
---
## Quick Reference
### Essential Commands
```bash
# Validation
./secubox-tools/validate-modules.sh
# Build (local)
./secubox-tools/local-build.sh build luci-app-module-name
# Deploy files
scp file.js root@router:/www/luci-static/resources/
# Fix permissions
ssh root@router "chmod 644 /www/luci-static/resources/**/*.css"
ssh root@router "chmod 755 /usr/libexec/rpcd/luci.*"
# Clear cache
ssh root@router "rm -f /tmp/luci-indexcache /tmp/luci-modulecache/*"
# Restart services
ssh root@router "/etc/init.d/rpcd restart && /etc/init.d/uhttpd restart"
# Test ubus
ssh root@router "ubus list | grep luci"
ssh root@router "ubus call luci.module-name getStatus"
# Validate JSON
jsonlint file.json
jq . file.json
```
### CSS Classes Quick Reference
```css
/* Layout */
.sh-page-header /* Page header container */
.sh-page-title /* Page title (gradient text) */
.sh-page-subtitle /* Page subtitle */
/* Stats */
.sh-stats-grid /* Grid for stat badges (130px min) */
.sh-stat-badge /* Stat badge container */
.sh-stat-value /* Stat value (monospace) */
.sh-stat-label /* Stat label (uppercase) */
/* Cards */
.sh-card /* Card container (with gradient border on hover) */
.sh-card-success /* Card with green border */
.sh-card-danger /* Card with red border */
.sh-card-warning /* Card with orange border */
.sh-card-header /* Card header */
.sh-card-title /* Card title */
.sh-card-body /* Card content */
/* Buttons */
.sh-btn /* Base button */
.sh-btn-primary /* Primary button (gradient) */
.sh-btn-success /* Success button (green) */
.sh-btn-danger /* Danger button (red) */
.sh-btn-secondary /* Secondary button (outline) */
/* Tabs */
.sh-filter-tabs /* Filter tabs container */
.sh-filter-tab /* Filter tab */
.sh-filter-tab.active /* Active filter tab (gradient) */
.sh-nav-tabs /* Navigation tabs (sticky) */
.sh-nav-tab /* Navigation tab */
.sh-nav-tab.active /* Active nav tab (underline) */
/* Utilities */
.sh-gradient-text /* Gradient text effect */
.sh-id-display /* Monospace ID display */
.sh-empty-state /* Empty state placeholder */
```
### Color Variables Quick Reference
```css
/* Text */
var(--sh-text-primary) /* Main text */
var(--sh-text-secondary) /* Secondary text */
/* Backgrounds */
var(--sh-bg-primary) /* Main background */
var(--sh-bg-secondary) /* Secondary background */
var(--sh-bg-tertiary) /* Tertiary background */
var(--sh-bg-card) /* Card background */
/* Borders */
var(--sh-border) /* Border color */
/* Colors */
var(--sh-primary) /* Indigo #6366f1 */
var(--sh-primary-end) /* Violet #8b5cf6 */
var(--sh-success) /* Green #22c55e */
var(--sh-danger) /* Red #ef4444 */
var(--sh-warning) /* Orange #f59e0b */
/* Effects */
var(--sh-shadow) /* Box shadow */
var(--sh-hover-shadow) /* Hover shadow */
var(--sh-hover-bg) /* Hover background */
```
---
## AI Assistant Context Files
SecuBox work is shared between Claude and Codex assistants. Keep the context folders synchronized so any agent can resume work quickly:
| Directory | File | Usage |
|-----------|------|-------|
| `.claude/` | `HISTORY.md` | Chronological log of UI/theme changes and major deployments |
| `.claude/` | `TODO.md` | High-level backlog (UX polish, docs, automation ideas) |
| `.claude/` | `WIP.md` | Active tasks, risks, and immediate next steps |
| `.codex/` | `HISTORY.md` | Mirrors the development timeline for Codex sessions |
| `.codex/` | `TODO.md` | Tooling-focused tasks (linting, scripts, build automation) |
| `.codex/` | `WIP.md` | Status tracker for ongoing Codex efforts |
**Maintenance rules**
1. **Update after each session:** When finishing work, append a short bullet to HISTORY and adjust WIP/TODO so they reflect the new state.
2. **Reference deployment scripts:** Note which `secubox-tools/*.sh` script was used (dashboard vs. full deploy) so the next assistant knows how to reproduce it.
3. **Keep entries concise:** A single paragraph or bullet per update is enough; detailed specs remain in DOCS.
4. **Cross-check before big changes:** Read both folders before starting work to avoid conflicts or duplicate efforts.
Treat these files as living handoff notes—if they drift, onboarding a new AI/teammate becomes significantly slower.
---
## Conclusion
Ce guide doit être consulté **AVANT** de:
1. Créer un nouveau module
2. Modifier des styles existants
3. Ajouter des méthodes RPCD
4. Déployer sur un routeur
5. Débugger des erreurs
**En cas de doute, TOUJOURS:**
1. Consulter ce guide
2. Exécuter validate-modules.sh
3. Tester en mode privé
4. Vérifier la console browser (F12)
**Ressources supplémentaires:**
- CLAUDE.md - Architecture et build
- secubox-tools/validate-modules.sh - Validation automatique
- Templates/ - Templates de code
---
**Dernière mise à jour:** 2025-12-26
**Maintenu par:** CyberMind Studio
**Version du guide:** 1.0.0