│ │ ├── templates/ # Handlebars, migrated from legacy admin
│ │ └── pdf.ts # Browser Rendering API OR external service
│ ├── email/
│ │ └── mailgun.ts # invoice email send
│ └── stripe/
│ └── client.ts
├── wrangler.toml # Cron Triggers for reconciliation
└── test/
This Worker runs alongside the admin-api Worker but has a distinct responsibility. It does not serve operator UI traffic — it serves Stripe webhooks, internal metering events, and scheduled reconciliation jobs.
Confirmed from repo analysis: the mix of pricing models includes custom per-account arrangements handled as manual InvoiceItems in billing_service. These must be inventoried per-customer from the Stripe invoice history and billing_invoice DB before B.6. Each requires a migration note in the cohort runbook (see Chapter 03).
Source: Redshift impression counts, queried by billing_service via Pdo_model
Event shape:{account_id, period (YYYY-MM), usage_type (ST|RM|CV), quantity}
Idempotency key:{account_id}:{period}:{usage_type} — prevents double-counting on retry
Target: Billing Worker POST /usage → Stripe Usage Record API (Meter or legacy create_usage_record)
Frequency: Can be as-accrued (daily push from stats pipeline) or end-of-period summary — either works with metered Prices; daily push reduces cutover risk
Added:stripe (Workers-compatible), handlebars (or a Workers-compatible fork), PDF rendering lib or Cloudflare Browser Rendering binding, mailgun.js or HTTP client.
Removed (end of B.8): legacy rollup job, billing calculation code, PHP PDF renderer, any custom dunning scheduler.
Unit: Vitest for handler logic, signature verification, idempotency keys, RBAC on /admin/* endpoints.
Integration (Stripe test mode): seeded fixture customers + prices; run full invoice lifecycle end-to-end; assert rendered PDF bytes match golden snapshot (≥ tolerance for date fields).
Mail deliverability: Mailgun test mode / sandbox domain before live cutover.
Reconciliation: daily Cron Trigger compares Stripe totals to Acodei / QuickBooks totals; alerts on drift.
Cohort gate: per-cohort dual-run. A cohort is “migrated” only after one full billing cycle with zero reconciliation drift.
Rollback per cohort: cohort can be moved back to legacy rollup until B.8 retires the legacy code. After B.8, rollback is recovery-from-backup only — so B.8 should come with extra scrutiny.