Commit graph

10 commits

Author SHA1 Message Date
justin
d8e3e40dda healthcare emails: remove prices, fix click tracking, de-risk claims
Diagnosing zero healthcare sales (11k sent, 5479 opens, 0 clicks, 0 orders).
Root cause of clicks=0: Listmonk only registers a link for tracking when the
href ends with the literal @TrackLink marker; all 10 hc templates lacked it
(trucking/CRTC have it). So the entire funnel was unmeasurable below 'open'.

Changes:
- Click tracking: append @TrackLink + UTM to every /order/ CTA across all 10
  templates (external gov self-verify links left untracked on purpose).
- Remove all service prices from emails (99/49/49/99yr/9mo). Price is
  now revealed on the order page after value is established; catalog
  (api/src/service-catalog.ts) stays source of truth. Kept the 0,000 OIG
  penalty stat (regulatory fact, not our price). Added a neutral 'flat fee shown
  up front' reassurance block where the fee table used to be.
- Compliance/honesty: the nppes_outdated email asserted a per-record
  'FLAGGED OUT OF DATE / detected' status, but its selector only checks
  deliverability and the data has no NPPES last-updated field -> unsubstantiated
  for every recipient. Reframed to a generally-true periodic-attestation message
  ('PERIODIC REVIEW REQUIRED', 'most practices drift out of date'). Same hedging
  applied to npi_reactivation ('may be deactivated ... confirm on official
  sources'). Substantiated reval 'past due' claims (backed by the public CMS
  Revalidation list) were kept.
- Fixed stale $299 OIG metadata in build script -> $79/mo (reference only).

Docs: docs/healthcare-competitive-pricing.md (benchmark research) and
docs/healthcare-email-compliance-review.md (CAN-SPAM / FTC / impersonation pass;
flags SOC2/HIPAA/PCI badge claims for owner confirmation).

Verified headless: all 10 render with 0 JS errors, exactly 1 tracked CTA each,
no price leaks.
2026-06-20 09:37:02 -05:00
justin
cf021e2f91 feat(healthcare): OIG/SAM exclusion screening as $79/mo Stripe Subscription
Convert OIG/SAM from one-time $299/yr to recurring $79/month (card+ACH only) -
the first real recurring-billing product in the system. Exclusion screening is
a *monthly* federal obligation, so recurring monitoring fits the requirement and
is the biggest valuation lever (vs a one-time annual run).

Catalog (single source of truth):
- service-catalog.ts: add billing_interval + allowed_methods to ComplianceService;
  oig-sam-screening -> 7900c, billing_interval:"month", allowed_methods:[card,ach],
  name "(Monthly Monitoring)".
- gen-service-catalog.py + check-service-catalog-drift.py: carry/guard the two new
  fields; regenerate site catalog.

Checkout (api/src/routes/checkout.ts):
- mode:"subscription" with recurring price_data when billing_interval is set;
  surcharge absorbed for recurring (clean $79/mo); server-side METHOD_NOT_ALLOWED
  re-validation against allowed_methods.
- ensureColumns + migration 100: compliance_orders.stripe_subscription_id,
  bundle_upsell_sent_at (+ subscription index).

Webhooks (api/src/routes/webhooks.ts):
- record stripe_subscription_id on checkout.session.completed (subscription mode).
- invoice.paid (subscription_cycle only) -> re-dispatch screening for the cycle;
  invoice.payment_failed -> admin alert + first-failure customer nudge;
  customer.subscription.deleted -> mark order cancelled. (API 2026-03-25 moved the
  subscription link to invoice.parent.subscription_details.subscription.)

Fulfillment:
- job_server.py: pass recurring_cycle/invoice_id into the order.
- npi_provider.py: OIG handler labels renewal cycles "[Monthly cycle]" + re-screen
  note; bundle action runs only the FIRST screening + flags the $79/mo upsell.

Bundle land-and-expand:
- Provider Compliance Bundle now includes only the first OIG/SAM screening (was
  giving away $948/yr of monitoring inside an $899 bundle).
- new worker scripts/workers/bundle_upsell.py (+ pw-bundle-upsell timer): ~3 weeks
  after a paid bundle, emails the customer to continue $79/mo monitoring; dedup via
  bundle_upsell_sent_at; skips customers who already have an OIG/SAM order.

Surfaces updated to $79/mo: PaymentStep (filters methods, "Billed every month,
cancel anytime"), order pages, healthcare index, npi-compliance-check tool (also
fixed stale $699 bundle drift -> $899), hc_oig_screening + hc_compliance_bundle
emails.

Docs: billing.md gains a "Stripe-native Subscriptions" section + a reality-check
banner (Adyen/ERPNext-gateway model documented there is NOT live; Stripe is the
real rail). Fixed run-migrations.yml container name bug
(performancewest-postgres-1 -> performancewest-api-postgres-1, overridable).

Tests: api/tests/recurring-subscription.test.ts (28 assertions) covers catalog
gating, method validation, surcharge suppression, recurring line-item build,
invoiceSubscriptionId extraction, renewal-cycle gating. tsc clean; site build
clean; catalog drift OK.

