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,21 @@
-- V7: Stripe subscription management
CREATE TABLE IF NOT EXISTS subscriptions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
club_id UUID NOT NULL REFERENCES clubs(id),
stripe_customer_id VARCHAR(255) NOT NULL,
stripe_subscription_id VARCHAR(255),
plan_tier VARCHAR(20) NOT NULL DEFAULT 'TRIAL',
member_limit INTEGER NOT NULL DEFAULT 500,
trial_ends_at TIMESTAMP WITH TIME ZONE,
current_period_start TIMESTAMP WITH TIME ZONE,
current_period_end TIMESTAMP WITH TIME ZONE,
status VARCHAR(20) NOT NULL DEFAULT 'TRIALING',
canceled_at TIMESTAMP WITH TIME ZONE,
tenant_id UUID NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_subscriptions_club ON subscriptions(club_id);
CREATE INDEX idx_subscriptions_stripe_customer ON subscriptions(stripe_customer_id);
CREATE INDEX idx_subscriptions_status ON subscriptions(status);