Building blocks for digital commerce
Crazy Tees ecommerce monorepo — Medusa v2 API + Next.js storefront on branch feature/medusa-mvp, scaffolded from ltbongo/medusa-next-starter (B9 Design template).
| App | Path |
|---|---|
| Medusa backend + admin | apps/backend |
| Next.js storefront | apps/storefront |
Related: the public static marketing demo stays on main (tagged releases / crazytees.demo.b9design.co.za). Commerce work lives on feature/medusa-mvp in this repo.
- Root overview:
.env.example - Backend: copy
apps/backend/.env.template→apps/backend/.env - Storefront: copy
apps/storefront/.env.template→apps/storefront/.env.local
Default storefront region is South Africa (NEXT_PUBLIC_DEFAULT_REGION=za).
Requirements: Node.js 22 LTS, Docker (for local Postgres + Redis), npm 11+.
git clone https://github.com/ltbongo/crazytees.git
cd crazytees
git checkout feature/medusa-mvp
npm install --include=dev- Start data services:
docker compose up -d(Postgres 15 + Redis 7 onlocalhost). - Backend env:
cp apps/backend/.env.template apps/backend/.env— defaults matchdocker-compose.yml(DATABASE_URL,REDIS_URL, CORS for local Next.js). - Seed demo catalogue (South Africa region, B9 demo products plus Crazy Tees tees/mugs):
cd apps/backend && npm run seed
The seed adds 3 tees and 2 mugs (handles prefixedct-) with size/colour variants, on top of the migration baseline. Re-runnpm run seed:crazyteesto add only the Crazy Tees catalogue on an existing DB.
The command runs migrations and prints the publishable API key token for the storefront. You can also copy it later from Medusa admin → Settings → Publishable API Keys (http://localhost:9000/app). - Create an admin user (once):
cd apps/backend && npx medusa user -e admin@test.com -p <password> - Start backend:
npm run dev(fromapps/backend) — admin athttp://localhost:9000/app. - Storefront env:
cp apps/storefront/.env.template apps/storefront/.env.localand setNEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEYto the key from step 3. - Start storefront:
cd apps/storefront && npm run dev→http://localhost:8000(use country codezain the URL path when browsing regions).
Storefront production build (CI / Docker image): the default npm run build sets B9_STOREFRONT_OFFLINE_BUILD=1, which skips Medusa-backed static path generation so the image can build without a live API. You still need NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY set (any non-empty placeholder is enough for the env check).
cd apps/storefront
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=pk_... npm run buildFull static prerender (optional, closer to upstream Medusa): unset the offline flag and run the backend during build:
B9_STOREFRONT_OFFLINE_BUILD=0 NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=pk_... npm run buildUses the same Docker patterns as the B9 Medusa template (docker-compose.dokploy.yml, per-app Dockerfiles). Staging hostnames will be configured when this stack is wired on Dokploy (Crazy Tees delivery plan BDE-856).
After the first deploy, copy the publishable API key from backend seed logs into NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY and redeploy the storefront. Public pages stay open; admin uses the app login (b9demo + company demo credential pattern).
PayFast credentials and mode are set on the Medusa backend (apps/backend), not in the Next.js storefront bundle. Copy apps/backend/.env.template and configure the variables below in Dokploy (or your host env). Never commit merchant keys, passphrases, or live credentials to git.
| Variable | Purpose |
|---|---|
PAYFAST_MERCHANT_ID |
PayFast merchant ID (numeric) |
PAYFAST_MERCHANT_KEY |
PayFast merchant key |
PAYFAST_PASSPHRASE |
Salt passphrase from the PayFast dashboard (required in live mode; strongly recommended in sandbox) |
PAYFAST_SANDBOX |
true = sandbox hosts and checkout; false = live PayFast |
SITE_URL |
Public https storefront origin (no trailing slash); used for return/cancel URLs |
MEDUSA_BACKEND_URL |
Public https Medusa API origin (no trailing slash); used to build the ITN notify_url |
- Sandbox:
PAYFAST_SANDBOX=true. Use sandbox merchant credentials from your own PayFast sandbox account (B9 stores these as Paperclip secrets for staging; DevOps maps them onto the variable names above). - Live:
PAYFAST_SANDBOX=false. Live merchant ID, key, and passphrase are supplied only by Ludwig via Paperclip secrets and applied by DevOps — do not paste them in issues, chat, or the repo.
You can also set PAYFAST_MODE to sandbox or live if PAYFAST_SANDBOX is unset; prefer PAYFAST_SANDBOX=true/false for per-client Dokploy env.
PayFast posts ITNs to the Medusa API. The checkout notify_url is:
https://<medusa-api-host>/hooks/payfast/itn
Example on the B9 reference stack: https://medusa-next-starter-api.demo.b9design.co.za/hooks/payfast/itn (replace the hostname with the client’s Medusa API URL on Dokploy).
Medusa also accepts the provider webhook path https://<medusa-api-host>/hooks/payment/payfast (same handler). The route must be publicly reachable over HTTPS, must not sit behind site-wide basic auth, and must return HTTP 200 when the ITN is processed. See PayFast’s ITN documentation: Instant Transaction Notification.
Optional: PAYFAST_CLIENT_IP_HEADER (default x-real-ip) if a CDN or proxy sits in front of the API.
A production-ready monorepo starter for direct-to-consumer ecommerce stores powered by Medusa and Next.js. Includes a fully featured storefront with product browsing, cart, checkout, customer accounts, and order management.
- All of Medusa's commerce features
- Multi-region support with automatic country detection
- Product catalog with variant selection
- Cart with promotion codes
- Multi-step checkout with shipping and payment
- Customer accounts with order history and address management
- Order transfer between accounts
The fastest way to get started is deploying with Medusa Cloud:
- Create a Medusa Cloud account
- Deploy this starter directly from your dashboard
**Prerequisites:
- Node.js v20+
- PostgreSQL v15+
- pnpm v10+
- Clone the repository and install dependencies:
git clone https://github.com/medusajs/dtc-starter.git
cd dtc-starter
pnpm install- Set up environment variables for the backend:
cp apps/backend/.env.template apps/backend/.env- Set the database URL in
apps/backend.env:
# Replace with actual database URL, make sure the database exists.
DATABASE_URL=postgres://postgres:@localhost:5432/medusa-dtc-starter- Run migrations:
cd apps/backend
pnpm medusa db:migrate- Add admin user:
cd apps/backend
pnpm medusa user -e admin@test.com -p supersecret- Start Medusa backend:
cd apps/backend
pnpm dev-
Open the admin dashboard at
localhost:9000/appand log in. Retrieve your publishable API key at Settings > Publishable API key. -
Set up environment variables for the storefront:
cp apps/storefront/.env.template apps/storefront/.env.local- Update
apps/storefront/.env.localwith your Medusa publishable API key:
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY=pk_6c3...- Start storefront:
cd apps/storefront
pnpm devThe storefront runs on http://localhost:8000.
You can slo run the following command from the root to start both backend and storefront:
pnpm devThe storefront is configured via environment variables in apps/storefront/.env.local:
| Variable | Description | Default |
|---|---|---|
NEXT_PUBLIC_MEDUSA_PUBLISHABLE_KEY |
Publishable API key from your Medusa backend | — |
NEXT_PUBLIC_MEDUSA_BACKEND_URL |
URL of your Medusa backend | http://localhost:9000 |
NEXT_PUBLIC_DEFAULT_REGION |
Default region country code | dk |
NEXT_PUBLIC_BASE_URL |
Base URL of the storefront | https://localhost:8000 |
NEXT_PUBLIC_STRIPE_KEY |
Stripe publishable key (optional) | — |