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>
This commit is contained in:
commit
f8cd37ac8c
1823 changed files with 145167 additions and 0 deletions
97
site/src/lib/fcc_constants.ts
Normal file
97
site/src/lib/fcc_constants.ts
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
// FCC Constants — safe harbor %s, de minimis factors, Line 105 ticking rules
|
||||
//
|
||||
// The authoritative source of these values is USAC's annual Form 499-A
|
||||
// Instructions (released each November). Kept here for client-side use in
|
||||
// the intake wizard (display defaults, validation). The server-side
|
||||
// lookup goes against fcc_deminimis_factors + fcc_safe_harbor_percentages
|
||||
// DB tables — so this file mirrors those and must stay in sync.
|
||||
//
|
||||
// Authority: 2026 Form 499-A Instructions
|
||||
// docs/fcc-references/2026-FCC-Form-499A-Form-Instructions.pdf
|
||||
|
||||
export const US_STATES_AND_TERRITORIES: string[] = [
|
||||
"AL","AK","AZ","AR","CA","CO","CT","DE","DC","FL","GA","HI","ID","IL","IN",
|
||||
"IA","KS","KY","LA","ME","MD","MA","MI","MN","MS","MO","MT","NE","NV","NH",
|
||||
"NJ","NM","NY","NC","ND","OH","OK","OR","PA","RI","SC","SD","TN","TX","UT",
|
||||
"VT","VA","WA","WV","WI","WY",
|
||||
// US territories (Line 227 requires these as well)
|
||||
"PR","GU","VI","AS","MP","UM", // Puerto Rico, Guam, USVI, Am. Samoa, N. Mariana, US Minor Outlying
|
||||
];
|
||||
|
||||
// ── De minimis factor by form year ──────────────────────────────────────
|
||||
// Per 2026 Form 499-A Appendix A Line 10 = 0.256. The factor changes
|
||||
// annually; keep in sync with fcc_deminimis_factors table.
|
||||
export const DE_MINIMIS_FACTOR_BY_YEAR: Record<number, number> = {
|
||||
2026: 0.2560,
|
||||
};
|
||||
|
||||
// De minimis exemption threshold ($)
|
||||
export const DE_MINIMIS_THRESHOLD_USD = 10000;
|
||||
|
||||
// ── Safe harbor percentages by form year + category ─────────────────────
|
||||
// Per 2026 Form 499-A Section IV.C.5.g. Non-interconnected VoIP has NO
|
||||
// safe harbor — must use traffic study or actual data.
|
||||
export const SAFE_HARBOR_PCT_BY_YEAR: Record<
|
||||
number,
|
||||
Record<string, number>
|
||||
> = {
|
||||
2026: {
|
||||
voip_interconnected: 64.9,
|
||||
cellular_pcs: 37.1,
|
||||
paging: 12.0,
|
||||
smr_dispatch: 1.0,
|
||||
},
|
||||
};
|
||||
|
||||
// Categories for which safe-harbor election is DISALLOWED (must use traffic study or actual data)
|
||||
export const SAFE_HARBOR_DISALLOWED_CATEGORIES: Set<string> = new Set([
|
||||
"voip_non_interconnected",
|
||||
]);
|
||||
|
||||
// ── Officer-definition help text (Lines 221/223/225) ────────────────────
|
||||
// Verbatim from 2026 instructions, paraphrased slightly for clarity.
|
||||
export const OFFICER_DEFINITION_HELP_TEXT =
|
||||
"An officer is an occupant of a position listed in the articles of "
|
||||
+ "incorporation, articles of formation, or other similar legal document. "
|
||||
+ "For corporations and LLCs, list the CEO/President/Chairman (and if "
|
||||
+ "the same person holds multiple, the next-most-senior officers). For "
|
||||
+ "sole proprietorships, list the owner only. For partnerships, list "
|
||||
+ "the managing partner plus the two partners with the greatest "
|
||||
+ "financial interest.";
|
||||
|
||||
// ── Form 499-A filing types (Line 612) ──────────────────────────────────
|
||||
export type FilingType =
|
||||
| "original_april_1"
|
||||
| "registration_new_filer"
|
||||
| "revised_registration"
|
||||
| "revised_revenue";
|
||||
|
||||
export const FILING_TYPE_LABELS: Record<FilingType, string> = {
|
||||
original_april_1: "Original Filing (April 1)",
|
||||
registration_new_filer: "Registration — New Filer",
|
||||
revised_registration: "Revised Filing (Registration Info)",
|
||||
revised_revenue: "Revised Filing (Revenue Info)",
|
||||
};
|
||||
|
||||
// ── Reseller certification — sample language (FCC Section IV.C.4) ───────
|
||||
// Near-verbatim from 2026 instructions. Used as default text in
|
||||
// ResellerCertStep.astro for the signed certification body.
|
||||
export const RESELLER_CERTIFICATION_SAMPLE_TEXT =
|
||||
"I certify under penalty of perjury that the company is purchasing "
|
||||
+ "service(s) for resale, at least in part, and that the company is "
|
||||
+ "incorporating the purchased services into its own offerings which are, "
|
||||
+ "at least in part, assessable U.S. telecommunications or interconnected "
|
||||
+ "Voice over Internet Protocol services. I also certify under penalty "
|
||||
+ "of perjury that the company either directly contributes or has a "
|
||||
+ "reasonable expectation that another entity in the downstream chain "
|
||||
+ "of resellers directly contributes to the federal universal service "
|
||||
+ "support mechanisms on the assessable portion of revenues from "
|
||||
+ "offerings that incorporate the purchased services.";
|
||||
|
||||
// ── Nondisclosure (Line 605) certification text ─────────────────────────
|
||||
export const NONDISCLOSURE_CERT_TEXT =
|
||||
"By checking this box, the officer of the company signing the Worksheet "
|
||||
+ "certifies that the information contained on the Worksheet is "
|
||||
+ "privileged or confidential commercial or financial information and "
|
||||
+ "that disclosure of such information would likely cause substantial "
|
||||
+ "harm to the competitive position of the company filing the Worksheet.";
|
||||
143
site/src/lib/intake_manifest.ts
Normal file
143
site/src/lib/intake_manifest.ts
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/**
|
||||
* Per-service intake step manifest.
|
||||
*
|
||||
* Each service slug maps to the ordered list of wizard steps. The Wizard
|
||||
* component inserts category-gated dynamic steps (wireless, earth_station,
|
||||
* audio_bridging, icc_import, reseller_cert) at runtime based on the
|
||||
* user's Line 105 selection, between the declared step markers.
|
||||
*
|
||||
* Keep in sync with:
|
||||
* - api/src/routes/compliance-orders.ts REQUIRED_FIELDS
|
||||
* - scripts/workers/services/__init__.py SERVICE_HANDLERS registry
|
||||
*/
|
||||
|
||||
export type IntakeStep =
|
||||
| "entity"
|
||||
| "category" // NEW: Line 105 ranked multi-select
|
||||
| "officer"
|
||||
| "jurisdiction"
|
||||
| "history" // NEW: Line 228 first-service date
|
||||
| "wireless" // NEW: category-gated — inserted when wireless selected
|
||||
| "earth_station" // NEW: category-gated — satellite + private_line
|
||||
| "audio_bridging" // NEW: category-gated — audio_bridging
|
||||
| "revenue"
|
||||
| "bundled_service" // NEW: local+toll bundle allocation
|
||||
| "icc_import" // NEW: ICC revenue file uploads
|
||||
| "reseller_cert" // NEW: Line 303 reseller certifications
|
||||
| "lnpa_region" // NEW: Block 5 Lines 503-510 LNPA regions
|
||||
| "block6_cert" // NEW: exemptions + nondisclosure + filing type
|
||||
| "bdc_data"
|
||||
| "stir_shaken"
|
||||
| "calea"
|
||||
| "foreign_carrier"
|
||||
| "foreign_qual" // NEW: multi-state COA picker
|
||||
| "dc_agent" // NEW: DC registered agent choice
|
||||
| "cpni_questions" // NEW: CPNI certification questionnaire (sec 5-9)
|
||||
| "cdr_period"
|
||||
| "ocn"
|
||||
| "review"
|
||||
| "payment";
|
||||
|
||||
export const INTAKE_MANIFEST: Record<string, IntakeStep[]> = {
|
||||
// Diagnostic — lightweight; just needs the entity
|
||||
"fcc-compliance-checkup": ["entity", "review", "payment"],
|
||||
|
||||
// Entry-point filings
|
||||
"cores-frn-registration": ["entity", "officer", "review", "payment"],
|
||||
"fcc-499-initial": [
|
||||
"entity", "classification", "category", "officer", "jurisdiction", "history",
|
||||
"dc_agent", "block6_cert", "review", "payment",
|
||||
],
|
||||
|
||||
// Annual + quarterly revenue filings — the full fidelity flow
|
||||
"fcc-499a": [
|
||||
"entity", "classification", "category", "officer", "jurisdiction", "history",
|
||||
"dc_agent", "revenue", "bundled_service", "icc_import",
|
||||
"reseller_cert", "lnpa_region",
|
||||
"block6_cert", "review", "payment",
|
||||
],
|
||||
"fcc-499a-499q": [
|
||||
"entity", "classification", "category", "officer", "jurisdiction",
|
||||
"revenue", "icc_import",
|
||||
"block6_cert", "review", "payment",
|
||||
],
|
||||
|
||||
// RMD + CPNI + STIR/SHAKEN
|
||||
"rmd-filing": ["entity", "officer", "stir_shaken", "review", "payment"],
|
||||
"cpni-certification": ["entity", "officer", "cpni_questions", "review", "payment"],
|
||||
"stir-shaken": ["entity", "stir_shaken", "review", "payment"],
|
||||
|
||||
// BDC tiers (formerly Form 477)
|
||||
"bdc-broadband": ["entity", "bdc_data", "review", "payment"],
|
||||
"bdc-voice": ["entity", "bdc_data", "review", "payment"],
|
||||
"bdc-filing": ["entity", "bdc_data", "review", "payment"],
|
||||
|
||||
// CALEA + foreign-affiliation
|
||||
"calea-ssi": ["entity", "category", "calea", "review", "payment"],
|
||||
"fcc-63-11-notification": ["entity", "foreign_carrier", "review", "payment"],
|
||||
|
||||
// Supporting services
|
||||
"ocn-registration": ["entity", "ocn", "review", "payment"],
|
||||
"dc-agent": ["entity", "review", "payment"],
|
||||
"cdr-analysis": ["entity", "cdr_period", "review", "payment"],
|
||||
|
||||
// Foreign qualification — Certificate of Authority across US states
|
||||
"foreign-qualification-single": [
|
||||
"entity", "foreign_qual", "review", "payment",
|
||||
],
|
||||
"foreign-qualification-multi": [
|
||||
"entity", "foreign_qual", "review", "payment",
|
||||
],
|
||||
|
||||
// Bundles
|
||||
"fcc-full-compliance": [
|
||||
"entity", "category", "officer", "jurisdiction", "history",
|
||||
"revenue", "stir_shaken", "icc_import",
|
||||
"reseller_cert", "lnpa_region", "block6_cert",
|
||||
"review", "payment",
|
||||
],
|
||||
"new-carrier-bundle": [
|
||||
"entity", "category", "officer", "jurisdiction", "history",
|
||||
"dc_agent", "calea", "review", "payment",
|
||||
],
|
||||
};
|
||||
|
||||
// Category-gated dynamic steps. The Wizard inserts these after the `category`
|
||||
// step when the corresponding Line 105 category is in line_105_categories.
|
||||
export const CATEGORY_GATED_STEPS: Record<string, IntakeStep[]> = {
|
||||
wireless: ["wireless"],
|
||||
satellite: ["earth_station"],
|
||||
mobile_satellite:["earth_station"],
|
||||
private_line: ["earth_station"],
|
||||
audio_bridging: ["audio_bridging"],
|
||||
};
|
||||
|
||||
// ── Pricing + human name lookup (mirrors COMPLIANCE_SERVICES server-side)
|
||||
export const SERVICE_META: Record<string, { name: string; price_cents: number }> = {
|
||||
"fcc-compliance-checkup": { name: "FCC Carrier Compliance Checkup", price_cents: 79900 },
|
||||
"fcc-499a": { name: "FCC Form 499-A Filing", price_cents: 49900 },
|
||||
"fcc-499a-499q": { name: "FCC Form 499-A + 499-Q Bundle", price_cents: 59900 },
|
||||
"fcc-full-compliance": { name: "FCC Full Compliance Bundle", price_cents: 149900 },
|
||||
"cpni-certification": { name: "CPNI Annual Certification", price_cents: 14900 },
|
||||
"rmd-filing": { name: "RMD Registration / Recertification", price_cents: 21900 }, // + $100 FCC filing fee passthrough
|
||||
"stir-shaken": { name: "STIR/SHAKEN Implementation Assistance", price_cents: 49900 },
|
||||
"dc-agent": { name: "D.C. Registered Agent (Annual)", price_cents: 9900 },
|
||||
"bdc-broadband": { name: "BDC Broadband Deployment Filing", price_cents: 19900 },
|
||||
"bdc-voice": { name: "BDC Voice Subscription (formerly Form 477)", price_cents: 14900 },
|
||||
"bdc-filing": { name: "BDC Filing (Broadband + Voice)", price_cents: 29900 },
|
||||
"ocn-registration": { name: "NECA OCN / Company Code Registration", price_cents: 65000 },
|
||||
"cdr-analysis": { name: "CDR Traffic Study (Annual)", price_cents: 49900 },
|
||||
"cores-frn-registration": { name: "CORES / FRN Registration", price_cents: 9900 },
|
||||
"fcc-499-initial": { name: "Form 499 Initial Registration", price_cents: 29900 },
|
||||
"calea-ssi": { name: "CALEA SSI Plan", price_cents: 29900 },
|
||||
"fcc-63-11-notification": { name: "Foreign Carrier Affiliation Notification", price_cents: 34900 },
|
||||
"new-carrier-bundle": { name: "New Carrier Onboarding Bundle", price_cents: 179900 },
|
||||
"foreign-qualification-single": { name: "Foreign Qualification (One State)", price_cents: 14900 },
|
||||
"foreign-qualification-multi": { name: "Foreign Qualification (Multi-State)", price_cents: 9900 },
|
||||
};
|
||||
|
||||
export function formatUSD(cents: number): string {
|
||||
return `$${(cents / 100).toLocaleString("en-US", {
|
||||
minimumFractionDigits: 2, maximumFractionDigits: 2,
|
||||
})}`;
|
||||
}
|
||||
302
site/src/lib/line_105_catalog.ts
Normal file
302
site/src/lib/line_105_catalog.ts
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
// Line 105 Category Catalog — FCC Form 499-A Appendix B (2026 edition)
|
||||
//
|
||||
// The 2026 instructions enumerate 22 Line 105 categories, grouped in this
|
||||
// file by how much intake flow each gets:
|
||||
// * first_class — dedicated intake step, CPNI/CALEA variant, special
|
||||
// revenue-line logic
|
||||
// * subtype_of — not a standalone category; marks a CLEC/IXC/Wireless
|
||||
// with infra_type=reseller/mvno, or Satellite with a
|
||||
// subservice flag. form_499a.py still ticks the box on
|
||||
// the form; handler behavior mirrors the parent.
|
||||
// * flag_only — we tick the Line 105 box correctly, nothing else
|
||||
// special (revenue flows through standard lines)
|
||||
// * deprecated — admin ToDo only; we don't support new flows for
|
||||
// these categories, too rare to prioritize
|
||||
//
|
||||
// The catalog drives CategoryStep.astro (ranked multi-select UI) and the
|
||||
// handler's form-filling logic.
|
||||
|
||||
export type Line105Status =
|
||||
| "first_class"
|
||||
| "subtype_of"
|
||||
| "flag_only"
|
||||
| "deprecated";
|
||||
|
||||
export type Line105Grouping =
|
||||
| "common" // shown expanded by default
|
||||
| "carrier_grade" // collapsed; "expand to see more carrier types"
|
||||
| "specialized" // collapsed; satellite / audio-bridging / MSS
|
||||
| "rare"; // collapsed; "handled manually" warning
|
||||
|
||||
export interface Line105Entry {
|
||||
id: string; // matches form_499a.py handler enum
|
||||
label: string; // UI label
|
||||
fcc_box_number: number; // the numbered box on the paper form
|
||||
status: Line105Status;
|
||||
grouping: Line105Grouping;
|
||||
parent?: string; // when status=subtype_of, the parent category id
|
||||
tooltip: string; // short plain-English help
|
||||
reseller_offered?: boolean; // show "Do you own facilities or resell?" sub-question
|
||||
tdm_offered?: boolean; // show "TDM or packet?" under reseller
|
||||
mvno_offered?: boolean; // show "Do you own spectrum or are you an MVNO?"
|
||||
}
|
||||
|
||||
export const LINE_105_CATALOG: Line105Entry[] = [
|
||||
// ── COMMON (expanded by default) ───────────────────────────────────────
|
||||
{
|
||||
id: "voip_interconnected",
|
||||
label: "Interconnected VoIP provider",
|
||||
fcc_box_number: 1,
|
||||
status: "first_class",
|
||||
grouping: "common",
|
||||
tooltip:
|
||||
"VoIP service that interconnects with the PSTN and allows customers "
|
||||
+ "to make and receive calls to/from ordinary phone numbers. Safe "
|
||||
+ "harbor of 64.9% interstate available.",
|
||||
},
|
||||
{
|
||||
id: "voip_non_interconnected",
|
||||
label: "Non-interconnected (one-way) VoIP",
|
||||
fcc_box_number: 2,
|
||||
status: "first_class",
|
||||
grouping: "common",
|
||||
tooltip:
|
||||
"VoIP that only makes OR only receives calls (not both). No safe "
|
||||
+ "harbor — requires traffic study or actual billing data.",
|
||||
},
|
||||
{
|
||||
id: "clec",
|
||||
label: "Competitive Local Exchange Carrier (CLEC)",
|
||||
fcc_box_number: 3,
|
||||
status: "first_class",
|
||||
grouping: "common",
|
||||
tooltip:
|
||||
"Competitive local carrier offering wireline telephone service in "
|
||||
+ "direct competition with the incumbent (ILEC).",
|
||||
reseller_offered: true,
|
||||
tdm_offered: true,
|
||||
},
|
||||
{
|
||||
id: "ixc",
|
||||
label: "Interexchange Carrier (IXC)",
|
||||
fcc_box_number: 7,
|
||||
status: "first_class",
|
||||
grouping: "common",
|
||||
tooltip:
|
||||
"Long-distance (toll) carrier. Access-charge collection matters here "
|
||||
+ "— originating access and 8YY revenue belong on Line 404.x.",
|
||||
reseller_offered: true,
|
||||
tdm_offered: true,
|
||||
},
|
||||
{
|
||||
id: "wireless",
|
||||
label: "Wireless / Cellular / PCS (CMRS)",
|
||||
fcc_box_number: 8,
|
||||
status: "first_class",
|
||||
grouping: "common",
|
||||
tooltip:
|
||||
"Commercial Mobile Radio Service — cellular, PCS. Safe harbor of "
|
||||
+ "37.1% interstate. MVNOs are a subtype below.",
|
||||
mvno_offered: true,
|
||||
},
|
||||
|
||||
// ── CARRIER_GRADE (collapsed) ──────────────────────────────────────────
|
||||
{
|
||||
id: "ilec",
|
||||
label: "Incumbent LEC (ILEC)",
|
||||
fcc_box_number: 4,
|
||||
status: "flag_only",
|
||||
grouping: "carrier_grade",
|
||||
tooltip:
|
||||
"Historical local exchange carrier. We don't onboard ILECs — select "
|
||||
+ "this and our team will reach out.",
|
||||
},
|
||||
{
|
||||
id: "local_reseller",
|
||||
label: "Local Reseller (TDM era)",
|
||||
fcc_box_number: 5,
|
||||
status: "subtype_of",
|
||||
parent: "clec",
|
||||
grouping: "carrier_grade",
|
||||
tooltip:
|
||||
"Historical category for carriers that buy wholesale from an ILEC "
|
||||
+ "and rebrand. If this describes you, check CLEC above and set "
|
||||
+ "infrastructure = reseller.",
|
||||
},
|
||||
{
|
||||
id: "toll_reseller",
|
||||
label: "Toll Reseller",
|
||||
fcc_box_number: 6,
|
||||
status: "subtype_of",
|
||||
parent: "ixc",
|
||||
grouping: "carrier_grade",
|
||||
tooltip:
|
||||
"Long-distance reseller buying wholesale minutes. Check IXC above "
|
||||
+ "and set infrastructure = reseller.",
|
||||
},
|
||||
{
|
||||
id: "private_line",
|
||||
label: "Private Line / Business Data Service",
|
||||
fcc_box_number: 11,
|
||||
status: "first_class",
|
||||
grouping: "carrier_grade",
|
||||
tooltip:
|
||||
"Dedicated point-to-point circuits (DS-1/DS-3/Ethernet). Includes "
|
||||
+ "special-access and BDS services.",
|
||||
},
|
||||
{
|
||||
id: "toll_free",
|
||||
label: "Toll-Free (8YY) Service",
|
||||
fcc_box_number: 17,
|
||||
status: "flag_only",
|
||||
grouping: "carrier_grade",
|
||||
tooltip:
|
||||
"Customer-paid-calling (8YY) service provider. 8YY originating "
|
||||
+ "access revenue flows through ICC imports.",
|
||||
},
|
||||
|
||||
// ── SPECIALIZED (collapsed) ─────────────────────────────────────────────
|
||||
{
|
||||
id: "mvno",
|
||||
label: "Mobile Virtual Network Operator (MVNO)",
|
||||
fcc_box_number: 9,
|
||||
status: "subtype_of",
|
||||
parent: "wireless",
|
||||
grouping: "specialized",
|
||||
tooltip:
|
||||
"Wireless service that uses another carrier's network (e.g., buying "
|
||||
+ "from T-Mobile / Verizon / AT&T). Check Wireless above and set "
|
||||
+ "infrastructure = MVNO.",
|
||||
},
|
||||
{
|
||||
id: "satellite",
|
||||
label: "Satellite Service",
|
||||
fcc_box_number: 12,
|
||||
status: "first_class",
|
||||
grouping: "specialized",
|
||||
tooltip:
|
||||
"Earth-station based satellite service (FSS / BSS). Requires FCC "
|
||||
+ "Form 312 earth station license.",
|
||||
},
|
||||
{
|
||||
id: "mobile_satellite",
|
||||
label: "Mobile Satellite Service (MSS)",
|
||||
fcc_box_number: 21,
|
||||
status: "subtype_of",
|
||||
parent: "satellite",
|
||||
grouping: "specialized",
|
||||
tooltip:
|
||||
"Mobile satellite (Iridium, Globalstar, Starlink Commercial mobile). "
|
||||
+ "Check Satellite above and set service_type=MSS.",
|
||||
},
|
||||
{
|
||||
id: "audio_bridging",
|
||||
label: "Audio Bridging / Conferencing Service",
|
||||
fcc_box_number: 16,
|
||||
status: "first_class",
|
||||
grouping: "specialized",
|
||||
tooltip:
|
||||
"Multi-party audio conferencing provider. FCC clarified in 2021 "
|
||||
+ "that bridging in interstate commerce is telecom service.",
|
||||
},
|
||||
{
|
||||
id: "fixed_wireless",
|
||||
label: "Fixed Wireless (non-mobile)",
|
||||
fcc_box_number: 20,
|
||||
status: "subtype_of",
|
||||
parent: "clec",
|
||||
grouping: "specialized",
|
||||
tooltip:
|
||||
"Fixed wireless last-mile local service. Check CLEC above and set "
|
||||
+ "infrastructure = facilities + wireless_metadata.",
|
||||
},
|
||||
{
|
||||
id: "prepaid_calling_card",
|
||||
label: "Prepaid Calling Card",
|
||||
fcc_box_number: 10,
|
||||
status: "flag_only",
|
||||
grouping: "specialized",
|
||||
tooltip:
|
||||
"Prepaid long-distance cards. Revenue goes on Line 411 with special "
|
||||
+ "safe-harbor rules.",
|
||||
},
|
||||
|
||||
// ── RARE / DEPRECATED (collapsed with warning) ─────────────────────────
|
||||
{
|
||||
id: "payphone",
|
||||
label: "Payphone Service Provider (PSP)",
|
||||
fcc_box_number: 13,
|
||||
status: "deprecated",
|
||||
grouping: "rare",
|
||||
tooltip:
|
||||
"Rare in 2026 — if this describes you, our team will handle manually.",
|
||||
},
|
||||
{
|
||||
id: "osp",
|
||||
label: "Operator Service Provider (OSP)",
|
||||
fcc_box_number: 14,
|
||||
status: "flag_only",
|
||||
grouping: "rare",
|
||||
tooltip: "Operator-assisted call service provider.",
|
||||
},
|
||||
{
|
||||
id: "shared_tenant",
|
||||
label: "Shared Tenant Services",
|
||||
fcc_box_number: 15,
|
||||
status: "flag_only",
|
||||
grouping: "rare",
|
||||
tooltip: "Shared tenant telecommunications (e.g., building-wide PBX resale).",
|
||||
},
|
||||
{
|
||||
id: "paging",
|
||||
label: "Paging / Messaging",
|
||||
fcc_box_number: 18,
|
||||
status: "deprecated",
|
||||
grouping: "rare",
|
||||
tooltip: "Standalone paging — rare in 2026. Our team will handle manually.",
|
||||
},
|
||||
{
|
||||
id: "smr",
|
||||
label: "Specialized Mobile Radio (SMR)",
|
||||
fcc_box_number: 19,
|
||||
status: "deprecated",
|
||||
grouping: "rare",
|
||||
tooltip: "Specialized mobile radio dispatch. Rare — our team will handle manually.",
|
||||
},
|
||||
{
|
||||
id: "other",
|
||||
label: "Other (describe separately)",
|
||||
fcc_box_number: 22,
|
||||
status: "flag_only",
|
||||
grouping: "rare",
|
||||
tooltip:
|
||||
"Any category not listed above. Our team will follow up for a "
|
||||
+ "free-text description required on the form.",
|
||||
},
|
||||
];
|
||||
|
||||
// Convenience lookups
|
||||
export const LINE_105_BY_ID: Record<string, Line105Entry> = Object.fromEntries(
|
||||
LINE_105_CATALOG.map((c) => [c.id, c]),
|
||||
);
|
||||
|
||||
export const LINE_105_GROUPS: Record<Line105Grouping, Line105Entry[]> =
|
||||
LINE_105_CATALOG.reduce((acc, entry) => {
|
||||
(acc[entry.grouping] ||= []).push(entry);
|
||||
return acc;
|
||||
}, {} as Record<Line105Grouping, Line105Entry[]>);
|
||||
|
||||
// Map a category id → the extra Line 105 box that gets auto-ticked because
|
||||
// of the infra_type/mvno flag. form_499a.py mirrors this logic.
|
||||
export function derivedLine105Boxes(
|
||||
categoryId: string,
|
||||
infra_type?: string,
|
||||
): number[] {
|
||||
const boxes: number[] = [];
|
||||
if (infra_type === "reseller") {
|
||||
if (categoryId === "clec") boxes.push(5); // local_reseller
|
||||
if (categoryId === "ixc") boxes.push(6); // toll_reseller
|
||||
}
|
||||
if (infra_type === "mvno" && categoryId === "wireless") boxes.push(9);
|
||||
return boxes;
|
||||
}
|
||||
113
site/src/lib/lnpa_regions_catalog.ts
Normal file
113
site/src/lib/lnpa_regions_catalog.ts
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// LNPA Region Catalog — 10 regions for Form 499-A Block 5 Lines 503-510
|
||||
//
|
||||
// The NANPA/LNPA regions as defined by iconectiv NPAC. Every filer with
|
||||
// telecom revenue must allocate Block 3 (carrier's carrier) and Block 4
|
||||
// (end user) revenues across these regions as percentages summing to 100%
|
||||
// per column.
|
||||
//
|
||||
// Used by LNPARegionStep.astro to render the 10-region grid.
|
||||
|
||||
export interface LnpaRegion {
|
||||
code: string;
|
||||
label: string;
|
||||
states: string[]; // postal codes of states in the region
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const LNPA_REGIONS: LnpaRegion[] = [
|
||||
{
|
||||
code: "NE",
|
||||
label: "Northeast",
|
||||
states: ["CT", "MA", "ME", "NH", "NY", "RI", "VT"],
|
||||
description: "Connecticut, Massachusetts, Maine, New Hampshire, New York, Rhode Island, Vermont",
|
||||
},
|
||||
{
|
||||
code: "MA",
|
||||
label: "Mid-Atlantic",
|
||||
states: ["DC", "DE", "MD", "NJ", "PA", "VA", "WV"],
|
||||
description: "DC, Delaware, Maryland, New Jersey, Pennsylvania, Virginia, West Virginia",
|
||||
},
|
||||
{
|
||||
code: "SE",
|
||||
label: "Southeast",
|
||||
states: ["AL", "FL", "GA", "KY", "MS", "NC", "SC", "TN"],
|
||||
description: "Alabama, Florida, Georgia, Kentucky, Mississippi, North Carolina, South Carolina, Tennessee",
|
||||
},
|
||||
{
|
||||
code: "SC",
|
||||
label: "Southern / South Central",
|
||||
states: ["AR", "LA", "NM", "OK"],
|
||||
description: "Arkansas, Louisiana, New Mexico, Oklahoma",
|
||||
},
|
||||
{
|
||||
code: "TX",
|
||||
label: "Texas",
|
||||
states: ["TX"],
|
||||
description: "Texas",
|
||||
},
|
||||
{
|
||||
code: "MW",
|
||||
label: "Midwest",
|
||||
states: ["IL", "IN", "MI", "OH", "WI"],
|
||||
description: "Illinois, Indiana, Michigan, Ohio, Wisconsin",
|
||||
},
|
||||
{
|
||||
code: "IA",
|
||||
label: "Iowa / Plains",
|
||||
states: ["IA", "KS", "MN", "MO", "ND", "NE", "SD"],
|
||||
description: "Iowa, Kansas, Minnesota, Missouri, North Dakota, Nebraska, South Dakota",
|
||||
},
|
||||
{
|
||||
code: "RM",
|
||||
label: "Rocky Mountain",
|
||||
states: ["CO", "ID", "MT", "UT", "WY"],
|
||||
description: "Colorado, Idaho, Montana, Utah, Wyoming",
|
||||
},
|
||||
{
|
||||
code: "NW",
|
||||
label: "Northwest",
|
||||
states: ["AK", "OR", "WA"],
|
||||
description: "Alaska, Oregon, Washington",
|
||||
},
|
||||
{
|
||||
code: "WC",
|
||||
label: "West Coast",
|
||||
states: ["AZ", "CA", "HI", "NV"],
|
||||
description: "Arizona, California, Hawaii, Nevada",
|
||||
},
|
||||
];
|
||||
|
||||
export const LNPA_REGION_BY_CODE: Record<string, LnpaRegion> = Object.fromEntries(
|
||||
LNPA_REGIONS.map((r) => [r.code, r]),
|
||||
);
|
||||
|
||||
// Given a state postal code, return the LNPA region that contains it.
|
||||
export function stateToRegion(state: string): string | null {
|
||||
const upper = state.toUpperCase();
|
||||
for (const r of LNPA_REGIONS) {
|
||||
if (r.states.includes(upper)) return r.code;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Convert a state → revenue map (e.g., from CDR billing state distribution)
|
||||
// into a region → percentage map. Used by the "Paste from billing
|
||||
// distribution" helper in LNPARegionStep.
|
||||
export function stateDistributionToRegionPct(
|
||||
stateRevenue: Record<string, number>,
|
||||
): Record<string, number> {
|
||||
const regionTotals: Record<string, number> = {};
|
||||
let grandTotal = 0;
|
||||
for (const [state, revenue] of Object.entries(stateRevenue)) {
|
||||
const region = stateToRegion(state);
|
||||
if (!region) continue;
|
||||
regionTotals[region] = (regionTotals[region] || 0) + revenue;
|
||||
grandTotal += revenue;
|
||||
}
|
||||
if (grandTotal === 0) return {};
|
||||
const regionPct: Record<string, number> = {};
|
||||
for (const r of LNPA_REGIONS) {
|
||||
regionPct[r.code] = Math.round((regionTotals[r.code] || 0) / grandTotal * 10000) / 100;
|
||||
}
|
||||
return regionPct;
|
||||
}
|
||||
79
site/src/lib/safe_harbor_recommender.ts
Normal file
79
site/src/lib/safe_harbor_recommender.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// Safe harbor recommender — client-side wrapper around
|
||||
// GET /api/v1/fcc/safe-harbor-recommendation.
|
||||
//
|
||||
// Consumed by RevenueStep to display a contextual recommendation next
|
||||
// to the method dropdown. The server does the actual comparison against
|
||||
// the customer's CDR traffic study — this is just a thin fetch wrapper.
|
||||
|
||||
export type Recommendation =
|
||||
| "safe_harbor_okay"
|
||||
| "use_actual_saves"
|
||||
| "use_actual_required"
|
||||
| "no_actual_data"
|
||||
| "not_allowed"
|
||||
| "no_safe_harbor_for_category";
|
||||
|
||||
export interface SafeHarborRecommendation {
|
||||
recommendation: Recommendation;
|
||||
category: string;
|
||||
year: number;
|
||||
safe_harbor_pct: number | null;
|
||||
actual_interstate_pct: number | null;
|
||||
delta_percentage_points?: number;
|
||||
estimated_usf_delta_cents?: number;
|
||||
total_revenue_cents?: number;
|
||||
study_methodology?: string | null;
|
||||
total_classified_calls?: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export async function fetchSafeHarborRecommendation(opts: {
|
||||
profile_id?: number | null;
|
||||
year: number;
|
||||
category: string;
|
||||
total_revenue_cents?: number;
|
||||
}): Promise<SafeHarborRecommendation | null> {
|
||||
const params = new URLSearchParams({
|
||||
year: String(opts.year),
|
||||
category: opts.category,
|
||||
});
|
||||
if (opts.profile_id) params.set("profile_id", String(opts.profile_id));
|
||||
if (opts.total_revenue_cents) {
|
||||
params.set("total_revenue_cents", String(opts.total_revenue_cents));
|
||||
}
|
||||
try {
|
||||
const r = await fetch(`/api/v1/fcc/safe-harbor-recommendation?${params.toString()}`);
|
||||
if (!r.ok) return null;
|
||||
return await r.json();
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** UI hint: banner color + preferred method for a recommendation. */
|
||||
export function recommendationBadge(rec: Recommendation): {
|
||||
tone: "ok" | "info" | "warn" | "danger";
|
||||
suggest: "safe_harbor" | "actual_data" | "traffic_study" | null;
|
||||
headline: string;
|
||||
} {
|
||||
switch (rec) {
|
||||
case "safe_harbor_okay":
|
||||
return { tone: "ok", suggest: "safe_harbor",
|
||||
headline: "Safe harbor is a good choice here." };
|
||||
case "use_actual_saves":
|
||||
return { tone: "info", suggest: "actual_data",
|
||||
headline: "Using actual data would save you money." };
|
||||
case "use_actual_required":
|
||||
return { tone: "warn", suggest: "traffic_study",
|
||||
headline: "Safe harbor would under-report — switch to traffic study." };
|
||||
case "no_actual_data":
|
||||
return { tone: "info", suggest: "safe_harbor",
|
||||
headline: "No traffic study — safe harbor is the sensible default." };
|
||||
case "not_allowed":
|
||||
return { tone: "danger", suggest: "traffic_study",
|
||||
headline: "Safe harbor not allowed for this category." };
|
||||
case "no_safe_harbor_for_category":
|
||||
return { tone: "danger", suggest: "actual_data",
|
||||
headline: "No safe harbor defined for this category / year." };
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue