Skip to content
PharmaFlow Knowledgebase
Esc
↑↓navigate↵open⌘Jpreview
On this page

Running the Platform

Install prerequisites, configure env, seed the demo, boot server plus register plus docs, and verify with health and login.

You go from a clean machine to a working pharmacy in about ten minutes. You need Bun, pinned to 1.4.3 by the packageManager field in package.json, and Git. The server runs on SQLite through DATABASE_PATH by default, and it switches to PostgreSQL only when you set DATABASE_URL.

Check your prerequisites

You confirm the toolchain before cloning so version errors surface early. The pinned bun version lives in the packageManager field of the root package.json; a mismatched runtime is the most common cause of lockfile churn.

bun --version

If it does not print 1.4.3, install that version before you continue.

Clone and install

You clone the repo, check out the branch you are working on, and install every workspace at once.

git clone https://github.com/vernonthedev/pharmaflow.git
cd pharmaflow
bun install

Configure the server environment

You copy apps/server/.env.example to apps/server/.env and fill in your values. Bun loads .env from the working directory when apps/server/src/index.ts boots, and the full key list in the example file is read through readEnv in apps/server/src/core/config/env.ts. JWT_SECRET must be at least 32 characters or every boot fails fast.

cp apps/server/.env.example apps/server/.env

The server defaults to SQLite: leave DATABASE_PATH unset and apps/server/src/core/database/db.ts falls back to resolveDatabaseFile in packages/database/src/paths.ts, which points at a database file under packages/database/data/. Set an absolute DATABASE_PATH to use another SQLite file, or point DATABASE_URL at a Postgres instance instead. PORT serves the API, and ALLOWED_ORIGINS already lists the register, the marketing app, and the Tauri console in the example file.

JWT_SECRET=<at-least-32-characters-long-random-string>
PORT=8000
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3001,tauri://localhost,https://tauri.localhost,http://tauri.localhost

Seed the demo data

You create the demo branches, users, medicines, batches, and the DEMO10 coupon with the seed script in packages/database.

bun --cwd packages/database seed

You now sign in as admin@demo.pharmaflow, pharm1@demo.pharmaflow, or pharm2@demo.pharmaflow, all with password Demo@1234. You reset any time by running the same command again.

Boot server, register, and docs

You run each app in its own terminal. The API serves port 8000, the register serves port 3000, and the docs print their own URL.

bun run dev:server
bun run --cwd apps/register dev
bun run --cwd apps/knowledgebase dev

Verify health and login

You hit GET /health in apps/server/src/index.ts for the smoke check, then you log in and store a token for the rest of your session. Router routes mount under the /api/v1 prefix that apps/server/src/app.ts applies with app.route("/api/v1", apiV1), so auth sits at /api/v1/auth.

curl http://localhost:8000/health
TOKEN=$(curl -s -X POST http://localhost:8000/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@demo.pharmaflow","password":"Demo@1234"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
curl http://localhost:8000/api/v1/auth/me -H "Authorization: Bearer $TOKEN"

Start the desktop console

You run the Tauri v2 console wrapping the register UI from the repository root:

bunx -p @tauri-apps/cli tauri dev

The shell config in apps/console/tauri.conf.json points devUrl at http://localhost:3000 and its beforeDevCommand starts the register dev server for you, so you can skip the separate register terminal when you use the console. The Rust backend lives in apps/console/src.

Next steps

Walk your first counter sale in /guides/selling-end-to-end, connect an offline device in /guides/offline-first-flow, and learn the auth model in /platform/authentication-and-users.

Last updated on October 20, 2026