Uh oh!
There was an error while loading. Please reload this page.
Add Stripe subscription integration for paid storage upgrades - #5810
Conversation
e42f75e to
d8ea559Comparemarcellamaki
commented
Apr 2, 2026
d8ea559 to
bee8581Compare
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)
2b57f0c to
7994fd8Compare7994fd8 to
b2344cbCompareUsers 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>
b2344cb to
363d10dCompare
marcellamaki
left a comment
There was a problem hiding this comment.
Approved, and infra is ready with the relevant updates per slack discussion
Uh oh!
There was an error while loading. Please reload this page.




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.