<aside> โก
Up and running in 3 commands: npm ci โ npm run build โ npm run local, then open http://127.0.0.1:8080 and switch roles from the profile menu.
</aside>
<aside> ๐ฉ
Node 24+
required runtime
</aside>
<aside> ๐
Embedded PG 16
port 55432, no install
</aside>
<aside> ๐ญ
Demo auth
X-Demo-Role on loopback
</aside>
Run
npm ci
npm run build # vite build + Sites packaging
npm run local # Postgres + app at <http://127.0.0.1:8080>
npm run dev # Vite dev server, proxies /api (run npm run local alongside)
npm run local -- --migrate-sqlite # one-off v0.1 SQLite import
Test
npm test # all tests, temp PG clusters
node --test tests/business.test.mjs # one file
node --test --test-name-pattern="accept" tests/business.test.mjs # one test
npm run test:sites # Sites packaging
CI also runs py_compile scripts/deploy.py, az bicep build on both templates and docker build.
Data
npm run db:generate # regenerate 001_native.sql + dictionary (never on a deployed migration)
npm run import -- --mapping m.json --input file.csv [--stage|--apply] [--delta]
npm run myob:sync # one MYOB pass (needs MYOB_ENABLED=true)
Env vars
| Variable | Notes |
|---|---|
AUTH_MODE |
demo or entra (production = entra) |
HOST, PORT |
Default 127.0.0.1:8080 |
DB_DRIVER, PGHOST, PGDATABASE, PGUSER, PGPASSWORD |
Postgres; password from Key Vault only |
DB_MIGRATE |
false for serving app; migration job applies DDL |
ENTRA_TENANT_ID, ENTRA_CLIENT_ID |
Entra app registration |
STORAGE_ACCOUNT_URL, AZURE_CLIENT_ID |
Blob + managed identity |
ALLOWED_ORIGINS, SEED_DEMO |
CORS; demo records (local only) |
โ๏ธ server/: Express API
๐ฅ๏ธ src/: React SPA
๐ค shared/: roles and workflow
๐๏ธ database/: catalog and migrations
๐ scripts/: tooling
โ๏ธ infra/: Bicep
๐จ tools/quoteflow/: desktop tool
๐ data/: local only
<aside> ๐
Schema change = new numbered migration. Never edit an applied one or rerun db:generate on 001_native.sql.
</aside>