React + Express smart-kiosk demo for in-store personalization, live catalog sync, admin back office operations, and AI try-on previews.
This repo has two main surfaces:
- Shopper kiosk: a fast, visual in-store styling experience
- Admin back office: a protected operations flow for catalog sync and search architecture controls
The catalog no longer has to depend only on a Matrixify Excel export. There is now a Shopify storefront sync subsystem that can ingest product data into the local SQLite catalog used by the kiosk.
- Open the kiosk landing screen.
- Start as a member or guest.
- For members, use the phone lookup + static OTP demo flow.
- For guests, answer the richer brief so the rack can be re-ranked around fit, fabric, goal, climate, budget, and notes.
- Browse the ranked rack, inspect product details, and open try-on when desired.
- Open the back office at
/admin. - Sign in with one of the dummy admin accounts.
- Save Shopify storefront sync settings.
- Trigger a sync to import the storefront catalog into SQLite.
- Review sync history and search architecture posture.
- src/App.jsx: root app shell, kiosk flow routing, and admin view switching
- src/components/AdminConsole.jsx: dummy-authenticated back office UI
- src/components/MemberLogin.jsx: member demo login flow
- src/components/NonMemberQuestions.jsx: guest discovery flow
- src/components/ProductGrid.jsx: rack view
- src/components/ProductDetails.jsx: product detail overlay
- src/components/ARPreview.jsx: try-on capture and preview flow
- src/styles.css: kiosk and admin visual system
- src/services/apiClient.js: frontend API wrapper
- src/services/recommendationEngine.js: heuristic ranking and profile summary logic
- server/index.js: Express app, shopper APIs, admin APIs, and static serving for production/Docker
- server/catalogDb.js: read-side SQLite access
- server/catalogAdminDb.js: write-side SQLite helpers, settings, sync runs, and migration safety
- server/catalogSyncService.js: Shopify sync orchestration
- server/shopifyStorefrontService.js: Shopify Storefront GraphQL ingestion
- server/adminAuth.js: dummy admin auth/session handling
- server/openrouterService.js: try-on generation via OpenRouter
- db/schema.sql: products, variants, imports, admin settings, sync history
- data/catalog.sqlite: local persisted catalog and back office state
- scripts/bootstrapCatalogDb.js: legacy Excel bootstrap script
npm install
npm run devThis repo now includes:
- a committed SQLite catalog file at
data/catalog.sqlite - a bundled non-member recommendation seed at
db/seeds/codex_feed_non_member_tags.csv
So a fresh clone can run directly without downloading external Excel/CSV files.
If you ever receive an updated non-member tag feed, import it with:
npm run db:import-nonmember-tags -- /absolute/path/to/codex_feed_non_member_tags.csvDefault local URLs:
- shopper kiosk:
http://localhost:5173/ - admin back office:
http://localhost:5173/admin - toy mascot studio:
http://localhost:5173/?view=toy - API:
http://localhost:8787
Use Node 24.x or newer for the backend because this project uses node:sqlite.
The Docker setup builds the frontend and serves both the compiled React app and the API from a single Express process on port 8787.
Quick start:
docker compose up --buildOpen:
- shopper kiosk:
http://localhost:8787/ - admin back office:
http://localhost:8787/admin - toy mascot studio:
http://localhost:8787/?view=toy
Plain Docker flow:
docker build -t ebo-smart-kiosk .
docker run --rm -p 8787:8787 --env-file .env -v "$(pwd)/data:/app/data" ebo-smart-kioskDocker notes:
./datais mounted so SQLite catalog data and sync history survive container restarts- the container expects
.envfor OpenRouter and optional admin overrides - inside Docker the catalog DB path is
/app/data/catalog.sqlite
The admin back office is intentionally protected, even in demo mode.
Default dummy accounts:
merch.admin / ebo1234ops.lead / ebo5678
These are also exposed by the bootstrap API and can be overridden with ADMIN_USERS_JSON in .env.
Yes, you do need Shopify credentials for a real sync.
Required values:
- Shopify store domain, for example
your-store.myshopify.com - Shopify Storefront access token
- Shopify API version, for example
2025-01
Where they are used:
- you enter them in the admin back office
- they are saved into the local SQLite-backed admin settings for this demo
- the sync worker uses them to call Shopify Storefront GraphQL and normalize product data into the local catalog DB
Important limitation:
- Shopify Storefront API is enough for product catalog ingestion
- it is not enough for true admin-grade inventory-by-location sync
- if you want exact live stock and richer operational sync, the next step is Shopify Admin API integration
Current sync behavior:
- imports product, variant, price, compare-at price, image, handle, vendor, and option data
- derives activity, fit, and material tags heuristically
- overwrites the local SQLite product catalog with the synced storefront payload
- stores sync run history in SQLite
Current search mode:
- deterministic keyword filtering
- heuristic recommendation ranking
- no live vector database yet
Why that is okay for now:
- cheaper
- easier to debug
- stable for kiosk/demo usage
When to add a vector DB:
- long natural-language stylist prompts
- semantic retrieval such as “breathable travel tee with a polished silhouette”
- similarity search over richer product content and embeddings
The back office already exposes this as a “vector-ready” architecture decision, but the actual vector DB is not implemented yet.
The old Matrixify import path still exists:
npm run db:bootstrap -- /absolute/path/to/Export.xlsxThat should now be treated as a fallback/bootstrap utility, not the preferred operating model.
GET /api/healthGET /api/experiencePOST /api/member/loginGET /api/member/:phoneGET /api/productsPOST /api/recommendationsGET /api/inventory/:productIdPOST /api/tryon
GET /api/admin/bootstrapPOST /api/admin/loginGET /api/admin/backofficePOST /api/admin/shopify/settingsPOST /api/admin/shopify/sync
Useful env values:
OPENROUTER_API_KEYOPENROUTER_MODELOPENROUTER_APP_URLOPENROUTER_APP_NAMECATALOG_DB_PATHADMIN_USERS_JSON
- if you only want to demo the kiosk, you can run it without Shopify sync and keep using the existing SQLite catalog
- if you want the admin console to feel real, log in with a dummy account and save real Shopify storefront credentials there
- if try-on is expected to work, make sure
OPENROUTER_API_KEYis set before starting the app