Manual deploy step: enable invoice.paid, invoice.payment_failed,
customer.subscription.deleted on the Stripe webhook endpoint.
2026-06-18 07:54:38 -05:00
justin
bb736f6c01 hc: add founder guarantee card to all other HC templates (npi/nppes/oig/bundle)
Per your call: add the same personal founder card (headshot linked to /about,
service-neutral satisfaction-guarantee quote, signature, title) to the four
remaining HC templates for a consistent trust signal across all healthcare
outreach. Kept the factually-direct subjects where the situation IS past-due/
deactivated (npi_reactivation) -- only the framing softens, not the facts.
All HC templates now use the v2 signature.
2026-06-13 21:31:01 -05:00
justin
16f3dd67e4 can-spam: add full street address to ALL email templates + wire HC personal variant
CAN-SPAM requires a valid physical postal address in every commercial email.
All 8 HC campaign templates and the FCC campaign_template.html only had
'Cheyenne, WY' (no street) -- added the full
'525 Randall Ave Ste 100-1195, Cheyenne, WY 82001' to match the (already-correct)
trucking templates. Audited every Listmonk source/sent campaign + wrapper
templates: all active sends carry address + unsubscribe.

Also: revalidation segments now use hc_revalidation_personal.html with subject
'Let's make sure your Medicare revalidation is handled in time'.
2026-06-13 21:27:16 -05:00
justin
c79a7715e1 fix(hc): bugs found in self-audit of the new refresh + warmup + templates
Refresh (hc_data_refresh.py):
- CRITICAL: drop optout_ending from REFRESHED_FIELDS -- the refresh never
  computes it, so propagating it blanked the channel CSVs and would starve the
  compliance_bundle segment (whose selector IS optout_ending).
- MAJOR: only rewrite leie_excluded when OIG was actually pulled (guard was
  'not skip_oig OR not skip_sam', so a --skip-oig run blanked all exclusion
  flags). Also write 'Y' (matching the original list builder) not '1'.
- Use 'no_reval_flag' (the original vocabulary) instead of 'not_on_list' when an
  NPI drops off the reval list, and clear reval_due_date too.
- Throttle politeness: move time.sleep(0.05) above the early-continue paths so
  EVERY CMS request is spaced, not just the minority that are on the list.
- Guard blank-NPI rows (leave their status untouched instead of mislabeling).
- Master write preserves any columns beyond HEADER (no silent column drop).

Warmup cron (build_healthcare_campaigns_cron.py):
- Fix the daily-slice split: it summed to less than the budget (dropped ~2/day)
  and could OVERSHOOT on tiny totals (each 'other' floored to >=1). Now uses
  divmod for an even remainder and reclaims rounding onto the lead, so
  sum(per_seg) == total_slice exactly for every input (verified 0,1,2,7,100,300).

Templates: the non-revalidation emails rendered {{ .Subscriber.Attribs.detail }}
(a reval due date) under a 'Practice'/'Status'/'Record' label -- a wrong/
confusing personalization on a live send (esp. OIG, selector 'any'). All four
now show the practice name; 'detail' is retired from rendering (revalidation
uses reval_due_date/days_overdue directly).
2026-06-08 03:23:47 -05:00
justin
aa195e6c18 hc emails: add source-grounded 'verify it yourself' trust blocks to all programs
The revalidation email had a 'check the official CMS record yourself' proof
block (the strongest trust signal), but the other four healthcare programs had
none -- just the generic SOC2/guarantee footer. Each now points the provider to
the actual public government source that backs its claim:

- NPPES outdated -> 'Look up my NPI on NPPES' (npiregistry.cms.hhs.gov, fully
  public; shows the exact address/taxonomy/contact payers and CMS see).
- OIG screening -> 'Search OIG LEIE / Search SAM.gov' (exclusions.oig.hhs.gov +
  sam.gov), with an honest note that a one-time self-search isn't the documented
  recurring screening CMS expects.
- Reactivation (deactivated) -> deactivation isn't a single public dataset, so
  this is framed honestly: most deactivations follow a lapsed revalidation
  (public CMS Revalidation list) and show in NPPES; also 'are your claims
  paying?' as a self-check. No fabricated 'deactivated record' card.
- Compliance bundle -> all four official sources (CMS Revalidation, NPPES, OIG
  LEIE, SAM.gov) it monitors year-round.

All four government URLs verified reachable (200/302). No paper/mail filing
mechanics revealed; CMS/NPPES/OIG/SAM public names are fine and signal
expertise.
2026-06-08 02:43:02 -05:00
justin
022407e807 email(healthcare): add not-affiliated disclaimer to all HC campaigns + scrub mechanics
- Add the 'Performance West is an independent compliance firm, not affiliated
  with CMS or Medicare' footer disclaimer to the 4 remaining HC emails
  (reactivation, NPPES, OIG/SAM, bundle), matching the revalidation email.
  OIG email also names the OIG and SAM.gov it references.
- Scrub client-facing mechanics: drop the CMS-855 form number from the
  reactivation CTA and the PECOS system name from the revalidation CTA; clean
  the same out of source comments.
2026-06-08 00:06:29 -05:00
justin
53ec011198 email trust signals: add data-safety + guarantee + social-proof strip to HC, telecom (campaign_template), and trucking (6 source + active campaigns via injector). Vertical accents: teal/blue/orange 2026-06-06 04:13:16 -05:00
justin
29c7a421e9 healthcare email: teal gradient header (matches site hero) + standalone CSV MX/SMTP verifier (binds .72 non-sending IP); gitignore PII warmup lists 2026-06-06 03:39:19 -05:00
justin
3859557506 healthcare: +$200 across all 6 provider services; add segmented marketing email builder (5 compliance-problem campaigns) + rendered HTML 2026-06-06 02:33:46 -05:00