@nextsparkjs/ai-workflow 0.1.0-beta.126 → 0.1.0-beta.128
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -7,7 +7,7 @@ Interactive guide to configure subscription plans, features, and billing in Next
|
|
|
7
7
|
## Required Skills
|
|
8
8
|
|
|
9
9
|
Before executing, these skills provide deeper context:
|
|
10
|
-
- `.claude/skills/billing-subscriptions/SKILL.md` -
|
|
10
|
+
- `.claude/skills/billing-subscriptions/SKILL.md` - Multi-provider billing and Gateway Factory patterns
|
|
11
11
|
- `.claude/skills/permissions-system/SKILL.md` - Three-layer permission model
|
|
12
12
|
|
|
13
13
|
---
|
|
@@ -22,7 +22,7 @@ Before executing, these skills provide deeper context:
|
|
|
22
22
|
|
|
23
23
|
## Behavior
|
|
24
24
|
|
|
25
|
-
Guides the user through configuring subscription plans with features, usage limits, and
|
|
25
|
+
Guides the user through configuring subscription plans with features, usage limits, and payment provider integration.
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
@@ -43,8 +43,8 @@ Step 3: Define Usage Limits (Quotas)
|
|
|
43
43
|
Step 4: Configure Plans
|
|
44
44
|
└── Create free, pro, enterprise plans
|
|
45
45
|
|
|
46
|
-
Step 5: Set Up
|
|
47
|
-
└── Create products and prices
|
|
46
|
+
Step 5: Set Up Payment Provider
|
|
47
|
+
└── Create products and prices (Stripe or Polar)
|
|
48
48
|
|
|
49
49
|
Step 6: Test the Checkout Flow
|
|
50
50
|
└── Verify the complete flow
|
|
@@ -327,8 +327,7 @@ export const billingConfig: BillingConfig = {
|
|
|
327
327
|
api_calls: 1000,
|
|
328
328
|
email_sends: 100,
|
|
329
329
|
},
|
|
330
|
-
|
|
331
|
-
stripePriceIdYearly: null,
|
|
330
|
+
// No price IDs for free plan
|
|
332
331
|
},
|
|
333
332
|
|
|
334
333
|
// PRO PLAN
|
|
@@ -357,8 +356,10 @@ export const billingConfig: BillingConfig = {
|
|
|
357
356
|
api_calls: 100000,
|
|
358
357
|
email_sends: 5000,
|
|
359
358
|
},
|
|
360
|
-
|
|
361
|
-
|
|
359
|
+
providerPriceIds: {
|
|
360
|
+
monthly: 'price_xxx_monthly', // From your payment provider
|
|
361
|
+
yearly: 'price_xxx_yearly',
|
|
362
|
+
},
|
|
362
363
|
},
|
|
363
364
|
|
|
364
365
|
// ENTERPRISE PLAN
|
|
@@ -386,7 +387,7 @@ export const billingConfig: BillingConfig = {
|
|
|
386
387
|
📋 Plan Types:
|
|
387
388
|
|
|
388
389
|
• 'free' - No payment required
|
|
389
|
-
• 'paid' - Requires
|
|
390
|
+
• 'paid' - Requires payment subscription
|
|
390
391
|
• 'enterprise' - Custom pricing (contact sales)
|
|
391
392
|
|
|
392
393
|
📋 Visibility:
|
|
@@ -398,37 +399,47 @@ export const billingConfig: BillingConfig = {
|
|
|
398
399
|
|
|
399
400
|
What would you like to do?
|
|
400
401
|
|
|
401
|
-
[1] Continue to Step 5 (
|
|
402
|
+
[1] Continue to Step 5 (Payment Provider Setup)
|
|
402
403
|
[2] How do I add more plan tiers?
|
|
403
404
|
[3] Show me the pricing page component
|
|
404
405
|
```
|
|
405
406
|
|
|
406
407
|
---
|
|
407
408
|
|
|
408
|
-
## Step 5: Set Up
|
|
409
|
+
## Step 5: Set Up Payment Provider
|
|
409
410
|
|
|
410
411
|
```
|
|
411
412
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
412
|
-
STEP 5 OF 6: Set Up
|
|
413
|
+
STEP 5 OF 6: Set Up Payment Provider
|
|
413
414
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
414
415
|
|
|
415
|
-
1️⃣ Create
|
|
416
|
-
|
|
417
|
-
In Stripe Dashboard (dashboard.stripe.com):
|
|
416
|
+
1️⃣ Create Products and Prices in your provider:
|
|
418
417
|
|
|
418
|
+
For Stripe (dashboard.stripe.com):
|
|
419
419
|
• Products → Add Product → "Pro Plan"
|
|
420
420
|
• Add Price → $29/month → Copy price_xxx_monthly
|
|
421
421
|
• Add Price → $290/year → Copy price_xxx_yearly
|
|
422
422
|
|
|
423
|
+
For Polar (polar.sh):
|
|
424
|
+
• Products → Create Product → Set pricing
|
|
425
|
+
• Copy the Product Price ID
|
|
426
|
+
|
|
423
427
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
424
428
|
|
|
425
429
|
2️⃣ Configure Environment Variables:
|
|
426
430
|
|
|
427
431
|
```env
|
|
428
432
|
# .env.local
|
|
433
|
+
|
|
434
|
+
# For Stripe:
|
|
429
435
|
STRIPE_SECRET_KEY=sk_test_xxx
|
|
430
436
|
STRIPE_PUBLISHABLE_KEY=pk_test_xxx
|
|
431
437
|
STRIPE_WEBHOOK_SECRET=whsec_xxx
|
|
438
|
+
|
|
439
|
+
# For Polar:
|
|
440
|
+
POLAR_ACCESS_TOKEN=pat_xxx
|
|
441
|
+
POLAR_WEBHOOK_SECRET=whsec_xxx
|
|
442
|
+
POLAR_SERVER=sandbox
|
|
432
443
|
```
|
|
433
444
|
|
|
434
445
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
@@ -440,8 +451,10 @@ STRIPE_WEBHOOK_SECRET=whsec_xxx
|
|
|
440
451
|
{
|
|
441
452
|
slug: 'pro',
|
|
442
453
|
// ...
|
|
443
|
-
|
|
444
|
-
|
|
454
|
+
providerPriceIds: {
|
|
455
|
+
monthly: 'price_1xxx', // From your provider
|
|
456
|
+
yearly: 'price_1yyy',
|
|
457
|
+
},
|
|
445
458
|
}
|
|
446
459
|
```
|
|
447
460
|
|
|
@@ -449,23 +462,17 @@ STRIPE_WEBHOOK_SECRET=whsec_xxx
|
|
|
449
462
|
|
|
450
463
|
4️⃣ Set Up Webhook:
|
|
451
464
|
|
|
452
|
-
|
|
453
|
-
|
|
465
|
+
For Stripe: Dashboard → Webhooks → Add endpoint
|
|
454
466
|
URL: https://your-domain.com/api/v1/billing/webhooks/stripe
|
|
455
467
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
• invoice.paid
|
|
459
|
-
• invoice.payment_failed
|
|
460
|
-
• customer.subscription.updated
|
|
461
|
-
• customer.subscription.deleted
|
|
468
|
+
For Polar: Organization Settings → Webhooks → Add endpoint
|
|
469
|
+
URL: https://your-domain.com/api/v1/billing/webhooks/polar
|
|
462
470
|
|
|
463
471
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
464
472
|
|
|
465
|
-
5️⃣ Test
|
|
473
|
+
5️⃣ Test locally (Stripe example):
|
|
466
474
|
|
|
467
475
|
```bash
|
|
468
|
-
# Install Stripe CLI
|
|
469
476
|
stripe listen --forward-to localhost:3000/api/v1/billing/webhooks/stripe
|
|
470
477
|
```
|
|
471
478
|
|
|
@@ -474,7 +481,7 @@ stripe listen --forward-to localhost:3000/api/v1/billing/webhooks/stripe
|
|
|
474
481
|
What would you like to do?
|
|
475
482
|
|
|
476
483
|
[1] Continue to Step 6 (Test Checkout)
|
|
477
|
-
[2] I have questions about
|
|
484
|
+
[2] I have questions about provider setup
|
|
478
485
|
[3] Help me set up webhook forwarding
|
|
479
486
|
```
|
|
480
487
|
|
|
@@ -536,7 +543,7 @@ node core/scripts/build/registry.mjs
|
|
|
536
543
|
|
|
537
544
|
• Go to /pricing (or /dashboard/settings/billing)
|
|
538
545
|
• Click "Upgrade to Pro"
|
|
539
|
-
• Use
|
|
546
|
+
• Use test card (Stripe): 4242 4242 4242 4242
|
|
540
547
|
• Complete checkout
|
|
541
548
|
• Verify webhook updates subscription
|
|
542
549
|
• Check features are now available
|
|
@@ -557,7 +564,7 @@ You've configured:
|
|
|
557
564
|
• Feature flags for plan gating
|
|
558
565
|
• Usage limits and quotas
|
|
559
566
|
• Subscription plans with pricing
|
|
560
|
-
• Stripe
|
|
567
|
+
• Payment provider integration (Stripe or Polar)
|
|
561
568
|
|
|
562
569
|
📚 Related tutorials:
|
|
563
570
|
• /how-to:set-user-roles-and-permissions - RBAC configuration
|
|
@@ -20,7 +20,7 @@ BILLING ARCHITECTURE:
|
|
|
20
20
|
|
|
21
21
|
Configuration Layer:
|
|
22
22
|
contents/themes/{theme}/config/billing.config.ts
|
|
23
|
-
├── provider: 'stripe' | 'polar'
|
|
23
|
+
├── provider: 'stripe' | 'polar' # (paddle, lemonsqueezy, mercadopago: type defined, not yet implemented)
|
|
24
24
|
├── currency: 'usd' | 'eur' | ...
|
|
25
25
|
├── defaultPlan: 'free'
|
|
26
26
|
├── features: { featureSlug: FeatureDefinition }
|
|
@@ -37,7 +37,7 @@ core/lib/billing/
|
|
|
37
37
|
│ ├── types.ts # Provider-agnostic result types
|
|
38
38
|
│ ├── interface.ts # BillingGateway interface (contract)
|
|
39
39
|
│ ├── factory.ts # getBillingGateway() factory
|
|
40
|
-
│
|
|
40
|
+
│ ├── stripe.ts # StripeGateway implements BillingGateway
|
|
41
41
|
│ └── polar.ts # PolarGateway implements BillingGateway
|
|
42
42
|
├── queries.ts # Database queries
|
|
43
43
|
├── enforcement.ts # Limit/feature enforcement
|
|
@@ -97,6 +97,11 @@ export interface BillingGateway {
|
|
|
97
97
|
|
|
98
98
|
// Webhooks (Stripe passes string signature, Polar passes headers Record)
|
|
99
99
|
verifyWebhookSignature(payload: string | Buffer, signatureOrHeaders: string | Record<string, string>): WebhookEventResult
|
|
100
|
+
|
|
101
|
+
// Dashboard & Metadata
|
|
102
|
+
getProviderName(): string
|
|
103
|
+
getSubscriptionDashboardUrl(externalSubscriptionId: string | null | undefined): string | null
|
|
104
|
+
getResourceHintDomains(): { preconnect: string[]; dnsPrefetch: string[] }
|
|
100
105
|
}
|
|
101
106
|
```
|
|
102
107
|
|
|
@@ -144,29 +149,33 @@ const session = await getBillingGateway().createCheckoutSession(params)
|
|
|
144
149
|
const portal = await getBillingGateway().createPortalSession(params)
|
|
145
150
|
await getBillingGateway().cancelSubscriptionAtPeriodEnd(subId)
|
|
146
151
|
|
|
152
|
+
// Provider metadata
|
|
153
|
+
const name = getBillingGateway().getProviderName() // "Stripe" or "Polar"
|
|
154
|
+
const url = getBillingGateway().getSubscriptionDashboardUrl(id) // Dashboard URL or null
|
|
155
|
+
|
|
156
|
+
// Resource hints (used in layout.tsx automatically)
|
|
157
|
+
import { getBillingResourceHints } from '@nextsparkjs/core/lib/billing/gateways/factory'
|
|
158
|
+
const { preconnect, dnsPrefetch } = getBillingResourceHints()
|
|
159
|
+
|
|
147
160
|
// WRONG: Import from specific provider
|
|
148
161
|
import { createCheckoutSession } from '.../gateways/stripe' // DEPRECATED
|
|
149
162
|
```
|
|
150
163
|
|
|
151
164
|
### Plan Price IDs
|
|
152
165
|
|
|
153
|
-
Plans
|
|
166
|
+
Plans use `providerPriceIds` for price configuration (works with any provider):
|
|
154
167
|
|
|
155
168
|
```typescript
|
|
156
169
|
// PlanDefinition in config-types.ts
|
|
157
170
|
{
|
|
158
171
|
slug: 'pro',
|
|
159
|
-
// Generic (checked first) - works with any provider
|
|
160
172
|
providerPriceIds: {
|
|
161
173
|
monthly: 'price_xxx_monthly',
|
|
162
174
|
yearly: 'price_xxx_yearly',
|
|
163
175
|
},
|
|
164
|
-
// Stripe-specific (fallback for backward compat)
|
|
165
|
-
stripePriceIdMonthly: 'price_pro_monthly',
|
|
166
|
-
stripePriceIdYearly: 'price_pro_yearly',
|
|
167
176
|
}
|
|
168
177
|
|
|
169
|
-
// PlanService.getPriceId()
|
|
178
|
+
// PlanService.getPriceId() reads from providerPriceIds
|
|
170
179
|
const priceId = PlanService.getPriceId('pro', 'monthly')
|
|
171
180
|
```
|
|
172
181
|
|
|
@@ -237,13 +246,16 @@ export class StripeGateway implements BillingGateway {
|
|
|
237
246
|
// app/api/v1/billing/webhooks/stripe/route.ts
|
|
238
247
|
// NOTE: Webhook routes stay provider-specific by design.
|
|
239
248
|
// They need raw provider types for proper type narrowing.
|
|
240
|
-
import
|
|
241
|
-
|
|
249
|
+
import Stripe from 'stripe'
|
|
250
|
+
|
|
251
|
+
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!)
|
|
242
252
|
|
|
243
253
|
export async function POST(request: NextRequest) {
|
|
244
254
|
const payload = await request.text()
|
|
245
255
|
const signature = request.headers.get('stripe-signature')!
|
|
246
|
-
const event =
|
|
256
|
+
const event = stripe.webhooks.constructEvent(
|
|
257
|
+
payload, signature, process.env.STRIPE_WEBHOOK_SECRET!
|
|
258
|
+
)
|
|
247
259
|
|
|
248
260
|
switch (event.type) {
|
|
249
261
|
case 'checkout.session.completed':
|
|
@@ -659,15 +671,11 @@ export const billingConfig: BillingConfig = {
|
|
|
659
671
|
features: ['basic_analytics', 'advanced_analytics', 'api_access'],
|
|
660
672
|
limits: { team_members: 15, tasks: 1000, api_calls: 100000 },
|
|
661
673
|
|
|
662
|
-
//
|
|
674
|
+
// Price IDs from your payment provider dashboard
|
|
663
675
|
providerPriceIds: {
|
|
664
676
|
monthly: 'price_pro_monthly',
|
|
665
677
|
yearly: 'price_pro_yearly',
|
|
666
678
|
},
|
|
667
|
-
|
|
668
|
-
// OR Stripe-specific (backward compat)
|
|
669
|
-
stripePriceIdMonthly: 'price_pro_monthly',
|
|
670
|
-
stripePriceIdYearly: 'price_pro_yearly',
|
|
671
679
|
},
|
|
672
680
|
{
|
|
673
681
|
slug: 'enterprise',
|
|
@@ -784,8 +792,8 @@ CREATE TABLE plans (
|
|
|
784
792
|
"trialDays" INTEGER DEFAULT 0,
|
|
785
793
|
features JSONB DEFAULT '[]',
|
|
786
794
|
limits JSONB DEFAULT '{}',
|
|
787
|
-
|
|
788
|
-
|
|
795
|
+
-- Price IDs stored in providerPriceIds (via billing.config.ts)
|
|
796
|
+
-- Legacy: stripePriceIdMonthly/Yearly columns may exist in older migrations but are unused
|
|
789
797
|
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
|
|
790
798
|
"updatedAt" TIMESTAMPTZ DEFAULT NOW()
|
|
791
799
|
);
|
|
@@ -829,7 +837,7 @@ POLAR_SERVER=sandbox # 'sandbox' or 'production'
|
|
|
829
837
|
|
|
830
838
|
```typescript
|
|
831
839
|
// NEVER: Import from specific provider in consumers
|
|
832
|
-
import { createCheckoutSession } from '.../gateways/stripe' //
|
|
840
|
+
import { createCheckoutSession } from '.../gateways/stripe' // REMOVED
|
|
833
841
|
|
|
834
842
|
// CORRECT: Use factory
|
|
835
843
|
import { getBillingGateway } from '.../gateways/factory'
|
|
@@ -841,7 +849,7 @@ const session: Stripe.Checkout.Session = ...
|
|
|
841
849
|
// CORRECT: Use provider-agnostic types
|
|
842
850
|
const session: CheckoutSessionResult = ...
|
|
843
851
|
|
|
844
|
-
// NEVER: Use getStripePriceId (
|
|
852
|
+
// NEVER: Use getStripePriceId (removed)
|
|
845
853
|
PlanService.getStripePriceId('pro', 'monthly')
|
|
846
854
|
|
|
847
855
|
// CORRECT: Use generic getPriceId
|
|
@@ -885,7 +893,7 @@ if (current >= limit) return false
|
|
|
885
893
|
### General (all providers)
|
|
886
894
|
|
|
887
895
|
- [ ] Provider selected in `billing.config.ts`
|
|
888
|
-
- [ ] Plans defined with price IDs (providerPriceIds
|
|
896
|
+
- [ ] Plans defined with price IDs (providerPriceIds)
|
|
889
897
|
- [ ] Features and limits defined
|
|
890
898
|
- [ ] Action mappings configured
|
|
891
899
|
- [ ] Team-based subscription created on team creation
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/ai-workflow",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.128",
|
|
4
4
|
"description": "AI workflow templates for NextSpark - Claude Code agents, commands, skills, and multi-editor support",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "NextSpark <hello@nextspark.dev>",
|