When free=1 is in the URL, verify order status via API instead of
looking for a Stripe session. Checks payment_status=paid on the
server side — no security hole since the server already validated
the discount code before marking the order paid.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The checkout page was hardcoding 25% for all promo codes. Now fetches
/api/v1/discount/:code to get real discount_type (percent vs flat) and
discount_value, then displays correct amount.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Was returning 502 early instead of throwing to trigger the catch block
where the local fcc_499_filers fallback lives.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
FCC/Akamai is blocking our server IP (403). Name search now falls back
to querying the local fcc_499_filers table (20K+ records) when the
live FCC search fails.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- discount_codes.allowed_emails: when set, code only valid for listed emails
- Flat discounts now replace bundle discount (don't stack)
- $0 orders skip all payment gateways, mark paid immediately, redirect to success
- FREEDOM249: $249 flat off restricted to 4+ deficiency carriers
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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>
Templates (22 files):
- Replace "Reviewed By" with "Document prepared by" + consulting disclaimer
- Add "not a law firm / not legal advice" footer to all CPNI, CALEA, RMD docs
- Change "on behalf of" to "at the direction of" in discontinuance letter
- Reframe RMD penalty language as client acknowledgment
Bounce sync:
- New listmonk-bounce-sync.py replaces unreliable bash tail watcher
- Scans full mail.log, matches QIDs to campaign senders, inserts directly
into Listmonk DB with proper subscriber_id foreign keys
- Idempotent, runs via cron every 5 minutes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Checkout page reads ?code= or ?promo= from URL, pre-fills and locks the
promo field, shows the promo discount in the summary instead of the 15%
bundle discount
- API: when a promo code % >= bundle %, replace the bundle discount entirely
instead of stacking (e.g. MEMORIAL25 at 25% replaces the 15% bundle)
- Also checks discount code expiration in the query
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
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>
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>
- Card payment now default (was ACH — lower trust barrier for new customers)
- Removed +3% surcharge labels (reduces friction)
- Shortened authorization text to one line (was intimidating paragraph)
- Added trust signals below button: 256-bit SSL, Powered by Stripe, PCI compliant
- Added "Questions?" help box with phone + email below checkout
- Button text: "Continue to Secure Payment" with green glow shadow
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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>
Compliance batch orders now create commission ledger entries when
a discount code (agent referral) is used. Tracks total order amount,
discount applied, and links to the agent for payout processing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows specific penalty amounts for each filing type:
- RMD: $500K per violation, network disconnection
- CPNI: $239K per violation, $2.39M continuing
- 499-A: USAC Red Light blocks all FCC applications
- CALEA: $10K/day court-enforced
- Registration forfeiture for persistent non-compliance
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>
Prices removed from CTA buttons and banner cards on the checker.
Users see "Get Started" instead of dollar amounts, reducing sticker
shock before they understand the value. Prices shown on the order
page where they can see itemized services.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Check objects use status field (red/yellow/green), not severity
(critical/major/minor). Logging was always recording 0 issues.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Was only reading pdf_checks, missing structured_checks. Also skip
minor-only issues — show major/critical that match email campaign data.
This fixes the "clean" result for carriers our audit flagged as deficient.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New diagrams:
- business-flow.svg: acquisition → check → order → filing → delivery
- technical-architecture.svg: full Docker stack, data tier, external services
- order-flow.svg: detailed worker pipeline with eSign gate and handler map
Updated docs:
- infrastructure.md: DocServer, email servers, backup server sections
- architecture.md: linked to new SVGs, updated date
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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>
- erpnext/Dockerfile: builds from frappe/erpnext:v15 base with custom apps
- erpnext/build.sh: stages custom apps into build context before docker build
- Container update script now runs build.sh pre-build + extracts assets post-build
- ERPNext will auto-rebuild nightly when base image has security patches
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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>
- Added COMPLIANCE_PIPELINE with 7 stages (Received → Filing → Complete)
- Show service items as type label for compliance orders
- Fixed is_cancelled: only "Cancelled" counts, not "Closed" (ERPNext
auto-sets Closed when fully billed, which is wrong for active orders)
- Changed delivered badge text from "binder delivered" to "documents delivered"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
/Sales Invoice/NAME goes to desk (permission error for portal users).
Changed to PDF download API which respects portal user permissions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The custom_contact_email field doesn't exist on Sales Order DocType,
causing the email-based fallback query to crash. Simplified to use
Customer record lookup only (email_id match works).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Disable sidebar (was auto-linking order names as broken relative URLs)
- Remove broken portal_user_name lookup (field doesn't exist)
- Match orders by Customer record OR by custom_contact_email on Sales Order
- Merges both result sets without duplicates
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- CRTC letter now auto-emailed to secretary.general@crtc.gc.ca after eSign
- BITS admin todo updated to reference electronic + physical submission
- COLIN selectors.py: documented verification status per step
- BC config: added CRTC Secretary General email address
- plan.md: marked completed items (eSign, portal auth, CRTC email)
- go-live-todo.md: marked Compliance Calendar DocType as imported
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Compliance Deadline: created by job_server after filing completion,
tracks annual filing deadlines (RMD, CPNI, 499-A, BDC).
Compliance Calendar: used by renewal_worker for billing cycle,
tracks due dates, invoices, and recurring renewal entries.
Both were referenced in code but never created — caused 417 errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
_convert_to_pdf() now calls pdf_converter.convert_to_pdf() which tries
the Windows Word VM via MinIO first (pixel-perfect), falling back to
LibreOffice headless automatically when the VM is unavailable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- upload_file doesn't exist on MinioStorage — the method is upload()
- Return [] when pausing for eSign so job_server doesn't trigger instant delivery
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Each handler now pauses for officer signature via the eSign portal
before filing/submitting. esign_completed callback re-dispatches
through standard pipeline with client_approved=true.
- CPNI: officer signs certification before ECFS submission (perjury)
- CALEA SSI: officer signs plan before delivery
- 499-A engagement: replaced custom JWT/email with request_esign()
- Discontinuance: officer signs deactivation letter before USAC email
- job_server: injects client_approved + order_number into order_data
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reusable signing flow: service handler generates document → inserts
esign_records row → emails JWT link → client reviews PDF + signs →
API stores signature + resumes pipeline. Works for RMD, CPNI, CALEA,
499-A engagement, discontinuance, CRTC, and any future doc types.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The checklist was a manual-process artifact that listed what info the
client needed to gather. Since all data is now collected through the
intake wizard and CDR upload, the checklist is unnecessary. Removed
from the 499-A handler's prep packet and deleted the 1,326-line
generator file.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
_styles.py: Centralized typography, spacing, and formatting for all
26 DOCX generators. Calibri 9.5pt body, 1.15 line spacing, navy
headings, consistent signature blocks, page numbers, PW footer.
All generators will be migrated to use this instead of defining
their own styles.
Campaign tools:
- campaign_template.html: Styled email template for Listmonk campaigns
- populate_deficiency_list.py: Populates Listmonk with FCC deficiency data
- send_test_campaigns.py: Sends test emails with real carrier data
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sends to the monitoring bot immediately when payment is confirmed:
- Customer name and email
- Service/slug ordered
- Total amount (includes all fees: service + formation + state + addons)
- Payment method
- Order number and type
Fire-and-forget — never blocks the payment flow.
Requires TELEGRAM_BOT_TOKEN and TELEGRAM_CHAT_ID env vars on API container.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical #1 — CRTC: Fix undefined 'province' variable (canada_crtc.py:1322)
Crashes every order at Step 6 document generation. Replaced with
order_data.get("custom_incorporation_province", "BC").
Critical #2 — FCC Carrier Reg: Add State PUC state picker
The order page collected "1/few/nationwide" but API expected an array
of state codes. Added a multi-state checkbox grid that appears when
State PUC add-on is checked. Sends puc_states: ["CA","NY",...] in
service_wizard. Price updates per-state ($399 × count).
Critical #3 — Compliance: Add REQUIRED_FIELDS for fcc-499q and
fcc-499a-discontinuance. Without these, intake validation was
completely skipped — invalid data accepted silently.
High #4 — FCC Carrier Reg: Don't mark D.C. Agent complete
prematurely. Was calling _update_step() right after creating the
admin todo. Now waits for admin to confirm NW order is placed.
High #5 — Compliance: Add fcc-499q and fcc-499a-discontinuance to
REQUIRES_ENTITY_FRN set. Both require FRN for USAC filing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When any Playwright submission fails (selector not found, timeout, etc.):
1. Full-page screenshot captured and uploaded to MinIO
2. Telegram alert sent immediately with error details + screenshot link
3. Email alert to ops with same info
4. Admin todo includes screenshot MinIO path for debugging
5. Client order stays pending for manual completion
Proactive selector health check (daily 7am CT cron):
- Navigates to each portal (FCC RMD, USAC E-File, FCC CPNI/ECFS)
- Verifies all critical selectors are still present in the DOM
- If selectors are missing (UI changed): alerts via Telegram + email
BEFORE any real client order fails
- Reports which service slugs are affected
Integrated into:
- RMD filing handler (fccprod.servicenowservices.com)
- Form 499-A handler (forms.universalservice.org)
- Form 499-Q handler (already had error handling)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
job_server.py expects process() to return a list of file paths for
MinIO upload. The 499-Q and discontinuance handlers were returning
dicts like {'status':'admin_review'} which caused the job_server to
iterate dict keys as file paths -> 'File not found: status'.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When AUTO_FILING_ENABLED is explicitly set as an env var, skip the
ERPNext API call entirely. The ERPNext client hangs indefinitely
when the host is unreachable (dev workers can't reach prod ERPNext),
blocking all compliance handlers.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
499-Q Handler:
- Auto-filing toggle integration (same as 499-A)
- Playwright USAC E-File submission for quarterly form
- Revenue field filling (4 categories)
- Confirmation number capture + PDF save
- Client receives "data received" email immediately, then
"filed successfully" email with confirmation number after submission
- Falls back to admin todo if Playwright/session unavailable
Discontinuance Handler:
- Auto-emails deactivation letter to USAC (Form499@usac.org)
with DOCX attachment + entity summary in body
- CC to admin email for records
- Dev mode: redirects USAC email to admin instead
- Client confirmation email with process timeline
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Formal letter addressed to USAC Contributor Operations requesting
deactivation of a 499 Filer ID. Covers:
- Entity identification (name, Filer ID, FRN, EIN)
- Reason for deactivation + termination date
- Final 499-A status (zero-revenue included OR filed separately)
- Successor entity info (if applicable)
- Outstanding balance acknowledgment
- Related filings confirmation (RMD, CPNI, BDC)
- Officer signature block
- Entity summary box
Handler updated to:
- Generate the letter via document_gen template
- Upload DOCX to MinIO (compliance/{order_number}/)
- Reference the letter in admin todo
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both scrapers held a cursor/transaction open while doing slow HTTP
requests to FCC ServiceNow and company websites, causing
"idle in transaction" for 10+ minutes and triggering the
PostgresSlowQueries alert.
Fix: fetch all row IDs upfront, commit the read transaction
immediately, then process each row with its own short
UPDATE+COMMIT cycle. No long-lived transactions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>