Skip to main content

Development

EXEPERT is a hybrid monorepo: several independently deployed applications share one repository, but they do not all belong to one package-manager workspace. The root pnpm-workspace.yaml includes the AI Lab root and services/dsh-sidecar. The website, Brain Learning Lab, identity gateway, and docs keep their own package manifests, lockfiles, build commands, and deployment boundaries.

Application map

EXEPERT deployment-oriented tree
MASTER-exe/
|-- src/ + api/ app.exepert.com (AI Lab, API, auth, CMS)
|-- apps/
| |-- landing/ www.exepert.com (website and blog)
| |-- brain-learning/ learn.exepert.com (learning application)
| `-- auth-gateway/ auth.exepert.com (gated identity gateway)
|-- services/
| `-- identity-runtime/ portable Better Auth composition
`-- docs-site/ app.exepert.com/docs (this documentation)
SurfaceStart from the repository rootLocal address
AI Labpnpm.cmd devhttp://localhost:9001
Website and blogpnpm.cmd landing:devhttp://localhost:3001
Brain Learning Labbun --cwd=apps/brain-learning run devhttp://127.0.0.1:3012
Documentationpnpm.cmd --dir docs-site exec docusaurus starthttp://localhost:3000

The Brain Learning package is deliberately outside the root pnpm workspace. Run its Bun commands from apps/brain-learning or use Bun's --cwd option; running the root pnpm dev starts app.exepert.com, not the learning site.

Human Brain Learning Lab

Use the fast path when dependencies and prepared assets already exist:

Repository root - existing checkout
Set-Location '.\apps\brain-learning'
bun run dev

Open http://127.0.0.1:3012 after Vite reports that it is ready. The port is fixed and strict, so Vite stops with an error instead of silently selecting a different port.

For a fresh checkout or after dependency changes, install from the package's pinned Bun lockfile first:

Repository root - first run
Set-Location '.\apps\brain-learning'
bun install --frozen-lockfile
bun run dev

Vite provides hot module replacement for the React, TypeScript, and CSS UI. The repository already contains the public anatomy and prepared MRI assets used by the development server. Ordinary UI/UX work does not require a .env file, Supabase, Vercel, Cloudflare, or a Hugging Face runtime. Lessons, quizzes, simulation, 3D/MRI views, downloads, and guest progress remain available, with progress stored only in the current browser.

The plain Vite server does not emulate Cloudflare Pages Functions. Its /api/session request therefore falls back to the application's session-unavailable state; this does not block device-local learning. Use the Pages emulator when the UI needs the production API boundary:

apps/brain-learning - Cloudflare Pages emulation
python -m pip install -r requirements-mri.txt
bun run build
bunx wrangler@4.130.0 pages dev dist --port 8788

Open http://127.0.0.1:8788 for that build. The build verifies and prepares the pinned MRI inputs and therefore needs network access. CI uses Bun 1.3.14 and Python 3.11; the deployment workflow pins Wrangler 4.130.0. wrangler.toml keeps IDENTITY_ENABLED=false and TUTOR_ENABLED=false, so local Pages emulation must not be treated as an authenticated release.

UI/UX source map

PathPrimary responsibility
apps/brain-learning/src/App.tsxPage structure, learning flow, comparison dashboard, quizzes, and experiment UI.
apps/brain-learning/src/styles.cssVisual system, responsive layout, controls, focus states, and reduced-motion behavior.
apps/brain-learning/src/Viewer.tsxThree.js anatomy, exploded structures, labels, outlines, and camera controls.
apps/brain-learning/src/MriViewer.tsxMRI slice rendering and comparison interaction.
apps/brain-learning/src/content.tsChapters, audience tracks, activities, questions, sources, and limitations.

AI Lab browser application

Start the root dev server:

pnpm dev

pnpm dev runs three steps in order (from package.json):

package.json
"dev": "pnpm run build:wasm && pnpm run build:vanilla-logger && vite"
  1. build:wasm: compiles rust/brain_sim to WebAssembly via wasm-pack.
  2. build:vanilla-logger: bundles the diagnostics logger into a standalone IIFE for the legacy reference pages (see Diagnostics Logger and Reference Pages).
  3. vite: starts the Vite dev server on port 9001.

Open http://localhost:9001 once Vite reports it is ready.

Keyboard shortcuts

The shortcuts are registered in src/events.ts:

KeyAction
SpaceToggle simulation pause.
AToggle the grid helper.
SToggle the axis helper.

The diagnostics panel adds one more, handled in src/diag/logger.ts:

KeyAction
Ctrl + Shift + LToggle the in-app diagnostics panel.

Hot reload

Vite handles HMR for the TypeScript and CSS. Changes to the Rust code are not hot-reloaded: rerun pnpm run build:wasm (or restart pnpm dev) to pick up simulation changes.

AI Lab commands

CommandDescription
pnpm devStart dev server (builds WASM + vanilla logger, then Vite HMR)
pnpm buildFull production build (WASM + vanilla logger + Vite)
pnpm previewPreview production build locally on port 9001
pnpm typecheckRun TypeScript type checking (no emit)
pnpm testRun unit tests (Vitest)
pnpm test:watchRun tests in watch mode
pnpm test:e2eRun Playwright end-to-end tests
pnpm test:e2e:uiRun Playwright tests with UI
pnpm search:indexPopulate Typesense search indexes
pnpm supabase:startStart local Supabase stack
pnpm supabase:stopStop local Supabase stack
pnpm supabase:resetReset local database
pnpm supabase:diffGenerate migration diff
pnpm supabase:pushPush migrations to remote
pnpm supabase:gen-typesRegenerate TypeScript types from schema

Documentation site

cd docs-site
pnpm install
pnpm start # Live-editing dev server at http://localhost:3000
pnpm build # Production build, including the local search index
pnpm serve # Serve the production build
pnpm preview:search # Build, serve, and verify local search

When the app runs from a local origin such as http://localhost:9001, the top-nav Docs button and in-app help links default to the Docusaurus dev server at http://localhost:3000. Start both servers when you want the app and docs to work side by side locally.

The docs search box uses @easyops-cn/docusaurus-search-local. pnpm start is useful for editing layout and content, but it does not serve the generated search index. To test search, run pnpm build followed by pnpm serve, or use pnpm preview:search.

Troubleshooting stale AI Lab content

If changes don't appear after saving:

  1. Hard refresh the browser: Ctrl+Shift+R
  2. Clear Vite cache: npx vite --force
  3. Full clean rebuild: pnpm build
  4. Check terminal: if the Vite process crashed, restart with pnpm dev

Security note for shared AI Lab servers

vite.config.ts sets server.fs.allow: ['..'] and binds the dev server on port 9001 with no authentication. That is convenient locally because the build serves sibling reference directories, but it means anyone who can reach the port can read files from the parent directory. Do not expose the dev server on a public or shared network as-is. For sharing a build, use the static output from pnpm build behind your own server instead.

Typesense Search Indexer (Plan 008)

When Typesense is configured, populate or refresh the search indexes:

pnpm search:index

This runs scripts/typesense-index.mjs, which connects to Typesense (using TYPESENSE_ADMIN_KEY + VITE_TYPESENSE_HOST from .env), drops and recreates the traces_spans and docs collections, then bulk-imports data from Supabase and docs-site/docs/**/*.md. The script auto-loads .env so it works without the --env-file flag on Node < 20.6. Requires admin credentials in .env.