shipd 0.1.3 → 0.2.0
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.
- package/base-package/app/globals.css +126 -0
- package/base-package/app/layout.tsx +53 -0
- package/base-package/app/page.tsx +15 -0
- package/base-package/base.config.json +57 -0
- package/base-package/components/ui/avatar.tsx +53 -0
- package/base-package/components/ui/badge.tsx +46 -0
- package/base-package/components/ui/button.tsx +59 -0
- package/base-package/components/ui/card.tsx +92 -0
- package/base-package/components/ui/chart.tsx +353 -0
- package/base-package/components/ui/checkbox.tsx +32 -0
- package/base-package/components/ui/dialog.tsx +135 -0
- package/base-package/components/ui/dropdown-menu.tsx +257 -0
- package/base-package/components/ui/form.tsx +167 -0
- package/base-package/components/ui/input.tsx +21 -0
- package/base-package/components/ui/label.tsx +24 -0
- package/base-package/components/ui/progress.tsx +31 -0
- package/base-package/components/ui/resizable.tsx +56 -0
- package/base-package/components/ui/select.tsx +185 -0
- package/base-package/components/ui/separator.tsx +28 -0
- package/base-package/components/ui/sheet.tsx +139 -0
- package/base-package/components/ui/skeleton.tsx +13 -0
- package/base-package/components/ui/sonner.tsx +25 -0
- package/base-package/components/ui/switch.tsx +31 -0
- package/base-package/components/ui/tabs.tsx +66 -0
- package/base-package/components/ui/textarea.tsx +18 -0
- package/base-package/components/ui/toggle-group.tsx +73 -0
- package/base-package/components/ui/toggle.tsx +47 -0
- package/base-package/components/ui/tooltip.tsx +61 -0
- package/base-package/components.json +21 -0
- package/base-package/eslint.config.mjs +16 -0
- package/base-package/lib/utils.ts +6 -0
- package/base-package/middleware.ts +12 -0
- package/base-package/next.config.ts +27 -0
- package/base-package/package.json +49 -0
- package/base-package/postcss.config.mjs +5 -0
- package/base-package/public/favicon.svg +4 -0
- package/base-package/tailwind.config.ts +89 -0
- package/base-package/tsconfig.json +27 -0
- package/dist/index.js +1858 -956
- package/docs-template/README.md +74 -0
- package/features/ai-chat/README.md +316 -0
- package/features/ai-chat/app/api/chat/route.ts +16 -0
- package/features/ai-chat/app/dashboard/_components/chatbot.tsx +39 -0
- package/features/ai-chat/app/dashboard/chat/page.tsx +73 -0
- package/features/ai-chat/feature.config.json +22 -0
- package/features/analytics/README.md +364 -0
- package/features/analytics/feature.config.json +20 -0
- package/features/analytics/lib/posthog.ts +36 -0
- package/features/auth/README.md +409 -0
- package/features/auth/app/api/auth/[...all]/route.ts +4 -0
- package/features/auth/app/dashboard/layout.tsx +15 -0
- package/features/auth/app/dashboard/page.tsx +140 -0
- package/features/auth/app/sign-in/page.tsx +228 -0
- package/features/auth/app/sign-up/page.tsx +243 -0
- package/features/auth/auth-schema.ts +47 -0
- package/features/auth/components/auth/setup-instructions.tsx +123 -0
- package/features/auth/feature.config.json +33 -0
- package/features/auth/lib/auth-client.ts +8 -0
- package/features/auth/lib/auth.ts +295 -0
- package/features/auth/lib/email-stub.ts +55 -0
- package/features/auth/lib/email.ts +47 -0
- package/features/auth/middleware.patch.ts +43 -0
- package/features/database/README.md +312 -0
- package/features/database/db/drizzle.ts +48 -0
- package/features/database/db/schema.ts +21 -0
- package/features/database/drizzle.config.ts +13 -0
- package/features/database/feature.config.json +30 -0
- package/features/email/README.md +341 -0
- package/features/email/emails/components/layout.tsx +181 -0
- package/features/email/emails/password-reset.tsx +67 -0
- package/features/email/emails/payment-failed.tsx +167 -0
- package/features/email/emails/subscription-confirmation.tsx +129 -0
- package/features/email/emails/welcome.tsx +100 -0
- package/features/email/feature.config.json +22 -0
- package/features/email/lib/email.ts +118 -0
- package/features/file-upload/README.md +329 -0
- package/features/file-upload/app/api/upload-image/route.ts +64 -0
- package/features/file-upload/app/dashboard/upload/page.tsx +324 -0
- package/features/file-upload/feature.config.json +23 -0
- package/features/file-upload/lib/upload-image.ts +28 -0
- package/features/marketing-landing/README.md +333 -0
- package/features/marketing-landing/app/page.tsx +25 -0
- package/features/marketing-landing/components/homepage/cli-workflow-section.tsx +231 -0
- package/features/marketing-landing/components/homepage/features-section.tsx +152 -0
- package/features/marketing-landing/components/homepage/footer.tsx +53 -0
- package/features/marketing-landing/components/homepage/hero-section.tsx +112 -0
- package/features/marketing-landing/components/homepage/integrations.tsx +124 -0
- package/features/marketing-landing/components/homepage/navigation.tsx +116 -0
- package/features/marketing-landing/components/homepage/news-section.tsx +82 -0
- package/features/marketing-landing/components/homepage/pricing-section.tsx +98 -0
- package/features/marketing-landing/components/homepage/testimonials-section.tsx +34 -0
- package/features/marketing-landing/components/logos/BetterAuth.tsx +21 -0
- package/features/marketing-landing/components/logos/NeonPostgres.tsx +41 -0
- package/features/marketing-landing/components/logos/Nextjs.tsx +72 -0
- package/features/marketing-landing/components/logos/Polar.tsx +7 -0
- package/features/marketing-landing/components/logos/TailwindCSS.tsx +27 -0
- package/features/marketing-landing/components/logos/index.ts +6 -0
- package/features/marketing-landing/components/logos/shadcnui.tsx +8 -0
- package/features/marketing-landing/feature.config.json +23 -0
- package/features/payments/README.md +375 -0
- package/features/payments/app/api/subscription/route.ts +25 -0
- package/features/payments/app/dashboard/payment/_components/manage-subscription.tsx +22 -0
- package/features/payments/app/dashboard/payment/page.tsx +126 -0
- package/features/payments/app/success/page.tsx +123 -0
- package/features/payments/feature.config.json +31 -0
- package/features/payments/lib/polar-products.ts +49 -0
- package/features/payments/lib/subscription.ts +148 -0
- package/features/payments/payments-schema.ts +30 -0
- package/features/seo/README.md +302 -0
- package/features/seo/app/blog/[slug]/page.tsx +314 -0
- package/features/seo/app/blog/page.tsx +107 -0
- package/features/seo/app/robots.txt +13 -0
- package/features/seo/app/sitemap.ts +70 -0
- package/features/seo/feature.config.json +19 -0
- package/features/seo/lib/seo-utils.ts +163 -0
- package/package.json +3 -1
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
# Payments Module - Integration Guide
|
|
2
|
+
|
|
3
|
+
**Module Version:** 1.0.0
|
|
4
|
+
**Last Updated:** 2025-12-22
|
|
5
|
+
**Standalone:** ⚠️ Requires Auth + Database Modules
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
This module adds complete subscription management and payment processing using Polar.sh. It includes subscription management pages, billing interfaces, webhook handling, and success pages.
|
|
12
|
+
|
|
13
|
+
**Key Features:**
|
|
14
|
+
- Polar.sh subscription integration
|
|
15
|
+
- Subscription management dashboard
|
|
16
|
+
- Customer portal access
|
|
17
|
+
- Webhook handling for subscription events
|
|
18
|
+
- Payment success page
|
|
19
|
+
- Subscription status tracking
|
|
20
|
+
- Product and pricing management
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Files Added
|
|
25
|
+
|
|
26
|
+
### Pages/Routes
|
|
27
|
+
- `app/dashboard/payment/page.tsx` - Payment and subscription management page
|
|
28
|
+
- `app/success/page.tsx` - Success page after payment completion
|
|
29
|
+
- `app/api/subscription/route.ts` - Subscription API endpoint
|
|
30
|
+
|
|
31
|
+
### Components
|
|
32
|
+
- `app/dashboard/payment/_components/manage-subscription.tsx` - Subscription management component
|
|
33
|
+
|
|
34
|
+
### Utilities/Libraries
|
|
35
|
+
- `lib/subscription.ts` - Subscription utilities and helpers
|
|
36
|
+
- `lib/polar-products.ts` - Polar product fetching utilities
|
|
37
|
+
- `payments-schema.ts` - Subscription table schema (merged into db/schema.ts)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Dependencies
|
|
42
|
+
|
|
43
|
+
### Package Dependencies
|
|
44
|
+
The following packages will be added to `package.json`:
|
|
45
|
+
- `@polar-sh/sdk@^0.42.1` - Polar.sh SDK
|
|
46
|
+
|
|
47
|
+
### Required Modules
|
|
48
|
+
- **Auth Module** - Payments requires authentication
|
|
49
|
+
- **Database Module** - Payments requires database for subscription storage
|
|
50
|
+
|
|
51
|
+
### Included Components
|
|
52
|
+
This module uses UI components from the base package:
|
|
53
|
+
- ✅ `components/ui/button.tsx` - For action buttons
|
|
54
|
+
- ✅ `components/ui/card.tsx` - For subscription cards
|
|
55
|
+
- ✅ `components/ui/badge.tsx` - For status badges
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Environment Variables
|
|
60
|
+
|
|
61
|
+
Add these to your `.env.local`:
|
|
62
|
+
|
|
63
|
+
```env
|
|
64
|
+
# Payments (Polar.sh)
|
|
65
|
+
POLAR_ACCESS_TOKEN="your-polar-access-token"
|
|
66
|
+
POLAR_WEBHOOK_SECRET="your-webhook-secret"
|
|
67
|
+
POLAR_SUCCESS_URL="success" # Path to success page (e.g., "success")
|
|
68
|
+
NEXT_PUBLIC_STARTER_TIER="your-product-id" # Product ID for starter tier
|
|
69
|
+
NEXT_PUBLIC_STARTER_SLUG="starter" # Product slug
|
|
70
|
+
NEXT_PUBLIC_APP_URL="http://localhost:3000" # Your app URL (for webhooks)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Required Variables:**
|
|
74
|
+
- `POLAR_ACCESS_TOKEN` - Your Polar.sh API access token
|
|
75
|
+
- `POLAR_WEBHOOK_SECRET` - Secret for webhook signature verification
|
|
76
|
+
- `NEXT_PUBLIC_STARTER_TIER` - Product ID from Polar.sh dashboard
|
|
77
|
+
- `NEXT_PUBLIC_STARTER_SLUG` - Product slug
|
|
78
|
+
- `NEXT_PUBLIC_APP_URL` - Your application URL (for webhook callbacks)
|
|
79
|
+
|
|
80
|
+
**Optional Variables:**
|
|
81
|
+
- `POLAR_SUCCESS_URL` - Custom success page path (defaults to "success")
|
|
82
|
+
|
|
83
|
+
**Where to get them:**
|
|
84
|
+
- **Polar.sh Dashboard**: [polar.sh](https://polar.sh) - Create account and products
|
|
85
|
+
- Get access token from API settings
|
|
86
|
+
- Create webhook secret for signature verification
|
|
87
|
+
- Create products and get product IDs
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Manual Integration Steps
|
|
92
|
+
|
|
93
|
+
If you're appending this module to an existing project, follow these steps:
|
|
94
|
+
|
|
95
|
+
### Step 1: Install Dependencies
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npm install
|
|
99
|
+
# or
|
|
100
|
+
pnpm install
|
|
101
|
+
# or
|
|
102
|
+
yarn install
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The append command automatically adds missing dependencies to `package.json`, but you need to install them.
|
|
106
|
+
|
|
107
|
+
### Step 2: Add Environment Variables
|
|
108
|
+
|
|
109
|
+
1. Copy `.env.example` to `.env.local` (if not exists)
|
|
110
|
+
2. Add the required environment variables listed above
|
|
111
|
+
3. Get your Polar.sh credentials from the [Polar.sh dashboard](https://polar.sh)
|
|
112
|
+
|
|
113
|
+
### Step 3: Update Database Schema
|
|
114
|
+
|
|
115
|
+
The payments module adds a subscription table. If you have the database module installed, the schema will be merged automatically. Otherwise:
|
|
116
|
+
|
|
117
|
+
1. Add the subscription table to your `db/schema.ts`:
|
|
118
|
+
```typescript
|
|
119
|
+
// Import from payments-schema.ts or copy the table definition
|
|
120
|
+
export { subscription } from '@/payments-schema';
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
2. Generate and run migrations:
|
|
124
|
+
```bash
|
|
125
|
+
npm run db:generate
|
|
126
|
+
npm run db:push
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Step 4: Update Auth Configuration
|
|
130
|
+
|
|
131
|
+
The payments module integrates with the auth module's Polar webhook handling. The auth module already includes webhook code, but you need to ensure:
|
|
132
|
+
|
|
133
|
+
1. `lib/auth.ts` includes Polar integration (already done if auth module is installed)
|
|
134
|
+
2. Webhook endpoint is accessible at `/api/auth/callback/polar`
|
|
135
|
+
3. Webhook secret matches your Polar.sh configuration
|
|
136
|
+
|
|
137
|
+
### Step 5: Verify Installation
|
|
138
|
+
|
|
139
|
+
1. Start your dev server: `npm run dev`
|
|
140
|
+
2. Visit `http://localhost:3000/dashboard/payment` to see subscription management
|
|
141
|
+
3. Visit `http://localhost:3000/success` to see the success page
|
|
142
|
+
4. Test the subscription API: `GET /api/subscription`
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Usage Examples
|
|
147
|
+
|
|
148
|
+
### Checking Subscription Status
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { getSubscriptionDetails, hasActiveSubscription } from "@/lib/subscription";
|
|
152
|
+
|
|
153
|
+
// Get full subscription details
|
|
154
|
+
const details = await getSubscriptionDetails();
|
|
155
|
+
if (details.hasSubscription && details.subscription) {
|
|
156
|
+
console.log("Status:", details.subscription.status);
|
|
157
|
+
console.log("Amount:", details.subscription.amount);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Quick check for active subscription
|
|
161
|
+
const isActive = await hasActiveSubscription();
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Opening Customer Portal
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
"use client";
|
|
168
|
+
|
|
169
|
+
import { authClient } from "@/lib/auth-client";
|
|
170
|
+
|
|
171
|
+
export function ManageSubscriptionButton() {
|
|
172
|
+
const handleOpenPortal = async () => {
|
|
173
|
+
try {
|
|
174
|
+
await authClient.customer.portal();
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error("Failed to open portal:", error);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
return <button onClick={handleOpenPortal}>Manage Subscription</button>;
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Creating Checkout Session
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
"use client";
|
|
188
|
+
|
|
189
|
+
import { authClient } from "@/lib/auth-client";
|
|
190
|
+
|
|
191
|
+
export function SubscribeButton({ productId }: { productId: string }) {
|
|
192
|
+
const handleSubscribe = async () => {
|
|
193
|
+
try {
|
|
194
|
+
await authClient.checkout({
|
|
195
|
+
productId,
|
|
196
|
+
successUrl: `${window.location.origin}/success`,
|
|
197
|
+
});
|
|
198
|
+
} catch (error) {
|
|
199
|
+
console.error("Checkout failed:", error);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return <button onClick={handleSubscribe}>Subscribe</button>;
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Customization
|
|
210
|
+
|
|
211
|
+
### Styling
|
|
212
|
+
- Payment pages use Tailwind CSS classes
|
|
213
|
+
- Customize colors in `tailwind.config.ts`
|
|
214
|
+
- Modify page layouts in `app/dashboard/payment/page.tsx`
|
|
215
|
+
|
|
216
|
+
### Configuration
|
|
217
|
+
- Product IDs are configured via environment variables
|
|
218
|
+
- Webhook handling is in `lib/auth.ts` (auth module)
|
|
219
|
+
- Customize success page in `app/success/page.tsx`
|
|
220
|
+
|
|
221
|
+
### Subscription Management
|
|
222
|
+
- Customize subscription display in `app/dashboard/payment/page.tsx`
|
|
223
|
+
- Add custom subscription actions in `_components/manage-subscription.tsx`
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Integration Points
|
|
228
|
+
|
|
229
|
+
### Files That May Need Manual Updates
|
|
230
|
+
|
|
231
|
+
**lib/auth.ts** (if auth module installed):
|
|
232
|
+
- Polar webhook handling is already included
|
|
233
|
+
- Ensure webhook secret matches your Polar.sh configuration
|
|
234
|
+
|
|
235
|
+
**db/schema.ts** (if database module installed):
|
|
236
|
+
- Subscription table will be automatically merged
|
|
237
|
+
- If manual merge needed, import from `payments-schema.ts`
|
|
238
|
+
|
|
239
|
+
**Middleware** (if auth module installed):
|
|
240
|
+
- No changes needed - payments uses existing auth protection
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Troubleshooting
|
|
245
|
+
|
|
246
|
+
### Common Issues
|
|
247
|
+
|
|
248
|
+
**Issue:** "Subscription table not found" error
|
|
249
|
+
**Solution:**
|
|
250
|
+
- Ensure database module is installed
|
|
251
|
+
- Run `npm run db:push` to create tables
|
|
252
|
+
- Verify subscription table exists in `db/schema.ts`
|
|
253
|
+
|
|
254
|
+
**Issue:** Webhooks not working
|
|
255
|
+
**Solution:**
|
|
256
|
+
- Verify `POLAR_WEBHOOK_SECRET` matches Polar.sh dashboard
|
|
257
|
+
- Check webhook URL is correct: `https://yourdomain.com/api/auth/callback/polar`
|
|
258
|
+
- Ensure webhook events are enabled in Polar.sh dashboard
|
|
259
|
+
|
|
260
|
+
**Issue:** "POLAR_ACCESS_TOKEN is required"
|
|
261
|
+
**Solution:**
|
|
262
|
+
- Add `POLAR_ACCESS_TOKEN` to `.env.local`
|
|
263
|
+
- Get token from Polar.sh API settings
|
|
264
|
+
- Restart dev server after adding env vars
|
|
265
|
+
|
|
266
|
+
**Issue:** Checkout not redirecting
|
|
267
|
+
**Solution:**
|
|
268
|
+
- Verify `NEXT_PUBLIC_APP_URL` is set correctly
|
|
269
|
+
- Check `POLAR_SUCCESS_URL` matches your success page path
|
|
270
|
+
- Ensure product IDs are correct
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Next Steps
|
|
275
|
+
|
|
276
|
+
After installing this module:
|
|
277
|
+
|
|
278
|
+
1. Set up Polar.sh account and create products
|
|
279
|
+
2. Configure environment variables
|
|
280
|
+
3. Run database migrations
|
|
281
|
+
4. Test checkout flow
|
|
282
|
+
5. Configure webhooks in Polar.sh dashboard
|
|
283
|
+
6. Customize success page
|
|
284
|
+
7. Add pricing page (optional - can use marketing landing pricing section)
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Related Modules
|
|
289
|
+
|
|
290
|
+
This module requires:
|
|
291
|
+
- **Auth Module** - For user authentication and webhook handling
|
|
292
|
+
- **Database Module** - For subscription storage
|
|
293
|
+
|
|
294
|
+
This module works well with:
|
|
295
|
+
- **Email Module** - For subscription confirmation emails
|
|
296
|
+
- **Marketing Landing Module** - For pricing page display
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Module Status
|
|
301
|
+
|
|
302
|
+
✅ **Core Files Included** - All payment pages and utilities
|
|
303
|
+
⚠️ **Requires Auth + Database** - Must be installed first
|
|
304
|
+
✅ **Webhook Integration** - Works with auth module's webhook handler
|
|
305
|
+
✅ **Well Documented** - Comprehensive integration guide
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## AI Integration Prompt
|
|
310
|
+
|
|
311
|
+
**For AI Assistants:** Use this prompt to understand and integrate the Payments module into an existing Next.js application.
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
The Payments module has been appended to this Next.js project. Your task is to ensure it's properly integrated and functional.
|
|
315
|
+
|
|
316
|
+
**Installed Packages:**
|
|
317
|
+
- @polar-sh/sdk@^0.42.1 - Polar.sh SDK for subscription management
|
|
318
|
+
|
|
319
|
+
**Files Added:**
|
|
320
|
+
- app/dashboard/payment/page.tsx - Subscription management page
|
|
321
|
+
- app/dashboard/payment/_components/manage-subscription.tsx - Subscription management component
|
|
322
|
+
- app/success/page.tsx - Checkout success page
|
|
323
|
+
- app/api/subscription/route.ts - API route for fetching subscription details
|
|
324
|
+
- lib/subscription.ts - Utilities for subscription operations
|
|
325
|
+
- lib/polar-products.ts - Utilities for fetching Polar products
|
|
326
|
+
- payments-schema.ts - Drizzle schema for subscription table
|
|
327
|
+
|
|
328
|
+
**Schema Table Added to db/schema.ts:**
|
|
329
|
+
- subscription - Subscription records with status, billing info, and user linkage
|
|
330
|
+
|
|
331
|
+
**Environment Variables Required:**
|
|
332
|
+
- POLAR_ACCESS_TOKEN - Polar.sh API access token
|
|
333
|
+
- POLAR_SUCCESS_URL - Success page path (e.g., "success")
|
|
334
|
+
- POLAR_WEBHOOK_SECRET - Webhook secret for verifying Polar webhooks
|
|
335
|
+
- NEXT_PUBLIC_STARTER_TIER - Polar product ID for starter tier
|
|
336
|
+
- NEXT_PUBLIC_STARTER_SLUG - Polar organization slug
|
|
337
|
+
- NEXT_PUBLIC_APP_URL - Application URL (e.g., http://localhost:3000)
|
|
338
|
+
- DATABASE_URL - Required (from database module)
|
|
339
|
+
- BETTER_AUTH_SECRET - Required (from auth module)
|
|
340
|
+
|
|
341
|
+
**Integration Steps:**
|
|
342
|
+
1. Verify auth and database modules are installed (payments requires both)
|
|
343
|
+
2. Check that subscription table was merged into db/schema.ts
|
|
344
|
+
3. Verify lib/auth.ts has webhook handler for Polar subscription events
|
|
345
|
+
4. Ensure app/api/subscription/route.ts is protected (requires authentication)
|
|
346
|
+
5. Check that app/success/page.tsx exists for checkout redirects
|
|
347
|
+
6. Verify environment variables are set in .env.local
|
|
348
|
+
7. Run database migrations: npm run db:push (to create subscription table)
|
|
349
|
+
|
|
350
|
+
**Key Integration Points:**
|
|
351
|
+
- Webhook handling: lib/auth.ts contains onWebhook handler for Polar subscription events
|
|
352
|
+
- Subscription table: Automatically merged into db/schema.ts during append
|
|
353
|
+
- User linkage: subscription.userId references user.id from auth module
|
|
354
|
+
- API routes: app/api/subscription/route.ts fetches subscription for authenticated user
|
|
355
|
+
- Checkout flow: Users redirected to /success after successful checkout
|
|
356
|
+
- Dynamic imports: auth.ts dynamically imports subscription table (only if payments installed)
|
|
357
|
+
|
|
358
|
+
**Dependencies:**
|
|
359
|
+
- REQUIRES: Auth module (for user authentication and webhook handling)
|
|
360
|
+
- REQUIRES: Database module (for subscription storage)
|
|
361
|
+
- OPTIONAL: Email module (for subscription confirmation emails)
|
|
362
|
+
|
|
363
|
+
**Common Issues to Check:**
|
|
364
|
+
- If "subscription is not exported" error: Check that subscription table was merged into db/schema.ts
|
|
365
|
+
- If webhooks not working: Verify POLAR_WEBHOOK_SECRET matches Polar dashboard
|
|
366
|
+
- If checkout fails: Check NEXT_PUBLIC_STARTER_TIER and NEXT_PUBLIC_STARTER_SLUG are correct
|
|
367
|
+
- If subscription not showing: Ensure user is authenticated and subscription exists in database
|
|
368
|
+
|
|
369
|
+
**Next Steps After Integration:**
|
|
370
|
+
- Set up Polar.sh account and create products
|
|
371
|
+
- Configure webhook URL in Polar dashboard: https://yourdomain.com/api/auth/callback/polar
|
|
372
|
+
- Test checkout flow: Visit /dashboard/payment and subscribe
|
|
373
|
+
- Verify webhook events are received and subscription table is updated
|
|
374
|
+
- Customize success page at app/success/page.tsx
|
|
375
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { auth } from "@/lib/auth";
|
|
2
|
+
import { getSubscriptionDetails } from "@/lib/subscription";
|
|
3
|
+
import { headers } from "next/headers";
|
|
4
|
+
import { NextResponse } from "next/server";
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
try {
|
|
8
|
+
const result = await auth.api.getSession({
|
|
9
|
+
headers: await headers(),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
if (!result?.session?.userId) {
|
|
13
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const subscriptionDetails = await getSubscriptionDetails();
|
|
17
|
+
return NextResponse.json(subscriptionDetails);
|
|
18
|
+
} catch (error) {
|
|
19
|
+
console.error("Error fetching subscription details:", error);
|
|
20
|
+
return NextResponse.json(
|
|
21
|
+
{ error: "Failed to fetch subscription details" },
|
|
22
|
+
{ status: 500 }
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Button } from "@/components/ui/button";
|
|
3
|
+
import { ExternalLink } from "lucide-react";
|
|
4
|
+
import { authClient } from "@/lib/auth-client";
|
|
5
|
+
|
|
6
|
+
export default function ManageSubscription() {
|
|
7
|
+
return (
|
|
8
|
+
<Button
|
|
9
|
+
variant="outline"
|
|
10
|
+
onClick={async () => {
|
|
11
|
+
try {
|
|
12
|
+
await authClient.customer.portal();
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error("Failed to open customer portal:", error);
|
|
15
|
+
}
|
|
16
|
+
}}
|
|
17
|
+
>
|
|
18
|
+
<ExternalLink className="h-4 w-4 mr-2" />
|
|
19
|
+
Manage Subscription
|
|
20
|
+
</Button>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Button } from "@/components/ui/button";
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
CardDescription,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle,
|
|
8
|
+
} from "@/components/ui/card";
|
|
9
|
+
import { getSubscriptionDetails } from "@/lib/subscription";
|
|
10
|
+
import Link from "next/link";
|
|
11
|
+
import ManageSubscription from "./_components/manage-subscription";
|
|
12
|
+
|
|
13
|
+
export default async function PaymentPage() {
|
|
14
|
+
const subscriptionDetails = await getSubscriptionDetails();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div>
|
|
18
|
+
<div className="p-6 space-y-4">
|
|
19
|
+
<div className="relative min-h-screen">
|
|
20
|
+
{!subscriptionDetails.hasSubscription ||
|
|
21
|
+
subscriptionDetails.subscription?.status !== "active" ? (
|
|
22
|
+
<>
|
|
23
|
+
<div className="absolute inset-0 z-10 rounded-lg flex items-center justify-center">
|
|
24
|
+
<div className="bg-white dark:bg-gray-900 p-8 rounded-lg shadow-lg text-center max-w-md">
|
|
25
|
+
<h3 className="text-xl font-semibold mb-2">
|
|
26
|
+
Subscription Required
|
|
27
|
+
</h3>
|
|
28
|
+
<p className="text-muted-foreground mb-4">
|
|
29
|
+
You need an active subscription to access payment management
|
|
30
|
+
features.
|
|
31
|
+
</p>
|
|
32
|
+
<Link href="/pricing">
|
|
33
|
+
<Button>Subscribe Now</Button>
|
|
34
|
+
</Link>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
<div className="blur-sm pointer-events-none">
|
|
38
|
+
<Card>
|
|
39
|
+
<CardHeader>
|
|
40
|
+
<CardTitle>Payment Management</CardTitle>
|
|
41
|
+
<CardDescription>
|
|
42
|
+
Manage your billing and payment methods
|
|
43
|
+
</CardDescription>
|
|
44
|
+
</CardHeader>
|
|
45
|
+
<CardContent className="space-y-4">
|
|
46
|
+
<div className="grid grid-cols-2 gap-4">
|
|
47
|
+
<div>
|
|
48
|
+
<p className="text-sm font-medium text-muted-foreground">
|
|
49
|
+
Current Plan
|
|
50
|
+
</p>
|
|
51
|
+
<p className="text-md">Pro Plan</p>
|
|
52
|
+
</div>
|
|
53
|
+
<div>
|
|
54
|
+
<p className="text-sm font-medium text-muted-foreground">
|
|
55
|
+
Billing Status
|
|
56
|
+
</p>
|
|
57
|
+
<p className="text-md">Active</p>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</CardContent>
|
|
61
|
+
</Card>
|
|
62
|
+
</div>
|
|
63
|
+
</>
|
|
64
|
+
) : (
|
|
65
|
+
<Card>
|
|
66
|
+
<CardHeader>
|
|
67
|
+
<CardTitle>Subscription Details</CardTitle>
|
|
68
|
+
<CardDescription>
|
|
69
|
+
Your current subscription information
|
|
70
|
+
</CardDescription>
|
|
71
|
+
</CardHeader>
|
|
72
|
+
<CardContent className="space-y-4">
|
|
73
|
+
<div className="grid grid-cols-2 gap-4">
|
|
74
|
+
<div>
|
|
75
|
+
<p className="text-sm font-semibold text-muted-foreground">
|
|
76
|
+
Status
|
|
77
|
+
</p>
|
|
78
|
+
<p className="text-md capitalize">
|
|
79
|
+
{subscriptionDetails.subscription.status}
|
|
80
|
+
</p>
|
|
81
|
+
</div>
|
|
82
|
+
<div>
|
|
83
|
+
<p className="text-sm font-semibold text-muted-foreground">
|
|
84
|
+
Amount
|
|
85
|
+
</p>
|
|
86
|
+
<p className="text-md">
|
|
87
|
+
{subscriptionDetails.subscription.amount / 100}{" "}
|
|
88
|
+
{subscriptionDetails.subscription.currency.toUpperCase()}
|
|
89
|
+
</p>
|
|
90
|
+
</div>
|
|
91
|
+
<div>
|
|
92
|
+
<p className="text-sm font-semibold text-muted-foreground">
|
|
93
|
+
Billing Interval
|
|
94
|
+
</p>
|
|
95
|
+
<p className="text-md capitalize">
|
|
96
|
+
{subscriptionDetails.subscription.recurringInterval}
|
|
97
|
+
</p>
|
|
98
|
+
</div>
|
|
99
|
+
<div>
|
|
100
|
+
<p className="text-sm font-semibold text-muted-foreground">
|
|
101
|
+
Current Period End
|
|
102
|
+
</p>
|
|
103
|
+
<p className="text-md">
|
|
104
|
+
{new Date(
|
|
105
|
+
subscriptionDetails.subscription.currentPeriodEnd,
|
|
106
|
+
).toLocaleDateString()}
|
|
107
|
+
</p>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
{subscriptionDetails.subscription.cancelAtPeriodEnd && (
|
|
111
|
+
<div className="p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
|
|
112
|
+
<p className="text-sm text-yellow-800">
|
|
113
|
+
Your subscription will cancel at the end of the current
|
|
114
|
+
billing period.
|
|
115
|
+
</p>
|
|
116
|
+
</div>
|
|
117
|
+
)}
|
|
118
|
+
<ManageSubscription />
|
|
119
|
+
</CardContent>
|
|
120
|
+
</Card>
|
|
121
|
+
)}
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { Button } from "@/components/ui/button";
|
|
4
|
+
import { Card, CardContent } from "@/components/ui/card";
|
|
5
|
+
import { CheckCircle2, Terminal, BookOpen, Zap } from "lucide-react";
|
|
6
|
+
import { useRouter } from "next/navigation";
|
|
7
|
+
import Link from "next/link";
|
|
8
|
+
|
|
9
|
+
export default function SuccessPage() {
|
|
10
|
+
const router = useRouter();
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<div className="min-h-screen bg-black flex items-center justify-center p-6">
|
|
14
|
+
<Card className="bg-[#0a0a0a] border-[#2a2a2a] max-w-2xl w-full">
|
|
15
|
+
<CardContent className="p-12">
|
|
16
|
+
{/* Success Icon */}
|
|
17
|
+
<div className="w-20 h-20 bg-green-500/10 rounded-full flex items-center justify-center mx-auto mb-6">
|
|
18
|
+
<CheckCircle2 className="w-12 h-12 text-green-400" />
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
{/* Success Message */}
|
|
22
|
+
<div className="text-center mb-8">
|
|
23
|
+
<h1 className="text-3xl font-bold text-white mb-3">
|
|
24
|
+
Welcome! 🎉
|
|
25
|
+
</h1>
|
|
26
|
+
<p className="text-gray-400 text-lg">
|
|
27
|
+
Your subscription is now active. Let's get you started building your SaaS.
|
|
28
|
+
</p>
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
{/* Next Steps */}
|
|
32
|
+
<div className="space-y-6 mb-8">
|
|
33
|
+
<h2 className="text-xl font-semibold text-white">Next Steps</h2>
|
|
34
|
+
|
|
35
|
+
{/* Step 1 */}
|
|
36
|
+
<div className="flex gap-4">
|
|
37
|
+
<div className="w-8 h-8 rounded-full bg-[#ff5722] flex items-center justify-center text-white text-sm font-semibold flex-shrink-0">
|
|
38
|
+
1
|
|
39
|
+
</div>
|
|
40
|
+
<div className="flex-1">
|
|
41
|
+
<h3 className="text-white font-semibold mb-1">Authenticate the CLI</h3>
|
|
42
|
+
<p className="text-gray-400 text-sm mb-2">
|
|
43
|
+
Run this command in your terminal to authenticate:
|
|
44
|
+
</p>
|
|
45
|
+
<div className="bg-black/70 p-3 rounded-lg border border-[#2a2a2a]">
|
|
46
|
+
<code className="text-[#ff5722] font-mono text-sm">
|
|
47
|
+
npx your-cli login
|
|
48
|
+
</code>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
{/* Step 2 */}
|
|
54
|
+
<div className="flex gap-4">
|
|
55
|
+
<div className="w-8 h-8 rounded-full bg-[#ff5722] flex items-center justify-center text-white text-sm font-semibold flex-shrink-0">
|
|
56
|
+
2
|
|
57
|
+
</div>
|
|
58
|
+
<div className="flex-1">
|
|
59
|
+
<h3 className="text-white font-semibold mb-1">Create your first project</h3>
|
|
60
|
+
<p className="text-gray-400 text-sm mb-2">
|
|
61
|
+
Generate a complete SaaS application:
|
|
62
|
+
</p>
|
|
63
|
+
<div className="bg-black/70 p-3 rounded-lg border border-[#2a2a2a]">
|
|
64
|
+
<code className="text-[#ff5722] font-mono text-sm">
|
|
65
|
+
npx your-cli init my-app
|
|
66
|
+
</code>
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
{/* Step 3 */}
|
|
72
|
+
<div className="flex gap-4">
|
|
73
|
+
<div className="w-8 h-8 rounded-full bg-[#ff5722] flex items-center justify-center text-white text-sm font-semibold flex-shrink-0">
|
|
74
|
+
3
|
|
75
|
+
</div>
|
|
76
|
+
<div className="flex-1">
|
|
77
|
+
<h3 className="text-white font-semibold mb-1">Start building</h3>
|
|
78
|
+
<p className="text-gray-400 text-sm">
|
|
79
|
+
Your project includes authentication, billing, dashboard, and more - all ready to customize and deploy.
|
|
80
|
+
</p>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
|
|
85
|
+
{/* Action Buttons */}
|
|
86
|
+
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
|
87
|
+
<Button
|
|
88
|
+
onClick={() => router.push("/dashboard")}
|
|
89
|
+
className="w-full bg-[#ff5722] hover:bg-[#d84315]"
|
|
90
|
+
>
|
|
91
|
+
<Zap className="w-4 h-4 mr-2" />
|
|
92
|
+
Go to Dashboard
|
|
93
|
+
</Button>
|
|
94
|
+
<Link href="/dashboard/cli" className="w-full">
|
|
95
|
+
<Button variant="outline" className="w-full border-[#2a2a2a] hover:bg-[#1a1a1a]">
|
|
96
|
+
<Terminal className="w-4 h-4 mr-2" />
|
|
97
|
+
CLI Guide
|
|
98
|
+
</Button>
|
|
99
|
+
</Link>
|
|
100
|
+
<Link href="/docs" className="w-full">
|
|
101
|
+
<Button variant="outline" className="w-full border-[#2a2a2a] hover:bg-[#1a1a1a]">
|
|
102
|
+
<BookOpen className="w-4 h-4 mr-2" />
|
|
103
|
+
Documentation
|
|
104
|
+
</Button>
|
|
105
|
+
</Link>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
{/* Help Section */}
|
|
109
|
+
<div className="mt-8 pt-8 border-t border-[#2a2a2a] text-center">
|
|
110
|
+
<p className="text-gray-400 text-sm mb-2">
|
|
111
|
+
Need help getting started?
|
|
112
|
+
</p>
|
|
113
|
+
<Link href="mailto:support@yourdomain.com">
|
|
114
|
+
<Button variant="link" className="text-[#ff5722] hover:text-[#d84315]">
|
|
115
|
+
Contact Support
|
|
116
|
+
</Button>
|
|
117
|
+
</Link>
|
|
118
|
+
</div>
|
|
119
|
+
</CardContent>
|
|
120
|
+
</Card>
|
|
121
|
+
</div>
|
|
122
|
+
);
|
|
123
|
+
}
|