checkout.session.completed tells you someone started a subscription, not that they still have one. That is why your customer kept Pro.
Stop deriving the plan from individual events. On every customer.subscription.created, .updated and .deleted, write the whole state you care about:
await db.from('profiles').update({
plan: sub.status === 'active' || sub.status === 'trialing' ? priceToPlan[sub.items.data[0].price.id] : 'free',
current_period_end: new Date(sub.current_period_end * 1000)
}).eq('stripe_customer_id', sub.customer)Stripe sends the full object every time, so the last event wins and out-of-order delivery stops mattering. Also store stripe_customer_id on the profile, not the session id.