/** * Vendor Reliability Scores * * Routes: * GET /api/vendor-reliability — Reliability score 0–100 per vendor */ import { Router, Request, Response } from "express"; import { pool } from "../db/client"; export const vendorReliabilityRouter = Router(); // ─── GET /api/vendor-reliability ───────────────────────────────────────────── vendorReliabilityRouter.get("/", async (_req: Request, res: Response) => { try { const result = await pool.query<{ vendor_id: number; vendor_name: string; last_observation: Date; obs_30d: string; distinct_skus_60d: string; days_since_last: string; }>(` WITH base AS ( SELECT po.source_vendor_id AS vendor_id, MAX(po.time) AS last_observation, COUNT(*) FILTER (WHERE po.time > NOW() - INTERVAL '30 days') AS obs_30d, COUNT(DISTINCT po.transceiver_id) FILTER (WHERE po.time > NOW() - INTERVAL '60 days') AS distinct_skus_60d FROM price_observations po WHERE po.time > NOW() - INTERVAL '90 days' GROUP BY po.source_vendor_id ) SELECT b.vendor_id, v.name AS vendor_name, b.last_observation, b.obs_30d, b.distinct_skus_60d, EXTRACT(EPOCH FROM (NOW() - b.last_observation)) / 86400.0 AS days_since_last FROM base b JOIN vendors v ON v.id = b.vendor_id ORDER BY b.last_observation DESC `); const vendors = result.rows.map((row) => { const days = parseFloat(row.days_since_last); const obs30d = parseInt(row.obs_30d, 10); const skus60d = parseInt(row.distinct_skus_60d, 10); const freshnessScore = days <= 7 ? 40 : days <= 14 ? 30 : days <= 30 ? 20 : days <= 60 ? 10 : 0; const frequencyScore = Math.min(Math.round((obs30d / 100) * 30), 30); const coverageScore = Math.min(Math.round((skus60d / 500) * 30), 30); const reliabilityScore = freshnessScore + frequencyScore + coverageScore; return { vendor_id: row.vendor_id, vendor_name: row.vendor_name, reliability_score: reliabilityScore, freshness_score: freshnessScore, frequency_score: frequencyScore, coverage_score: coverageScore, last_observation: row.last_observation.toISOString().slice(0, 10), obs_30d: obs30d, distinct_skus_60d: skus60d, }; }); vendors.sort((a, b) => b.reliability_score - a.reliability_score); res.json({ success: true, vendors }); } catch (err) { console.error("GET /api/vendor-reliability error:", err); res.status(500).json({ success: false, error: String(err) }); } });