Files
html/enterprise-management.html

432 lines
33 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"><head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEVAL Enterprise Management — SaaS Platform</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@600;700;800;900&display=swap');
:root{--bg:#0a0e1a;--card:#111827;--border:#1e293b;--accent:#c96442;--green:#10b981;--blue:#3b82f6;--purple:#8b5cf6;--yellow:#f59e0b;--red:#ef4444;--cyan:#06b6d4;--text:#e2e8f0;--muted:#64748b;--font:'DM Sans',sans-serif;--mono:'JetBrains Mono',monospace}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--text);font-family:var(--font);overflow-x:hidden}
.topbar{display:flex;align-items:center;justify-content:space-between;padding:12px 24px;background:rgba(17,24,39,.95);border-bottom:1px solid var(--border);position:sticky;top:0;z-index:100;backdrop-filter:blur(12px)}
.logo{font-size:18px;font-weight:700;color:var(--accent)}.logo span{color:var(--text);font-weight:400}
.tabs{display:flex;gap:4px}
.tab{padding:8px 16px;border-radius:8px;cursor:pointer;font-size:13px;font-weight:500;color:var(--muted);transition:.2s}
.tab:hover,.tab.act{background:rgba(201,100,66,.15);color:var(--accent)}
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;padding:16px 24px}
.kpi{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:16px;text-align:center}
.kpi .v{font-size:28px;font-weight:700;font-family:var(--mono)}.kpi .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-top:4px}
.main{display:grid;grid-template-columns:1fr 1fr;gap:16px;padding:0 24px 24px}
.full{grid-column:1/-1}
.card{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:20px;overflow:hidden}
.card h3{font-size:14px;font-weight:600;margin-bottom:12px;display:flex;align-items:center;gap:8px}
.card h3 .badge{font-size:10px;background:rgba(201,100,66,.2);color:var(--accent);padding:2px 8px;border-radius:99px;font-weight:500}
/* Pipeline */
.pipeline{display:flex;gap:0;overflow-x:auto;padding:8px 0}
.pipe-stage{flex:1;min-width:140px;text-align:center;position:relative;padding:12px 8px}
.pipe-stage::after{content:'→';position:absolute;right:-8px;top:50%;transform:translateY(-50%);color:var(--muted);font-size:18px}
.pipe-stage:last-child::after{display:none}
.pipe-icon{width:40px;height:40px;border-radius:10px;display:flex;align-items:center;justify-content:center;margin:0 auto 8px;font-size:18px}
.pipe-name{font-size:12px;font-weight:600}.pipe-count{font-size:10px;color:var(--muted);margin-top:2px}
.pipe-bar{height:3px;border-radius:2px;margin-top:6px}
/* Agent grid */
.agent-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:8px}
.agent{background:rgba(255,255,255,.03);border:1px solid var(--border);border-radius:8px;padding:10px;text-align:center;font-size:11px;transition:.2s}
.agent:hover{border-color:var(--accent);transform:translateY(-2px)}
.agent .icon{font-size:22px;margin-bottom:4px}.agent .name{font-weight:600;font-size:11px}.agent .role{color:var(--muted);font-size:9px}
.agent .dot{width:6px;height:6px;border-radius:50%;display:inline-block;margin-right:4px}
/* n8n */
.n8n-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:8px}
.n8n-wf{background:rgba(59,130,246,.05);border:1px solid rgba(59,130,246,.2);border-radius:8px;padding:12px;font-size:12px}
.n8n-wf .wf-name{font-weight:600;margin-bottom:4px}.n8n-wf .wf-status{font-size:10px;color:var(--green)}
/* Dept sections */
.dept{border-left:3px solid var(--accent);padding-left:16px;margin-bottom:16px}
.dept-name{font-size:16px;font-weight:700;margin-bottom:4px}.dept-sub{font-size:11px;color:var(--muted)}
.view{display:none}.view.act{display:block}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
.card{animation:fadeIn .3s ease}
@media(max-width:768px){.main{grid-template-columns:1fr}.kpis{grid-template-columns:repeat(3,1fr)}}
</style></head><body style="padding-top:60px"><div style="position:fixed;top:0;left:0;right:0;height:28px;background:#ffffffee;z-index:100;display:flex;align-items:center;padding:0 14px;font-family:Nunito,sans-serif;font-size:.65rem;gap:12px;border-bottom:1px solid #e2e8f0;backdrop-filter:blur(8px)"><b style="color:#059669">WEVIA</b></div>
<div style="position:fixed;top:30px;left:0;right:0;display:flex;justify-content:center;gap:5px;padding:4px;z-index:100;background:#f8fafcee;backdrop-filter:blur(8px);font-family:Nunito,sans-serif">
<a href="/agents-archi.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Architecture</a>
<a href="/director-center.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Director</a>
<a href="/wevia-meeting-rooms.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Rooms</a>
<a href="/enterprise-model.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Enterprise</a>
<a href="/agents-ia.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Pyramid</a>
<a href="/director-chat.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">Chat</a>
<a href="/l99-brain.html" style="padding:2px 8px;border-radius:4px;font:700 8px Nunito;text-decoration:none;color:#5a6a80;border:1px solid #c8d8e8">L99</a>
</div>
<div class="topbar">
<div class="logo">WEVAL <span>Enterprise Management</span></div>
<div class="tabs" id="tabs">
<div class="tab act" onclick="showView('overview')">Overview</div>
<div class="tab" onclick="showView('pipelines')">Pipelines</div>
<div class="tab" onclick="showView('agents')">Agents</div>
<div class="tab" onclick="showView('n8n')">n8n Workflows</div>
<div class="tab" onclick="showView('infra')">Infrastructure</div>
<div class="tab" onclick="showView('saas')">SaaS Products</div>
</div>
<div style="font-family:var(--mono);font-size:12px;color:var(--green)">● LIVE <span id="clock"></span></div>
</div>
<div class="kpis" id="kpis"></div>
<!-- OVERVIEW -->
<div class="view act" id="v-overview"><div class="main" id="overview-content"></div></div>
<!-- PIPELINES -->
<div class="view" id="v-pipelines"><div class="main" id="pipelines-content"></div></div>
<!-- AGENTS -->
<div class="view" id="v-agents"><div class="main" id="agents-content"></div></div>
<!-- N8N -->
<div class="view" id="v-n8n"><div class="main" id="n8n-content"></div></div>
<!-- INFRA -->
<div class="view" id="v-infra"><div class="main" id="infra-content"></div></div>
<!-- SAAS -->
<div class="view" id="v-saas"><div class="main" id="saas-content"></div></div>
<script>
// === DATA ===
const DEPTS = [
{id:'ceo',name:'CEO Office',icon:'👔',color:'#c96442',agents:['CEO','Brain','Orch','TaskMgr','Intro'],pipeline:['Decision','Budget','Strategy','Hiring','Review'],kpi:'1 brief/day'},
{id:'prospect',name:'Prospect & Sales',icon:'🎯',color:'#f59e0b',agents:['Ethica','Analyst','Writer','Proposal','Contract'],pipeline:['Leads','Qualify','Outreach','Convert','Close'],kpi:'1052 leads'},
{id:'consult',name:'Consulting',icon:'🏗️',color:'#3b82f6',agents:['Architect','Planner','DeerFlow','Critic','Translate','Academy','ECC36','Persona6'],pipeline:['Analyse','Design','Propose','Deliver','Support'],kpi:'3 proposals'},
{id:'dev',name:'Dev Lab',icon:'⚡',color:'#8b5cf6',agents:['Executor','Debugger','Reviewer','Designer','WEDROID','Simplifier','Blueprint','DevForge'],pipeline:['Code','Review','Test','Deploy','Monitor'],kpi:'12 deploys/j'},
{id:'infra',name:'Infrastructure',icon:'🖥️',color:'#06b6d4',agents:['Watchdog','Guardian','Blade','GitMaster','Loki'],pipeline:['Monitor','Fix','Deploy','Verify','Report'],kpi:'99.9% uptime'},
{id:'security',name:'Security & Compliance',icon:'🔐',color:'#ef4444',agents:['Security','Verifier','Nuclei'],pipeline:['Scan','Detect','Assess','Remediate','Audit'],kpi:'Grade B (Nuclei+Trivy)'},
{id:'qa',name:'Quality Assurance',icon:'🧪',color:'#10b981',agents:['QA','TestEng','Tracer','Scientist'],pipeline:['Plan','Execute','Analyze','Report','Fix'],kpi:'153/153 NR + 450 L99'},
{id:'pharma',name:'Pharma & Ethica',icon:'💊',color:'#ec4899',agents:['Explore','DocSpec','MiroFish'],pipeline:['Scrape','Validate','Enrich','Campaign','Track'],kpi:'131K+ HCPs (DZ+MA+TN)'},
{id:'ai',name:'AI Engine',icon:'🧠',color:'#a855f7',agents:['Groq','Cerebras','Ollama','Sovereign','ClaudeCode','OpenWebUI','Flowise'],pipeline:['Ingest','Route','Infer','Validate','Deliver'],kpi:'247 AIs benchmarked'},
{id:'mta',name:'Email Infrastructure',icon:'📧',color:'#f97316',agents:['PMTA','KumoMTA','Postfix'],pipeline:['Compose','Route','Deliver','Track','Bounce'],kpi:'3M contacts (5582 standby)'},
{id:'cog',name:'Cognitive Modes',icon:'🎯',color:'#6366f1',agents:['Analysis','Codegen','Creative','Debug','Strategy','Research','Orchestration','TokenEff','BusinessPanel'],pipeline:['Perceive','Process','Generate','Validate','Output'],kpi:'9 modes'},
{id:'oss',name:'OSS Integration',icon:'🌐',color:'#14b8a6',agents:['BrowserUse','OpenClaw','Goose','AIOS','Dify','Mastra','EvoMaster','Activepieces','AEGIS','Prometheus','Flowise','OpenWebUI','CrewAI','LangChain','Scrapy','Supermemory'],pipeline:['Discover','Evaluate','Wire','Test','Deploy'],kpi:'685 tools'},
{id:'saas',name:'SaaS Products',icon:'📦',color:'#0ea5e9',agents:['LeadForge','OutreachAI','MailWarm','ProposalAI','WhatsAppAPI','WEVIA PUB','Manager'],pipeline:['Build','Launch','Sell','Support','Scale'],kpi:'38 tools'},
{id:'cron',name:'Automation',icon:'⏰',color:'#64748b',agents:['EthicaCron','B2BCron','NonRegCron','BackupCron','OSSChain','SkillSync','L99Auto','GuardCron'],pipeline:['Schedule','Execute','Validate','Alert','Log'],kpi:'30+ crons'},
];
const N8N_WORKFLOWS = [
{name:'Ethica HCP Enrichment',trigger:'Cron */6h',nodes:12,status:'active',desc:'Scrape → Validate → Enrich emails/phones → Store PG'},
{name:'B2B Lead Generation',trigger:'Cron */4h',nodes:8,status:'active',desc:'LinkedIn → Email pattern → Verify → CRM'},
{name:'NonReg Watchdog',trigger:'Cron 6h/18h',nodes:6,status:'active',desc:'Run 153 tests → Telegram alert → HTML report'},
{name:'Sovereign AI Router',trigger:'Webhook',nodes:5,status:'active',desc:'Request → Provider select → Inference → Cache → Return'},
{name:'WhatsApp Campaign',trigger:'Manual',nodes:7,status:'ready',desc:'Template → Audience → Send → Track → Report'},
{name:'Email Drip DZ+MA+TN',trigger:'Cron */5min',nodes:9,status:'active',desc:'Queue → Segment → Personalize → Send → Track'},
{name:'OSS Discovery Sync',trigger:'Cron */6h',nodes:6,status:'active',desc:'GitHub scan → Evaluate → Wire Paperclip → Alert'},
{name:'DeerFlow Research',trigger:'Webhook',nodes:8,status:'active',desc:'Query → Multi-source → Synthesize → Report → Store'},
{name:'Paperclip Agent Chain',trigger:'API',nodes:10,status:'active',desc:'Trigger → Select agent → Execute → Report → Learn'},
{name:'Azure AD O365 Sync',trigger:'Cron daily',nodes:5,status:'active',desc:'Check tenants → Sync accounts → Refresh tokens → Report'},
{name:'Guardian Auto-Heal',trigger:'Cron */5min',nodes:4,status:'active',desc:'Check services → Detect failure → Auto-restart → Alert'},
{name:'Stripe Billing',trigger:'Webhook',nodes:6,status:'ready',desc:'Event → Process payment → Update status → Invoice → Email'},
{name:'L99 Alive Monitor',trigger:'Cron */30min',nodes:7,status:'active',desc:'Scan → Playwright test → Screenshots → Infra check → Telegram'},
{name:'Backup & GOLD',trigger:'Cron daily 4am',nodes:5,status:'active',desc:'PG dump → GOLD snapshot → S3 upload → Verify → Clean old'},
{name:'IP Warmup Pipeline',trigger:'Cron daily',nodes:8,status:'active',desc:'Select IPs → Ramp volume → Monitor reputation → Adjust → Report'},
];
const INFRA = {
servers:[
{name:'S204',ip:'204.168.152.13',role:'Primary Web',disk:'83%',docker:20,services:['nginx','php-fpm','postgresql','ollama','sovereign','paperclip','deerflow']},
{name:'S95',ip:'95.216.167.89',role:'Email/Arsenal',disk:'65%',docker:4,services:['PMTA:25','KumoMTA:587','Postfix:2525','Sentinel:5890','PostgreSQL:5432']},
{name:'S151',ip:'151.80.235.110',role:'Tracking/Relay',disk:'45%',docker:2,services:['OpenClaw','Ollama','Tracking relay']},
{name:'Blade',ip:'Desktop',role:'Agent Desktop',disk:'N/A',docker:0,services:['Sentinel Agent','PowerShell','Claude Code']},
],
docker:['authentik-server','authentik-worker','authentik-db','plausible','plausible-events','plausible-db','uptime-kuma','mattermost','searxng','loki','twenty-redis','paperclip','openwebui','flowise','vaultwarden','n8n','qdrant','redis'],
ports:[9090,9443,8000,8001,3000,3100,3102,3033,5678,6333,6380,8222,8281,11434,4000]
};
const SAAS_PRODUCTS = [
{name:'WEVIA PUBLIC',desc:'AI Chat Widget + Command Center',modules:71,status:'live'},
{name:'WEVADS IA',desc:'Omnichannel Email Intelligence',pages:81,status:'live'},
{name:'Ethica HCP',desc:'Pharma Healthcare Professional Platform',hcps:'141K+',status:'live'},
{name:'Sovereign Claude',desc:'Multi-provider AI Gateway',providers:6,status:'live'},
{name:'LeadForge',desc:'B2B Lead Generation Engine',leads:'1052',status:'live'},
{name:'MailWarm',desc:'IP Warmup & Reputation Manager',accounts:2036,status:'live'},
{name:'OutreachAI',desc:'AI-Powered Email Sequences',templates:50,status:'live'},
{name:'ProposalAI',desc:'Smart Proposal Generator',formats:3,status:'beta'},
{name:'Arsenal',desc:'192 Tools Security Platform',tools:192,status:'live'},
{name:'DeerFlow',desc:'Deep Research AI Agent',skills:528,status:'live'},
{name:'Paperclip',desc:'150-Agent AI Organization',agents:150,status:'live'},
{name:'WhatsApp API',desc:'Meta Business Messaging',mode:'LIVE',status:'live'},
];
// === RENDER ===
function renderKPIs(){
const kpis=[
{v:'150',l:'Agents',c:'var(--accent)'},{v:'25',l:'Departments',c:'var(--blue)'},
{v:'15',l:'n8n Workflows',c:'var(--purple)'},{v:'685',l:'OSS Tools',c:'var(--cyan)'},
{v:'3M',l:'Contacts',c:'var(--yellow)'},{v:'141K+',l:'HCPs',c:'var(--green)'},
{v:'20',l:'Docker',c:'var(--red)'},{v:'93%',l:'L99 Score',c:'var(--accent)'},
{v:'12',l:'SaaS Products',c:'var(--blue)'},{v:'528',l:'Skills',c:'var(--purple)'}
];
document.getElementById('kpis').innerHTML=kpis.map(k=>`<div class="kpi"><div class="v" style="color:${k.c}">${k.v}</div><div class="l">${k.l}</div></div>`).join('');
}
function renderPipeline(stages,color){
return `<div class="pipeline">${stages.map((s,i)=>`<div class="pipe-stage"><div class="pipe-icon" style="background:${color}22;color:${color}">${i+1}</div><div class="pipe-name">${s}</div><div class="pipe-bar" style="background:linear-gradient(90deg,${color},${color}44);width:${70+Math.random()*30}%"></div></div>`).join('')}</div>`;
}
function renderOverview(){
let html='';
DEPTS.forEach(d=>{
html+=`<div class="card"><h3>${d.icon} ${d.name} <span class="badge">${d.agents.length} agents</span> <span class="badge" style="background:rgba(16,185,129,.2);color:var(--green)">${d.kpi}</span></h3>${renderPipeline(d.pipeline,d.color)}<div style="display:flex;flex-wrap:wrap;gap:4px;margin-top:8px">${d.agents.map(a=>`<span style="font-size:10px;background:${d.color}15;color:${d.color};padding:2px 8px;border-radius:4px">${a}</span>`).join('')}</div></div>`;
});
document.getElementById('overview-content').innerHTML=html;
}
function renderPipelines(){
let html=`<div class="card full"><h3>🔄 All Business Pipelines <span class="badge">${DEPTS.length} pipelines</span></h3>`;
DEPTS.forEach(d=>{
html+=`<div class="dept"><div class="dept-name">${d.icon} ${d.name}</div><div class="dept-sub">${d.agents.length} agents → ${d.kpi}</div>${renderPipeline(d.pipeline,d.color)}</div>`;
});
html+=`</div>`;
// n8n integration
html+=`<div class="card full"><h3>⚙️ n8n Workflow Pipelines <span class="badge">${N8N_WORKFLOWS.length} workflows</span></h3><div class="n8n-grid">${N8N_WORKFLOWS.map(w=>`<div class="n8n-wf"><div class="wf-name">⚙️ ${w.name}</div><div style="font-size:10px;color:var(--muted)">${w.trigger}${w.nodes} nodes</div><div class="wf-status">${w.status==='active'?'● Active':'○ Ready'}</div><div style="font-size:10px;color:var(--text);margin-top:4px;opacity:.7">${w.desc}</div></div>`).join('')}</div></div>`;
document.getElementById('pipelines-content').innerHTML=html;
}
function renderAgents(){
let html='';
DEPTS.forEach(d=>{
html+=`<div class="card"><h3>${d.icon} ${d.name} <span class="badge">${d.agents.length}</span></h3><div class="agent-grid">${d.agents.map(a=>`<div class="agent"><div class="icon">${d.icon}</div><div class="name">${a}</div><div class="role">${d.id}</div><div><span class="dot" style="background:var(--green)"></span><span style="font-size:9px;color:var(--green)">Active</span></div></div>`).join('')}</div></div>`;
});
document.getElementById('agents-content').innerHTML=html;
}
function renderN8N(){
let html=`<div class="card full"><h3>⚙️ n8n Automation Hub <span class="badge">${N8N_WORKFLOWS.length} workflows</span> <span class="badge" style="background:rgba(16,185,129,.2);color:var(--green)">${N8N_WORKFLOWS.filter(w=>w.status==='active').length} active</span></h3>`;
N8N_WORKFLOWS.forEach(w=>{
const color=w.status==='active'?'var(--green)':'var(--yellow)';
html+=`<div style="display:flex;align-items:center;gap:12px;padding:12px;border-bottom:1px solid var(--border)"><div style="width:8px;height:8px;border-radius:50%;background:${color}"></div><div style="flex:1"><div style="font-weight:600;font-size:13px">${w.name}</div><div style="font-size:11px;color:var(--muted)">${w.desc}</div></div><div style="text-align:right"><div style="font-family:var(--mono);font-size:11px;color:${color}">${w.status.toUpperCase()}</div><div style="font-size:10px;color:var(--muted)">${w.trigger}${w.nodes} nodes</div></div></div>`;
});
html+=`</div>`;
document.getElementById('n8n-content').innerHTML=html;
}
function renderInfra(){
let html=`<div class="card full"><h3>🖥️ Servers <span class="badge">${INFRA.servers.length}</span></h3><div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:12px">${INFRA.servers.map(s=>`<div style="background:rgba(255,255,255,.02);border:1px solid var(--border);border-radius:10px;padding:16px"><div style="display:flex;justify-content:space-between;margin-bottom:8px"><span style="font-weight:700">${s.name}</span><span style="font-family:var(--mono);font-size:11px;color:var(--muted)">${s.ip}</span></div><div style="font-size:11px;color:var(--accent);margin-bottom:4px">${s.role}</div><div style="font-size:10px;color:var(--muted)">Disk: ${s.disk} | Docker: ${s.docker}</div><div style="display:flex;flex-wrap:wrap;gap:3px;margin-top:6px">${s.services.map(sv=>`<span style="font-size:9px;background:var(--green)15;color:var(--green);padding:1px 6px;border-radius:3px">${sv}</span>`).join('')}</div></div>`).join('')}</div></div>`;
html+=`<div class="card"><h3>🐳 Docker Containers <span class="badge">${INFRA.docker.length}</span></h3><div style="display:flex;flex-wrap:wrap;gap:6px">${INFRA.docker.map(d=>`<span style="font-size:11px;background:rgba(16,185,129,.1);color:var(--green);padding:4px 10px;border-radius:6px;border:1px solid rgba(16,185,129,.2)">● ${d}</span>`).join('')}</div></div>`;
html+=`<div class="card"><h3>🔌 Active Ports <span class="badge">${INFRA.ports.length}</span></h3><div style="display:flex;flex-wrap:wrap;gap:6px">${INFRA.ports.map(p=>`<span style="font-family:var(--mono);font-size:11px;background:rgba(59,130,246,.1);color:var(--blue);padding:4px 10px;border-radius:6px">:${p}</span>`).join('')}</div></div>`;
document.getElementById('infra-content').innerHTML=html;
}
function renderSaaS(){
let html=`<div class="card full"><h3>📦 SaaS Product Suite <span class="badge">${SAAS_PRODUCTS.length} products</span></h3><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px">${SAAS_PRODUCTS.map(p=>`<div style="background:rgba(255,255,255,.02);border:1px solid var(--border);border-radius:10px;padding:16px"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px"><span style="font-weight:700;font-size:14px">${p.name}</span><span style="font-size:10px;background:${p.status==='live'?'rgba(16,185,129,.2)':'rgba(245,158,11,.2)'};color:${p.status==='live'?'var(--green)':'var(--yellow)'};padding:2px 8px;border-radius:4px">${p.status.toUpperCase()}</span></div><div style="font-size:12px;color:var(--muted);margin-bottom:8px">${p.desc}</div><div style="font-size:11px;color:var(--accent)">${Object.entries(p).filter(([k])=>!['name','desc','status'].includes(k)).map(([k,v])=>`${k}: ${v}`).join(' • ')}</div></div>`).join('')}</div></div>`;
document.getElementById('saas-content').innerHTML=html;
}
function showView(id){
document.querySelectorAll('.view').forEach(v=>v.classList.remove('act'));
document.querySelectorAll('.tab').forEach(t=>t.classList.remove('act'));
document.getElementById('v-'+id).classList.add('act');
event.target.classList.add('act');
}
// Clock
setInterval(()=>{document.getElementById('clock').textContent=new Date().toLocaleTimeString()},1000);
// Init
renderKPIs();renderOverview();renderPipelines();renderAgents();renderN8N();renderInfra();renderSaaS();
</script>
<!-- WTP-GAP-FILL-V1 (doctrine 90-v2 gap-fill showcase, 18avr 2026) -->
<style>
.wtp-gapfill-banner{position:fixed;bottom:0;left:0;right:0;z-index:99999;background:linear-gradient(90deg,#05060a,#0b0d15 20%,#181d2e 50%,#0b0d15 80%,#05060a);border-top:2px solid #14b8a6;color:#e2e8f0;padding:10px 16px;font-family:Inter,system-ui,-apple-system,sans-serif;font-size:11.5px;display:flex;align-items:center;gap:12px;flex-wrap:wrap;box-shadow:0 -10px 30px rgba(20,184,166,.28)}
.wtp-gapfill-banner a{color:#5eead4;text-decoration:none;font-weight:600;transition:color .15s}
.wtp-gapfill-banner a:hover{color:#22d3ee}
.wtp-gapfill-banner .pill{padding:2px 9px;background:rgba(99,102,241,.14);color:#a5b4fc;border-radius:10px;font-size:10.5px;font-family:JetBrains Mono,monospace;font-weight:600}
.wtp-gapfill-banner .pill.new{background:rgba(20,184,166,.22);color:#5eead4}
.wtp-gapfill-banner .pill.hot{background:rgba(236,72,153,.22);color:#f472b6}
.wtp-gapfill-banner .close{margin-left:auto;cursor:pointer;color:#64748b;padding:0 8px;font-size:16px;line-height:1;border:1px solid #334155;border-radius:4px}
.wtp-gapfill-banner .close:hover{color:#e2e8f0;border-color:#64748b}
.wtp-gapfill-banner.hidden{display:none}
@media(max-width:768px){.wtp-gapfill-banner{font-size:10px;padding:7px 10px;gap:8px}}
</style>
<div class="wtp-gapfill-banner" id="wtpGapFillBanner">
<span>🎯 <strong>WEVAL Agents Gap-Fill ERP</strong></span>
<span class="pill hot" id="gaps-banner-count">17 gaps live</span>
<span class="pill">SAP · Oracle · NetSuite · Dynamics</span>
<span class="pill new">🆕 Meeting Rooms</span>
<span class="pill new">🆕 Lean 6 Sigma</span>
<span id="wtp-gfb-metrics" class="pill">— chargement —</span>
<a href="/weval-technology-platform.html">→ WTP Portal (16 mod)</a>
<a href="/enterprise-model.html">Enterprise Model</a>
<a href="/api/weval-agents-gap-fill-manifest.json" target="_blank">📋 Manifest</a>
<span class="close" onclick="document.getElementById("wtpGapFillBanner").classList.add("hidden");localStorage.setItem("wtpGapFillHidden","1")">×</span>
</div>
<script>
(async()=>{
if(localStorage.getItem("wtpGapFillHidden")==="1"){document.getElementById("wtpGapFillBanner").classList.add("hidden");return;}
try{
const r=await fetch("/api/source-of-truth.json?t="+Date.now());
const d=await r.json();
const el=document.getElementById("wtp-gfb-metrics");
if(el)el.textContent=(d.ethica_total||"?")+" HCPs · "+(d.nonreg||"?")+" · "+(d.providers_count||"?")+" IA · "+(d.agents_count||"?")+" agents · "+(d.docker_running||"?")+" 🐳";
}catch(e){}
})();
</script>
<!-- WTP-D90V2-ENRICH-BANNER (doctrine 90-v2, 17avr 2026) -->
<style>
.wtp-enrich-banner{position:fixed;bottom:0;left:0;right:0;z-index:9999;background:linear-gradient(90deg,#0b0d15,#181d2e,#0b0d15);border-top:2px solid #14b8a6;color:#e2e8f0;padding:9px 18px;font-family:'JetBrains Mono',monospace,-apple-system,system-ui;font-size:11.5px;display:flex;align-items:center;gap:14px;flex-wrap:wrap;box-shadow:0 -8px 24px rgba(20,184,166,.25)}
.wtp-enrich-banner a{color:#14b8a6;text-decoration:none;font-weight:600}
.wtp-enrich-banner a:hover{color:#22d3ee}
.wtp-enrich-banner .pill{padding:2px 8px;background:rgba(99,102,241,.15);color:#a5b4fc;border-radius:10px;font-size:10.5px}
.wtp-enrich-banner .pill.new{background:rgba(20,184,166,.2);color:#5eead4}
.wtp-enrich-banner .close{margin-left:auto;cursor:pointer;color:#64748b;padding:0 6px;font-size:14px}
.wtp-enrich-banner .close:hover{color:#e2e8f0}
.wtp-enrich-banner.hidden{display:none}
@media(max-width:768px){.wtp-enrich-banner{font-size:10px;padding:6px 10px}}
</style>
<div class="wtp-enrich-banner" id="wtpEnrichBanner">
<span>🏛️ <strong>Enterprise Model 16 depts</strong></span>
<span class="pill new">🆕 Meeting Rooms</span>
<span class="pill new">🆕 Lean 6 Sigma</span>
<span id="wtp-eb-metrics" class="pill">— chargement —</span>
<a href="/weval-technology-platform.html">→ WEVAL Technology Platform (16 modules)</a>
<a href="/enterprise-model.html">Enterprise Model</a>
<a href="/wevia-master.html">WEVIA Master</a>
<span class="close" onclick="document.getElementById('wtpEnrichBanner').classList.add('hidden')">×</span>
</div>
<script>
(async()=>{try{const r=await fetch('/api/source-of-truth.json?t='+Date.now());const d=await r.json();const el=document.getElementById('wtp-eb-metrics');if(el)el.textContent=(d.ethica_total||'?')+' HCPs · '+(d.nonreg||'?')+' · '+(d.providers_count||'?')+' IA · '+(d.docker_running||'?')+' 🐳 · '+(d.subdomains_live||'?')+' subdomains';}catch(e){}})();
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN v1 19avr — append-only, doctrine #14 === -->
<script>
(function(){
if (window.__opusUniversalDrill) return; window.__opusUniversalDrill = true;
var d = document;
var m = d.createElement('div');
m.id = 'opus-udrill';
m.style.cssText = 'position:fixed;inset:0;background:rgba(0,0,0,0.82);backdrop-filter:blur(6px);display:none;align-items:center;justify-content:center;z-index:99995;padding:20px;cursor:pointer';
var inner = d.createElement('div');
inner.id = 'opus-udrill-in';
inner.style.cssText = 'max-width:900px;width:100%;max-height:90vh;overflow:auto;background:#0b0d15;border:1px solid rgba(99,102,241,0.35);border-radius:14px;padding:28px;cursor:default;box-shadow:0 20px 60px rgba(0,0,0,0.6);color:#e2e8f0;font:14px/1.55 Inter,system-ui,sans-serif';
inner.addEventListener('click', function(e){ e.stopPropagation(); });
m.appendChild(inner);
m.addEventListener('click', function(){ m.style.display='none'; });
d.addEventListener('keydown', function(e){ if(e.key==='Escape') m.style.display='none'; });
(d.body || d.documentElement).appendChild(m);
function openCard(card) {
// Clone card content + show close btn + increase font-size
var html = '<div style="display:flex;justify-content:flex-end;margin-bottom:14px"><button id="opus-udrill-close" style="padding:6px 14px;background:#171b2a;border:1px solid rgba(99,102,241,0.25);color:#e2e8f0;border-radius:8px;cursor:pointer;font-size:12px">✕ Fermer (Esc)</button></div>';
html += '<div style="transform-origin:top left;font-size:1.05em">' + card.outerHTML + '</div>';
inner.innerHTML = html;
d.getElementById('opus-udrill-close').onclick = function(){ m.style.display='none'; };
m.style.display = 'flex';
}
function wire(root) {
var sels = '.card,[class*="card"],.kpi,[class*="kpi"],.stat,[class*="stat"],.tile,[class*="tile"],.metric,[class*="metric"],.widget,[class*="widget"]';
var cards = root.querySelectorAll(sels);
for (var i = 0; i < cards.length; i++) {
var c = cards[i];
if (c.__opusWired) continue;
if (c.closest('button, a, input, select, textarea, #opus-udrill')) continue;
var r = c.getBoundingClientRect();
if (r.width < 60 || r.height < 40) continue;
c.__opusWired = true;
c.style.cursor = 'pointer';
c.setAttribute('role','button');
c.setAttribute('tabindex','0');
c.addEventListener('click', function(ev){
// If a more-specific drill is already active (e.g. pp-card custom), let it handle
if (ev.target.closest('[data-pp-id]') && window.__opusDrillInit) return;
if (ev.target.closest('a,button,input,select')) return;
ev.preventDefault(); ev.stopPropagation();
openCard(this);
});
c.addEventListener('keydown', function(ev){ if(ev.key==='Enter'||ev.key===' '){ev.preventDefault();openCard(this);} });
}
}
// Initial + mutation observer
var initRun = function(){ wire(d.body || d.documentElement); };
if (d.readyState === 'loading') d.addEventListener('DOMContentLoaded', initRun);
else initRun();
var mo = new MutationObserver(function(muts){
var newCard = false;
for (var i=0;i<muts.length;i++) if (muts[i].addedNodes.length) { newCard = true; break; }
if (newCard) initRun();
});
mo.observe(d.body || d.documentElement, {childList:true, subtree:true});
})();
</script>
<!-- === OPUS UNIVERSAL DRILL-DOWN END === -->
<!-- === OPUS HONEST NR/L99 OVERLAY v1 19avr - append-only doctrine #14 === -->
<script>
(function(){
if (window.__opusHonestOverlay) return; window.__opusHonestOverlay = true;
async function updateHonestValues(){
try {
const r = await fetch('/api/l99-honest.php', {cache:'no-store'});
const d = await r.json();
if (!d.ok) return;
const realNR = `${d.combined.pass}/${d.combined.total}`;
const realSigma = d.sigma;
// Find elements showing the myth values
const mythRegex = /(153\/153|304\/304|NR status 153\/153|L99 status 304\/304|NR 153\/153|L99 304\/304)/g;
// Walk text nodes
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
const toReplace = [];
let node;
while (node = walker.nextNode()) {
if (node.nodeValue && mythRegex.test(node.nodeValue)) toReplace.push(node);
}
toReplace.forEach(textNode => {
const parent = textNode.parentNode;
if (!parent || parent.hasAttribute('data-opus-honest-applied')) return;
const newText = textNode.nodeValue.replace(/153\/153/g, realNR).replace(/304\/304/g, realNR);
textNode.nodeValue = newText;
parent.setAttribute('data-opus-honest-applied', '1');
});
// Add a small badge bottom-right showing honest live status
if (!document.getElementById('opus-honest-badge')) {
const b = document.createElement('div');
b.id = 'opus-honest-badge';
b.style.cssText = 'position:fixed;bottom:12px;right:12px;background:linear-gradient(90deg,#14b8a6,#a855f7);color:#05060a;padding:6px 12px;font:10px/1.3 Inter,system-ui,sans-serif;font-weight:700;border-radius:8px;z-index:99993;box-shadow:0 4px 12px rgba(0,0,0,0.3);cursor:pointer;max-width:280px';
b.title = 'Cliquer pour détails';
b.innerHTML = `✓ NR ${realNR} · ${realSigma} live`;
b.onclick = () => {
alert(`HONEST NonReg (doctrine #4):\n\nmaster: ${d.master.pass}/${d.master.total}\nopus: ${d.opus.pass}/${d.opus.total}\ncombined: ${realNR}\nsigma: ${realSigma}\n\n${d.myth_153}\n${d.myth_304}`);
};
document.body.appendChild(b);
}
} catch(e){console.error('L99-honest fetch error:', e);}
}
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', updateHonestValues);
else updateHonestValues();
setInterval(updateHonestValues, 90000);
})();
</script>
<!-- === OPUS HONEST END === -->
<script>
// Opus v9.32 gaps banner live
(async function(){
try {
const r = await fetch('/api/weval-agents-gap-fill-manifest.json');
const d = await r.json();
const erp = d.erp_gaps_covered || {};
let total = 0;
for (const k in erp) {
const v = erp[k];
if (Array.isArray(v)) total += v.length;
else if (v && Array.isArray(v.gaps)) total += v.gaps.length;
}
const el = document.getElementById('gaps-banner-count');
if (el && total > 0) el.textContent = total + ' ERP gaps';
} catch(e) {}
})();
</script>
<script src="/api/a11y-auto-enhancer.js" defer></script>
<!-- WTP_UDOCK_V1 (Opus 21-avr t32b4) --><script src="/wtp-unified-dock.js" defer></script>
</body></html>