ROAR DocumentationROAR Documentation
  • Tech Specs
  • Data Flow Diagram
  • Databases
  • BigQuery
  • Workflows
  • Application
  • GitHub Actions
  • Dashboard Components
  • Firebase App Check
  • Cloud Functions
  • Backend Architecture
  • Internationalization
  • Integrating New Apps
  • Optimizing Assets
  • ROAR Redivis Instance
  • Logging and Querying
  • Emulation
  • Data Tools
  • Data Organization
  • Data Requests
  • Data Cleaning
  • Assessment Environment
  • Project Development Lifecycle & Definitions of Done
GitHub
  • Tech Specs
  • Data Flow Diagram
  • Databases
  • BigQuery
  • Workflows
  • Application
  • GitHub Actions
  • Dashboard Components
  • Firebase App Check
  • Cloud Functions
  • Backend Architecture
  • Internationalization
  • Integrating New Apps
  • Optimizing Assets
  • ROAR Redivis Instance
  • Logging and Querying
  • Emulation
  • Data Tools
  • Data Organization
  • Data Requests
  • Data Cleaning
  • Assessment Environment
  • Project Development Lifecycle & Definitions of Done
GitHub
  • Data Tools
    • Data Tools
  • Data Organization
    • Data Organization
  • Data Cleaning
    • Data Cleaning
  • Data Requests
    • Data Requests and Task Management
  • Assessment Environment
    • Assessment Environment
    • Quick Reference

Quick Reference

Lookup only — for what any of it means, see the Assessment Environment guide. Run every command from the assessment's directory, e.g. apps/assessments/roar-swr/.

Commands

CommandDoesData
npm run setupCheck prerequisites, install, build libraries, create your configsafe
npm startStart the stack if needed, then this assessment's dev serversafe
npm run seed:tasksSeed new variants into the running databasesafe
npm run updateRebuild platform libraries on your machinesafe
npm run rebuildClean rebuild of the Docker imagessafe
npm stopStop everything and delete the databasedeletes
npm restartTeardown and delete the database, then start freshdeletes

Four ways to stop

ActionRuns, trials, scoresSeeded variants
Ctrl+C — dev server onlykeptkept
TRUNCATE app.runs CASCADE; in roar_assessmentcleared, on purposekept
npm stopdeleteddeleted
npm restartdeleteddeleted, re-seeded

Both destructive commands prompt for confirmation; declining changes nothing.

Ports

ProcessURL
Dev server — where you playhttp://localhost:8000
PostgreSQL — where you querylocalhost:5433 (not 5432)
Backendhttp://localhost:4000
Firebase Auth / Storage emulatorshttp://localhost:9099 · http://localhost:9199
Firebase Emulator UIhttp://localhost:9000

Connecting

Host localhost · port 5433 (ASSESSMENT_PG_PORT) · user postgres · no password · sslmode=disable · databases roar_core and roar_assessment.

pgweb --url "postgres://postgres@localhost:5433/roar_core?sslmode=disable"                       # → :8081
pgweb --url "postgres://postgres@localhost:5433/roar_assessment?sslmode=disable" --listen 8082   # → :8082
psql "postgres://postgres@localhost:5433/roar_core?sslmode=disable"

Or run pgweb with no arguments and fill in those values on the Standard tab of the form it opens at http://localhost:8081 — see the guide for a screenshot.

PgAdmin: host localhost, port 5433, user postgres, blank password.

Where the data lives

Every table is in the app schema — always prefix with app.

DataDatabaseTables
Participants, tasks, variantsroar_coreusers, tasks, task_variants, task_variant_parameters
Runs, trials, scores, interactionsroar_assessmentruns, run_trials, run_scores, run_trial_interactions
Runs and scores, joinable to participants and tasksroar_coreapp_assessment_fdw.runs, app_assessment_fdw.run_scores

run_trials is not mirrored — trial data is only in roar_assessment. run_demographics is in roar_core, and stays empty for anonymous runs.

