Production-ready Next.js webshop engine for fork-and-deploy workflows with:
- runtime shop customization from
/admin/info(branding/theme/SEO), - MongoDB persistence,
- Docker-first deployment,
- optional integrations for payments, shipping, invoicing, and email.
- Reusable base: one codebase, many shop deployments.
- Safe promotions: Docker image tags by branch and commit SHA.
- Runtime branding: adjust store identity without rebuilding code.
- Portable hosting: run with Docker Compose, custom VPS, or Vercel.
- Next.js 16 (App Router)
- Node.js 20
- MongoDB
- Auth.js / NextAuth (Google provider)
- Docker + Docker Compose
npm installStart from this minimal local setup:
DATABASE_URL=mongodb://root:example@localhost:27017/webshop?authSource=admin
NEXT_PUBLIC_APP_URL=http://localhost:3000
NEXTAUTH_URL=http://localhost:3000
AUTH_URL=http://localhost:3000
AUTH_TRUST_HOST=true
AUTH_SECRET=replace-with-long-random-secret
AUTH_GOOGLE_ID=replace-with-google-client-id
AUTH_GOOGLE_SECRET=replace-with-google-client-secretYou can run MongoDB with Docker and app in dev mode:
docker compose up -d mongo
npm run devOpen http://localhost:3000.
- Sign in.
- Promote your user to admin in MongoDB if needed.
- Open
/admin/info. - Configure branding, theme, and SEO values.
The repository includes:
Dockerfile(multi-stage Next.js production build),docker-compose.yml(app + MongoDB + uploads volume mapping).
- Create
.envin project root (see environment variable reference below). - Start the stack:
docker compose up -d --build- Check logs:
docker compose logs -f app- Stop:
docker compose downApp is exposed on http://localhost:3000, MongoDB on localhost:27017.
- Database: named volume
mongo-data. - Uploads: bind mount
./uploads:/app/uploads.
This keeps product images/files between container recreations.
- Install Docker Engine + Docker Compose plugin.
- Open ports (
80/443via reverse proxy, app internally on3000). - Set up DNS for your domain.
At minimum:
DATABASE_URL(managed MongoDB or self-hosted Mongo),NEXT_PUBLIC_APP_URLandNEXTAUTH_URLas your canonical HTTPS domain,AUTH_SECRETstrong random secret,AUTH_GOOGLE_ID/AUTH_GOOGLE_SECRETwith matching callback URL.
docker compose pull
docker compose up -d --build- Homepage loads on your domain.
- Google login works.
/admin/infoaccessible for admin.- Media upload and retrieval work.
Values are grouped by required core, recommended, and feature-specific variables.
| Variable | Required | Purpose | Example |
|---|---|---|---|
DATABASE_URL |
Yes | MongoDB connection string used by the app at startup. App throws if missing. | mongodb://root:example@mongo:27017/webshop?authSource=admin |
NEXT_PUBLIC_APP_URL |
Yes | Public base URL used in generated links and callbacks. | https://shop.example.com |
NEXTAUTH_URL |
Yes | Auth.js canonical URL for callback/session handling. | https://shop.example.com |
AUTH_SECRET |
Yes | Auth.js signing/encryption secret. | openssl rand -base64 32 output |
AUTH_GOOGLE_ID |
Yes (if using built-in login) | Google OAuth client ID. | 123456.apps.googleusercontent.com |
AUTH_GOOGLE_SECRET |
Yes (if using built-in login) | Google OAuth secret. | your-google-secret |
| Variable | Required | Purpose | Example |
|---|---|---|---|
AUTH_URL |
Recommended | Explicit auth origin, useful behind reverse proxies. | https://shop.example.com |
AUTH_TRUST_HOST |
Recommended | Trust forwarded host headers (true for proxy/Vercel setups). |
true |
ENABLE_SHOP |
Optional | Set to false to ship this codebase as landing/CMS-only (hides storefront, cart, checkout, profile, shop admin, related APIs). Omit or use any value other than false for full commerce. |
false |
| Variable | Required | Purpose | Example |
|---|---|---|---|
NEXT_PUBLIC_GTM_ID |
Optional | Google Tag Manager container ID (loads after cookie consent). | GTM-KZNTSD4M |
NEXT_PUBLIC_META_PIXEL_ID |
Optional | Meta (Facebook) Pixel ID (loads after cookie consent). | 1618980845831904 |
NEXT_PUBLIC_ANALYTICS_ENABLED |
Optional | Set to false to disable marketing tags entirely. |
true |
See docs/integrations/analytics-gtm-meta.md for GTM/GA4 setup and event mapping.
| Variable | Required | Purpose | Example |
|---|---|---|---|
BOOTSTRAP_ADMIN_EMAILS |
Optional | Comma-separated allowlist of emails promoted to ADMIN on first login when no ADMIN exists yet. Remove after onboard. | [email protected] |
| Variable | Required | Purpose | Example |
|---|---|---|---|
EMAIL_HOST |
Optional (needed for real email delivery) | SMTP server hostname. | smtp.sendgrid.net |
EMAIL_PORT |
Optional | SMTP port. | 587 |
EMAIL_USER |
Optional | SMTP username. | apikey |
EMAIL_PASS |
Optional | SMTP password/token. | *** |
EMAIL_FROM |
Optional | Sender address used by transactional mail. | [email protected] |
EMAIL_FROM_NAME |
Optional | Display name in the inbox “From” field (order mails, newsletters, password reset). | My Shop Name |
Mailer logs (Vercel / server): search runtime logs for the prefix [mailer]. Events are JSON lines, e.g. send_start, send_success, send_failed, smtp_env_incomplete, order_confirmation_skipped. SMTP passwords are never logged; to addresses are masked. Optional MAILER_VERIFY_SMTP=1 runs nodemailer verify() before send (slower, good for debugging). Optional MAILER_LOG_STACK=1 includes stack traces on errors in any environment.
| Variable | Required | Purpose | Example |
|---|---|---|---|
STRIPE_SECRET_KEY |
Required when Stripe features are used | Server-side Stripe API access. | sk_live_... |
STRIPE_WEBHOOK_SECRET |
Required when Stripe webhooks are enabled | Signature validation for webhook endpoint. | whsec_... |
Webhooks: point Stripe at https://<your-domain>/api/stripe/webhook and subscribe to the events listed in docs/integrations/STRIPE_WEBHOOK_SETUP.md (including payment_intent.canceled for hold release when Checkout session events are delayed). That doc also covers API version alignment with the stripe npm package and step-by-step Dashboard setup. For local development, use the Stripe CLI (stripe listen --forward-to localhost:3000/api/stripe/webhook) and paste the CLI signing secret into STRIPE_WEBHOOK_SECRET (it differs from the Dashboard endpoint secret).
Inventory holds (Stripe checkout): stock is reserved when the Checkout Session is created. Optional tuning (defaults are safe with Stripe’s minimum session lifetime):
| Variable | Required | Purpose | Example |
|---|---|---|---|
RESERVATION_TTL_MIN_MS |
Optional | Minimum hold duration (ms). Default 30 minutes (aligns with Stripe). | 1800000 |
RESERVATION_TTL_MAX_MS |
Optional | Maximum hold (ms). Default 60 minutes. | 3600000 |
RESERVATION_STRIPE_SESSION_BUFFER_SEC |
Optional | Stripe session ends this many seconds before DB hold. Default 60. |
60 |
CRON_SECRET |
Optional | Bearer secret for POST /api/internal/reservations/sweep to release expired pending holds. |
long random string |
| Variable | Required | Purpose |
|---|---|---|
GLS_API_USERNAME |
Required for GLS | GLS API username |
GLS_API_PASSWORD |
Required for GLS | GLS API password |
GLS_CLIENT_NUMBER |
Required for GLS | GLS client/customer number |
GLS_PICKUP_NAME |
Required for GLS | Pickup point/company name |
GLS_PICKUP_STREET |
Required for GLS | Pickup street |
GLS_PICKUP_HOUSE_NUMBER |
Required for GLS | Pickup house number |
GLS_PICKUP_CITY |
Required for GLS | Pickup city |
GLS_PICKUP_ZIP |
Required for GLS | Pickup ZIP/postcode |
GLS_API_BASE_URL |
Optional | API URL (defaults to test endpoint) |
GLS_WEBSHOP_ENGINE |
Optional | Webshop identifier sent to GLS |
GLS_PRINTER_TYPE |
Optional | Label format (default A4_2x2) |
GLS_PICKUP_HOUSE_NUMBER_INFO |
Optional | Extra house number info |
GLS_PICKUP_COUNTRY_ISO |
Optional | Pickup country ISO (default HU) |
GLS_PICKUP_CONTACT_NAME |
Optional | Pickup contact person |
GLS_PICKUP_CONTACT_PHONE |
Optional | Pickup contact phone |
GLS_PICKUP_CONTACT_EMAIL |
Optional | Pickup contact email |
GLS_SHIPPING_METHOD_NAME |
Optional | Display name for GLS shipping method |
Enable the four GLS/Foxpost flags under Admin → Beállítások (/admin/info): picker (checkout) and manager (admin labels). Full setup: docs/integrations/parcel-locker-gls-foxpost.md.
Create active shipping methods named GLS Csomagpont and/or Foxpost Csomagautomata (or override GLS_SHIPPING_METHOD_NAME / FOXPOST_SHIPPING_METHOD_NAME).
Checkout uses the official Foxpost APT finder iframe (cdn.foxpost.hu). Admin order detail can create parcels and download labels via FoxWeb API.
| Variable | Required | Description |
|---|---|---|
FOXPOST_API_USERNAME |
Required for Foxpost | Basic auth username (from foxpost.hu Beállítások) |
FOXPOST_API_PASSWORD |
Required for Foxpost | Basic auth password |
FOXPOST_API_KEY |
Required for Foxpost | API key header value |
FOXPOST_API_BASE_URL |
Optional | API base (default sandbox https://webapi-test.foxpost.hu/api) |
FOXPOST_SHIPPING_METHOD_NAME |
Optional | DB shipping method name to match (default Foxpost Csomagautomata) |
FOXPOST_PARCEL_SIZE |
Optional | Parcel size at create time (default M) |
FOXPOST_LABEL_PAGE_SIZE |
Optional | Label PDF size: A6, A7, _85X85 (default A6) |
FOXPOST_IS_WEB |
Optional | Set true to pass isWeb=true on parcel create (default false on sandbox) |
Set one authentication mode:
SZAMLAZZ_AGENT_KEY, orSZAMLAZZ_USER+SZAMLAZZ_PASSWORD
Optional invoicing settings:
SZAMLAZZ_TIMEOUT_MSSZAMLAZZ_SELLER_BANK_NAMESZAMLAZZ_SELLER_BANK_ACCOUNTSZAMLAZZ_ISSUER_NAMESZAMLAZZ_EMAIL_SUBJECTSZAMLAZZ_EMAIL_MESSAGE
| Variable | Required | Purpose |
|---|---|---|
NEWSLETTER_UNSUBSCRIBE_SECRET |
Optional (recommended) | Secret token for unsubscribe verification fallback. |
# Development
npm run dev
# Local only (before deploy / after inventory changes): integration + in-memory Mongo race tests.
# Not run in CI — no database, dev server, or Stripe CLI in the pipeline.
npm run test:predeploy
# Race tests only (mongodb-memory-server bundled; no external Mongo required)
npm run test:concurrency
# Optional local Stripe checkout race (needs RUN_STRIPE_RACE_TESTS=1 and STRIPE_SECRET_KEY in .env)
npm run test:concurrency:stripe
# Production build
npm run build
npm run start
# Lint
npm run lint
# Tests
npm run testSee docs/README.md for the full index. Quick links:
- Fork / deployment engine: docs/deployment/FORK_DEPLOYMENT_ENGINE.md
- Vercel + custom domain: docs/deployment/VERCEL_CUSTOM_DOMAIN_DEPLOYMENT.md
- Portability: docs/deployment/PORTABILITY.md
- Google OAuth: docs/auth/GOOGLE_OAUTH_SETUP.md
- Auth PKCE verification: docs/auth/AUTH_PKCE_VERIFICATION.md
- Stripe webhooks: docs/integrations/STRIPE_WEBHOOK_SETUP.md
- Számlázz.hu invoicing: docs/integrations/szamlazzhu-integration.md
- Templates (human spec + agent brief): docs/templates/CREATING_A_TEMPLATE.md, docs/templates/AI_AGENTS_TEMPLATE_GUIDE.md
- Homepage block CMS: docs/cms/HOMEPAGE_BLOCKS_CMS_ARCHITECTURE.md