Files
html/api/erp-gap-scans.php
opus 2d59cbc7eb
Some checks failed
WEVAL NonReg / nonreg (push) Has been cancelled
auto-commit via WEVIA vault_git intent 2026-04-19T19:30:31+00:00
2026-04-19 21:30:32 +02:00

115 lines
4.4 KiB
PHP

<?php
// WEVAL — ERP Gap Scans API
// GET /api/erp-gap-scans.php[?erp=<id>&min_conf=0.5&limit=20&source=llm|rss|playwright]
// Returns aggregated scan data for pain-points-atlas integration
header('Content-Type: application/json');
header('Cache-Control: public, max-age=60');
header('Access-Control-Allow-Origin: *');
$erp = $_GET['erp'] ?? null;
$min_conf = isset($_GET['min_conf']) ? (float)$_GET['min_conf'] : 0.3;
$limit = isset($_GET['limit']) ? min(100, (int)$_GET['limit']) : 50;
$source = $_GET['source'] ?? null; // llm|rss|playwright
try {
$pdo = new PDO('pgsql:host=10.1.0.3;port=5432;dbname=adx_system', 'admin', 'admin123', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_TIMEOUT => 3,
]);
// Source filter
$source_clause = "";
$params_stats = [];
if ($source) {
$source_clause = " WHERE query LIKE :source_pattern";
$params_stats[':source_pattern'] = $source . '_%';
}
// Global stats
$stmt = $pdo->prepare("SELECT
COUNT(*) as total_gaps,
COUNT(DISTINCT erp_id) as erps_covered,
ROUND(AVG(confidence_score)::NUMERIC, 3) as avg_confidence,
MAX(scanned_at) as last_scan_at,
COUNT(*) FILTER (WHERE query LIKE 'llm_%') as gaps_llm,
COUNT(*) FILTER (WHERE query LIKE 'rss_%') as gaps_rss,
COUNT(*) FILTER (WHERE query LIKE 'playwright%') as gaps_playwright
FROM erp_gap_scans" . $source_clause);
$stmt->execute($params_stats);
$stats = $stmt->fetch(PDO::FETCH_ASSOC);
// Per-ERP breakdown
$stmt = $pdo->prepare("-- V96.4: GROUP BY erp_id only (not erp_name) to avoid duplicates (Oracle Fusion vs Oracle Fusion Cloud ERP)
SELECT
erp_id,
MAX(erp_name) as erp_name, -- canonical display name
COUNT(*) as gaps_count,
ROUND(AVG(confidence_score)::NUMERIC, 3) as avg_conf,
MAX(scanned_at) as last_scan,
array_agg(DISTINCT CASE
WHEN query LIKE 'llm_%' THEN 'LLM'
WHEN query LIKE 'rss_%' THEN 'RSS'
WHEN query LIKE 'playwright%' THEN 'Playwright'
ELSE 'Other'
END) as sources
FROM erp_gap_scans" . $source_clause . "
GROUP BY erp_id
ORDER BY gaps_count DESC");
$stmt->execute($params_stats);
$per_erp = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Detail gaps (filtered)
$detail_sql = "SELECT id, erp_id, erp_name, title, snippet, source_url, confidence_score, keywords,
CASE
WHEN query LIKE 'llm_%' THEN 'LLM'
WHEN query LIKE 'rss_%' THEN 'RSS'
WHEN query LIKE 'playwright%' THEN 'Playwright'
ELSE 'Other'
END as source,
scanned_at
FROM erp_gap_scans
WHERE confidence_score >= :min_conf";
$params = [':min_conf' => $min_conf];
if ($erp) { $detail_sql .= " AND erp_id = :erp"; $params[':erp'] = $erp; }
if ($source) { $detail_sql .= " AND query LIKE :src"; $params[':src'] = $source . '_%'; }
$detail_sql .= " ORDER BY confidence_score DESC, scanned_at DESC LIMIT " . (int)$limit;
$stmt = $pdo->prepare($detail_sql);
$stmt->execute($params);
$details = $stmt->fetchAll(PDO::FETCH_ASSOC);
// Latest scans per source
$stmt = $pdo->query("SELECT
CASE
WHEN query LIKE 'llm_%' THEN 'LLM'
WHEN query LIKE 'rss_%' THEN 'RSS'
WHEN query LIKE 'playwright%' THEN 'Playwright'
ELSE 'Other'
END as source,
MAX(scanned_at) as last_scan,
COUNT(*) as gaps,
COUNT(DISTINCT erp_id) as erps
FROM erp_gap_scans GROUP BY source ORDER BY last_scan DESC");
$sources = $stmt->fetchAll(PDO::FETCH_ASSOC);
echo json_encode([
'generated_at' => date('c'),
'version' => 'V96',
'module' => 'ERP Gap Scans — consolidated D+C+B',
'stats' => $stats,
'sources' => $sources,
'per_erp' => $per_erp,
'gaps' => $details,
'filters_applied' => [
'erp' => $erp,
'min_confidence' => $min_conf,
'limit' => $limit,
'source' => $source,
],
], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => 'db_error', 'message' => $e->getMessage()]);
}