Files
html/api/kpi-unified.php
opus c49928485f
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-sync via WEVIA git_sync_all intent 2026-04-21T11:28:41+02:00
2026-04-21 11:28:41 +02:00

168 lines
5.5 KiB
PHP

<?php
// V118 KPI UNIFIED - Single source-of-truth endpoint for all dashboards
// Consolidates source-of-truth.json + nonreg-latest + token-health-cache + docker live
// Cache 60s for performance
// UX premium doctrine 60 - zero doublon zero divergence
header("Content-Type: application/json");
header("Access-Control-Allow-Origin: *");
header("Cache-Control: public, max-age=60");
$cache_file = "/tmp/kpi-unified-cache.json";
$cache_ttl = 60;
$force = !empty($_GET["force"]);
// Try cache first
if (!$force && is_readable($cache_file)) {
$age = time() - filemtime($cache_file);
if ($age < $cache_ttl) {
$cached = @json_decode(@file_get_contents($cache_file), true);
if (is_array($cached)) {
$cached["cache_hit"] = true;
$cached["cache_age_sec"] = $age;
echo json_encode($cached, JSON_PRETTY_PRINT);
exit;
}
}
}
// Build from sources (honest, no fake)
$sot = [];
if (is_readable("/var/www/html/api/source-of-truth.json")) {
$sot = @json_decode(@file_get_contents("/var/www/html/api/source-of-truth.json"), true) ?: [];
}
$nonreg = [];
if (is_readable("/var/www/html/api/nonreg-latest.json")) {
$nonreg = @json_decode(@file_get_contents("/var/www/html/api/nonreg-latest.json"), true) ?: [];
}
$tokens = [];
if (is_readable("/tmp/token-health-cache.json")) {
$tokens = @json_decode(@file_get_contents("/tmp/token-health-cache.json"), true) ?: [];
}
// Docker running count (live via shell)
$docker_count = 0;
$out = @shell_exec("docker ps 2>/dev/null | tail -n +2 | wc -l");
if ($out !== null) $docker_count = (int)trim($out);
if ($docker_count === 0 && isset($sot["docker_running"])) $docker_count = (int)$sot["docker_running"];
// V83 summary (via architecture_quality)
$v83 = ["kpis" => null, "ok" => null, "warn" => null, "fail" => null, "complete_pct" => null];
if (is_readable("/var/www/html/api/v83-business-kpi-latest.json")) {
$v83_raw = @json_decode(@file_get_contents("/var/www/html/api/v83-business-kpi-latest.json"), true);
if ($v83_raw && isset($v83_raw["summary"])) {
$v83 = [
"kpis" => $v83_raw["summary"]["total_kpis"] ?? null,
"ok" => $v83_raw["summary"]["ok"] ?? null,
"warn" => $v83_raw["summary"]["warn"] ?? null,
"fail" => $v83_raw["summary"]["fail"] ?? null,
"complete_pct" => $v83_raw["summary"]["data_completeness_pct"] ?? null
];
}
}
// Orphans (from V83 architecture_quality KPI)
$orphans_count = 0;
if (is_readable("/tmp/wevia-pages-registry-cache.json")) {
$reg = @json_decode(@file_get_contents("/tmp/wevia-pages-registry-cache.json"), true);
if ($reg && isset($reg["orphans"])) $orphans_count = (int)$reg["orphans"];
}
// Build unified schema (SINGLE SOURCE OF TRUTH)
$response = [
"ok" => true,
"version" => "v118-kpi-unified",
"doctrine" => "zero doublon single source-of-truth",
"ts" => date("c"),
"cache_hit" => false,
"cache_ttl_sec" => $cache_ttl,
"providers" => [
"total" => $sot["providers_count"] ?? ($sot["counts"]["providers"] ?? 0),
"ok" => $tokens["summary"]["live_ok"] ?? null,
"expired" => $tokens["summary"]["expired_ko"] ?? null,
"health_pct" => $tokens["summary"]["health_pct"] ?? null
],
"agents" => [
"active" => $sot["agents_count"] ?? 0,
"total_live" => $sot["counts"]["agents_total_live"] ?? ($sot["agents_total"] ?? 0)
],
"skills" => [
"count" => $sot["skills_count"] ?? 0,
"total" => $sot["skills_total"] ?? ($sot["counts"]["skills_total"] ?? 0)
],
"intents" => [
"count" => $sot["intents_count"] ?? ($sot["counts"]["intents"] ?? 0),
"total" => $sot["intents_total"] ?? 0
],
"docker" => [
"running" => $docker_count
],
"orphans" => [
"count" => $orphans_count,
"status" => ($orphans_count === 0) ? "ok" : "warn"
],
"nonreg" => [
"pass" => $nonreg["pass"] ?? 0,
"fail" => $nonreg["fail"] ?? 0,
"total" => ($nonreg["pass"] ?? 0) + ($nonreg["fail"] ?? 0),
"score" => $nonreg["score"] ?? 0,
"ts" => $nonreg["ts"] ?? null
],
"v83" => $v83,
"autonomy" => [
"score" => $sot["autonomy_score"] ?? 0,
"level" => $sot["autonomy_level"] ?? "UNKNOWN"
],
"qdrant" => [
"collections" => $sot["counts"]["qdrant_cols"] ?? 0,
"points" => $sot["counts"]["qdrant_points"] ?? 0
],
"dashboards" => [
"count" => $sot["dashboards_count"] ?? ($sot["counts"]["dashboards"] ?? 0)
],
"brains" => [
"count" => $sot["brains_count"] ?? ($sot["counts"]["brains"] ?? 0)
],
"doctrines" => [
"count" => $sot["doctrines_count"] ?? ($sot["counts"]["doctrines"] ?? 0)
],
"business" => [
"cash_collected_month_keur" => $sot["cash_collected_month_keur"] ?? 0,
"cash_collected_ytd_keur" => $sot["cash_collected_ytd_keur"] ?? 0,
"cash_target_month_keur" => $sot["cash_target_month_keur"] ?? 0,
"dso_days" => $sot["dso_days"] ?? 0
],
"ethica" => [
"total_hcps" => $sot["ethica_total"] ?? 0
],
"sources_used" => [
"source_of_truth_json" => !empty($sot),
"nonreg_latest" => !empty($nonreg),
"token_health_cache" => !empty($tokens),
"v83_latest" => ($v83["kpis"] !== null),
"docker_live" => ($docker_count > 0)
]
];
// Write cache
@file_put_contents($cache_file, json_encode($response, JSON_PRETTY_PRINT));
echo json_encode($response, JSON_PRETTY_PRINT);