new-site/api/src/routes/puc.ts
justin f8cd37ac8c Initial commit — Performance West telecom compliance platform
Includes: API (Express/TypeScript), Astro site, Python workers,
document generators, FCC compliance tools, Canada CRTC formation,
Ansible infrastructure, and deployment scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 06:54:22 -05:00

253 lines
8.8 KiB
TypeScript

/**
* State PUC/PSC Registration Requirements API
*
* GET /api/v1/puc/requirements?state=TX
* Returns PUC requirements for a single state.
*
* GET /api/v1/puc/requirements/all
* Returns all states for the multi-state picker.
*
* POST /api/v1/puc/quote
* Accepts { states: ['TX','NY'], type: 'voip'|'broadband'|'clec' }
* Returns per-state fee breakdown + bond requirements + service fee.
*/
import { Router, type Request, type Response } from "express";
import { pool } from "../db.js";
const router = Router();
// Our service fee per state
const PUC_SERVICE_FEE_CENTS = 39900; // $399/state
// ── GET /api/v1/puc/requirements?state=TX ────────────────────────────────────
router.get("/api/v1/puc/requirements", async (req: Request, res: Response) => {
try {
const state = (req.query.state as string || "").toUpperCase().trim();
if (!state || state.length !== 2) {
res.status(400).json({ error: "state query param required (2-letter code)" });
return;
}
const { rows } = await pool.query(
`SELECT * FROM state_puc_requirements WHERE state_code = $1`,
[state]
);
if (rows.length === 0) {
res.status(404).json({ error: `No PUC data for state: ${state}` });
return;
}
const r = rows[0];
res.json({
state_code: r.state_code,
agency_name: r.agency_name,
agency_url: r.agency_url,
voip: {
registration_required: r.voip_registration_required,
registration_type: r.voip_registration_type,
registration_fee_cents: r.voip_registration_fee_cents,
annual_fee_cents: r.voip_annual_fee_cents,
bond_required: r.voip_bond_required,
bond_amount_cents: r.voip_bond_amount_cents,
bond_type: r.voip_bond_type,
reseller_exempt: r.voip_reseller_exempt,
reseller_bond_cents: r.voip_reseller_bond_cents,
reseller_notes: r.voip_reseller_notes,
ott_exempt: r.voip_ott_exempt,
notes: r.voip_notes,
},
broadband: {
registration_required: r.broadband_registration_required,
registration_type: r.broadband_registration_type,
registration_fee_cents: r.broadband_registration_fee_cents,
annual_fee_cents: r.broadband_annual_fee_cents,
notes: r.broadband_notes,
},
clec: {
certification_required: r.clec_certification_required,
certification_fee_cents: r.clec_certification_fee_cents,
bond_required: r.clec_bond_required,
bond_amount_cents: r.clec_bond_amount_cents,
},
ongoing: {
annual_report_required: r.annual_report_required,
annual_report_due: r.annual_report_due,
usf_surcharge_required: r.usf_surcharge_required,
usf_surcharge_description: r.usf_surcharge_description,
},
notes: r.notes,
last_verified_date: r.last_verified_date,
service_fee_cents: PUC_SERVICE_FEE_CENTS,
});
} catch (err) {
console.error("[puc] requirements error:", err);
res.status(500).json({ error: "Internal server error" });
}
});
// ── GET /api/v1/puc/requirements/all ─────────────────────────────────────────
router.get("/api/v1/puc/requirements/all", async (_req: Request, res: Response) => {
try {
const { rows } = await pool.query(`
SELECT
r.state_code,
j.name AS state_name,
r.agency_name,
r.agency_url,
r.voip_registration_required,
r.voip_registration_type,
r.voip_registration_fee_cents,
r.voip_bond_required,
r.voip_bond_amount_cents,
r.voip_reseller_exempt,
r.voip_reseller_bond_cents,
r.voip_reseller_notes,
r.voip_ott_exempt,
r.broadband_registration_required,
r.broadband_registration_fee_cents,
r.clec_certification_required,
r.clec_certification_fee_cents,
r.clec_bond_required,
r.clec_bond_amount_cents,
r.annual_report_required,
r.usf_surcharge_required,
r.notes
FROM state_puc_requirements r
JOIN jurisdictions j ON j.code = r.state_code
WHERE j.country = 'US'
ORDER BY j.name
`);
res.json({
states: rows.map(r => ({
state_code: r.state_code,
state_name: r.state_name,
agency_name: r.agency_name,
agency_url: r.agency_url,
voip_required: r.voip_registration_required,
voip_type: r.voip_registration_type,
voip_fee_cents: r.voip_registration_fee_cents,
voip_bond_required: r.voip_bond_required,
voip_bond_cents: r.voip_bond_amount_cents,
voip_reseller_exempt: r.voip_reseller_exempt,
voip_reseller_bond_cents: r.voip_reseller_bond_cents,
voip_reseller_notes: r.voip_reseller_notes,
voip_ott_exempt: r.voip_ott_exempt,
broadband_required: r.broadband_registration_required,
broadband_fee_cents: r.broadband_registration_fee_cents,
clec_required: r.clec_certification_required,
clec_fee_cents: r.clec_certification_fee_cents,
clec_bond_required: r.clec_bond_required,
clec_bond_cents: r.clec_bond_amount_cents,
annual_report: r.annual_report_required,
usf_surcharge: r.usf_surcharge_required,
notes: r.notes,
})),
service_fee_cents: PUC_SERVICE_FEE_CENTS,
count: rows.length,
});
} catch (err) {
console.error("[puc] requirements/all error:", err);
res.status(500).json({ error: "Internal server error" });
}
});
// ── POST /api/v1/puc/quote ───────────────────────────────────────────────────
router.post("/api/v1/puc/quote", async (req: Request, res: Response) => {
try {
const { states, type } = req.body as { states?: string[]; type?: string };
if (!states || !Array.isArray(states) || states.length === 0) {
res.status(400).json({ error: "states array required" });
return;
}
const regType = type || "voip";
if (!["voip", "broadband", "clec", "bundle"].includes(regType)) {
res.status(400).json({ error: "type must be voip, broadband, clec, or bundle" });
return;
}
const codes = states.map(s => s.toUpperCase().trim()).filter(s => s.length === 2);
if (codes.length === 0) {
res.status(400).json({ error: "No valid 2-letter state codes provided" });
return;
}
const { rows } = await pool.query(
`SELECT r.*, j.name AS state_name
FROM state_puc_requirements r
JOIN jurisdictions j ON j.code = r.state_code
WHERE r.state_code = ANY($1)
ORDER BY j.name`,
[codes]
);
const breakdown = rows.map(r => {
let fee_cents = 0;
let bond_cents = 0;
let required = false;
if (regType === "voip" || regType === "bundle") {
fee_cents += r.voip_registration_fee_cents;
bond_cents += r.voip_bond_amount_cents;
required = r.voip_registration_required;
}
if (regType === "broadband" || regType === "bundle") {
fee_cents += r.broadband_registration_fee_cents;
required = required || r.broadband_registration_required;
}
if (regType === "clec" || regType === "bundle") {
fee_cents += r.clec_certification_fee_cents;
bond_cents = Math.max(bond_cents, r.clec_bond_amount_cents);
required = required || r.clec_certification_required;
}
return {
state_code: r.state_code,
state_name: r.state_name,
registration_required: required,
state_fee_cents: required ? fee_cents : 0,
bond_required: required && bond_cents > 0,
bond_amount_cents: required ? bond_cents : 0,
service_fee_cents: required ? PUC_SERVICE_FEE_CENTS : 0,
total_cents: required ? (PUC_SERVICE_FEE_CENTS + fee_cents) : 0,
exempt: !required,
notes: r.voip_notes || r.notes,
};
});
const requiredStates = breakdown.filter(b => b.registration_required);
const exemptStates = breakdown.filter(b => !b.registration_required);
const totalServiceFees = requiredStates.reduce((sum, b) => sum + b.service_fee_cents, 0);
const totalStateFees = requiredStates.reduce((sum, b) => sum + b.state_fee_cents, 0);
const totalBondAmount = requiredStates.reduce((sum, b) => sum + b.bond_amount_cents, 0);
res.json({
type: regType,
breakdown,
summary: {
total_states: codes.length,
required_states: requiredStates.length,
exempt_states: exemptStates.length,
service_fee_total_cents: totalServiceFees,
state_fee_total_cents: totalStateFees,
bond_total_cents: totalBondAmount,
grand_total_cents: totalServiceFees + totalStateFees,
bond_note: totalBondAmount > 0
? "Bond amounts shown are typical ranges. Exact bond requirement depends on provider size and type. Bond procurement is coordinated separately."
: null,
},
});
} catch (err) {
console.error("[puc] quote error:", err);
res.status(500).json({ error: "Internal server error" });
}
});
export default router;