Skip to content

# 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
2. Architecture & Naming Conventions
3. RPCD & ubus Best Practices
4. ACL & Permissions
5. JavaScript Patterns
6. CSS/Styling Standards
7. Common Errors & Solutions
8. Validation Checklist
9. Deployment Procedures
10. 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)

    --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)

    --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

    /* 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):

    @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

    /* 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:

    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 2‑3 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:

    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

    E('div', { 'class': 'sh-stat-badge' }, [
        E('div', { 'class': 'sh-stat-value' }, '92'),
        E('div', { 'class': 'sh-stat-label' }, 'CPU %')
    ])

Grid Layout:

    .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

    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):

    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

    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)

    grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
    gap: 16px;

#### Metric Cards (Medium)

    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 20px;

#### Info Cards (Large)

    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 20px;

### Gradient Effects

#### Gradient Text (Titles)

    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)

    background: linear-gradient(135deg, var(--sh-primary), var(--sh-primary-end));

#### Gradient Borders (Top)

    /* 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

    transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    transform: translateY(-3px);  /* Cards */
    transform: translateY(-2px);  /* Buttons, badges */

#### Shadow Progression

    /* 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:

    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:

    var callStatus = rpc.declare({
        object: 'luci.system-hub',  // ← Nom objet
        method: 'getHealth'
    });

Fichier RPCD:

    root/usr/libexec/rpcd/luci.system-hub  # ← EXACT MATCH

#### ❌ INCORRECT (Causes d'erreur -32000):

    # 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:

    {
        "action": {
            "type": "view",
            "path": "system-hub/overview"
        }
    }

Fichier de vue:

    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>`

    #!/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:

    # 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:

    # 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:

    # 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:

    # 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`

    {
        "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:

    {
        "read": {
            "ubus": {
                "luci.system-hub": [
                    "getHealth"  // ← Ajouter la méthode manquante
                ]
            }
        }
    }

#### Error: "UCI config not accessible"

Cause: Config UCI pas dans ACL

Solution:

    {
        "read": {
            "uci": [
                "system-hub"  // ← Ajouter le config
            ]
        }
    }

## JavaScript Patterns

### API Module Template

Fichier: `htdocs/luci-static/resources/<module-name>/api.js`

    '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`

    '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

    // ✅ 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

    // ❌ 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

    // ❌ 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

    // ❌ 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

    /**
     * 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

    /* ❌ 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

    /* 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

    /* 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

    /* 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:

    /* 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:

    --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:

    # 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:

    # 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:

    # Vérifier permissions
    ls -la /www/luci-static/resources/system-hub/common.css

Solution:

    # 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:

    # 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:

    # ❌ 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:

    # 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:

    # 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:

      ./secubox-tools/validate-modules.sh

- Test RPCD local:

      /usr/libexec/rpcd/luci.module-name list
      /usr/libexec/rpcd/luci.module-name call getStatus

- Test JSON:

      find . -name "*.json" -exec jsonlint {} \;

- Shellcheck:

      shellcheck root/usr/libexec/rpcd/*

- Permissions:

      # 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:

      /etc/init.d/rpcd status
      /etc/init.d/uhttpd status

- ubus objects:

      ubus list | grep luci.module-name

- Fichiers présents:

      ls -la /www/luci-static/resources/view/module-name/
      ls -la /www/luci-static/resources/module-name/

- Permissions correctes:

      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:

    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

    # 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%):

    # 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:

    # 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:

    # 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:

    # 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:

    ./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:

    #!/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":

    #!/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

    #!/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:

    #!/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
    PKG_VERSION:=0.3.0
    PKG_RELEASE:=1

    /* CSS files */
    /**
     * Module - Styles
     * Version: 0.3.0
     */

    // 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

    # 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

    /* 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

    /* 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