Pair Research is a group collaboration method developed by Miller, Zhang, Gilbert, and Gerber to pair members together each round so they can work through one another’s blockers and projects. Based on the original Pair Research method from Delta Lab, this application extends the earlier Google Sheets and spreadsheet-based workflow into a full web app where users can create customized groups, generate pairings, view analytics, and support collaboration across specific subgroups, such as professors and students in a research lab.
- lets people create and join groups
- tracks each member's current task
- collects "how much can I help?" ratings between members
- builds pairings for the current round
- shows live group updates in realtime
- supports group settings, roles, invitations, and profile avatars
- TanStack Start + Vite
- React 19 + TypeScript
- Tailwind CSS v4 + shadcn/ui
- Prisma for app data (orm)
- Supabase for auth and realtime
- Cloudflare Workers for deployment
- Cloudflare R2 for avatar storage
- Cloudflare Turnstile for bot protection
- Vitest + Testing Library for unit and component tests
- Playwright for end-to-end tests
src/
routes/ Route files and page entry points
features/ Feature code by domain
auth/ Sign in, sign up, password reset, redirects
account/ Profile editing and avatar upload
groups/ Group creation, invites, tasks, pairing, settings
home/ Public landing page
shared/ Shared UI, config, server helpers, styles
prisma/ Prisma schema and generated client
e2e/ Playwright tests
tests/ Test setup and mocks
/public home page/loginsign in/signupsign up/forgot-passwordrequest password reset/reset-passwordset a new password from the reset link/groupslist joined and pending groups/groups/createcreate a group/groups/$slugactive group page/groups/$slug/settingsgroup settings/accountprofile and avatar settings
Each member adds a task for the current round and rates how much they can help on other members' tasks. The app uses those ratings to build pairings.
The pairing code lives under src/features/groups/lib/pairing. It tries a stable-roommates pass first, then fills any remaining unmatched people with maximum-weight matching. This keeps pairings stable when possible and still gives good results for hard or odd-sized pools.
Copy .env.example to .env and fill in the values.
VITE_SUPABASE_URLpublic Supabase project URLVITE_SUPABASE_PUBLISHABLE_KEYpublic Supabase browser keyDATABASE_URLPostgres connection string for PrismaSUPABASE_SECRET_KEYserver-only Supabase secret for admin actionsVITE_SITE_BASE_URLpublic site URL used for links and auth redirectsR2_PUBLIC_DOMAINpublic base URL for avatar files in R2VITE_CLOUDFLARE_TURNSTILE_SITE_KEYpublic Turnstile site keyCLOUDFLARE_TURNSTILE_SECRET_KEYserver-only Turnstile secret
R2_BUCKETCloudflare R2 bucket binding configured inwrangler.jsonc
pnpm install
cp .env.example .env
pnpm devThe local dev server runs on http://127.0.0.1:3000.
If you change the Prisma schema, regenerate the client:
pnpm run prisma:generatepnpm devstart the app locallypnpm dev:e2estart a local server for Playwrightpnpm buildtypecheck and buildpnpm previewpreview the production buildpnpm lintrun ESLintpnpm typecheckrun TypeScript checkspnpm test:unitrun Vitestpnpm test:e2erun Playwright smoke testspnpm test:e2e:authrun authenticated Playwright testspnpm testrun unit tests and e2e testspnpm deploybuild and deploy with Wrangler
For TypeScript changes, run:
pnpm testUseful focused commands:
pnpm test:unitfor fast local feedbackpnpm test:e2efor public route smoke testspnpm test:e2e:authfor authenticated flows
Playwright uses a local server by default. Authenticated e2e tests require PLAYWRIGHT_AUTH_EMAIL and PLAYWRIGHT_AUTH_PASSWORD.
The app deploys to Cloudflare Workers with Wrangler.
pnpm deployBefore deploying, make sure:
- the required environment variables are set
- the
R2_BUCKETbinding exists - Wrangler is authenticated for the target Cloudflare account
- Generated files such as
src/routeTree.gen.ts,cloudflare-env.d.ts, andprisma/generated/client/**should not be edited by hand.