import { Router } from "express"; import { pool } from "../db.js"; const router = Router(); /** * List all telecom entities for a customer. * * GET /api/v1/entities/telecom?customer_id=123 * GET /api/v1/entities/telecom?email=user@example.com */ router.get("/api/v1/entities/telecom", async (req, res) => { const { customer_id, email } = req.query; if (!customer_id && !email) { res.status(400).json({ error: "Provide customer_id or email." }); return; } try { let query: string; let params: any[]; if (customer_id) { query = "SELECT * FROM telecom_entities WHERE customer_id = $1 AND active = true ORDER BY jurisdiction, legal_name"; params = [customer_id]; } else { query = `SELECT te.* FROM telecom_entities te JOIN customers c ON c.id = te.customer_id WHERE c.email = $1 AND te.active = true ORDER BY te.jurisdiction, te.legal_name`; params = [(email as string).toLowerCase().trim()]; } const result = await pool.query(query, params); res.json({ entities: result.rows, count: result.rows.length, }); } catch (err) { console.error("[telecom-entities] List error:", err); res.status(500).json({ error: "Could not fetch entities." }); } }); /** * Get a single telecom entity by ID. * * GET /api/v1/entities/telecom/:id */ router.get("/api/v1/entities/telecom/:id", async (req, res) => { try { const result = await pool.query("SELECT * FROM telecom_entities WHERE id = $1", [req.params.id]); if (result.rows.length === 0) { res.status(404).json({ error: "Entity not found." }); return; } res.json(result.rows[0]); } catch (err) { console.error("[telecom-entities] Get error:", err); res.status(500).json({ error: "Could not fetch entity." }); } }); /** * Create a new telecom entity. * * POST /api/v1/entities/telecom */ router.post("/api/v1/entities/telecom", async (req, res) => { const { customer_id, customer_email, jurisdiction, legal_name, dba_name, ein, // FCC frn, filer_id_499, // CRTC incorporation_number, incorporation_province, crtc_registration_number, // Classification filer_type, infra_type, is_deminimis, is_lire, service_categories, // Contact contact_name, contact_email, contact_phone, ceo_name, ceo_title, // Address address_street, address_city, address_state, address_zip, // Revenue last_filing_year, total_revenue_cents, interstate_pct, international_pct, } = req.body ?? {}; if (!legal_name) { res.status(400).json({ error: "legal_name is required." }); return; } // Resolve customer_id from email if needed let resolvedCustomerId = customer_id; if (!resolvedCustomerId && customer_email) { const cust = await pool.query("SELECT id FROM customers WHERE email = $1", [customer_email.toLowerCase().trim()]); if (cust.rows.length > 0) { resolvedCustomerId = cust.rows[0].id; } } try { const result = await pool.query( `INSERT INTO telecom_entities ( customer_id, jurisdiction, legal_name, dba_name, ein, frn, filer_id_499, incorporation_number, incorporation_province, crtc_registration_number, filer_type, infra_type, is_deminimis, is_lire, service_categories, contact_name, contact_email, contact_phone, ceo_name, ceo_title, address_street, address_city, address_state, address_zip, last_filing_year, total_revenue_cents, interstate_pct, international_pct ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28) RETURNING *`, [ resolvedCustomerId || null, jurisdiction || "FCC", legal_name, dba_name || null, ein || null, frn || null, filer_id_499 || null, incorporation_number || null, incorporation_province || null, crtc_registration_number || null, filer_type || null, infra_type || null, is_deminimis === true, is_lire === true, service_categories || null, contact_name || null, contact_email || null, contact_phone || null, ceo_name || null, ceo_title || null, address_street || null, address_city || null, address_state || null, address_zip || null, last_filing_year || null, total_revenue_cents || 0, interstate_pct || 0, international_pct || 0, ], ); res.status(201).json(result.rows[0]); } catch (err) { console.error("[telecom-entities] Create error:", err); res.status(500).json({ error: "Could not create entity." }); } }); /** * Update a telecom entity. * * PATCH /api/v1/entities/telecom/:id */ router.patch("/api/v1/entities/telecom/:id", async (req, res) => { const id = req.params.id; const updates = req.body ?? {}; // Build dynamic SET clause from provided fields const allowedFields = [ "legal_name", "dba_name", "ein", "jurisdiction", "frn", "filer_id_499", "incorporation_number", "incorporation_province", "crtc_registration_number", "filer_type", "infra_type", "is_deminimis", "is_lire", "service_categories", "contact_name", "contact_email", "contact_phone", "ceo_name", "ceo_title", "address_street", "address_city", "address_state", "address_zip", "last_filing_year", "total_revenue_cents", "interstate_pct", "international_pct", "active", "notes", // Carrier classification (migration 043) "carrier_category", "is_wholesale", "is_gateway_provider", "is_international_only", "uses_ucaas_provider", "carrier_metadata", "stir_shaken_status", "stir_shaken_cert_authority", "upstream_provider_name", "upstream_provider_frn", "rmd_letter_minio_path", "rmd_letter_generated_at", "last_compliance_checkup", // FACS (Foreign Adversary Control System) fields (migration 045) "facs_schedule", "facs_has_foreign_adversary", "facs_filing_status", "facs_ownership_data", "covered_authorizations", "has_section_214", "facs_filed_at", // Form 499-A Block 1/2 fidelity (migrations 048, 054) "affiliated_filer_name", "affiliated_filer_ein", "management_company_name", "trade_names", "regulatory_contact_name", "regulatory_contact_email", "regulatory_contact_phone", "worksheet_office_company", "worksheet_office_street", "worksheet_office_city", "worksheet_office_state", "worksheet_office_zip", "billing_contact_name", "billing_contact_email", "itsp_regulatory_fee_email", "dc_agent_company", "dc_agent_street", "dc_agent_city", "dc_agent_state", "dc_agent_zip", "dc_agent_phone", "dc_agent_email", "officer_1_street", "officer_1_city", "officer_1_state", "officer_1_zip", "officer_2_name", "officer_2_title", "officer_2_street", "officer_2_city", "officer_2_state", "officer_2_zip", "officer_3_name", "officer_3_title", "officer_3_street", "officer_3_city", "officer_3_state", "officer_3_zip", "officer_count_claimed", "entity_structure", "jurisdictions_served", "first_telecom_service_year", "first_telecom_service_month", "first_telecom_service_pre_1999", // Form 499-A Block 6 fidelity (migrations 048, 054) "exempt_usf", "exempt_trs", "exempt_nanpa", "exempt_lnp", "exempt_itsp", "exemption_explanation", "is_state_local_gov", "is_tax_exempt_501c", "nondisclosure_requested", // Line 105 taxonomy (migration 053) "line_105_primary", "line_105_categories", "wireless_meta", "satellite_meta", "audio_bridging_meta", "private_line_circuits", // Safe harbor election (migration 054) "safe_harbor_election", // CORES + CALEA + foreign carrier (migration 052) "cores_username", "cores_password_hash", "cores_registered_at", "calea_ssi_generated_at", "calea_ssi_reviewer_name", "calea_ssi_next_review_date", "foreign_affiliations", // NECA OCN (migration 048) "ocn", "ocn_category", "ocn_assigned_at", ]; const sets: string[] = []; const values: any[] = []; let paramIdx = 1; for (const field of allowedFields) { if (field in updates) { sets.push(`${field} = $${paramIdx}`); values.push(updates[field]); paramIdx++; } } if (sets.length === 0) { res.status(400).json({ error: "No valid fields to update." }); return; } sets.push(`updated_at = NOW()`); values.push(id); try { const result = await pool.query( `UPDATE telecom_entities SET ${sets.join(", ")} WHERE id = $${paramIdx} RETURNING *`, values, ); if (result.rows.length === 0) { res.status(404).json({ error: "Entity not found." }); return; } res.json(result.rows[0]); } catch (err) { console.error("[telecom-entities] Update error:", err); res.status(500).json({ error: "Could not update entity." }); } }); /** * Classify a telecom entity's carrier type. * * PATCH /api/v1/entities/telecom/:id/classify * * Accepts the full carrier classification from the questionnaire and * validates field combinations (e.g. UCaaS provider requires metadata). */ router.patch("/api/v1/entities/telecom/:id/classify", async (req, res) => { const id = req.params.id; const body = req.body ?? {}; // Validate carrier_category const validCategories = [ "interconnected_voip", "non_interconnected_voip", "clec", "ixc", "cmrs", "other", ]; if (body.carrier_category && !validCategories.includes(body.carrier_category)) { res.status(400).json({ error: `Invalid carrier_category. Must be one of: ${validCategories.join(", ")}` }); return; } // Validate stir_shaken_status const validStirShaken = [ "complete_implementation", "partial_implementation", "robocall_mitigation_only", "exempt_small_carrier", "not_applicable", ]; if (body.stir_shaken_status && !validStirShaken.includes(body.stir_shaken_status)) { res.status(400).json({ error: `Invalid stir_shaken_status. Must be one of: ${validStirShaken.join(", ")}` }); return; } // Validate UCaaS metadata if (body.uses_ucaas_provider === true) { const meta = body.carrier_metadata ?? {}; if (!meta.ucaas_provider) { res.status(400).json({ error: "carrier_metadata.ucaas_provider is required when uses_ucaas_provider is true." }); return; } } // Validate gateway metadata if (body.is_gateway_provider === true) { const meta = body.carrier_metadata ?? {}; if (!meta.gateway_countries || !Array.isArray(meta.gateway_countries) || meta.gateway_countries.length === 0) { res.status(400).json({ error: "carrier_metadata.gateway_countries is required when is_gateway_provider is true." }); return; } } // Validate complete STIR/SHAKEN requires cert authority if (body.stir_shaken_status === "complete_implementation" && !body.stir_shaken_cert_authority) { res.status(400).json({ error: "stir_shaken_cert_authority is required for complete_implementation." }); return; } // Build update const classifyFields = [ "carrier_category", "is_wholesale", "is_gateway_provider", "is_international_only", "uses_ucaas_provider", "carrier_metadata", "stir_shaken_status", "stir_shaken_cert_authority", "upstream_provider_name", "upstream_provider_frn", // Also allow updating infra_type since the questionnaire captures it "infra_type", ]; const sets: string[] = []; const values: any[] = []; let paramIdx = 1; for (const field of classifyFields) { if (field in body) { if (field === "carrier_metadata") { sets.push(`${field} = $${paramIdx}::jsonb`); } else { sets.push(`${field} = $${paramIdx}`); } values.push(body[field]); paramIdx++; } } if (sets.length === 0) { res.status(400).json({ error: "No classification fields provided." }); return; } sets.push(`updated_at = NOW()`); values.push(id); try { const result = await pool.query( `UPDATE telecom_entities SET ${sets.join(", ")} WHERE id = $${paramIdx} RETURNING *`, values, ); if (result.rows.length === 0) { res.status(404).json({ error: "Entity not found." }); return; } res.json(result.rows[0]); } catch (err) { console.error("[telecom-entities] Classify error:", err); res.status(500).json({ error: "Could not classify entity." }); } }); /** * Run compliance check against a specific entity. * * GET /api/v1/entities/telecom/:id/compliance * * Uses the entity's FRN to run the same checks as /api/v1/fcc/lookup, * enriched with entity-specific data (classification, filing history). */ router.get("/api/v1/entities/telecom/:id/compliance", async (req, res) => { try { const entity = await pool.query("SELECT * FROM telecom_entities WHERE id = $1", [req.params.id]); if (entity.rows.length === 0) { res.status(404).json({ error: "Entity not found." }); return; } const e = entity.rows[0]; if (e.jurisdiction === "FCC" && e.frn) { // Proxy to the FCC lookup endpoint const lookupUrl = `http://localhost:${process.env.PORT || 3001}/api/v1/fcc/lookup?frn=${e.frn}`; const lookupResp = await fetch(lookupUrl, { signal: AbortSignal.timeout(30000) }); const lookupData = await lookupResp.json() as Record; res.json(Object.assign({ entity: { id: e.id, legal_name: e.legal_name, jurisdiction: e.jurisdiction, frn: e.frn, filer_type: e.filer_type, is_deminimis: e.is_deminimis, is_lire: e.is_lire, }, }, lookupData)); } else if (e.jurisdiction === "CRTC") { // CRTC compliance checks (simplified) const now = new Date(); const checks = [ { id: "crtc_registration", label: "CRTC Registration", status: e.crtc_registration_number ? "green" : "unknown", detail: e.crtc_registration_number ? `Registered: ${e.crtc_registration_number}` : "Registration number not on file", action_url: null, due_date: null, }, { id: "provincial_incorporation", label: `${e.incorporation_province || "Provincial"} Incorporation`, status: e.incorporation_number ? "green" : "unknown", detail: e.incorporation_number ? `${e.incorporation_province} #${e.incorporation_number}` : "Incorporation number not on file", action_url: null, due_date: null, }, ]; res.json({ entity: { id: e.id, legal_name: e.legal_name, jurisdiction: e.jurisdiction, incorporation_number: e.incorporation_number, incorporation_province: e.incorporation_province, }, checks, checked_at: new Date().toISOString(), }); } else { res.json({ entity: { id: e.id, legal_name: e.legal_name, jurisdiction: e.jurisdiction }, checks: [], note: "No FRN on file — add an FRN to run FCC compliance checks.", checked_at: new Date().toISOString(), }); } } catch (err) { console.error("[telecom-entities] Compliance check error:", err); res.status(500).json({ error: "Compliance check failed." }); } }); export default router;