When intake loads from ?order=CO-xxx, the FRN is in the order's
intake_data, not the URL. Now checks state.intake_data.frn and
state.entity.frn as fallback sources for auto-fill.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When the intake page is loaded with ?order=CO-xxx (from the
confirmation email), fetch the order and pre-fill customer name,
email, and FRN from the order record. Previously only worked
with JWT token-based links.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- "Email address (yours)" → "Your email address" with helper text
- "Your name" → "Your first and last name" with placeholder
- "Carrier legal name" → "Carrier entity legal name" with examples
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When discount brings total to zero, hide the payment method selector
and change button from "Continue to Secure Payment" to "Place Free Order".
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Was looking for .svc-cb:checked but checkboxes use
input[data-slug]:checked. Discount display never updated after
promo info loaded.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The confirmation email now includes a prominent blue box with
direct links to the intake form for each ordered service. Subject
changed to "Action Required" to prompt the customer to complete it.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Free orders bypass Stripe, so the Stripe webhook never fires and the
intake/confirmation email never gets sent. Now trigger
sendComplianceIntakeEmail directly in the $0 bypass flow.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Static inline script that verifies $0 orders via API and shows
"Order Confirmed" state. Re-asserts success state on delays to
override the Astro hoisted JS which would otherwise show error
(since there's no Stripe session_id for free orders).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The /api/v1/discount/:code endpoint now checks allowed_emails when
an email is provided. If the email isn't in the allowed list, returns
valid:false so the frontend doesn't show a fake discount. The promo
field is cleared and unlocked if validation fails.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When create-session is called for an order that's already paid (e.g.
free order with page refresh, duplicate submit, or browser retry),
return a success redirect instead of 404. Prevents confusing
"Payment Not Confirmed" errors on the success page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>