Client
Next.js 16 App Router app in client/. React 19, HeroUI + Tailwind, socket.io-client 4.
App Router map
client/src/app/
├── layout.js # UserProvider → SocketProvider → ClientConstantsLoader
├── page.js # Home (join experiment / friends / solo)
├── survey/
│ ├── page.js
│ └── [university]/page.js # Experiment survey flow (+ ExperimentRouter)
├── play/[roomCode]/page.js # Friends / solo rooms
└── admin/
├── login/page.js
├── dashboard/page.js
└── simulations/[runId]/page.js
Providers
Mounted in layout.js:
- UserProvider (
UserContext.js) — logged-in admin / participant identity - SocketProvider (
SocketContext.js) — single Socket.IO connection towindow.location.origin(dev rewrites or Nginx) - ClientConstantsLoader — loads tunable constants from the server
ExperimentContext exists under context/ but is not wired into the root layout.
Key components
| Component | Role |
|---|---|
ExperimentRouter.js | On /survey/[university], fetches GET /api/experiments/{university}/current and injects experiment into children; shows “no experiment” UI on failure |
ExperimentSurvey (survey package) | Owns step machine for the official experiment path |
SinglePlayerForaging.js | Solo foraging phase |
MultiplayerForaging.js | Multiplayer foraging phase |
components/home/* | Join session, waiting, solo practice |
components/dashboard/* | Admin UI (experiments, live monitor, constants, export, Empatica, simulations, …) |
Step names for the official flow live in client/src/constants/experimentSteps.js (shared with the admin monitor). See Participant journey.
Dev proxy
client/next.config.mjs:
output: "standalone"(Docker runner)- Dev-only rewrites of
/api,/socket.io,/health→DEV_SERVER_ORIGIN(defaulthttp://localhost:3001) - Production: empty rewrite list; Nginx does path proxying
Auth note
next-auth is listed in client/package.json but has no imports in application code. Admin auth is JWT against Express (/api/auth/* and requireAdminAuth).