HCTHE HCLAB

Research operations

Build, configure, and operate studies from the research admin panel.

Research operations tooling lives under /admin/research. It covers study design, exports, dual-rater coding, analytics, participant oversight, and background processing.

Who can access: Admin, Editor, Contributor, and Researcher roles (RESEARCH_ADMIN_ROLES). Researchers see the research panel only — not CMS content tools. System-level webhook replay and research-ops job panels are Admin only.


Admin route map

Route Purpose
/admin/research Cross-study dashboard (enrollment, completion, recent activity)
/admin/studies Create and list studies
/admin/studies/new New study form
/admin/studies/[id] Study settings, manual exports, export schedules, webhooks, framework links
/admin/studies/[id]/conditions Experimental arms
/admin/studies/[id]/tasks Task chain configuration
/admin/studies/[id]/participants Enrolled participants for this study
/admin/studies/[id]/artifacts Linked research artifacts
/admin/studies/[id]/analytics Descriptive stats + inferential ANOVA panel
/admin/studies/[id]/coding Rubric, raters, assignment generation, reliability
/admin/participants Cross-study participant search
/admin/events Event log and queue monitoring

Each study page includes a tab nav: Settings · Conditions · Tasks · Participants · Artifacts · Analytics · Coding.


How to build a study (step by step)

1. Create the study shell

  1. Go to /admin/studiesNew study
  2. Fill in title, slug (auto-generated if blank), abstract, description, and public summary (shown on /studies/[slug])
  3. Set study type (Experiment, Survey, Longitudinal, AI Task, etc.)
  4. Save — you land on the study settings page

2. Add experimental conditions

  1. Open Conditions tab → New condition
  2. For each arm, set:
    • Name and slug (unique within the study)
    • Control flag (one arm is typically control)
    • Order — display / assignment ordering
    • Config (JSON) — arm-specific settings consumed by tasks, e.g.:
{
  "aiEnabled": true,
  "frictionProfile": "purposeful"
}

How assignment works: On enrollment, participants are assigned uniformly at random to one condition when the study has any conditions defined.

3. Build the task chain

  1. Open Tasks tab → New task
  2. Configure each task:
Field Purpose
Title / slug Identifiers; slug used in URLs and sequencing
Task type WRITING, SURVEY, AI_ASSISTED, REFLECTION, TECHNICAL, LEARNING
Condition Blank = all arms; or pick one arm for arm-specific tasks
Order Default linear sort when no explicit nextTaskSlug
Config (JSON) Instructions, validation, sequencing, survey fields, AI prompts

Task config keys (stored in Task.config):

Key Purpose
instructions, prompt, placeholder Participant-facing copy
minWords, maxWords, timeLimitMinutes Validation
fields[] Survey fields: text, textarea, scale, choice
requiresTaskSlug Prerequisite — prior task must be completed to unlock
nextTaskSlug Explicit next task after submit
branchRules[] Conditional routing by response value
optional Excluded from study completion requirements
aiSystemPrompt System prompt for AI-assisted tasks

Example writing task config:

{
  "instructions": "Read the scenario and write a critical analysis.",
  "prompt": "Evaluate the rollout plan below…",
  "minWords": 100,
  "requiresTaskSlug": "agency-baseline",
  "nextTaskSlug": "offloading-post"
}

Example branch rule:

{
  "branchRules": [
    {
      "field": "confidence",
      "operator": "gte",
      "value": "5",
      "nextTaskSlug": "advanced-reflection"
    }
  ]
}

Operators: eq, gte, lte, contains.

Sequencing logic (runtime):

  1. Participant sees tasks where conditionId is null or matches their assigned arm
  2. A task is locked until requiresTaskSlug (if set) is completed
  3. After submit, next task = first matching branch rule → else nextTaskSlug → else next incomplete unlocked task by orderIndex
  4. Study is complete when all non-optional tasks are done

4. Configure recruitment and completion

On the study Settings tab:

Field Purpose
Status Lifecycle stage (see below)
Public study page Show on /studies when status allows
Recruitment goal Target N (informational)
Completion code prefix e.g. PFDF — used in SONA handoff codes
External credit instructions Shown to participants on completion
Variables (JSON) Document IVs/DVs for your protocol
Dissemination links (JSON) Link frameworks, media, artifacts on public study page

Study status lifecycle:

DRAFT → INTERNAL_REVIEW → RECRUITING → ACTIVE → PAUSED → COMPLETED → PUBLISHED → ARCHIVED
Status Public listing New enrollments
RECRUITING, ACTIVE, PUBLISHED Yes (if public visible) Yes
Others No No

