Actions
Bug #1623
openStripe Subscription Data Integrity Fix
Start date:
04/13/2026
Due date:
% Done:
100%
Estimated time:
Description
The Problem
Status Overwrite Bug: The backend was blindly updating user subscription status based on individual webhook events. If a user had one Active sub and one failed/expired attempt, the failed attempt would mark the user as "Expired" even though they were still paying for the other sub.
Ghost Sub Loop: The frontend was triggering new subscriptions every time the widget opened, creating a massive amount of incomplete records in Stripe and the DB.
Detection Hole: The duplicate check ignored past_due and incomplete statuses, allow multiple subscriptions for the same user.
The Solution
-
Master Status Ranking Engine
Created refreshUserSubscriptionStatus(userId) in StripeService.js.
Ranking System: Prioritizes active > trialing > past_due > paused > incomplete > expired.
Even if a user has many expired attempts, a single active subscription will keep their status as Active.
Automatically syncs the furthest expiry date (subscription_expires_at) from all valid plans. -
Subscription Reuse Logic
Modified createSubscription to look for existing incomplete records for the same price.
Instead of creating a new Stripe sub, the backend now re-uses the old one and returns its client_secret. This stops the "Ghost Sub" creation loop. -
Expanded Duplicate Blocking
The system now detects past_due and incomplete plans before allowing a new purchase.
Improved UX: Users with an overdue balance are blocked with a friendly message: "You already have a subscription. Please update your payment method or check your billing status to resume access."
Actions