A complete, production-shaped appointment-booking app — built with Vite + React
- TypeScript, no CSS framework, no backend required. It's the scheduling example app that ships with Adminium: browse a service menu, pick a stylist and a real open time slot, book, reschedule or cancel, buy a gift card, and manage the whole day from a staff-side calendar — all from built-in demo data.
Live demo → adminium.dev/demo/booking-scheduler
npm install
npm run devThen open the URL Vite prints (default http://localhost:5173).
-
Vercel — click the button above, or import the repo. Build command
npm run build, outputdist. -
DigitalOcean App Platform — click the button above, or use the included
.do/deploy.template.yaml. -
Host anywhere —
npm run buildproduces a fully staticdist/you can drop on any static host (Netlify, Cloudflare Pages, S3, GitHub Pages…). Or build the container:docker build -t booking-scheduler . docker run -p 8080:80 booking-scheduler
| Script | What it does |
|---|---|
npm run dev |
Start the Vite dev server. |
npm run build |
Type-check + build to dist/ at base / (root deploys). |
npm run build:demo |
Build to dist/ at base /demo/booking-scheduler/ (Adminium demo). |
npm run preview |
Preview a production build locally. |
docker compose up starts booking-db, the Postgres database behind the
self-host stack. On first boot it applies db/schema.sql, installs the demo
bookkeeping, then runs a hook that by default loads db/seed.sql — Lumen
Studio's service menu, specialists and appointments — so the database has
working data the moment it comes up.
To start empty instead, with the same full schema, set DEMO_DATA=0 in .env
before the first docker compose up. Neither choice is permanent — four
scripts move the demo rows in and out afterwards:
| Script | What it does |
|---|---|
npm run demo:status |
Report what is loaded, table by table. |
npm run demo:import |
Load db/seed.sql. |
npm run demo:wipe |
Remove the demo rows — your own rows and the schema stay. |
npm run demo:reset |
Wipe, then import a fresh copy. |
A wipe deletes only the rows the ledger attributes to the seed, so the schema
stays and, with one exception, so does anything you added yourself. A demo row
your own data depends on is kept rather than force-deleted, and reported under
kept. The exception is ON DELETE CASCADE: time off you entered against a
demo stylist goes when that stylist does, and those rows are counted
separately as cascaded. wipe and reset ask before they act; pass
-- --yes to skip the question. DATABASE_URL points all four at a Postgres
somewhere else. Full reference: db/README.md.
All scheduling data goes through a thin DataSource interface
(src/data/source.ts) with a single demoSource
implementation backed by the bundled demo business. To be honest about what runs
today: nothing is persisted and nothing is charged — bookings, gift cards and
cancellations live in memory for the length of the session, and reloading the
page resets everything.
Once Adminium's browser-safe publishable key (adm_pub_…) ships, the
frontend will read and write live data — your real services, staff,
availability and appointments from an Adminium-managed database — through the
Adminium records API via a second DataSource implementation, without touching
any of the screens or the store. The seam is already in place.
AGPL-3.0 © 2026 Booking Scheduler. A demo shipped with Adminium.
The Adminium skills teach Claude Code, Codex and other agents to build and change an app:
npx skills add Adminiumjs/skills — https://github.com/Adminiumjs/skills