Pixelle is a Next.js app that lets users upload a photo, configure a custom phone case, and purchase it via Stripe. It handles image uploads and dimensions, order creation and payment, webhook fulfillment, and transactional emails.
- Upload images with UploadThing; extract dimensions with Sharp
- Interactive case configurator with React/Framer Motion
- Auth via Kinde, user bootstrap on first login
- Orders and addresses in PostgreSQL via Prisma
- Stripe Checkout + verified webhooks
- Order confirmation emails via Resend
- App: Next.js 15, React 19, TypeScript, Tailwind CSS 4
- Auth: @kinde-oss/kinde-auth-nextjs
- DB/ORM: PostgreSQL + Prisma
- Payments: Stripe
- Uploads: UploadThing
- Email: Resend
- User logs in with Kinde (server action ensures a User row exists).
- User uploads an image via UploadThing. On complete, we create/update a
ConfigurationwithimageUrl,width,height(from Sharp metadata). - User customizes a case (color/model/material/finish) and proceeds to checkout.
- Stripe Checkout completes; Stripe webhook (
/api/webhook) setsOrder.isPaid = trueand creates shipping/billing addresses. - Resend sends an order confirmation email using
OrderReceivedEmail.
Database models are in prisma/schema.prisma; Prisma Client is generated to src/generated/prisma and consumed via src/db.
- Node.js 18.18+ (20+ recommended)
- A PostgreSQL database (local Docker, Neon, Supabase, RDS, etc.)
- Stripe account + Stripe CLI (for local webhooks)
- Kinde account and app (OIDC)
- UploadThing account
- Resend account
Create a .env or .env.local file in the project root with these variables:
# Database
DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DBNAME?schema=public"
# Stripe
STRIPE_SECRET_KEY="sk_live_or_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..." # Set after starting Stripe CLI listen (see below)
# Kinde (OIDC)
KINDE_ISSUER_URL="https://your-subdomain.kinde.com"
KINDE_CLIENT_ID="..."
KINDE_CLIENT_SECRET="..."
KINDE_REDIRECT_URI="http://localhost:3000/api/auth/kinde/callback"
KINDE_POST_LOGOUT_REDIRECT_URI="http://localhost:3000/"
# UploadThing
UPLOADTHING_SECRET="..."
UPLOADTHING_APP_ID="..."
# Resend
RESEND_API_KEY="re_..."
Notes
- The app uses the Prisma Client from
src/generated/prisma. - Stripe webhook secret is provided by Stripe CLI after you start
stripe listen.
- Install dependencies
npm ciThis will also run prisma generate via postinstall.
- Initialize the database schema (choose one)
# Recommended: create a migration and apply it
npx prisma migrate dev --name init
# Or: push schema without creating a migration (dev only)
npx prisma db push- (Optional, local only) Start Stripe webhook forwarding
# Forward events to the webhook route; copy the given signing secret into STRIPE_WEBHOOK_SECRET
stripe listen --forward-to http://localhost:3000/api/webhook- Run the app
npm run devnpm run dev— start Next.js (Turbopack) in developmentnpm run build— production buildnpm run start— start the production servernpm run lint— run ESLint
- UI pages:
src/app/** - API routes:
- Uploads:
src/app/api/uploadthing/* - Stripe webhook:
src/app/api/webhook/route.ts(POST)
- Uploads:
- Auth bootstrap:
src/app/auth-callback/actions.ts - Prisma schema:
prisma/schema.prisma - Prisma client:
src/generated/prisma(imported via@/generated/prismaand@/db) - Stripe client:
src/lib/stripe.ts - UploadThing helpers:
src/lib/uploadthing.ts - Email template:
src/components/emails/OrderReceivedEmail.tsx
- Configure the same environment variables in your hosting provider (e.g., Vercel).
- Set your production Stripe webhook to point to
/api/webhookand updateSTRIPE_WEBHOOK_SECRET. - Ensure your Prisma
DATABASE_URLpoints to your production Postgres.
- Prisma client not found or types missing: run
npx prisma generate. - DB connection issues: verify
DATABASE_URLand that the DB accepts connections from your machine. - Stripe webhook errors: confirm the
stripe-signatureheader arrives andSTRIPE_WEBHOOK_SECRETmatches the activestripe listensession. - Sharp install issues on Windows: ensure you are on a supported Node version; reinstall with
npm ci.
This project is open source and available under the MIT License.