Queries

Always include AND deleted_at IS NULL — records are soft-deleted.

Seeded variants, with their IDs · roar_core

SELECT t.slug AS task, tv.id AS variant_id,
       tv.name AS variant_name, tv.status,
       jsonb_object_agg(tvp.name, tvp.value)
         FILTER (WHERE tvp.name IS NOT NULL) AS params
FROM app.task_variants tv
JOIN app.tasks t ON t.id = tv.task_id
LEFT JOIN app.task_variant_parameters tvp ON tvp.task_variant_id = tv.id
GROUP BY t.slug, tv.id, tv.name, tv.status
ORDER BY t.slug, tv.name;

Runs for a task, with the participant · roar_core

SELECT r.id, u.assessment_pid, r.is_anonymous,
       r.completed_at, r.reliable_run, r.metadata
FROM app_assessment_fdw.runs r
JOIN app.users u ON u.id = r.user_id
JOIN app.task_variants tv ON tv.id = r.task_variant_id
JOIN app.tasks t ON t.id = tv.task_id
WHERE t.slug = 'swr'   -- English only; LIKE 'swr%' for all five
  AND r.deleted_at IS NULL
ORDER BY r.created_at DESC;

Anonymous runs have no name — assessment_pid is the identifier. Language-as-task assessments use suffixed slugs — SWR is five tasks (swr, swr-es, swr-it, swr-pt, swr-de) — so match with LIKE 'swr%' or list them; a single = silently misses runs.

Trials for one run · roar_assessment

SELECT trial_num_total, item, correct, response,
       response_time_ms, subtask, assessment_stage
FROM app.run_trials
WHERE run_id = '<your-run-id>'
ORDER BY trial_index;

Scores for completed runs · roar_assessment

SELECT r.id AS run_id, s.type, s.domain, s.name, s.value,
       s.assessment_stage, s.category_score
FROM app.run_scores s
JOIN app.runs r ON r.id = s.run_id
WHERE r.completed_at IS NOT NULL AND r.deleted_at IS NULL
ORDER BY r.completed_at DESC;

Run summary — counts, engagement, reliability · roar_assessment

SELECT r.id, r.completed_at, r.aborted_at,
       r.reliable_run, r.engagement_flags,
       (SELECT count(*) FROM app.run_trials t
          WHERE t.run_id = r.id) AS trial_count,
       (SELECT count(*) FROM app.run_scores s
          WHERE s.run_id = r.id) AS score_count
FROM app.runs r
WHERE r.deleted_at IS NULL
ORDER BY r.created_at DESC;

engagement_flags is a JSONB object of booleans — incomplete, responseTimeTooFast, accuracyTooLow, notEnoughResponses. reliable_run is the assessment's overall verdict.

Engagement events — focus/blur, fullscreen · roar_assessment

SELECT t.trial_index, i.interaction_type, i.time_ms
FROM app.run_trial_interactions i
JOIN app.run_trials t ON t.id = i.trial_id
WHERE t.run_id = '<your-run-id>'
ORDER BY t.trial_index, i.time_ms;

Scores with participant, task, and run metadata · roar_core

The one-query export, via the mirrored tables.

SELECT u.assessment_pid, t.slug AS task,
       s.name AS score_name, s.value AS score_value,
       r.metadata ->> 'sessionId' AS session_id
FROM app_assessment_fdw.run_scores s
JOIN app_assessment_fdw.runs r ON r.id = s.run_id
JOIN app.users u ON u.id = r.user_id
JOIN app.task_variants tv ON tv.id = r.task_variant_id
JOIN app.tasks t ON t.id = tv.task_id
WHERE r.deleted_at IS NULL
ORDER BY r.completed_at DESC NULLS LAST;

Metadata

runs.metadata holds run-level context. run_trials.metadata holds any trial field with no standard column. run_scores has no metadata column — join to the run.

