next_refill_at was set on UserHearts but never read or recalculated,
so a heart lost to zero never came back. UserHearts.apply_regen() now
catches up missed 24h intervals on read/deduct, and lose_heart() starts
the timer only when it isn't already running.
Any user with an active (non-expired) subscription now skips heart
deduction entirely, regardless of which plan they're on — good enough
for now until per-plan perks are needed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
subscription/views.py
- PlansListView: served from cache (subscription:plans:v1, 1h TTL);
plans change ~never and the list is read on every subscription screen.
subscription/receivers.py (new)
- post_save/post_delete on Plan -> cache.delete(PLANS_CACHE_KEY).
subscription/apps.py
- SubscriptionConfig.ready() imports receivers.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>