All transactional/worker senders built multipart/alternative (or mixed)
messages with ONLY an HTML part. A single-part multipart/alternative is
malformed and HTML-only mail is a spam-score signal -- the same class of
deliverability bug that hurt the campaign pipeline, but on the telecom /
filing / customer-transactional path (499-Q reminders, RMD/FCC filing
review links, intake/completion/delivery emails, commissions, etc).
- worker_email.send_worker_email: auto-derive plaintext from HTML when
caller omits text= (fixes the shared helper for all current+future use)
- 16 rolled-their-own senders in scripts/workers/** + scripts/formation/
document_delivery.py: attach html_to_text(...) plaintext sibling before
the HTML part (job_server + document_delivery wrap text+html in an
alternative sub-part so PDFs still attach to the mixed root)
- api/src/email.ts: add dependency-free htmlToText() and default
sendEmail text to it (fixes checkout/webhook HTML-only sends)
Verified: all py files compile + import at runtime, api tsc passes,
htmlToText handles hrefs/lists/entities, 11 plaintext unit tests pass.
Telecom campaign 407 (Jun 8) was HTML-only + sent in the DKIM-broken
window -> 384 sent / 0 clicks (same junked-mail signature).
Portal login + forgot-password read the Postgres customers table (bcrypt), NOT
ERPNext. ensureCompliancePortalUser (the common path for Stripe/PayPal/crypto via
handlePaymentComplete) only provisioned the ERPNext customer/website-user and
never created the customers row -- so customers (notably PayPal, who reach this
path directly) had no account to log into or reset a password against. Now upserts
the customers row (no password; ON CONFLICT keeps any existing hash) with name +
company so they can register/reset and log in immediately.
Also: narrowed the placeholder-email skip from 'any synthetic@ or pipeline.com' to
exactly 'synthetic@pipeline.com' (the FMCSA-census placeholder) so real customers
on those real consumer domains aren't wrongly skipped -- which is what bit Paul
Wilson. Added cc support to sendEmail. e2e-paypal-portal-fix.mjs is the regression
test (seeds a compliance order, runs handlePaymentComplete, asserts the customers
row is created). Rescue scripts for the affected customer included.
1. Email: add a 'Problem with your order? We're here to help' support band to
the shared htmlEmail() footer, so EVERY transactional email (confirmation,
portal link, receipts) has a prominent 'Get help with your order' button
linking to /contact. Less silent frustration -> fewer chargebacks.
2. NPI order form: entering a 10-digit NPI now auto-fills provider name, practice
state, and specialty from the live NPPES lookup (same API as the free
compliance-check tool), with a 'Found: <name>' confirmation. Only fills empty
fields so it never clobbers edits.
3. NPI order form: read ?npi= from the URL so the email 'Start my revalidation'
click lands with the NPI prefilled and the rest auto-filled (was being
ignored entirely before).
4. Support FAB: add the floating help button + panel to 27 static public pages
that were missing it (order, portal, trucking, survey, upload pages), so help
is one click away everywhere.
1. CRITICAL: Add compliance_batch to stripe session tableMap —
session IDs weren't being stored for batch orders
2. CRITICAL: Fix batch orders using order_number instead of batch_id
when storing stripe_session_id
3. MAJOR: Tax deductibility note only shows for compliance orders,
not CRTC/formation/bundles
4. MAJOR: Identity verification fallback changed from localhost:4321
to performancewest.net with warning log
5. MEDIUM: Fix discount rounding — last service absorbs remainder
to prevent cent loss across batch orders
6. LOW: Validate at least one paid service in batch orders
7. Standardize support email to info@performancewest.net everywhere
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>