secubox-openwrt/site/development-guidelines/index.html
CyberMind-FR ce543762cc chore: Update GitHub repo URL to CyberMind-FR organization
Replace github.com/gkerma/secubox-openwrt with
github.com/CyberMind-FR/secubox-openwrt across all files.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-14 09:44:01 +01:00

5575 lines
313 KiB
HTML
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.

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="OpenWrt LuCI Security & Management Suite">
<meta name="author" content="CyberMind.fr">
<link rel="canonical" href="https://gkerma.github.io/secubox-openwrt/development-guidelines/">
<link rel="prev" href="../repository-guidelines/">
<link rel="next" href="../code-templates/">
<link rel="icon" href="../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.7.1">
<title>Development Guidelines - SecuBox Documentation</title>
<link rel="stylesheet" href="../assets/stylesheets/main.484c7ddc.min.css">
<link rel="stylesheet" href="../assets/stylesheets/palette.ab4e12ef.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<link rel="stylesheet" href="../stylesheets/extra.css">
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="purple">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#secubox-system-hub-development-guidelines" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<div data-md-color-scheme="default" data-md-component="outdated" hidden>
</div>
<header class="md-header md-header--shadow md-header--lifted" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href=".." title="SecuBox Documentation" class="md-header__button md-logo" aria-label="SecuBox Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
SecuBox Documentation
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Development Guidelines
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="indigo" data-md-color-accent="purple" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a4 4 0 0 0-4 4 4 4 0 0 0 4 4 4 4 0 0 0 4-4 4 4 0 0 0-4-4m0 10a6 6 0 0 1-6-6 6 6 0 0 1 6-6 6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="indigo" data-md-color-accent="purple" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 18c-.89 0-1.74-.2-2.5-.55C11.56 16.5 13 14.42 13 12s-1.44-4.5-3.5-5.45C10.26 6.2 11.11 6 12 6a6 6 0 0 1 6 6 6 6 0 0 1-6 6m8-9.31V4h-4.69L12 .69 8.69 4H4v4.69L.69 12 4 15.31V20h4.69L12 23.31 15.31 20H20v-4.69L23.31 12z"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://github.com/CyberMind-FR/secubox-openwrt" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg>
</div>
<div class="md-source__repository">
gkerma/secubox-openwrt
</div>
</a>
</div>
</nav>
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href=".." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item">
<a href="../quick-start/" class="md-tabs__link">
Getting Started
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="./" class="md-tabs__link">
Development
</a>
</li>
<li class="md-tabs__item">
<a href="../claude/" class="md-tabs__link">
Reference
</a>
</li>
<li class="md-tabs__item">
<a href="../module-status/" class="md-tabs__link">
Modules
</a>
</li>
<li class="md-tabs__item">
<a href="../todo-analyse/" class="md-tabs__link">
Tools & Roadmap
</a>
</li>
<li class="md-tabs__item">
<a href="../archive/" class="md-tabs__link">
Archive
</a>
</li>
</ul>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href=".." title="SecuBox Documentation" class="md-nav__button md-logo" aria-label="SecuBox Documentation" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
SecuBox Documentation
</label>
<div class="md-nav__source">
<a href="https://github.com/CyberMind-FR/secubox-openwrt" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg>
</div>
<div class="md-source__repository">
gkerma/secubox-openwrt
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_2" >
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
<span class="md-ellipsis">
Getting Started
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Getting Started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../quick-start/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../documentation-index/" class="md-nav__link">
<span class="md-ellipsis">
Documentation Index
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../repository-guidelines/" class="md-nav__link">
<span class="md-ellipsis">
Repository Guidelines
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" checked>
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="">
<span class="md-ellipsis">
Development
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
Development
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Development Guidelines
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Development Guidelines
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#table-des-matieres" class="md-nav__link">
<span class="md-ellipsis">
Table des matières
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#design-system-ui-guidelines" class="md-nav__link">
<span class="md-ellipsis">
Design System &amp; UI Guidelines
</span>
</a>
<nav class="md-nav" aria-label="Design System &amp; UI Guidelines">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#color-palette-demo-inspired" class="md-nav__link">
<span class="md-ellipsis">
Color Palette (Demo-inspired)
</span>
</a>
<nav class="md-nav" aria-label="Color Palette (Demo-inspired)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#dark-mode-primary-recommended" class="md-nav__link">
<span class="md-ellipsis">
Dark Mode (Primary - Recommended)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#light-mode-secondary" class="md-nav__link">
<span class="md-ellipsis">
Light Mode (Secondary)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#typography" class="md-nav__link">
<span class="md-ellipsis">
Typography
</span>
</a>
<nav class="md-nav" aria-label="Typography">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#fonts-stack" class="md-nav__link">
<span class="md-ellipsis">
Fonts Stack
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#font-sizes" class="md-nav__link">
<span class="md-ellipsis">
Font Sizes
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#component-patterns" class="md-nav__link">
<span class="md-ellipsis">
Component Patterns
</span>
</a>
<nav class="md-nav" aria-label="Component Patterns">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#component-hierarchy" class="md-nav__link">
<span class="md-ellipsis">
Component Hierarchy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#1-page-header-standard" class="md-nav__link">
<span class="md-ellipsis">
1. Page Header (Standard)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-stats-badges" class="md-nav__link">
<span class="md-ellipsis">
2. Stats Badges
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-cards-avec-bordure-coloree" class="md-nav__link">
<span class="md-ellipsis">
3. Cards avec bordure colorée
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-buttons" class="md-nav__link">
<span class="md-ellipsis">
4. Buttons
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-filter-tabs" class="md-nav__link">
<span class="md-ellipsis">
5. Filter Tabs
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#grid-systems" class="md-nav__link">
<span class="md-ellipsis">
Grid Systems
</span>
</a>
<nav class="md-nav" aria-label="Grid Systems">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#stats-overview-compact" class="md-nav__link">
<span class="md-ellipsis">
Stats Overview (Compact)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#metric-cards-medium" class="md-nav__link">
<span class="md-ellipsis">
Metric Cards (Medium)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#info-cards-large" class="md-nav__link">
<span class="md-ellipsis">
Info Cards (Large)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#gradient-effects" class="md-nav__link">
<span class="md-ellipsis">
Gradient Effects
</span>
</a>
<nav class="md-nav" aria-label="Gradient Effects">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#gradient-text-titles" class="md-nav__link">
<span class="md-ellipsis">
Gradient Text (Titles)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#gradient-backgrounds-buttons-badges" class="md-nav__link">
<span class="md-ellipsis">
Gradient Backgrounds (Buttons, Badges)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#gradient-borders-top" class="md-nav__link">
<span class="md-ellipsis">
Gradient Borders (Top)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#animation-standards" class="md-nav__link">
<span class="md-ellipsis">
Animation Standards
</span>
</a>
<nav class="md-nav" aria-label="Animation Standards">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#hover-effects" class="md-nav__link">
<span class="md-ellipsis">
Hover Effects
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#shadow-progression" class="md-nav__link">
<span class="md-ellipsis">
Shadow Progression
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#architecture-naming-conventions" class="md-nav__link">
<span class="md-ellipsis">
Architecture &amp; Naming Conventions
</span>
</a>
<nav class="md-nav" aria-label="Architecture &amp; Naming Conventions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#system-architecture-overview" class="md-nav__link">
<span class="md-ellipsis">
System Architecture Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#critical-rpcd-script-naming" class="md-nav__link">
<span class="md-ellipsis">
CRITICAL: RPCD Script Naming
</span>
</a>
<nav class="md-nav" aria-label="CRITICAL: RPCD Script Naming">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#correct" class="md-nav__link">
<span class="md-ellipsis">
✅ CORRECT:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#incorrect-causes-derreur-32000" class="md-nav__link">
<span class="md-ellipsis">
❌ INCORRECT (Causes d'erreur -32000):
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#menu-path-conventions" class="md-nav__link">
<span class="md-ellipsis">
Menu Path Conventions
</span>
</a>
<nav class="md-nav" aria-label="Menu Path Conventions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#correct_1" class="md-nav__link">
<span class="md-ellipsis">
✅ CORRECT:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#incorrect-causes-404" class="md-nav__link">
<span class="md-ellipsis">
❌ INCORRECT (Causes 404):
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#prefixes-standards" class="md-nav__link">
<span class="md-ellipsis">
Prefixes Standards
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#file-structure-template" class="md-nav__link">
<span class="md-ellipsis">
File Structure Template
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#rpcd-ubus-best-practices" class="md-nav__link">
<span class="md-ellipsis">
RPCD &amp; ubus Best Practices
</span>
</a>
<nav class="md-nav" aria-label="RPCD &amp; ubus Best Practices">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#rpcd-script-template-shell" class="md-nav__link">
<span class="md-ellipsis">
RPCD Script Template (Shell)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#rpcd-script-validation" class="md-nav__link">
<span class="md-ellipsis">
RPCD Script Validation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#testing-rpcd-scripts" class="md-nav__link">
<span class="md-ellipsis">
Testing RPCD Scripts
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-rpcd-errors" class="md-nav__link">
<span class="md-ellipsis">
Common RPCD Errors
</span>
</a>
<nav class="md-nav" aria-label="Common RPCD Errors">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#error-object-not-found-32000" class="md-nav__link">
<span class="md-ellipsis">
Error: "Object not found" (-32000)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-method-not-found-32601" class="md-nav__link">
<span class="md-ellipsis">
Error: "Method not found" (-32601)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-invalid-json-returned" class="md-nav__link">
<span class="md-ellipsis">
Error: Invalid JSON returned
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#acl-permissions" class="md-nav__link">
<span class="md-ellipsis">
ACL &amp; Permissions
</span>
</a>
<nav class="md-nav" aria-label="ACL &amp; Permissions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#acl-file-template" class="md-nav__link">
<span class="md-ellipsis">
ACL File Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#acl-best-practices" class="md-nav__link">
<span class="md-ellipsis">
ACL Best Practices
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-acl-errors" class="md-nav__link">
<span class="md-ellipsis">
Common ACL Errors
</span>
</a>
<nav class="md-nav" aria-label="Common ACL Errors">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#error-access-denied" class="md-nav__link">
<span class="md-ellipsis">
Error: "Access denied"
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-uci-config-not-accessible" class="md-nav__link">
<span class="md-ellipsis">
Error: "UCI config not accessible"
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#javascript-patterns" class="md-nav__link">
<span class="md-ellipsis">
JavaScript Patterns
</span>
</a>
<nav class="md-nav" aria-label="JavaScript Patterns">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#api-module-template" class="md-nav__link">
<span class="md-ellipsis">
API Module Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#view-template" class="md-nav__link">
<span class="md-ellipsis">
View Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#event-handling-pattern" class="md-nav__link">
<span class="md-ellipsis">
Event Handling Pattern
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-javascript-errors" class="md-nav__link">
<span class="md-ellipsis">
Common JavaScript Errors
</span>
</a>
<nav class="md-nav" aria-label="Common JavaScript Errors">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#error-object-htmlbuttonelement-affiche" class="md-nav__link">
<span class="md-ellipsis">
Error: "[object HTMLButtonElement]" affiché
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-cannot-read-property-of-undefined" class="md-nav__link">
<span class="md-ellipsis">
Error: "Cannot read property of undefined"
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-poll-callback-failed" class="md-nav__link">
<span class="md-ellipsis">
Error: "poll callback failed"
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#cssstyling-standards" class="md-nav__link">
<span class="md-ellipsis">
CSS/Styling Standards
</span>
</a>
<nav class="md-nav" aria-label="CSS/Styling Standards">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#file-organization" class="md-nav__link">
<span class="md-ellipsis">
File Organization
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#css-file-template" class="md-nav__link">
<span class="md-ellipsis">
CSS File Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#css-best-practices" class="md-nav__link">
<span class="md-ellipsis">
CSS Best Practices
</span>
</a>
<nav class="md-nav" aria-label="CSS Best Practices">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-toujours-utiliser-les-variables-css" class="md-nav__link">
<span class="md-ellipsis">
1. TOUJOURS utiliser les variables CSS
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-prefix-classes-par-module" class="md-nav__link">
<span class="md-ellipsis">
2. Prefix classes par module
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-transitions-coherentes" class="md-nav__link">
<span class="md-ellipsis">
3. Transitions cohérentes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-responsive-breakpoints" class="md-nav__link">
<span class="md-ellipsis">
4. Responsive breakpoints
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-dark-mode-obligatoire" class="md-nav__link">
<span class="md-ellipsis">
5. Dark mode OBLIGATOIRE
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#z-index-scale" class="md-nav__link">
<span class="md-ellipsis">
Z-index Scale
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#common-errors-solutions" class="md-nav__link">
<span class="md-ellipsis">
Common Errors &amp; Solutions
</span>
</a>
<nav class="md-nav" aria-label="Common Errors &amp; Solutions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-rpcd-object-not-found-32000" class="md-nav__link">
<span class="md-ellipsis">
1. RPCD Object Not Found (-32000)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-view-not-found-404" class="md-nav__link">
<span class="md-ellipsis">
2. View Not Found (404)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-css-not-loading-403-forbidden" class="md-nav__link">
<span class="md-ellipsis">
3. CSS Not Loading (403 Forbidden)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-invalid-json-from-rpcd" class="md-nav__link">
<span class="md-ellipsis">
4. Invalid JSON from RPCD
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-browser-cache-issues" class="md-nav__link">
<span class="md-ellipsis">
5. Browser Cache Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#6-acl-access-denied" class="md-nav__link">
<span class="md-ellipsis">
6. ACL Access Denied
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#validation-checklist" class="md-nav__link">
<span class="md-ellipsis">
Validation Checklist
</span>
</a>
<nav class="md-nav" aria-label="Validation Checklist">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#pre-commit-checklist" class="md-nav__link">
<span class="md-ellipsis">
Pre-Commit Checklist
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pre-deploy-checklist" class="md-nav__link">
<span class="md-ellipsis">
Pre-Deploy Checklist
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#post-deploy-checklist" class="md-nav__link">
<span class="md-ellipsis">
Post-Deploy Checklist
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#deployment-procedures" class="md-nav__link">
<span class="md-ellipsis">
Deployment Procedures
</span>
</a>
<nav class="md-nav" aria-label="Deployment Procedures">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#deployment-workflow" class="md-nav__link">
<span class="md-ellipsis">
Deployment Workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pre-deployment-checks-critical" class="md-nav__link">
<span class="md-ellipsis">
⚠️ Pre-Deployment Checks (CRITICAL)
</span>
</a>
<nav class="md-nav" aria-label="⚠️ Pre-Deployment Checks (CRITICAL)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-verification-de-lespace-disque" class="md-nav__link">
<span class="md-ellipsis">
1. Vérification de l'Espace Disque
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-verification-des-permissions-critique-pour-eviter-erreurs-403" class="md-nav__link">
<span class="md-ellipsis">
2. Vérification des Permissions (Critique pour Éviter Erreurs 403)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-post-deployment-verification" class="md-nav__link">
<span class="md-ellipsis">
3. Post-Deployment Verification
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-common-deployment-errors" class="md-nav__link">
<span class="md-ellipsis">
4. Common Deployment Errors
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-emergency-disk-space-recovery" class="md-nav__link">
<span class="md-ellipsis">
5. Emergency Disk Space Recovery
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#standard-deployment-script-template" class="md-nav__link">
<span class="md-ellipsis">
Standard Deployment Script Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#rollback-procedure" class="md-nav__link">
<span class="md-ellipsis">
Rollback Procedure
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#version-control" class="md-nav__link">
<span class="md-ellipsis">
Version Control
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#quick-reference" class="md-nav__link">
<span class="md-ellipsis">
Quick Reference
</span>
</a>
<nav class="md-nav" aria-label="Quick Reference">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#essential-commands" class="md-nav__link">
<span class="md-ellipsis">
Essential Commands
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#css-classes-quick-reference" class="md-nav__link">
<span class="md-ellipsis">
CSS Classes Quick Reference
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#color-variables-quick-reference" class="md-nav__link">
<span class="md-ellipsis">
Color Variables Quick Reference
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#ai-assistant-context-files" class="md-nav__link">
<span class="md-ellipsis">
AI Assistant Context Files
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#conclusion" class="md-nav__link">
<span class="md-ellipsis">
Conclusion
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../code-templates/" class="md-nav__link">
<span class="md-ellipsis">
Code Templates
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../module-implementation-guide/" class="md-nav__link">
<span class="md-ellipsis">
Module Implementation
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_4" >
<label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
<span class="md-ellipsis">
Reference
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../claude/" class="md-nav__link">
<span class="md-ellipsis">
RPCD & Architecture
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../validation-guide/" class="md-nav__link">
<span class="md-ellipsis">
Validation Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../permissions-guide/" class="md-nav__link">
<span class="md-ellipsis">
Permissions Guide
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../luci-development-reference/" class="md-nav__link">
<span class="md-ellipsis">
LuCI Development
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../codex/" class="md-nav__link">
<span class="md-ellipsis">
Codex Manual
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_5" >
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
<span class="md-ellipsis">
Modules
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Modules
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../module-status/" class="md-nav__link">
<span class="md-ellipsis">
Module Status
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../feature-regeneration-prompts/" class="md-nav__link">
<span class="md-ellipsis">
Feature Prompts
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
<span class="md-ellipsis">
Tools & Roadmap
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Tools & Roadmap
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../todo-analyse/" class="md-nav__link">
<span class="md-ellipsis">
TODO Roadmap
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle md-toggle--indeterminate" type="checkbox" id="__nav_7" >
<label class="md-nav__link" for="__nav_7" id="__nav_7_label" tabindex="0">
<span class="md-ellipsis">
Archive
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_7_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_7">
<span class="md-nav__icon md-icon"></span>
Archive
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../archive/" class="md-nav__link">
<span class="md-ellipsis">
Archive Index
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../archive/build-issues/" class="md-nav__link">
<span class="md-ellipsis">
Build Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../archive/completion-report/" class="md-nav__link">
<span class="md-ellipsis">
Completion Report
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../archive/module-enable-disable-design/" class="md-nav__link">
<span class="md-ellipsis">
Module Enable/Disable
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#table-des-matieres" class="md-nav__link">
<span class="md-ellipsis">
Table des matières
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#design-system-ui-guidelines" class="md-nav__link">
<span class="md-ellipsis">
Design System &amp; UI Guidelines
</span>
</a>
<nav class="md-nav" aria-label="Design System &amp; UI Guidelines">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#color-palette-demo-inspired" class="md-nav__link">
<span class="md-ellipsis">
Color Palette (Demo-inspired)
</span>
</a>
<nav class="md-nav" aria-label="Color Palette (Demo-inspired)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#dark-mode-primary-recommended" class="md-nav__link">
<span class="md-ellipsis">
Dark Mode (Primary - Recommended)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#light-mode-secondary" class="md-nav__link">
<span class="md-ellipsis">
Light Mode (Secondary)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#typography" class="md-nav__link">
<span class="md-ellipsis">
Typography
</span>
</a>
<nav class="md-nav" aria-label="Typography">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#fonts-stack" class="md-nav__link">
<span class="md-ellipsis">
Fonts Stack
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#font-sizes" class="md-nav__link">
<span class="md-ellipsis">
Font Sizes
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#component-patterns" class="md-nav__link">
<span class="md-ellipsis">
Component Patterns
</span>
</a>
<nav class="md-nav" aria-label="Component Patterns">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#component-hierarchy" class="md-nav__link">
<span class="md-ellipsis">
Component Hierarchy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#1-page-header-standard" class="md-nav__link">
<span class="md-ellipsis">
1. Page Header (Standard)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-stats-badges" class="md-nav__link">
<span class="md-ellipsis">
2. Stats Badges
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-cards-avec-bordure-coloree" class="md-nav__link">
<span class="md-ellipsis">
3. Cards avec bordure colorée
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-buttons" class="md-nav__link">
<span class="md-ellipsis">
4. Buttons
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-filter-tabs" class="md-nav__link">
<span class="md-ellipsis">
5. Filter Tabs
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#grid-systems" class="md-nav__link">
<span class="md-ellipsis">
Grid Systems
</span>
</a>
<nav class="md-nav" aria-label="Grid Systems">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#stats-overview-compact" class="md-nav__link">
<span class="md-ellipsis">
Stats Overview (Compact)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#metric-cards-medium" class="md-nav__link">
<span class="md-ellipsis">
Metric Cards (Medium)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#info-cards-large" class="md-nav__link">
<span class="md-ellipsis">
Info Cards (Large)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#gradient-effects" class="md-nav__link">
<span class="md-ellipsis">
Gradient Effects
</span>
</a>
<nav class="md-nav" aria-label="Gradient Effects">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#gradient-text-titles" class="md-nav__link">
<span class="md-ellipsis">
Gradient Text (Titles)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#gradient-backgrounds-buttons-badges" class="md-nav__link">
<span class="md-ellipsis">
Gradient Backgrounds (Buttons, Badges)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#gradient-borders-top" class="md-nav__link">
<span class="md-ellipsis">
Gradient Borders (Top)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#animation-standards" class="md-nav__link">
<span class="md-ellipsis">
Animation Standards
</span>
</a>
<nav class="md-nav" aria-label="Animation Standards">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#hover-effects" class="md-nav__link">
<span class="md-ellipsis">
Hover Effects
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#shadow-progression" class="md-nav__link">
<span class="md-ellipsis">
Shadow Progression
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#architecture-naming-conventions" class="md-nav__link">
<span class="md-ellipsis">
Architecture &amp; Naming Conventions
</span>
</a>
<nav class="md-nav" aria-label="Architecture &amp; Naming Conventions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#system-architecture-overview" class="md-nav__link">
<span class="md-ellipsis">
System Architecture Overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#critical-rpcd-script-naming" class="md-nav__link">
<span class="md-ellipsis">
CRITICAL: RPCD Script Naming
</span>
</a>
<nav class="md-nav" aria-label="CRITICAL: RPCD Script Naming">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#correct" class="md-nav__link">
<span class="md-ellipsis">
✅ CORRECT:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#incorrect-causes-derreur-32000" class="md-nav__link">
<span class="md-ellipsis">
❌ INCORRECT (Causes d'erreur -32000):
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#menu-path-conventions" class="md-nav__link">
<span class="md-ellipsis">
Menu Path Conventions
</span>
</a>
<nav class="md-nav" aria-label="Menu Path Conventions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#correct_1" class="md-nav__link">
<span class="md-ellipsis">
✅ CORRECT:
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#incorrect-causes-404" class="md-nav__link">
<span class="md-ellipsis">
❌ INCORRECT (Causes 404):
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#prefixes-standards" class="md-nav__link">
<span class="md-ellipsis">
Prefixes Standards
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#file-structure-template" class="md-nav__link">
<span class="md-ellipsis">
File Structure Template
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#rpcd-ubus-best-practices" class="md-nav__link">
<span class="md-ellipsis">
RPCD &amp; ubus Best Practices
</span>
</a>
<nav class="md-nav" aria-label="RPCD &amp; ubus Best Practices">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#rpcd-script-template-shell" class="md-nav__link">
<span class="md-ellipsis">
RPCD Script Template (Shell)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#rpcd-script-validation" class="md-nav__link">
<span class="md-ellipsis">
RPCD Script Validation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#testing-rpcd-scripts" class="md-nav__link">
<span class="md-ellipsis">
Testing RPCD Scripts
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-rpcd-errors" class="md-nav__link">
<span class="md-ellipsis">
Common RPCD Errors
</span>
</a>
<nav class="md-nav" aria-label="Common RPCD Errors">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#error-object-not-found-32000" class="md-nav__link">
<span class="md-ellipsis">
Error: "Object not found" (-32000)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-method-not-found-32601" class="md-nav__link">
<span class="md-ellipsis">
Error: "Method not found" (-32601)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-invalid-json-returned" class="md-nav__link">
<span class="md-ellipsis">
Error: Invalid JSON returned
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#acl-permissions" class="md-nav__link">
<span class="md-ellipsis">
ACL &amp; Permissions
</span>
</a>
<nav class="md-nav" aria-label="ACL &amp; Permissions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#acl-file-template" class="md-nav__link">
<span class="md-ellipsis">
ACL File Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#acl-best-practices" class="md-nav__link">
<span class="md-ellipsis">
ACL Best Practices
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-acl-errors" class="md-nav__link">
<span class="md-ellipsis">
Common ACL Errors
</span>
</a>
<nav class="md-nav" aria-label="Common ACL Errors">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#error-access-denied" class="md-nav__link">
<span class="md-ellipsis">
Error: "Access denied"
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-uci-config-not-accessible" class="md-nav__link">
<span class="md-ellipsis">
Error: "UCI config not accessible"
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#javascript-patterns" class="md-nav__link">
<span class="md-ellipsis">
JavaScript Patterns
</span>
</a>
<nav class="md-nav" aria-label="JavaScript Patterns">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#api-module-template" class="md-nav__link">
<span class="md-ellipsis">
API Module Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#view-template" class="md-nav__link">
<span class="md-ellipsis">
View Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#event-handling-pattern" class="md-nav__link">
<span class="md-ellipsis">
Event Handling Pattern
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#common-javascript-errors" class="md-nav__link">
<span class="md-ellipsis">
Common JavaScript Errors
</span>
</a>
<nav class="md-nav" aria-label="Common JavaScript Errors">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#error-object-htmlbuttonelement-affiche" class="md-nav__link">
<span class="md-ellipsis">
Error: "[object HTMLButtonElement]" affiché
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-cannot-read-property-of-undefined" class="md-nav__link">
<span class="md-ellipsis">
Error: "Cannot read property of undefined"
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#error-poll-callback-failed" class="md-nav__link">
<span class="md-ellipsis">
Error: "poll callback failed"
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#cssstyling-standards" class="md-nav__link">
<span class="md-ellipsis">
CSS/Styling Standards
</span>
</a>
<nav class="md-nav" aria-label="CSS/Styling Standards">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#file-organization" class="md-nav__link">
<span class="md-ellipsis">
File Organization
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#css-file-template" class="md-nav__link">
<span class="md-ellipsis">
CSS File Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#css-best-practices" class="md-nav__link">
<span class="md-ellipsis">
CSS Best Practices
</span>
</a>
<nav class="md-nav" aria-label="CSS Best Practices">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-toujours-utiliser-les-variables-css" class="md-nav__link">
<span class="md-ellipsis">
1. TOUJOURS utiliser les variables CSS
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-prefix-classes-par-module" class="md-nav__link">
<span class="md-ellipsis">
2. Prefix classes par module
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-transitions-coherentes" class="md-nav__link">
<span class="md-ellipsis">
3. Transitions cohérentes
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-responsive-breakpoints" class="md-nav__link">
<span class="md-ellipsis">
4. Responsive breakpoints
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-dark-mode-obligatoire" class="md-nav__link">
<span class="md-ellipsis">
5. Dark mode OBLIGATOIRE
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#z-index-scale" class="md-nav__link">
<span class="md-ellipsis">
Z-index Scale
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#common-errors-solutions" class="md-nav__link">
<span class="md-ellipsis">
Common Errors &amp; Solutions
</span>
</a>
<nav class="md-nav" aria-label="Common Errors &amp; Solutions">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-rpcd-object-not-found-32000" class="md-nav__link">
<span class="md-ellipsis">
1. RPCD Object Not Found (-32000)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-view-not-found-404" class="md-nav__link">
<span class="md-ellipsis">
2. View Not Found (404)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-css-not-loading-403-forbidden" class="md-nav__link">
<span class="md-ellipsis">
3. CSS Not Loading (403 Forbidden)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-invalid-json-from-rpcd" class="md-nav__link">
<span class="md-ellipsis">
4. Invalid JSON from RPCD
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-browser-cache-issues" class="md-nav__link">
<span class="md-ellipsis">
5. Browser Cache Issues
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#6-acl-access-denied" class="md-nav__link">
<span class="md-ellipsis">
6. ACL Access Denied
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#validation-checklist" class="md-nav__link">
<span class="md-ellipsis">
Validation Checklist
</span>
</a>
<nav class="md-nav" aria-label="Validation Checklist">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#pre-commit-checklist" class="md-nav__link">
<span class="md-ellipsis">
Pre-Commit Checklist
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pre-deploy-checklist" class="md-nav__link">
<span class="md-ellipsis">
Pre-Deploy Checklist
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#post-deploy-checklist" class="md-nav__link">
<span class="md-ellipsis">
Post-Deploy Checklist
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#deployment-procedures" class="md-nav__link">
<span class="md-ellipsis">
Deployment Procedures
</span>
</a>
<nav class="md-nav" aria-label="Deployment Procedures">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#deployment-workflow" class="md-nav__link">
<span class="md-ellipsis">
Deployment Workflow
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#pre-deployment-checks-critical" class="md-nav__link">
<span class="md-ellipsis">
⚠️ Pre-Deployment Checks (CRITICAL)
</span>
</a>
<nav class="md-nav" aria-label="⚠️ Pre-Deployment Checks (CRITICAL)">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#1-verification-de-lespace-disque" class="md-nav__link">
<span class="md-ellipsis">
1. Vérification de l'Espace Disque
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#2-verification-des-permissions-critique-pour-eviter-erreurs-403" class="md-nav__link">
<span class="md-ellipsis">
2. Vérification des Permissions (Critique pour Éviter Erreurs 403)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#3-post-deployment-verification" class="md-nav__link">
<span class="md-ellipsis">
3. Post-Deployment Verification
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#4-common-deployment-errors" class="md-nav__link">
<span class="md-ellipsis">
4. Common Deployment Errors
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#5-emergency-disk-space-recovery" class="md-nav__link">
<span class="md-ellipsis">
5. Emergency Disk Space Recovery
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#standard-deployment-script-template" class="md-nav__link">
<span class="md-ellipsis">
Standard Deployment Script Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#rollback-procedure" class="md-nav__link">
<span class="md-ellipsis">
Rollback Procedure
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#version-control" class="md-nav__link">
<span class="md-ellipsis">
Version Control
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#quick-reference" class="md-nav__link">
<span class="md-ellipsis">
Quick Reference
</span>
</a>
<nav class="md-nav" aria-label="Quick Reference">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#essential-commands" class="md-nav__link">
<span class="md-ellipsis">
Essential Commands
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#css-classes-quick-reference" class="md-nav__link">
<span class="md-ellipsis">
CSS Classes Quick Reference
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#color-variables-quick-reference" class="md-nav__link">
<span class="md-ellipsis">
Color Variables Quick Reference
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#ai-assistant-context-files" class="md-nav__link">
<span class="md-ellipsis">
AI Assistant Context Files
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#conclusion" class="md-nav__link">
<span class="md-ellipsis">
Conclusion
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="secubox-system-hub-development-guidelines">SecuBox &amp; System Hub - Development Guidelines<a class="headerlink" href="#secubox-system-hub-development-guidelines" title="Permanent link">&para;</a></h1>
<p><strong>Version:</strong> 1.0.0<br />
<strong>Last Updated:</strong> 2025-12-28<br />
<strong>Status:</strong> Active<br />
<strong>Audience:</strong> Développeurs, IA assistants, mainteneurs</p>
<p>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.</p>
<hr />
<h2 id="table-des-matieres">Table des matières<a class="headerlink" href="#table-des-matieres" title="Permanent link">&para;</a></h2>
<ol>
<li><a href="#design-system-ui-guidelines">Design System &amp; UI Guidelines</a></li>
<li><a href="#architecture-naming-conventions">Architecture &amp; Naming Conventions</a></li>
<li><a href="#rpcd-ubus-best-practices">RPCD &amp; ubus Best Practices</a></li>
<li><a href="#acl-permissions">ACL &amp; Permissions</a></li>
<li><a href="#javascript-patterns">JavaScript Patterns</a></li>
<li><a href="#cssstyling-standards">CSS/Styling Standards</a></li>
<li><a href="#common-errors-solutions">Common Errors &amp; Solutions</a></li>
<li><a href="#validation-checklist">Validation Checklist</a></li>
<li><a href="#deployment-procedures">Deployment Procedures</a></li>
<li><a href="#ai-assistant-context-files">AI Assistant Context Files</a></li>
</ol>
<hr />
<h2 id="design-system-ui-guidelines">Design System &amp; UI Guidelines<a class="headerlink" href="#design-system-ui-guidelines" title="Permanent link">&para;</a></h2>
<h3 id="color-palette-demo-inspired">Color Palette (Demo-inspired)<a class="headerlink" href="#color-palette-demo-inspired" title="Permanent link">&para;</a></h3>
<p><strong>IMPORTANT:</strong> Toujours utiliser la palette définie dans <code>system-hub/common.css</code></p>
<h4 id="dark-mode-primary-recommended">Dark Mode (Primary - Recommended)<a class="headerlink" href="#dark-mode-primary-recommended" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="nt">--sh-text-primary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">fafafa</span><span class="o">;</span>
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="nt">--sh-text-secondary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">a0a0b0</span><span class="o">;</span>
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="nt">--sh-bg-primary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">0a0a0f</span><span class="o">;</span><span class="w"> </span><span class="c">/* Fond principal (noir profond) */</span>
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="nt">--sh-bg-secondary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">12121a</span><span class="o">;</span><span class="w"> </span><span class="c">/* Fond cartes/sections */</span>
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="nt">--sh-bg-tertiary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">1a1a24</span><span class="o">;</span><span class="w"> </span><span class="c">/* Fond hover/actif */</span>
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="nt">--sh-bg-card</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">12121a</span><span class="o">;</span>
<a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="nt">--sh-border</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">2a2a35</span><span class="o">;</span>
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a><span class="nt">--sh-primary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">6366f1</span><span class="o">;</span><span class="w"> </span><span class="c">/* Indigo */</span>
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a><span class="nt">--sh-primary-end</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">8b5cf6</span><span class="o">;</span><span class="w"> </span><span class="c">/* Violet (pour dégradés) */</span>
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a><span class="nt">--sh-success</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">22c55e</span><span class="o">;</span><span class="w"> </span><span class="c">/* Vert */</span>
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a><span class="nt">--sh-danger</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">ef4444</span><span class="o">;</span><span class="w"> </span><span class="c">/* Rouge */</span>
<a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a><span class="nt">--sh-warning</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">f59e0b</span><span class="o">;</span><span class="w"> </span><span class="c">/* Orange */</span>
</code></pre></div>
<h4 id="light-mode-secondary">Light Mode (Secondary)<a class="headerlink" href="#light-mode-secondary" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="nt">--sh-text-primary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">0f172a</span><span class="o">;</span>
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a><span class="nt">--sh-text-secondary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">475569</span><span class="o">;</span>
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="nt">--sh-bg-primary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">ffffff</span><span class="o">;</span>
<a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="nt">--sh-bg-secondary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">f8fafc</span><span class="o">;</span>
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a><span class="nt">--sh-bg-tertiary</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">f1f5f9</span><span class="o">;</span>
<a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="nt">--sh-bg-card</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">ffffff</span><span class="o">;</span>
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a><span class="nt">--sh-border</span><span class="o">:</span><span class="w"> </span><span class="p">#</span><span class="nn">e2e8f0</span><span class="o">;</span>
</code></pre></div>
<p><strong>✅ TOUJOURS utiliser les CSS variables</strong> - Ne JAMAIS hardcoder les couleurs.</p>
<h3 id="typography">Typography<a class="headerlink" href="#typography" title="Permanent link">&para;</a></h3>
<h4 id="fonts-stack">Fonts Stack<a class="headerlink" href="#fonts-stack" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="c">/* Texte général */</span>
<a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="nt">font-family</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;Inter&#39;</span><span class="o">,</span><span class="w"> </span><span class="nt">-apple-system</span><span class="o">,</span><span class="w"> </span><span class="nt">BlinkMacSystemFont</span><span class="o">,</span><span class="w"> </span><span class="nt">sans-serif</span><span class="o">;</span>
<a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a>
<a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a><span class="c">/* Valeurs numériques, IDs, code */</span>
<a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="nt">font-family</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;JetBrains Mono&#39;</span><span class="o">,</span><span class="w"> </span><span class="s1">&#39;Courier New&#39;</span><span class="o">,</span><span class="w"> </span><span class="nt">monospace</span><span class="o">;</span>
</code></pre></div>
<p><strong>Import requis</strong> (ajouté dans common.css):
<div class="highlight"><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="p">@</span><span class="k">import</span><span class="w"> </span><span class="nt">url</span><span class="o">(</span><span class="s1">&#39;https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&amp;family=Inter:wght@400;500;600;700&amp;display=swap&#39;</span><span class="o">)</span><span class="p">;</span>
</code></pre></div></p>
<h4 id="font-sizes">Font Sizes<a class="headerlink" href="#font-sizes" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="c">/* Titres */</span>
<a id="__codelineno-4-2" name="__codelineno-4-2" href="#__codelineno-4-2"></a><span class="nt">--sh-title-xl</span><span class="o">:</span><span class="w"> </span><span class="nt">28px</span><span class="o">;</span><span class="w"> </span><span class="c">/* Page titles */</span>
<a id="__codelineno-4-3" name="__codelineno-4-3" href="#__codelineno-4-3"></a><span class="nt">--sh-title-lg</span><span class="o">:</span><span class="w"> </span><span class="nt">20px</span><span class="o">;</span><span class="w"> </span><span class="c">/* Card titles */</span>
<a id="__codelineno-4-4" name="__codelineno-4-4" href="#__codelineno-4-4"></a><span class="nt">--sh-title-md</span><span class="o">:</span><span class="w"> </span><span class="nt">16px</span><span class="o">;</span><span class="w"> </span><span class="c">/* Section headers */</span>
<a id="__codelineno-4-5" name="__codelineno-4-5" href="#__codelineno-4-5"></a>
<a id="__codelineno-4-6" name="__codelineno-4-6" href="#__codelineno-4-6"></a><span class="c">/* Texte */</span>
<a id="__codelineno-4-7" name="__codelineno-4-7" href="#__codelineno-4-7"></a><span class="nt">--sh-text-base</span><span class="o">:</span><span class="w"> </span><span class="nt">14px</span><span class="o">;</span><span class="w"> </span><span class="c">/* Body text */</span>
<a id="__codelineno-4-8" name="__codelineno-4-8" href="#__codelineno-4-8"></a><span class="nt">--sh-text-sm</span><span class="o">:</span><span class="w"> </span><span class="nt">13px</span><span class="o">;</span><span class="w"> </span><span class="c">/* Labels, meta */</span>
<a id="__codelineno-4-9" name="__codelineno-4-9" href="#__codelineno-4-9"></a><span class="nt">--sh-text-xs</span><span class="o">:</span><span class="w"> </span><span class="nt">11px</span><span class="o">;</span><span class="w"> </span><span class="c">/* Uppercase labels */</span>
<a id="__codelineno-4-10" name="__codelineno-4-10" href="#__codelineno-4-10"></a>
<a id="__codelineno-4-11" name="__codelineno-4-11" href="#__codelineno-4-11"></a><span class="c">/* Valeurs */</span>
<a id="__codelineno-4-12" name="__codelineno-4-12" href="#__codelineno-4-12"></a><span class="nt">--sh-value-xl</span><span class="o">:</span><span class="w"> </span><span class="nt">40px</span><span class="o">;</span><span class="w"> </span><span class="c">/* Large metrics */</span>
<a id="__codelineno-4-13" name="__codelineno-4-13" href="#__codelineno-4-13"></a><span class="nt">--sh-value-lg</span><span class="o">:</span><span class="w"> </span><span class="nt">32px</span><span class="o">;</span><span class="w"> </span><span class="c">/* Stats overview */</span>
<a id="__codelineno-4-14" name="__codelineno-4-14" href="#__codelineno-4-14"></a><span class="nt">--sh-value-md</span><span class="o">:</span><span class="w"> </span><span class="nt">28px</span><span class="o">;</span><span class="w"> </span><span class="c">/* Badges */</span>
</code></pre></div>
<h3 id="component-patterns">Component Patterns<a class="headerlink" href="#component-patterns" title="Permanent link">&para;</a></h3>
<h4 id="component-hierarchy">Component Hierarchy<a class="headerlink" href="#component-hierarchy" title="Permanent link">&para;</a></h4>
<p>The following diagram shows the standard page structure and component relationships:</p>
<pre class="mermaid"><code>graph TB
PAGE[Page Container&lt;br/&gt;.module-dashboard] --&gt; HEADER[sh-page-header]
PAGE --&gt; CONTENT[sh-content]
HEADER --&gt; TITLE_SECTION[Title Section&lt;br/&gt;div]
HEADER --&gt; STATS[sh-stats-grid]
TITLE_SECTION --&gt; TITLE[sh-page-title&lt;br/&gt;gradient text]
TITLE_SECTION --&gt; SUBTITLE[sh-page-subtitle]
STATS --&gt; BADGE1[sh-stat-badge]
STATS --&gt; BADGE2[sh-stat-badge]
STATS --&gt; BADGE3[...]
BADGE1 --&gt; VALUE1[sh-stat-value&lt;br/&gt;monospace font]
BADGE1 --&gt; LABEL1[sh-stat-label&lt;br/&gt;uppercase]
CONTENT --&gt; TABS[sh-filter-tabs]
CONTENT --&gt; CARD_GRID[Card Grid&lt;br/&gt;grid layout]
TABS --&gt; TAB1[sh-filter-tab&lt;br/&gt;active]
TABS --&gt; TAB2[sh-filter-tab]
CARD_GRID --&gt; CARD1[sh-card]
CARD_GRID --&gt; CARD2[sh-card-success]
CARD_GRID --&gt; CARD3[sh-card-danger]
CARD1 --&gt; CH1[sh-card-header]
CARD1 --&gt; CB1[sh-card-body]
CH1 --&gt; CT1[sh-card-title]
CT1 --&gt; ICON1[sh-card-title-icon]
CB1 --&gt; BUTTONS[Button Group]
CB1 --&gt; INFO[Info Rows]
BUTTONS --&gt; BTN1[sh-btn&lt;br/&gt;sh-btn-primary]
BUTTONS --&gt; BTN2[sh-btn&lt;br/&gt;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</code></pre>
<p><strong>Component Categories:</strong>
1. <strong>Layout Containers:</strong> Page wrapper, header, content sections
2. <strong>Typography:</strong> Titles with gradient effects, subtitles, labels
3. <strong>Data Display:</strong> Stat badges with monospace values, cards with borders
4. <strong>Navigation:</strong> Filter tabs, nav tabs (sticky)
5. <strong>Interactive:</strong> Buttons with gradients and hover effects</p>
<p><strong>Styling Rules:</strong>
- <strong>Cards:</strong> 3px top border (gradient on hover, or colored for status)
- <strong>Stat Badges:</strong> Minimum 130px width, monospace font for values
- <strong>Buttons:</strong> Gradient backgrounds, shadow on hover, smooth transitions
- <strong>Tabs:</strong> Active state with gradient background and glow
- <strong>Grid Layouts:</strong> Auto-fit with minimums (130px, 240px, or 300px)</p>
<hr />
<h4 id="1-page-header-standard">1. Page Header (Standard)<a class="headerlink" href="#1-page-header-standard" title="Permanent link">&para;</a></h4>
<p><strong>REQUIREMENT:</strong> Every module view MUST begin with this compact <code>.sh-page-header</code>. 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 <code>.sh-stats-grid</code> for future metrics.</p>
<p><strong>Slim variant:</strong> When the page only needs 23 metrics, use <code>.sh-page-header-lite</code> + <code>.sh-header-chip</code> (see <code>luci-app-vhost-manager</code> and <code>luci-app-secubox</code> settings). Chips carry an emoji/icon, a tiny label, and the value; colors (<code>.success</code>, <code>.danger</code>, <code>.warn</code>) communicate state. This variant replaces the bulky hero blocks from older demos.</p>
<p><strong>Version chip:</strong> Always expose the package version from the RPC backend (read from <code>/usr/lib/opkg/info/&lt;pkg&gt;.control</code>) and display it as the first chip (<code>icon: 🏷️</code>). That keeps the UI and <code>PKG_VERSION</code> in sync without hunting for hard-coded strings.</p>
<p><strong>HTML Structure:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-page-header&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-5-2" name="__codelineno-5-2" href="#__codelineno-5-2"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-5-3" name="__codelineno-5-3" href="#__codelineno-5-3"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;h2&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-page-title&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-5-4" name="__codelineno-5-4" href="#__codelineno-5-4"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;span&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-page-title-icon&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;🎯&#39;</span><span class="p">),</span>
<a id="__codelineno-5-5" name="__codelineno-5-5" href="#__codelineno-5-5"></a><span class="w"> </span><span class="s1">&#39;Page Title&#39;</span>
<a id="__codelineno-5-6" name="__codelineno-5-6" href="#__codelineno-5-6"></a><span class="w"> </span><span class="p">]),</span>
<a id="__codelineno-5-7" name="__codelineno-5-7" href="#__codelineno-5-7"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;p&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-page-subtitle&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;Description of the page&#39;</span><span class="p">)</span>
<a id="__codelineno-5-8" name="__codelineno-5-8" href="#__codelineno-5-8"></a><span class="w"> </span><span class="p">]),</span>
<a id="__codelineno-5-9" name="__codelineno-5-9" href="#__codelineno-5-9"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-stats-grid&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-5-10" name="__codelineno-5-10" href="#__codelineno-5-10"></a><span class="w"> </span><span class="c1">// Stats badges here</span>
<a id="__codelineno-5-11" name="__codelineno-5-11" href="#__codelineno-5-11"></a><span class="w"> </span><span class="p">])</span>
<a id="__codelineno-5-12" name="__codelineno-5-12" href="#__codelineno-5-12"></a><span class="p">])</span>
</code></pre></div></p>
<p><strong>CSS Classes:</strong>
- <code>.sh-page-header</code> - Container with flex layout
- <code>.sh-page-title</code> - Gradient text effect
- <code>.sh-page-title-icon</code> - Icon (no gradient)
- <code>.sh-page-subtitle</code> - Secondary text
- <code>.sh-stats-grid</code> - Grid pour badges (130px min)</p>
<h4 id="2-stats-badges">2. Stats Badges<a class="headerlink" href="#2-stats-badges" title="Permanent link">&para;</a></h4>
<p><strong>RÈGLE:</strong> Minimum 130px, police monospace pour valeurs</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-stat-badge&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-stat-value&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;92&#39;</span><span class="p">),</span>
<a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-stat-label&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;CPU %&#39;</span><span class="p">)</span>
<a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a><span class="p">])</span>
</code></pre></div>
<p><strong>Grid Layout:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a><span class="p">.</span><span class="nc">sh-stats-grid</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-7-2" name="__codelineno-7-2" href="#__codelineno-7-2"></a><span class="w"> </span><span class="k">display</span><span class="p">:</span><span class="w"> </span><span class="k">grid</span><span class="p">;</span>
<a id="__codelineno-7-3" name="__codelineno-7-3" href="#__codelineno-7-3"></a><span class="w"> </span><span class="k">grid-template-columns</span><span class="p">:</span><span class="w"> </span><span class="nf">repeat</span><span class="p">(</span><span class="kc">auto</span><span class="nv">-fit</span><span class="p">,</span><span class="w"> </span><span class="nf">minmax</span><span class="p">(</span><span class="mi">130</span><span class="kt">px</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="n">fr</span><span class="p">));</span>
<a id="__codelineno-7-4" name="__codelineno-7-4" href="#__codelineno-7-4"></a><span class="w"> </span><span class="k">gap</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="kt">px</span><span class="p">;</span>
<a id="__codelineno-7-5" name="__codelineno-7-5" href="#__codelineno-7-5"></a><span class="p">}</span>
</code></pre></div></p>
<h4 id="3-cards-avec-bordure-coloree">3. Cards avec bordure colorée<a class="headerlink" href="#3-cards-avec-bordure-coloree" title="Permanent link">&para;</a></h4>
<p><strong>OBLIGATOIRE:</strong> Toutes les cards doivent avoir une bordure top de 3px</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-card sh-card-success&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-8-2" name="__codelineno-8-2" href="#__codelineno-8-2"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-card-header&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-8-3" name="__codelineno-8-3" href="#__codelineno-8-3"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;h3&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-card-title&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-8-4" name="__codelineno-8-4" href="#__codelineno-8-4"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;span&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-card-title-icon&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;⚙️&#39;</span><span class="p">),</span>
<a id="__codelineno-8-5" name="__codelineno-8-5" href="#__codelineno-8-5"></a><span class="w"> </span><span class="s1">&#39;Card Title&#39;</span>
<a id="__codelineno-8-6" name="__codelineno-8-6" href="#__codelineno-8-6"></a><span class="w"> </span><span class="p">])</span>
<a id="__codelineno-8-7" name="__codelineno-8-7" href="#__codelineno-8-7"></a><span class="w"> </span><span class="p">]),</span>
<a id="__codelineno-8-8" name="__codelineno-8-8" href="#__codelineno-8-8"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-card-body&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-8-9" name="__codelineno-8-9" href="#__codelineno-8-9"></a><span class="w"> </span><span class="c1">// Content</span>
<a id="__codelineno-8-10" name="__codelineno-8-10" href="#__codelineno-8-10"></a><span class="w"> </span><span class="p">])</span>
<a id="__codelineno-8-11" name="__codelineno-8-11" href="#__codelineno-8-11"></a><span class="p">])</span>
</code></pre></div>
<p><strong>Variants de bordure:</strong>
- <code>.sh-card</code> - Bordure gradient (visible au hover)
- <code>.sh-card-success</code> - Bordure verte permanente
- <code>.sh-card-danger</code> - Bordure rouge permanente
- <code>.sh-card-warning</code> - Bordure orange permanente</p>
<h4 id="4-buttons">4. Buttons<a class="headerlink" href="#4-buttons" title="Permanent link">&para;</a></h4>
<p><strong>Gradient buttons (preferred):</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;button&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-btn sh-btn-primary&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;Primary Action&#39;</span><span class="p">)</span>
<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;button&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-btn sh-btn-success&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;Success Action&#39;</span><span class="p">)</span>
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;button&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-btn sh-btn-danger&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;Danger Action&#39;</span><span class="p">)</span>
<a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;button&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-btn sh-btn-secondary&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;Secondary Action&#39;</span><span class="p">)</span>
</code></pre></div></p>
<p><strong>Tous les buttons doivent avoir:</strong>
- Shadow effect (déjà dans CSS)
- Hover animation (translateY(-2px))
- Transition smooth (0.3s cubic-bezier)</p>
<h4 id="5-filter-tabs">5. Filter Tabs<a class="headerlink" href="#5-filter-tabs" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-filter-tabs&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-filter-tab active&#39;</span><span class="p">,</span>
<a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="w"> </span><span class="s1">&#39;data-filter&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;all&#39;</span>
<a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;span&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-tab-icon&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;📋&#39;</span><span class="p">),</span>
<a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;span&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-tab-label&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;All&#39;</span><span class="p">)</span>
<a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="w"> </span><span class="p">])</span>
<a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a><span class="p">])</span>
</code></pre></div>
<p><strong>Active tab styling:</strong>
- Background: gradient indigo-violet
- Color: white
- Box-shadow avec glow</p>
<h3 id="grid-systems">Grid Systems<a class="headerlink" href="#grid-systems" title="Permanent link">&para;</a></h3>
<h4 id="stats-overview-compact">Stats Overview (Compact)<a class="headerlink" href="#stats-overview-compact" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a><span class="nt">grid-template-columns</span><span class="o">:</span><span class="w"> </span><span class="nt">repeat</span><span class="o">(</span><span class="nt">auto-fit</span><span class="o">,</span><span class="w"> </span><span class="nt">minmax</span><span class="o">(</span><span class="nt">130px</span><span class="o">,</span><span class="w"> </span><span class="nt">1fr</span><span class="o">));</span>
<a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a><span class="nt">gap</span><span class="o">:</span><span class="w"> </span><span class="nt">16px</span><span class="o">;</span>
</code></pre></div>
<h4 id="metric-cards-medium">Metric Cards (Medium)<a class="headerlink" href="#metric-cards-medium" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a><span class="nt">grid-template-columns</span><span class="o">:</span><span class="w"> </span><span class="nt">repeat</span><span class="o">(</span><span class="nt">auto-fit</span><span class="o">,</span><span class="w"> </span><span class="nt">minmax</span><span class="o">(</span><span class="nt">240px</span><span class="o">,</span><span class="w"> </span><span class="nt">1fr</span><span class="o">));</span>
<a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a><span class="nt">gap</span><span class="o">:</span><span class="w"> </span><span class="nt">20px</span><span class="o">;</span>
</code></pre></div>
<h4 id="info-cards-large">Info Cards (Large)<a class="headerlink" href="#info-cards-large" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="nt">grid-template-columns</span><span class="o">:</span><span class="w"> </span><span class="nt">repeat</span><span class="o">(</span><span class="nt">auto-fit</span><span class="o">,</span><span class="w"> </span><span class="nt">minmax</span><span class="o">(</span><span class="nt">300px</span><span class="o">,</span><span class="w"> </span><span class="nt">1fr</span><span class="o">));</span>
<a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a><span class="nt">gap</span><span class="o">:</span><span class="w"> </span><span class="nt">20px</span><span class="o">;</span>
</code></pre></div>
<h3 id="gradient-effects">Gradient Effects<a class="headerlink" href="#gradient-effects" title="Permanent link">&para;</a></h3>
<h4 id="gradient-text-titles">Gradient Text (Titles)<a class="headerlink" href="#gradient-text-titles" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a><span class="nt">background</span><span class="o">:</span><span class="w"> </span><span class="nt">linear-gradient</span><span class="o">(</span><span class="nt">135deg</span><span class="o">,</span><span class="w"> </span><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-primary</span><span class="o">),</span><span class="w"> </span><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-primary-end</span><span class="o">));</span>
<a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a><span class="nt">-webkit-background-clip</span><span class="o">:</span><span class="w"> </span><span class="nt">text</span><span class="o">;</span>
<a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a><span class="nt">-webkit-text-fill-color</span><span class="o">:</span><span class="w"> </span><span class="nt">transparent</span><span class="o">;</span>
<a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a><span class="nt">background-clip</span><span class="o">:</span><span class="w"> </span><span class="nt">text</span><span class="o">;</span>
</code></pre></div>
<p><strong>Utiliser:</strong> <code>.sh-gradient-text</code> class ou <code>.sh-page-title</code></p>
<h4 id="gradient-backgrounds-buttons-badges">Gradient Backgrounds (Buttons, Badges)<a class="headerlink" href="#gradient-backgrounds-buttons-badges" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="nt">background</span><span class="o">:</span><span class="w"> </span><span class="nt">linear-gradient</span><span class="o">(</span><span class="nt">135deg</span><span class="o">,</span><span class="w"> </span><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-primary</span><span class="o">),</span><span class="w"> </span><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-primary-end</span><span class="o">));</span>
</code></pre></div>
<h4 id="gradient-borders-top">Gradient Borders (Top)<a class="headerlink" href="#gradient-borders-top" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a><span class="c">/* 3px top border avec dégradé */</span>
<a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a><span class="p">.</span><span class="nc">element</span><span class="p">::</span><span class="nd">before</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a><span class="w"> </span><span class="k">content</span><span class="p">:</span><span class="w"> </span><span class="s1">&#39;&#39;</span><span class="p">;</span>
<a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a><span class="w"> </span><span class="k">position</span><span class="p">:</span><span class="w"> </span><span class="kc">absolute</span><span class="p">;</span>
<a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a><span class="w"> </span><span class="k">top</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<a id="__codelineno-16-6" name="__codelineno-16-6" href="#__codelineno-16-6"></a><span class="w"> </span><span class="k">left</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<a id="__codelineno-16-7" name="__codelineno-16-7" href="#__codelineno-16-7"></a><span class="w"> </span><span class="k">right</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<a id="__codelineno-16-8" name="__codelineno-16-8" href="#__codelineno-16-8"></a><span class="w"> </span><span class="k">height</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="kt">px</span><span class="p">;</span>
<a id="__codelineno-16-9" name="__codelineno-16-9" href="#__codelineno-16-9"></a><span class="w"> </span><span class="k">background</span><span class="p">:</span><span class="w"> </span><span class="nb">linear-gradient</span><span class="p">(</span><span class="mi">90</span><span class="kt">deg</span><span class="p">,</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--sh-primary</span><span class="p">),</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--sh-primary-end</span><span class="p">));</span>
<a id="__codelineno-16-10" name="__codelineno-16-10" href="#__codelineno-16-10"></a><span class="p">}</span>
</code></pre></div>
<h3 id="animation-standards">Animation Standards<a class="headerlink" href="#animation-standards" title="Permanent link">&para;</a></h3>
<h4 id="hover-effects">Hover Effects<a class="headerlink" href="#hover-effects" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="nt">transition</span><span class="o">:</span><span class="w"> </span><span class="nt">all</span><span class="w"> </span><span class="nt">0</span><span class="p">.</span><span class="nc">3s</span><span class="w"> </span><span class="nt">cubic-bezier</span><span class="o">(</span><span class="nt">0</span><span class="p">.</span><span class="nc">4</span><span class="o">,</span><span class="w"> </span><span class="nt">0</span><span class="o">,</span><span class="w"> </span><span class="nt">0</span><span class="p">.</span><span class="nc">2</span><span class="o">,</span><span class="w"> </span><span class="nt">1</span><span class="o">);</span>
<a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a><span class="nt">transform</span><span class="o">:</span><span class="w"> </span><span class="nt">translateY</span><span class="o">(</span><span class="nt">-3px</span><span class="o">);</span><span class="w"> </span><span class="c">/* Cards */</span>
<a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a><span class="nt">transform</span><span class="o">:</span><span class="w"> </span><span class="nt">translateY</span><span class="o">(</span><span class="nt">-2px</span><span class="o">);</span><span class="w"> </span><span class="c">/* Buttons, badges */</span>
</code></pre></div>
<h4 id="shadow-progression">Shadow Progression<a class="headerlink" href="#shadow-progression" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a><span class="c">/* Default */</span>
<a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a><span class="nt">box-shadow</span><span class="o">:</span><span class="w"> </span><span class="nt">none</span><span class="o">;</span>
<a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a>
<a id="__codelineno-18-4" name="__codelineno-18-4" href="#__codelineno-18-4"></a><span class="c">/* Hover - Subtle */</span>
<a id="__codelineno-18-5" name="__codelineno-18-5" href="#__codelineno-18-5"></a><span class="nt">box-shadow</span><span class="o">:</span><span class="w"> </span><span class="nt">0</span><span class="w"> </span><span class="nt">8px</span><span class="w"> </span><span class="nt">20px</span><span class="w"> </span><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-shadow</span><span class="o">);</span>
<a id="__codelineno-18-6" name="__codelineno-18-6" href="#__codelineno-18-6"></a>
<a id="__codelineno-18-7" name="__codelineno-18-7" href="#__codelineno-18-7"></a><span class="c">/* Hover - Pronounced */</span>
<a id="__codelineno-18-8" name="__codelineno-18-8" href="#__codelineno-18-8"></a><span class="nt">box-shadow</span><span class="o">:</span><span class="w"> </span><span class="nt">0</span><span class="w"> </span><span class="nt">12px</span><span class="w"> </span><span class="nt">28px</span><span class="w"> </span><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-hover-shadow</span><span class="o">);</span>
<a id="__codelineno-18-9" name="__codelineno-18-9" href="#__codelineno-18-9"></a>
<a id="__codelineno-18-10" name="__codelineno-18-10" href="#__codelineno-18-10"></a><span class="c">/* Button Hover */</span>
<a id="__codelineno-18-11" name="__codelineno-18-11" href="#__codelineno-18-11"></a><span class="nt">box-shadow</span><span class="o">:</span><span class="w"> </span><span class="nt">0</span><span class="w"> </span><span class="nt">8px</span><span class="w"> </span><span class="nt">20px</span><span class="w"> </span><span class="nt">rgba</span><span class="o">(</span><span class="nt">99</span><span class="o">,</span><span class="w"> </span><span class="nt">102</span><span class="o">,</span><span class="w"> </span><span class="nt">241</span><span class="o">,</span><span class="w"> </span><span class="nt">0</span><span class="p">.</span><span class="nc">5</span><span class="o">);</span>
</code></pre></div>
<hr />
<h2 id="architecture-naming-conventions">Architecture &amp; Naming Conventions<a class="headerlink" href="#architecture-naming-conventions" title="Permanent link">&para;</a></h2>
<h3 id="system-architecture-overview">System Architecture Overview<a class="headerlink" href="#system-architecture-overview" title="Permanent link">&para;</a></h3>
<p>The following diagram illustrates the complete data flow from browser JavaScript to system backend:</p>
<pre class="mermaid"><code>graph TB
subgraph "Browser"
UI[JavaScript View&lt;br/&gt;view/module/overview.js]
API[API Module&lt;br/&gt;module/api.js]
end
subgraph "LuCI Framework"
RPC[RPC Layer&lt;br/&gt;L.rpc.declare]
UHTTPD[uhttpd&lt;br/&gt;Web Server]
end
subgraph "Backend Services"
RPCD[RPCD Daemon]
SCRIPT[RPCD Script&lt;br/&gt;/usr/libexec/rpcd/luci.module-name]
UBUS[ubus Message Bus]
end
subgraph "System Layer"
UCI[UCI Configuration]
SYS[System Services&lt;br/&gt;init.d scripts]
FS[Filesystem&lt;br/&gt;proc, sys, etc]
end
UI --&gt;|"API.getStatus()"| API
API --&gt;|"rpc.declare({ object: 'luci.module' })"| RPC
RPC --&gt;|"HTTP POST /ubus"| UHTTPD
UHTTPD --&gt;|"call method"| RPCD
RPCD --&gt;|"execute script"| SCRIPT
SCRIPT --&gt;|"ubus call"| UBUS
UBUS --&gt;|"read/write"| UCI
UBUS --&gt;|"control"| SYS
SCRIPT --&gt;|"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</code></pre>
<p><strong>Key Components:</strong>
1. <strong>Browser Layer:</strong> JavaScript views and API modules handle UI and data requests
2. <strong>LuCI Framework:</strong> RPC layer translates JavaScript calls to ubus protocol
3. <strong>Backend Services:</strong> RPCD executes shell scripts via ubus message bus
4. <strong>System Layer:</strong> UCI configs, system services, and filesystem provide data</p>
<p><strong>Critical Naming Rule:</strong> The RPCD script name <strong>MUST</strong> match the <code>object</code> parameter in JavaScript's <code>rpc.declare()</code>.</p>
<hr />
<h3 id="critical-rpcd-script-naming">CRITICAL: RPCD Script Naming<a class="headerlink" href="#critical-rpcd-script-naming" title="Permanent link">&para;</a></h3>
<p><strong>RÈGLE ABSOLUE:</strong> Le nom du fichier RPCD DOIT correspondre EXACTEMENT au nom de l'objet ubus dans JavaScript.</p>
<h4 id="correct">✅ CORRECT:<a class="headerlink" href="#correct" title="Permanent link">&para;</a></h4>
<p><strong>JavaScript:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="kd">var</span><span class="w"> </span><span class="nx">callStatus</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">rpc</span><span class="p">.</span><span class="nx">declare</span><span class="p">({</span>
<a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a><span class="w"> </span><span class="nx">object</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;luci.system-hub&#39;</span><span class="p">,</span><span class="w"> </span><span class="c1">// ← Nom objet</span>
<a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a><span class="w"> </span><span class="nx">method</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;getHealth&#39;</span>
<a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a><span class="p">});</span>
</code></pre></div></p>
<p><strong>Fichier RPCD:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a>root/usr/libexec/rpcd/luci.system-hub<span class="w"> </span><span class="c1"># ← EXACT MATCH</span>
</code></pre></div></p>
<h4 id="incorrect-causes-derreur-32000">❌ INCORRECT (Causes d'erreur -32000):<a class="headerlink" href="#incorrect-causes-derreur-32000" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="c1"># Mauvais - manque le préfixe</span>
<a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a>root/usr/libexec/rpcd/system-hub
<a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a>
<a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a><span class="c1"># Mauvais - underscore au lieu de tiret</span>
<a id="__codelineno-21-5" name="__codelineno-21-5" href="#__codelineno-21-5"></a>root/usr/libexec/rpcd/luci.system_hub
<a id="__codelineno-21-6" name="__codelineno-21-6" href="#__codelineno-21-6"></a>
<a id="__codelineno-21-7" name="__codelineno-21-7" href="#__codelineno-21-7"></a><span class="c1"># Mauvais - nom différent</span>
<a id="__codelineno-21-8" name="__codelineno-21-8" href="#__codelineno-21-8"></a>root/usr/libexec/rpcd/systemhub
</code></pre></div>
<h3 id="menu-path-conventions">Menu Path Conventions<a class="headerlink" href="#menu-path-conventions" title="Permanent link">&para;</a></h3>
<p><strong>RÈGLE:</strong> Les chemins dans menu.d/*.json doivent correspondre EXACTEMENT aux fichiers de vue.</p>
<h4 id="correct_1">✅ CORRECT:<a class="headerlink" href="#correct_1" title="Permanent link">&para;</a></h4>
<p><strong>Menu JSON:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><span class="p">{</span>
<a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a><span class="w"> </span><span class="nt">&quot;action&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a><span class="w"> </span><span class="nt">&quot;type&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;view&quot;</span><span class="p">,</span>
<a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a><span class="w"> </span><span class="nt">&quot;path&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;system-hub/overview&quot;</span>
<a id="__codelineno-22-5" name="__codelineno-22-5" href="#__codelineno-22-5"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-22-6" name="__codelineno-22-6" href="#__codelineno-22-6"></a><span class="p">}</span>
</code></pre></div></p>
<p><strong>Fichier de vue:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a>htdocs/luci-static/resources/view/system-hub/overview.js
</code></pre></div></p>
<h4 id="incorrect-causes-404">❌ INCORRECT (Causes 404):<a class="headerlink" href="#incorrect-causes-404" title="Permanent link">&para;</a></h4>
<p>Menu: <code>"path": "system-hub/overview"</code> mais fichier: <code>view/systemhub/overview.js</code></p>
<h3 id="prefixes-standards">Prefixes Standards<a class="headerlink" href="#prefixes-standards" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Type</th>
<th>Prefix</th>
<th>Exemple</th>
</tr>
</thead>
<tbody>
<tr>
<td>ubus objects</td>
<td><code>luci.</code></td>
<td><code>luci.system-hub</code></td>
</tr>
<tr>
<td>CSS classes</td>
<td><code>sh-</code> (System Hub) ou <code>sb-</code> (SecuBox)</td>
<td><code>.sh-page-header</code></td>
</tr>
<tr>
<td>CSS variables</td>
<td><code>--sh-</code></td>
<td><code>--sh-primary</code></td>
</tr>
<tr>
<td>JavaScript modules</td>
<td>Nom du module</td>
<td><code>system-hub/api.js</code></td>
</tr>
</tbody>
</table>
<h3 id="file-structure-template">File Structure Template<a class="headerlink" href="#file-structure-template" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a>luci-app-&lt;module-name&gt;/
<a id="__codelineno-24-2" name="__codelineno-24-2" href="#__codelineno-24-2"></a>├── Makefile
<a id="__codelineno-24-3" name="__codelineno-24-3" href="#__codelineno-24-3"></a>├── README.md
<a id="__codelineno-24-4" name="__codelineno-24-4" href="#__codelineno-24-4"></a>├── htdocs/luci-static/resources/
<a id="__codelineno-24-5" name="__codelineno-24-5" href="#__codelineno-24-5"></a>│ ├── view/&lt;module-name&gt;/
<a id="__codelineno-24-6" name="__codelineno-24-6" href="#__codelineno-24-6"></a>│ │ ├── overview.js # Page principale
<a id="__codelineno-24-7" name="__codelineno-24-7" href="#__codelineno-24-7"></a>│ │ ├── settings.js # Configuration
<a id="__codelineno-24-8" name="__codelineno-24-8" href="#__codelineno-24-8"></a>│ │ └── *.js # Autres vues
<a id="__codelineno-24-9" name="__codelineno-24-9" href="#__codelineno-24-9"></a>│ └── &lt;module-name&gt;/
<a id="__codelineno-24-10" name="__codelineno-24-10" href="#__codelineno-24-10"></a>│ ├── api.js # RPC client
<a id="__codelineno-24-11" name="__codelineno-24-11" href="#__codelineno-24-11"></a>│ ├── theme.js # Theme helpers (optionnel)
<a id="__codelineno-24-12" name="__codelineno-24-12" href="#__codelineno-24-12"></a>│ ├── common.css # Styles partagés
<a id="__codelineno-24-13" name="__codelineno-24-13" href="#__codelineno-24-13"></a>│ └── *.css # Styles spécifiques
<a id="__codelineno-24-14" name="__codelineno-24-14" href="#__codelineno-24-14"></a>└── root/
<a id="__codelineno-24-15" name="__codelineno-24-15" href="#__codelineno-24-15"></a> ├── usr/
<a id="__codelineno-24-16" name="__codelineno-24-16" href="#__codelineno-24-16"></a> │ ├── libexec/rpcd/
<a id="__codelineno-24-17" name="__codelineno-24-17" href="#__codelineno-24-17"></a> │ │ └── luci.&lt;module-name&gt; # ⚠️ MUST match ubus object
<a id="__codelineno-24-18" name="__codelineno-24-18" href="#__codelineno-24-18"></a> │ └── share/
<a id="__codelineno-24-19" name="__codelineno-24-19" href="#__codelineno-24-19"></a> │ ├── luci/menu.d/
<a id="__codelineno-24-20" name="__codelineno-24-20" href="#__codelineno-24-20"></a> │ │ └── luci-app-&lt;module-name&gt;.json
<a id="__codelineno-24-21" name="__codelineno-24-21" href="#__codelineno-24-21"></a> │ └── rpcd/acl.d/
<a id="__codelineno-24-22" name="__codelineno-24-22" href="#__codelineno-24-22"></a> │ └── luci-app-&lt;module-name&gt;.json
<a id="__codelineno-24-23" name="__codelineno-24-23" href="#__codelineno-24-23"></a> └── etc/config/&lt;module-name&gt; (optionnel)
</code></pre></div>
<hr />
<h2 id="rpcd-ubus-best-practices">RPCD &amp; ubus Best Practices<a class="headerlink" href="#rpcd-ubus-best-practices" title="Permanent link">&para;</a></h2>
<h3 id="rpcd-script-template-shell">RPCD Script Template (Shell)<a class="headerlink" href="#rpcd-script-template-shell" title="Permanent link">&para;</a></h3>
<p><strong>Fichier:</strong> <code>root/usr/libexec/rpcd/luci.&lt;module-name&gt;</code></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-25-1" name="__codelineno-25-1" href="#__codelineno-25-1"></a><span class="ch">#!/bin/sh</span>
<a id="__codelineno-25-2" name="__codelineno-25-2" href="#__codelineno-25-2"></a><span class="c1"># RPCD backend for &lt;module-name&gt;</span>
<a id="__codelineno-25-3" name="__codelineno-25-3" href="#__codelineno-25-3"></a><span class="c1"># ubus object: luci.&lt;module-name&gt;</span>
<a id="__codelineno-25-4" name="__codelineno-25-4" href="#__codelineno-25-4"></a>
<a id="__codelineno-25-5" name="__codelineno-25-5" href="#__codelineno-25-5"></a><span class="k">case</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$1</span><span class="s2">&quot;</span><span class="w"> </span><span class="k">in</span>
<a id="__codelineno-25-6" name="__codelineno-25-6" href="#__codelineno-25-6"></a><span class="w"> </span>list<span class="o">)</span>
<a id="__codelineno-25-7" name="__codelineno-25-7" href="#__codelineno-25-7"></a><span class="w"> </span><span class="c1"># Liste des méthodes disponibles</span>
<a id="__codelineno-25-8" name="__codelineno-25-8" href="#__codelineno-25-8"></a><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s1">&#39;{</span>
<a id="__codelineno-25-9" name="__codelineno-25-9" href="#__codelineno-25-9"></a><span class="s1"> &quot;getStatus&quot;: {},</span>
<a id="__codelineno-25-10" name="__codelineno-25-10" href="#__codelineno-25-10"></a><span class="s1"> &quot;getHealth&quot;: {},</span>
<a id="__codelineno-25-11" name="__codelineno-25-11" href="#__codelineno-25-11"></a><span class="s1"> &quot;getServices&quot;: {}</span>
<a id="__codelineno-25-12" name="__codelineno-25-12" href="#__codelineno-25-12"></a><span class="s1"> }&#39;</span>
<a id="__codelineno-25-13" name="__codelineno-25-13" href="#__codelineno-25-13"></a><span class="w"> </span><span class="p">;;</span>
<a id="__codelineno-25-14" name="__codelineno-25-14" href="#__codelineno-25-14"></a><span class="w"> </span>call<span class="o">)</span>
<a id="__codelineno-25-15" name="__codelineno-25-15" href="#__codelineno-25-15"></a><span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$2</span><span class="s2">&quot;</span><span class="w"> </span><span class="k">in</span>
<a id="__codelineno-25-16" name="__codelineno-25-16" href="#__codelineno-25-16"></a><span class="w"> </span>getStatus<span class="o">)</span>
<a id="__codelineno-25-17" name="__codelineno-25-17" href="#__codelineno-25-17"></a><span class="w"> </span><span class="c1"># TOUJOURS retourner du JSON valide</span>
<a id="__codelineno-25-18" name="__codelineno-25-18" href="#__codelineno-25-18"></a><span class="w"> </span><span class="nb">printf</span><span class="w"> </span><span class="s1">&#39;{&quot;enabled&quot;: true, &quot;version&quot;: &quot;1.0.0&quot;}\n&#39;</span>
<a id="__codelineno-25-19" name="__codelineno-25-19" href="#__codelineno-25-19"></a><span class="w"> </span><span class="p">;;</span>
<a id="__codelineno-25-20" name="__codelineno-25-20" href="#__codelineno-25-20"></a><span class="w"> </span>getHealth<span class="o">)</span>
<a id="__codelineno-25-21" name="__codelineno-25-21" href="#__codelineno-25-21"></a><span class="w"> </span><span class="c1"># Lire les métriques système</span>
<a id="__codelineno-25-22" name="__codelineno-25-22" href="#__codelineno-25-22"></a><span class="w"> </span><span class="nv">cpu_usage</span><span class="o">=</span><span class="k">$(</span>top<span class="w"> </span>-bn1<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s2">&quot;CPU:&quot;</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span><span class="s1">&#39;{print $2}&#39;</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span><span class="s1">&#39;s/%//&#39;</span><span class="k">)</span>
<a id="__codelineno-25-23" name="__codelineno-25-23" href="#__codelineno-25-23"></a><span class="w"> </span><span class="nv">mem_total</span><span class="o">=</span><span class="k">$(</span>free<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>Mem<span class="w"> </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span><span class="s1">&#39;{print $2}&#39;</span><span class="k">)</span>
<a id="__codelineno-25-24" name="__codelineno-25-24" href="#__codelineno-25-24"></a><span class="w"> </span><span class="nv">mem_used</span><span class="o">=</span><span class="k">$(</span>free<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>Mem<span class="w"> </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span><span class="s1">&#39;{print $3}&#39;</span><span class="k">)</span>
<a id="__codelineno-25-25" name="__codelineno-25-25" href="#__codelineno-25-25"></a>
<a id="__codelineno-25-26" name="__codelineno-25-26" href="#__codelineno-25-26"></a><span class="w"> </span><span class="nb">printf</span><span class="w"> </span><span class="s1">&#39;{</span>
<a id="__codelineno-25-27" name="__codelineno-25-27" href="#__codelineno-25-27"></a><span class="s1"> &quot;cpu&quot;: {&quot;usage&quot;: %s},</span>
<a id="__codelineno-25-28" name="__codelineno-25-28" href="#__codelineno-25-28"></a><span class="s1"> &quot;memory&quot;: {&quot;total_kb&quot;: %s, &quot;used_kb&quot;: %s}</span>
<a id="__codelineno-25-29" name="__codelineno-25-29" href="#__codelineno-25-29"></a><span class="s1"> }\n&#39;</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$cpu_usage</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$mem_total</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$mem_used</span><span class="s2">&quot;</span>
<a id="__codelineno-25-30" name="__codelineno-25-30" href="#__codelineno-25-30"></a><span class="w"> </span><span class="p">;;</span>
<a id="__codelineno-25-31" name="__codelineno-25-31" href="#__codelineno-25-31"></a><span class="w"> </span>getServices<span class="o">)</span>
<a id="__codelineno-25-32" name="__codelineno-25-32" href="#__codelineno-25-32"></a><span class="w"> </span><span class="c1"># Exemple avec services</span>
<a id="__codelineno-25-33" name="__codelineno-25-33" href="#__codelineno-25-33"></a><span class="w"> </span><span class="nv">services</span><span class="o">=</span><span class="s1">&#39;[]&#39;</span>
<a id="__codelineno-25-34" name="__codelineno-25-34" href="#__codelineno-25-34"></a><span class="w"> </span><span class="k">for</span><span class="w"> </span>service<span class="w"> </span><span class="k">in</span><span class="w"> </span>/etc/init.d/*<span class="p">;</span><span class="w"> </span><span class="k">do</span>
<a id="__codelineno-25-35" name="__codelineno-25-35" href="#__codelineno-25-35"></a><span class="w"> </span><span class="c1"># Build JSON array</span>
<a id="__codelineno-25-36" name="__codelineno-25-36" href="#__codelineno-25-36"></a><span class="w"> </span>:
<a id="__codelineno-25-37" name="__codelineno-25-37" href="#__codelineno-25-37"></a><span class="w"> </span><span class="k">done</span>
<a id="__codelineno-25-38" name="__codelineno-25-38" href="#__codelineno-25-38"></a><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$services</span><span class="s2">&quot;</span>
<a id="__codelineno-25-39" name="__codelineno-25-39" href="#__codelineno-25-39"></a><span class="w"> </span><span class="p">;;</span>
<a id="__codelineno-25-40" name="__codelineno-25-40" href="#__codelineno-25-40"></a><span class="w"> </span>*<span class="o">)</span>
<a id="__codelineno-25-41" name="__codelineno-25-41" href="#__codelineno-25-41"></a><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s1">&#39;{&quot;error&quot;: &quot;Method not found&quot;}&#39;</span>
<a id="__codelineno-25-42" name="__codelineno-25-42" href="#__codelineno-25-42"></a><span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">1</span>
<a id="__codelineno-25-43" name="__codelineno-25-43" href="#__codelineno-25-43"></a><span class="w"> </span><span class="p">;;</span>
<a id="__codelineno-25-44" name="__codelineno-25-44" href="#__codelineno-25-44"></a><span class="w"> </span><span class="k">esac</span>
<a id="__codelineno-25-45" name="__codelineno-25-45" href="#__codelineno-25-45"></a><span class="w"> </span><span class="p">;;</span>
<a id="__codelineno-25-46" name="__codelineno-25-46" href="#__codelineno-25-46"></a><span class="k">esac</span>
</code></pre></div>
<h3 id="rpcd-script-validation">RPCD Script Validation<a class="headerlink" href="#rpcd-script-validation" title="Permanent link">&para;</a></h3>
<p><strong>CHECKLIST OBLIGATOIRE:</strong></p>
<ol>
<li>✅ Fichier exécutable: <code>chmod +x root/usr/libexec/rpcd/luci.&lt;module-name&gt;</code></li>
<li>✅ Shebang présent: <code>#!/bin/sh</code></li>
<li>✅ Structure case/esac correcte</li>
<li>✅ Méthode <code>list</code> retourne JSON avec toutes les méthodes</li>
<li>✅ Méthode <code>call</code> gère tous les cas</li>
<li>✅ Toujours retourner du JSON valide</li>
<li>✅ Pas de <code>echo</code> de debug (commentés en prod)</li>
<li>✅ Gestion d'erreur pour méthodes inconnues</li>
</ol>
<h3 id="testing-rpcd-scripts">Testing RPCD Scripts<a class="headerlink" href="#testing-rpcd-scripts" title="Permanent link">&para;</a></h3>
<p><strong>Sur le routeur:</strong></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-26-1" name="__codelineno-26-1" href="#__codelineno-26-1"></a><span class="c1"># Test direct</span>
<a id="__codelineno-26-2" name="__codelineno-26-2" href="#__codelineno-26-2"></a>/usr/libexec/rpcd/luci.system-hub<span class="w"> </span>list
<a id="__codelineno-26-3" name="__codelineno-26-3" href="#__codelineno-26-3"></a>
<a id="__codelineno-26-4" name="__codelineno-26-4" href="#__codelineno-26-4"></a><span class="c1"># Via ubus</span>
<a id="__codelineno-26-5" name="__codelineno-26-5" href="#__codelineno-26-5"></a>ubus<span class="w"> </span>list<span class="w"> </span>luci.system-hub
<a id="__codelineno-26-6" name="__codelineno-26-6" href="#__codelineno-26-6"></a>ubus<span class="w"> </span>call<span class="w"> </span>luci.system-hub<span class="w"> </span>getStatus
<a id="__codelineno-26-7" name="__codelineno-26-7" href="#__codelineno-26-7"></a>
<a id="__codelineno-26-8" name="__codelineno-26-8" href="#__codelineno-26-8"></a><span class="c1"># Restart RPCD après modification</span>
<a id="__codelineno-26-9" name="__codelineno-26-9" href="#__codelineno-26-9"></a>/etc/init.d/rpcd<span class="w"> </span>restart
</code></pre></div>
<h3 id="common-rpcd-errors">Common RPCD Errors<a class="headerlink" href="#common-rpcd-errors" title="Permanent link">&para;</a></h3>
<h4 id="error-object-not-found-32000">Error: "Object not found" (-32000)<a class="headerlink" href="#error-object-not-found-32000" title="Permanent link">&para;</a></h4>
<p><strong>Cause:</strong> Nom du fichier RPCD ne correspond pas à l'objet ubus</p>
<p><strong>Solution:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-27-1" name="__codelineno-27-1" href="#__codelineno-27-1"></a><span class="c1"># Vérifier le nom dans JS</span>
<a id="__codelineno-27-2" name="__codelineno-27-2" href="#__codelineno-27-2"></a>grep<span class="w"> </span>-r<span class="w"> </span><span class="s2">&quot;object:&quot;</span><span class="w"> </span>htdocs/luci-static/resources/view/<span class="w"> </span>--include<span class="o">=</span><span class="s2">&quot;*.js&quot;</span>
<a id="__codelineno-27-3" name="__codelineno-27-3" href="#__codelineno-27-3"></a>
<a id="__codelineno-27-4" name="__codelineno-27-4" href="#__codelineno-27-4"></a><span class="c1"># Renommer le fichier RPCD pour correspondre</span>
<a id="__codelineno-27-5" name="__codelineno-27-5" href="#__codelineno-27-5"></a>mv<span class="w"> </span>root/usr/libexec/rpcd/wrong-name<span class="w"> </span>root/usr/libexec/rpcd/luci.correct-name
</code></pre></div></p>
<h4 id="error-method-not-found-32601">Error: "Method not found" (-32601)<a class="headerlink" href="#error-method-not-found-32601" title="Permanent link">&para;</a></h4>
<p><strong>Cause:</strong> Méthode non déclarée dans <code>list</code> ou non implémentée dans <code>call</code></p>
<p><strong>Solution:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-28-1" name="__codelineno-28-1" href="#__codelineno-28-1"></a><span class="c1"># Vérifier que la méthode est dans les deux blocs</span>
<a id="__codelineno-28-2" name="__codelineno-28-2" href="#__codelineno-28-2"></a>grep<span class="w"> </span><span class="s2">&quot;getStatus&quot;</span><span class="w"> </span>root/usr/libexec/rpcd/luci.*
</code></pre></div></p>
<h4 id="error-invalid-json-returned">Error: Invalid JSON returned<a class="headerlink" href="#error-invalid-json-returned" title="Permanent link">&para;</a></h4>
<p><strong>Cause:</strong> Output RPCD n'est pas du JSON valide</p>
<p><strong>Solution:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-29-1" name="__codelineno-29-1" href="#__codelineno-29-1"></a><span class="c1"># Tester le JSON</span>
<a id="__codelineno-29-2" name="__codelineno-29-2" href="#__codelineno-29-2"></a>/usr/libexec/rpcd/luci.module-name<span class="w"> </span>call<span class="w"> </span>getStatus<span class="w"> </span><span class="p">|</span><span class="w"> </span>jsonlint
<a id="__codelineno-29-3" name="__codelineno-29-3" href="#__codelineno-29-3"></a>
<a id="__codelineno-29-4" name="__codelineno-29-4" href="#__codelineno-29-4"></a><span class="c1"># Utiliser printf au lieu de echo pour le JSON</span>
<a id="__codelineno-29-5" name="__codelineno-29-5" href="#__codelineno-29-5"></a><span class="nb">printf</span><span class="w"> </span><span class="s1">&#39;{&quot;key&quot;: &quot;%s&quot;}\n&#39;</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$value</span><span class="s2">&quot;</span>
</code></pre></div></p>
<hr />
<h2 id="acl-permissions">ACL &amp; Permissions<a class="headerlink" href="#acl-permissions" title="Permanent link">&para;</a></h2>
<h3 id="acl-file-template">ACL File Template<a class="headerlink" href="#acl-file-template" title="Permanent link">&para;</a></h3>
<p><strong>Fichier:</strong> <code>root/usr/share/rpcd/acl.d/luci-app-&lt;module-name&gt;.json</code></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-30-1" name="__codelineno-30-1" href="#__codelineno-30-1"></a><span class="p">{</span>
<a id="__codelineno-30-2" name="__codelineno-30-2" href="#__codelineno-30-2"></a><span class="w"> </span><span class="nt">&quot;luci-app-&lt;module-name&gt;&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-30-3" name="__codelineno-30-3" href="#__codelineno-30-3"></a><span class="w"> </span><span class="nt">&quot;description&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;Grant access to &lt;Module Name&gt;&quot;</span><span class="p">,</span>
<a id="__codelineno-30-4" name="__codelineno-30-4" href="#__codelineno-30-4"></a><span class="w"> </span><span class="nt">&quot;read&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-30-5" name="__codelineno-30-5" href="#__codelineno-30-5"></a><span class="w"> </span><span class="nt">&quot;ubus&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-30-6" name="__codelineno-30-6" href="#__codelineno-30-6"></a><span class="w"> </span><span class="nt">&quot;luci.&lt;module-name&gt;&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-30-7" name="__codelineno-30-7" href="#__codelineno-30-7"></a><span class="w"> </span><span class="s2">&quot;getStatus&quot;</span><span class="p">,</span>
<a id="__codelineno-30-8" name="__codelineno-30-8" href="#__codelineno-30-8"></a><span class="w"> </span><span class="s2">&quot;getHealth&quot;</span><span class="p">,</span>
<a id="__codelineno-30-9" name="__codelineno-30-9" href="#__codelineno-30-9"></a><span class="w"> </span><span class="s2">&quot;getServices&quot;</span>
<a id="__codelineno-30-10" name="__codelineno-30-10" href="#__codelineno-30-10"></a><span class="w"> </span><span class="p">]</span>
<a id="__codelineno-30-11" name="__codelineno-30-11" href="#__codelineno-30-11"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-30-12" name="__codelineno-30-12" href="#__codelineno-30-12"></a><span class="w"> </span><span class="nt">&quot;uci&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-30-13" name="__codelineno-30-13" href="#__codelineno-30-13"></a><span class="w"> </span><span class="s2">&quot;&lt;module-name&gt;&quot;</span>
<a id="__codelineno-30-14" name="__codelineno-30-14" href="#__codelineno-30-14"></a><span class="w"> </span><span class="p">]</span>
<a id="__codelineno-30-15" name="__codelineno-30-15" href="#__codelineno-30-15"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-30-16" name="__codelineno-30-16" href="#__codelineno-30-16"></a><span class="w"> </span><span class="nt">&quot;write&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-30-17" name="__codelineno-30-17" href="#__codelineno-30-17"></a><span class="w"> </span><span class="nt">&quot;ubus&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-30-18" name="__codelineno-30-18" href="#__codelineno-30-18"></a><span class="w"> </span><span class="nt">&quot;luci.&lt;module-name&gt;&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-30-19" name="__codelineno-30-19" href="#__codelineno-30-19"></a><span class="w"> </span><span class="s2">&quot;setConfig&quot;</span><span class="p">,</span>
<a id="__codelineno-30-20" name="__codelineno-30-20" href="#__codelineno-30-20"></a><span class="w"> </span><span class="s2">&quot;restartService&quot;</span>
<a id="__codelineno-30-21" name="__codelineno-30-21" href="#__codelineno-30-21"></a><span class="w"> </span><span class="p">]</span>
<a id="__codelineno-30-22" name="__codelineno-30-22" href="#__codelineno-30-22"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-30-23" name="__codelineno-30-23" href="#__codelineno-30-23"></a><span class="w"> </span><span class="nt">&quot;uci&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-30-24" name="__codelineno-30-24" href="#__codelineno-30-24"></a><span class="w"> </span><span class="s2">&quot;&lt;module-name&gt;&quot;</span>
<a id="__codelineno-30-25" name="__codelineno-30-25" href="#__codelineno-30-25"></a><span class="w"> </span><span class="p">]</span>
<a id="__codelineno-30-26" name="__codelineno-30-26" href="#__codelineno-30-26"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-30-27" name="__codelineno-30-27" href="#__codelineno-30-27"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-30-28" name="__codelineno-30-28" href="#__codelineno-30-28"></a><span class="p">}</span>
</code></pre></div>
<h3 id="acl-best-practices">ACL Best Practices<a class="headerlink" href="#acl-best-practices" title="Permanent link">&para;</a></h3>
<ol>
<li><strong>Séparation read/write:</strong> Ne donnez que les permissions nécessaires</li>
<li><strong>Liste explicite:</strong> Listez toutes les méthodes ubus utilisées</li>
<li><strong>UCI access:</strong> Ajoutez les configs UCI dans <code>read</code> et <code>write</code></li>
<li><strong>Validation JSON:</strong> Toujours valider avec <code>jsonlint</code></li>
</ol>
<h3 id="common-acl-errors">Common ACL Errors<a class="headerlink" href="#common-acl-errors" title="Permanent link">&para;</a></h3>
<h4 id="error-access-denied">Error: "Access denied"<a class="headerlink" href="#error-access-denied" title="Permanent link">&para;</a></h4>
<p><strong>Cause:</strong> Méthode ubus pas dans ACL</p>
<p><strong>Solution:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-31-1" name="__codelineno-31-1" href="#__codelineno-31-1"></a><span class="p">{</span>
<a id="__codelineno-31-2" name="__codelineno-31-2" href="#__codelineno-31-2"></a><span class="w"> </span><span class="nt">&quot;read&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-31-3" name="__codelineno-31-3" href="#__codelineno-31-3"></a><span class="w"> </span><span class="nt">&quot;ubus&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-31-4" name="__codelineno-31-4" href="#__codelineno-31-4"></a><span class="w"> </span><span class="nt">&quot;luci.system-hub&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-31-5" name="__codelineno-31-5" href="#__codelineno-31-5"></a><span class="w"> </span><span class="s2">&quot;getHealth&quot;</span><span class="w"> </span><span class="c1">// ← Ajouter la méthode manquante</span>
<a id="__codelineno-31-6" name="__codelineno-31-6" href="#__codelineno-31-6"></a><span class="w"> </span><span class="p">]</span>
<a id="__codelineno-31-7" name="__codelineno-31-7" href="#__codelineno-31-7"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-31-8" name="__codelineno-31-8" href="#__codelineno-31-8"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-31-9" name="__codelineno-31-9" href="#__codelineno-31-9"></a><span class="p">}</span>
</code></pre></div></p>
<h4 id="error-uci-config-not-accessible">Error: "UCI config not accessible"<a class="headerlink" href="#error-uci-config-not-accessible" title="Permanent link">&para;</a></h4>
<p><strong>Cause:</strong> Config UCI pas dans ACL</p>
<p><strong>Solution:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-32-1" name="__codelineno-32-1" href="#__codelineno-32-1"></a><span class="p">{</span>
<a id="__codelineno-32-2" name="__codelineno-32-2" href="#__codelineno-32-2"></a><span class="w"> </span><span class="nt">&quot;read&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-32-3" name="__codelineno-32-3" href="#__codelineno-32-3"></a><span class="w"> </span><span class="nt">&quot;uci&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-32-4" name="__codelineno-32-4" href="#__codelineno-32-4"></a><span class="w"> </span><span class="s2">&quot;system-hub&quot;</span><span class="w"> </span><span class="c1">// ← Ajouter le config</span>
<a id="__codelineno-32-5" name="__codelineno-32-5" href="#__codelineno-32-5"></a><span class="w"> </span><span class="p">]</span>
<a id="__codelineno-32-6" name="__codelineno-32-6" href="#__codelineno-32-6"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-32-7" name="__codelineno-32-7" href="#__codelineno-32-7"></a><span class="p">}</span>
</code></pre></div></p>
<hr />
<h2 id="javascript-patterns">JavaScript Patterns<a class="headerlink" href="#javascript-patterns" title="Permanent link">&para;</a></h2>
<h3 id="api-module-template">API Module Template<a class="headerlink" href="#api-module-template" title="Permanent link">&para;</a></h3>
<p><strong>Fichier:</strong> <code>htdocs/luci-static/resources/&lt;module-name&gt;/api.js</code></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-33-1" name="__codelineno-33-1" href="#__codelineno-33-1"></a><span class="s1">&#39;use strict&#39;</span><span class="p">;</span>
<a id="__codelineno-33-2" name="__codelineno-33-2" href="#__codelineno-33-2"></a><span class="s1">&#39;require rpc&#39;</span><span class="p">;</span>
<a id="__codelineno-33-3" name="__codelineno-33-3" href="#__codelineno-33-3"></a><span class="s1">&#39;require uci&#39;</span><span class="p">;</span>
<a id="__codelineno-33-4" name="__codelineno-33-4" href="#__codelineno-33-4"></a>
<a id="__codelineno-33-5" name="__codelineno-33-5" href="#__codelineno-33-5"></a><span class="k">return</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">Class</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<a id="__codelineno-33-6" name="__codelineno-33-6" href="#__codelineno-33-6"></a><span class="w"> </span><span class="c1">// Déclarer les appels RPC</span>
<a id="__codelineno-33-7" name="__codelineno-33-7" href="#__codelineno-33-7"></a><span class="w"> </span><span class="nx">callGetStatus</span><span class="o">:</span><span class="w"> </span><span class="nx">rpc</span><span class="p">.</span><span class="nx">declare</span><span class="p">({</span>
<a id="__codelineno-33-8" name="__codelineno-33-8" href="#__codelineno-33-8"></a><span class="w"> </span><span class="nx">object</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;luci.&lt;module-name&gt;&#39;</span><span class="p">,</span>
<a id="__codelineno-33-9" name="__codelineno-33-9" href="#__codelineno-33-9"></a><span class="w"> </span><span class="nx">method</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;getStatus&#39;</span><span class="p">,</span>
<a id="__codelineno-33-10" name="__codelineno-33-10" href="#__codelineno-33-10"></a><span class="w"> </span><span class="nx">expect</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-33-11" name="__codelineno-33-11" href="#__codelineno-33-11"></a><span class="w"> </span><span class="p">}),</span>
<a id="__codelineno-33-12" name="__codelineno-33-12" href="#__codelineno-33-12"></a>
<a id="__codelineno-33-13" name="__codelineno-33-13" href="#__codelineno-33-13"></a><span class="w"> </span><span class="nx">callGetHealth</span><span class="o">:</span><span class="w"> </span><span class="nx">rpc</span><span class="p">.</span><span class="nx">declare</span><span class="p">({</span>
<a id="__codelineno-33-14" name="__codelineno-33-14" href="#__codelineno-33-14"></a><span class="w"> </span><span class="nx">object</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;luci.&lt;module-name&gt;&#39;</span><span class="p">,</span>
<a id="__codelineno-33-15" name="__codelineno-33-15" href="#__codelineno-33-15"></a><span class="w"> </span><span class="nx">method</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;getHealth&#39;</span><span class="p">,</span>
<a id="__codelineno-33-16" name="__codelineno-33-16" href="#__codelineno-33-16"></a><span class="w"> </span><span class="nx">expect</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-33-17" name="__codelineno-33-17" href="#__codelineno-33-17"></a><span class="w"> </span><span class="p">}),</span>
<a id="__codelineno-33-18" name="__codelineno-33-18" href="#__codelineno-33-18"></a>
<a id="__codelineno-33-19" name="__codelineno-33-19" href="#__codelineno-33-19"></a><span class="w"> </span><span class="c1">// Méthodes wrapper avec gestion d&#39;erreur</span>
<a id="__codelineno-33-20" name="__codelineno-33-20" href="#__codelineno-33-20"></a><span class="w"> </span><span class="nx">getStatus</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-33-21" name="__codelineno-33-21" href="#__codelineno-33-21"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">callGetStatus</span><span class="p">().</span><span class="k">catch</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-33-22" name="__codelineno-33-22" href="#__codelineno-33-22"></a><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s1">&#39;Failed to get status:&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">);</span>
<a id="__codelineno-33-23" name="__codelineno-33-23" href="#__codelineno-33-23"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">enabled</span><span class="o">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w"> </span><span class="nx">error</span><span class="o">:</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">message</span><span class="w"> </span><span class="p">};</span>
<a id="__codelineno-33-24" name="__codelineno-33-24" href="#__codelineno-33-24"></a><span class="w"> </span><span class="p">});</span>
<a id="__codelineno-33-25" name="__codelineno-33-25" href="#__codelineno-33-25"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-33-26" name="__codelineno-33-26" href="#__codelineno-33-26"></a>
<a id="__codelineno-33-27" name="__codelineno-33-27" href="#__codelineno-33-27"></a><span class="w"> </span><span class="nx">getHealth</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-33-28" name="__codelineno-33-28" href="#__codelineno-33-28"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">callGetHealth</span><span class="p">().</span><span class="k">catch</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-33-29" name="__codelineno-33-29" href="#__codelineno-33-29"></a><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s1">&#39;Failed to get health:&#39;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">);</span>
<a id="__codelineno-33-30" name="__codelineno-33-30" href="#__codelineno-33-30"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-33-31" name="__codelineno-33-31" href="#__codelineno-33-31"></a><span class="w"> </span><span class="nx">cpu</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">usage</span><span class="o">:</span><span class="w"> </span><span class="mf">0</span><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-33-32" name="__codelineno-33-32" href="#__codelineno-33-32"></a><span class="w"> </span><span class="nx">memory</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">usage</span><span class="o">:</span><span class="w"> </span><span class="mf">0</span><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-33-33" name="__codelineno-33-33" href="#__codelineno-33-33"></a><span class="w"> </span><span class="nx">error</span><span class="o">:</span><span class="w"> </span><span class="nx">err</span><span class="p">.</span><span class="nx">message</span>
<a id="__codelineno-33-34" name="__codelineno-33-34" href="#__codelineno-33-34"></a><span class="w"> </span><span class="p">};</span>
<a id="__codelineno-33-35" name="__codelineno-33-35" href="#__codelineno-33-35"></a><span class="w"> </span><span class="p">});</span>
<a id="__codelineno-33-36" name="__codelineno-33-36" href="#__codelineno-33-36"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-33-37" name="__codelineno-33-37" href="#__codelineno-33-37"></a>
<a id="__codelineno-33-38" name="__codelineno-33-38" href="#__codelineno-33-38"></a><span class="w"> </span><span class="c1">// Utilitaires</span>
<a id="__codelineno-33-39" name="__codelineno-33-39" href="#__codelineno-33-39"></a><span class="w"> </span><span class="nx">formatBytes</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">(</span><span class="nx">bytes</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-33-40" name="__codelineno-33-40" href="#__codelineno-33-40"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">bytes</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="mf">0</span><span class="p">)</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="s1">&#39;0 B&#39;</span><span class="p">;</span>
<a id="__codelineno-33-41" name="__codelineno-33-41" href="#__codelineno-33-41"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">k</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">1024</span><span class="p">;</span>
<a id="__codelineno-33-42" name="__codelineno-33-42" href="#__codelineno-33-42"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">sizes</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s1">&#39;B&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;KB&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;MB&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;GB&#39;</span><span class="p">];</span>
<a id="__codelineno-33-43" name="__codelineno-33-43" href="#__codelineno-33-43"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nb">Math</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">bytes</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nb">Math</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">k</span><span class="p">));</span>
<a id="__codelineno-33-44" name="__codelineno-33-44" href="#__codelineno-33-44"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">parseFloat</span><span class="p">((</span><span class="nx">bytes</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nb">Math</span><span class="p">.</span><span class="nx">pow</span><span class="p">(</span><span class="nx">k</span><span class="p">,</span><span class="w"> </span><span class="nx">i</span><span class="p">)).</span><span class="nx">toFixed</span><span class="p">(</span><span class="mf">2</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s1">&#39; &#39;</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">sizes</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
<a id="__codelineno-33-45" name="__codelineno-33-45" href="#__codelineno-33-45"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-33-46" name="__codelineno-33-46" href="#__codelineno-33-46"></a><span class="p">});</span>
</code></pre></div>
<h3 id="view-template">View Template<a class="headerlink" href="#view-template" title="Permanent link">&para;</a></h3>
<p><strong>Fichier:</strong> <code>htdocs/luci-static/resources/view/&lt;module-name&gt;/overview.js</code></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-34-1" name="__codelineno-34-1" href="#__codelineno-34-1"></a><span class="s1">&#39;use strict&#39;</span><span class="p">;</span>
<a id="__codelineno-34-2" name="__codelineno-34-2" href="#__codelineno-34-2"></a><span class="s1">&#39;require view&#39;</span><span class="p">;</span>
<a id="__codelineno-34-3" name="__codelineno-34-3" href="#__codelineno-34-3"></a><span class="s1">&#39;require ui&#39;</span><span class="p">;</span>
<a id="__codelineno-34-4" name="__codelineno-34-4" href="#__codelineno-34-4"></a><span class="s1">&#39;require dom&#39;</span><span class="p">;</span>
<a id="__codelineno-34-5" name="__codelineno-34-5" href="#__codelineno-34-5"></a><span class="s1">&#39;require poll&#39;</span><span class="p">;</span>
<a id="__codelineno-34-6" name="__codelineno-34-6" href="#__codelineno-34-6"></a><span class="s1">&#39;require &lt;module-name&gt;/api as API&#39;</span><span class="p">;</span>
<a id="__codelineno-34-7" name="__codelineno-34-7" href="#__codelineno-34-7"></a>
<a id="__codelineno-34-8" name="__codelineno-34-8" href="#__codelineno-34-8"></a><span class="k">return</span><span class="w"> </span><span class="nx">view</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
<a id="__codelineno-34-9" name="__codelineno-34-9" href="#__codelineno-34-9"></a><span class="w"> </span><span class="c1">// State</span>
<a id="__codelineno-34-10" name="__codelineno-34-10" href="#__codelineno-34-10"></a><span class="w"> </span><span class="nx">healthData</span><span class="o">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span>
<a id="__codelineno-34-11" name="__codelineno-34-11" href="#__codelineno-34-11"></a><span class="w"> </span><span class="nx">sysInfo</span><span class="o">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span>
<a id="__codelineno-34-12" name="__codelineno-34-12" href="#__codelineno-34-12"></a>
<a id="__codelineno-34-13" name="__codelineno-34-13" href="#__codelineno-34-13"></a><span class="w"> </span><span class="c1">// Load data</span>
<a id="__codelineno-34-14" name="__codelineno-34-14" href="#__codelineno-34-14"></a><span class="w"> </span><span class="nx">load</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-34-15" name="__codelineno-34-15" href="#__codelineno-34-15"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">([</span>
<a id="__codelineno-34-16" name="__codelineno-34-16" href="#__codelineno-34-16"></a><span class="w"> </span><span class="nx">API</span><span class="p">.</span><span class="nx">getStatus</span><span class="p">(),</span>
<a id="__codelineno-34-17" name="__codelineno-34-17" href="#__codelineno-34-17"></a><span class="w"> </span><span class="nx">API</span><span class="p">.</span><span class="nx">getHealth</span><span class="p">()</span>
<a id="__codelineno-34-18" name="__codelineno-34-18" href="#__codelineno-34-18"></a><span class="w"> </span><span class="p">]);</span>
<a id="__codelineno-34-19" name="__codelineno-34-19" href="#__codelineno-34-19"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-34-20" name="__codelineno-34-20" href="#__codelineno-34-20"></a>
<a id="__codelineno-34-21" name="__codelineno-34-21" href="#__codelineno-34-21"></a><span class="w"> </span><span class="c1">// Render UI</span>
<a id="__codelineno-34-22" name="__codelineno-34-22" href="#__codelineno-34-22"></a><span class="w"> </span><span class="nx">render</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-34-23" name="__codelineno-34-23" href="#__codelineno-34-23"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">self</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">;</span>
<a id="__codelineno-34-24" name="__codelineno-34-24" href="#__codelineno-34-24"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">sysInfo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">data</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">{};</span>
<a id="__codelineno-34-25" name="__codelineno-34-25" href="#__codelineno-34-25"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">healthData</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">data</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">{};</span>
<a id="__codelineno-34-26" name="__codelineno-34-26" href="#__codelineno-34-26"></a>
<a id="__codelineno-34-27" name="__codelineno-34-27" href="#__codelineno-34-27"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">container</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;&lt;module&gt;-dashboard&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-34-28" name="__codelineno-34-28" href="#__codelineno-34-28"></a><span class="w"> </span><span class="c1">// Link CSS files</span>
<a id="__codelineno-34-29" name="__codelineno-34-29" href="#__codelineno-34-29"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;link&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;rel&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;stylesheet&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;href&#39;</span><span class="o">:</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">resource</span><span class="p">(</span><span class="s1">&#39;&lt;module&gt;/common.css&#39;</span><span class="p">)</span><span class="w"> </span><span class="p">}),</span>
<a id="__codelineno-34-30" name="__codelineno-34-30" href="#__codelineno-34-30"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;link&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;rel&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;stylesheet&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;href&#39;</span><span class="o">:</span><span class="w"> </span><span class="nx">L</span><span class="p">.</span><span class="nx">resource</span><span class="p">(</span><span class="s1">&#39;&lt;module&gt;/overview.css&#39;</span><span class="p">)</span><span class="w"> </span><span class="p">}),</span>
<a id="__codelineno-34-31" name="__codelineno-34-31" href="#__codelineno-34-31"></a>
<a id="__codelineno-34-32" name="__codelineno-34-32" href="#__codelineno-34-32"></a><span class="w"> </span><span class="c1">// Header</span>
<a id="__codelineno-34-33" name="__codelineno-34-33" href="#__codelineno-34-33"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">renderHeader</span><span class="p">(),</span>
<a id="__codelineno-34-34" name="__codelineno-34-34" href="#__codelineno-34-34"></a>
<a id="__codelineno-34-35" name="__codelineno-34-35" href="#__codelineno-34-35"></a><span class="w"> </span><span class="c1">// Content</span>
<a id="__codelineno-34-36" name="__codelineno-34-36" href="#__codelineno-34-36"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">renderContent</span><span class="p">()</span>
<a id="__codelineno-34-37" name="__codelineno-34-37" href="#__codelineno-34-37"></a><span class="w"> </span><span class="p">]);</span>
<a id="__codelineno-34-38" name="__codelineno-34-38" href="#__codelineno-34-38"></a>
<a id="__codelineno-34-39" name="__codelineno-34-39" href="#__codelineno-34-39"></a><span class="w"> </span><span class="c1">// Setup auto-refresh</span>
<a id="__codelineno-34-40" name="__codelineno-34-40" href="#__codelineno-34-40"></a><span class="w"> </span><span class="nx">poll</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">L</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-34-41" name="__codelineno-34-41" href="#__codelineno-34-41"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Promise</span><span class="p">.</span><span class="nx">all</span><span class="p">([</span>
<a id="__codelineno-34-42" name="__codelineno-34-42" href="#__codelineno-34-42"></a><span class="w"> </span><span class="nx">API</span><span class="p">.</span><span class="nx">getStatus</span><span class="p">(),</span>
<a id="__codelineno-34-43" name="__codelineno-34-43" href="#__codelineno-34-43"></a><span class="w"> </span><span class="nx">API</span><span class="p">.</span><span class="nx">getHealth</span><span class="p">()</span>
<a id="__codelineno-34-44" name="__codelineno-34-44" href="#__codelineno-34-44"></a><span class="w"> </span><span class="p">]).</span><span class="nx">then</span><span class="p">(</span><span class="nx">L</span><span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">refreshData</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-34-45" name="__codelineno-34-45" href="#__codelineno-34-45"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">sysInfo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">refreshData</span><span class="p">[</span><span class="mf">0</span><span class="p">]</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">{};</span>
<a id="__codelineno-34-46" name="__codelineno-34-46" href="#__codelineno-34-46"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">healthData</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">refreshData</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">{};</span>
<a id="__codelineno-34-47" name="__codelineno-34-47" href="#__codelineno-34-47"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">updateDashboard</span><span class="p">();</span>
<a id="__codelineno-34-48" name="__codelineno-34-48" href="#__codelineno-34-48"></a><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="k">this</span><span class="p">));</span>
<a id="__codelineno-34-49" name="__codelineno-34-49" href="#__codelineno-34-49"></a><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="k">this</span><span class="p">),</span><span class="w"> </span><span class="mf">30</span><span class="p">);</span><span class="w"> </span><span class="c1">// Refresh every 30s</span>
<a id="__codelineno-34-50" name="__codelineno-34-50" href="#__codelineno-34-50"></a>
<a id="__codelineno-34-51" name="__codelineno-34-51" href="#__codelineno-34-51"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">container</span><span class="p">;</span>
<a id="__codelineno-34-52" name="__codelineno-34-52" href="#__codelineno-34-52"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-34-53" name="__codelineno-34-53" href="#__codelineno-34-53"></a>
<a id="__codelineno-34-54" name="__codelineno-34-54" href="#__codelineno-34-54"></a><span class="w"> </span><span class="nx">renderHeader</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-34-55" name="__codelineno-34-55" href="#__codelineno-34-55"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-page-header&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-34-56" name="__codelineno-34-56" href="#__codelineno-34-56"></a><span class="w"> </span><span class="c1">// Header content</span>
<a id="__codelineno-34-57" name="__codelineno-34-57" href="#__codelineno-34-57"></a><span class="w"> </span><span class="p">]);</span>
<a id="__codelineno-34-58" name="__codelineno-34-58" href="#__codelineno-34-58"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-34-59" name="__codelineno-34-59" href="#__codelineno-34-59"></a>
<a id="__codelineno-34-60" name="__codelineno-34-60" href="#__codelineno-34-60"></a><span class="w"> </span><span class="nx">renderContent</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-34-61" name="__codelineno-34-61" href="#__codelineno-34-61"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-content&#39;</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-34-62" name="__codelineno-34-62" href="#__codelineno-34-62"></a><span class="w"> </span><span class="c1">// Main content</span>
<a id="__codelineno-34-63" name="__codelineno-34-63" href="#__codelineno-34-63"></a><span class="w"> </span><span class="p">]);</span>
<a id="__codelineno-34-64" name="__codelineno-34-64" href="#__codelineno-34-64"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-34-65" name="__codelineno-34-65" href="#__codelineno-34-65"></a>
<a id="__codelineno-34-66" name="__codelineno-34-66" href="#__codelineno-34-66"></a><span class="w"> </span><span class="nx">updateDashboard</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-34-67" name="__codelineno-34-67" href="#__codelineno-34-67"></a><span class="w"> </span><span class="c1">// Update existing DOM elements</span>
<a id="__codelineno-34-68" name="__codelineno-34-68" href="#__codelineno-34-68"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">element</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="s1">&#39;.my-element&#39;</span><span class="p">);</span>
<a id="__codelineno-34-69" name="__codelineno-34-69" href="#__codelineno-34-69"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">element</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-34-70" name="__codelineno-34-70" href="#__codelineno-34-70"></a><span class="w"> </span><span class="nx">dom</span><span class="p">.</span><span class="nx">content</span><span class="p">(</span><span class="nx">element</span><span class="p">,</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">renderContent</span><span class="p">());</span>
<a id="__codelineno-34-71" name="__codelineno-34-71" href="#__codelineno-34-71"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-34-72" name="__codelineno-34-72" href="#__codelineno-34-72"></a><span class="w"> </span><span class="p">},</span>
<a id="__codelineno-34-73" name="__codelineno-34-73" href="#__codelineno-34-73"></a>
<a id="__codelineno-34-74" name="__codelineno-34-74" href="#__codelineno-34-74"></a><span class="w"> </span><span class="c1">// Required stubs for LuCI</span>
<a id="__codelineno-34-75" name="__codelineno-34-75" href="#__codelineno-34-75"></a><span class="w"> </span><span class="nx">handleSaveApply</span><span class="o">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span>
<a id="__codelineno-34-76" name="__codelineno-34-76" href="#__codelineno-34-76"></a><span class="w"> </span><span class="nx">handleSave</span><span class="o">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span>
<a id="__codelineno-34-77" name="__codelineno-34-77" href="#__codelineno-34-77"></a><span class="w"> </span><span class="nx">handleReset</span><span class="o">:</span><span class="w"> </span><span class="kc">null</span>
<a id="__codelineno-34-78" name="__codelineno-34-78" href="#__codelineno-34-78"></a><span class="p">});</span>
</code></pre></div>
<h3 id="event-handling-pattern">Event Handling Pattern<a class="headerlink" href="#event-handling-pattern" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><a id="__codelineno-35-1" name="__codelineno-35-1" href="#__codelineno-35-1"></a><span class="c1">// ✅ CORRECT: Bind events après render</span>
<a id="__codelineno-35-2" name="__codelineno-35-2" href="#__codelineno-35-2"></a><span class="nx">render</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-35-3" name="__codelineno-35-3" href="#__codelineno-35-3"></a><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="nx">container</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-35-4" name="__codelineno-35-4" href="#__codelineno-35-4"></a><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;button&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-35-5" name="__codelineno-35-5" href="#__codelineno-35-5"></a><span class="w"> </span><span class="s1">&#39;id&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;my-button&#39;</span><span class="p">,</span>
<a id="__codelineno-35-6" name="__codelineno-35-6" href="#__codelineno-35-6"></a><span class="w"> </span><span class="s1">&#39;class&#39;</span><span class="o">:</span><span class="w"> </span><span class="s1">&#39;sh-btn sh-btn-primary&#39;</span>
<a id="__codelineno-35-7" name="__codelineno-35-7" href="#__codelineno-35-7"></a><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="s1">&#39;Click Me&#39;</span><span class="p">)</span>
<a id="__codelineno-35-8" name="__codelineno-35-8" href="#__codelineno-35-8"></a><span class="w"> </span><span class="p">]);</span>
<a id="__codelineno-35-9" name="__codelineno-35-9" href="#__codelineno-35-9"></a>
<a id="__codelineno-35-10" name="__codelineno-35-10" href="#__codelineno-35-10"></a><span class="w"> </span><span class="c1">// Ajouter l&#39;événement après le container est créé</span>
<a id="__codelineno-35-11" name="__codelineno-35-11" href="#__codelineno-35-11"></a><span class="w"> </span><span class="nx">container</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">&#39;click&#39;</span><span class="p">,</span><span class="w"> </span><span class="kd">function</span><span class="p">(</span><span class="nx">ev</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-35-12" name="__codelineno-35-12" href="#__codelineno-35-12"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">ev</span><span class="p">.</span><span class="nx">target</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">ev</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">id</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s1">&#39;my-button&#39;</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-35-13" name="__codelineno-35-13" href="#__codelineno-35-13"></a><span class="w"> </span><span class="nx">self</span><span class="p">.</span><span class="nx">handleButtonClick</span><span class="p">();</span>
<a id="__codelineno-35-14" name="__codelineno-35-14" href="#__codelineno-35-14"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-35-15" name="__codelineno-35-15" href="#__codelineno-35-15"></a><span class="w"> </span><span class="p">});</span>
<a id="__codelineno-35-16" name="__codelineno-35-16" href="#__codelineno-35-16"></a>
<a id="__codelineno-35-17" name="__codelineno-35-17" href="#__codelineno-35-17"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">container</span><span class="p">;</span>
<a id="__codelineno-35-18" name="__codelineno-35-18" href="#__codelineno-35-18"></a><span class="p">},</span>
<a id="__codelineno-35-19" name="__codelineno-35-19" href="#__codelineno-35-19"></a>
<a id="__codelineno-35-20" name="__codelineno-35-20" href="#__codelineno-35-20"></a><span class="nx">handleButtonClick</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-35-21" name="__codelineno-35-21" href="#__codelineno-35-21"></a><span class="w"> </span><span class="nx">ui</span><span class="p">.</span><span class="nx">addNotification</span><span class="p">(</span><span class="kc">null</span><span class="p">,</span><span class="w"> </span><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;p&#39;</span><span class="p">,</span><span class="w"> </span><span class="s1">&#39;Button clicked!&#39;</span><span class="p">),</span><span class="w"> </span><span class="s1">&#39;info&#39;</span><span class="p">);</span>
<a id="__codelineno-35-22" name="__codelineno-35-22" href="#__codelineno-35-22"></a><span class="p">}</span>
</code></pre></div>
<h3 id="common-javascript-errors">Common JavaScript Errors<a class="headerlink" href="#common-javascript-errors" title="Permanent link">&para;</a></h3>
<h4 id="error-object-htmlbuttonelement-affiche">Error: "[object HTMLButtonElement]" affiché<a class="headerlink" href="#error-object-htmlbuttonelement-affiche" title="Permanent link">&para;</a></h4>
<p><strong>Cause:</strong> Array imbriqué quand E() attend un array simple</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-36-1" name="__codelineno-36-1" href="#__codelineno-36-1"></a><span class="c1">// ❌ INCORRECT</span>
<a id="__codelineno-36-2" name="__codelineno-36-2" href="#__codelineno-36-2"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{},</span><span class="w"> </span><span class="p">[</span>
<a id="__codelineno-36-3" name="__codelineno-36-3" href="#__codelineno-36-3"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">renderButtons</span><span class="p">()</span><span class="w"> </span><span class="c1">// renderButtons retourne déjà un array</span>
<a id="__codelineno-36-4" name="__codelineno-36-4" href="#__codelineno-36-4"></a><span class="p">])</span>
<a id="__codelineno-36-5" name="__codelineno-36-5" href="#__codelineno-36-5"></a>
<a id="__codelineno-36-6" name="__codelineno-36-6" href="#__codelineno-36-6"></a><span class="c1">// ✅ CORRECT</span>
<a id="__codelineno-36-7" name="__codelineno-36-7" href="#__codelineno-36-7"></a><span class="nx">E</span><span class="p">(</span><span class="s1">&#39;div&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">{},</span>
<a id="__codelineno-36-8" name="__codelineno-36-8" href="#__codelineno-36-8"></a><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">renderButtons</span><span class="p">()</span><span class="w"> </span><span class="c1">// Pas de [ ] supplémentaire</span>
<a id="__codelineno-36-9" name="__codelineno-36-9" href="#__codelineno-36-9"></a><span class="p">)</span>
</code></pre></div>
<h4 id="error-cannot-read-property-of-undefined">Error: "Cannot read property of undefined"<a class="headerlink" href="#error-cannot-read-property-of-undefined" title="Permanent link">&para;</a></h4>
<p><strong>Cause:</strong> Données API non disponibles</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-37-1" name="__codelineno-37-1" href="#__codelineno-37-1"></a><span class="c1">// ❌ INCORRECT</span>
<a id="__codelineno-37-2" name="__codelineno-37-2" href="#__codelineno-37-2"></a><span class="kd">var</span><span class="w"> </span><span class="nx">cpuUsage</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">healthData</span><span class="p">.</span><span class="nx">cpu</span><span class="p">.</span><span class="nx">usage</span><span class="p">;</span>
<a id="__codelineno-37-3" name="__codelineno-37-3" href="#__codelineno-37-3"></a>
<a id="__codelineno-37-4" name="__codelineno-37-4" href="#__codelineno-37-4"></a><span class="c1">// ✅ CORRECT (avec optional chaining)</span>
<a id="__codelineno-37-5" name="__codelineno-37-5" href="#__codelineno-37-5"></a><span class="kd">var</span><span class="w"> </span><span class="nx">cpuUsage</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">healthData</span><span class="p">.</span><span class="nx">cpu</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">healthData</span><span class="p">.</span><span class="nx">cpu</span><span class="p">.</span><span class="nx">usage</span><span class="p">)</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="mf">0</span><span class="p">;</span>
<a id="__codelineno-37-6" name="__codelineno-37-6" href="#__codelineno-37-6"></a><span class="c1">// ou</span>
<a id="__codelineno-37-7" name="__codelineno-37-7" href="#__codelineno-37-7"></a><span class="kd">var</span><span class="w"> </span><span class="nx">cpuUsage</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="nx">healthData</span><span class="p">.</span><span class="nx">cpu</span><span class="o">?</span><span class="p">.</span><span class="nx">usage</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="mf">0</span><span class="p">;</span><span class="w"> </span><span class="c1">// ES2020</span>
</code></pre></div>
<h4 id="error-poll-callback-failed">Error: "poll callback failed"<a class="headerlink" href="#error-poll-callback-failed" title="Permanent link">&para;</a></h4>
<p><strong>Cause:</strong> Promise non retournée dans poll.add</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-38-1" name="__codelineno-38-1" href="#__codelineno-38-1"></a><span class="c1">// ❌ INCORRECT</span>
<a id="__codelineno-38-2" name="__codelineno-38-2" href="#__codelineno-38-2"></a><span class="nx">poll</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-38-3" name="__codelineno-38-3" href="#__codelineno-38-3"></a><span class="w"> </span><span class="nx">API</span><span class="p">.</span><span class="nx">getHealth</span><span class="p">();</span><span class="w"> </span><span class="c1">// Pas de return!</span>
<a id="__codelineno-38-4" name="__codelineno-38-4" href="#__codelineno-38-4"></a><span class="p">},</span><span class="w"> </span><span class="mf">30</span><span class="p">);</span>
<a id="__codelineno-38-5" name="__codelineno-38-5" href="#__codelineno-38-5"></a>
<a id="__codelineno-38-6" name="__codelineno-38-6" href="#__codelineno-38-6"></a><span class="c1">// ✅ CORRECT</span>
<a id="__codelineno-38-7" name="__codelineno-38-7" href="#__codelineno-38-7"></a><span class="nx">poll</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-38-8" name="__codelineno-38-8" href="#__codelineno-38-8"></a><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">API</span><span class="p">.</span><span class="nx">getHealth</span><span class="p">().</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-38-9" name="__codelineno-38-9" href="#__codelineno-38-9"></a><span class="w"> </span><span class="c1">// Update UI</span>
<a id="__codelineno-38-10" name="__codelineno-38-10" href="#__codelineno-38-10"></a><span class="w"> </span><span class="p">});</span>
<a id="__codelineno-38-11" name="__codelineno-38-11" href="#__codelineno-38-11"></a><span class="p">},</span><span class="w"> </span><span class="mf">30</span><span class="p">);</span>
</code></pre></div>
<hr />
<h2 id="cssstyling-standards">CSS/Styling Standards<a class="headerlink" href="#cssstyling-standards" title="Permanent link">&para;</a></h2>
<h3 id="file-organization">File Organization<a class="headerlink" href="#file-organization" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><a id="__codelineno-39-1" name="__codelineno-39-1" href="#__codelineno-39-1"></a>&lt;module-name&gt;/
<a id="__codelineno-39-2" name="__codelineno-39-2" href="#__codelineno-39-2"></a>├── common.css # Shared components (headers, buttons, cards, tabs)
<a id="__codelineno-39-3" name="__codelineno-39-3" href="#__codelineno-39-3"></a>├── overview.css # Overview page specific
<a id="__codelineno-39-4" name="__codelineno-39-4" href="#__codelineno-39-4"></a>├── services.css # Services page specific
<a id="__codelineno-39-5" name="__codelineno-39-5" href="#__codelineno-39-5"></a>└── *.css # Other page-specific styles
</code></pre></div>
<h3 id="css-file-template">CSS File Template<a class="headerlink" href="#css-file-template" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><a id="__codelineno-40-1" name="__codelineno-40-1" href="#__codelineno-40-1"></a><span class="c">/**</span>
<a id="__codelineno-40-2" name="__codelineno-40-2" href="#__codelineno-40-2"></a><span class="c"> * Module Name - Page/Component Styles</span>
<a id="__codelineno-40-3" name="__codelineno-40-3" href="#__codelineno-40-3"></a><span class="c"> * Description of what this file styles</span>
<a id="__codelineno-40-4" name="__codelineno-40-4" href="#__codelineno-40-4"></a><span class="c"> * Version: X.Y.Z</span>
<a id="__codelineno-40-5" name="__codelineno-40-5" href="#__codelineno-40-5"></a><span class="c"> */</span>
<a id="__codelineno-40-6" name="__codelineno-40-6" href="#__codelineno-40-6"></a>
<a id="__codelineno-40-7" name="__codelineno-40-7" href="#__codelineno-40-7"></a><span class="c">/* === Import shared styles (if needed) === */</span>
<a id="__codelineno-40-8" name="__codelineno-40-8" href="#__codelineno-40-8"></a><span class="c">/* Not required if loaded in HTML */</span>
<a id="__codelineno-40-9" name="__codelineno-40-9" href="#__codelineno-40-9"></a>
<a id="__codelineno-40-10" name="__codelineno-40-10" href="#__codelineno-40-10"></a><span class="c">/* === Page-specific variables (if needed) === */</span>
<a id="__codelineno-40-11" name="__codelineno-40-11" href="#__codelineno-40-11"></a><span class="p">:</span><span class="nd">root</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-40-12" name="__codelineno-40-12" href="#__codelineno-40-12"></a><span class="w"> </span><span class="nv">--page-specific-var</span><span class="p">:</span><span class="w"> </span><span class="n">value</span><span class="p">;</span>
<a id="__codelineno-40-13" name="__codelineno-40-13" href="#__codelineno-40-13"></a><span class="p">}</span>
<a id="__codelineno-40-14" name="__codelineno-40-14" href="#__codelineno-40-14"></a>
<a id="__codelineno-40-15" name="__codelineno-40-15" href="#__codelineno-40-15"></a><span class="c">/* === Layout === */</span>
<a id="__codelineno-40-16" name="__codelineno-40-16" href="#__codelineno-40-16"></a><span class="p">.</span><span class="nc">module-page-container</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-40-17" name="__codelineno-40-17" href="#__codelineno-40-17"></a><span class="w"> </span><span class="c">/* Layout styles */</span>
<a id="__codelineno-40-18" name="__codelineno-40-18" href="#__codelineno-40-18"></a><span class="p">}</span>
<a id="__codelineno-40-19" name="__codelineno-40-19" href="#__codelineno-40-19"></a>
<a id="__codelineno-40-20" name="__codelineno-40-20" href="#__codelineno-40-20"></a><span class="c">/* === Components === */</span>
<a id="__codelineno-40-21" name="__codelineno-40-21" href="#__codelineno-40-21"></a><span class="p">.</span><span class="nc">module-component</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-40-22" name="__codelineno-40-22" href="#__codelineno-40-22"></a><span class="w"> </span><span class="c">/* Component styles */</span>
<a id="__codelineno-40-23" name="__codelineno-40-23" href="#__codelineno-40-23"></a><span class="p">}</span>
<a id="__codelineno-40-24" name="__codelineno-40-24" href="#__codelineno-40-24"></a>
<a id="__codelineno-40-25" name="__codelineno-40-25" href="#__codelineno-40-25"></a><span class="c">/* === Responsive === */</span>
<a id="__codelineno-40-26" name="__codelineno-40-26" href="#__codelineno-40-26"></a><span class="p">@</span><span class="k">media</span><span class="w"> </span><span class="o">(</span><span class="nt">max-width</span><span class="o">:</span><span class="w"> </span><span class="nt">768px</span><span class="o">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-40-27" name="__codelineno-40-27" href="#__codelineno-40-27"></a><span class="w"> </span><span class="c">/* Mobile styles */</span>
<a id="__codelineno-40-28" name="__codelineno-40-28" href="#__codelineno-40-28"></a><span class="p">}</span>
<a id="__codelineno-40-29" name="__codelineno-40-29" href="#__codelineno-40-29"></a>
<a id="__codelineno-40-30" name="__codelineno-40-30" href="#__codelineno-40-30"></a><span class="c">/* === Dark Mode Overrides === */</span>
<a id="__codelineno-40-31" name="__codelineno-40-31" href="#__codelineno-40-31"></a><span class="o">[</span><span class="nt">data-theme</span><span class="o">=</span><span class="s2">&quot;dark&quot;</span><span class="o">]</span><span class="w"> </span><span class="p">.</span><span class="nc">module-component</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-40-32" name="__codelineno-40-32" href="#__codelineno-40-32"></a><span class="w"> </span><span class="c">/* Dark mode specific */</span>
<a id="__codelineno-40-33" name="__codelineno-40-33" href="#__codelineno-40-33"></a><span class="p">}</span>
</code></pre></div>
<h3 id="css-best-practices">CSS Best Practices<a class="headerlink" href="#css-best-practices" title="Permanent link">&para;</a></h3>
<h4 id="1-toujours-utiliser-les-variables-css">1. TOUJOURS utiliser les variables CSS<a class="headerlink" href="#1-toujours-utiliser-les-variables-css" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-41-1" name="__codelineno-41-1" href="#__codelineno-41-1"></a><span class="c">/* ❌ INCORRECT */</span>
<a id="__codelineno-41-2" name="__codelineno-41-2" href="#__codelineno-41-2"></a><span class="p">.</span><span class="nc">my-card</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-41-3" name="__codelineno-41-3" href="#__codelineno-41-3"></a><span class="w"> </span><span class="k">background</span><span class="p">:</span><span class="w"> </span><span class="mh">#12121a</span><span class="p">;</span>
<a id="__codelineno-41-4" name="__codelineno-41-4" href="#__codelineno-41-4"></a><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="mh">#fafafa</span><span class="p">;</span>
<a id="__codelineno-41-5" name="__codelineno-41-5" href="#__codelineno-41-5"></a><span class="p">}</span>
<a id="__codelineno-41-6" name="__codelineno-41-6" href="#__codelineno-41-6"></a>
<a id="__codelineno-41-7" name="__codelineno-41-7" href="#__codelineno-41-7"></a><span class="c">/* ✅ CORRECT */</span>
<a id="__codelineno-41-8" name="__codelineno-41-8" href="#__codelineno-41-8"></a><span class="p">.</span><span class="nc">my-card</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-41-9" name="__codelineno-41-9" href="#__codelineno-41-9"></a><span class="w"> </span><span class="k">background</span><span class="p">:</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--sh-bg-card</span><span class="p">);</span>
<a id="__codelineno-41-10" name="__codelineno-41-10" href="#__codelineno-41-10"></a><span class="w"> </span><span class="k">color</span><span class="p">:</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--sh-text-primary</span><span class="p">);</span>
<a id="__codelineno-41-11" name="__codelineno-41-11" href="#__codelineno-41-11"></a><span class="p">}</span>
</code></pre></div>
<h4 id="2-prefix-classes-par-module">2. Prefix classes par module<a class="headerlink" href="#2-prefix-classes-par-module" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-42-1" name="__codelineno-42-1" href="#__codelineno-42-1"></a><span class="c">/* System Hub */</span>
<a id="__codelineno-42-2" name="__codelineno-42-2" href="#__codelineno-42-2"></a><span class="p">.</span><span class="nc">sh-page-header</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-42-3" name="__codelineno-42-3" href="#__codelineno-42-3"></a><span class="p">.</span><span class="nc">sh-card</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-42-4" name="__codelineno-42-4" href="#__codelineno-42-4"></a><span class="p">.</span><span class="nc">sh-btn</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-42-5" name="__codelineno-42-5" href="#__codelineno-42-5"></a>
<a id="__codelineno-42-6" name="__codelineno-42-6" href="#__codelineno-42-6"></a><span class="c">/* SecuBox */</span>
<a id="__codelineno-42-7" name="__codelineno-42-7" href="#__codelineno-42-7"></a><span class="p">.</span><span class="nc">sb-module-grid</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-42-8" name="__codelineno-42-8" href="#__codelineno-42-8"></a><span class="p">.</span><span class="nc">sb-dashboard</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-42-9" name="__codelineno-42-9" href="#__codelineno-42-9"></a>
<a id="__codelineno-42-10" name="__codelineno-42-10" href="#__codelineno-42-10"></a><span class="c">/* Module spécifique */</span>
<a id="__codelineno-42-11" name="__codelineno-42-11" href="#__codelineno-42-11"></a><span class="p">.</span><span class="nc">netdata-chart</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-42-12" name="__codelineno-42-12" href="#__codelineno-42-12"></a><span class="p">.</span><span class="nc">crowdsec-alert</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">}</span>
</code></pre></div>
<h4 id="3-transitions-coherentes">3. Transitions cohérentes<a class="headerlink" href="#3-transitions-coherentes" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-43-1" name="__codelineno-43-1" href="#__codelineno-43-1"></a><span class="c">/* Standard transition */</span>
<a id="__codelineno-43-2" name="__codelineno-43-2" href="#__codelineno-43-2"></a><span class="nt">transition</span><span class="o">:</span><span class="w"> </span><span class="nt">all</span><span class="w"> </span><span class="nt">0</span><span class="p">.</span><span class="nc">3s</span><span class="w"> </span><span class="nt">cubic-bezier</span><span class="o">(</span><span class="nt">0</span><span class="p">.</span><span class="nc">4</span><span class="o">,</span><span class="w"> </span><span class="nt">0</span><span class="o">,</span><span class="w"> </span><span class="nt">0</span><span class="p">.</span><span class="nc">2</span><span class="o">,</span><span class="w"> </span><span class="nt">1</span><span class="o">);</span>
<a id="__codelineno-43-3" name="__codelineno-43-3" href="#__codelineno-43-3"></a>
<a id="__codelineno-43-4" name="__codelineno-43-4" href="#__codelineno-43-4"></a><span class="c">/* Quick transition (hover states) */</span>
<a id="__codelineno-43-5" name="__codelineno-43-5" href="#__codelineno-43-5"></a><span class="nt">transition</span><span class="o">:</span><span class="w"> </span><span class="nt">all</span><span class="w"> </span><span class="nt">0</span><span class="p">.</span><span class="nc">2s</span><span class="w"> </span><span class="nt">ease</span><span class="o">;</span>
<a id="__codelineno-43-6" name="__codelineno-43-6" href="#__codelineno-43-6"></a>
<a id="__codelineno-43-7" name="__codelineno-43-7" href="#__codelineno-43-7"></a><span class="c">/* Smooth transition (large movements) */</span>
<a id="__codelineno-43-8" name="__codelineno-43-8" href="#__codelineno-43-8"></a><span class="nt">transition</span><span class="o">:</span><span class="w"> </span><span class="nt">all</span><span class="w"> </span><span class="nt">0</span><span class="p">.</span><span class="nc">5s</span><span class="w"> </span><span class="nt">ease</span><span class="o">;</span>
</code></pre></div>
<h4 id="4-responsive-breakpoints">4. Responsive breakpoints<a class="headerlink" href="#4-responsive-breakpoints" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-44-1" name="__codelineno-44-1" href="#__codelineno-44-1"></a><span class="c">/* Mobile */</span>
<a id="__codelineno-44-2" name="__codelineno-44-2" href="#__codelineno-44-2"></a><span class="p">@</span><span class="k">media</span><span class="w"> </span><span class="o">(</span><span class="nt">max-width</span><span class="o">:</span><span class="w"> </span><span class="nt">768px</span><span class="o">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-44-3" name="__codelineno-44-3" href="#__codelineno-44-3"></a><span class="w"> </span><span class="p">.</span><span class="nc">sh-stats-grid</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-44-4" name="__codelineno-44-4" href="#__codelineno-44-4"></a><span class="w"> </span><span class="k">grid-template-columns</span><span class="p">:</span><span class="w"> </span><span class="nf">repeat</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">1</span><span class="n">fr</span><span class="p">);</span>
<a id="__codelineno-44-5" name="__codelineno-44-5" href="#__codelineno-44-5"></a><span class="w"> </span><span class="p">}</span>
<a id="__codelineno-44-6" name="__codelineno-44-6" href="#__codelineno-44-6"></a><span class="p">}</span>
<a id="__codelineno-44-7" name="__codelineno-44-7" href="#__codelineno-44-7"></a>
<a id="__codelineno-44-8" name="__codelineno-44-8" href="#__codelineno-44-8"></a><span class="c">/* Tablet */</span>
<a id="__codelineno-44-9" name="__codelineno-44-9" href="#__codelineno-44-9"></a><span class="p">@</span><span class="k">media</span><span class="w"> </span><span class="o">(</span><span class="nt">min-width</span><span class="o">:</span><span class="w"> </span><span class="nt">769px</span><span class="o">)</span><span class="w"> </span><span class="nt">and</span><span class="w"> </span><span class="o">(</span><span class="nt">max-width</span><span class="o">:</span><span class="w"> </span><span class="nt">1024px</span><span class="o">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-44-10" name="__codelineno-44-10" href="#__codelineno-44-10"></a><span class="w"> </span><span class="c">/* Tablet specific */</span>
<a id="__codelineno-44-11" name="__codelineno-44-11" href="#__codelineno-44-11"></a><span class="p">}</span>
<a id="__codelineno-44-12" name="__codelineno-44-12" href="#__codelineno-44-12"></a>
<a id="__codelineno-44-13" name="__codelineno-44-13" href="#__codelineno-44-13"></a><span class="c">/* Desktop */</span>
<a id="__codelineno-44-14" name="__codelineno-44-14" href="#__codelineno-44-14"></a><span class="p">@</span><span class="k">media</span><span class="w"> </span><span class="o">(</span><span class="nt">min-width</span><span class="o">:</span><span class="w"> </span><span class="nt">1025px</span><span class="o">)</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-44-15" name="__codelineno-44-15" href="#__codelineno-44-15"></a><span class="w"> </span><span class="c">/* Desktop specific */</span>
<a id="__codelineno-44-16" name="__codelineno-44-16" href="#__codelineno-44-16"></a><span class="p">}</span>
</code></pre></div>
<h4 id="5-dark-mode-obligatoire">5. Dark mode OBLIGATOIRE<a class="headerlink" href="#5-dark-mode-obligatoire" title="Permanent link">&para;</a></h4>
<p><strong>Toujours fournir des styles dark mode:</strong></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-45-1" name="__codelineno-45-1" href="#__codelineno-45-1"></a><span class="c">/* Light mode (default) */</span>
<a id="__codelineno-45-2" name="__codelineno-45-2" href="#__codelineno-45-2"></a><span class="p">.</span><span class="nc">my-component</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-45-3" name="__codelineno-45-3" href="#__codelineno-45-3"></a><span class="w"> </span><span class="k">background</span><span class="p">:</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--sh-bg-card</span><span class="p">);</span>
<a id="__codelineno-45-4" name="__codelineno-45-4" href="#__codelineno-45-4"></a><span class="w"> </span><span class="k">border</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="kt">px</span><span class="w"> </span><span class="kc">solid</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--sh-border</span><span class="p">);</span>
<a id="__codelineno-45-5" name="__codelineno-45-5" href="#__codelineno-45-5"></a><span class="p">}</span>
<a id="__codelineno-45-6" name="__codelineno-45-6" href="#__codelineno-45-6"></a>
<a id="__codelineno-45-7" name="__codelineno-45-7" href="#__codelineno-45-7"></a><span class="c">/* Dark mode override */</span>
<a id="__codelineno-45-8" name="__codelineno-45-8" href="#__codelineno-45-8"></a><span class="o">[</span><span class="nt">data-theme</span><span class="o">=</span><span class="s2">&quot;dark&quot;</span><span class="o">]</span><span class="w"> </span><span class="p">.</span><span class="nc">my-component</span><span class="w"> </span><span class="p">{</span>
<a id="__codelineno-45-9" name="__codelineno-45-9" href="#__codelineno-45-9"></a><span class="w"> </span><span class="k">background</span><span class="p">:</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--sh-bg-card</span><span class="p">);</span>
<a id="__codelineno-45-10" name="__codelineno-45-10" href="#__codelineno-45-10"></a><span class="w"> </span><span class="k">border-color</span><span class="p">:</span><span class="w"> </span><span class="nf">var</span><span class="p">(</span><span class="nv">--sh-border</span><span class="p">);</span>
<a id="__codelineno-45-11" name="__codelineno-45-11" href="#__codelineno-45-11"></a><span class="p">}</span>
</code></pre></div>
<h3 id="z-index-scale">Z-index Scale<a class="headerlink" href="#z-index-scale" title="Permanent link">&para;</a></h3>
<p><strong>Respecter cette échelle:</strong></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-46-1" name="__codelineno-46-1" href="#__codelineno-46-1"></a><span class="nt">--z-base</span><span class="o">:</span><span class="w"> </span><span class="nt">0</span><span class="o">;</span>
<a id="__codelineno-46-2" name="__codelineno-46-2" href="#__codelineno-46-2"></a><span class="nt">--z-dropdown</span><span class="o">:</span><span class="w"> </span><span class="nt">100</span><span class="o">;</span>
<a id="__codelineno-46-3" name="__codelineno-46-3" href="#__codelineno-46-3"></a><span class="nt">--z-sticky</span><span class="o">:</span><span class="w"> </span><span class="nt">200</span><span class="o">;</span>
<a id="__codelineno-46-4" name="__codelineno-46-4" href="#__codelineno-46-4"></a><span class="nt">--z-fixed</span><span class="o">:</span><span class="w"> </span><span class="nt">300</span><span class="o">;</span>
<a id="__codelineno-46-5" name="__codelineno-46-5" href="#__codelineno-46-5"></a><span class="nt">--z-modal-backdrop</span><span class="o">:</span><span class="w"> </span><span class="nt">400</span><span class="o">;</span>
<a id="__codelineno-46-6" name="__codelineno-46-6" href="#__codelineno-46-6"></a><span class="nt">--z-modal</span><span class="o">:</span><span class="w"> </span><span class="nt">500</span><span class="o">;</span>
<a id="__codelineno-46-7" name="__codelineno-46-7" href="#__codelineno-46-7"></a><span class="nt">--z-popover</span><span class="o">:</span><span class="w"> </span><span class="nt">600</span><span class="o">;</span>
<a id="__codelineno-46-8" name="__codelineno-46-8" href="#__codelineno-46-8"></a><span class="nt">--z-tooltip</span><span class="o">:</span><span class="w"> </span><span class="nt">700</span><span class="o">;</span>
</code></pre></div>
<hr />
<h2 id="common-errors-solutions">Common Errors &amp; Solutions<a class="headerlink" href="#common-errors-solutions" title="Permanent link">&para;</a></h2>
<h3 id="1-rpcd-object-not-found-32000">1. RPCD Object Not Found (-32000)<a class="headerlink" href="#1-rpcd-object-not-found-32000" title="Permanent link">&para;</a></h3>
<p><strong>Erreur complète:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-47-1" name="__codelineno-47-1" href="#__codelineno-47-1"></a>RPC call to luci.system-hub/getHealth failed with error -32000: Object not found
</code></pre></div></p>
<p><strong>Diagnostic:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-48-1" name="__codelineno-48-1" href="#__codelineno-48-1"></a><span class="c1"># 1. Vérifier que le fichier RPCD existe</span>
<a id="__codelineno-48-2" name="__codelineno-48-2" href="#__codelineno-48-2"></a>ls<span class="w"> </span>-la<span class="w"> </span>/usr/libexec/rpcd/luci.system-hub
<a id="__codelineno-48-3" name="__codelineno-48-3" href="#__codelineno-48-3"></a>
<a id="__codelineno-48-4" name="__codelineno-48-4" href="#__codelineno-48-4"></a><span class="c1"># 2. Vérifier qu&#39;il est exécutable</span>
<a id="__codelineno-48-5" name="__codelineno-48-5" href="#__codelineno-48-5"></a>chmod<span class="w"> </span>+x<span class="w"> </span>/usr/libexec/rpcd/luci.system-hub
<a id="__codelineno-48-6" name="__codelineno-48-6" href="#__codelineno-48-6"></a>
<a id="__codelineno-48-7" name="__codelineno-48-7" href="#__codelineno-48-7"></a><span class="c1"># 3. Lister les objets ubus</span>
<a id="__codelineno-48-8" name="__codelineno-48-8" href="#__codelineno-48-8"></a>ubus<span class="w"> </span>list<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>system-hub
<a id="__codelineno-48-9" name="__codelineno-48-9" href="#__codelineno-48-9"></a>
<a id="__codelineno-48-10" name="__codelineno-48-10" href="#__codelineno-48-10"></a><span class="c1"># 4. Si absent, redémarrer RPCD</span>
<a id="__codelineno-48-11" name="__codelineno-48-11" href="#__codelineno-48-11"></a>/etc/init.d/rpcd<span class="w"> </span>restart
<a id="__codelineno-48-12" name="__codelineno-48-12" href="#__codelineno-48-12"></a>ubus<span class="w"> </span>list<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>system-hub
</code></pre></div></p>
<p><strong>Solutions:</strong>
1. Renommer le fichier RPCD pour correspondre exactement
2. Vérifier permissions (755 ou rwxr-xr-x)
3. Redémarrer rpcd</p>
<h3 id="2-view-not-found-404">2. View Not Found (404)<a class="headerlink" href="#2-view-not-found-404" title="Permanent link">&para;</a></h3>
<p><strong>Erreur:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-49-1" name="__codelineno-49-1" href="#__codelineno-49-1"></a>HTTP error 404 while loading class file &#39;/luci-static/resources/view/system-hub/overview.js&#39;
</code></pre></div></p>
<p><strong>Diagnostic:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-50-1" name="__codelineno-50-1" href="#__codelineno-50-1"></a><span class="c1"># 1. Vérifier que le fichier existe</span>
<a id="__codelineno-50-2" name="__codelineno-50-2" href="#__codelineno-50-2"></a>ls<span class="w"> </span>-la<span class="w"> </span>/www/luci-static/resources/view/system-hub/overview.js
<a id="__codelineno-50-3" name="__codelineno-50-3" href="#__codelineno-50-3"></a>
<a id="__codelineno-50-4" name="__codelineno-50-4" href="#__codelineno-50-4"></a><span class="c1"># 2. Vérifier le chemin dans menu.d</span>
<a id="__codelineno-50-5" name="__codelineno-50-5" href="#__codelineno-50-5"></a>grep<span class="w"> </span><span class="s2">&quot;path&quot;</span><span class="w"> </span>/usr/share/luci/menu.d/luci-app-system-hub.json
</code></pre></div></p>
<p><strong>Solutions:</strong>
1. Vérifier que le path dans menu JSON correspond au fichier
2. Vérifier permissions du fichier (644)
3. Nettoyer cache: <code>rm -f /tmp/luci-indexcache /tmp/luci-modulecache/*</code></p>
<h3 id="3-css-not-loading-403-forbidden">3. CSS Not Loading (403 Forbidden)<a class="headerlink" href="#3-css-not-loading-403-forbidden" title="Permanent link">&para;</a></h3>
<p><strong>Erreur:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-51-1" name="__codelineno-51-1" href="#__codelineno-51-1"></a>GET /luci-static/resources/system-hub/common.css 403 Forbidden
</code></pre></div></p>
<p><strong>Diagnostic:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-52-1" name="__codelineno-52-1" href="#__codelineno-52-1"></a><span class="c1"># Vérifier permissions</span>
<a id="__codelineno-52-2" name="__codelineno-52-2" href="#__codelineno-52-2"></a>ls<span class="w"> </span>-la<span class="w"> </span>/www/luci-static/resources/system-hub/common.css
</code></pre></div></p>
<p><strong>Solution:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-53-1" name="__codelineno-53-1" href="#__codelineno-53-1"></a><span class="c1"># Corriger permissions</span>
<a id="__codelineno-53-2" name="__codelineno-53-2" href="#__codelineno-53-2"></a>chmod<span class="w"> </span><span class="m">644</span><span class="w"> </span>/www/luci-static/resources/system-hub/*.css
</code></pre></div></p>
<h3 id="4-invalid-json-from-rpcd">4. Invalid JSON from RPCD<a class="headerlink" href="#4-invalid-json-from-rpcd" title="Permanent link">&para;</a></h3>
<p><strong>Erreur dans browser console:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-54-1" name="__codelineno-54-1" href="#__codelineno-54-1"></a>SyntaxError: Unexpected token in JSON at position X
</code></pre></div></p>
<p><strong>Diagnostic:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-55-1" name="__codelineno-55-1" href="#__codelineno-55-1"></a><span class="c1"># Tester le JSON directement</span>
<a id="__codelineno-55-2" name="__codelineno-55-2" href="#__codelineno-55-2"></a>/usr/libexec/rpcd/luci.system-hub<span class="w"> </span>call<span class="w"> </span>getHealth<span class="w"> </span><span class="p">|</span><span class="w"> </span>jsonlint
<a id="__codelineno-55-3" name="__codelineno-55-3" href="#__codelineno-55-3"></a>
<a id="__codelineno-55-4" name="__codelineno-55-4" href="#__codelineno-55-4"></a><span class="c1"># Ou avec jq</span>
<a id="__codelineno-55-5" name="__codelineno-55-5" href="#__codelineno-55-5"></a>/usr/libexec/rpcd/luci.system-hub<span class="w"> </span>call<span class="w"> </span>getHealth<span class="w"> </span><span class="p">|</span><span class="w"> </span>jq<span class="w"> </span>.
</code></pre></div></p>
<p><strong>Solutions courantes:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-56-1" name="__codelineno-56-1" href="#__codelineno-56-1"></a><span class="c1"># ❌ INCORRECT - Quote simple non échappée</span>
<a id="__codelineno-56-2" name="__codelineno-56-2" href="#__codelineno-56-2"></a><span class="nb">echo</span><span class="w"> </span><span class="s1">&#39;{&quot;error&quot;: &quot;can&#39;</span>t<span class="w"> </span>process<span class="s2">&quot;}&#39;</span>
<a id="__codelineno-56-3" name="__codelineno-56-3" href="#__codelineno-56-3"></a>
<a id="__codelineno-56-4" name="__codelineno-56-4" href="#__codelineno-56-4"></a><span class="s2"># ✅ CORRECT - Utiliser printf et doubles quotes</span>
<a id="__codelineno-56-5" name="__codelineno-56-5" href="#__codelineno-56-5"></a><span class="s2">printf &#39;{&quot;</span>error<span class="s2">&quot;: &quot;</span>cannot<span class="w"> </span>process<span class="s2">&quot;}\n&#39;</span>
<a id="__codelineno-56-6" name="__codelineno-56-6" href="#__codelineno-56-6"></a>
<a id="__codelineno-56-7" name="__codelineno-56-7" href="#__codelineno-56-7"></a><span class="s2"># ❌ INCORRECT - Variable non quotée</span>
<a id="__codelineno-56-8" name="__codelineno-56-8" href="#__codelineno-56-8"></a><span class="s2">echo &quot;</span><span class="o">{</span><span class="se">\&quot;</span>value<span class="se">\&quot;</span>:<span class="w"> </span><span class="nv">$var</span><span class="o">}</span><span class="s2">&quot;</span>
<a id="__codelineno-56-9" name="__codelineno-56-9" href="#__codelineno-56-9"></a>
<a id="__codelineno-56-10" name="__codelineno-56-10" href="#__codelineno-56-10"></a><span class="s2"># ✅ CORRECT - Variable quotée</span>
<a id="__codelineno-56-11" name="__codelineno-56-11" href="#__codelineno-56-11"></a><span class="s2">printf &#39;{&quot;</span>value<span class="s2">&quot;: &quot;</span>%s<span class="s2">&quot;}\n&#39; &quot;</span><span class="nv">$var</span><span class="s2">&quot;</span>
</code></pre></div></p>
<h3 id="5-browser-cache-issues">5. Browser Cache Issues<a class="headerlink" href="#5-browser-cache-issues" title="Permanent link">&para;</a></h3>
<p><strong>Symptômes:</strong>
- Changements CSS/JS non visibles
- Anciennes données affichées
- Code mis à jour mais interface identique</p>
<p><strong>Solutions:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-57-1" name="__codelineno-57-1" href="#__codelineno-57-1"></a><span class="c1"># 1. Côté serveur - nettoyer cache LuCI</span>
<a id="__codelineno-57-2" name="__codelineno-57-2" href="#__codelineno-57-2"></a>ssh<span class="w"> </span>root@router<span class="w"> </span><span class="s2">&quot;rm -f /tmp/luci-indexcache /tmp/luci-modulecache/* &amp;&amp; /etc/init.d/uhttpd restart&quot;</span>
<a id="__codelineno-57-3" name="__codelineno-57-3" href="#__codelineno-57-3"></a>
<a id="__codelineno-57-4" name="__codelineno-57-4" href="#__codelineno-57-4"></a><span class="c1"># 2. Côté client - hard refresh</span>
<a id="__codelineno-57-5" name="__codelineno-57-5" href="#__codelineno-57-5"></a>Ctrl<span class="w"> </span>+<span class="w"> </span>Shift<span class="w"> </span>+<span class="w"> </span>R<span class="w"> </span><span class="o">(</span>Chrome/Firefox<span class="o">)</span>
<a id="__codelineno-57-6" name="__codelineno-57-6" href="#__codelineno-57-6"></a>Ctrl<span class="w"> </span>+<span class="w"> </span>F5<span class="w"> </span><span class="o">(</span>Windows<span class="o">)</span>
<a id="__codelineno-57-7" name="__codelineno-57-7" href="#__codelineno-57-7"></a>Cmd<span class="w"> </span>+<span class="w"> </span>Shift<span class="w"> </span>+<span class="w"> </span>R<span class="w"> </span><span class="o">(</span>Mac<span class="o">)</span>
<a id="__codelineno-57-8" name="__codelineno-57-8" href="#__codelineno-57-8"></a>
<a id="__codelineno-57-9" name="__codelineno-57-9" href="#__codelineno-57-9"></a><span class="c1"># 3. Mode privé/incognito pour test</span>
<a id="__codelineno-57-10" name="__codelineno-57-10" href="#__codelineno-57-10"></a>Ctrl<span class="w"> </span>+<span class="w"> </span>Shift<span class="w"> </span>+<span class="w"> </span>N<span class="w"> </span><span class="o">(</span>Chrome<span class="o">)</span>
<a id="__codelineno-57-11" name="__codelineno-57-11" href="#__codelineno-57-11"></a>Ctrl<span class="w"> </span>+<span class="w"> </span>Shift<span class="w"> </span>+<span class="w"> </span>P<span class="w"> </span><span class="o">(</span>Firefox<span class="o">)</span>
</code></pre></div></p>
<h3 id="6-acl-access-denied">6. ACL Access Denied<a class="headerlink" href="#6-acl-access-denied" title="Permanent link">&para;</a></h3>
<p><strong>Erreur:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-58-1" name="__codelineno-58-1" href="#__codelineno-58-1"></a>Access to path &#39;/admin/secubox/system/system-hub&#39; denied
</code></pre></div></p>
<p><strong>Diagnostic:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-59-1" name="__codelineno-59-1" href="#__codelineno-59-1"></a><span class="c1"># Vérifier ACL</span>
<a id="__codelineno-59-2" name="__codelineno-59-2" href="#__codelineno-59-2"></a>cat<span class="w"> </span>/usr/share/rpcd/acl.d/luci-app-system-hub.json<span class="w"> </span><span class="p">|</span><span class="w"> </span>jq<span class="w"> </span>.
<a id="__codelineno-59-3" name="__codelineno-59-3" href="#__codelineno-59-3"></a>
<a id="__codelineno-59-4" name="__codelineno-59-4" href="#__codelineno-59-4"></a><span class="c1"># Vérifier que méthodes ubus sont listées</span>
<a id="__codelineno-59-5" name="__codelineno-59-5" href="#__codelineno-59-5"></a>grep<span class="w"> </span><span class="s2">&quot;getHealth&quot;</span><span class="w"> </span>/usr/share/rpcd/acl.d/luci-app-system-hub.json
</code></pre></div></p>
<p><strong>Solution:</strong>
Ajouter la méthode manquante dans ACL et redémarrer rpcd.</p>
<hr />
<h2 id="validation-checklist">Validation Checklist<a class="headerlink" href="#validation-checklist" title="Permanent link">&para;</a></h2>
<h3 id="pre-commit-checklist">Pre-Commit Checklist<a class="headerlink" href="#pre-commit-checklist" title="Permanent link">&para;</a></h3>
<p>Avant chaque commit, vérifier:</p>
<ul class="task-list">
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>RPCD Script:</strong></li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Nom fichier correspond à objet ubus</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Exécutable (chmod +x)</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Structure list/call correcte</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Retourne JSON valide</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Toutes méthodes implémentées</p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Menu &amp; ACL:</strong></p>
</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Path menu correspond au fichier vue</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> ACL liste toutes les méthodes ubus</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> JSON valide (jsonlint)</p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>JavaScript:</strong></p>
</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> 'use strict' en première ligne</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Imports requis présents</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Pas de console.log en prod</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Gestion d'erreur sur API calls</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Event handlers bindés correctement</p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>CSS:</strong></p>
</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Variables CSS utilisées (pas de hardcode)</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Classes prefixées (sh-, sb-, module-)</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Dark mode supporté</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Responsive (max-width: 768px)</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Transitions cohérentes</p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Makefile:</strong></p>
</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> PKG_VERSION incrémenté</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> LUCI_DEPENDS correct</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Include path correct (../../luci.mk)</li>
</ul>
<h3 id="pre-deploy-checklist">Pre-Deploy Checklist<a class="headerlink" href="#pre-deploy-checklist" title="Permanent link">&para;</a></h3>
<p>Avant déploiement sur routeur:</p>
<ul class="task-list">
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Validation scripts:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-60-1" name="__codelineno-60-1" href="#__codelineno-60-1"></a>./secubox-tools/validate-modules.sh
</code></pre></div></p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Test RPCD local:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-61-1" name="__codelineno-61-1" href="#__codelineno-61-1"></a>/usr/libexec/rpcd/luci.module-name<span class="w"> </span>list
<a id="__codelineno-61-2" name="__codelineno-61-2" href="#__codelineno-61-2"></a>/usr/libexec/rpcd/luci.module-name<span class="w"> </span>call<span class="w"> </span>getStatus
</code></pre></div></p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Test JSON:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-62-1" name="__codelineno-62-1" href="#__codelineno-62-1"></a>find<span class="w"> </span>.<span class="w"> </span>-name<span class="w"> </span><span class="s2">&quot;*.json&quot;</span><span class="w"> </span>-exec<span class="w"> </span>jsonlint<span class="w"> </span><span class="o">{}</span><span class="w"> </span><span class="se">\;</span>
</code></pre></div></p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Shellcheck:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-63-1" name="__codelineno-63-1" href="#__codelineno-63-1"></a>shellcheck<span class="w"> </span>root/usr/libexec/rpcd/*
</code></pre></div></p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Permissions:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-64-1" name="__codelineno-64-1" href="#__codelineno-64-1"></a><span class="c1"># RPCD scripts</span>
<a id="__codelineno-64-2" name="__codelineno-64-2" href="#__codelineno-64-2"></a>chmod<span class="w"> </span><span class="m">755</span><span class="w"> </span>root/usr/libexec/rpcd/*
<a id="__codelineno-64-3" name="__codelineno-64-3" href="#__codelineno-64-3"></a>
<a id="__codelineno-64-4" name="__codelineno-64-4" href="#__codelineno-64-4"></a><span class="c1"># CSS/JS files</span>
<a id="__codelineno-64-5" name="__codelineno-64-5" href="#__codelineno-64-5"></a>chmod<span class="w"> </span><span class="m">644</span><span class="w"> </span>htdocs/luci-static/resources/**/*
</code></pre></div></p>
</li>
</ul>
<h3 id="post-deploy-checklist">Post-Deploy Checklist<a class="headerlink" href="#post-deploy-checklist" title="Permanent link">&para;</a></h3>
<p>Après déploiement:</p>
<ul class="task-list">
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Services:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-65-1" name="__codelineno-65-1" href="#__codelineno-65-1"></a>/etc/init.d/rpcd<span class="w"> </span>status
<a id="__codelineno-65-2" name="__codelineno-65-2" href="#__codelineno-65-2"></a>/etc/init.d/uhttpd<span class="w"> </span>status
</code></pre></div></p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>ubus objects:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-66-1" name="__codelineno-66-1" href="#__codelineno-66-1"></a>ubus<span class="w"> </span>list<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>luci.module-name
</code></pre></div></p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Fichiers présents:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-67-1" name="__codelineno-67-1" href="#__codelineno-67-1"></a>ls<span class="w"> </span>-la<span class="w"> </span>/www/luci-static/resources/view/module-name/
<a id="__codelineno-67-2" name="__codelineno-67-2" href="#__codelineno-67-2"></a>ls<span class="w"> </span>-la<span class="w"> </span>/www/luci-static/resources/module-name/
</code></pre></div></p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Permissions correctes:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-68-1" name="__codelineno-68-1" href="#__codelineno-68-1"></a>ls<span class="w"> </span>-la<span class="w"> </span>/usr/libexec/rpcd/luci.module-name
<a id="__codelineno-68-2" name="__codelineno-68-2" href="#__codelineno-68-2"></a>ls<span class="w"> </span>-la<span class="w"> </span>/www/luci-static/resources/module-name/*.css
</code></pre></div></p>
</li>
<li class="task-list-item">
<p><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> <strong>Test navigateur:</strong></p>
</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Ouvrir en mode privé</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Vérifier console (F12) - pas d'erreurs</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Vérifier Network tab - tous les fichiers chargent (200)</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Tester dark/light mode</li>
<li class="task-list-item"><label class="task-list-control"><input type="checkbox" disabled/><span class="task-list-indicator"></span></label> Tester responsive (mobile view)</li>
</ul>
<hr />
<h2 id="deployment-procedures">Deployment Procedures<a class="headerlink" href="#deployment-procedures" title="Permanent link">&para;</a></h2>
<h3 id="deployment-workflow">Deployment Workflow<a class="headerlink" href="#deployment-workflow" title="Permanent link">&para;</a></h3>
<p>The following flowchart illustrates the complete deployment process with validation checkpoints:</p>
<pre class="mermaid"><code>flowchart TD
START([Start Deployment]) --&gt; LOCAL_VAL{Local Validation&lt;br/&gt;Passed?}
LOCAL_VAL --&gt;|No| FIX_LOCAL[Fix Issues Locally]
FIX_LOCAL --&gt; LOCAL_VAL
LOCAL_VAL --&gt;|Yes| CHECK_DISK{Disk Space&lt;br/&gt;&lt; 90%?}
CHECK_DISK --&gt;|No| CLEAN_DISK[Clean Temp Files&lt;br/&gt;&amp; Old Backups]
CLEAN_DISK --&gt; CHECK_DISK
CHECK_DISK --&gt;|Yes| FIX_PERM_LOCAL[Fix Permissions&lt;br/&gt;Local Source]
FIX_PERM_LOCAL --&gt; COPY[Copy Files to Router&lt;br/&gt;scp JS/CSS/RPCD]
COPY --&gt; FIX_PERM_REMOTE[Fix Permissions&lt;br/&gt;Remote Files&lt;br/&gt;755 RPCD / 644 CSS-JS]
FIX_PERM_REMOTE --&gt; CLEAR[Clear LuCI Cache&lt;br/&gt;/tmp/luci-*]
CLEAR --&gt; RESTART[Restart Services&lt;br/&gt;rpcd + uhttpd]
RESTART --&gt; V1{ubus Object&lt;br/&gt;Available?}
V1 --&gt;|No| DEBUG1[Debug RPCD Script&lt;br/&gt;Check naming &amp; permissions]
DEBUG1 --&gt; FIX_PERM_REMOTE
V1 --&gt;|Yes| V2{Files&lt;br/&gt;Accessible?}
V2 --&gt;|403 Error| DEBUG2[Fix File Permissions&lt;br/&gt;chmod 644]
DEBUG2 --&gt; FIX_PERM_REMOTE
V2 --&gt;|Yes| V3{Menu Path&lt;br/&gt;Matches View?}
V3 --&gt;|404 Error| DEBUG3[Fix Menu JSON Path]
DEBUG3 --&gt; COPY
V3 --&gt;|Yes| V4{UI Loads&lt;br/&gt;Correctly?}
V4 --&gt;|Errors| DEBUG4[Check Browser Console&lt;br/&gt;Fix JavaScript Errors]
DEBUG4 --&gt; COPY
V4 --&gt;|Yes| TEST[Browser Testing&lt;br/&gt;Private Mode&lt;br/&gt;Dark/Light Mode&lt;br/&gt;Responsive]
TEST --&gt; 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</code></pre>
<p><strong>Deployment Stages:</strong>
1. <strong>Local Validation:</strong> Run <code>validate-modules.sh</code> and <code>fix-permissions.sh --local</code>
2. <strong>Pre-Flight Checks:</strong> Disk space and permission verification
3. <strong>File Transfer:</strong> Copy JavaScript, CSS, and RPCD scripts
4. <strong>Remote Setup:</strong> Fix permissions and clear caches
5. <strong>Service Restart:</strong> Reload rpcd and uhttpd daemons
6. <strong>Validation:</strong> Multi-stage verification (ubus, files, menu, UI)
7. <strong>Testing:</strong> Browser testing in private mode</p>
<p><strong>Common Error Recovery Paths:</strong>
- <strong>Object not found (-32000):</strong> Check RPCD script naming and permissions
- <strong>403 Forbidden:</strong> Fix file permissions to 644 for CSS/JS
- <strong>404 Not Found:</strong> Verify menu path matches view file location
- <strong>JavaScript errors:</strong> Check browser console and fix code issues</p>
<hr />
<h3 id="pre-deployment-checks-critical">⚠️ Pre-Deployment Checks (CRITICAL)<a class="headerlink" href="#pre-deployment-checks-critical" title="Permanent link">&para;</a></h3>
<p><strong>TOUJOURS exécuter ces vérifications AVANT tout déploiement:</strong></p>
<h4 id="1-verification-de-lespace-disque">1. Vérification de l'Espace Disque<a class="headerlink" href="#1-verification-de-lespace-disque" title="Permanent link">&para;</a></h4>
<div class="highlight"><pre><span></span><code><a id="__codelineno-69-1" name="__codelineno-69-1" href="#__codelineno-69-1"></a><span class="c1"># Sur le routeur cible</span>
<a id="__codelineno-69-2" name="__codelineno-69-2" href="#__codelineno-69-2"></a>ssh<span class="w"> </span>root@192.168.8.191<span class="w"> </span><span class="s2">&quot;df -h | grep overlay&quot;</span>
<a id="__codelineno-69-3" name="__codelineno-69-3" href="#__codelineno-69-3"></a>
<a id="__codelineno-69-4" name="__codelineno-69-4" href="#__codelineno-69-4"></a><span class="c1"># Vérifier que l&#39;utilisation est &lt; 90%</span>
<a id="__codelineno-69-5" name="__codelineno-69-5" href="#__codelineno-69-5"></a><span class="c1"># Exemple OK:</span>
<a id="__codelineno-69-6" name="__codelineno-69-6" href="#__codelineno-69-6"></a><span class="c1"># /dev/loop0 98.8M 45.2M 53.6M 46% /overlay</span>
<a id="__codelineno-69-7" name="__codelineno-69-7" href="#__codelineno-69-7"></a>
<a id="__codelineno-69-8" name="__codelineno-69-8" href="#__codelineno-69-8"></a><span class="c1"># Exemple CRITIQUE (STOP deployment):</span>
<a id="__codelineno-69-9" name="__codelineno-69-9" href="#__codelineno-69-9"></a><span class="c1"># /dev/loop0 98.8M 98.8M 0 100% /overlay ← PLEIN!</span>
</code></pre></div>
<p><strong>Si l'overlay est plein (≥95%):</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-70-1" name="__codelineno-70-1" href="#__codelineno-70-1"></a><span class="c1"># Libérer de l&#39;espace avant déploiement</span>
<a id="__codelineno-70-2" name="__codelineno-70-2" href="#__codelineno-70-2"></a>ssh<span class="w"> </span>root@192.168.8.191<span class="w"> </span><span class="s">&lt;&lt; &#39;EOF&#39;</span>
<a id="__codelineno-70-3" name="__codelineno-70-3" href="#__codelineno-70-3"></a><span class="s"># Supprimer fichiers temporaires</span>
<a id="__codelineno-70-4" name="__codelineno-70-4" href="#__codelineno-70-4"></a><span class="s">rm -rf /tmp/*.ipk /tmp/luci-* 2&gt;/dev/null</span>
<a id="__codelineno-70-5" name="__codelineno-70-5" href="#__codelineno-70-5"></a>
<a id="__codelineno-70-6" name="__codelineno-70-6" href="#__codelineno-70-6"></a><span class="s"># Supprimer anciens backups (&gt;7 jours)</span>
<a id="__codelineno-70-7" name="__codelineno-70-7" href="#__codelineno-70-7"></a><span class="s">find /root -name &#39;*.backup-*&#39; -type f -mtime +7 -delete 2&gt;/dev/null</span>
<a id="__codelineno-70-8" name="__codelineno-70-8" href="#__codelineno-70-8"></a>
<a id="__codelineno-70-9" name="__codelineno-70-9" href="#__codelineno-70-9"></a><span class="s"># Vérifier packages inutilisés</span>
<a id="__codelineno-70-10" name="__codelineno-70-10" href="#__codelineno-70-10"></a><span class="s">opkg list-installed | grep -E &#39;netdata|unused&#39;</span>
<a id="__codelineno-70-11" name="__codelineno-70-11" href="#__codelineno-70-11"></a>
<a id="__codelineno-70-12" name="__codelineno-70-12" href="#__codelineno-70-12"></a><span class="s"># Après nettoyage, vérifier l&#39;espace libéré</span>
<a id="__codelineno-70-13" name="__codelineno-70-13" href="#__codelineno-70-13"></a><span class="s">df -h | grep overlay</span>
<a id="__codelineno-70-14" name="__codelineno-70-14" href="#__codelineno-70-14"></a><span class="s">EOF</span>
</code></pre></div></p>
<p><strong>Tailles typiques à surveiller:</strong>
- Netdata web UI: ~22MB (considérer suppression si non utilisé)
- Modules LuCI: ~1-2MB chacun
- Fichiers CSS/JS: ~10-50KB chacun</p>
<h4 id="2-verification-des-permissions-critique-pour-eviter-erreurs-403">2. Vérification des Permissions (Critique pour Éviter Erreurs 403)<a class="headerlink" href="#2-verification-des-permissions-critique-pour-eviter-erreurs-403" title="Permanent link">&para;</a></h4>
<p><strong>Permissions OBLIGATOIRES:</strong></p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Permission</th>
<th>Octal</th>
<th>Raison</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>RPCD scripts</strong></td>
<td><code>rwxr-xr-x</code></td>
<td><code>755</code></td>
<td>Exécutable par system</td>
</tr>
<tr>
<td><strong>CSS files</strong></td>
<td><code>rw-r--r--</code></td>
<td><code>644</code></td>
<td>Lecture web server</td>
</tr>
<tr>
<td><strong>JS files</strong></td>
<td><code>rw-r--r--</code></td>
<td><code>644</code></td>
<td>Lecture web server</td>
</tr>
<tr>
<td><strong>JSON files</strong></td>
<td><code>rw-r--r--</code></td>
<td><code>644</code></td>
<td>Lecture rpcd</td>
</tr>
</tbody>
</table>
<p><strong>Erreur commune:</strong> Fichiers créés avec <code>600</code> (rw-------) au lieu de <code>644</code></p>
<p><strong>Symptôme:</strong> HTTP 403 Forbidden lors du chargement de fichiers JS/CSS</p>
<p><strong>Exemple d'erreur:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-71-1" name="__codelineno-71-1" href="#__codelineno-71-1"></a>NetworkError: HTTP error 403 while loading class file
<a id="__codelineno-71-2" name="__codelineno-71-2" href="#__codelineno-71-2"></a>&quot;/luci-static/resources/view/netdata-dashboard/dashboard.js&quot;
</code></pre></div></p>
<p><strong>Diagnostic rapide:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-72-1" name="__codelineno-72-1" href="#__codelineno-72-1"></a><span class="c1"># Vérifier permissions des fichiers déployés</span>
<a id="__codelineno-72-2" name="__codelineno-72-2" href="#__codelineno-72-2"></a>ssh<span class="w"> </span>root@192.168.8.191<span class="w"> </span><span class="s2">&quot;ls -la /www/luci-static/resources/view/MODULE_NAME/&quot;</span>
<a id="__codelineno-72-3" name="__codelineno-72-3" href="#__codelineno-72-3"></a>
<a id="__codelineno-72-4" name="__codelineno-72-4" href="#__codelineno-72-4"></a><span class="c1"># Chercher fichiers avec permissions incorrectes (600)</span>
<a id="__codelineno-72-5" name="__codelineno-72-5" href="#__codelineno-72-5"></a>ssh<span class="w"> </span>root@192.168.8.191<span class="w"> </span><span class="s2">&quot;find /www/luci-static/resources/view/ -type f -name &#39;*.js&#39; -perm 600&quot;</span>
<a id="__codelineno-72-6" name="__codelineno-72-6" href="#__codelineno-72-6"></a>
<a id="__codelineno-72-7" name="__codelineno-72-7" href="#__codelineno-72-7"></a><span class="c1"># MAUVAIS (cause 403):</span>
<a id="__codelineno-72-8" name="__codelineno-72-8" href="#__codelineno-72-8"></a><span class="c1"># -rw------- 1 root root 9763 dashboard.js ← 600 = pas lisible par web!</span>
<a id="__codelineno-72-9" name="__codelineno-72-9" href="#__codelineno-72-9"></a>
<a id="__codelineno-72-10" name="__codelineno-72-10" href="#__codelineno-72-10"></a><span class="c1"># BON:</span>
<a id="__codelineno-72-11" name="__codelineno-72-11" href="#__codelineno-72-11"></a><span class="c1"># -rw-r--r-- 1 root root 9763 dashboard.js ← 644 = OK</span>
</code></pre></div></p>
<p><strong>Correction immédiate:</strong>
<div class="highlight"><pre><span></span><code><a id="__codelineno-73-1" name="__codelineno-73-1" href="#__codelineno-73-1"></a><span class="c1"># Corriger TOUS les fichiers CSS/JS</span>
<a id="__codelineno-73-2" name="__codelineno-73-2" href="#__codelineno-73-2"></a>ssh<span class="w"> </span>root@192.168.8.191<span class="w"> </span><span class="s">&lt;&lt; &#39;EOF&#39;</span>
<a id="__codelineno-73-3" name="__codelineno-73-3" href="#__codelineno-73-3"></a><span class="s">find /www/luci-static/resources/ -name &#39;*.css&#39; -exec chmod 644 {} \;</span>
<a id="__codelineno-73-4" name="__codelineno-73-4" href="#__codelineno-73-4"></a><span class="s">find /www/luci-static/resources/ -name &#39;*.js&#39; -exec chmod 644 {} \;</span>
<a id="__codelineno-73-5" name="__codelineno-73-5" href="#__codelineno-73-5"></a><span class="s">find /usr/libexec/rpcd/ -name &#39;luci.*&#39; -exec chmod 755 {} \;</span>
<a id="__codelineno-73-6" name="__codelineno-73-6" href="#__codelineno-73-6"></a><span class="s">EOF</span>
</code></pre></div></p>
<p><strong>⚡ Correction Automatique (Recommandé):</strong></p>
<p>Utiliser le script automatique qui vérifie et corrige toutes les permissions:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-74-1" name="__codelineno-74-1" href="#__codelineno-74-1"></a><span class="c1"># Corriger permissions locales (source code)</span>
<a id="__codelineno-74-2" name="__codelineno-74-2" href="#__codelineno-74-2"></a>./secubox-tools/fix-permissions.sh<span class="w"> </span>--local
<a id="__codelineno-74-3" name="__codelineno-74-3" href="#__codelineno-74-3"></a>
<a id="__codelineno-74-4" name="__codelineno-74-4" href="#__codelineno-74-4"></a><span class="c1"># Corriger permissions sur routeur</span>
<a id="__codelineno-74-5" name="__codelineno-74-5" href="#__codelineno-74-5"></a>./secubox-tools/fix-permissions.sh<span class="w"> </span>--remote
<a id="__codelineno-74-6" name="__codelineno-74-6" href="#__codelineno-74-6"></a>
<a id="__codelineno-74-7" name="__codelineno-74-7" href="#__codelineno-74-7"></a><span class="c1"># Corriger les deux (local + remote)</span>
<a id="__codelineno-74-8" name="__codelineno-74-8" href="#__codelineno-74-8"></a>./secubox-tools/fix-permissions.sh
</code></pre></div>
<p>Le script <code>fix-permissions.sh</code> 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</p>
<p><strong>🔍 Validation Automatique des Permissions:</strong></p>
<p>Le script <code>validate-modules.sh</code> inclut maintenant un Check 7 qui vérifie automatiquement les permissions:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-75-1" name="__codelineno-75-1" href="#__codelineno-75-1"></a>./secubox-tools/validate-modules.sh
<a id="__codelineno-75-2" name="__codelineno-75-2" href="#__codelineno-75-2"></a>
<a id="__codelineno-75-3" name="__codelineno-75-3" href="#__codelineno-75-3"></a><span class="c1"># Check 7 validera:</span>
<a id="__codelineno-75-4" name="__codelineno-75-4" href="#__codelineno-75-4"></a><span class="c1"># ✓ Tous les RPCD sont 755</span>
<a id="__codelineno-75-5" name="__codelineno-75-5" href="#__codelineno-75-5"></a><span class="c1"># ✓ Tous les CSS sont 644</span>
<a id="__codelineno-75-6" name="__codelineno-75-6" href="#__codelineno-75-6"></a><span class="c1"># ✓ Tous les JS sont 644</span>
<a id="__codelineno-75-7" name="__codelineno-75-7" href="#__codelineno-75-7"></a><span class="c1"># ❌ Affichera erreurs si permissions incorrectes</span>
</code></pre></div>
<p><strong>Workflow recommandé:</strong>
1. Développer/modifier code
2. <code>./secubox-tools/fix-permissions.sh --local</code> (avant commit)
3. <code>./secubox-tools/validate-modules.sh</code> (vérifier tout)
4. Commit &amp; push
5. Deploy sur routeur
6. <code>./secubox-tools/fix-permissions.sh --remote</code> (après deploy)</p>
<h4 id="3-post-deployment-verification">3. Post-Deployment Verification<a class="headerlink" href="#3-post-deployment-verification" title="Permanent link">&para;</a></h4>
<p><strong>Checklist après déploiement:</strong></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-76-1" name="__codelineno-76-1" href="#__codelineno-76-1"></a><span class="ch">#!/bin/bash</span>
<a id="__codelineno-76-2" name="__codelineno-76-2" href="#__codelineno-76-2"></a><span class="nv">ROUTER</span><span class="o">=</span><span class="s2">&quot;root@192.168.8.191&quot;</span>
<a id="__codelineno-76-3" name="__codelineno-76-3" href="#__codelineno-76-3"></a><span class="nv">MODULE</span><span class="o">=</span><span class="s2">&quot;module-name&quot;</span>
<a id="__codelineno-76-4" name="__codelineno-76-4" href="#__codelineno-76-4"></a>
<a id="__codelineno-76-5" name="__codelineno-76-5" href="#__codelineno-76-5"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;🔍 Post-Deployment Verification&quot;</span>
<a id="__codelineno-76-6" name="__codelineno-76-6" href="#__codelineno-76-6"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-76-7" name="__codelineno-76-7" href="#__codelineno-76-7"></a>
<a id="__codelineno-76-8" name="__codelineno-76-8" href="#__codelineno-76-8"></a><span class="c1"># 1. Vérifier espace disque</span>
<a id="__codelineno-76-9" name="__codelineno-76-9" href="#__codelineno-76-9"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;1. Espace disque restant:&quot;</span>
<a id="__codelineno-76-10" name="__codelineno-76-10" href="#__codelineno-76-10"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;df -h | grep overlay | awk &#39;{print \$5}&#39;&quot;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;❌ FAIL&quot;</span>
<a id="__codelineno-76-11" name="__codelineno-76-11" href="#__codelineno-76-11"></a>
<a id="__codelineno-76-12" name="__codelineno-76-12" href="#__codelineno-76-12"></a><span class="c1"># 2. Vérifier permissions CSS/JS</span>
<a id="__codelineno-76-13" name="__codelineno-76-13" href="#__codelineno-76-13"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;2. Permissions CSS/JS:&quot;</span>
<a id="__codelineno-76-14" name="__codelineno-76-14" href="#__codelineno-76-14"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;find /www/luci-static/resources/</span><span class="nv">$MODULE</span><span class="s2"> -type f \( -name &#39;*.css&#39; -o -name &#39;*.js&#39; \) ! -perm 644&quot;</span><span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="se">\</span>
<a id="__codelineno-76-15" name="__codelineno-76-15" href="#__codelineno-76-15"></a><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-z<span class="w"> </span><span class="s2">&quot;</span><span class="k">$(</span>cat<span class="k">)</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;✅ OK&quot;</span><span class="p">;</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;❌ FAIL - Permissions incorrectes&quot;</span><span class="p">;</span><span class="w"> </span><span class="k">fi</span>
<a id="__codelineno-76-16" name="__codelineno-76-16" href="#__codelineno-76-16"></a>
<a id="__codelineno-76-17" name="__codelineno-76-17" href="#__codelineno-76-17"></a><span class="c1"># 3. Vérifier permissions RPCD</span>
<a id="__codelineno-76-18" name="__codelineno-76-18" href="#__codelineno-76-18"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;3. Permissions RPCD:&quot;</span>
<a id="__codelineno-76-19" name="__codelineno-76-19" href="#__codelineno-76-19"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;ls -l /usr/libexec/rpcd/luci.</span><span class="nv">$MODULE</span><span class="s2"> | grep -q rwxr-xr-x&quot;</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;✅ OK&quot;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;❌ FAIL&quot;</span>
<a id="__codelineno-76-20" name="__codelineno-76-20" href="#__codelineno-76-20"></a>
<a id="__codelineno-76-21" name="__codelineno-76-21" href="#__codelineno-76-21"></a><span class="c1"># 4. Vérifier ubus object</span>
<a id="__codelineno-76-22" name="__codelineno-76-22" href="#__codelineno-76-22"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;4. ubus object disponible:&quot;</span>
<a id="__codelineno-76-23" name="__codelineno-76-23" href="#__codelineno-76-23"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;ubus list | grep -q luci.</span><span class="nv">$MODULE</span><span class="s2">&quot;</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;✅ OK&quot;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;❌ FAIL&quot;</span>
<a id="__codelineno-76-24" name="__codelineno-76-24" href="#__codelineno-76-24"></a>
<a id="__codelineno-76-25" name="__codelineno-76-25" href="#__codelineno-76-25"></a><span class="c1"># 5. Vérifier fichiers accessibles (HTTP)</span>
<a id="__codelineno-76-26" name="__codelineno-76-26" href="#__codelineno-76-26"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;5. Fichiers web accessibles:&quot;</span>
<a id="__codelineno-76-27" name="__codelineno-76-27" href="#__codelineno-76-27"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;test -r /www/luci-static/resources/</span><span class="nv">$MODULE</span><span class="s2">/common.css&quot;</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;✅ OK&quot;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;⚠️ common.css non trouvé&quot;</span>
<a id="__codelineno-76-28" name="__codelineno-76-28" href="#__codelineno-76-28"></a>
<a id="__codelineno-76-29" name="__codelineno-76-29" href="#__codelineno-76-29"></a><span class="c1"># 6. Vérifier cache cleared</span>
<a id="__codelineno-76-30" name="__codelineno-76-30" href="#__codelineno-76-30"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;6. Cache LuCI cleared:&quot;</span>
<a id="__codelineno-76-31" name="__codelineno-76-31" href="#__codelineno-76-31"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;test ! -f /tmp/luci-indexcache&quot;</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;✅ OK&quot;</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;⚠️ Cache encore présent&quot;</span>
<a id="__codelineno-76-32" name="__codelineno-76-32" href="#__codelineno-76-32"></a>
<a id="__codelineno-76-33" name="__codelineno-76-33" href="#__codelineno-76-33"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-76-34" name="__codelineno-76-34" href="#__codelineno-76-34"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;✅ Vérification terminée&quot;</span>
</code></pre></div>
<h4 id="4-common-deployment-errors">4. Common Deployment Errors<a class="headerlink" href="#4-common-deployment-errors" title="Permanent link">&para;</a></h4>
<table>
<thead>
<tr>
<th>Erreur</th>
<th>Cause</th>
<th>Solution Rapide</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>HTTP 403 Forbidden</strong></td>
<td>Permissions 600 au lieu de 644</td>
<td><code>chmod 644 *.js *.css</code></td>
</tr>
<tr>
<td><strong>No space left on device</strong></td>
<td>Overlay plein</td>
<td>Nettoyer /tmp, supprimer anciens backups</td>
</tr>
<tr>
<td><strong>Object not found -32000</strong></td>
<td>RPCD pas exécutable ou mal nommé</td>
<td><code>chmod 755 rpcd/luci.*</code> + vérifier nom</td>
</tr>
<tr>
<td><strong>Module not appearing</strong></td>
<td>Cache LuCI pas cleared</td>
<td><code>rm /tmp/luci-*</code> + restart services</td>
</tr>
<tr>
<td><strong>Changes not visible</strong></td>
<td>Cache navigateur</td>
<td>Mode privé + Ctrl+Shift+R</td>
</tr>
</tbody>
</table>
<h4 id="5-emergency-disk-space-recovery">5. Emergency Disk Space Recovery<a class="headerlink" href="#5-emergency-disk-space-recovery" title="Permanent link">&para;</a></h4>
<p><strong>Si le déploiement échoue avec "No space left on device":</strong></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-77-1" name="__codelineno-77-1" href="#__codelineno-77-1"></a><span class="ch">#!/bin/bash</span>
<a id="__codelineno-77-2" name="__codelineno-77-2" href="#__codelineno-77-2"></a><span class="nv">ROUTER</span><span class="o">=</span><span class="s2">&quot;root@192.168.8.191&quot;</span>
<a id="__codelineno-77-3" name="__codelineno-77-3" href="#__codelineno-77-3"></a>
<a id="__codelineno-77-4" name="__codelineno-77-4" href="#__codelineno-77-4"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;🚨 Emergency Disk Space Recovery&quot;</span>
<a id="__codelineno-77-5" name="__codelineno-77-5" href="#__codelineno-77-5"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-77-6" name="__codelineno-77-6" href="#__codelineno-77-6"></a>
<a id="__codelineno-77-7" name="__codelineno-77-7" href="#__codelineno-77-7"></a><span class="c1"># 1. Analyser l&#39;utilisation</span>
<a id="__codelineno-77-8" name="__codelineno-77-8" href="#__codelineno-77-8"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;Top 10 consumers:&quot;</span>
<a id="__codelineno-77-9" name="__codelineno-77-9" href="#__codelineno-77-9"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;du -k /overlay/upper 2&gt;/dev/null | sort -rn | head -10&quot;</span>
<a id="__codelineno-77-10" name="__codelineno-77-10" href="#__codelineno-77-10"></a>
<a id="__codelineno-77-11" name="__codelineno-77-11" href="#__codelineno-77-11"></a><span class="c1"># 2. Nettoyer temporaires</span>
<a id="__codelineno-77-12" name="__codelineno-77-12" href="#__codelineno-77-12"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-77-13" name="__codelineno-77-13" href="#__codelineno-77-13"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;Cleaning temp files...&quot;</span>
<a id="__codelineno-77-14" name="__codelineno-77-14" href="#__codelineno-77-14"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;rm -rf /tmp/*.ipk /tmp/luci-* /root/*.ipk 2&gt;/dev/null&quot;</span>
<a id="__codelineno-77-15" name="__codelineno-77-15" href="#__codelineno-77-15"></a>
<a id="__codelineno-77-16" name="__codelineno-77-16" href="#__codelineno-77-16"></a><span class="c1"># 3. Supprimer anciens backups</span>
<a id="__codelineno-77-17" name="__codelineno-77-17" href="#__codelineno-77-17"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;Removing old backups (&gt;7 days)...&quot;</span>
<a id="__codelineno-77-18" name="__codelineno-77-18" href="#__codelineno-77-18"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;find /root -name &#39;*.backup-*&#39; -mtime +7 -delete 2&gt;/dev/null&quot;</span>
<a id="__codelineno-77-19" name="__codelineno-77-19" href="#__codelineno-77-19"></a>
<a id="__codelineno-77-20" name="__codelineno-77-20" href="#__codelineno-77-20"></a><span class="c1"># 4. Option: Supprimer Netdata Web UI (libère ~22MB)</span>
<a id="__codelineno-77-21" name="__codelineno-77-21" href="#__codelineno-77-21"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-77-22" name="__codelineno-77-22" href="#__codelineno-77-22"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;⚠️ Option: Remove Netdata Web UI (saves ~22MB)?&quot;</span>
<a id="__codelineno-77-23" name="__codelineno-77-23" href="#__codelineno-77-23"></a><span class="nb">read</span><span class="w"> </span>-p<span class="w"> </span><span class="s2">&quot;Continue? (y/N) &quot;</span><span class="w"> </span>-n<span class="w"> </span><span class="m">1</span><span class="w"> </span>-r
<a id="__codelineno-77-24" name="__codelineno-77-24" href="#__codelineno-77-24"></a><span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="nv">$REPLY</span><span class="w"> </span><span class="o">=</span>~<span class="w"> </span>^<span class="o">[</span>Yy<span class="o">]</span>$<span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<a id="__codelineno-77-25" name="__codelineno-77-25" href="#__codelineno-77-25"></a><span class="w"> </span>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;opkg remove netdata-web 2&gt;/dev/null || rm -rf /usr/share/netdata/web/*&quot;</span>
<a id="__codelineno-77-26" name="__codelineno-77-26" href="#__codelineno-77-26"></a><span class="k">fi</span>
<a id="__codelineno-77-27" name="__codelineno-77-27" href="#__codelineno-77-27"></a>
<a id="__codelineno-77-28" name="__codelineno-77-28" href="#__codelineno-77-28"></a><span class="c1"># 5. Vérifier espace libéré</span>
<a id="__codelineno-77-29" name="__codelineno-77-29" href="#__codelineno-77-29"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-77-30" name="__codelineno-77-30" href="#__codelineno-77-30"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;Space after cleanup:&quot;</span>
<a id="__codelineno-77-31" name="__codelineno-77-31" href="#__codelineno-77-31"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;df -h | grep overlay&quot;</span>
</code></pre></div>
<h3 id="standard-deployment-script-template">Standard Deployment Script Template<a class="headerlink" href="#standard-deployment-script-template" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><a id="__codelineno-78-1" name="__codelineno-78-1" href="#__codelineno-78-1"></a><span class="ch">#!/bin/bash</span>
<a id="__codelineno-78-2" name="__codelineno-78-2" href="#__codelineno-78-2"></a><span class="c1"># Deploy &lt;Module Name&gt;</span>
<a id="__codelineno-78-3" name="__codelineno-78-3" href="#__codelineno-78-3"></a>
<a id="__codelineno-78-4" name="__codelineno-78-4" href="#__codelineno-78-4"></a><span class="nv">ROUTER</span><span class="o">=</span><span class="s2">&quot;root@192.168.8.191&quot;</span>
<a id="__codelineno-78-5" name="__codelineno-78-5" href="#__codelineno-78-5"></a><span class="nv">MODULE</span><span class="o">=</span><span class="s2">&quot;&lt;module-name&gt;&quot;</span>
<a id="__codelineno-78-6" name="__codelineno-78-6" href="#__codelineno-78-6"></a><span class="nv">LOCAL_DIR</span><span class="o">=</span><span class="s2">&quot;/path/to/luci-app-</span><span class="nv">$MODULE</span><span class="s2">/htdocs/luci-static/resources&quot;</span>
<a id="__codelineno-78-7" name="__codelineno-78-7" href="#__codelineno-78-7"></a><span class="nv">REMOTE_DIR</span><span class="o">=</span><span class="s2">&quot;/www/luci-static/resources&quot;</span>
<a id="__codelineno-78-8" name="__codelineno-78-8" href="#__codelineno-78-8"></a>
<a id="__codelineno-78-9" name="__codelineno-78-9" href="#__codelineno-78-9"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;📦 Déploiement </span><span class="nv">$MODULE</span><span class="s2">&quot;</span>
<a id="__codelineno-78-10" name="__codelineno-78-10" href="#__codelineno-78-10"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-78-11" name="__codelineno-78-11" href="#__codelineno-78-11"></a>
<a id="__codelineno-78-12" name="__codelineno-78-12" href="#__codelineno-78-12"></a><span class="c1"># 1. Deploy JS files</span>
<a id="__codelineno-78-13" name="__codelineno-78-13" href="#__codelineno-78-13"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;1. Copie des fichiers JS...&quot;</span>
<a id="__codelineno-78-14" name="__codelineno-78-14" href="#__codelineno-78-14"></a>scp<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$LOCAL_DIR</span><span class="s2">/view/</span><span class="nv">$MODULE</span><span class="s2">/&quot;</span>*.js<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">:</span><span class="nv">$REMOTE_DIR</span><span class="s2">/view/</span><span class="nv">$MODULE</span><span class="s2">/&quot;</span>
<a id="__codelineno-78-15" name="__codelineno-78-15" href="#__codelineno-78-15"></a>scp<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$LOCAL_DIR</span><span class="s2">/</span><span class="nv">$MODULE</span><span class="s2">/api.js&quot;</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">:</span><span class="nv">$REMOTE_DIR</span><span class="s2">/</span><span class="nv">$MODULE</span><span class="s2">/&quot;</span>
<a id="__codelineno-78-16" name="__codelineno-78-16" href="#__codelineno-78-16"></a>
<a id="__codelineno-78-17" name="__codelineno-78-17" href="#__codelineno-78-17"></a><span class="c1"># 2. Deploy CSS files</span>
<a id="__codelineno-78-18" name="__codelineno-78-18" href="#__codelineno-78-18"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;2. Copie des fichiers CSS...&quot;</span>
<a id="__codelineno-78-19" name="__codelineno-78-19" href="#__codelineno-78-19"></a>scp<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$LOCAL_DIR</span><span class="s2">/</span><span class="nv">$MODULE</span><span class="s2">/&quot;</span>*.css<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">:</span><span class="nv">$REMOTE_DIR</span><span class="s2">/</span><span class="nv">$MODULE</span><span class="s2">/&quot;</span>
<a id="__codelineno-78-20" name="__codelineno-78-20" href="#__codelineno-78-20"></a>
<a id="__codelineno-78-21" name="__codelineno-78-21" href="#__codelineno-78-21"></a><span class="c1"># 3. Deploy RPCD backend</span>
<a id="__codelineno-78-22" name="__codelineno-78-22" href="#__codelineno-78-22"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;3. Copie du backend RPCD...&quot;</span>
<a id="__codelineno-78-23" name="__codelineno-78-23" href="#__codelineno-78-23"></a>scp<span class="w"> </span><span class="s2">&quot;root/usr/libexec/rpcd/luci.</span><span class="nv">$MODULE</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">:/usr/libexec/rpcd/&quot;</span>
<a id="__codelineno-78-24" name="__codelineno-78-24" href="#__codelineno-78-24"></a>
<a id="__codelineno-78-25" name="__codelineno-78-25" href="#__codelineno-78-25"></a><span class="c1"># 4. Fix permissions</span>
<a id="__codelineno-78-26" name="__codelineno-78-26" href="#__codelineno-78-26"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;4. Correction des permissions...&quot;</span>
<a id="__codelineno-78-27" name="__codelineno-78-27" href="#__codelineno-78-27"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;chmod 755 /usr/libexec/rpcd/luci.</span><span class="nv">$MODULE</span><span class="s2">&quot;</span>
<a id="__codelineno-78-28" name="__codelineno-78-28" href="#__codelineno-78-28"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;chmod 644 </span><span class="nv">$REMOTE_DIR</span><span class="s2">/</span><span class="nv">$MODULE</span><span class="s2">/*.css&quot;</span>
<a id="__codelineno-78-29" name="__codelineno-78-29" href="#__codelineno-78-29"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;chmod 644 </span><span class="nv">$REMOTE_DIR</span><span class="s2">/view/</span><span class="nv">$MODULE</span><span class="s2">/*.js&quot;</span>
<a id="__codelineno-78-30" name="__codelineno-78-30" href="#__codelineno-78-30"></a>
<a id="__codelineno-78-31" name="__codelineno-78-31" href="#__codelineno-78-31"></a><span class="c1"># 5. Clear cache</span>
<a id="__codelineno-78-32" name="__codelineno-78-32" href="#__codelineno-78-32"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;5. Nettoyage du cache...&quot;</span>
<a id="__codelineno-78-33" name="__codelineno-78-33" href="#__codelineno-78-33"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;rm -f /tmp/luci-indexcache /tmp/luci-modulecache/* 2&gt;/dev/null&quot;</span>
<a id="__codelineno-78-34" name="__codelineno-78-34" href="#__codelineno-78-34"></a>
<a id="__codelineno-78-35" name="__codelineno-78-35" href="#__codelineno-78-35"></a><span class="c1"># 6. Restart services</span>
<a id="__codelineno-78-36" name="__codelineno-78-36" href="#__codelineno-78-36"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;6. Redémarrage des services...&quot;</span>
<a id="__codelineno-78-37" name="__codelineno-78-37" href="#__codelineno-78-37"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;/etc/init.d/rpcd restart&quot;</span>
<a id="__codelineno-78-38" name="__codelineno-78-38" href="#__codelineno-78-38"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;/etc/init.d/uhttpd restart&quot;</span>
<a id="__codelineno-78-39" name="__codelineno-78-39" href="#__codelineno-78-39"></a>
<a id="__codelineno-78-40" name="__codelineno-78-40" href="#__codelineno-78-40"></a><span class="c1"># 7. Verify</span>
<a id="__codelineno-78-41" name="__codelineno-78-41" href="#__codelineno-78-41"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-78-42" name="__codelineno-78-42" href="#__codelineno-78-42"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;7. Vérification...&quot;</span>
<a id="__codelineno-78-43" name="__codelineno-78-43" href="#__codelineno-78-43"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;ubus list | grep luci.</span><span class="nv">$MODULE</span><span class="s2">&quot;</span>
<a id="__codelineno-78-44" name="__codelineno-78-44" href="#__codelineno-78-44"></a>
<a id="__codelineno-78-45" name="__codelineno-78-45" href="#__codelineno-78-45"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-78-46" name="__codelineno-78-46" href="#__codelineno-78-46"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;✅ Déploiement terminé!&quot;</span>
<a id="__codelineno-78-47" name="__codelineno-78-47" href="#__codelineno-78-47"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;&quot;</span>
<a id="__codelineno-78-48" name="__codelineno-78-48" href="#__codelineno-78-48"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot;🌐 Testez (mode privé):&quot;</span>
<a id="__codelineno-78-49" name="__codelineno-78-49" href="#__codelineno-78-49"></a><span class="nb">echo</span><span class="w"> </span><span class="s2">&quot; https://192.168.8.191/cgi-bin/luci/admin/secubox/path/to/</span><span class="nv">$MODULE</span><span class="s2">&quot;</span>
</code></pre></div>
<h3 id="rollback-procedure">Rollback Procedure<a class="headerlink" href="#rollback-procedure" title="Permanent link">&para;</a></h3>
<p>En cas de problème:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-79-1" name="__codelineno-79-1" href="#__codelineno-79-1"></a><span class="ch">#!/bin/bash</span>
<a id="__codelineno-79-2" name="__codelineno-79-2" href="#__codelineno-79-2"></a><span class="c1"># Rollback to previous version</span>
<a id="__codelineno-79-3" name="__codelineno-79-3" href="#__codelineno-79-3"></a>
<a id="__codelineno-79-4" name="__codelineno-79-4" href="#__codelineno-79-4"></a><span class="nv">ROUTER</span><span class="o">=</span><span class="s2">&quot;root@192.168.8.191&quot;</span>
<a id="__codelineno-79-5" name="__codelineno-79-5" href="#__codelineno-79-5"></a><span class="nv">BACKUP_DIR</span><span class="o">=</span><span class="s2">&quot;/root/luci-backups/</span><span class="k">$(</span>date<span class="w"> </span>+%Y%m%d<span class="k">)</span><span class="s2">&quot;</span>
<a id="__codelineno-79-6" name="__codelineno-79-6" href="#__codelineno-79-6"></a>
<a id="__codelineno-79-7" name="__codelineno-79-7" href="#__codelineno-79-7"></a><span class="c1"># 1. Créer backup avant deploy</span>
<a id="__codelineno-79-8" name="__codelineno-79-8" href="#__codelineno-79-8"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;mkdir -p </span><span class="nv">$BACKUP_DIR</span><span class="s2">&quot;</span>
<a id="__codelineno-79-9" name="__codelineno-79-9" href="#__codelineno-79-9"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;cp -r /www/luci-static/resources/module-name </span><span class="nv">$BACKUP_DIR</span><span class="s2">/&quot;</span>
<a id="__codelineno-79-10" name="__codelineno-79-10" href="#__codelineno-79-10"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;cp /usr/libexec/rpcd/luci.module-name </span><span class="nv">$BACKUP_DIR</span><span class="s2">/&quot;</span>
<a id="__codelineno-79-11" name="__codelineno-79-11" href="#__codelineno-79-11"></a>
<a id="__codelineno-79-12" name="__codelineno-79-12" href="#__codelineno-79-12"></a><span class="c1"># 2. En cas de problème, restore</span>
<a id="__codelineno-79-13" name="__codelineno-79-13" href="#__codelineno-79-13"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;cp -r </span><span class="nv">$BACKUP_DIR</span><span class="s2">/module-name /www/luci-static/resources/&quot;</span>
<a id="__codelineno-79-14" name="__codelineno-79-14" href="#__codelineno-79-14"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;cp </span><span class="nv">$BACKUP_DIR</span><span class="s2">/luci.module-name /usr/libexec/rpcd/&quot;</span>
<a id="__codelineno-79-15" name="__codelineno-79-15" href="#__codelineno-79-15"></a>ssh<span class="w"> </span><span class="s2">&quot;</span><span class="nv">$ROUTER</span><span class="s2">&quot;</span><span class="w"> </span><span class="s2">&quot;/etc/init.d/rpcd restart &amp;&amp; /etc/init.d/uhttpd restart&quot;</span>
</code></pre></div>
<h3 id="version-control">Version Control<a class="headerlink" href="#version-control" title="Permanent link">&para;</a></h3>
<p><strong>Toujours incrémenter les versions:</strong></p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-80-1" name="__codelineno-80-1" href="#__codelineno-80-1"></a><span class="c"># Makefile</span>
<a id="__codelineno-80-2" name="__codelineno-80-2" href="#__codelineno-80-2"></a><span class="nv">PKG_VERSION</span><span class="o">:=</span><span class="m">0</span>.3.0
<a id="__codelineno-80-3" name="__codelineno-80-3" href="#__codelineno-80-3"></a><span class="nv">PKG_RELEASE</span><span class="o">:=</span><span class="m">1</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><a id="__codelineno-81-1" name="__codelineno-81-1" href="#__codelineno-81-1"></a><span class="c">/* CSS files */</span>
<a id="__codelineno-81-2" name="__codelineno-81-2" href="#__codelineno-81-2"></a><span class="c">/**</span>
<a id="__codelineno-81-3" name="__codelineno-81-3" href="#__codelineno-81-3"></a><span class="c"> * Module - Styles</span>
<a id="__codelineno-81-4" name="__codelineno-81-4" href="#__codelineno-81-4"></a><span class="c"> * Version: 0.3.0</span>
<a id="__codelineno-81-5" name="__codelineno-81-5" href="#__codelineno-81-5"></a><span class="c"> */</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><a id="__codelineno-82-1" name="__codelineno-82-1" href="#__codelineno-82-1"></a><span class="c1">// JavaScript</span>
<a id="__codelineno-82-2" name="__codelineno-82-2" href="#__codelineno-82-2"></a><span class="c1">// Version: 0.3.0</span>
</code></pre></div>
<p><strong>Semantic Versioning:</strong>
- MAJOR.MINOR.PATCH (1.2.3)
- MAJOR: Breaking changes
- MINOR: New features (backward compatible)
- PATCH: Bug fixes</p>
<hr />
<h2 id="quick-reference">Quick Reference<a class="headerlink" href="#quick-reference" title="Permanent link">&para;</a></h2>
<h3 id="essential-commands">Essential Commands<a class="headerlink" href="#essential-commands" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><a id="__codelineno-83-1" name="__codelineno-83-1" href="#__codelineno-83-1"></a><span class="c1"># Validation</span>
<a id="__codelineno-83-2" name="__codelineno-83-2" href="#__codelineno-83-2"></a>./secubox-tools/validate-modules.sh
<a id="__codelineno-83-3" name="__codelineno-83-3" href="#__codelineno-83-3"></a>
<a id="__codelineno-83-4" name="__codelineno-83-4" href="#__codelineno-83-4"></a><span class="c1"># Build (local)</span>
<a id="__codelineno-83-5" name="__codelineno-83-5" href="#__codelineno-83-5"></a>./secubox-tools/local-build.sh<span class="w"> </span>build<span class="w"> </span>luci-app-module-name
<a id="__codelineno-83-6" name="__codelineno-83-6" href="#__codelineno-83-6"></a>
<a id="__codelineno-83-7" name="__codelineno-83-7" href="#__codelineno-83-7"></a><span class="c1"># Deploy files</span>
<a id="__codelineno-83-8" name="__codelineno-83-8" href="#__codelineno-83-8"></a>scp<span class="w"> </span>file.js<span class="w"> </span>root@router:/www/luci-static/resources/
<a id="__codelineno-83-9" name="__codelineno-83-9" href="#__codelineno-83-9"></a>
<a id="__codelineno-83-10" name="__codelineno-83-10" href="#__codelineno-83-10"></a><span class="c1"># Fix permissions</span>
<a id="__codelineno-83-11" name="__codelineno-83-11" href="#__codelineno-83-11"></a>ssh<span class="w"> </span>root@router<span class="w"> </span><span class="s2">&quot;chmod 644 /www/luci-static/resources/**/*.css&quot;</span>
<a id="__codelineno-83-12" name="__codelineno-83-12" href="#__codelineno-83-12"></a>ssh<span class="w"> </span>root@router<span class="w"> </span><span class="s2">&quot;chmod 755 /usr/libexec/rpcd/luci.*&quot;</span>
<a id="__codelineno-83-13" name="__codelineno-83-13" href="#__codelineno-83-13"></a>
<a id="__codelineno-83-14" name="__codelineno-83-14" href="#__codelineno-83-14"></a><span class="c1"># Clear cache</span>
<a id="__codelineno-83-15" name="__codelineno-83-15" href="#__codelineno-83-15"></a>ssh<span class="w"> </span>root@router<span class="w"> </span><span class="s2">&quot;rm -f /tmp/luci-indexcache /tmp/luci-modulecache/*&quot;</span>
<a id="__codelineno-83-16" name="__codelineno-83-16" href="#__codelineno-83-16"></a>
<a id="__codelineno-83-17" name="__codelineno-83-17" href="#__codelineno-83-17"></a><span class="c1"># Restart services</span>
<a id="__codelineno-83-18" name="__codelineno-83-18" href="#__codelineno-83-18"></a>ssh<span class="w"> </span>root@router<span class="w"> </span><span class="s2">&quot;/etc/init.d/rpcd restart &amp;&amp; /etc/init.d/uhttpd restart&quot;</span>
<a id="__codelineno-83-19" name="__codelineno-83-19" href="#__codelineno-83-19"></a>
<a id="__codelineno-83-20" name="__codelineno-83-20" href="#__codelineno-83-20"></a><span class="c1"># Test ubus</span>
<a id="__codelineno-83-21" name="__codelineno-83-21" href="#__codelineno-83-21"></a>ssh<span class="w"> </span>root@router<span class="w"> </span><span class="s2">&quot;ubus list | grep luci&quot;</span>
<a id="__codelineno-83-22" name="__codelineno-83-22" href="#__codelineno-83-22"></a>ssh<span class="w"> </span>root@router<span class="w"> </span><span class="s2">&quot;ubus call luci.module-name getStatus&quot;</span>
<a id="__codelineno-83-23" name="__codelineno-83-23" href="#__codelineno-83-23"></a>
<a id="__codelineno-83-24" name="__codelineno-83-24" href="#__codelineno-83-24"></a><span class="c1"># Validate JSON</span>
<a id="__codelineno-83-25" name="__codelineno-83-25" href="#__codelineno-83-25"></a>jsonlint<span class="w"> </span>file.json
<a id="__codelineno-83-26" name="__codelineno-83-26" href="#__codelineno-83-26"></a>jq<span class="w"> </span>.<span class="w"> </span>file.json
</code></pre></div>
<h3 id="css-classes-quick-reference">CSS Classes Quick Reference<a class="headerlink" href="#css-classes-quick-reference" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><a id="__codelineno-84-1" name="__codelineno-84-1" href="#__codelineno-84-1"></a><span class="c">/* Layout */</span>
<a id="__codelineno-84-2" name="__codelineno-84-2" href="#__codelineno-84-2"></a><span class="p">.</span><span class="nc">sh-page-header</span><span class="w"> </span><span class="c">/* Page header container */</span>
<a id="__codelineno-84-3" name="__codelineno-84-3" href="#__codelineno-84-3"></a><span class="p">.</span><span class="nc">sh-page-title</span><span class="w"> </span><span class="c">/* Page title (gradient text) */</span>
<a id="__codelineno-84-4" name="__codelineno-84-4" href="#__codelineno-84-4"></a><span class="p">.</span><span class="nc">sh-page-subtitle</span><span class="w"> </span><span class="c">/* Page subtitle */</span>
<a id="__codelineno-84-5" name="__codelineno-84-5" href="#__codelineno-84-5"></a>
<a id="__codelineno-84-6" name="__codelineno-84-6" href="#__codelineno-84-6"></a><span class="c">/* Stats */</span>
<a id="__codelineno-84-7" name="__codelineno-84-7" href="#__codelineno-84-7"></a><span class="p">.</span><span class="nc">sh-stats-grid</span><span class="w"> </span><span class="c">/* Grid for stat badges (130px min) */</span>
<a id="__codelineno-84-8" name="__codelineno-84-8" href="#__codelineno-84-8"></a><span class="p">.</span><span class="nc">sh-stat-badge</span><span class="w"> </span><span class="c">/* Stat badge container */</span>
<a id="__codelineno-84-9" name="__codelineno-84-9" href="#__codelineno-84-9"></a><span class="p">.</span><span class="nc">sh-stat-value</span><span class="w"> </span><span class="c">/* Stat value (monospace) */</span>
<a id="__codelineno-84-10" name="__codelineno-84-10" href="#__codelineno-84-10"></a><span class="p">.</span><span class="nc">sh-stat-label</span><span class="w"> </span><span class="c">/* Stat label (uppercase) */</span>
<a id="__codelineno-84-11" name="__codelineno-84-11" href="#__codelineno-84-11"></a>
<a id="__codelineno-84-12" name="__codelineno-84-12" href="#__codelineno-84-12"></a><span class="c">/* Cards */</span>
<a id="__codelineno-84-13" name="__codelineno-84-13" href="#__codelineno-84-13"></a><span class="p">.</span><span class="nc">sh-card</span><span class="w"> </span><span class="c">/* Card container (with gradient border on hover) */</span>
<a id="__codelineno-84-14" name="__codelineno-84-14" href="#__codelineno-84-14"></a><span class="p">.</span><span class="nc">sh-card-success</span><span class="w"> </span><span class="c">/* Card with green border */</span>
<a id="__codelineno-84-15" name="__codelineno-84-15" href="#__codelineno-84-15"></a><span class="p">.</span><span class="nc">sh-card-danger</span><span class="w"> </span><span class="c">/* Card with red border */</span>
<a id="__codelineno-84-16" name="__codelineno-84-16" href="#__codelineno-84-16"></a><span class="p">.</span><span class="nc">sh-card-warning</span><span class="w"> </span><span class="c">/* Card with orange border */</span>
<a id="__codelineno-84-17" name="__codelineno-84-17" href="#__codelineno-84-17"></a><span class="p">.</span><span class="nc">sh-card-header</span><span class="w"> </span><span class="c">/* Card header */</span>
<a id="__codelineno-84-18" name="__codelineno-84-18" href="#__codelineno-84-18"></a><span class="p">.</span><span class="nc">sh-card-title</span><span class="w"> </span><span class="c">/* Card title */</span>
<a id="__codelineno-84-19" name="__codelineno-84-19" href="#__codelineno-84-19"></a><span class="p">.</span><span class="nc">sh-card-body</span><span class="w"> </span><span class="c">/* Card content */</span>
<a id="__codelineno-84-20" name="__codelineno-84-20" href="#__codelineno-84-20"></a>
<a id="__codelineno-84-21" name="__codelineno-84-21" href="#__codelineno-84-21"></a><span class="c">/* Buttons */</span>
<a id="__codelineno-84-22" name="__codelineno-84-22" href="#__codelineno-84-22"></a><span class="p">.</span><span class="nc">sh-btn</span><span class="w"> </span><span class="c">/* Base button */</span>
<a id="__codelineno-84-23" name="__codelineno-84-23" href="#__codelineno-84-23"></a><span class="p">.</span><span class="nc">sh-btn-primary</span><span class="w"> </span><span class="c">/* Primary button (gradient) */</span>
<a id="__codelineno-84-24" name="__codelineno-84-24" href="#__codelineno-84-24"></a><span class="p">.</span><span class="nc">sh-btn-success</span><span class="w"> </span><span class="c">/* Success button (green) */</span>
<a id="__codelineno-84-25" name="__codelineno-84-25" href="#__codelineno-84-25"></a><span class="p">.</span><span class="nc">sh-btn-danger</span><span class="w"> </span><span class="c">/* Danger button (red) */</span>
<a id="__codelineno-84-26" name="__codelineno-84-26" href="#__codelineno-84-26"></a><span class="p">.</span><span class="nc">sh-btn-secondary</span><span class="w"> </span><span class="c">/* Secondary button (outline) */</span>
<a id="__codelineno-84-27" name="__codelineno-84-27" href="#__codelineno-84-27"></a>
<a id="__codelineno-84-28" name="__codelineno-84-28" href="#__codelineno-84-28"></a><span class="c">/* Tabs */</span>
<a id="__codelineno-84-29" name="__codelineno-84-29" href="#__codelineno-84-29"></a><span class="p">.</span><span class="nc">sh-filter-tabs</span><span class="w"> </span><span class="c">/* Filter tabs container */</span>
<a id="__codelineno-84-30" name="__codelineno-84-30" href="#__codelineno-84-30"></a><span class="p">.</span><span class="nc">sh-filter-tab</span><span class="w"> </span><span class="c">/* Filter tab */</span>
<a id="__codelineno-84-31" name="__codelineno-84-31" href="#__codelineno-84-31"></a><span class="p">.</span><span class="nc">sh-filter-tab</span><span class="p">.</span><span class="nc">active</span><span class="w"> </span><span class="c">/* Active filter tab (gradient) */</span>
<a id="__codelineno-84-32" name="__codelineno-84-32" href="#__codelineno-84-32"></a><span class="p">.</span><span class="nc">sh-nav-tabs</span><span class="w"> </span><span class="c">/* Navigation tabs (sticky) */</span>
<a id="__codelineno-84-33" name="__codelineno-84-33" href="#__codelineno-84-33"></a><span class="p">.</span><span class="nc">sh-nav-tab</span><span class="w"> </span><span class="c">/* Navigation tab */</span>
<a id="__codelineno-84-34" name="__codelineno-84-34" href="#__codelineno-84-34"></a><span class="p">.</span><span class="nc">sh-nav-tab</span><span class="p">.</span><span class="nc">active</span><span class="w"> </span><span class="c">/* Active nav tab (underline) */</span>
<a id="__codelineno-84-35" name="__codelineno-84-35" href="#__codelineno-84-35"></a>
<a id="__codelineno-84-36" name="__codelineno-84-36" href="#__codelineno-84-36"></a><span class="c">/* Utilities */</span>
<a id="__codelineno-84-37" name="__codelineno-84-37" href="#__codelineno-84-37"></a><span class="p">.</span><span class="nc">sh-gradient-text</span><span class="w"> </span><span class="c">/* Gradient text effect */</span>
<a id="__codelineno-84-38" name="__codelineno-84-38" href="#__codelineno-84-38"></a><span class="p">.</span><span class="nc">sh-id-display</span><span class="w"> </span><span class="c">/* Monospace ID display */</span>
<a id="__codelineno-84-39" name="__codelineno-84-39" href="#__codelineno-84-39"></a><span class="p">.</span><span class="nc">sh-empty-state</span><span class="w"> </span><span class="c">/* Empty state placeholder */</span>
</code></pre></div>
<h3 id="color-variables-quick-reference">Color Variables Quick Reference<a class="headerlink" href="#color-variables-quick-reference" title="Permanent link">&para;</a></h3>
<div class="highlight"><pre><span></span><code><a id="__codelineno-85-1" name="__codelineno-85-1" href="#__codelineno-85-1"></a><span class="c">/* Text */</span>
<a id="__codelineno-85-2" name="__codelineno-85-2" href="#__codelineno-85-2"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-text-primary</span><span class="o">)</span><span class="w"> </span><span class="c">/* Main text */</span>
<a id="__codelineno-85-3" name="__codelineno-85-3" href="#__codelineno-85-3"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-text-secondary</span><span class="o">)</span><span class="w"> </span><span class="c">/* Secondary text */</span>
<a id="__codelineno-85-4" name="__codelineno-85-4" href="#__codelineno-85-4"></a>
<a id="__codelineno-85-5" name="__codelineno-85-5" href="#__codelineno-85-5"></a><span class="c">/* Backgrounds */</span>
<a id="__codelineno-85-6" name="__codelineno-85-6" href="#__codelineno-85-6"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-bg-primary</span><span class="o">)</span><span class="w"> </span><span class="c">/* Main background */</span>
<a id="__codelineno-85-7" name="__codelineno-85-7" href="#__codelineno-85-7"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-bg-secondary</span><span class="o">)</span><span class="w"> </span><span class="c">/* Secondary background */</span>
<a id="__codelineno-85-8" name="__codelineno-85-8" href="#__codelineno-85-8"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-bg-tertiary</span><span class="o">)</span><span class="w"> </span><span class="c">/* Tertiary background */</span>
<a id="__codelineno-85-9" name="__codelineno-85-9" href="#__codelineno-85-9"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-bg-card</span><span class="o">)</span><span class="w"> </span><span class="c">/* Card background */</span>
<a id="__codelineno-85-10" name="__codelineno-85-10" href="#__codelineno-85-10"></a>
<a id="__codelineno-85-11" name="__codelineno-85-11" href="#__codelineno-85-11"></a><span class="c">/* Borders */</span>
<a id="__codelineno-85-12" name="__codelineno-85-12" href="#__codelineno-85-12"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-border</span><span class="o">)</span><span class="w"> </span><span class="c">/* Border color */</span>
<a id="__codelineno-85-13" name="__codelineno-85-13" href="#__codelineno-85-13"></a>
<a id="__codelineno-85-14" name="__codelineno-85-14" href="#__codelineno-85-14"></a><span class="c">/* Colors */</span>
<a id="__codelineno-85-15" name="__codelineno-85-15" href="#__codelineno-85-15"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-primary</span><span class="o">)</span><span class="w"> </span><span class="c">/* Indigo #6366f1 */</span>
<a id="__codelineno-85-16" name="__codelineno-85-16" href="#__codelineno-85-16"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-primary-end</span><span class="o">)</span><span class="w"> </span><span class="c">/* Violet #8b5cf6 */</span>
<a id="__codelineno-85-17" name="__codelineno-85-17" href="#__codelineno-85-17"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-success</span><span class="o">)</span><span class="w"> </span><span class="c">/* Green #22c55e */</span>
<a id="__codelineno-85-18" name="__codelineno-85-18" href="#__codelineno-85-18"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-danger</span><span class="o">)</span><span class="w"> </span><span class="c">/* Red #ef4444 */</span>
<a id="__codelineno-85-19" name="__codelineno-85-19" href="#__codelineno-85-19"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-warning</span><span class="o">)</span><span class="w"> </span><span class="c">/* Orange #f59e0b */</span>
<a id="__codelineno-85-20" name="__codelineno-85-20" href="#__codelineno-85-20"></a>
<a id="__codelineno-85-21" name="__codelineno-85-21" href="#__codelineno-85-21"></a><span class="c">/* Effects */</span>
<a id="__codelineno-85-22" name="__codelineno-85-22" href="#__codelineno-85-22"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-shadow</span><span class="o">)</span><span class="w"> </span><span class="c">/* Box shadow */</span>
<a id="__codelineno-85-23" name="__codelineno-85-23" href="#__codelineno-85-23"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-hover-shadow</span><span class="o">)</span><span class="w"> </span><span class="c">/* Hover shadow */</span>
<a id="__codelineno-85-24" name="__codelineno-85-24" href="#__codelineno-85-24"></a><span class="nt">var</span><span class="o">(</span><span class="nt">--sh-hover-bg</span><span class="o">)</span><span class="w"> </span><span class="c">/* Hover background */</span>
</code></pre></div>
<hr />
<h2 id="ai-assistant-context-files">AI Assistant Context Files<a class="headerlink" href="#ai-assistant-context-files" title="Permanent link">&para;</a></h2>
<p>SecuBox work is shared between Claude and Codex assistants. Keep the context folders synchronized so any agent can resume work quickly:</p>
<table>
<thead>
<tr>
<th>Directory</th>
<th>File</th>
<th>Usage</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>.claude/</code></td>
<td><code>HISTORY.md</code></td>
<td>Chronological log of UI/theme changes and major deployments</td>
</tr>
<tr>
<td><code>.claude/</code></td>
<td><code>TODO.md</code></td>
<td>High-level backlog (UX polish, docs, automation ideas)</td>
</tr>
<tr>
<td><code>.claude/</code></td>
<td><code>WIP.md</code></td>
<td>Active tasks, risks, and immediate next steps</td>
</tr>
<tr>
<td><code>.codex/</code></td>
<td><code>HISTORY.md</code></td>
<td>Mirrors the development timeline for Codex sessions</td>
</tr>
<tr>
<td><code>.codex/</code></td>
<td><code>TODO.md</code></td>
<td>Tooling-focused tasks (linting, scripts, build automation)</td>
</tr>
<tr>
<td><code>.codex/</code></td>
<td><code>WIP.md</code></td>
<td>Status tracker for ongoing Codex efforts</td>
</tr>
</tbody>
</table>
<p><strong>Maintenance rules</strong></p>
<ol>
<li><strong>Update after each session:</strong> When finishing work, append a short bullet to HISTORY and adjust WIP/TODO so they reflect the new state.</li>
<li><strong>Reference deployment scripts:</strong> Note which <code>secubox-tools/*.sh</code> script was used (dashboard vs. full deploy) so the next assistant knows how to reproduce it.</li>
<li><strong>Keep entries concise:</strong> A single paragraph or bullet per update is enough; detailed specs remain in DOCS.</li>
<li><strong>Cross-check before big changes:</strong> Read both folders before starting work to avoid conflicts or duplicate efforts.</li>
</ol>
<p>Treat these files as living handoff notes—if they drift, onboarding a new AI/teammate becomes significantly slower.</p>
<hr />
<h2 id="conclusion">Conclusion<a class="headerlink" href="#conclusion" title="Permanent link">&para;</a></h2>
<p>Ce guide doit être consulté <strong>AVANT</strong> 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</p>
<p><strong>En cas de doute, TOUJOURS:</strong>
1. Consulter ce guide
2. Exécuter validate-modules.sh
3. Tester en mode privé
4. Vérifier la console browser (F12)</p>
<p><strong>Ressources supplémentaires:</strong>
- CLAUDE.md - Architecture et build
- secubox-tools/validate-modules.sh - Validation automatique
- Templates/ - Templates de code</p>
<hr />
<p><strong>Dernière mise à jour:</strong> 2025-12-26
<strong>Maintenu par:</strong> CyberMind Studio
<strong>Version du guide:</strong> 1.0.0</p>
</article>
</div>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
<div class="md-social">
<a href="https://github.com/CyberMind-FR/secubox-openwrt" target="_blank" rel="noopener" title="github.com" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M173.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6m-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3m44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9M252.8 8C114.1 8 8 113.3 8 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C436.2 457.8 504 362.9 504 252 504 113.3 391.5 8 252.8 8M105.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1m-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7m32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1m-11.4-14.7c-1.6 1-1.6 3.6 0 5.9s4.3 3.3 5.6 2.3c1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2"/></svg>
</a>
<a href="https://secubox.cybermood.eu" target="_blank" rel="noopener" title="secubox.cybermood.eu" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M351.9 280H161c2.9 64.5 17.2 123.9 37.5 167.4 11.4 24.5 23.7 41.8 35.1 52.4 11.2 10.5 18.9 12.2 22.9 12.2s11.7-1.7 22.9-12.2c11.4-10.6 23.7-28 35.1-52.4 20.3-43.5 34.6-102.9 37.5-167.4zm-191-48h190.9c-2.8-64.5-17.1-123.9-37.4-167.4-11.4-24.4-23.7-41.8-35.1-52.4C268.1 1.7 260.4 0 256.4 0s-11.7 1.7-22.9 12.2c-11.4 10.6-23.7 28-35.1 52.4-20.3 43.5-34.6 102.9-37.5 167.4m-48 0c3.5-85.6 25.6-165.1 57.9-217.3C78.7 47.3 10.9 131.2 1.5 232zM1.5 280c9.4 100.8 77.2 184.7 169.3 217.3-32.3-52.2-54.4-131.7-57.9-217.3zm398.4 0c-3.5 85.6-25.6 165.1-57.9 217.3 92.1-32.7 159.9-116.5 169.3-217.3zm111.4-48C501.9 131.2 434.1 47.3 342 14.7c32.3 52.2 54.4 131.7 57.9 217.3z"/></svg>
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "..", "features": ["navigation.instant", "navigation.tracking", "navigation.tabs", "navigation.tabs.sticky", "navigation.sections", "navigation.expand", "navigation.top", "search.suggest", "search.highlight", "content.code.copy", "content.code.annotate"], "search": "../assets/javascripts/workers/search.2c215733.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": {"provider": "mike"}}</script>
<script src="../assets/javascripts/bundle.79ae519e.min.js"></script>
</body>
</html>