# NODAVX — nodavx.com

> **This folder is the NODAVX site.** A full copy of the audited `spectra-3d-atlas` application
> (milestones M1–M6, system audit 2026-10-17/18), rebranded for **nodavx.com** and given its own
> loopback ports so it runs side by side with the original. Product surface — page title, wordmark,
> metadata — says NODAVX by SPECTRA Research Pte Ltd; internal identifiers (`@atlas/*` workspace
> names, `atlas:*` DOM events, the `spectra`/`atlas` database namespace) stayed put so nothing
> inherited from the audited tree broke. Ports differ from the original: UI **5299**, API **8897**,
> SurrealDB **18180**.

An operational-ontology workspace that runs entirely on one Apple Silicon Mac: two segment packs
(**Defense** and **Commercial**) whose objects, links, actions, evidence and metrics live in a
disk-backed SurrealDB; a live 3D/2D graph, scene and table view that all read **one** snapshot
contract; reviewed actions that mutate real records; and a copilot grounded by your own local oMLX
engine. Nothing in the demo path calls a hosted service — no external fonts, assets, tiles or APIs.

It is a proof of capability, not a product: single-user loopback auth, deterministic synthetic data,
and honest states wherever something is not verified.

## What runs, and where

| Service | URL / path | Notes |
|---|---|---|
| UI (Vite dev) | http://127.0.0.1:5299 | the app you use; `http://nodavx.com:5299` once the hostname resolves here |
| API (Fastify) | http://127.0.0.1:8897 | `/health` reports API, database and ontology versions; also serves `apps/web/dist` same-origin |
| SurrealDB | http://127.0.0.1:18180 (ws `:18180/rpc`) | namespace `spectra`, database `atlas`, data in `data/db/atlas-skv` |
| oMLX (yours) | http://127.0.0.1:8000/v1 | read, never started or reconfigured by this project |

To browse it as **nodavx.com**, point the hostname at loopback (needs sudo, and it is yours to run):

```bash
echo '127.0.0.1 nodavx.com' | sudo tee -a /etc/hosts
```

Then open `http://nodavx.com:8897` (API-served production build) or `http://nodavx.com:5299`
(Vite dev server; `allowedHosts` already lists `nodavx.com`).

## Screenshots

![Defense readiness shortfall](docs/screenshots/13-c-readiness-shortfall.png)
![Current versus planned inventory](docs/screenshots/14-c-inventory-current-vs-planned.png)
![Grounded copilot answer](docs/screenshots/17-a-copilot-answer.png)
![What-if branch compared with live](docs/screenshots/18-a-branch-compare.png)
![Ingestion rejects with reasons](docs/screenshots/15-a-validation-rejects.png)
![Narrow viewport, honest scope bar](docs/screenshots/20-d-narrow-atlas.png)

`docs/screenshots/` holds one image per asserted browser step, regenerated by `pnpm test:e2e`.

## Architecture in one paragraph

SurrealDB is the only authority: entities and native `entity_link` relation records, an append-only
event journal with per-transaction receipts, ontology definitions as versioned records, and evidence
artefacts hashed on disk. The Fastify API exposes scoped reads (`/api/graph`, `/api/entity/:uid`,
`/api/metrics`), reviewed actions (`preview` then `commit` with an idempotency key), ingestion,
lineage, baselines and scenario branches. Live updates are **invalidation-only**: a named SSE channel
per lens carries journal cursors, and the client re-reads the scoped snapshot — so a dropped stream, a
reordered notification or an out-of-band `surreal sql` edit converges instead of silently diverging
(checks 4, 7, 8). The React app renders that one snapshot in 3D (React Three Fiber + `d3-force-3d`
in a worker), 2D, scene and table views, with `frameloop="demand"` so an idle graph costs no frames.
The copilot sends a validated query plan to oMLX, executes it against the store, and answers with
citations that select real records; unparseable output is reported as invalid, never dressed up.

## Prerequisites (the versions this was verified on)

- macOS on Apple Silicon (measured: MacBook Pro, Apple M5 Max, 128 GB RAM).
- **Node 24.19+ under 25** — verified `v24.21.0` (`node --version`). Node runs the `.ts` sources
  directly; there is no build step for the API.
- **pnpm 11.x** — verified `11.25.0` (`packageManager` pin).
- **SurrealDB 3.2.3** on `PATH` — verified `/opt/homebrew/bin/surreal`,
  `3.2.3+20260721.40522d1 aarch64`.
- **Google Chrome** at `/Applications/Google Chrome.app` for `pnpm test:e2e` (puppeteer-core, no
  downloaded driver).
- **oMLX** at `http://127.0.0.1:8000/v1` for the copilot only. Start it yourself; ATLAS never does.

Ports 8787, 5173 and 18080 belong to this project. Ports 8001/8002 may hold unrelated SurrealDB
instances — leave them alone.

## Setup

```bash
cd "/Users/aquek/Documents/ChatGPT/SPECTRA Team/spectra-3d-atlas"
cp .env.example .env.local      # then fill SURREAL_PASSWORD and SURREAL_ADMIN_PASSWORD
node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"  # → ATLAS_SESSION_SECRET
pnpm install
```

`ATLAS_SESSION_SECRET` matters: without it the session cookie is signed with a per-process random
key, so every API restart logs the browser out.

## Start, stop, reset

