Repository layout
Monorepo: one top-level directory per deployable.
eacmlab/
├── client/ # Next.js 16 App Router (participant + admin UI)
├── server/ # Express 4 + Socket.IO + Prisma
├── docs-site/ # Docusaurus → docs.eacmlab.org
├── docs/ # Ops notes, nginx conf, deploy scripts (not the public site)
├── docker-compose.dev.yml
├── docker-compose.test.yml
├── docker-compose.prod.yml
└── .github/workflows/
Root package.json only orchestrates dev / build / start for client+server. It is not an npm workspaces root.
Client (client/src/)
App Router (app/)
| Route | File | Role |
|---|---|---|
/ | app/page.js | Home: join experiment / friends / solo |
/survey | app/survey/page.js | Survey entry |
/survey/[university] | app/survey/[university]/page.js | University experiment flow |
/play/[roomCode] | app/play/[roomCode]/page.js | Friends / solo play |
/admin/login | app/admin/login/page.js | Admin login |
/admin/dashboard | app/admin/dashboard/page.js | Admin dashboard |
/admin/simulations/[runId] | app/admin/simulations/[runId]/page.js | Simulation run detail |
Components (components/)
| Folder / file | Purpose |
|---|---|
home/ | Join flows, waiting room, solo practice |
survey/ | Consent, SQ/EQ/StPSQ, exit survey, instructions |
foraging/ | Foraging UI pieces |
arithmetic/ | Arithmetic stress task UI |
dashboard/ | Admin tabs (experiments, monitor, export, simulations, …) |
ExperimentRouter.js | Loads current experiment for /survey/[university] |
SinglePlayerForaging.js / MultiplayerForaging.js | Game shells |
Context (context/)
Root layout wraps: UserProvider → SocketProvider → ClientConstantsLoader.
UserContext.js— participant/admin user stateSocketContext.js— Socket.IO clientClientConstantsLoader.js+client_constants.js— server-driven constantsExperimentContext.js— exists; not mounted in root layout today
Server (server/src/)
| Directory | Purpose |
|---|---|
routes/ | authRoutes, adminRoutes, participantRoutes |
controllers/ | HTTP handlers (auth, admin, experiment, survey, export, …) |
services/ | RoomService, foraging save, export jobs, Empatica, simulations |
socket/ | Socket.IO handlers + roomManager |
game/ | ForagingGame, ArithmeticTest, BotManager, GameRegistry |
data/ | Persistence helpers for foraging / practice / arithmetic |
middleware/ | Auth, helmet/rate-limit/CORS, error handler, HTTP logger |
config/ | Prisma client, room settings, server constants |
utils/ | logger, env (Zod), errors, safeArithmeticEval, timers |
simulation/ | Simulation queue / CSV helpers |
Entry: server/index.js. Container start: server/entrypoint.sh (prisma migrate deploy then node index.js).
Docs vs docs-site
| Path | Role |
|---|---|
docs/ | Host Nginx config (docs/nginx/eacmlab.conf), deploy scripts, internal guides |
docs-site/ | Public documentation site (this project) |
Do not scaffold Docusaurus into docs/ — ops paths depend on that folder name.