From c127cdd9087a72e2480fa8e07f12cac662dd1e00 Mon Sep 17 00:00:00 2001 From: justin Date: Wed, 6 May 2026 22:37:29 -0500 Subject: [PATCH] Improve compliance checker UX + add search logging - Loading message: shows estimated time (30-90 seconds) + rotating status updates (RMD, CPNI, USAC, BDC, STIR/SHAKEN, compiling report) - Timeout increased to 90s (was 60s) - Error messages: "try again in a few minutes" (not "moments" or "check internet") - New compliance_check_log table: logs every FCC lookup with FRN, entity, IP, user agent, referrer, issue count, severity, response time - Enables conversion funnel analysis and follow-up Co-Authored-By: Claude Opus 4.6 (1M context) --- api/migrations/077_compliance_check_log.sql | 26 ++++++++++++++++ api/src/routes/fcc-lookup.ts | 31 +++++++++++++++++++ .../pages/tools/fcc-compliance-check.astro | 31 ++++++++++++++++--- 3 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 api/migrations/077_compliance_check_log.sql diff --git a/api/migrations/077_compliance_check_log.sql b/api/migrations/077_compliance_check_log.sql new file mode 100644 index 0000000..cf72747 --- /dev/null +++ b/api/migrations/077_compliance_check_log.sql @@ -0,0 +1,26 @@ +-- 077: Log every FCC compliance check for analytics and follow-up. +-- Tracks who runs checks, what results they see, and whether they convert. + +CREATE TABLE IF NOT EXISTS compliance_check_log ( + id SERIAL PRIMARY KEY, + frn TEXT NOT NULL, + entity_name TEXT, + ip_address TEXT, + user_agent TEXT, + referrer TEXT, + -- Results summary + total_checks INTEGER DEFAULT 0, + issues_found INTEGER DEFAULT 0, + severity TEXT, -- critical, major, minor, clean + check_slugs TEXT[], -- which services were flagged + -- Timing + response_ms INTEGER, -- how long the API call took + -- Conversion tracking + clicked_order BOOLEAN DEFAULT FALSE, + order_number TEXT, -- if they eventually ordered + -- Metadata + created_at TIMESTAMPTZ DEFAULT NOW() +); + +CREATE INDEX IF NOT EXISTS idx_check_log_frn ON compliance_check_log(frn); +CREATE INDEX IF NOT EXISTS idx_check_log_created ON compliance_check_log(created_at); diff --git a/api/src/routes/fcc-lookup.ts b/api/src/routes/fcc-lookup.ts index 16e59a3..cca1a12 100644 --- a/api/src/routes/fcc-lookup.ts +++ b/api/src/routes/fcc-lookup.ts @@ -55,6 +55,7 @@ router.get("/api/v1/fcc/lookup", async (req, res) => { return; } + const startMs = Date.now(); try { // Phase 1: Fast local DB lookups first (~10ms) const [localRmdP, localRemovedP, local499P] = await Promise.allSettled([ @@ -824,6 +825,36 @@ router.get("/api/v1/fcc/lookup", async (req, res) => { checks, checked_at: new Date().toISOString(), }); + + // Log the check for analytics (non-blocking) + try { + const issueCount = checks?.filter((c: any) => c.severity === "critical" || c.severity === "major").length || 0; + const worstSeverity = checks?.some((c: any) => c.severity === "critical") ? "critical" + : checks?.some((c: any) => c.severity === "major") ? "major" + : checks?.some((c: any) => c.severity === "minor") ? "minor" : "clean"; + const flaggedSlugs = checks + ?.filter((c: any) => c.severity === "critical" || c.severity === "major") + .map((c: any) => c.id || c.slug || "") + .filter(Boolean) || []; + const elapsed = Date.now() - startMs; + + pool.query( + `INSERT INTO compliance_check_log (frn, entity_name, ip_address, user_agent, referrer, total_checks, issues_found, severity, check_slugs, response_ms) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`, + [ + frn, + entityName || null, + (req as any).clientIp || req.ip || null, + req.headers["user-agent"]?.slice(0, 200) || null, + req.headers.referer?.slice(0, 200) || null, + checks?.length || 0, + issueCount, + worstSeverity, + flaggedSlugs.length > 0 ? flaggedSlugs : null, + elapsed, + ], + ).catch(() => {}); // non-blocking, don't fail the response + } catch { /* ignore logging errors */ } } catch (err) { console.error("[fcc-lookup] Error:", err); res.status(500).json({ error: "FCC lookup failed. Please try again." }); diff --git a/site/src/pages/tools/fcc-compliance-check.astro b/site/src/pages/tools/fcc-compliance-check.astro index 3f24683..c04c7e1 100644 --- a/site/src/pages/tools/fcc-compliance-check.astro +++ b/site/src/pages/tools/fcc-compliance-check.astro @@ -84,7 +84,8 @@ import Base from "../../layouts/Base.astro"; -

Checking FCC databases…

+

Checking FCC databases…

+

This usually takes 30–90 seconds — we're querying multiple FCC systems in real time.

@@ -381,16 +382,36 @@ import Base from "../../layouts/Base.astro"; errorBox.classList.add("hidden"); loadingEl.classList.remove("hidden"); + // Progress status updates while waiting + const statusEl = document.getElementById("loading-status"); + const statusMsgs = [ + "Checking FCC databases\u2026", + "Querying Robocall Mitigation Database\u2026", + "Checking CPNI certification status\u2026", + "Looking up USAC 499 filing history\u2026", + "Verifying BDC / Form 477 records\u2026", + "Checking STIR/SHAKEN implementation\u2026", + "Compiling your compliance report\u2026", + ]; + let msgIdx = 0; + const statusTimer = setInterval(() => { + msgIdx++; + if (statusEl && msgIdx < statusMsgs.length) { + statusEl.textContent = statusMsgs[msgIdx]; + } + }, 8000); + // Cancel any prior in-flight request if (currentController) currentController.abort(); const controller = new AbortController(); currentController = controller; try { - const timeout = setTimeout(() => controller.abort(), 60000); + const timeout = setTimeout(() => controller.abort(), 90000); const res = await fetch(`${API}/api/v1/fcc/lookup?frn=${frn}`, { signal: controller.signal }); clearTimeout(timeout); + clearInterval(statusTimer); // Ignore if a newer request superseded this one if (currentController !== controller) return; @@ -409,12 +430,14 @@ import Base from "../../layouts/Base.astro"; } renderResults(data); } catch (err) { + clearInterval(statusTimer); if (err.name === "AbortError") { - showError("The FCC databases are taking too long to respond. Please try again in a few moments."); + showError("The FCC databases are taking too long to respond. Please try again in a few minutes."); } else { - showError(err.message || "Could not reach the FCC databases. Please check your internet connection and try again."); + showError(err.message || "Could not reach the FCC databases right now. Please try again in a few minutes."); } } finally { + clearInterval(statusTimer); loadingEl.classList.add("hidden"); } }