Skip to content

Live Demo

theGreenGuy edited this page Jun 19, 2026 · 5 revisions

Live demo (public sandbox)

A public, fully client-side sandbox of the real openWCS app, embedded on the marketing site at /live-demo. It is read-only, runs entirely in the visitor's browser over a snapshot of the demo box's data, and persists nothing: a page reload resets it. No login, no backend, no risk.

It is not a mockup or a fork. It is a build of the same /ui SPA that ships to production, so it reuses every component, the full sidebar, the menus, and the real screens. Authoritative detail: docs/public-live-demo-spec.md and docs/AS-BUILT.md §7j.

What a visitor gets

  • Lands on the Control room dashboard, populated from a snapshot of app.openwcs.ai.
  • Can open every menu read-only: dashboards, master data, operations, reporting, engineering, configuration, administration. The headline screens show snapshot data; the long tail renders clean empty states (the app already handles empty states gracefully). Every create / edit / delete control is hidden or disabled.
  • The Reporting screens (Stock, ASRS, Material flow, Inbound / Outbound) now render with data in the demo: the Reporting endpoints are mocked from a demo-box snapshot, so these screens show charts and figures instead of a blank screen.
  • The centrepiece interaction: at the goods-to-person (GTP) station, five totes arrive and the visitor picks them, full pick or short pick, including the normal exceptions (tote dirty / units broken).
  • A persistent banner reads "Live demo, sample data, nothing is saved" with a Restart action.

How it works (architecture)

The whole thing is a VITE_DEMO=true build of the existing SPA (npm run build:demo, asset base /demo-app/). The flag toggles three things and nothing else, so the production app and its tests are unaffected.

1. Synthetic read-only session

On boot (ui/src/demo/session.ts) a fixed demo session is seeded and Keycloak is skipped entirely (the login screen is never shown). The session resolves so can() is true for every screen (all menus visible) while canWrite() / writeAllowed() are false everywhere. Read-only is enforced by the same access-control machinery the real app uses.

2. Mock service layer (the core, and the security guarantee)

The SPA has a single network chokepoint: ui/src/lib/authFetch.ts, through which every /api, /admin and /realms call passes. In demo mode that chokepoint routes to ui/src/demo/mockApi.ts instead of the network, so no request ever leaves the browser (verified: zero offsite requests). This is a hard guarantee, not a convention: the demo build cannot reach or mutate any real service.

  • GET requests resolve from committed fixtures (below). Unknown GETs return a benign empty payload ([] / {} / a zeroed shape) so a screen renders an empty state, never an error.
  • Mutations (POST/PUT/DELETE) are no-op successes, except the whitelisted GTP pick-station endpoints, which are handled by the in-memory pick engine.

3. Fixtures (the demo-box snapshot)

GET responses are snapshotted from app.openwcs.ai by tools/demo-snapshot.mjs and committed under ui/src/demo/fixtures/*.json. Coverage is the headline screens: the dashboards (orders / inventory / SLA / dispatch, replenishment, ABC, automation summary, alerts and alert thresholds), master data (warehouses, SKUs, locations, areas, storage blocks, HU types), inventory (stock overview, handling units), orders (dispatch, pick-tasks), GTP workplaces and a few SKU cards, plus the Reporting datasets (inventory stock-by-sku and storage-density; flow scan-quality / traffic / transit-times / storage-movements / device-movements; orders flow by direction) so the /reporting/* screens render. emptyFor was hardened so any unmapped report path returns [] (the previously blank Stock screen was a crash from spreading an object as an array). This is honest sample data with real response shapes, frozen, not a claim of full data on every screen.

4. In-memory pick engine

ui/src/demo/pickEngine.ts holds the only "live" state. On demo start it arms 5 totes at the GTP station and walks the induction queue REQUESTED -> IN_TRANSIT -> QUEUED on a short timer so the queue visibly fills. It answers the GTP endpoints: present a tote, confirm a put full or short, close the cycle and present the next tote, plus the dirty-tote / broken-units exceptions. A reset() re-arms all five. No timers or state survive a reload, so there is no persistence.

5. No persistence, no leakage

All demo state is in JS memory. The fetch interceptor blocks every real network call. The build ships no secrets and no real tokens. A reload reconstructs everything from the fixtures.

Build and serve

# Build the demo variant of the SPA (asset base /demo-app/):
cd ui && npm run build:demo

# Then copy dist/* into public/static/demo/, OR do both in one step from /public:
cd public && npm run build:demo-app   # runs public/scripts/build-demo-app.js
  • The public page is public/views/pages/live-demo.ejs (route in public/data/pages.json); it embeds the demo full-bleed via <iframe src="/demo-app/">.
  • The public Express server (public/server.js) serves the bundle at /demo-app/ (static + SPA deep-link fallback) from public/static/demo, which is committed to the repo and travels with the public/ folder on every deploy. The openwcs.ai host (Hostinger Node app) only serves the public/ directory and has no ui/ build toolchain, so the bundle must be committed; if it were gitignored the /demo-app/ route would return 404.
  • Whenever a product change affects the demo, rebuild and re-commit: cd public && npm run build:demo-app then commit the updated public/static/demo/ (the folder is replaced wholesale, ~4 MB).
  • The primary nav Live demo points to this in-site sandbox, with a secondary Full demo box link to https://app.openwcs.ai.
  • CI runs npm run build:demo in the UI job, so the demo build cannot silently break.

Maintenance rule

The demo is a standing update target like the README, AS-BUILT, wiki and public site. Any relevant product change should keep the demo in step in the same change: new or renamed screens or menu sections, changed API response shapes, and any change to the picking flow or the GTP present / put / cycle contract the pick engine depends on. Concretely: refresh the affected fixtures (tools/demo-snapshot.mjs or hand-edit), keep mockApi.ts and its types in step with changed endpoints, ensure new screens still render read-only, and re-run the demo. Pure backend internals the demo never exercises do not require an update.

See also

Clone this wiki locally