2025-11-02 07:56:31 +00:00
|
|
|
# 💳 Stripe Integration for Xtablo
|
|
|
|
|
|
|
|
|
|
Complete Stripe subscription integration with a single "Standard" plan using your Node.js API.
|
|
|
|
|
|
|
|
|
|
## 📁 Files Created
|
|
|
|
|
|
|
|
|
|
### Database (SQL)
|
|
|
|
|
- `sql/35_stripe_wrappers.sql` - Database schema, tables, functions, triggers
|
|
|
|
|
- `sql/36_stripe_webhooks.sql` - Webhook handler functions
|
|
|
|
|
|
|
|
|
|
### Backend (Node.js API)
|
|
|
|
|
- `api/src/stripe.ts` - API routes for Stripe operations
|
|
|
|
|
- `api/src/stripe-webhook.ts` - Webhook event processor
|
|
|
|
|
- `api/src/routers.ts` - ✅ Updated with Stripe routes
|
|
|
|
|
|
|
|
|
|
### Frontend (React)
|
|
|
|
|
- `apps/main/src/hooks/stripe.ts` - React hooks for Stripe
|
|
|
|
|
- `apps/main/src/components/SubscriptionCard.tsx` - Ready-to-use subscription UI
|
|
|
|
|
- `packages/shared/src/types/stripe.types.ts` - TypeScript types
|
|
|
|
|
|
|
|
|
|
### Documentation
|
|
|
|
|
- `docs/STRIPE_SETUP.md` - Complete setup guide
|
|
|
|
|
- `docs/STRIPE_IMPLEMENTATION_SUMMARY.md` - Technical overview
|
|
|
|
|
- `docs/STRIPE_QUICK_REFERENCE.md` - Quick reference guide
|
|
|
|
|
- `docs/STRIPE_README.md` - This file
|
|
|
|
|
|
|
|
|
|
## ⚡ Quick Setup
|
|
|
|
|
|
|
|
|
|
### 1. Install Dependencies
|
|
|
|
|
```bash
|
2025-11-10 07:53:03 +00:00
|
|
|
cd apps/api && npm install stripe @stripe/stripe-js
|
2025-11-02 07:56:31 +00:00
|
|
|
cd ../apps/main && npm install @stripe/stripe-js
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 2. Run Database Migrations
|
|
|
|
|
Execute in Supabase SQL Editor:
|
|
|
|
|
```sql
|
|
|
|
|
\i sql/35_stripe_wrappers.sql
|
|
|
|
|
\i sql/36_stripe_webhooks.sql
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 3. Configure Stripe Dashboard
|
|
|
|
|
1. Create product named **"Standard"**
|
|
|
|
|
2. Add monthly/yearly pricing
|
|
|
|
|
3. Save the price IDs
|
|
|
|
|
4. Add webhook endpoint: `https://your-api.com/api/v1/stripe/webhook`
|
|
|
|
|
5. Copy webhook signing secret
|
|
|
|
|
|
|
|
|
|
### 4. Set Environment Variables
|
|
|
|
|
|
|
|
|
|
**API (`.env`):**
|
|
|
|
|
```env
|
|
|
|
|
STRIPE_SECRET_KEY=sk_test_xxxxx
|
|
|
|
|
STRIPE_WEBHOOK_SECRET=whsec_xxxxx
|
|
|
|
|
SUPABASE_SERVICE_ROLE_KEY=your_key
|
|
|
|
|
FRONTEND_URL=http://localhost:5173
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Frontend (`apps/main/.env`):**
|
|
|
|
|
```env
|
|
|
|
|
VITE_STRIPE_PUBLISHABLE_KEY=pk_test_xxxxx
|
|
|
|
|
VITE_STRIPE_STANDARD_MONTHLY_PRICE_ID=price_xxxxx
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### 5. Add Subscription Card to Settings
|
|
|
|
|
|
|
|
|
|
In `apps/main/src/pages/settings.tsx`:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SubscriptionCard } from "../components/SubscriptionCard";
|
|
|
|
|
|
|
|
|
|
// Inside your settings page JSX, add:
|
|
|
|
|
<SubscriptionCard />
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 🎯 How It Works
|
|
|
|
|
|
|
|
|
|
### User Journey
|
|
|
|
|
|
|
|
|
|
1. **Free User** sees upgrade prompt in SubscriptionCard
|
|
|
|
|
2. Clicks "Passer à Standard"
|
|
|
|
|
3. Redirected to Stripe Checkout
|
|
|
|
|
4. Completes payment
|
|
|
|
|
5. Redirected back to settings with `?success=true`
|
|
|
|
|
6. Webhook updates database
|
|
|
|
|
7. `user.is_paying` becomes `true`
|
|
|
|
|
8. `user.subscription_tier` becomes `'standard'`
|
|
|
|
|
9. UI automatically updates
|
|
|
|
|
|
|
|
|
|
### Data Sync
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
Stripe → Webhook → API → Database → Frontend
|
|
|
|
|
↓
|
|
|
|
|
profiles.is_paying = true
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 🎨 Using Subscription Card
|
|
|
|
|
|
|
|
|
|
The `SubscriptionCard` component shows:
|
|
|
|
|
|
|
|
|
|
**For Free Users:**
|
|
|
|
|
- "Plan Gratuit" badge
|
|
|
|
|
- "Passer à Standard" button
|
|
|
|
|
- Initiates Stripe Checkout
|
|
|
|
|
|
|
|
|
|
**For Paying Users:**
|
|
|
|
|
- "Actif" badge
|
|
|
|
|
- Current subscription details
|
|
|
|
|
- Renewal date
|
|
|
|
|
- "Gérer l'abonnement" button (opens Stripe portal)
|
|
|
|
|
- "Annuler" button
|
|
|
|
|
|
|
|
|
|
**For Canceling Users:**
|
|
|
|
|
- "Annulation en cours" warning
|
|
|
|
|
- Access until period end
|
|
|
|
|
- "Réactiver l'abonnement" button
|
|
|
|
|
|
|
|
|
|
## 🔍 Check Payment Status Anywhere
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { useUser } from '../providers/UserStoreProvider';
|
|
|
|
|
|
|
|
|
|
function PremiumFeature() {
|
|
|
|
|
const user = useUser();
|
|
|
|
|
|
|
|
|
|
if (!user.is_paying) {
|
|
|
|
|
return <UpgradePrompt />;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return <PremiumContent />;
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 🎣 Available Hooks
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Get subscription details
|
|
|
|
|
const { data: subscription } = useSubscription();
|
|
|
|
|
|
|
|
|
|
// Check if paying (boolean)
|
|
|
|
|
const { data: isPaying } = useIsPayingUser();
|
|
|
|
|
|
|
|
|
|
// Get available prices
|
|
|
|
|
const { data: prices } = useStripePrices();
|
|
|
|
|
|
|
|
|
|
// Create checkout session
|
|
|
|
|
const { mutate: checkout } = useCreateCheckoutSession();
|
|
|
|
|
checkout({ priceId: 'price_xxxxx' });
|
|
|
|
|
|
|
|
|
|
// Open customer portal
|
|
|
|
|
const { mutate: portal } = useCreatePortalSession();
|
|
|
|
|
portal();
|
|
|
|
|
|
|
|
|
|
// Cancel subscription
|
|
|
|
|
const { mutate: cancel } = useCancelSubscription();
|
|
|
|
|
cancel();
|
|
|
|
|
|
|
|
|
|
// Reactivate subscription
|
|
|
|
|
const { mutate: reactivate } = useReactivateSubscription();
|
|
|
|
|
reactivate();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 🧪 Testing
|
|
|
|
|
|
|
|
|
|
### Test Cards
|
|
|
|
|
```
|
|
|
|
|
Success: 4242 4242 4242 4242
|
|
|
|
|
Decline: 4000 0000 0000 0002
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Test Webhooks Locally
|
|
|
|
|
```bash
|
|
|
|
|
stripe listen --forward-to http://localhost:3000/api/v1/stripe/webhook
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Trigger Events
|
|
|
|
|
```bash
|
|
|
|
|
stripe trigger customer.subscription.created
|
|
|
|
|
stripe trigger customer.subscription.updated
|
|
|
|
|
stripe trigger customer.subscription.deleted
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 🔐 Security Features
|
|
|
|
|
|
|
|
|
|
✅ Webhook signature verification
|
|
|
|
|
✅ Row Level Security on all tables
|
|
|
|
|
✅ Users can only see their own subscriptions
|
|
|
|
|
✅ API keys never exposed to frontend
|
|
|
|
|
✅ Service role for database operations
|
|
|
|
|
|
|
|
|
|
## 📊 Database Schema
|
|
|
|
|
|
|
|
|
|
### Tables
|
|
|
|
|
- `stripe_customers` - Links Stripe customers to users
|
|
|
|
|
- `stripe_subscriptions` - Subscription records
|
|
|
|
|
- `stripe_products` - Product catalog
|
|
|
|
|
- `stripe_prices` - Pricing information
|
|
|
|
|
|
|
|
|
|
### Profile Fields
|
|
|
|
|
- `is_paying: boolean` - Quick check for payment status
|
|
|
|
|
- `subscription_tier: 'free' | 'standard'` - Current tier
|
|
|
|
|
|
|
|
|
|
### Functions
|
|
|
|
|
- `is_paying_user(uuid)` - Returns boolean
|
|
|
|
|
- `get_user_subscription_status(uuid)` - Returns subscription details
|
|
|
|
|
- `get_user_stripe_customer_id(uuid)` - Returns Stripe customer ID
|
|
|
|
|
|
|
|
|
|
## 🐛 Troubleshooting
|
|
|
|
|
|
|
|
|
|
**Webhooks not working?**
|
|
|
|
|
1. Check API logs
|
|
|
|
|
2. Verify webhook secret in `.env`
|
|
|
|
|
3. Test with Stripe CLI
|
|
|
|
|
4. Check Stripe Dashboard → Webhooks for delivery status
|
|
|
|
|
|
|
|
|
|
**Subscription not showing?**
|
|
|
|
|
1. Check `stripe_subscriptions` table in Supabase
|
|
|
|
|
2. Verify webhook was received
|
|
|
|
|
3. Check `profiles.is_paying` field
|
|
|
|
|
4. Ensure customer has `user_id` in metadata
|
|
|
|
|
|
|
|
|
|
**Can't create checkout?**
|
|
|
|
|
1. Verify `STRIPE_SECRET_KEY` is set
|
|
|
|
|
2. Check `VITE_STRIPE_PUBLISHABLE_KEY` in frontend
|
|
|
|
|
3. Ensure price ID is correct
|
|
|
|
|
4. Check browser console for errors
|
|
|
|
|
|
|
|
|
|
## 📞 Support
|
|
|
|
|
|
|
|
|
|
See detailed docs:
|
|
|
|
|
- **Setup Guide**: `docs/STRIPE_SETUP.md`
|
|
|
|
|
- **Technical Details**: `docs/STRIPE_IMPLEMENTATION_SUMMARY.md`
|
|
|
|
|
- **Quick Reference**: `docs/STRIPE_QUICK_REFERENCE.md`
|
|
|
|
|
|
|
|
|
|
## 🎉 Next Steps
|
|
|
|
|
|
|
|
|
|
1. ✅ Database schema created
|
|
|
|
|
2. ✅ API endpoints implemented
|
|
|
|
|
3. ✅ Frontend hooks ready
|
|
|
|
|
4. ✅ UI component created
|
|
|
|
|
5. ⏳ Run migrations
|
|
|
|
|
6. ⏳ Configure Stripe
|
|
|
|
|
7. ⏳ Set environment variables
|
|
|
|
|
8. ⏳ Test with test cards
|
|
|
|
|
9. ⏳ Add SubscriptionCard to settings page
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
**Status**: ✅ Implementation Complete
|
|
|
|
|
**Architecture**: Node.js API + Supabase Database
|
|
|
|
|
**Plan**: Single "Standard" tier
|
|
|
|
|
**Ready to Deploy**: Yes, follow setup guide
|
|
|
|
|
|