Alahubs Checkout
Dedicated microservice for multi-currency payment processing—Stripe + Mercado Pago integration with dual subscription models, coupon management, idempotent transactions, and real-time Discord/Meta Ads event tracking.
2024ProductionFounder & Full-Stack ArchitectSaaSPaymentsE-commerceFintech
- NestJS
- TypeScript
- PostgreSQL
- Stripe
- Mercado Pago
- Docker
- Kubernetes
- Meta Ads
- Discord API
2500+
5k+ transactions
<500ms (payment processing)
2 payment processors + webhooks
Impact
- Microservice isolation: Separate NestJS service decoupled from core Alahubs platform enables independent payment scaling, framework upgrades, and isolated failure domains. Processes 5k+ daily transactions across 2 providers without impacting user operations.
- Dual payment processor abstraction layer: Stripe (USD subscriptions) + Mercado Pago (BRL orders) unified through single
/payments/process/stripe/ccendpoint with provider-agnostic transaction model. Idempotency keys prevent double-charging on retry; reconciliation cron detects provider discrepancies. - From Prisma ORM to native PostgreSQL: Migrated from Prisma to raw
pgdriver (20-connection pool) achieving direct query control and 15% latency reduction. DatabaseService manages connection lifecycle; parametrized queries prevent SQL injection; transaction support for atomic operations. - Four core entities and repositories: Products, Purchases, CustomerCards, Coupons modeled as TypeScript interfaces backed by repository pattern. ProductsRepository, CustomerCardRepository, CouponsRepository, PurchasesRepository encapsulate all DB access with type-safe query builders.
- Real-time event integrations: Discord webhook alerts for payment failures, successful transactions, and revenue updates streamed to sales teams. Meta Ads conversion tracking via SHA256-hashed PII (email, first/last name) sent to Ad Pixel API for lead attribution across campaigns.
Key Performance Indicators
Entities Modeled
4 (Products, Purchases, Cards, Coupons)
DB Connection Pool
20 connections
Payment Providers
2 (Stripe & Mercado Pago)
Avg Latency
<500ms
Daily Transactions
5k+
Supported Currencies
USD, BRL
Event Integrations
2 (Discord, Meta Ads)
Coupon Types
Flat, Percentage
Traction & Growth
Active Users
2500+
Paying Customers
120+
Monthly Price
$9.99 - $99.99
MRR
~$8k - $12k
Acquisition Channel: Alahubs organic growth + Meta Ads
Checkout service processes all Alahubs subscription revenue. Payment success rate >98.5%. Mercado Pago conversion rate higher in LATAM markets; Stripe dominates US/EU. CAC recovery: 3-4 months; LTV estimated $250+ based on 12-month subscription retention.
Architecture
alahubs-checkout-architecture
Key Decisions
- Native PostgreSQL driver (
pg) instead of Prisma ORM: Lower abstraction layer requires manual SQL but enables query optimization, connection pooling control, and zero-overhead raw queries. Eliminated Prisma schema drift issues and added 15% latency improvement for high-volume payment processing. - Repository pattern for data access abstraction: Extra indirection (Repository → DatabaseService → pg driver) but provides testability, maintainability, and decoupling from DB implementation. Easy to swap PostgreSQL for another database or add caching layer without touching services.
- Unified payment endpoint masking provider differences: Single
/payments/process/stripe/ccendpoint internally routes based onproviderfield. Simplifies frontend integration but requires careful error mapping—Stripe and Mercado Pago return different response shapes, status codes. - Idempotency keys for payment reliability: Every request includes
idempotencyKey(hash of user + product + amount). Stripe/Mercado Pago APIs deduplicate retries. Adds complexity to request DTOs and response caching but prevents customer double-charges on network failures. - Synchronous payment processing (no job queue yet): Payment endpoint blocks until Stripe/Mercado Pago responds (500ms+ latency). Avoids complexity of Bull/RabbitMQ but impacted by provider API slowdowns. Planned improvement: async with webhook callbacks.
Hard Problems
- Multi-currency subscription reconciliation: Stripe charges in USD with monthly subscriptions; Mercado Pago processes BRL through order API without native subscription model. Solved with
BillingTypeenum (ONE_TIME, SUBSCRIPTION) and provider-specific logic in PaymentsService. Currency conversion cached; Mercado Pago subscriptions emulated via recurring order creation + scheduled cron checks. - Type-safe parametrized queries without ORM: Raw PostgreSQL requires manual parameter binding ($1, $2, etc.). Solved by building query builder utilities and strict TypeScript interfaces for entity shapes. Repositories hide query details; services work with domain objects only.
- Coupon application across product mix: Single request can contain multiple products (one-time + subscriptions) with varying discounts. Solved with coupon repository tracking which products a coupon applies to; discount calculation sums per-product reductions before payment processing. Prevents invalid coupon combination attacks.
- PII hashing for Meta Ads without leaking data: Must send user email/name to Meta Pixel API for lead tracking, but cannot store plaintext PII. Solved with SHA256 hashing at payment request time; hashed values sent to Ad Pixel and stored in audit logs. Raw PII never persisted; can be re-hashed from request if needed.
- Connection pool exhaustion under load: High transaction volume can exhaust 20-connection pool, causing timeouts. Solved by implementing connection pooling metrics; alerting at 80% utilization; graceful rejection of non-critical requests (e.g., analytics) when pool near capacity. Pools separate read connections for reports.
Ops & Runbook
- Payment processor failover: Stripe primary, Mercado Pago fallback. If Stripe API unreachable (status !200), PaymentsService catches error and retries via Mercado Pago. Circuit breaker logic (3 consecutive failures → trip) prevents cascade; manual recovery requires
/admin/circuit-breaker/resetendpoint. - Database connection pool monitoring: DatadogAPM tracks pool utilization, connection wait times, query latencies. Alert triggered if pool utilization >80% for >5min. Response: scale horizontally (add more Checkout service pods) or investigate slow queries (enable query logging).
- Webhook reliability: Discord + Meta Ads webhooks fire asynchronously after transaction success. Failed webhooks retried 3x with exponential backoff (1s, 2s, 4s). If final retry fails, event logged to DLQ (dead-letter queue) table for manual investigation.
- Coupon/Product hot patching: ProductsRepository caches results for 1min to reduce DB hits. Updating product price or coupon terms requires cache invalidation via
/admin/cache/invalidate?entity=productsendpoint. Changes propagate to replicas within 30s. - Reconciliation cron: Nightly job (03:00 UTC) compares local transaction ledger vs Stripe invoice API + Mercado Pago orders API. Discrepancies (refund pending, charge pending, webhook missing) trigger Slack alert to payments team for investigation.
Security & Privacy
- Input validation with class-validator: DTOs (ProcessStripePaymentDto) decorated with
@IsEmail(),@IsPositive(),@Length(). Validation pipe rejecting malformed requests early prevents downstream errors and SQL injection vectors. - Parametrized SQL queries: All queries use
pgclient parameter binding ($1, $2, etc.). Dynamic query construction prevented; if need ad-hoc queries, require admin review + code change. - Coupon enumeration prevention: Coupons identified by slug (e.g., 'SUMMER20'); no sequential integer IDs. Prevents attackers brute-forcing valid coupons. Coupon creation limited to admin endpoint with role-based guards.
- Stripe API key in environment variables: Secret key never hardcoded or logged. NestJS ConfigService retrieves from
.env; secrets rotated quarterly via CI/CD secret manager integration. - Webhook signature verification: Stripe webhooks signed with
sig_*header; app verifies signature before processing. Prevents replay attacks and forged webhook events from untrusted sources.
What I'd Improve Next
- Async job queue (Bull/RabbitMQ): Replace synchronous payment processing with queue-based architecture. Payment requests enqueued immediately; workers process transactions asynchronously; webhooks update frontend in real-time.
- Payment retry logic with exponential backoff: Transient failures (network timeout, rate-limit) automatically retried without user intervention. Configurable backoff curve per provider.
- Ledger-based accounting: Immutable transaction log (payment created → processing → completed/failed). Enables full audit trail, dispute resolution, and financial reporting without relying on 3rd-party APIs alone.
- Subscription management UI: Self-service portal for customers to view invoices, manage payment methods, update subscription tier. Currently requires manual API calls.
- Multi-tenancy support: Extend architecture to support multiple organizations, each with custom payment processor credentials, coupon strategies, product catalogs. Enables white-label checkout.