feat(billing): add subscription and Stripe billing router

- Add stripeCustomerId column to users table
- Create Stripe client initialization (web/src/server/stripe.ts)
- Add billing service with getOrCreateCustomer, checkout/portal sessions,
  subscription management, invoice listing, and webhook event handling
- Create billing tRPC router with getSubscription, createCheckoutSession,
  createPortalSession, cancelSubscription, reactivateSubscription, listInvoices
- Add raw webhook endpoint at /api/stripe/webhook with signature verification
- Define Valibot schemas for all billing procedure inputs
- Wire billing router into root tRPC router
- Update schema tests for new column/index counts
- Write unit tests for billing service and router
This commit is contained in:
2026-05-25 16:07:00 -04:00
parent 28c33a930d
commit 40a9ef146c
14 changed files with 1006 additions and 4 deletions

View File

@@ -0,0 +1,27 @@
import type { APIEvent } from "@solidjs/start/server";
import { stripe } from "~/server/stripe";
import { handleWebhookEvent } from "~/server/services/billing.service";
export async function POST(event: APIEvent) {
const body = await event.request.text();
const signature = event.request.headers.get("stripe-signature");
if (!signature) {
return new Response("Missing stripe-signature header", { status: 400 });
}
try {
const webhookEvent = stripe.webhooks.constructEvent(
body,
signature,
process.env.STRIPE_WEBHOOK_SECRET ?? "",
);
await handleWebhookEvent(webhookEvent);
return new Response("OK", { status: 200 });
} catch (err) {
const message = err instanceof Error ? err.message : "Webhook error";
return new Response(message, { status: 400 });
}
}