Shipping Payments and Messaging in a TypeScript Monorepo
Payments and notifications are where "it works on my machine" dies in production. Here's how we structured these subsystems at ClassTablet.
Payments & billing
Billing workflows are tenant-scoped: each organization has its own branding, pricing context, and parent payment views. Long-running billing tasks run through BullMQ so HTTP requests stay fast and failures can retry with backoff.
Messaging architecture
- Web push: handled on the API with the web-push library
- Email, WhatsApp, SMS: outbound adapters behind a unified notification service
- Localization: multi-locale copy stored alongside templates
Observability
Sentry traces errors across the monorepo. Structured logs include tenant IDs (never raw PII) so we can diagnose failures per organization without exposing sensitive data in log aggregators.
Takeaway
Queue everything that talks to a third party. Your users' submit buttons will thank you.