---
title: Getting started
description: Set up PharmaFlow on your machine, prerequisites, install, environment configuration, demo seed, and running the apps.
---

This page gets you from a clean machine to a running pharmacy. The goal is a local instance where you can sign in as admin, ring up the demo sale, and see stock move.

### Prerequisites

Before you clone the repository, make sure your machine has:

- **Bun 1.4.3** - the runtime and package manager, pinned in the root `package.json` (`packageManager: "bun@1.4.3"`).
- **Node.js 22.12 or newer** - required by Blume, the docs tool in `apps/knowledgebase` (its `package.json` declares `node >= 22.12.0`).
- **Git** - to clone the repository.

You do not need a Postgres server to run the demo. The demo database is SQLite, and the seed writes the demo file into the packages/database data directory chosen by `packages/database/src/paths.ts`. Point `DATABASE_URL` at Postgres only when you want the multi organization tenant schemas described in `apps/server/src/core/database/tenancy.ts`.

### Clone and install

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

### Configure your environment

The server reads its config with `readEnv` in `apps/server/src/core/config/env.ts`, which reads the Bun runtime env first and `process.env` second. Copy the examples and fill in the values:

```bash
cp apps/server/.env.example apps/server/.env
cp apps/register/.env.example apps/register/.env
```

```env
JWT_SECRET=<at-least-32-characters-long-random-string>
PORT=8000
LOG_LEVEL=info
TRUST_PROXY=false
```

`apps/server/.env.example` documents every key, including `JWT_EXPIRE_MINUTES` (default 480), `ALLOWED_ORIGINS` (the default already includes the `tauri://localhost` desktop origins), `LOG_PRETTY`, and the `AWS_*` keys that configure S3 image storage in `apps/server/src/core/storage/storage.ts`. `apps/server/src/core/auth/token.ts` refuses to sign tokens with a `JWT_SECRET` shorter than 32 characters.

You can leave `DATABASE_URL` empty. The server then opens the SQLite file that `resolveDatabaseFile()` in `packages/database/src/paths.ts` resolves inside the packages/database data directory (`apps/server/src/core/database/db.ts`). Set `DATABASE_URL` to run against Postgres instead; the server detects the backend with `usesPostgres()` in `apps/server/src/core/database/db.ts`.

### Seed the demo data

```bash
bun --cwd packages/database seed
```

This deletes and recreates the database at `DATABASE_PATH`, defaulting to the file `defaultTarget` in `packages/database/src/seed.ts` resolves inside the packages/database data directory (`packages/database/src/paths.ts`). It creates the demo branches, users, medicines, batches, and the `DEMO10` coupon. Demo logins are `admin@demo.pharmaflow`, `pharm1@demo.pharmaflow`, and `pharm2@demo.pharmaflow`, all with password `Demo@1234`.

### Run the apps

```bash
bun run dev:server
bun run dev:register
bun run dev:knowledgebase
```

- The API serves `http://localhost:8000`, with `GET /health` as the smoke check (`apps/server/src/index.ts`). Every feature route mounts under `/api/v1` (`apps/server/src/app.ts`).
- The register runs on `http://localhost:3000`.
- The docs run on the URL Blume prints, with Guides on `/` and the API reference on `/api` (`apps/knowledgebase/blume.config.ts`).
- For the offline desktop app, run `bunx -p @tauri-apps/cli tauri dev` from the repository root. `apps/console/tauri.conf.json` wraps the register UI and its `beforeDevCommand` starts the register dev server for you.

Root scripts you will use most: `bun run dev:server`, `dev:register`, `dev:knowledgebase`, `dev:marketing`, `dev:app` (server plus register through turbo), `docs:api` (regenerates `apps/knowledgebase/openapi.json` from the server routes), `typecheck`, `lint`, and `format` (root `package.json`).

### Next steps

**[Understand the architecture](/architecture)**

Read how branches, auth, stock movements, VAT, and sync work before changing code.

**[Browse the API](/api)**

Open the generated reference and try the login and list endpoints.
