2025-11-03 08:46:10 +00:00
|
|
|
# 🎉 Final Stripe Setup - Using Official Library
|
|
|
|
|
|
|
|
|
|
## Overview
|
|
|
|
|
|
|
|
|
|
We're using the official **@supabase/stripe-sync-engine** library from Supabase.
|
|
|
|
|
This handles ALL webhook processing automatically - we just add custom profile integration on top!
|
|
|
|
|
|
|
|
|
|
**Repository**: [https://github.com/supabase/stripe-sync-engine](https://github.com/supabase/stripe-sync-engine)
|
|
|
|
|
|
|
|
|
|
## 📦 What's Implemented
|
|
|
|
|
|
|
|
|
|
### ✅ Files That Matter
|
|
|
|
|
|
|
|
|
|
**Backend:**
|
|
|
|
|
|
|
|
|
|
- `api/src/stripe.ts` - Webhook + action endpoints (uses StripeSync)
|
|
|
|
|
- `sql/35_stripe_wrappers.sql` - Profile integration & RLS policies
|
|
|
|
|
|
|
|
|
|
**Frontend:**
|
|
|
|
|
|
|
|
|
|
- `apps/main/src/hooks/stripe.ts` - React hooks (queries Supabase directly)
|
|
|
|
|
- `apps/main/src/components/SubscriptionCard.tsx` - Ready-to-use UI
|
|
|
|
|
|
|
|
|
|
**Documentation:**
|
|
|
|
|
|
|
|
|
|
- `docs/STRIPE_WITH_SYNC_ENGINE.md` - Main guide ⭐
|
|
|
|
|
- `docs/TESTING_WITH_FAKE_ACCOUNTS.md` - Testing guide
|
|
|
|
|
|
|
|
|
|
### ❌ Files Deleted (Not Needed Anymore)
|
|
|
|
|
|
|
|
|
|
- ~~`api/src/stripe-webhook.ts`~~ - Library handles this!
|
|
|
|
|
- ~~`sql/36_stripe_webhooks.sql`~~ - Library handles this!
|
|
|
|
|
|
|
|
|
|
## 🚀 Setup Steps
|
|
|
|
|
|
|
|
|
|
### 1. Install Library
|
|
|
|
|
|
|
|
|
|
```bash
|
2025-11-10 07:53:03 +00:00
|
|
|
cd apps/api
|
2025-11-03 08:46:10 +00:00
|
|
|
npm install @supabase/stripe-sync-engine
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
✅ Already done!
|
|
|
|
|
|
|
|
|
|
### 2. Run Library Migrations
|
|
|
|
|
|
|
|
|
|
The library needs to create its tables first. Either:
|
|
|
|
|
|
|
|
|
|
**Option A: Via Code** (recommended for first time)
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { runMigrations } from "@supabase/stripe-sync-engine";
|
|
|
|
|
|
|
|
|
|
await runMigrations({
|
|
|
|
|
databaseUrl:
|
|
|
|
|
"postgresql://postgres:[password]@db.[project].supabase.co:5432/postgres",
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Option B: Manually**
|
|
|
|
|
Copy migrations from `node_modules/@supabase/stripe-sync-engine/dist/migrations/*.sql` and run in Supabase SQL Editor.
|
|
|
|
|
|
|
|
|
|
### 3. Run Custom SQL
|
|
|
|
|
|
|
|
|
|
After library migrations, run:
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
\i sql/35_stripe_wrappers.sql
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This adds:
|
|
|
|
|
|
|
|
|
|
- `user_id` columns for RLS
|
|
|
|
|
- `profiles.is_paying` and `subscription_tier` fields
|
|
|
|
|
- Automatic triggers
|
|
|
|
|
- Helper functions
|
|
|
|
|
|
|
|
|
|
### 4. Configure Environment
|
|
|
|
|
|
|
|
|
|
**API (`.env`):**
|
|
|
|
|
|
|
|
|
|
```env
|
|
|
|
|
STRIPE_SECRET_KEY=sk_test_xxxxx
|
|
|
|
|
STRIPE_WEBHOOK_SECRET=whsec_xxxxx
|
|
|
|
|
DATABASE_URL=postgresql://postgres:[password]@db.[project].supabase.co:5432/postgres
|
|
|
|
|
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. Create "Standard" Product in Stripe
|
|
|
|
|
|
|
|
|
|
1. Stripe Dashboard → **Test Mode** → Products
|
|
|
|
|
2. Add product: **"Standard"**
|
|
|
|
|
3. Monthly price: €9.99/month
|
|
|
|
|
4. Copy the `price_id`
|
|
|
|
|
5. Add to frontend `.env`
|
|
|
|
|
|
|
|
|
|
### 6. Configure Webhook
|
|
|
|
|
|
|
|
|
|
1. Stripe Dashboard → Developers → Webhooks
|
|
|
|
|
2. Add endpoint: `https://your-api.com/api/v1/stripe/webhook`
|
|
|
|
|
3. Select **all events** (library handles them all!)
|
|
|
|
|
4. Copy signing secret → Add to API `.env`
|
|
|
|
|
|
|
|
|
|
### 7. Add UI to Settings
|
|
|
|
|
|
|
|
|
|
In `apps/main/src/pages/settings.tsx`:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
import { SubscriptionCard } from "../components/SubscriptionCard";
|
|
|
|
|
|
|
|
|
|
// Add in your cards section:
|
|
|
|
|
<SubscriptionCard />;
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## 🎯 How It Works
|
|
|
|
|
|
|
|
|
|
### Webhook Flow
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
Stripe event → API webhook endpoint → StripeSync library → Database tables → Triggers → Profile updated
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Read Flow (From Frontend)
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
Frontend → Supabase Client → RLS policies → stripe_subscriptions → User's data
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**No custom webhook code needed!** The library handles everything.
|
|
|
|
|
|
|
|
|
|
## 🧪 Testing
|
|
|
|
|
|
|
|
|
|
### Quick Test
|
|
|
|
|
|
2025-11-10 07:53:03 +00:00
|
|
|
1. **Start API**: `cd apps/api && npm run dev`
|
2025-11-03 08:46:10 +00:00
|
|
|
2. **Start Frontend**: `cd apps/main && npm run dev`
|
|
|
|
|
3. **Start Webhook Forwarding**:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
stripe listen --forward-to http://localhost:3000/api/v1/stripe/webhook
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
4. **Create test account**: `test@example.com`
|
|
|
|
|
5. **Subscribe**: Use card `4242 4242 4242 4242`
|
|
|
|
|
6. **Verify**: Check `user.is_paying === true`
|
|
|
|
|
|
|
|
|
|
## 📊 What Tables Are Created
|
|
|
|
|
|
|
|
|
|
### By stripe-sync-engine Library:
|
|
|
|
|
|
|
|
|
|
- `stripe_customers`
|
|
|
|
|
- `stripe_subscriptions`
|
|
|
|
|
- `stripe_subscription_items`
|
|
|
|
|
- `stripe_products`
|
|
|
|
|
- `stripe_prices`
|
|
|
|
|
- `stripe_invoices`
|
|
|
|
|
- `stripe_charges`
|
|
|
|
|
- `stripe_payment_intents`
|
|
|
|
|
- `stripe_payment_methods`
|
|
|
|
|
- ... and 30+ more!
|
|
|
|
|
|
|
|
|
|
### By Our SQL (35_stripe_wrappers.sql):
|
|
|
|
|
|
|
|
|
|
- Adds `user_id` to customers/subscriptions
|
|
|
|
|
- Adds `is_paying` to profiles
|
|
|
|
|
- Adds `subscription_tier` to profiles
|
|
|
|
|
- Creates RLS policies
|
|
|
|
|
- Creates triggers
|
|
|
|
|
- Creates helper functions
|
|
|
|
|
|
|
|
|
|
## ⚡ Key Advantages
|
|
|
|
|
|
|
|
|
|
| Aspect | Before | After (with library) |
|
|
|
|
|
| -------------- | -------------- | -------------------- |
|
|
|
|
|
| Webhook code | 267 lines | ~15 lines |
|
|
|
|
|
| Event coverage | 8 events | 100+ events |
|
|
|
|
|
| Maintenance | You | Supabase |
|
|
|
|
|
| Schema updates | Manual | Automatic |
|
|
|
|
|
| Backfilling | Custom scripts | Built-in |
|
|
|
|
|
| Battle-tested | No | ✅ Yes |
|
|
|
|
|
|
|
|
|
|
## 🎓 Using the Library Features
|
|
|
|
|
|
|
|
|
|
### Backfill Historical Data
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Sync all existing Stripe data
|
|
|
|
|
await stripeSync.syncBackfill({ object: "all" });
|
|
|
|
|
|
|
|
|
|
// Or sync specific objects
|
|
|
|
|
await stripeSync.syncProducts();
|
|
|
|
|
await stripeSync.syncCustomers();
|
|
|
|
|
await stripeSync.syncSubscriptions();
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Sync Single Entity
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Sync a specific customer
|
|
|
|
|
await stripeSync.syncSingleEntity("cus_xxxxx");
|
|
|
|
|
|
|
|
|
|
// Sync a specific subscription
|
|
|
|
|
await stripeSync.syncSingleEntity("sub_xxxxx");
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## ✅ Success Criteria
|
|
|
|
|
|
|
|
|
|
Your integration works when:
|
|
|
|
|
|
|
|
|
|
1. ✅ Library installed: `npm list @supabase/stripe-sync-engine`
|
|
|
|
|
2. ✅ Library migrations run
|
|
|
|
|
3. ✅ Custom SQL (35) run
|
|
|
|
|
4. ✅ Environment variables configured
|
|
|
|
|
5. ✅ Webhook endpoint configured in Stripe
|
|
|
|
|
6. ✅ Test subscription creates data in `stripe_subscriptions`
|
|
|
|
|
7. ✅ `profiles.is_paying` updates automatically
|
|
|
|
|
8. ✅ Frontend shows subscription status
|
|
|
|
|
9. ✅ RLS policies work (users see only their data)
|
|
|
|
|
|
|
|
|
|
## 🐛 Troubleshooting
|
|
|
|
|
|
|
|
|
|
### Library Not Found
|
|
|
|
|
|
|
|
|
|
```bash
|
2025-11-10 07:53:03 +00:00
|
|
|
cd apps/api && npm install @supabase/stripe-sync-engine
|
2025-11-03 08:46:10 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
|
|
### Migrations Failing
|
|
|
|
|
|
|
|
|
|
Make sure to run **library migrations first**, then `sql/35_stripe_wrappers.sql`
|
|
|
|
|
|
|
|
|
|
### user_id Not Populating
|
|
|
|
|
|
|
|
|
|
Ensure customer is created with metadata:
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
stripe.customers.create({
|
|
|
|
|
email: user.email,
|
|
|
|
|
metadata: { user_id: user.id }, // ← Important!
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This is already handled in `api/src/stripe.ts` create-checkout-session endpoint.
|
|
|
|
|
|
|
|
|
|
## 📞 Support
|
|
|
|
|
|
|
|
|
|
- **Library Issues**: https://github.com/supabase/stripe-sync-engine/issues
|
|
|
|
|
- **Library Docs**: https://supabase.github.io/stripe-sync-engine
|
|
|
|
|
- **Our Implementation**: See `docs/STRIPE_WITH_SYNC_ENGINE.md`
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
**Status**: ✅ Fully Implemented
|
|
|
|
|
**Complexity**: Minimal (library does the heavy lifting)
|
|
|
|
|
**Maintenance**: Low (library handles updates)
|
|
|
|
|
**Ready to Deploy**: Yes!
|