Running a public demo
A demo lets prospective buyers sign in and try Proventory before they buy. It must be a separate deployment with its own database, never your real customers' site.
What the demo gives visitors
- A working business, Demo Foodstuff Mart: 16 products with stock, 8 customers, 3 suppliers, sales (cash, transfer, card and on credit), invoices, expenses, 4 staff and a live Christmas sales page.
- Two logins, one click each from
/demo:- Owner: full access.
- Cashier: what a shop assistant sees.
- Both can also sign in on
/signinwith the email and password shown on the demo page. - An online store at
/find/b/demo-foodstuff-martand a sales page at/s/demo-foodstuff-mart/festive-foodstuff-deals.
What is switched off in the demo
Billing and plan changes, payment keys and bank accounts, two-factor setup, inviting or removing team members, creating more businesses, business verification, emailing documents, test emails, password reset and sign-up. Everything else works. The two demo logins never lock after wrong passwords, so one visitor's typo cannot block everyone else.
Set it up (about 30 minutes)
1. A new database. In Neon create a second project, for example proventory-demo. Copy its two connection strings: the direct one (owner, not pooled) and the pooled one. Do not reuse your real database.
2. Create the tables and the app role (once, from your computer, in a temporary command window; do not save these values in a file):
set DIRECT_URL=postgresql://OWNER:PASSWORD@HOST/DBNAME?sslmode=require
set DATABASE_URL=postgresql://bmt_app:CHOOSE_A_PASSWORD@HOST/DBNAME?sslmode=require
npx prisma migrate deploy
npm run db:roles
bmt_app is the restricted role the live app uses; the password you choose here goes into the pooled URL in step 3.
3. A new Vercel project. Add New, Project, import the same GitHub repository. Under Settings, Git, set the Production Branch to the branch that has the demo code (claude/dreamy-dirac-idduc8, or main after you merge it). Add these environment variables for Production:
| Name | Value |
|---|---|
DATABASE_URL |
the demo pooled URL, user bmt_app (add ?pgbouncer=true&connection_limit=5) |
DIRECT_URL |
the demo direct owner URL |
APP_URL |
https://YOUR-DEMO-SITE (no trailing slash) |
APP_SECRET |
a new random value, 32+ characters |
CRON_SECRET |
a new random value, 16+ characters |
DEMO_MODE |
true |
Leave out the payment and email provider keys. Make random values with node -e "console.log(require('crypto').randomBytes(32).toString('hex'))". |
4. Deploy. Migrations run automatically on a production deploy when DIRECT_URL is set.
5. Load the demo data once. From any computer with curl (use your own address and secret):
curl -H "Authorization: Bearer YOUR_CRON_SECRET" https://YOUR-DEMO-SITE/api/cron/demo-reset
It answers with the new business and how many seconds it took. If it times out, run it from your computer instead, with the demo URLs set as in step 2: set DEMO_MODE=true then npm run demo:reset.
6. Check it. Open https://YOUR-DEMO-SITE/demo and click through both logins. Open the store and sales page links on that page.
Keeping it fresh
vercel.json calls /api/cron/demo-reset every night at 02:00 (UTC), which builds a fresh business with the original data. The old one is closed and its address is reused, so links on your listing keep working. Ledger tables cannot be deleted by design, so old demo businesses stay in the database, closed. They are small.
On the marketplace listing
- Trial or demo link:
https://YOUR-DEMO-SITE/demo - Credentials, if the form asks:
demo.owner@example.com/Try-Proventory-2026
Honest limits
- All sample activity is dated the day it is built, so charts show one day of history that grows as visitors use it.
- Email, payments and SMS are not live in the demo. Visitors cannot see those parts working.
- The demo is shared: visitors can see each other's changes until the nightly reset.