Getting started with Pharmacy

Clone the source, configure PostgreSQL, sessions, and S3 storage, apply migrations, create the first user, run onboarding, and deploy.

Requirements

  • Node.js 20 or later (package.json engines is >=20.0.0). The README recommends Node.js 22 for Next.js 16.
  • npm. The repository ships a package-lock.json.
  • A PostgreSQL database you are allowed to migrate.
  • S3-compatible object storage. It is required when NODE_ENV=production.

Hosted app

The hosted app is at pharmacy.openship.org.

Install

git clone https://github.com/openshiporg/openfront-pharmacy.git
cd openfront-pharmacy
npm install
cp .env.example .env

Environment

features/keystone/index.ts will not start without DATABASE_URL and SESSION_SECRET. It also rejects a session secret shorter than 32 characters. The five S3 values fall back to development placeholders outside production. In production they are required.

DATABASE_URL=postgresql://user:password@127.0.0.1:5432/openfront_pharmacy
SESSION_SECRET=replace-with-at-least-32-random-characters   # openssl rand -hex 32

S3_BUCKET_NAME=your-bucket
S3_REGION=your-region
S3_ACCESS_KEY_ID=your-access-key-id
S3_SECRET_ACCESS_KEY=your-secret-access-key
S3_ENDPOINT=https://your-s3-compatible-endpoint

The code also reads these optional settings:

VariableUsed for
SHADOW_DATABASE_URLPrisma shadow database, used when generating migrations
PUBLIC_SIGNUPS_ALLOWEDSet to true to open the dashboard sign-up page (/dashboard/signup). Off by default
SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSWORD, SMTP_FROM, SMTP_STORE_LINKPassword-reset email and links in emails
NEXT_PUBLIC_STRIPE_KEY, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRETStripe payment adapter and the storefront card step
NEXT_PUBLIC_PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, PAYPAL_WEBHOOK_ID, NEXT_PUBLIC_PAYPAL_SANDBOXPayPal payment adapter (see Payment providers)
OPENROUTER_API_KEY, OPENROUTER_MODEL, OPENROUTER_MAX_TOKENSDashboard AI chat (/api/completion)
NEXT_PUBLIC_VIEW_ORDERFallback dashboard field view order when the generated file is missing

Keep .env out of source control.

Migrations and local run

npm run dev

npm run dev runs keystone build --no-ui, applies the checked-in migrations with prisma migrate deploy, and starts Next.js. The migrations/ folder holds 23 migrations: seven inherited from the starter and sixteen Pharmacy migrations.

To change the schema, run npm run migrate:gen against a disposable database. It rebuilds the schema, regenerates the dashboard view order, and runs keystone prisma migrate dev. Commit model changes and their migrations together.

npm run dev applies migrations to whatever DATABASE_URL points at.

Once running:

  • Storefront: /
  • Customer account: /account
  • Operator dashboard: /dashboard
  • GraphQL API: /api/graphql

The package defines dev, build, start, lint (ESLint), migrate, migrate:gen, and release:migrate. It has no test or typecheck script. The README also lists npm run worker:outbox, but that script is not in package.json.

First user

While the database has no users, every request redirects to /dashboard/init. The first account created there gets an Admin role with all 19 permissions. Later accounts never get that role automatically.

Customer accounts are created on the storefront through registerPharmacyCustomer. That mutation refuses to run while no users exist, so the first user must come from /dashboard/init.

Give other staff only the permissions their job needs. A role with dashboard access does not make someone a pharmacist. Licensure is checked by your pharmacy. The app stores the evidence an operator records.

Onboarding

The dashboard shows onboarding cards to users with canManageOnboarding until onboarding is completed or dismissed. The dialog runs runPharmacyOnboarding with one of two templates:

TemplateWhat it creates
Basic Setup (minimal)Organization "Cedar & Elm Pharmacy", one location, owner membership for you, the "Pay at pickup" provider (installed), one supplier, two OTC products with opening-stock lots, and four integration provider records (eRx, Wholesaler, Insurance, Tax), all unconfigured
Complete Setup (full)Everything above, plus a Stripe provider (not installed), a second supplier, nine products in total (eight OTC and one prescription item, "Amoxicillin 500 mg Capsules"), one drug reference, three sample patients, and two unverified prescribers

Onboarding also records a cash policy with a 0% tax rate, reviewed by you. It creates no prescriptions.

Onboarding runs only on a new install. It fails if you already have an active membership, or if the seed organization or location code already exists. If you already own the seed organization, it marks onboarding complete and returns the existing counts. setPharmacyOnboardingStatus only changes your own onboarding status.

Before dispensing

The Credential review page (/dashboard/platform/credentials) shows a setup checklist. Dispensing needs all of these:

  1. A pharmacist credential review on a staff membership (recordPharmacyStaffCredentialReview).
  2. A prescriber with an NPI and a credential review (recordPharmacyPrescriberCredentialReview).
  3. A drug reference review that marks the drug active and non-controlled (recordPharmacyDrugReferenceReview).
  4. A recorded cash and sales-tax policy (recordPharmacyCashPolicy).
  5. A stocked prescription product.
  6. A fill policy for the organization (recordPharmacyFillPolicy).

Next: Prepare to dispense, then Deployment.

On this page