-- discover the keys first
SELECT DISTINCT jsonb_object_keys(metadata) FROM app.run_trials
WHERE run_id = '<your-run-id>' AND metadata IS NOT NULL;

-- extract:  ->> yields text, -> keeps JSON
SELECT item, metadata ->> 'someField' AS some_field FROM app.run_trials …

-- filter:  ->> compares as text, @> does JSON containment
WHERE metadata ->> 'condition' = 'practice'
WHERE metadata @> '{"condition": "practice"}'

Export to CSV

  • PgWeb — run the query, then the export control on the results toolbar → CSV.
  • psql \copy — one physical line, writes to your current directory: \copy (SELECT …) TO 'trials.csv' WITH (FORMAT csv, HEADER)
  • Shell — psql "postgres://postgres@localhost:5433/roar_assessment?sslmode=disable" --csv -c "SELECT …" > trials.csv

Trial-level exports run against roar_assessment; participant and score joins against roar_core.

Variants

  • taskVariantParameters.json is yours, not committed, and required before the first start. taskVariantParameters.example.json beside it documents every parameter.
  • Seeding is idempotent and additive, matched by name. To change parameters, use a new variantName.
  • Editing the file does not seed it — run npm run seed:tasks, not npm restart.
  • Variant picker: top-right of the assessment, development and staging only, scoped to this assessment's tasks.
  • With no variantId: the task's entry in DEFAULT_VARIANT_NAMES in serve/serve.js (matched by name), else the oldest published variant. A default that doesn't resolve warns in the browser console and falls back — check the console if a run looks wrong.
URL parameterPurpose
variantIdRun a specific seeded variant
participantParticipant ID (PID) for the run
gradeParticipant grade
birthyear, birthmonth, age, agemonthsAge or date-of-birth context
labIdLab identifier
taskVersionTask version string (defaults to 1.0)

Game parameters always come from the variant; URL parameters only select one and attach participant context.

Switching assessments

Ctrl+C → cd ../<other> → npm run seed:tasks (first visit only) → npm start. Switching back needs no re-seed, and you never re-run npm run setup.

After a git pull

ChangedRun
SDK, assessment schema, scoring tablesnpm run update, then restart the dev server
Backend, migrations, API contract, Dockerfile, root dependenciesnpm run rebuild
The assessment schema (used by both)both
Not sure — big pullnpm run rebuild, then npm run update

Neither deletes data.

Troubleshooting

SymptomFix
Port 5433 in usedocker ps | grep 5433; stop it, or ASSESSMENT_PG_PORT=<port> npm start
Port 8000 in useA previous dev server is still running — stop that process
taskVariantParameters.json not foundnpm run setup, or copy the example file
Migration container failed / "Unknown task"Unregistered assessment or invalid parameter; the error names both
New variant didn't show upnpm run seed:tasks — not npm restart
Wrong variant loadedDeclared default doesn't match your names — check the browser console
Code change not taking effectHost library → update; backend or migration → rebuild
Firebase emulator won't start / can't bind 9000, 9099, 9199Another Firebase emulator holds them — stop it, then npm start. Recreate the container if the failed attempt left it in Created state
Stale containers on startnpm stop then npm start — deletes data
docker stop permission denied (Linux)npm stop prints the exact sudo kill to run

Two seeding messages are benign: Launch sandbox administration not found (that fixture isn't seeded here) and Config "…" names defaultVariant "…", which is not in the parameters file (you renamed your variants — only the sandbox assignment was skipped). Neither affects what localhost:8000 loads.

Recordings

Browse at http://localhost:9000 → Storage tab, bucket demo-roar.appspot.com (screenshots). Path is {taskId}/{participantId}/{assessmentPid}/{administrationId}/{runId}/{filename}, and each recording's gs:// reference lands in run_trials.metadata (Read Aloud: uploadUrl).

Held in memory — recordings survive Ctrl+C but are cleared by npm restart and npm stop. Download anything you need to keep.

Edit this page
Last Updated:
Contributors: Kyle Montville
Prev
Assessment Environment