Commit graph

62 commits

Author SHA1 Message Date
justin
fdbed5c097 Pre-fill email from URL on checkout and compliance checker
Email passes through the full funnel: campaign email (?email=) →
compliance checker → order page. Reduces friction for campaign
recipients who would otherwise have to type their email manually.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-22 00:49:28 -05:00
justin
868b0eeca5 Pass promo code through compliance checker to order page
- Compliance checker reads ?code= from URL, stores it, passes it
  through to the order page CTA link
- Allows email campaigns to link to checker with coupon pre-applied

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-21 15:16:27 -05:00
justin
5a07335b2f Fix: remove escaped backticks that broke compliance checker JS
The lead capture template literal used \` (escaped backtick) which
passed through Astro's compiler literally, creating an invalid JS
token that prevented the entire script from executing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 16:18:30 -05:00
justin
397e006321 Fix: remove remaining TypeScript assertions from inline script
as HTMLInputElement and as HTMLElement leaked into compiled JS,
causing SyntaxError in the lead capture handler block.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 16:06:33 -05:00
justin
b9f27e939a Fix: remove TypeScript annotation from inline script (broke compliance checker)
Record<string, string> type annotation leaked into compiled JS output,
causing SyntaxError that silently broke the entire script block.
runCheck() and all event handlers stopped working.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-20 16:02:42 -05:00
justin
54bdb9d480 Add sticky CTA bar, penalty warnings, lead capture to compliance checker
- Sticky bar fixed to bottom: "N issues found — your filing needs to be
  corrected" with "See How to Fix This" + "Call Us" buttons
- Per-filing penalty warnings on red/yellow cards: RMD removal from network,
  CPNI $239K/violation, 499-A Red Light blocks all FCC apps, CALEA $10K/day,
  CORES can't legally operate
- CTA copy changed: "Your filing is inaccurate" urgency box + "Fix My Filing"
  button with "no commitment until you pay" reassurance
- Lead capture form: "Get your compliance report emailed" for people not
  ready to buy — creates ticket + tracks lead-capture event in Umami

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 12:29:47 -05:00
justin
0ef07e25b4 Remove prices from compliance checker service selection
Hide individual service prices and total/discount row from the
compliance checker results. Users see service names + checkboxes
only. Prices revealed on the order page after clicking Get Started.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-09 11:05:24 -05:00
justin
c127cdd908 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) <noreply@anthropic.com>
2026-05-06 22:37:29 -05:00
justin
bd5193e45f Add Umami custom event tracking across all key pages
- Created /js/pw-analytics.js with conversion funnel events
- Added to Base.astro layout (all Astro pages) + 6 static HTML pages
- Events tracked: compliance-check-start, compliance-check-complete,
  order-cta-click, checkout-page-view, checkout-start, esign-opened,
  esign-submitted, campaign-click (UTM attribution), contact-form-submit
- Server-side payment-complete event from checkout webhook via Umami API
- Auto-tracks any element with data-track="event-name" attribute

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-05 05:10:13 -05:00
justin
7d783bdb39 Reprice services: à la carte ~$2,000 vs FCC Carrier Reg bundle $1,299
Individual services repriced so buying separately costs ~$2K, making
the $1,299 FCC Carrier Registration a clear 35% savings:

- CORES/FRN: $99 → $149
- Form 499 Initial: $299 → $349
- D.C. Registered Agent: $99 → $149/yr
- RMD: $219 → $249 (+ $100 FCC fee)
- CPNI: $149 → $199
- CALEA SSI: $299 → $799 (includes consulting work)
- BDC Broadband: $199 → $249
- BDC Voice: $149 → $199
- BDC Both: $299 → $349

Retired New Carrier Bundle ($1,799) — redirected to FCC Carrier
Registration ($1,299) which includes more services and the wizard.

Updated prices in: API catalog, batch order page, compliance checker CTA.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 06:23:19 -05:00
justin
16b5c2da0b Fix BDC pricing in compliance checker CTA
- BDC both (broadband+voice): $299 (was $349, now matches bdc-filing API price)
- BDC broadband-only: $199 (uses bdc_broadband slug)
- BDC voice-only: $149 (uses bdc_voice slug — was showing $199)
- Added _bdcVariant tracking so CTA uses correct slug per user answer
- Reset variant on undo

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-04 06:17:06 -05:00
justin
5e74c1dcb9 Split discontinuance CTA into two options based on revenue
When user selects "cancel registration" in the compliance checker:
- Option 1: "499-A Discontinuance (incl. zero-revenue filing)" $299
  For carriers with no revenue — includes final zero-revenue 499-A
  + deactivation letter + CORES update
- Option 2: "499-A Filing + Discontinuance" $798 ($499+$299)
  For carriers with actual revenue — full 499-A filed separately
  + deactivation process

Standalone discontinuance ($299) is for carriers already current
on filings who just want to close out.

Handler detects whether zero-revenue filing is included vs
handled by a separate full 499-A order.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-03 03:39:52 -05:00
justin
0fc318cb38 Add 499-Q intake page, 499-Q handler, and 499-A discontinuance handler
499-Q Quarterly Filing:
- Intake page at /order/fcc-499q with simplified revenue form
  (4 fields: carrier's carrier inter/intra, end-user inter/intra)
- Zero-revenue confirmation checkbox
- Handler creates admin todo with filing details + sends client email
- Registers as fcc-499q in SERVICE_HANDLERS

499-A Discontinuance:
- Handler creates admin todo with step-by-step USAC instructions
  (file zero-revenue 499-A, request account closure, confirm CPNI/RMD)
- Sends client confirmation email explaining the process
- Compliance checker CTA: when user selects "No — cancel registration"
  in the 499-A toggle, shows discontinuance option ($299) instead of
  standard filing
- Order page maps form_499a_disc to fcc-499a-discontinuance slug

Compliance checker intelligence:
- 499-A toggle tracks _499aVariant (null/zero/discontinuance)
- CTA adapts: revenue=standard 499-A, zero=zero-revenue, cancel=discontinuance
- Reset clears variant flag

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-03 02:34:18 -05:00
justin
3e04a8fc16 Add zero-revenue 499-A filing at $179
New service slug fcc-499a-zero for carriers with no telecom revenue:
- $179 instead of $499 (no revenue analysis needed)
- Minimal intake: entity, officer, filer ID, filing type only
- Skips revenue schedules (blocks 3-4), USF calculations (block 5),
  traffic study upload, and revenue workbook generation
- Fills blocks 1-2 and 6 only, all revenue lines left as zero

Compliance checker: shows both options (mutually exclusive checkboxes)
Order page: maps form_499a_zero to fcc-499a-zero slug
Handler: detects slug and skips revenue pipeline
DC Agent shown when either 499-A variant is checked

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-03 02:04:18 -05:00
justin
5dabac856d Revert quick=1, keep 60s timeout — full RMD quality checks needed
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-03 01:52:34 -05:00
justin
aef3cc7bbe Fix FCC timeout: add quick=1 param and increase timeout to 60s
FCC APIs (CORES, ServiceNow) are responding in 28-45 seconds.
The 30s frontend timeout was being hit ~50% of the time. Added
quick=1 to skip slow Playwright corp checks and increased timeout
to 60s as safety margin.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-03 01:51:55 -05:00
justin
d4af416b8e Remove 'compliance advice' from disclaimer — we do provide compliance services
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-03 01:49:09 -05:00
justin
1d4d562c0f Fix BDC CTA: add red (voice+broadband) option at higher price
When both voice and broadband are selected, BDC status is red but
the CTA had no case for red — nothing was added to the order.
Now: red = "BDC Broadband + Voice Filing" at $349 (both filings),
yellow = single filing at $199 (unchanged).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-02 09:24:53 -05:00
justin
95749b138c Fix BDC toggle in Astro page: ask voice first, then broadband
The BDC toggle was in the static HTML file (site/public/tools/)
which is overridden by the Astro page. Fixed the ACTUAL page at
site/src/pages/tools/fcc-compliance-check.astro.

Two-step flow: asks about retail voice first, then broadband.
Results: voice+broadband=red (both filings), voice-only=yellow
(BDC Voice), broadband-only=yellow (BDC Broadband), neither=green.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-02 09:20:27 -05:00
justin
fbf3b8a1ea Add terminate-only STIR/SHAKEN option across RMD pipeline
STIRShakenStep intake:
- New "Terminate only" option for carriers that only receive pre-signed
  calls and don't originate
- Contextual hints for each option explaining requirements
- Show/hide vendor and upstream fields based on selection

RMD letter generator:
- New terminate_only section explaining verification-only posture,
  citing 47 CFR § 64.6301 (signing obligation on originating provider)
- Added to needs_exhibit_a list

RMD Exhibit A generator:
- New terminate_only STIR/SHAKEN paragraph with SBC verification language
- Fixed scope paragraph: wholesale/facilities carriers no longer get
  "small provider without Class 4 switch" boilerplate
- Fixed OCN paragraph: wholesale carriers get neutral wording instead
  of "no OCN required for small retail provider"

RMD filing handler:
- Maps stir_shaken_status to rmd_option for Exhibit A generation
- Passes entity metadata (ocn, wholesale, gateway, contact) to generator
- Maps terminate_only → partial_implementation for FCC RMD form radio

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 10:59:28 -05:00
justin
118d24cc1a Rename 'IPES & ISP Registrations' to 'FCC Carrier / ISP Registration'
Updated across 61 static HTML files (nav links), bundles catalog,
service page title/description/heading, and llms.txt.
URL stays /services/telecom/ipes-isp (no redirect needed).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 08:06:47 -05:00
justin
02d2415d7a Fix escaped backtick that broke Docker Astro build
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:42:12 -05:00
justin
e1b95a20fb Show 'Intake Already Completed' screen with Revise button on revisit
When the user revisits a completed intake (intake_data_validated=true),
shows a success screen with Go to Portal and Revise buttons instead of
the blank form. Revise adds ?revise=1 to bypass the check.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:40:48 -05:00
justin
e49efb7207 Scroll to page title on step navigation instead of wizard body
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:31:34 -05:00
justin
f6f4853ab6 Scroll to top of wizard on Next/Back step navigation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:29:32 -05:00
justin
27108b9080 Change prefill notice to 'public sources' instead of 'FCC records'
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:28:40 -05:00
justin
1f87ad4554 Add pre-fill review notice on every step, fix CORES address detection
- Yellow banner on each step: "We've pre-filled this from your FCC records.
  Please review carefully and correct any information that is inaccurate."
- Only shows when accessed via token/FRN (post-payment intake)
- CORES address: filter by company name suffix (LLC/Inc/Corp) instead of
  requiring a number — addresses like "PO Box 123" now work

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:26:25 -05:00
justin
42f331101e Skip CORES address suggestion when it's just the company name
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:24:10 -05:00
justin
63f74e8486 Style officer suggestions as clickable cards with arrow hint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:22:25 -05:00
justin
834d2fc1ee Keep officer suggestions visible after selection, highlight chosen one
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:18:11 -05:00
justin
dcdc6df879 Fix CategoryStep crashing non-499-A intake pages
CategoryStep script runs on ALL pages using the Wizard component.
It tried to find #pw-wizard (its inner quiz div) and called
querySelectorAll on it — null on CPNI/RMD/etc pages, crashing the
entire script bundle. This prevented FRN auto-fill, officer
suggestions, and all other intake functionality.

Guard: if #pw-wizard doesn't exist, skip all CategoryStep logic.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:13:06 -05:00
justin
acf63eb819 Officer suggestions: use FCC data (RMD contact, CORES address) instead of entity_cache
Entity cache has no RA/officer data yet. Instead, fetch the FCC lookup
(quick mode) and offer RMD contact name + address and CORES principal
address as clickable suggestions to auto-fill Officer 1.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 01:02:18 -05:00
justin
6a0162f0a9 Simplify Officer step: remove count dropdown, officers 2+3 optional
- Removed "How many officers" dropdown — all 3 always visible
- Officers 2 and 3 marked as (optional) in legend
- Only Officer 1 validated (name, title, street, city required)
- Blank optional officers skipped in saved data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-29 00:56:45 -05:00
justin
59c2d06736 Always show corp suggestions on Officer step, check intake_data for name
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 23:37:22 -05:00
justin
159a576157 Add corporate record suggestions on Officer step, search all states
- OfficerStep searches entity_cache for matching corporations when loaded
- Shows clickable suggestions with RA name and address to auto-fill Officer 1
- Pre-fills contact_name/email/phone from entity data (helps data-only filers)
- Corp search endpoint: state param now optional (searches all states)
- Corp search returns registered_agent and principal_address fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 23:02:16 -05:00
justin
ab7a2d7dc0 Rename EIN to TIN/EIN, accept SSN format (XXX-XX-XXXX)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 18:53:24 -05:00
justin
862c06a8fd Add validation to CPNI and STIR/SHAKEN intake steps
- CPNI: requires either clean compliance checkbox OR issues section opened
- STIR/SHAKEN: requires selecting implementation status before advancing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 18:40:28 -05:00
justin
06143c51c2 Add stricter entity step validation: structure, EIN format, address required
- Entity structure (LLC/Corp/etc) is now required
- EIN must be provided and match XX-XXXXXXX format
- Full address (street, city, state, ZIP) required
- Email validation format checked

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 18:35:43 -05:00
justin
7b650179e4 Add Finish button handler + intake save API endpoint
- Wizard "Finish" button now submits intake data to the API
- New PUT /api/v1/compliance-orders/:id/intake endpoint saves intake data,
  updates entity, re-dispatches worker, and unpauses batch siblings
- Shows success screen with portal link after submission

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 18:26:20 -05:00
justin
3614284a78 Fix intake wizard: global styles for JS-created step bar, re-render after pre-fill
- Changed <style> to <style is:global> so CSS applies to dynamically
  created step chips (Astro scoped styles don't match JS-created elements)
- After async pre-fill from order data completes, re-renders the active
  step so EntityStep reads the populated state
- Removes payment step when token/order param is present

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 05:04:21 -05:00
justin
0d07b6a2d9 Skip worker intake emails for batch orders, remove payment step for paid orders
- Batch orders: checkout API already sends combined intake email, so worker
  handlers no longer send their own (was causing 2-3 duplicate emails)
- When accessed via ?token= or ?order= (post-payment), the "payment" step
  is removed from the intake wizard since payment is already complete

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 04:52:49 -05:00
justin
98a4c90e3a Pre-fill intake wizard from order data + FRN, use quick mode for FCC lookup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 04:46:09 -05:00
justin
cbfb8d6091 Add engagement authorization, remove price headers from intake pages, fix duplicate emails
- Add clickwrap authorization checkbox to fcc-compliance, state-puc, neca-ocn order pages
- Store engagement_accepted_at/ip/version in compliance_orders (migration 074)
- Add 499-A past-due/multi-year eSign engagement letter generator
- Gate 499-A handler on engagement signature for past-due/multi-year orders
- Remove price/tax/fee headers from all 19 intake pages (post-payment only)
- Fix duplicate confirmation email for compliance_batch orders
- Add USAC past-due fee negotiation research doc

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 02:50:02 -05:00
justin
6171c64b90 Fix 8 bugs: XSS, race condition, null safety, form reset, pricing
1. XSS: error messages use textContent by default, innerHTML only
   for controlled HTML (CORES link) via allowHtml flag
2. XSS: name search errors built with DOM API, not innerHTML
3. Race condition: concurrent FRN lookups cancel prior request
   via AbortController tracking
4. Null safety: DOM element guards with error logging
5. Null safety: check.detail uses || "" fallback, \n → <br>
6. Quote form: auto-resets after 3 seconds on successful submit
7. Pricing: discount uses Math.round(total*15)/100 for cent precision
8. Future-proofing: parseFloat for prices instead of parseInt

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 22:34:08 -05:00
justin
4853f67f5e Improve UX: better error messages, validation, and mobile fixes
FCC Compliance Check:
- FRN validation: shows "must be 10 digits" with digit count
- Auto-strips non-digits and pads to 10
- 30-second timeout with friendly message
- "Not found in any FCC database" with link to CORES
- Network error guidance
- FRN display uses overflow-wrap for mobile
- Error box uses innerHTML for clickable links

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 22:25:47 -05:00
justin
783eeeb645 Remove standalone Astro portal page — compliance orders now in Frappe
Compliance orders portal page moved to ERPNext/Frappe at:
portal.performancewest.net/compliance-orders

Includes USAC delegation confirmation via Frappe API.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 21:47:48 -05:00
justin
438d3a6e2e Add customer portal orders page + my-orders API
- GET /api/v1/compliance-orders/my-orders?email= returns all orders
  grouped by batch, with USAC delegation status
- /account/orders page shows order history with:
  - Entity name, FRN, batch ID, date, payment status
  - Itemized services with pricing
  - USAC delegation callout with confirmation button
  - Auth-gated (requires login)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 21:27:10 -05:00
justin
1a27fd7913 Rework 499-A questions into two-step flow
Step 1: "Did ENTITY provide and bill for telecom services?"
  - Yes → red, filing required for each missed year
  - No → Step 2 follow-up

Step 2: "Does ENTITY plan to provide telecom services going forward?"
  - Yes, keep active → yellow, zero-revenue 499-A filings needed
  - No, cancel → yellow, catch-up filings + USAC cancellation

Fixes: white-on-red button visibility, removes confusing 3-way
choice, uses inline styles for button colors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 20:52:03 -05:00
justin
edf81765ac 499-A question: "provide and bill" instead of just "bill"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-27 20:47:42 -05:00
justin
d6780dd9f9 Use entity name in ALL CAPS for compliance questions
RMD: "Does WYOMING FIBER PHONE INC provide any voice services?"
499-A: "Did WYOMING FIBER PHONE INC bill customers for voice or data..."
BDC: "Does WYOMING FIBER PHONE INC provide broadband internet access?"

Also applies entity name to response messages.

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