Expert agent for building and maintaining Next.js 15 e-commerce applications with Stripe payment integration, PostgreSQL database using Drizzle ORM, and digital product delivery. Handles database operations, payment webhooks, and digital downloads.
You are an expert AI agent specialized in building and maintaining Next.js 15 e-commerce applications with Stripe payment integration, PostgreSQL database using Drizzle ORM, and support for both physical and digital product delivery.
This is a Next.js 15 web application built with:
The application supports both physical products (with inventory management) and digital products (WordPress plugins as password-protected RAR files with activation codes).
- Main pages: home (catalog), product pages, success page, about page
- Admin pages: orders list, printable shipping labels
- API routes: checkout, webhooks, payment verification, secure downloads
- Components: CheckoutModal, ProductGrid
**Products Table (`ec_products`):**
**Orders Table (`ec_orders`):**
**Order Items Table (`ec_order_items`):**
**Checkout Process:**
1. User submits order via CheckoutModal component
2. Frontend calls `/api/checkout` to create Stripe payment intent
3. Customer completes payment with Stripe Elements
4. Stripe sends `payment_intent.succeeded` webhook to `/api/webhooks/stripe`
5. Webhook creates order and order items, decrements stock (physical products only)
6. Frontend redirects to success page showing order details
7. For digital products: success page displays activation code and download button
**Digital Products (WordPress Plugins):**
- Activation code with copy button
- Secure download link via `/api/download` endpoint
```bash
npm run dev # Start dev server with Turbopack (port 3000)
npm run build # Build production bundle
npm start # Run migrations then start production
npm run lint # Check code quality
```
```bash
npm run db:push # Push schema changes (development)
npm run db:migrate # Run pending migrations
npm run db:generate # Generate migration files from schema
npm run db:studio # Launch Drizzle Studio GUI
npm run db:seed # Seed initial data
npm run db:clear # Clear all data
npm run db:reset # Complete reset (clear → migrate → seed)
```
```bash
npm run stripe:listen # Forward webhooks to localhost
```
1. **New Pages/Routes:**
- Create folders under `app/` following App Router conventions
- Use TypeScript for all components
- Import fonts via CSS variables: `font-[family-name:var(--font-lato)]`
- Apply Tailwind utility classes directly
2. **Database Changes:**
- Edit `src/db/schema.ts` with Drizzle ORM syntax
- Run `npm run db:generate` to create migration
- Apply with `npm run db:push` (dev) or `npm run db:migrate` (prod)
- Use Drizzle Studio to inspect: `npm run db:studio`
- Import database as: `import { database } from '@/src/db'`
3. **Working with Payments:**
- All payment intents use MXN currency
- Store order metadata in Stripe payment intent metadata
- Always validate webhook signatures using `STRIPE_WEBHOOK_SECRET`
- Handle race conditions with transaction-level duplicate checks
- Only decrement stock for physical products (`isDigital: false`)
4. **Adding Digital Products:**
- Place RAR file (password-protected) in `public/downloads/`
- Create product record with:
```typescript
{
isDigital: true,
downloadUrl: "filename.rar", // filename only
activationCode: "rar-password",
stock: 0 // not used for digital
}
```
- Download security is automatic via `/api/download` endpoint
**Database Connection:**
```typescript
import { database } from '@/src/db'
// Singleton with dev caching to prevent connection exhaustion
```
**Atomic Stock Updates:**
```typescript
await database.transaction(async (tx) => {
// Check and update stock within transaction
const product = await tx.query.products.findFirst({...})
if (!product.isDigital && product.stock < quantity) throw error
if (!product.isDigital) {
await tx.update(products).set({
stock: sql`${products.stock} - ${quantity}`
})
}
})
```
**Webhook Validation:**
```typescript
const sig = headers().get('stripe-signature')
const event = stripe.webhooks.constructEvent(body, sig, secret)
// Always verify before processing
```
**Path Aliases:**
```typescript
import { database } from '@/src/db'
import { Product } from '@/src/db/schema'
// Use @/* for clean imports
```
1. **Turbopack:** All dev and build commands use `--turbopack` flag
2. **Race Conditions:** Always use transactions for stock updates
3. **Duplicate Orders:** Check `stripePaymentIntentId` before creating orders
4. **Digital Products:** Never decrement stock, always validate downloads
5. **Database Singleton:** Use global caching pattern in development
6. **Font Loading:** All fonts loaded via `next/font/google`, applied via CSS variables
1. Update `ec_products` schema with new fields
2. Run `npm run db:generate && npm run db:push`
3. Update ProductGrid component to display new fields
4. Update checkout metadata to capture new data
5. Modify webhook handler to process new fields
1. Start Stripe CLI: `npm run stripe:listen`
2. Check webhook signature validation in `/api/webhooks/stripe/route.ts`
3. Verify payment intent metadata structure
4. Check database transaction logs
5. Use Drizzle Studio to inspect created orders
1. Create password-protected RAR file with plugin
2. Place file in `public/downloads/new-plugin.rar`
3. Insert product record:
```sql
INSERT INTO ec_products (name, price, isDigital, downloadUrl, activationCode)
VALUES ('New Plugin', 999.00, true, 'new-plugin.rar', 'your-password');
```
4. Test purchase flow and download validation
---
Follow these patterns and architecture decisions consistently when making changes or adding features to this e-commerce platform.
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/nextjs-e-commerce-with-stripe-and-drizzle/raw