Appearance
Dev Setup
This guide gets you from a fresh clone to a running Haptique stack (server + mobile app + wiki) in under 10 minutes.
Prerequisites
Before starting, make sure you have the following installed:
- Node.js (LTS — check
.nvmrcorenginesin rootpackage.jsonfor the pinned version) - npm (comes with Node.js)
- Git
- Xcode + iOS Simulator (macOS — for running the mobile app on an iOS simulator)
- Android Studio (for Android emulator — optional if using iOS)
- Expo Go (install on a physical device if you prefer not to use a simulator)
Step 1: Clone and Install
bash
git clone <repo-url>
cd nfs_haptique
npm installnpm install at the repo root installs dependencies for all workspaces in the monorepo: apps/server, apps/mobile, packages/shared, and sdk. This is a single-command install for the entire stack.
Step 2: Configure Environment Variables
Copy the example env file to create your local env:
bash
cp apps/server/.env.example apps/server/.envThen open apps/server/.env and fill in the required values below.
Never commit your
.envfile. It is already in.gitignore.
Required env vars (minimum for local dev)
These must be set before the server will start correctly:
| Variable | Example Value | Why |
|---|---|---|
APP_NAME | Cantata | Application display name |
APP_SECRET_KEY | Any random string | Session signing key |
ENCRYPTION_KEY | Any random string | Data encryption key |
APP_URL | http://localhost:8080 | Server base URL (used in redirects and links) |
PORT | 8080 | HTTP server listen port |
LICENSE_BYPASS | true | Skip license validation in dev (required — see pitfalls) |
LICENSE_PRODUCT_CODE | HAPTIQUE_OS | Product identifier for license check |
APP_DEBUG | true | Enable verbose debug logging |
SELF_HOSTED | true | Required for OS UI to render (see pitfalls) |
DB_BACKEND | sqlite | Database backend — use sqlite for local dev (no setup needed) |
ADMIN_AUTH_BYPASS | true | Skip admin authentication in dev |
JWT_SECRET_KEY | Any random string | JWT access token signing key |
JWT_EXPIRATION | 1d | Access token TTL |
JWT_REFRESH_SECRET_KEY | Any random string | JWT refresh token signing key |
JWT_REFRESH_EXPIRATION | 7d | Refresh token TTL |
Optional env vars (for feature testing)
| Variable | Value | Why |
|---|---|---|
DRIVER_WS_PORT | (blank) | Separate port for the driver WebSocket server — defaults to PORT if not set |
HOS_NODE_BINARY | (blank) | Optional Node executable for OS-local JavaScript drivers; defaults to process.execPath or node |
FIREBASE_ENABLED | false | Disable push notifications (skip Firebase setup) |
S3_ENABLED | false | Disable S3 media storage |
MAIL_ENABLED | false | Disable email sending |
DEVICE_MOCK | true | Run mock devices without real hardware |
Step 3: Start the Server
bash
# From repo root:
npm run server
# Equivalent:
npm run dev --workspace=apps/server
# Under the hood this runs:
# ts-node-dev --respawn --transpile-only -r tsconfig-paths/register index.tsThe server starts at http://localhost:8080. You should see console output confirming:
- Express HTTP server is listening on the configured
PORT - Driver WebSocket server is ready (same port unless
DRIVER_WS_PORTis set separately) - SQLite database is initialized (file created automatically — no external DB setup needed)
The SQLite database file is created at apps/server/src/storage/. To specify a custom path, set DB_PATH in .env.
Step 4: Start the Mobile App
bash
# From repo root:
npm run mobile
# Equivalent:
npm run start --workspace=apps/mobile
# Under the hood this runs:
# expo startAfter Expo CLI starts:
- Press
ito open in the iOS Simulator - Press
ato open in the Android Emulator - Scan the QR code with the Expo Go app on a physical device
On the Discovery screen, enter the server URL:
| Device type | URL to enter |
|---|---|
| iOS/Android Simulator | http://localhost:8080 |
| Physical device (same network) | http://<your-mac-lan-ip>:8080 |
To find your Mac's LAN IP:
bash
ifconfig | grep "inet " | grep -v 127.0.0.1Step 5: Start the Wiki (optional)
bash
cd wiki
npm install # first time only — wiki is a standalone package
npm run devThe wiki dev server opens at http://localhost:5173 (VitePress default port).
To build the wiki for static deployment:
bash
cd wiki
npm run buildOutput goes to wiki/docs/.vitepress/dist/.
Common Pitfalls
1. Missing .env in apps/server/
Symptom: Server starts but authentication fails silently, or routes return HTTP 500 errors.
Cause: The server loads dotenv at startup. If apps/server/.env does not exist, critical variables like APP_SECRET_KEY and JWT_SECRET_KEY are undefined — sessions cannot be signed and JWT auth fails for all requests.
Fix: Run cp apps/server/.env.example apps/server/.env and fill in the required values (Step 2 above).
2. SELF_HOSTED not set to true
Symptom: The root route (/) shows a "construction" or "coming soon" page. The OS web UI does not load.
Cause: The server checks SELF_HOSTED before rendering the OS web UI. Without it, a fallback placeholder page is served instead.
Fix: Set SELF_HOSTED=true in apps/server/.env.
3. LICENSE_BYPASS not set to true
Symptom: Every route redirects to /os/license. No content is reachable.
Cause: License validation middleware intercepts all requests before any route handler. Without a valid license or bypass flag, the entire server redirects to the license page.
Fix: Set LICENSE_BYPASS=true in apps/server/.env.
4. SQLite database location confusion
Note: DB_BACKEND=sqlite requires no external database. The SQLite file is created automatically when the server first starts.
Default location: apps/server/src/storage/
To customize: Set DB_PATH in .env to an absolute path for the SQLite file.
5. Mobile app cannot reach server on a physical device
Symptom: The Discovery screen times out or shows "Network request failed".
Cause: localhost resolves to the device itself on a physical phone — not to your Mac. This only works on simulators (which share the host network stack).
Fix: Use your Mac's LAN IP address instead of localhost when prompted in the app (e.g., http://192.168.1.50:8080). Find your IP with ifconfig | grep "inet " | grep -v 127.0.0.1.
6. DRIVER_WS_PORT confusion
Note: If DRIVER_WS_PORT is left blank (or not set), the driver WebSocket server shares the HTTP server port (PORT). A single port handles both HTTP and WebSocket driver connections.
If you set DRIVER_WS_PORT to a different value, external driver processes must connect to that specific port. The sdk/ sample drivers pick up this value from process.env.DRIVER_WS_PORT.
7. JavaScript driver runtime unavailable
Symptom: A local .js driver package uploads but fails to start.
Cause: HOS starts JavaScript drivers through JavaScriptDriverProcess, which needs a Node-compatible executable. In dev this normally resolves to process.execPath or node; packaged Electron builds may need an explicit runtime path.
Fix: Set HOS_NODE_BINARY to a valid Node executable. In Electron packaging, the runtime sets ELECTRON_RUN_AS_NODE=1 when needed so the bundled executable can run driver JavaScript.
Useful Commands
| Command | Run from | What it does |
|---|---|---|
npm run server | Repo root | Start HOS server in dev mode (hot-reload) |
npm run mobile | Repo root | Start Expo mobile app (choose simulator or device) |
cd wiki && npm run dev | Repo root | Start VitePress wiki dev server |
npm run build --workspace=apps/server | Repo root | Build server TypeScript for production |
npm run build --workspace=apps/mcp-driver-builder | Repo root | Build the AI Driver Builder MCP server |
npm run test --workspace=apps/mcp-driver-builder | Repo root | Run MCP driver-builder tests |
cd wiki && npm run build | Repo root | Build wiki static site |
npm install | Repo root | Install/sync all workspace dependencies |
Cross-References
- Monorepo Map — directory-by-directory breakdown of the entire repo
- Server Internals — how the server's request pipeline, middleware, and driver WebSocket work
- API Reference — endpoint reference for testing the server manually once it is running