feat(sprint-6): Phase 3 — Stripe integration (SEPA + PayPal + Card)
Deploy to Production / test (push) Has been cancelled
Deploy to Production / deploy (push) Has been cancelled

- V7 migration: subscriptions table with plan tiers
- Subscription entity + PlanTier/SubscriptionStatus enums
- StripeService: customer creation, checkout, portal, webhook handling
- SubscriptionController: /api/v1/billing endpoints
- Webhook handler: invoice.paid, payment_failed, subscription.deleted/updated
- Plan enforcement: member limit interceptor, trial expiry check
- Frontend: /settings/billing page (plan card, usage, upgrade, portal link)
- Trial expired banner on all admin pages
- React Query hooks (useSubscriptionQuery, checkout/portal mutations)
- Stripe Java SDK 28.2.0
- Full i18n (de/en) for billing namespace
This commit is contained in:
Patrick Plate
2026-06-12 22:31:03 +02:00
parent 3232d2f7fd
commit 61e481b37b
17 changed files with 892 additions and 0 deletions
@@ -0,0 +1,50 @@
import { useMutation, useQuery } from "@tanstack/react-query"
import { apiClient } from "@/lib/api-client"
export interface SubscriptionData {
planTier: string
status: string
memberLimit: number
trialEndsAt: string | null
currentPeriodStart: string | null
currentPeriodEnd: string | null
canceledAt: string | null
hasStripeSubscription: boolean
}
export function useSubscriptionQuery() {
return useQuery({
queryKey: ["billing", "subscription"],
queryFn: () => apiClient<SubscriptionData>("/billing/subscription"),
})
}
export function useCreateCheckoutMutation() {
return useMutation({
mutationFn: async (planTier: string) => {
const data = await apiClient<{ url: string }>("/billing/checkout", {
method: "POST",
body: { planTier },
})
return data
},
onSuccess: (data) => {
window.location.href = data.url
},
})
}
export function useCreatePortalMutation() {
return useMutation({
mutationFn: async () => {
const data = await apiClient<{ url: string }>("/billing/portal", {
method: "POST",
})
return data
},
onSuccess: (data) => {
window.location.href = data.url
},
})
}