Technical specification for CHRONOS Premium: architecture, Stripe webhook logic, subscription sync job, role system and system components.
[User] ↓ clicks Upgrade [Billing UI Modal] ↓ Stripe Checkout [Stripe Checkout Session] ↓ payment success [Stripe Webhook] → checkout.session.completed → customer.subscription.created → customer.subscription.updated → customer.subscription.deleted ↓ [Backend] → set user.role = premium → store subscription_id → store customer_id ↓ [App] → unlock premium features → remove ads → enable AI planners → enable unlimited presets
POST /functions/stripeWebhook
verifyStripeSignature(request)
switch (event.type) {
case "checkout.session.completed":
userId = event.data.object.client_reference_id
customerId = event.data.object.customer
subscriptionId = event.data.object.subscription
updateUser(userId, {
stripe_customer_id: customerId,
stripe_subscription_id: subscriptionId,
role: "premium"
})
case "customer.subscription.updated":
status = event.data.object.status
user = findUserBySubscription(event.data.object.id)
if (status == "active") user.role = "premium"
else if (status == "past_due") user.role = "premium" // grace period
else if (status == "canceled") user.role = "free"
save(user)
case "customer.subscription.deleted":
user = findUserBySubscription(event.data.object.id)
user.role = "free"
save(user)
}Scheduled task (cron): runs every 12 hours
for each user with stripe_subscription_id:
subscription = stripe.subscriptions.retrieve(id)
if subscription.status != "active":
downgrade user.role to "free"user.role = "free" | "premium" // anonymous visitors are "free"
const { user } = useAuth();
const isPremium = user?.role === "premium";
// Premium-only feature
isPremium
? renderFeature()
: renderLocked(() => openUpgradeModal())