Skip to content

Getting Started

Ankit Upadhyay edited this page Aug 13, 2026 · 1 revision

Getting started

This page takes you from a fresh clone to a running staff application with demo data, using only commands that work today. It is for a developer setting up for the first time.

Prerequisites

Tool Version Notes
Node.js 22 Pinned in .nvmrc. engine-strict=true in .npmrc means a different major fails the install rather than warning.
pnpm 10.30.1 Pinned in the root package.json packageManager field. Install it through corepack, not globally.
PostgreSQL 17 Only needed for database work. The web app runs without it.
Docker any recent Optional, the easiest way to get Postgres.

Clone and install

git clone https://github.com/YosemiteCrew/openrunic.git
cd openrunic
corepack enable
pnpm install

pnpm install takes longer than you might expect the first time. pnpm-workspace.yaml sets minimumReleaseAge: 4320, which refuses any package version published in the last three days as a supply-chain guard, and pnpm 10 blocks postinstall scripts except for the six packages on the onlyBuiltDependencies allow list.

The prepare script installs husky hooks. From this point, committing runs Prettier and secret scanning on staged files, and pushing runs lint and type-check.

Run the staff application

The web app runs in mock mode by default. It needs no database, no API, and no configuration.

pnpm --filter web dev

Open http://localhost:3000. You will see the public landing page. The application itself starts at http://localhost:3000/schedule.

Mock mode is the default because apps/web/src/lib/api/config.ts resolves anything other than the literal string live to mock. Every screen reads from fixtures in apps/web/src/lib/api/mock/. The top bar shows a "Demo data" badge so nobody mistakes it for real state. See Web app for what mock mode does and does not do.

The 26-route staff application is on the feat/emr-app branch and has not merged to dev yet. On dev, apps/web is still the landing skeleton.

Run the API

pnpm --filter api dev

The API listens on port 4000 by default. Three endpoints are public:

curl http://localhost:4000/healthz
curl http://localhost:4000/fhir/metadata
curl http://localhost:4000/openapi.json

Everything else needs a bearer token. The demo resolver accepts four synthetic tokens across two synthetic tenants:

curl -H 'Authorization: Bearer dev-clinician-a' \
  'http://localhost:4000/bff/v0/patients?pageSize=5'

The four tokens are dev-clinician-a, dev-frontdesk-a, dev-biller-a, and dev-clinician-b. The last one belongs to a different tenant, which makes cross-tenant behaviour easy to try by hand. See API service.

Set up the database

Only needed for schema work, seeding, or running the API against real storage.

Start Postgres:

docker run --name openrunic-db -e POSTGRES_PASSWORD=postgres \
  -e POSTGRES_DB=openrunic -p 5432:5432 -d postgres:17-alpine

Prisma reads a package-local .env, not a root one:

cp packages/database/.env.example packages/database/.env

Fill in DATABASE_URL and DIRECT_URL. DATABASE_URL is what the application connects through and may point at a pooler. DIRECT_URL is what Prisma Migrate uses and must point straight at Postgres. Locally they are usually the same value.

Then:

pnpm --filter @openrunic/database db:generate   # generate the client
pnpm --filter @openrunic/database db:deploy     # apply the migration history
pnpm --filter @openrunic/database db:seed       # load the demo practice

The seed builds a deterministic synthetic practice: one organisation, facilities, staff, twenty patients, a week of appointments, encounters, notes, orders, results, charges, claims, and a verifiable audit chain. It is entirely reproducible, with no random source and no wall clock, so two runs produce byte-identical rows. It refuses to run when NODE_ENV is production unless OPENRUNIC_SEED_FORCE is set.

Point the web app at the API

NEXT_PUBLIC_API_MODE=live NEXT_PUBLIC_API_BASE_URL=http://localhost:4000 pnpm --filter web dev

Two things to expect. Authentication is not wired, so the web app sends no Authorization header and the API answers 401, which the screens render as an honest error state rather than hiding. And only the schedule, patients, and chart screens have a live path at all; admin, reports, orders, results, inbox, and billing stay on fixtures in either mode, because the API answers 501 for those aggregates today.

Run Storybook

pnpm --filter @openrunic/ui storybook

Opens on port 6007. 143 stories across the 22 components, with the accessibility addon enabled. See Component library.

The commands that matter

Scope commands to what you are working on. Repo-wide runs are the slow path.

pnpm --filter <workspace> dev
pnpm --filter <workspace> lint
pnpm --filter <workspace> type-check
pnpm --filter <workspace> test
pnpm turbo run build --filter=<workspace>

Workspace names: web and api for the apps; @openrunic/types, @openrunic/fhir, @openrunic/database, and @openrunic/ui for the packages. Turbo filters want the full package name; pnpm --filter accepts either.

Repo-wide:

pnpm dev          # every app in dev mode
pnpm lint
pnpm type-check
pnpm test
pnpm build
pnpm verify       # lint + type-check + test + build
pnpm format       # Prettier write
pnpm check:secrets
pnpm doctor       # react-doctor

Ports

Service Port
apps/web 3000
apps/portal 3300
apps/api 4000
Storybook 6007
PostgreSQL 5432

Where to go next

Clone this wiki locally