Skip to content

Commit 320dc83

Browse files
committed
docs: Refactor Stripe integration skill with comprehensive guide
1 parent ff69b10 commit 320dc83

File tree

7 files changed

+2421
-66
lines changed

7 files changed

+2421
-66
lines changed
Lines changed: 134 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,163 @@
11
---
22
name: riligar-dev-stripe
33
type: development
4-
description: Stripe payment integration patterns. Use when implementing payments, subscriptions, webhooks, checkout flows, or billing in Elysia/Bun applications.
4+
description: 'Complete guide for Stripe payment integration in RiLiGar applications. Use when implementing: (1) Checkout flows (hosted or embedded), (2) Subscription management, (3) Webhook handlers, (4) Customer portal, (5) One-time payments, (6) Database schema for billing.'
55
---
66

7-
# Stripe Integration Patterns
7+
# Stripe Integration Skill
88

9-
> Patterns for integrating Stripe payments in RiLiGar applications.
10-
11-
---
9+
This skill provides a complete workflow for integrating Stripe payments using Elysia (backend) and React (frontend).
1210

1311
## Mandatory Guidelines
1412

1513
> [!IMPORTANT]
1614
> All work in this skill MUST adhere to:
1715
>
18-
> - @[.agent/skills/riligar-dev-backend] (API Standards)
16+
> - @[.agent/skills/riligar-dev-backend] (Elysia API Standards)
17+
> - @[.agent/skills/riligar-dev-frontend] (React Patterns)
1918
> - @[.agent/skills/riligar-dev-clean-code] (Clean Code Standards)
2019
2120
---
2221

23-
## 1. Core Concepts
22+
## Quick Reference
2423

25-
| Concept | Description |
26-
| --- | --- |
27-
| **Customer** | User identity in Stripe |
28-
| **Product** | What you're selling |
29-
| **Price** | How much and billing cycle |
30-
| **Subscription** | Recurring payment |
31-
| **PaymentIntent** | One-time payment |
32-
| **Webhook** | Event notifications |
24+
```
25+
Stripe Flow:
26+
┌─────────────────────────────────────────────────────────────────────┐
27+
│ Frontend (React) │ Backend (Elysia) │
28+
├────────────────────────────────┼────────────────────────────────────┤
29+
│ 1. User clicks "Subscribe" │ │
30+
│ 2. Call POST /checkout │ → 3. Create checkout session │
31+
│ 4. Redirect to Stripe │ │
32+
│ │ 5. Webhook: checkout.completed │
33+
│ │ 6. Update database │
34+
│ 7. Redirect to success_url │ │
35+
└────────────────────────────────┴────────────────────────────────────┘
36+
```
3337

3438
---
3539

36-
## 2. Environment Setup
40+
## Core Integration Workflow
41+
42+
### 1. Installation
3743

3844
```bash
39-
# .env
45+
# Backend (Elysia)
46+
bun add stripe
47+
48+
# Frontend (React)
49+
bun add @stripe/stripe-js @stripe/react-stripe-js
50+
```
51+
52+
### 2. Environment Variables
53+
54+
```bash
55+
# Backend .env
4056
STRIPE_SECRET_KEY=sk_live_...
4157
STRIPE_WEBHOOK_SECRET=whsec_...
42-
STRIPE_PUBLISHABLE_KEY=pk_live_...
43-
```
4458

45-
> [!IMPORTANT]
46-
> Never expose `STRIPE_SECRET_KEY` in frontend code.
59+
# Frontend .env.local
60+
VITE_STRIPE_PUBLISHABLE_KEY=pk_live_...
61+
```
4762

48-
---
63+
> [!CAUTION]
64+
> **STRIPE_SECRET_KEY** is for backend only. Never expose it in frontend code.
4965
50-
## 3. Server-Side Patterns (Elysia)
66+
### 3. Initialize Stripe
5167

52-
### Initialize Stripe
68+
**Backend (Elysia)**
5369

5470
```javascript
5571
import Stripe from 'stripe'
5672

