# Kaboot Payment Feature Implementation Plan ## Overview Add Stripe subscription payments to allow users to pay for AI access (`kaboot-ai-access`). Users get 250 AI generations per month for $5/month (or yearly equivalent). ### Pricing Model - **Monthly**: $5/month for 250 AI generations - **Yearly**: $50/year for 250 AI generations/month (save ~17%) - **Grace Period**: 1 day after failed payment before revoking access - **Refund Policy**: 7-day money-back guarantee --- ## Implementation Checklist ### Phase 1: Backend Infrastructure - [x] **1.1** Add Stripe dependency to server - `npm install stripe` in server directory - File: `server/package.json` - [x] **1.2** Add environment variables - `STRIPE_SECRET_KEY` - Stripe secret key - `STRIPE_WEBHOOK_SECRET` - Webhook signing secret - `STRIPE_PRICE_ID_MONTHLY` - Monthly price ID - `STRIPE_PRICE_ID_YEARLY` - Yearly price ID - Files: `.env.example`, `docs/PRODUCTION.md` - [x] **1.3** Database migration - Add subscription and generation tracking - Add `stripe_customer_id` to users table - Add `subscription_status` (none, active, past_due, canceled) - Add `subscription_id` for Stripe subscription ID - Add `subscription_current_period_end` for billing cycle - Add `generation_count` for current period usage - Add `generation_reset_date` for when to reset count - Create `payments` table for payment history - File: `server/src/db/schema.sql` - [x] **1.4** Create Stripe service - Initialize Stripe client - Create/retrieve customer helper - Create checkout session helper - Create customer portal session helper - File: `server/src/services/stripe.ts` - [x] **1.5** Create payments routes - `POST /api/payments/checkout` - Create Stripe Checkout session - `POST /api/payments/webhook` - Handle Stripe webhooks (raw body) - `GET /api/payments/status` - Get subscription & generation status - `POST /api/payments/portal` - Create customer portal session - File: `server/src/routes/payments.ts` - [x] **1.6** Implement webhook handlers - `checkout.session.completed` - Activate subscription, set generation quota - `customer.subscription.updated` - Sync status changes - `customer.subscription.deleted` - Mark as canceled - `invoice.payment_failed` - Set past_due status - `invoice.paid` - Reset generation count on renewal - File: `server/src/routes/payments.ts` - [x] **1.7** Update AI access middleware - Check subscription status OR existing group membership - Check generation count against limit (250) - Increment generation count on AI use - Return remaining generations in response - Files: `server/src/middleware/auth.ts`, `server/src/routes/ai.ts` (or equivalent) - [x] **1.8** Register payments router in main app - File: `server/src/index.ts` ### Phase 2: Frontend - Upgrade Page - [x] **2.1** Create UpgradePage component - Pricing card with monthly/yearly toggle - Feature comparison (Free vs Pro) - CTA button triggering Stripe Checkout - Trust signals (secure payment, money-back guarantee) - File: `components/UpgradePage.tsx` - [x] **2.2** Create PaymentResult component - Success state with confetti - Cancel/return state - File: `components/PaymentResult.tsx` - [x] **2.3** Add routes to App.tsx - `/upgrade` route - `/payment/success` route - `/payment/cancel` route - File: `App.tsx` - [x] **2.4** Create payments API service (integrated in UpgradePage) - `createCheckoutSession(planType: 'monthly' | 'yearly')` - `getSubscriptionStatus()` - `createPortalSession()` - File: `services/paymentsApi.ts` - [x] **2.5** Update UI to show generation usage - Show remaining generations in preferences/header - Show upgrade CTA when generations low or user is free tier - Files: Various components - [x] **2.6** Add upgrade prompts in AI generation flow - When user tries AI generation without access - When user is low on generations - Files: Components using AI generation ### Phase 3: Production Updates - [x] **3.1** Update docker-compose.prod.yml - Add Stripe environment variables to backend service - File: `docker-compose.prod.yml` - [x] **3.2** Update PRODUCTION.md documentation - Add Stripe configuration section - Add webhook setup instructions - Add Stripe Dashboard product setup - File: `docs/PRODUCTION.md` - [x] **3.3** Update setup-prod.sh script (not needed - manual env config) - Prompt for Stripe keys during setup - File: `scripts/setup-prod.sh` ### Phase 4: Testing - [ ] **4.1** Test with Stripe test mode - Use test API keys - Test card: 4242 4242 4242 4242 - [ ] **4.2** Test webhook locally - Use Stripe CLI: `stripe listen --forward-to localhost:3001/api/payments/webhook` - [ ] **4.3** Test full payment flow - Checkout → Success → Access granted → Generations work - [ ] **4.4** Test generation limits - Verify count increments - Verify block at 250 - Verify reset on renewal --- ## Database Schema Changes ```sql -- Add subscription fields to users table ALTER TABLE users ADD COLUMN stripe_customer_id TEXT UNIQUE; ALTER TABLE users ADD COLUMN subscription_status TEXT DEFAULT 'none'; ALTER TABLE users ADD COLUMN subscription_id TEXT; ALTER TABLE users ADD COLUMN subscription_current_period_end DATETIME; ALTER TABLE users ADD COLUMN generation_count INTEGER DEFAULT 0; ALTER TABLE users ADD COLUMN generation_reset_date DATETIME; -- Payments log table CREATE TABLE IF NOT EXISTS payments ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id), stripe_payment_intent_id TEXT, stripe_invoice_id TEXT, amount INTEGER NOT NULL, currency TEXT DEFAULT 'usd', status TEXT NOT NULL, description TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS idx_payments_user ON payments(user_id); ``` --- ## Environment Variables ```bash # Stripe Configuration STRIPE_SECRET_KEY=sk_test_... # or sk_live_... for production STRIPE_WEBHOOK_SECRET=whsec_... # From Stripe Dashboard or CLI STRIPE_PRICE_ID_MONTHLY=price_... # Monthly plan price ID STRIPE_PRICE_ID_YEARLY=price_... # Yearly plan price ID ``` --- ## API Endpoints | Method | Endpoint | Auth | Description | |--------|----------|------|-------------| | `POST` | `/api/payments/checkout` | Required | Create Stripe Checkout session | | `POST` | `/api/payments/webhook` | Stripe Sig | Handle Stripe webhook events | | `GET` | `/api/payments/status` | Required | Get subscription & generation status | | `POST` | `/api/payments/portal` | Required | Create Stripe Customer Portal session | --- ## Stripe Dashboard Setup 1. Create Product: "Kaboot AI Pro" 2. Add Monthly Price: $5.00/month 3. Add Yearly Price: $50.00/year 4. Copy Price IDs to environment variables 5. Set up Webhook endpoint: `https://your-domain.com/api/payments/webhook` 6. Subscribe to events: - `checkout.session.completed` - `customer.subscription.created` - `customer.subscription.updated` - `customer.subscription.deleted` - `invoice.paid` - `invoice.payment_failed` --- ## Generation Tracking Logic 1. On subscription activation: Set `generation_count = 0`, `generation_reset_date = period_end` 2. On each AI generation: Increment `generation_count` 3. Before AI generation: Check `generation_count < 250` 4. On `invoice.paid` (renewal): Reset `generation_count = 0`, update `generation_reset_date` 5. Return `remaining_generations = 250 - generation_count` in API responses --- ## Notes - Existing `kaboot-ai-access` group users (via Authentik) get unlimited access (grandfathered) - Subscription users get 250 generations/month regardless of Authentik group - Both access methods are valid - check either condition in middleware