MFP by Alena
Wellness e-commerce for a pilates studio with Stripe, PayPal and admin dashboard.
The Problem
Alena runs a pilates studio and had an audience - but no way to convert them online. She was selling memberships and class packages manually via PayPal links and bank transfers, chasing invoices by hand, and tracking customer access through spreadsheets.
The ask: build something that handles the full purchase flow, issues invoices automatically, restricts content by membership tier, and lets her manage customers without touching a database.
There was no off-the-shelf solution that fit the combination of requirements and budget. The choice was custom software.
What I Built
MFP by Alena is a full-stack wellness e-commerce platform built on Angular 20 SSR and Express, with TypeORM on PostgreSQL as the data layer. Two payment providers - Stripe for card payments and PayPal for bank-linked purchases - are wired in with full webhook support.
Core features:
- Membership tiers - three access levels (free preview, monthly, annual) with role-based content gating
- Stripe + PayPal checkout - unified checkout flow with provider selection, auto-redirects, and fallback handling
- Webhook processing - idempotent event handlers for payment.succeeded, subscription.cancelled, and dispute events
- Automatic invoicing - PDF invoices generated on purchase and emailed via Nodemailer
- Admin dashboard - Alena can view customers, extend memberships, issue refunds, and export data without developer involvement
- Course library - gated video content with signed URLs so content can't be hotlinked or shared
- Responsive frontend - Angular SSR so the marketing pages are crawlable and fast on first load
Architecture
Frontend: Angular 20 with SSR (Angular Universal) via Express. The marketing and landing pages are server-rendered for SEO. The member portal and course library are client-side after authentication. Tailwind v4 for styling - utility-first with the Angular component model keeps the CSS footprint small.
Backend: Express with TypeORM on PostgreSQL. The data model separates users, memberships, orders, and webhook events into clean tables. TypeORM migrations keep the schema in version control, so production updates are tracked and reversible.
Payments: Both Stripe and PayPal are integrated at the webhook level, not just the redirect level. This means cancelled subscriptions, failed charges, and refunds all update the database automatically without Alena having to do anything. The webhook handlers are idempotent - replayed events don't create duplicate records.
Deployment: Docker Compose with Caddy as the reverse proxy. A single docker-compose up on any VPS brings up Postgres, the Express API, the Angular SSR server, and Caddy with auto-renewing TLS. Alena's hosting cost is a fixed VPS fee rather than a SaaS per-seat price that scales with her customer count.
Engineering Challenges
Two payment providers, one checkout flow. Stripe and PayPal have fundamentally different SDKs and webhook schemas. I abstracted both behind a unified PaymentService interface - the frontend sends an intent, the backend routes it to the right provider, and the webhook normalization layer maps both into the same internal event schema.
Idempotent webhooks are non-negotiable. Payment providers can replay webhooks if they don't get a 200 response. Without idempotency, a network blip between receiving the event and acknowledging it can create double purchases. Every webhook handler checks if the event ID has already been processed before taking any action.
Admin UX that a non-technical user can actually use. Alena isn't a developer. The admin dashboard was iterated through three rounds of feedback sessions to make sure the core tasks - extending a membership, sending a manual invoice, checking who has access - require no explanation and no documentation.
Status
MFP by Alena is currently in active development (as of April 2026). Metrics and final results will follow after launch.



