Pharma Care Pro — a self-hosted pharmacy & small-clinic management system.
Website · Case study · API Docs · Wiki · Report an Issue
KinetiRx runs your pharmacy's day-to-day operations — point-of-sale billing, medicine inventory, patient records, OPD scheduling, a due-khata (credit ledger), daily cash-drawer reconciliation, expense tracking, and role-based staff accounts — on a Postgres database you own, on hardware you control. No subscription, no third-party SaaS dependency for core operations. Optional Gemini AI integration adds purchase-bill OCR scanning and a clinical assistant when you supply an API key; without one, the app runs fully offline in fallback mode.
Built for independent pharmacies and small clinics that want a real, auditable system of record instead of a spreadsheet — and that would rather self-host than hand patient and financial data to a SaaS vendor.
- Features
- Screenshots
- Tech stack
- Quick start (Docker Compose)
- Self-hosting on CasaOS / ZimaOS
- Development setup
- Environment variables
- Architecture
- MCP server (AI assistant integration)
- Security notes
- Documentation
- License
- Dashboard — daily/period overview and analytics: today's sales, total dues, drawer cash, stock valuation, revenue-vs-expense and inventory-turnover charts
- Daily Sales — sales register with cash-drawer reconciliation (opening cash, denominations, cash/UPI/card split, closing difference)
- POS — point-of-sale billing with GST invoicing, strip/loose dispensing, discounts, mixed payment modes (cash, UPI, card, due, partial), and 80mm/58mm thermal or A4 receipt printing (zero driver/setup — prints through the OS's native print dialog to whatever printer is already installed)
- Live Sync — a second cashier/pharmacist/director counter sees new sales, stock changes, due-khata updates, and register changes without a manual refresh (Server-Sent Events, not a full duplicate-state sync)
- Master Security PIN — an admin-configurable second factor (separate from login passwords) required to unlock System Reset, with a 5-attempt lockout
- Due-Khata — patient credit ledger (dues, payment history, WhatsApp reminders)
- Medicine Orders — track medicines needed/ordered from distributors, and generate a printable/downloadable/WhatsApp-shareable Purchase Order grouped by distributor straight from the shortage book
- Inventory — medicine & lab-test stock, batch/expiry tracking, rack location, distributor tracking, low-stock and short-expiry alerts
- Inward OCR — AI-powered purchase-bill scanning (Gemini) that extracts line items straight into inventory
- OPD — outpatient visit scheduling and follow-up reminders
- Patients — patient records, visit history, purchase history, blood-test tracking
- Expenses — day-to-day expense logging by category
- Business Development — doctor outreach / marketing campaigns and worksheet tasks
- Employee Management — role-based staff accounts with per-tab permissions
- Invoice Settings — store letterhead, GST/DL numbers, invoice retention policy, printer config
- System Reset — administrative data-reset tooling with a 5-day rolling backup
Every route above (except health check and login) requires a valid JWT and is authorized server-side against the employee's role/permissions — there is no client-side-only access control.
| Dashboard | Smart Pharmacy POS |
|---|---|
![]() |
![]() |
| Medicine Stock Management | Patient Database Profiles |
|---|---|
![]() |
![]() |
| Due Register (Due-Khata) |
|---|
![]() |
| Layer | Stack |
|---|---|
| Backend | Go + Gin, PostgreSQL, JWT auth, bcrypt password hashing |
| Frontend | React 19 + Vite + TypeScript + Tailwind CSS v4, dark/light mode |
| AI | Google Gemini (gemini-3.7-flash) for invoice OCR and a clinical assistant — optional, degrades to offline fallback if unconfigured |
| Deployment | Docker Compose (Postgres + backend + nginx-served SPA); one-click install via the CasaOS/ZimaOS App Store |
| AI tooling | Optional MCP (Model Context Protocol) server — lets Claude or any MCP-aware assistant operate a running KinetiRx instance through tool calls |
git clone https://github.com/Raktim94/KinetiRx.git
cd KinetiRx
cp deploy/.env.example deploy/.env
# Edit deploy/.env and set at minimum:
# POSTGRES_PASSWORD
# JWT_SECRET (openssl rand -hex 32)
# GEMINI_API_KEY (optional — enables AI OCR + assistant)
docker compose -f deploy/docker-compose.yml --env-file deploy/.env up -d --buildOpen http://localhost:3080 in a browser. On first visit you'll land on
a "Create Admin Account" screen — name + password, no manual configuration
needed. (You can instead set KINETIRX_ADMIN_PASSWORD in deploy/.env
before first boot to pre-seed employee ID EMP-ADMIN-1 with that password
and skip the screen — whichever happens first wins.) There is no
password-reset flow yet, so keep your password safe.
The backend API is also published directly on http://localhost:8080
(for curl/health checks/admin scripts); the browser SPA never needs this
since nginx proxies /api/* internally. Postgres itself is not published to
the host by default.
KinetiRx ships a ready-to-use casaos/docker-compose.yml
(x-casaos v2 compose-extension spec) for one-click installation from the
CasaOS/ZimaOS App Store, plus the icon, thumbnail, and screenshots the store
listing needs (all under casaos/ — see that directory's own
README for the full install-now instructions and
publishing workflow).
What it installs: Postgres + the KinetiRx backend + the nginx-served
frontend, wired together on an internal Docker network, with persistent
storage under /DATA/AppData/$AppID. The Postgres password, JWT secret, and
admin password ship with real default values in the manifest — CasaOS has no
mechanism to auto-generate them at install time (verified against 189 real
apps in the official store: none use anything like that). Change all
three before using this beyond a local trial — the install prompt
(tips.before_install) says so, and each field's own description repeats
it.
- Status: images are built and pushed (multi-arch:
amd64,arm64) toghcr.io/raktim94/kinetirx-backendandkinetirx-frontend(tag1.0.0), and the manifest is submitted as a PR toIceWhaleTech/CasaOS-AppStore(Apps/KinetiRx/). Not merged into the official store index yet — PR review can take anywhere from about a day to several weeks. Both ghcr.io packages must be flipped to public visibility (Package settings → Danger Zone, GitHub's REST/GraphQL API cannot do this for a personal-account package) before any install — CasaOS or otherwise — can actually pull them; until that's done, install fails with anunauthorizederror on the image pull. - Installing today, before the PR merges: CasaOS's "Custom
Install" / import-a-compose-file feature accepts
casaos/docker-compose.ymldirectly (or its raw GitHub URL — seecasaos/README.md) — paste its contents in, confirm the pre-filled WebUI port/volume/env fields (pulled from thex-casaosblock), and install. - Category:
Productivity· Architectures:amd64,arm64· App ID:com.nodedr.kinetirx.
Requires Go 1.26+, Node.js, and a local Postgres instance (or run
docker compose -f deploy/docker-compose.yml up postgres for just the DB).
Backend:
cd backend
cp .env.example .env # set DATABASE_URL, JWT_SECRET
go run ./cmd/serverRuns on :8080 by default; migrations in backend/migrations/ run automatically on start.
Frontend:
cd frontend
cp .env.example .env # optional — defaults to http://localhost:8080 if unset
npm install
npm run dev # Vite dev server, http://localhost:5173Other scripts: npm run build (production build), npm run preview (serve the build), npm run lint (tsc --noEmit).
| Variable | Required | Default | Purpose |
|---|---|---|---|
DATABASE_URL |
yes | — | Postgres connection string |
JWT_SECRET |
yes | — | Signs JWT access tokens; min 16 chars enforced at startup, use 32+ random bytes |
KINETIRX_ADMIN_PASSWORD |
no | unset | Optional. If set, pre-seeds the "Master Admin" account (EMP-ADMIN-1) with this password on first boot; bcrypt-hashed, never read again once the employees table has a row. If unset, create the admin account from the app's own first-run screen instead (POST /api/auth/setup) — whichever happens first wins |
GEMINI_API_KEY |
no | unset | Enables AI OCR (/api/ocr/parse-bill) and the clinical assistant (/api/ai/ask); both degrade to a fallback response when unset |
PORT |
no | 8080 |
Backend listen port |
GIN_MODE |
no | release |
Gin mode (debug/release) |
ALLOWED_ORIGINS |
no | http://localhost:5173,http://localhost:3000 |
CORS allow-list for direct (non-proxied) browser access |
| Variable | Required | Default | Purpose |
|---|---|---|---|
VITE_API_URL |
no | http://localhost:8080 (code default) |
Base URL of the backend API; only needed when the backend isn't at the default local port |
| Variable | Required | Default | Purpose |
|---|---|---|---|
POSTGRES_USER |
no | kinetirx |
Postgres role |
POSTGRES_PASSWORD |
yes | — | Postgres password |
POSTGRES_DB |
no | kinetirx |
Postgres database name |
HTTP_PORT |
no | 3080 |
Host port for the frontend (the app you visit) |
BACKEND_PORT |
no | 8080 |
Host port for direct backend access |
Secrets are never committed — .env files are gitignored; only the
.env.example templates are tracked.
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
│ Browser │──HTTP─▶│ frontend (nginx) │──/api─▶│ backend │──▶ PostgreSQL
│ (React │ │ serves the SPA, │ │ (Go + Gin, │ (data of
│ 19 SPA) │◀───────│ reverse-proxies │◀───────│ JWT auth) │ record)
└─────────────┘ │ /api/* same- │ └──────┬──────┘
│ origin │ │
└──────────────────┘ ▼
Google Gemini
(optional — OCR + AI assistant,
falls back offline if unset)
The frontend never talks to the backend cross-origin in production: nginx
proxies /api/* to the backend container over the internal Compose network,
so the browser only ever sees one origin. The backend is the sole source of
truth for authorization — every route (bar health-check and login) checks
the caller's JWT and role/permissions server-side, regardless of what the
SPA renders.
mcp-server/ is a Model Context Protocol
server that lets an MCP-aware AI assistant (Claude Desktop, Claude Code,
etc.) operate a running KinetiRx instance through tool calls — inventory
lookup, patient/due-khata lookup, daily register, recording sales/expenses,
and more. See mcp-server/README.md for the full
tool list and a ready-to-paste client config. It's gated behind the mcp
Compose profile (not part of the always-on stack) since it speaks MCP over
stdio, not a network port:
docker compose -f deploy/docker-compose.yml --env-file deploy/.env \
--profile mcp run --rm -T mcp-server- Passwords are bcrypt-hashed; nothing sensitive is logged.
- JWT access tokens are the only auth mechanism — every non-public route is authorized server-side against the caller's role/permissions.
- Postgres is never published to the host in the Docker Compose or CasaOS deployment paths — only reachable from other containers on the same Compose network.
- There is currently no password-reset flow for the admin account — keep
whatever password you choose (either at the first-run signup screen, or
via
KINETIRX_ADMIN_PASSWORD) somewhere safe. POST /api/auth/setup(first-run account creation) only ever succeeds once — it's permanently rejected the instant any employee row exists, same one-time gateKINETIRX_ADMIN_PASSWORD-based seeding already enforces on the backend.
- Full REST API contract:
backend/API.md - Deeper guides (architecture, deployment troubleshooting, contributor setup, MCP server): see the GitHub Wiki
This project is licensed under the GNU Affero General Public License v3.0. See LICENSE for the full text. If you modify KinetiRx and make it available to users over a network, the AGPL-3.0 requires you to offer those users the corresponding source code.
KinetiRx · made by
Nodedr Infotech Private Limited
· kinetirx.nodedr.com
Read the KinetiRx case study for the product background and design decisions.
Licensed under the AGPL-3.0. A commercial licence is available on request for use without the AGPL obligations. The KinetiRx name and logo are not covered by the AGPL.






