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

Repository overview

How the PharmaFlow monorepo is split across server features, client apps, and shared packages, and why.

PharmaFlow is a bun workspaces monorepo with turbo task running. Every app lives under apps/* and every shared library under packages/*.

Layout

Path Package What lives there
apps/server @pharmaflow/server Hono API, one folder per feature in src/features
apps/register @pharmaflow/register Next.js point of sale register, English only
apps/console Rust and Tauri Offline desktop shell that hosts the register UI and owns the local mirror, outbox, and sync engine
apps/marketing @pharmaflow/marketing Public marketing site with changelog, terms, privacy, and security pages
apps/knowledgebase @pharmaflow/knowledgebase This Blume documentation site plus the generated openapi.json
packages/database @pharmaflow/database Drizzle schema under schema/ combined into schema.sql, drizzle migrations, translator, multitenancy, and seed scripts
packages/shared @pharmaflow/shared Money, pagination, and response helpers, plus the minor unit currency helpers in src/currency.ts

apps/console has no package.json. It is a Rust and Tauri crate (apps/console/Cargo.toml, apps/console/tauri.conf.json) that wraps the register build and adds the offline engine described next.

What the console adds

apps/console is not a second UI. Its Rust layer owns offline trading:

  • Local mirror - apps/console/src/db.rs creates the pharmaflow.db file in the app data dir from apps/console/sql/local-schema.sql, keeps _device, _sync_state, _outbox, and _offline_sessions as internal tables, and reconciles missing mirror columns on launch.
  • Mirror schema pipeline - apps/console/scripts/build-mirror-schema.ts regenerates apps/console/sql/local-schema.sql from packages/database/schema.sql through the overlays in apps/console/scripts/mirror-overlays.ts and the manifest apps/console/sql/mirror-overlays.json. packages/database exposes the same run as its schema:build and schema:check scripts.
  • Outbox - apps/console/src/outbox/queue.rs freezes client_mutation_id, tax_policy, and the currency fields at queue time, deducts mirror stock earliest expiry first, and records the draw in stock_json.
  • Sync engine - apps/console/src/sync/push.rs batches 50 outbox rows to POST /api/v1/sync/push, apps/console/src/sync/pull.rs follows the since_rev cursor, apps/console/src/sync/bootstrap.rs loads the snapshot, and apps/console/src/sync/apply.rs (reconcile_accepted_sale) rekeys an accepted sale to the server id.
  • Offline identity - apps/console/src/identity/offline_auth.rs verifies a stored password hash and honours the offline_expires_at window, so a till keeps selling while disconnected.

The server feature pattern

Each domain is a folder under apps/server/src/features with a route.ts that mounts one router. Shared concerns live under apps/server/src/core: core/auth/ for JWT (token.ts), passwords (password.ts), the middleware (middleware.ts), and login throttling (login-attempts.ts), core/config/env.ts for environment reads, core/database/ for backend selection, transactions, and tenant scoping (db.ts, tx.ts, tenancy.ts), core/common/ for HTTP helpers, validation, time, and sync visibility (http.ts, validate.ts, time.ts, visibility.ts), core/audit/ for the audit log and outbox (audit.ts, outbox.ts), core/logging/logger.ts, core/openapi/ (document.ts, components.ts), and core/storage/storage.ts for S3.

The mount table lives in apps/server/src/app.ts: it composes the Hono instance and mounts every feature under apiV1, for example apiV1.route("/sales", saleRoutes), then serves the whole router at /api/v1. The Bun entry apps/server/src/index.ts only builds the default exported server object with port and fetch and runs ensureLoginAttemptsTable() from apps/server/src/core/auth/login-attempts.ts on startup.

Where to look next

Last updated on October 20, 2026