kaboot/docs/PAYMENT_FEATURE_PLAN.md
Joey Yakimowich-Payne 2e12edc249
Add Stripe payment integration for AI subscriptions
Implement subscription-based AI access with 250 generations/month at $5/month or $50/year.

Changes:
- Backend: Stripe service, payment routes, webhook handlers, generation tracking
- Frontend: Upgrade page with pricing, payment success/cancel pages, UI prompts
- Database: Add subscription fields to users, payments table, migrations
- Config: Stripe env vars to .env.example, docker-compose.prod.yml, PRODUCTION.md
- Tests: Payment route tests, component tests, subscription hook tests

Users without AI access see upgrade prompts; subscribers see remaining generation count.
2026-01-21 16:11:03 -07:00

7.6 KiB

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

  • 1.1 Add Stripe dependency to server

    • npm install stripe in server directory
    • File: server/package.json
  • 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
  • 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
  • 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
  • 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
  • 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
  • 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)
  • 1.8 Register payments router in main app

    • File: server/src/index.ts

Phase 2: Frontend - Upgrade Page

  • 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
  • 2.2 Create PaymentResult component

    • Success state with confetti
    • Cancel/return state
    • File: components/PaymentResult.tsx
  • 2.3 Add routes to App.tsx

    • /upgrade route
    • /payment/success route
    • /payment/cancel route
    • File: App.tsx
  • 2.4 Create payments API service (integrated in UpgradePage)

    • createCheckoutSession(planType: 'monthly' | 'yearly')
    • getSubscriptionStatus()
    • createPortalSession()
    • File: services/paymentsApi.ts
  • 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
  • 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

  • 3.1 Update docker-compose.prod.yml

    • Add Stripe environment variables to backend service
    • File: docker-compose.prod.yml
  • 3.2 Update PRODUCTION.md documentation

    • Add Stripe configuration section
    • Add webhook setup instructions
    • Add Stripe Dashboard product setup
    • File: docs/PRODUCTION.md
  • 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

-- 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

# 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