5773
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY)
5874
```
5975

60-
### Create Checkout Session
76+
**Frontend (React)**
6177

6278
```javascript
79+
import { loadStripe } from '@stripe/stripe-js'
80+
81+
const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY)
82+
```
83+
84+
For complete setup patterns, see [stripe-server.js](assets/stripe-server.js) and [stripe-client.js](assets/stripe-client.js).
85+
86+
---
87+
88+
## Specialized Guides
89+
90+
| Guide | Content |
91+
| --- | --- |
92+
| [stripe-elysia.md](references/stripe-elysia.md) | Backend routes, checkout, customer management |
93+
| [stripe-react.md](references/stripe-react.md) | Frontend components, Elements, forms |
94+
| [stripe-webhooks.md](references/stripe-webhooks.md) | Event handling, signature verification |
95+
| [stripe-database.md](references/stripe-database.md) | Drizzle schema for billing data |
96+
97+
---
98+
99+
## Core Concepts
100+
101+
| Concept | Description |
102+
| --- | --- |
103+
| **Customer** | User identity in Stripe (link to your user table) |
104+
| **Product** | What you're selling (Pro Plan, Enterprise) |
105+
| **Price** | Amount and billing cycle (monthly, yearly) |
106+
| **Subscription** | Recurring payment relationship |
107+
| **PaymentIntent** | One-time payment flow |
108+
| **Checkout Session** | Hosted payment page |
109+
| **Customer Portal** | Self-service billing management |
110+
| **Webhook** | Server-to-server event notifications |
111+
112+
---
113+
114+
## Common Tasks
115+
116+
### Create Checkout Session (Subscription)
117+
118+
```javascript
119+
// Backend: POST /api/checkout
63120
const session = await stripe.checkout.sessions.create({
64121
mode: 'subscription',
65122
customer_email: user.email,
66123
line_items: [{ price: priceId, quantity: 1 }],
67124
success_url: `${baseUrl}/success?session_id={CHECKOUT_SESSION_ID}`,
68-
cancel_url: `${baseUrl}/cancel`,
125+
cancel_url: `${baseUrl}/pricing`,
126+
metadata: { userId: user.id }
127+
})
128+
129+
return { url: session.url }
130+
```
131+
132+
### Redirect to Checkout (React)
133+
134+
```javascript
135+
const handleCheckout = async (priceId) => {
136+
const response = await ky.post('/api/checkout', { json: { priceId } }).json()
137+
window.location.href = response.url
138+
}
139+
```
140+
141+
### Open Customer Portal
142+
143+
```javascript
144+
// Backend: POST /api/portal
145+
const portal = await stripe.billingPortal.sessions.create({
146+
customer: user.stripeCustomerId,
147+
return_url: `${baseUrl}/account`
69148
})
149+
150+
return { url: portal.url }
70151
```
71152
72-
### Webhook Handler
153+
### Handle Webhook
73154
74155
```javascript
75-
app.post('/webhook/stripe', async ({ request, set }) => {
156+
app.post('/webhook/stripe', async ({ request }) => {
76157
const sig = request.headers.get('stripe-signature')
77158
const body = await request.text()
78159

79-
const event = stripe.webhooks.constructEvent(
80-
body,
81-
sig,
82-
process.env.STRIPE_WEBHOOK_SECRET
83-
)
160+
const event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET)
84161

85162
switch (event.type) {
86163
case 'checkout.session.completed':
@@ -89,9 +166,6 @@ app.post('/webhook/stripe', async ({ request, set }) => {
89166
case 'customer.subscription.updated':
90167
await handleSubscriptionUpdate(event.data.object)
91168
break
92-
case 'customer.subscription.deleted':
93-
await handleSubscriptionCancel(event.data.object)
94-
break
95169
}
96170

97171
return { received: true }
@@ -100,53 +174,47 @@ app.post('/webhook/stripe', async ({ request, set }) => {
100174
101175
---
102176
103-
## 4. Essential Webhooks
104-
105-
| Event | When to Handle |
106-
| --- | --- |
107-
| `checkout.session.completed` | Provision access after payment |
108-
| `customer.subscription.updated` | Plan changes, renewals |
109-
| `customer.subscription.deleted` | Cancellation |
110-
| `invoice.payment_failed` | Payment issues |
111-
| `invoice.paid` | Successful recurring payment |
112-
113-
---
114-
115-
## 5. Customer Portal
116-
117-
```javascript
118-
const portalSession = await stripe.billingPortal.sessions.create({
119-
customer: customerId,
120-
return_url: `${baseUrl}/account`,
121-
})
122-
```
123-
124-
---
125-
126-
## 6. Security Checklist
177+
## Security Checklist
127178
128-
- [ ] Verify webhook signatures
129-
- [ ] Use idempotency keys for retries
130-
- [ ] Store customer ID in database
131-
- [ ] Handle edge cases (expired cards, disputes)
132-
- [ ] Test with Stripe CLI locally
179+
- [ ] Webhook signatures verified with `constructEvent`
180+
- [ ] Secret key only in backend environment
181+
- [ ] Customer ID stored in database
182+
- [ ] Idempotency keys for create operations
183+
- [ ] Prices validated server-side (never trust frontend)
184+
- [ ] Subscription status checked before granting access
133185
134186
---
135187
136-
## 7. Testing
188+
## Testing
137189
138190
```bash
139191
# Install Stripe CLI
140192
brew install stripe/stripe-cli/stripe
141193

194+
# Login
195+
stripe login
196+
142197
# Forward webhooks to local server
143198
stripe listen --forward-to localhost:3000/webhook/stripe
199+
200+
# Trigger test events
201+
stripe trigger checkout.session.completed
144202
```
145203
204+
**Test Cards:**
205+
206+
| Card | Scenario |
207+
| --- | --- |
208+
| `4242 4242 4242 4242` | Successful payment |
209+
| `4000 0000 0000 3220` | 3D Secure required |
210+
| `4000 0000 0000 9995` | Declined |
211+
146212
---
147213
148214
## Related Skills
149215
150216
- @[.agent/skills/riligar-dev-backend]
217+
- @[.agent/skills/riligar-dev-frontend]
151218
- @[.agent/skills/riligar-dev-auth-elysia]
219+
- @[.agent/skills/riligar-dev-auth-react]
152220
- @[.agent/skills/riligar-tech-stack]

0 commit comments

Comments
 (0)