feat: add subscriptions service layer and webhook endpoint - M2 (refs #55)

- Implement SubscriptionsService with getSubscription, createSubscription,
  upgradeSubscription, cancelSubscription, reactivateSubscription
- Add handleWebhookEvent for Stripe webhook processing with idempotency
- Handle 5 webhook events: subscription.created/updated/deleted, invoice.payment_succeeded/failed
- Auto-sync tier changes to user_profiles.subscription_tier
- Add public webhook endpoint POST /api/webhooks/stripe (signature verified)
- Implement 30-day grace period on payment failure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Eric Gullickson
2026-01-18 16:10:20 -06:00
parent 88b820b1c3
commit 7a0c09b83f
5 changed files with 745 additions and 5 deletions

View File

@@ -0,0 +1,24 @@
/**
* @ai-summary Webhook routes for Stripe events
* @ai-context PUBLIC endpoint - no JWT auth, authenticated via Stripe signature
*/
import { FastifyPluginAsync } from 'fastify';
import { WebhooksController } from './webhooks.controller';
export const webhooksRoutes: FastifyPluginAsync = async (fastify) => {
const controller = new WebhooksController();
// POST /api/webhooks/stripe - PUBLIC endpoint (no JWT auth)
// Stripe authenticates via webhook signature verification
// IMPORTANT: rawBody MUST be enabled for signature verification to work
fastify.post(
'/webhooks/stripe',
{
config: {
rawBody: true, // Enable raw body for Stripe signature verification
},
},
controller.handleStripeWebhook.bind(controller)
);
};