Polar's subscription.canceled signals a scheduled cancellation (access
continues until the period end), while subscription.revoked is the event
that should actually remove access. The webhook handler was downgrading
immediately on cancel and never handled revoke, so a Pro user dropped to
Free the moment they canceled instead of at their real period end.
- cancelSubscription now records cancelAtPeriodEnd + currentPeriodEnd and
keeps the subscription active instead of deactivating it
- add revokeSubscription for the real downgrade, wired to the
subscription.revoked event in the Polar webhook handler
- add controller + service specs covering event dispatch and the
record-vs-downgrade DB semantics
- add jest moduleNameMapper so specs can resolve src/* path aliases
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>