fix: rework stripe webhooks into idempotent subscription sync (#2977)

Replace per-event webhook handlers with a single sync function that
fetches the current state from Stripe and converges the local
subscription, claim, and organisation type.

- Create organisations upfront before checkout, restricted as
  "pending payment" until the first payment syncs
- Add rate-limited subscription sync route, triggered on checkout
  success so the UI doesn't wait on webhooks
- Surface pending payment state in banner, billing table, and limits
This commit is contained in:
Lucas Smith
2026-06-12 16:01:03 +10:00
committed by GitHub
parent b84b87cea6
commit 3887aa67c8
19 changed files with 667 additions and 664 deletions
+10
View File
@@ -1,5 +1,6 @@
import { IS_BILLING_ENABLED } from '@documenso/lib/constants/app';
import { INTERNAL_CLAIM_ID } from '@documenso/lib/types/subscription';
import { isOrganisationPendingPayment } from '@documenso/lib/utils/billing';
import { prisma } from '@documenso/prisma';
import { DocumentSource, EnvelopeType, SubscriptionStatus } from '@prisma/client';
import { DateTime } from 'luxon';
@@ -69,6 +70,15 @@ export const getServerLimits = async ({ userId, teamId }: GetServerLimitsOptions
};
}
// Early return for organisations created ahead of a paid checkout that are still awaiting payment.
if (isOrganisationPendingPayment(organisation)) {
return {
quota: INACTIVE_PLAN_LIMITS,
remaining: INACTIVE_PLAN_LIMITS,
maximumEnvelopeItemCount,
};
}
// Allow unlimited documents for users with an unlimited documents claim.
// This also allows "free" claim users without subscriptions if they have this flag.
if (organisation.organisationClaim.flags.unlimitedDocuments) {