One-page digital goods storefront with instant checkout, secure download links, and an authenticated admin console for managing orders, products, and operational settings. This project follows the "Digital Goods One-Page Store + Admin" PRD.
- Framework: Next.js 15 App Router, TypeScript
- Styling: Tailwind CSS 4, shadcn/ui, Geist font
- Auth: NextAuth.js (credentials)
- ORM/DB: Prisma + SQLite (file-based, easily swap to other drivers)
- State & Forms: React Hook Form, Zod, TanStack Query
- Email: Resend or SMTP (optional via env)
-
Install dependencies
npm install
-
Environment variables
- Copy
.env.exampleto.envand adjust values (setNEXTAUTH_SECRET, update store identity, etc.). DATABASE_URLdefaults tofile:./dev.db, which lives inside theprismadirectory.
- Copy
Create a .env file in the project root using values that match your stack. The snippet below mirrors a local SQLite setup with optional payment and storage providers disabled by default:
DATABASE_URL="file:./prisma/dev.db"
NEXTAUTH_SECRET="change-me"
# Branding
STORE_NAME="Digital Goods Store"
STORE_CONTACT_EMAIL="hello@store.test"
# Storage (leave empty for local filesystem fallback)
STORAGE_PROVIDER="local"
STORAGE_BASE_URL=""
STORAGE_BUCKET=""
# Download policy overrides
DOWNLOAD_EXPIRY_HOURS="72"
DOWNLOAD_MAX_COUNT="3"
# Optional email providers
RESEND_API_KEY=""
SMTP_URL=""
# Payment gateways (populate when integrating)
STRIPE_SECRET_KEY=""
MIDTRANS_SERVER_KEY=""
MIDTRANS_CLIENT_KEY=""
MIDTRANS_MERCHANT_ID=""
XENDIT_API_KEY=""
DUITKU_MERCHANT_CODE=""
DUITKU_API_KEY=""
# Auto QRIS worker (optional)
AUTOQRIS_WORKER_URL=""
AUTOQRIS_API_KEY=""
AUTOQRIS_STATIC_QRIS=""
# Cloudflare R2 (optional)
R2_ACCOUNT_ID=""
R2_ACCESS_KEY_ID=""
R2_SECRET_ACCESS_KEY=""
R2_BUCKET=""
R2_PUBLIC_BASE_URL=""
-
Initialize the database
- Apply the schema to SQLite using the provided migration SQL:
mkdir -p prisma sqlite3 prisma/dev.db < prisma/migrations/0001_init/migration.sql - Seed demo data (admin user + sample products):
npm run db:seed
Default admin credentials:
admin@demo.test/Admin123!
- Apply the schema to SQLite using the provided migration SQL:
-
Run the development server
npm run dev
Visit http://localhost:3000 to explore the storefront. Admin routes live under
/adminand require sign-in.
| Command | Description |
|---|---|
npm run dev |
Start local development server |
npm run build |
Build for production |
npm run start |
Start the production server |
npm run lint |
Run ESLint |
npm run db:seed |
Seed database with demo admin and products |
npm run db:migrate:d1 |
Generate SQL script for Cloudflare D1 migration |
src/
app/
(storefront, success page, auth, admin dashboards, API routes)
components/
admin/ // Admin UI widgets and forms
storefront/ // Storefront interactions (grid, checkout, etc.)
ui/ // shadcn/ui primitives
lib/
auth.ts // NextAuth configuration
prisma.ts // Prisma client helper
payments.ts // Webhook + token helpers
serializers.ts // Normalize DB payloads for UI/API
prisma/
migrations/ // SQL schema for SQLite
seed.ts // Demo data seeding script
- Storefront: search & tag filters, markdown product detail modal, checkout sheet integrated with active gateway configuration.
- Checkout Flow: creates orders, returns gateway instructions or redirect URLs (Stripe / Midtrans / Xendit / Duitku / Manual QRIS / Auto QRIS), issues download tokens on successful payment.
- Secure Downloads:
/api/download/:tokenenforces expiry & quota, with optional Cloudflare R2 signed URLs or custom storage domains. - Admin Console: dashboard metrics, order table + detail view (manual status updates & email resend), product CRUD (with file pointers), settings management for payment/storage/policies.
- Webhooks: Stripe, Midtrans, Xendit, and Duitku handlers map gateway payloads to unified order updates. Auto QRIS polling endpoint verifies payments against detected push notifications.
- Run
npm run lintbefore committing changes. - The project ships with sample products and an admin user via the seed script to accelerate manual QA.
- Webhook endpoints expect verified signatures in production. Current implementation focuses on payload handling; plug in verification when wiring to live gateways.
- Swap
DATABASE_URLto your production database (SQLite, Postgres, etc.) and re-run migrations. - Configure environment variables for the selected payment gateway, object storage, and email provider. For Duitku supply
DUITKU_MERCHANT_CODE/DUITKU_API_KEY(and optionallyDUITKU_BASE_URL). For Auto QRIS setAUTOQRIS_WORKER_URL,AUTOQRIS_API_KEY,AUTOQRIS_STATIC_QRIS, andAUTOQRIS_CALLBACK_URL(optional). To use Cloudflare R2 signed links, provideR2_ACCOUNT_ID,R2_ACCESS_KEY_ID,R2_SECRET_ACCESS_KEY, andR2_BUCKET(orR2_PUBLIC_BASE_URLif serving files via a public domain) and set the storage provider to R2 in the admin settings. next.config.tssetsimages.unoptimized = trueto support arbitrary remote assets (QR codes, marketing images). Adjust as needed for production CDN setups.- Remember to update
APP_BASE_URLto the deployed origin so receipt emails contain valid download links. - To target Cloudflare D1, run
npm run db:migrate:d1to emitprisma/d1-migration.sql, then apply it withwrangler d1 execute <DB_NAME> --remote --file prisma/d1-migration.sql.