Set Public study page + status RECRUITING or ACTIVE to go live.

5. Link frameworks and artifacts

  • Framework links — on Settings tab, connect published frameworks for dissemination
  • Artifacts tab — attach research artifacts (protocols, codebooks, instruments)

6. Configure exports and schedules

On the study Settings tab (export panels):

Manual exports — download immediately:

Export kind Format Contents
PARTICIPANTS CSV Anonymized IDs, status, condition, completion codes, counts
TASK_RESPONSES CSV Per-response preview + full response JSON
EVENTS JSON Anonymized event log for this study
ANALYSIS_WIDE CSV One row per participant — wide analysis dataset
BLINDED_RATER_PACKET CSV Blinded labels + response text for external coding

Scheduled exports — one schedule per export kind:

  • Frequency: DAILY or WEEKLY
  • Hour (UTC), optional notify email
  • Cron job GET /api/cron/run-export-schedules processes due schedules

Storage behavior:

  • Exports under 512 KB (configurable via EXPORT_S3_THRESHOLD_BYTES) stay in Postgres
  • Larger exports upload to S3 when EXPORT_S3_* is configured
  • Download persisted exports from history or via GET /api/admin/research/exports/[id]

7. Set up status webhooks (optional)

On Settings tab → Status webhook:

  • Webhook URL — receives POST on status change
  • Signing secret — enables X-HCLAB-Signature: sha256=… HMAC header
  • Notify on statuses — check specific statuses, or leave all unchecked to fire on every change

Deliveries are queued and processed by cron (/api/cron/process-webhooks). View delivery history on the study webhook panel.

8. Configure dual-rater coding

Open Coding tab:

  1. Save rubric — JSON dimensions array:
[
  { "id": "argument_quality", "label": "Argument quality", "min": 1, "max": 4 },
  { "id": "evidence_quality", "label": "Evidence quality", "min": 1, "max": 4 }
]
  1. Task slugs — comma-separated slugs to include (empty = default writable task types)
  2. Add raters — by email; user must have signed up first
  3. Generate assignments — requires rubric + at least 2 raters

Generation creates one assignment per (completed response × rater). Each response gets a shared blind label (R-001, …) with no condition exposed to raters.

Raters score at /research/code. Cohen's κ appears on the Coding tab when two raters submit scores for the same response.

9. Configure inferential analysis

Open Analytics tab → Inferential analysis panel:

  1. Set outcome fields — column names from the wide analysis dataset, e.g. task_agency-baseline_agency_ownership
  2. Optionally set covariates
  3. Save — the panel runs descriptive stats by condition and one-way ANOVA (F, p, η²)

Outcome field names follow the pattern task_{taskSlug}_{fieldId} for survey/writing responses. Rater dimension columns use rater_{dimensionId}.

Note: analysisConfig is saved from the Analytics page, not the main study form.


How exports and analytics connect

Participant completes tasks
        ↓
TaskResponse rows (JSON payloads)
        ↓
buildWideAnalysisRows()  →  ANALYSIS_WIDE CSV
        ↓
analysisConfig.outcomeFields  →  ANOVA by condition

For coding reliability, submitted CodingScore rows feed κ calculations separately from the wide export.


PFDF seed template

Running npm run db:seed creates a reference study you can inspect and clone conceptually:

Property Value
Slug purposeful-friction-pilot
URL /studies/purposeful-friction-pilot
Arms non-ai, frictionless-ai, purposeful-friction-ai
Completion prefix PFDF
Demo participants pfdf-demo-*@thehclab.com / password pfdf-demo

Seed files:

  • prisma/seed-pfdf-study.ts — study, conditions, tasks, rubric, analysis config
  • prisma/seed-pfdf-demo-participants.ts — synthetic completions + coding scores

Use this as a working example of multi-arm task chains, completion codes, exports, and inferential panels.


Environment variables (research ops)

Variable Purpose
CRON_SECRET Bearer auth for cron routes (required in production)
EVENT_QUEUE_DISABLED "true" = write events synchronously (debug)
EXPORT_S3_BUCKET, AWS_*, EXPORT_S3_* Large export storage
OPENAI_API_KEY, OPENAI_MODEL AI-assisted task suggestions
RESEND_API_KEY, RESEARCH_ADMIN_EMAIL Enrollment/completion/export emails
AUTH_URL / NEXT_PUBLIC_SITE_URL Export download links in scheduled emails

See Usage & configuration → Environment variables for the full reference.


Related documentation

  • Studies & participation — participant-facing flows, consent, task runner
  • Background jobs — cron endpoints and event queue
  • Roles & permissions — researcher vs admin access