secubox-openwrt/package/secubox/luci-app-system-hub/htdocs/luci-static/resources/system-hub/dev-status-standalone.html
CyberMind-FR 0cdbffda4c feat(dev-status): Redesign widget v2.1 with dynamic architecture dashboard
- 4-layer architecture visualization (Core, AI, MirrorNet, Certification)
- 22+ features with dependency tracking (dependsOn/usedBy)
- 80+ components with status indicators
- Interactive filters: layer, status, category with localStorage persistence
- Feature cards: click to expand and see full dependencies
- Live RPCD data refresh (60s auto-refresh)
- Standalone HTML page for public access (/dev-status.html)
- ES5 compatible for older browsers
- Milestone timeline to v1.0

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-09 13:02:28 +01:00

367 lines
40 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. 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">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SecuBox Development Status</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: #0f1019;
color: #f1f5f9;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
min-height: 100vh;
}
.page-header {
background: linear-gradient(135deg, #1a1a24 0%, #0f1019 100%);
border-bottom: 1px solid #2a2a3a;
padding: 24px 32px;
}
.page-header h1 {
font-size: 24px;
font-weight: 800;
background: linear-gradient(135deg, #10b981, #06b6d4);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 4px;
}
.page-header p {
color: #94a3b8;
font-size: 14px;
}
.page-header a {
color: #06b6d4;
text-decoration: none;
}
.page-header a:hover {
text-decoration: underline;
}
#dev-status-container {
max-width: 1400px;
margin: 0 auto;
}
.footer {
text-align: center;
padding: 24px;
color: #64748b;
font-size: 12px;
border-top: 1px solid #2a2a3a;
margin-top: 32px;
}
.footer a {
color: #06b6d4;
text-decoration: none;
}
</style>
</head>
<body>
<div class="page-header">
<h1>SecuBox OpenWrt</h1>
<p>Development Status Dashboard &mdash; <a href="https://secubox.in" target="_blank">secubox.in</a></p>
</div>
<div id="dev-status-container"></div>
<div class="footer">
<p>SecuBox OpenWrt &copy; 2024-2026 &mdash; <a href="https://github.com/secubox" target="_blank">GitHub</a></p>
</div>
<script>
// Inline the widget for standalone mode
var DevStatusWidget = {
targetVersion: '1.0.0',
lastUpdate: '2026-03-09',
totalPackages: 185,
refreshInterval: null,
refreshSeconds: 60,
activeFilters: { layer: null, status: null, category: null },
layers: {
'core': { id: 'core', name: 'Couche 1: Core Mesh', description: 'Infrastructure fondamentale: reverse proxy, WAF, DNS, containers', progress: 85, icon: '🏗️', color: '#10b981', order: 1 },
'ai': { id: 'ai', name: 'Couche 2: AI Gateway', description: 'Intelligence artificielle: inference, agents, mémoire contextuelle', progress: 60, icon: '🤖', color: '#8b5cf6', order: 2 },
'mirrornet': { id: 'mirrornet', name: 'Couche 3: MirrorNet P2P', description: 'Réseau maillé: identité, gossip, partage IOC, mirroring', progress: 40, icon: '🌐', color: '#06b6d4', order: 3 },
'certification': { id: 'certification', name: 'Couche 4: Certification', description: 'Conformité: ANSSI CSPN, CRA, audit sécurité', progress: 20, icon: '🏆', color: '#f59e0b', order: 4 }
},
features: {
'intrusion-prevention': { id: 'intrusion-prevention', name: 'Intrusion Prevention', layer: 'core', category: 'security', status: 'production', progress: 95, icon: '🛡️', description: 'Détection et blocage des menaces en temps réel', components: ['crowdsec', 'firewall-bouncer', 'wazuh'], dependsOn: ['network-stack'], usedBy: ['threat-intelligence', 'ai-security'] },
'waf': { id: 'waf', name: 'Web Application Firewall', layer: 'core', category: 'security', status: 'production', progress: 90, icon: '🔥', description: 'Inspection HTTP/HTTPS, détection bots, analytics', components: ['mitmproxy', 'haproxy-router', 'analytics'], dependsOn: ['reverse-proxy'], usedBy: ['session-analytics', 'threat-intelligence'] },
'dns-firewall': { id: 'dns-firewall', name: 'DNS Firewall', layer: 'core', category: 'security', status: 'production', progress: 85, icon: '🚫', description: 'Blocage DNS (RPZ), threat feeds, mesh DNS', components: ['vortex-dns', 'vortex-firewall', 'rpz-zones'], dependsOn: ['dns-master'], usedBy: ['ai-security', 'mesh-network'] },
'access-control': { id: 'access-control', name: 'Access Control', layer: 'core', category: 'security', status: 'production', progress: 90, icon: '🔐', description: 'NAC, portail captif, OAuth2, vouchers', components: ['auth-guardian', 'client-guardian', 'nodogsplash', 'mac-guardian'], dependsOn: ['network-stack'], usedBy: ['user-management'] },
'reverse-proxy': { id: 'reverse-proxy', name: 'Reverse Proxy & SSL', layer: 'core', category: 'network', status: 'production', progress: 95, icon: '🔀', description: 'HAProxy SNI routing, ACME SSL, 226 vhosts', components: ['haproxy', 'acme', 'vhost-manager'], dependsOn: ['dns-master'], usedBy: ['waf', 'service-exposure'] },
'dns-master': { id: 'dns-master', name: 'DNS Master', layer: 'core', category: 'network', status: 'production', progress: 90, icon: '🌍', description: 'BIND9 authoritative, zone management, 7 zones', components: ['bind9', 'dns-provider', 'zone-editor'], dependsOn: [], usedBy: ['reverse-proxy', 'dns-firewall', 'mesh-network'] },
'vpn-mesh': { id: 'vpn-mesh', name: 'VPN & Mesh', layer: 'core', category: 'network', status: 'production', progress: 85, icon: '🔒', description: 'WireGuard tunnels, QR codes, mesh topology', components: ['wireguard', 'mesh-discovery', 'qr-generator'], dependsOn: ['network-stack'], usedBy: ['mirrornet-p2p', 'master-link'] },
'bandwidth-qos': { id: 'bandwidth-qos', name: 'Bandwidth & QoS', layer: 'core', category: 'network', status: 'production', progress: 85, icon: '📊', description: 'SQM/CAKE, quotas, traffic shaping', components: ['bandwidth-manager', 'traffic-shaper', 'sqm'], dependsOn: ['network-stack'], usedBy: ['media-services'] },
'container-platform': { id: 'container-platform', name: 'Container Platform', layer: 'core', category: 'services', status: 'production', progress: 95, icon: '📦', description: 'LXC containers, 18 running, auto-start', components: ['lxc-manager', 'container-networking', 'resource-limits'], dependsOn: ['network-stack'], usedBy: ['media-services', 'communication', 'cloud-services'] },
'media-services': { id: 'media-services', name: 'Media Services', layer: 'core', category: 'services', status: 'production', progress: 90, icon: '🎬', description: 'Streaming, photos, musique', components: ['jellyfin', 'photoprism', 'lyrion', 'peertube'], dependsOn: ['container-platform', 'reverse-proxy'], usedBy: [] },
'communication': { id: 'communication', name: 'Communication', layer: 'core', category: 'services', status: 'production', progress: 85, icon: '💬', description: 'Chat, video, federation', components: ['matrix', 'jitsi', 'jabber', 'gotosocial', 'simplex'], dependsOn: ['container-platform', 'reverse-proxy'], usedBy: [] },
'cloud-services': { id: 'cloud-services', name: 'Cloud Services', layer: 'core', category: 'services', status: 'production', progress: 85, icon: '☁️', description: 'Files, email, git', components: ['nextcloud', 'mailserver', 'gitea'], dependsOn: ['container-platform', 'reverse-proxy'], usedBy: [] },
'remote-access': { id: 'remote-access', name: 'Remote Access', layer: 'core', category: 'services', status: 'production', progress: 80, icon: '🖥️', description: 'Terminal web, RDP, TURN/STUN', components: ['rtty-remote', 'turn-server', 'rustdesk'], dependsOn: ['reverse-proxy'], usedBy: ['master-link'] },
'ai-inference': { id: 'ai-inference', name: 'AI Inference', layer: 'ai', category: 'ai', status: 'production', progress: 80, icon: '🧠', description: 'LocalAI, Ollama, embeddings, completions', components: ['localai', 'ollama', 'model-manager'], dependsOn: ['container-platform'], usedBy: ['ai-security', 'ai-agents'] },
'ai-security': { id: 'ai-security', name: 'AI Security Agents', layer: 'ai', category: 'ai', status: 'beta', progress: 50, icon: '🤖', description: 'Threat analysis, DNS anomaly, network behavior', components: ['threat-analyst', 'dns-guard-ai', 'network-anomaly'], dependsOn: ['ai-inference', 'intrusion-prevention'], usedBy: [] },
'ai-memory': { id: 'ai-memory', name: 'AI Memory & Context', layer: 'ai', category: 'ai', status: 'alpha', progress: 30, icon: '💾', description: 'LocalRecall, RAG, conversation history', components: ['localrecall', 'mcp-server', 'embedding-store'], dependsOn: ['ai-inference'], usedBy: ['ai-security'] },
'mesh-network': { id: 'mesh-network', name: 'Mesh Network', layer: 'mirrornet', category: 'p2p', status: 'beta', progress: 50, icon: '🕸️', description: 'P2P mesh, gossip protocol, service discovery', components: ['p2p-core', 'gossip', 'mesh-dns'], dependsOn: ['vpn-mesh', 'dns-master'], usedBy: ['p2p-intel', 'service-mirroring'] },
'identity-trust': { id: 'identity-trust', name: 'Identity & Trust', layer: 'mirrornet', category: 'p2p', status: 'alpha', progress: 30, icon: '🪪', description: 'DID identity, reputation, trust hierarchy', components: ['identity-did', 'reputation', 'master-link'], dependsOn: ['mesh-network'], usedBy: ['p2p-intel'] },
'p2p-intel': { id: 'p2p-intel', name: 'P2P Intelligence', layer: 'mirrornet', category: 'p2p', status: 'alpha', progress: 25, icon: '🔍', description: 'IOC sharing, signed alerts, collective defense', components: ['p2p-intel-core', 'ioc-signatures', 'alert-propagation'], dependsOn: ['identity-trust', 'intrusion-prevention'], usedBy: [] },
'service-exposure': { id: 'service-exposure', name: 'Service Exposure', layer: 'core', category: 'exposure', status: 'production', progress: 80, icon: '🚀', description: 'Peek/Poke/Emancipate, multi-channel exposure', components: ['exposure-engine', 'tor-hidden', 'dns-ssl', 'mesh-publish'], dependsOn: ['reverse-proxy', 'dns-master'], usedBy: ['mesh-network'] },
'system-monitoring': { id: 'system-monitoring', name: 'System Monitoring', layer: 'core', category: 'monitoring', status: 'production', progress: 90, icon: '📈', description: 'Glances, Netdata, system health', components: ['glances', 'netdata', 'health-checks'], dependsOn: [], usedBy: ['ai-security'] },
'network-analytics': { id: 'network-analytics', name: 'Network Analytics', layer: 'core', category: 'monitoring', status: 'production', progress: 85, icon: '🔬', description: 'DPI, flow analysis, application detection', components: ['netifyd', 'ndpid', 'flow-analyzer'], dependsOn: ['network-stack'], usedBy: ['ai-security', 'bandwidth-qos'] },
'session-analytics': { id: 'session-analytics', name: 'Session Analytics', layer: 'core', category: 'monitoring', status: 'production', progress: 85, icon: '👁️', description: 'Avatar-Tap recording, cookie tracking, replay', components: ['avatar-tap', 'cookie-tracker', 'session-replay'], dependsOn: ['waf'], usedBy: ['threat-intelligence'] },
'threat-intelligence': { id: 'threat-intelligence', name: 'Threat Intelligence', layer: 'core', category: 'monitoring', status: 'production', progress: 80, icon: '🎯', description: 'CVE triage, cyberfeed, device intel', components: ['cve-triage', 'cyberfeed', 'device-intel'], dependsOn: ['intrusion-prevention'], usedBy: ['ai-security'] },
'config-management': { id: 'config-management', name: 'Configuration Management', layer: 'certification', category: 'admin', status: 'beta', progress: 60, icon: '', description: 'Backup, restore, config advisor, cloning', components: ['backup', 'config-advisor', 'cloner'], dependsOn: [], usedBy: [] },
'compliance': { id: 'compliance', name: 'Compliance & Audit', layer: 'certification', category: 'admin', status: 'alpha', progress: 20, icon: '📋', description: 'ANSSI CSPN, CRA, security audit', components: ['anssi-checker', 'sbom-generator', 'audit-log'], dependsOn: ['config-management'], usedBy: [] }
},
components: {
'crowdsec': { name: 'CrowdSec', type: 'backend', status: 'production' },
'firewall-bouncer': { name: 'Firewall Bouncer', type: 'backend', status: 'production' },
'wazuh': { name: 'Wazuh SIEM', type: 'backend', status: 'production' },
'mitmproxy': { name: 'Mitmproxy WAF', type: 'backend', status: 'production' },
'haproxy-router': { name: 'HAProxy Router', type: 'addon', status: 'production' },
'analytics': { name: 'SecuBox Analytics', type: 'addon', status: 'production' },
'vortex-dns': { name: 'Vortex DNS', type: 'backend', status: 'production' },
'vortex-firewall': { name: 'Vortex Firewall', type: 'backend', status: 'production' },
'rpz-zones': { name: 'RPZ Zones', type: 'config', status: 'production' },
'auth-guardian': { name: 'Auth Guardian', type: 'luci', status: 'production' },
'client-guardian': { name: 'Client Guardian', type: 'luci', status: 'production' },
'nodogsplash': { name: 'Nodogsplash', type: 'backend', status: 'production' },
'mac-guardian': { name: 'MAC Guardian', type: 'backend', status: 'production' },
'haproxy': { name: 'HAProxy', type: 'backend', status: 'production' },
'acme': { name: 'ACME SSL', type: 'backend', status: 'production' },
'vhost-manager': { name: 'VHost Manager', type: 'luci', status: 'production' },
'bind9': { name: 'BIND9', type: 'backend', status: 'production' },
'dns-provider': { name: 'DNS Provider API', type: 'backend', status: 'beta' },
'zone-editor': { name: 'Zone Editor', type: 'luci', status: 'production' },
'wireguard': { name: 'WireGuard', type: 'backend', status: 'production' },
'mesh-discovery': { name: 'Mesh Discovery', type: 'backend', status: 'beta' },
'qr-generator': { name: 'QR Generator', type: 'addon', status: 'production' },
'bandwidth-manager': { name: 'Bandwidth Manager', type: 'luci', status: 'production' },
'traffic-shaper': { name: 'Traffic Shaper', type: 'luci', status: 'production' },
'sqm': { name: 'SQM/CAKE', type: 'backend', status: 'production' },
'lxc-manager': { name: 'LXC Manager', type: 'luci', status: 'production' },
'container-networking': { name: 'Container Networking', type: 'backend', status: 'production' },
'resource-limits': { name: 'Resource Limits', type: 'config', status: 'production' },
'jellyfin': { name: 'Jellyfin', type: 'backend', status: 'production' },
'photoprism': { name: 'PhotoPrism', type: 'backend', status: 'production' },
'lyrion': { name: 'Lyrion Music', type: 'backend', status: 'production' },
'peertube': { name: 'PeerTube', type: 'backend', status: 'beta' },
'matrix': { name: 'Matrix', type: 'backend', status: 'production' },
'jitsi': { name: 'Jitsi', type: 'backend', status: 'production' },
'jabber': { name: 'Prosody XMPP', type: 'backend', status: 'production' },
'gotosocial': { name: 'GoToSocial', type: 'backend', status: 'production' },
'simplex': { name: 'SimpleX', type: 'backend', status: 'beta' },
'nextcloud': { name: 'Nextcloud', type: 'backend', status: 'production' },
'mailserver': { name: 'Mail Server', type: 'backend', status: 'production' },
'gitea': { name: 'Gitea', type: 'backend', status: 'production' },
'rtty-remote': { name: 'RTTY Remote', type: 'backend', status: 'production' },
'turn-server': { name: 'TURN Server', type: 'backend', status: 'production' },
'rustdesk': { name: 'RustDesk', type: 'backend', status: 'beta' },
'localai': { name: 'LocalAI', type: 'backend', status: 'production' },
'ollama': { name: 'Ollama', type: 'backend', status: 'beta' },
'model-manager': { name: 'Model Manager', type: 'luci', status: 'beta' },
'threat-analyst': { name: 'Threat Analyst', type: 'backend', status: 'beta' },
'dns-guard-ai': { name: 'DNS Guard AI', type: 'backend', status: 'beta' },
'network-anomaly': { name: 'Network Anomaly', type: 'backend', status: 'beta' },
'localrecall': { name: 'LocalRecall', type: 'backend', status: 'alpha' },
'mcp-server': { name: 'MCP Server', type: 'backend', status: 'beta' },
'embedding-store': { name: 'Embedding Store', type: 'backend', status: 'alpha' },
'p2p-core': { name: 'P2P Core', type: 'backend', status: 'beta' },
'gossip': { name: 'Gossip Protocol', type: 'backend', status: 'beta' },
'mesh-dns': { name: 'Mesh DNS', type: 'backend', status: 'beta' },
'identity-did': { name: 'Identity DID', type: 'backend', status: 'alpha' },
'reputation': { name: 'Reputation System', type: 'backend', status: 'alpha' },
'master-link': { name: 'Master Link', type: 'backend', status: 'production' },
'p2p-intel-core': { name: 'P2P Intel Core', type: 'backend', status: 'alpha' },
'ioc-signatures': { name: 'IOC Signatures', type: 'backend', status: 'alpha' },
'alert-propagation': { name: 'Alert Propagation', type: 'backend', status: 'alpha' },
'exposure-engine': { name: 'Exposure Engine', type: 'backend', status: 'production' },
'tor-hidden': { name: 'Tor Hidden Services', type: 'backend', status: 'production' },
'dns-ssl': { name: 'DNS/SSL Channel', type: 'backend', status: 'production' },
'mesh-publish': { name: 'Mesh Publish', type: 'backend', status: 'beta' },
'glances': { name: 'Glances', type: 'backend', status: 'production' },
'netdata': { name: 'Netdata', type: 'backend', status: 'production' },
'health-checks': { name: 'Health Checks', type: 'backend', status: 'production' },
'netifyd': { name: 'Netifyd', type: 'backend', status: 'production' },
'ndpid': { name: 'nDPId', type: 'backend', status: 'production' },
'flow-analyzer': { name: 'Flow Analyzer', type: 'backend', status: 'production' },
'avatar-tap': { name: 'Avatar-Tap', type: 'backend', status: 'production' },
'cookie-tracker': { name: 'Cookie Tracker', type: 'backend', status: 'production' },
'session-replay': { name: 'Session Replay', type: 'luci', status: 'production' },
'cve-triage': { name: 'CVE Triage', type: 'backend', status: 'beta' },
'cyberfeed': { name: 'CyberFeed', type: 'backend', status: 'production' },
'device-intel': { name: 'Device Intel', type: 'backend', status: 'production' },
'backup': { name: 'Backup', type: 'backend', status: 'production' },
'config-advisor': { name: 'Config Advisor', type: 'backend', status: 'beta' },
'cloner': { name: 'Station Cloner', type: 'luci', status: 'alpha' },
'anssi-checker': { name: 'ANSSI Checker', type: 'backend', status: 'alpha' },
'sbom-generator': { name: 'SBOM Generator', type: 'backend', status: 'planned' },
'audit-log': { name: 'Audit Log', type: 'backend', status: 'beta' },
'network-stack': { name: 'Network Stack', type: 'system', status: 'production' }
},
milestones: [
{ version: '0.19', name: 'Core Stability', target: '2026-03-15', status: 'in-progress', progress: 85, highlights: ['RTTY Remote Web Terminal', 'DNS Master LuCI sync', 'WAF memory optimization'] },
{ version: '0.20', name: 'AI Gateway Expansion', target: '2026-03-30', status: 'planned', progress: 20, highlights: ['Threat Analyst auto-rules', 'DNS Guard AI', 'LocalRecall persistence'] },
{ version: '0.21', name: 'MirrorNet Phase 1', target: '2026-04-15', status: 'planned', progress: 10, highlights: ['DID Identity', 'Gossip protocol', 'IOC sharing'] },
{ version: '0.22', name: 'Station Cloning', target: '2026-04-30', status: 'planned', progress: 5, highlights: ['Clone image builder', 'Auto-mesh join', 'First-boot provisioning'] },
{ version: '1.0', name: 'Certification Ready', target: '2026-06-01', status: 'planned', progress: 0, highlights: ['ANSSI CSPN', 'CRA Annex I SBOM', 'Security documentation'] }
],
stats: { totalPackages: 185, luciApps: 89, backends: 96, lxcContainers: 18, haproxyVhosts: 226, sslCertificates: 92, dnsZones: 7, dnsRecords: 78, mitmproxyRoutes: 150, commits: 1700 },
loadFiltersFromStorage: function() {
try {
var stored = localStorage.getItem('dsw_filters');
if (stored) this.activeFilters = JSON.parse(stored);
} catch (e) {}
},
saveFiltersToStorage: function() {
try { localStorage.setItem('dsw_filters', JSON.stringify(this.activeFilters)); } catch (e) {}
},
calculateOverallProgress: function() {
var self = this;
var features = Object.keys(this.features).map(function(k) { return self.features[k]; });
var total = features.reduce(function(sum, f) { return sum + f.progress; }, 0);
return Math.round(total / features.length);
},
getStatusBadge: function(status) {
return { 'production': '', 'beta': '🔶', 'alpha': '🔷', 'planned': '' }[status] || '';
},
applyFilters: function() {
var self = this;
var cards = document.querySelectorAll('.dsw-feature-card');
cards.forEach(function(card) {
var feature = self.features[card.dataset.feature];
if (!feature) return;
var visible = true;
if (self.activeFilters.status && self.activeFilters.status !== 'all' && feature.status !== self.activeFilters.status) visible = false;
if (self.activeFilters.category && self.activeFilters.category !== 'all' && feature.category !== self.activeFilters.category) visible = false;
if (self.activeFilters.layer && feature.layer !== self.activeFilters.layer) visible = false;
card.style.opacity = visible ? '1' : '0.2';
card.style.pointerEvents = visible ? 'auto' : 'none';
});
document.querySelectorAll('.dsw-layer-card').forEach(function(card) {
card.classList.toggle('dsw-layer-active', card.dataset.layer === self.activeFilters.layer);
});
},
render: function(containerId) {
var self = this;
var container = document.getElementById(containerId);
if (!container) return;
this.loadFiltersFromStorage();
var overallProgress = this.calculateOverallProgress();
// Build layers HTML
var sortedLayers = Object.keys(this.layers).map(function(k) { return self.layers[k]; }).sort(function(a,b) { return a.order - b.order; });
var layersHtml = sortedLayers.map(function(layer) {
var featureCount = Object.keys(self.features).filter(function(k) { return self.features[k].layer === layer.id; }).length;
return '<div class="dsw-layer-card" data-layer="' + layer.id + '" style="--layer-color: ' + layer.color + '"><div class="dsw-layer-icon">' + layer.icon + '</div><div class="dsw-layer-info"><h3 class="dsw-layer-name">' + layer.name + '</h3><p class="dsw-layer-desc">' + layer.description + '</p></div><div class="dsw-layer-stats"><div class="dsw-layer-progress"><div class="dsw-layer-bar"><div class="dsw-layer-fill" style="width: ' + layer.progress + '%"></div></div><span class="dsw-layer-percent">' + layer.progress + '%</span></div><span class="dsw-layer-features">' + featureCount + ' features</span></div></div>';
}).join('');
// Build features by category
var categories = { security: {name:'Security',icon:'🛡️'}, network: {name:'Network',icon:'🌍'}, services: {name:'Services',icon:'📦'}, ai: {name:'AI',icon:'🤖'}, p2p: {name:'P2P/Mesh',icon:'🕸️'}, monitoring: {name:'Monitoring',icon:'📊'}, exposure: {name:'Exposure',icon:'🚀'}, admin: {name:'Admin',icon:'⚙️'} };
var featuresHtml = '';
Object.keys(categories).forEach(function(catId) {
var cat = categories[catId];
var features = Object.keys(self.features).filter(function(k) { return self.features[k].category === catId; }).map(function(k) { return self.features[k]; });
if (!features.length) return;
featuresHtml += '<div class="dsw-category" data-category="' + catId + '"><h4 class="dsw-category-title">' + cat.icon + ' ' + cat.name + '</h4><div class="dsw-features-grid">';
features.forEach(function(f) {
var layer = self.layers[f.layer];
var compTags = (f.components || []).slice(0,4).map(function(c) {
var comp = self.components[c];
return comp ? '<span class="dsw-component-tag dsw-comp-' + comp.status + '">' + comp.name + '</span>' : '';
}).join('');
featuresHtml += '<div class="dsw-feature-card dsw-status-' + f.status + '" data-feature="' + f.id + '" data-layer="' + f.layer + '" data-status="' + f.status + '"><div class="dsw-feature-header"><span class="dsw-feature-icon">' + f.icon + '</span><span class="dsw-feature-name">' + f.name + '</span><span class="dsw-feature-status">' + self.getStatusBadge(f.status) + '</span></div><p class="dsw-feature-desc">' + f.description + '</p><div class="dsw-feature-progress"><div class="dsw-feature-bar"><div class="dsw-feature-fill" style="width:' + f.progress + '%;background:' + layer.color + '"></div></div><span>' + f.progress + '%</span></div><div class="dsw-feature-components">' + compTags + '</div></div>';
});
featuresHtml += '</div></div>';
});
// Milestones
var milestonesHtml = this.milestones.map(function(m,i) {
var isActive = m.status === 'in-progress';
var highlights = m.highlights.map(function(h) { return '<li>' + h + '</li>'; }).join('');
return '<div class="dsw-milestone ' + (isActive?'dsw-milestone-active ':'') + 'dsw-milestone-' + m.status + '"><div class="dsw-milestone-marker"><div class="dsw-milestone-dot"></div>' + (i < self.milestones.length - 1 ? '<div class="dsw-milestone-line"></div>' : '') + '</div><div class="dsw-milestone-content"><div class="dsw-milestone-header"><span class="dsw-milestone-version">v' + m.version + '</span><span class="dsw-milestone-name">' + m.name + '</span><span class="dsw-milestone-date">' + m.target + '</span></div><div class="dsw-milestone-progress"><div class="dsw-milestone-bar"><div class="dsw-milestone-fill" style="width:' + m.progress + '%"></div></div><span>' + m.progress + '%</span></div><ul class="dsw-milestone-highlights">' + highlights + '</ul></div></div>';
}).join('');
// Stats
var statsData = [
{label:'Packages',value:this.stats.totalPackages,icon:'📦'},
{label:'LuCI Apps',value:this.stats.luciApps,icon:'🖥️'},
{label:'LXC Running',value:this.stats.lxcContainers,icon:'📦'},
{label:'HAProxy Vhosts',value:this.stats.haproxyVhosts,icon:'🔀'},
{label:'SSL Certs',value:this.stats.sslCertificates,icon:'🔒'},
{label:'DNS Zones',value:this.stats.dnsZones,icon:'🌍'},
{label:'WAF Routes',value:this.stats.mitmproxyRoutes,icon:'🔥'},
{label:'Commits',value:this.stats.commits,icon:'📝'}
];
var statsHtml = statsData.map(function(s) {
return '<div class="dsw-stat-card"><span class="dsw-stat-icon">' + s.icon + '</span><span class="dsw-stat-value">' + s.value + '</span><span class="dsw-stat-label">' + s.label + '</span></div>';
}).join('');
container.innerHTML = '<div class="dsw-v2">' + this.renderStyles() +
'<div class="dsw-header"><div class="dsw-header-left"><h2 class="dsw-title">SecuBox Development Status</h2><p class="dsw-subtitle">Architecture: ' + this.totalPackages + ' packages · 4 couches · ' + Object.keys(this.features).length + ' features</p></div><div class="dsw-header-right"><div class="dsw-progress-ring"><svg viewBox="0 0 100 100"><circle class="dsw-ring-bg" cx="50" cy="50" r="45"/><circle class="dsw-ring-fill" cx="50" cy="50" r="45" style="stroke-dasharray:' + (283*overallProgress/100) + ',283"/></svg><span class="dsw-ring-text">' + overallProgress + '%</span></div><div class="dsw-target"><span class="dsw-target-label">Target</span><span class="dsw-target-version">v' + this.targetVersion + '</span></div></div></div>' +
'<div class="dsw-controls"><div class="dsw-control-group"><label>Status:</label><select class="dsw-filter-status"><option value="all">All</option><option value="production">Production</option><option value="beta">Beta</option><option value="alpha">Alpha</option><option value="planned">Planned</option></select></div><div class="dsw-control-group"><label>Category:</label><select class="dsw-filter-category"><option value="all">All</option><option value="security">Security</option><option value="network">Network</option><option value="services">Services</option><option value="ai">AI</option><option value="p2p">P2P</option><option value="monitoring">Monitoring</option><option value="exposure">Exposure</option><option value="admin">Admin</option></select></div><div class="dsw-control-group"><button class="dsw-btn dsw-btn-clear">Clear Filters</button></div></div>' +
'<div class="dsw-section"><h3 class="dsw-section-title">🏛️ Architecture 4 Couches</h3><div class="dsw-layers-grid">' + layersHtml + '</div></div>' +
'<div class="dsw-section"><h3 class="dsw-section-title">📦 Features & Components</h3>' + featuresHtml + '</div>' +
'<div class="dsw-section"><h3 class="dsw-section-title">🎯 Milestones → v' + this.targetVersion + '</h3><div class="dsw-milestones-timeline">' + milestonesHtml + '</div></div>' +
'<div class="dsw-section"><h3 class="dsw-section-title">📈 Production Stats</h3><div class="dsw-stats-grid">' + statsHtml + '</div></div>' +
'</div>';
this.initInteractions();
},
initInteractions: function() {
var self = this;
document.querySelectorAll('.dsw-feature-card').forEach(function(card) {
card.addEventListener('click', function() { card.classList.toggle('dsw-expanded'); });
});
document.querySelectorAll('.dsw-layer-card').forEach(function(card) {
card.addEventListener('click', function() {
var layer = card.dataset.layer;
self.activeFilters.layer = (self.activeFilters.layer === layer) ? null : layer;
self.saveFiltersToStorage();
self.applyFilters();
});
});
var statusSelect = document.querySelector('.dsw-filter-status');
if (statusSelect) statusSelect.addEventListener('change', function() {
self.activeFilters.status = this.value === 'all' ? null : this.value;
self.saveFiltersToStorage();
self.applyFilters();
});
var categorySelect = document.querySelector('.dsw-filter-category');
if (categorySelect) categorySelect.addEventListener('change', function() {
self.activeFilters.category = this.value === 'all' ? null : this.value;
self.saveFiltersToStorage();
self.applyFilters();
});
var clearBtn = document.querySelector('.dsw-btn-clear');
if (clearBtn) clearBtn.addEventListener('click', function() {
self.activeFilters = { layer: null, status: null, category: null };
self.saveFiltersToStorage();
document.querySelector('.dsw-filter-status').value = 'all';
document.querySelector('.dsw-filter-category').value = 'all';
self.applyFilters();
});
},
renderStyles: function() {
return '<style>.dsw-v2{--dsw-bg:#0f1019;--dsw-card:#1a1a24;--dsw-border:#2a2a3a;--dsw-text:#f1f5f9;--dsw-muted:#94a3b8;--dsw-dim:#64748b;font-family:"Inter",-apple-system,sans-serif;color:var(--dsw-text);padding:24px}.dsw-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px;flex-wrap:wrap;gap:20px}.dsw-title{font-size:28px;font-weight:800;margin:0;background:linear-gradient(135deg,#10b981,#06b6d4);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}.dsw-subtitle{color:var(--dsw-muted);margin:8px 0 0;font-size:14px}.dsw-header-right{display:flex;align-items:center;gap:24px}.dsw-progress-ring{position:relative;width:80px;height:80px}.dsw-progress-ring svg{transform:rotate(-90deg);width:100%;height:100%}.dsw-ring-bg{fill:none;stroke:var(--dsw-border);stroke-width:8}.dsw-ring-fill{fill:none;stroke:#10b981;stroke-width:8;stroke-linecap:round}.dsw-ring-text{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);font-size:18px;font-weight:700;color:#10b981}.dsw-target{text-align:center}.dsw-target-label{display:block;font-size:11px;color:var(--dsw-dim);text-transform:uppercase}.dsw-target-version{font-size:20px;font-weight:700;color:#06b6d4}.dsw-controls{display:flex;align-items:center;gap:16px;margin-bottom:24px;flex-wrap:wrap;padding:12px 16px;background:var(--dsw-card);border-radius:8px;border:1px solid var(--dsw-border)}.dsw-control-group{display:flex;align-items:center;gap:8px}.dsw-control-group label{font-size:12px;color:var(--dsw-muted)}.dsw-control-group select{background:var(--dsw-bg);border:1px solid var(--dsw-border);color:var(--dsw-text);padding:6px 10px;border-radius:4px;font-size:12px;cursor:pointer}.dsw-btn{background:var(--dsw-bg);border:1px solid var(--dsw-border);color:var(--dsw-text);padding:6px 12px;border-radius:4px;font-size:12px;cursor:pointer;transition:all .2s}.dsw-btn:hover{border-color:#06b6d4;color:#06b6d4}.dsw-section{margin-bottom:32px}.dsw-section-title{font-size:18px;font-weight:700;margin-bottom:16px;display:flex;align-items:center;gap:8px}.dsw-layers-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px}.dsw-layer-card{background:var(--dsw-card);border:1px solid var(--dsw-border);border-radius:12px;padding:20px;display:flex;gap:16px;align-items:flex-start;cursor:pointer;transition:all .2s;border-left:4px solid var(--layer-color)}.dsw-layer-card:hover{transform:translateY(-2px);border-color:var(--layer-color)}.dsw-layer-card.dsw-layer-active{background:rgba(16,185,129,.1);border-color:var(--layer-color)}.dsw-layer-icon{font-size:32px}.dsw-layer-info{flex:1;min-width:0}.dsw-layer-name{font-size:14px;font-weight:700;margin:0 0 4px}.dsw-layer-desc{font-size:12px;color:var(--dsw-muted);margin:0}.dsw-layer-stats{text-align:right}.dsw-layer-progress{display:flex;align-items:center;gap:8px;margin-bottom:4px}.dsw-layer-bar{width:60px;height:6px;background:var(--dsw-bg);border-radius:3px;overflow:hidden}.dsw-layer-fill{height:100%;background:var(--layer-color);border-radius:3px}.dsw-layer-percent{font-size:14px;font-weight:700;color:var(--layer-color);min-width:36px}.dsw-layer-features{font-size:11px;color:var(--dsw-dim)}.dsw-category{margin-bottom:24px}.dsw-category-title{font-size:14px;font-weight:600;color:var(--dsw-muted);margin-bottom:12px}.dsw-features-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:16px}.dsw-feature-card{background:var(--dsw-card);border:1px solid var(--dsw-border);border-radius:12px;padding:16px;cursor:pointer;transition:all .2s}.dsw-feature-card:hover{border-color:#06b6d4;transform:translateY(-2px)}.dsw-feature-card.dsw-expanded{grid-column:span 2}.dsw-feature-header{display:flex;align-items:center;gap:10px;margin-bottom:8px}.dsw-feature-icon{font-size:20px}.dsw-feature-name{font-weight:700;flex:1}.dsw-feature-status{font-size:14px}.dsw-feature-desc{font-size:12px;color:var(--dsw-muted);margin-bottom:12px;line-height:1.4}.dsw-feature-progress{display:flex;align-items:center;gap:8px;margin-bottom:10px}.dsw-feature-bar{flex:1;height:6px;background:var(--dsw-bg);border-radius:3px;overflow:hidden}.dsw-feature-fill{height:100%;border-radius:3px}.dsw-feature-progress span{font-size:12px;font-weight:600;color:var(--dsw-muted);min-width:32px;text-align:right}.dsw-feature-components{display:flex;flex-wrap:wrap;gap:6px}.dsw-component-tag{font-size:10px;padding:3px 8px;border-radius:4px;background:var(--dsw-bg);color:var(--dsw-muted)}.dsw-comp-production{border-left:2px solid #10b981}.dsw-comp-beta{border-left:2px solid #f59e0b}.dsw-comp-alpha{border-left:2px solid #3b82f6}.dsw-status-production{border-left:3px solid #10b981}.dsw-status-beta{border-left:3px solid #f59e0b}.dsw-status-alpha{border-left:3px solid #3b82f6}.dsw-status-planned{border-left:3px solid var(--dsw-dim);opacity:.7}.dsw-milestones-timeline{position:relative}.dsw-milestone{display:flex;gap:20px}.dsw-milestone-marker{display:flex;flex-direction:column;align-items:center;padding-top:6px}.dsw-milestone-dot{width:14px;height:14px;border-radius:50%;background:var(--dsw-border);border:3px solid var(--dsw-card);z-index:1}.dsw-milestone-line{width:2px;flex:1;background:var(--dsw-border);margin:4px 0}.dsw-milestone-in-progress .dsw-milestone-dot{background:#f59e0b;animation:pulse 2s infinite}.dsw-milestone-content{flex:1;padding-bottom:24px}.dsw-milestone-header{display:flex;align-items:center;gap:12px;margin-bottom:8px;flex-wrap:wrap}.dsw-milestone-version{font-weight:700;font-size:16px;color:#06b6d4}.dsw-milestone-name{font-weight:600}.dsw-milestone-date{font-size:12px;color:var(--dsw-dim);margin-left:auto}.dsw-milestone-progress{display:flex;align-items:center;gap:8px;margin-bottom:10px}.dsw-milestone-bar{flex:1;max-width:200px;height:6px;background:var(--dsw-bg);border-radius:3px;overflow:hidden}.dsw-milestone-fill{height:100%;background:linear-gradient(90deg,#10b981,#06b6d4);border-radius:3px}.dsw-milestone-progress span{font-size:12px;color:var(--dsw-muted);min-width:32px}.dsw-milestone-highlights{margin:0;padding-left:16px;font-size:12px;color:var(--dsw-muted)}.dsw-milestone-highlights li{margin-bottom:4px}.dsw-milestone-active{background:rgba(6,182,212,.05);margin:-8px;padding:8px;border-radius:8px}@keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}}.dsw-stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:12px}.dsw-stat-card{background:var(--dsw-card);border:1px solid var(--dsw-border);border-radius:12px;padding:16px;text-align:center;transition:all .2s}.dsw-stat-card:hover{border-color:#06b6d4;transform:translateY(-2px)}.dsw-stat-icon{font-size:20px;display:block;margin-bottom:8px}.dsw-stat-value{font-size:28px;font-weight:800;color:#10b981;display:block}.dsw-stat-label{font-size:11px;color:var(--dsw-dim);text-transform:uppercase}@media(max-width:768px){.dsw-v2{padding:16px}.dsw-header{flex-direction:column;align-items:flex-start}.dsw-controls{flex-direction:column;align-items:stretch}.dsw-features-grid{grid-template-columns:1fr}.dsw-feature-card.dsw-expanded{grid-column:span 1}}</style>';
}
};
// Initialize on load
document.addEventListener('DOMContentLoaded', function() {
DevStatusWidget.render('dev-status-container');
});
</script>
</body>
</html>