Add Stripe subscription integration for paid storage upgrades#5810
Add Stripe subscription integration for paid storage upgrades#5810rtibbles wants to merge 1 commit intolearningequality:unstablefrom
Conversation
e42f75e to
d8ea559
Compare
Users can purchase additional storage (1-50 GB at $15/GB/year) via Stripe Checkout, manage subscriptions through the Customer Portal, and see their subscription status on the Storage settings page. Environment-gated configuration ensures non-production deployments use Stripe test/sandbox keys automatically. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
d8ea559 to
bee8581
Compare
marcellamaki
left a comment
There was a problem hiding this comment.
blocking (and impactful non-blocking) feedback resolved, and code is very readable/standard. i did not go over it with a super fine toothed comb but overall: readable, uses KComponents not vuetify, composables -- all good.
| fetchSubscriptionStatus, | ||
| createCheckoutSession, | ||
| createPortalSession, | ||
| } = useSubscription(); |
| </KButton> | ||
| </div> | ||
|
|
||
| <Banner |
There was a problem hiding this comment.
Would you please use non-Vuetify replacement StudioBanner?
Note that there will be a visual difference compared to Banner ~ it's intentional.
| :style="{ backgroundColor: $themePalette.grey.v_100 }" | ||
| > | ||
| <div | ||
| v-if="loading" |
There was a problem hiding this comment.
For new loaders, could you use v-if="show('loader', loading, 400)" to align with https://design-system.learningequality.org/loaders#minimum-visible-time?
(old loaders in Studio don't have this, and some newer loaders use wrong value, but 400 is closest to the expected experience ~ we recently fine-tuned with Tomiwa)
There was a problem hiding this comment.
Here's an example which also has transition applied https://design-system.learningequality.org/usekshow#example
| @click="handleUpgradeClick" | ||
| > | ||
| <span class="upgrade-btn-content"> | ||
| <KCircularLoader |
There was a problem hiding this comment.
https://github.com/learningequality/studio/pull/5810/changes#r3038962811
(not 100% sure, if I recall there may animation glitch if show applied directly on the loader component, so if you observe that ~ disableDefaultTransition on KCircularLoader should help, or maybe also applying show on the wrapping div / span)




Summary
Adds Stripe subscription integration allowing users to purchase additional storage (1–50 GB at $15/GB/year). Uses Stripe Checkout Sessions for payment, Customer Portal for self-service management, and webhooks for lifecycle sync. Storage is additive to admin-granted quotas.
Environment-gated configuration (
BRANCH_ENVIRONMENT) ensures non-production deployments automatically use Stripe sandbox keys — no risk of processing real payments on QA/staging.Includes documentation at
docs/stripe_integration.mdcovering setup, Stripe Dashboard configuration, and local dev workflow withmake devserver-stripe.stripe-upgrade-demo.webm
Reviewer guidance
Testing
STRIPE_TEST_SECRET_KEY,STRIPE_TEST_PRICE_IDenv varsmake devserver-stripeto start the dev server with webhook forwarding4242 4242 4242 4242Risky areas
contentcuration/views/subscription.py— webhook handlers: verify idempotency and thatcustomer.subscription.updatedcorrectly syncs quantity after checkoutcontentcuration/migrations/0166_add_usersubscription.py— new table, review schemacontentcuration/frontend/shared/mixins.js—bytesForHumansnow shows 1 decimal for GB, 2 for TB instead of integers; affects all file size displays at GB+ scaleAI usage
Used Claude Code throughout. Reviewed Stripe best practices via their published AI skill, iterated on the implementation against those guidelines, and verified the UI in-browser using Playwright. Manually tested the full checkout, cancellation, and webhook flows against a Stripe sandbox.