```bash
pnpm dev            # SurrealDB + API + UI (foreground supervisor, Ctrl-C stops them)
pnpm start          # SurrealDB + API only (no UI); used when the UI is already hot-reloading
pnpm demo           # reset + seed both packs, print both story scripts
pnpm stop           # stop what this project started (needs --confirm for the database)

node tools/run-tool.mjs status              # what is running, on which pid/port
node tools/run-tool.mjs reset --confirm     # migrate + seed both workspaces from scratch (~17 s)
node tools/run-tool.mjs backup              # → data/backups/atlas-<timestamp>.json
node tools/run-tool.mjs restore --file <path> --confirm
pnpm preflight      # environment and port checks before anything else
pnpm probe:ai       # oMLX capability probe (models, tool calling, streaming) — no key printed
```

Restart just the API after editing `apps/api/**`:

```bash
pkill -f "apps/api/src/main.ts" && node tools/dev.mjs &     # or: pnpm dev
```

Files under `apps/web/**` hot-reload through Vite — no restart needed.

## Tests and validation

```bash
pnpm typecheck      # contracts + ontology + api + web — clean
pnpm build          # → dist/, 1,318.47 kB / 359.63 kB gzip (Vite warns: no code-splitting)
pnpm test           # 22 integration + unit checks, ~38 s, includes a real backup/restore
pnpm test:e2e       # Chrome journeys 13–20 + performance sample, ~3 min, resets and re-seeds
```

Last measured here (2026-10-17, 12:30–12:33 +08): `pnpm test` **22 pass / 0 fail** in 38.1 s;
`pnpm test:e2e` **82 checks / 0 failures** in 2m27s; scoped graph query p50 **88 ms**,
commit-to-visible p95 **104 ms** (20/20 converged), camera drag **p50 59.9 fps**. Full numbers,
targets and unverified items: `docs/VALIDATION.md`.

## First demo (five minutes)

1. `pnpm demo`, then open http://127.0.0.1:5173 — the launcher shows both segment cards with counts.
2. Open **Commercial**, Overview → `Executive overview`: shortfall **20 units** (300 demand against
   80 on hand plus 200 timely planned), each tile printing its formula.
3. Click `1 · Delay inbound 48 h` → shortfall **220 units**, the late shipment named and excluded.
   `2 · Preview & commit transfer` → **80** (on hand unchanged, planned up). `3 · Expedite 80 units`
   → **0** with intervention cost **SGD 1,380.00**. No page reload at any point.
4. Open the right drawer, `COPILOT`, ask *"Why are orders at risk?"* — the answer cites stored
   objects; click a citation, then `Show supporting graph` to re-scope the Atlas onto the evidence.
5. Switch to **Defense** from `Launcher`, Overview → `Response readiness`, and run
   `1 · Record maintenance failure` (margin **+6 → −6**, Operation CORMORANT short 10 places), then
   `2 · Activate reserve vessel` (back to **+6**, unmet **0**).

Full walkthrough with every expected number: `docs/DEMO_GUIDE.md`.

## Troubleshooting

- **Blank page / "needs JavaScript"** — the shell renders without JS only as a notice; check
  `node tools/run-tool.mjs status` and that Vite is on 5173.
- **Everything reads 0 objects after switching workspaces** — a uid typed in one workspace matches
  nothing in the other. The empty state says so; `Reset scope` clears focus, filters and search.
- **Logged out after an API restart** — `ATLAS_SESSION_SECRET` is empty (see Setup).
- **`AI UNKNOWN` in the top bar** — oMLX is not answering on 8000. Start it yourself; the rest of
  the app keeps working, and Settings → `Local inference (oMLX)` has `Re-probe`.
- **Seed report shows `drift`** — the workspace already holds records this seed did not write (an
  import, a scenario branch, an earlier `--stress` pass). A seed is additive and says so instead of
  failing: `missing` counts what it failed to write, `extra`/`extraUids` name what it did not write.
  `node tools/run-tool.mjs seed --clean` prunes only synthetic strays and the edges that point at
  them — imported objects, Ontology Studio types, scenario branches and their evidence survive and
  are reported under `preserved`. `node tools/run-tool.mjs reset --confirm` rebuilds both workspaces
  from scratch if you want exact counts back.
- **Port already in use** — check `pnpm preflight`; 8001/8002 SurrealDB instances are not ours.
- **A long job died when the terminal closed** — these tools detach what they start, but a shell
  pipeline you started yourself dies with it; use `pnpm dev` or `nohup`.
- **Browser console shows `/api/stream … ERR_ABORTED`** — EventSource teardown during a lens or
  workspace switch, classified benign by the e2e harness.

## Documentation

| File | Contents |
|---|---|
| `docs/DEMO_GUIDE.md` | step-by-step walkthrough of both stories, copilot, what-if, ingestion, keyboard path |
| `docs/ARCHITECTURE.md` | data flow, live-state design, implementation decisions and their measured basis |
| `docs/ONTOLOGY.md` | object/link/action definitions, identity rules, validation boundaries, segment packs |
| `docs/LIVE_STATE.md` | transaction/journal/stream/snapshot protocol and recovery guarantees |
| `docs/VALIDATION.md` | commands run, measured results, screenshots, unverified items |
| `docs/OPERATIONS.md` | configuration, credential handling, data paths, backup/restore, reset scope |
| `docs/RESEARCH.md` | sources checked with dates, versions and what each one changed in the design |
| `docs/ROADMAP.md` | explicitly optional next steps (Neo4j projection, AI Assurance, hardening) |
| `docs/BUILD_STATUS.md` | durable checkpoint: current state, resume instructions, easy-to-regress decisions |

Data stays on this machine: `data/db` (store), `data/evidence` (artefacts), `data/backups`
(snapshots), `data/logs` (service logs). None of it is committed.
