尚未收集仓库信息。
尚未检测到更新。GitHub 发布版本后会显示在这里。
Open-source clinic management system for doctors and receptionists: patient registration, appointment booking, OPD queue, e-prescriptions with Indian medicine autocomplete, billing and invoices. Built with Next.js 16, React 19, TypeScript and SQLite.
翻译准备中
取自仓库 README
正在加载完整 README。
查看完整 README ↗One login for the whole clinic: the front desk runs the day, the doctor runs the consultation.
A role-based clinic management app for doctors and receptionists: patient registration, appointments, a live waiting queue, prescriptions with medicine autocomplete, and billing.
Quick start · Screenshots · Features · Roles & permissions · Architecture · Project structure
Small clinics often run on paper registers, a token counter and a separate billing book. Clinicdesk puts that workflow in one place:
Both roles sign in on the same login page. The role is stored in the database, never chosen at login, and every page, Server Action and API route checks permissions on the server.
Screenshots were captured from a local production build (
next build && next start) using a sample database. The patients and visits are made-up demo data; the medicine suggestions come from the real CSV dataset.
Every action is guarded by a permission from lib/permissions.ts. Doctors get every receptionist permission plus the clinical ones.
| Permission | What it allows | Receptionist | Doctor |
|---|---|---|---|
patients:read | Search patients, view profiles and visit dates | ✅ | ✅ |
patients:write | Register and edit patients | ✅ | ✅ |
appointments:manage | Book, reschedule, cancel appointments | ✅ | ✅ |
queue:manage | Check in patients, maintain the waiting queue | ✅ | ✅ |
invoices:manage | Create invoices, update payment status, print | ✅ | ✅ |
clinical:read | View diagnoses, notes, medical history, prescriptions | ❌ | ✅ |
clinical:write | Record consultations, write prescriptions, medicine search | ❌ | ✅ |
How it is enforced
requirePermission(...) from lib/auth.ts; API routes call checkApiPermission(...) and return 401/403 JSON. Hiding buttons is only a convenience.allergies and medical_history unless the user has clinical:write.extra_permissions column (e.g. clinical:read).httpOnly, SameSite=Lax cookie; the database stores only its SHA-256 hash. Logging out deletes the row, so the cookie stops working immediately. Passwords are hashed with bcrypt (cost 12).proxy.ts sends requests without a session cookie to /login (or returns 401 for /api/*) before any page renders.flowchart LR
B["Browser<br/>(doctor or receptionist)"] -->|"request + session cookie"| P["proxy.ts<br/>no cookie → /login"]
P --> R["Pages · Server Actions · API routes<br/>(app/)"]
R -->|"requirePermission()"| A["lib/auth.ts<br/>session → user → permissions"]
A -->|"SHA-256 token lookup"| DB[("SQLite<br/>data/clinic.db")]
R -->|"plain SQL via lib/db.ts"| DB
CSV["data/medicines.csv"] -->|"npm run db:import-medicines"| DB
loading.tsx, so navigation shows a skeleton instantly while the server renders the page.app/actions/; each one re-checks permissions.node:sqlite with plain SQL. One file holds users, sessions and clinic data. The full schema is in lib/schema.mjs.| Table | Purpose |
|---|---|
users | id, name, username, password_hash, role (doctor / receptionist), extra_permissions |
sessions | Hashed session tokens with expiry (7 days) |
patients | Demographics, contact details, allergies, medical history |
appointments | Date, time, reason, status (scheduled, arrived, completed, cancelled, no_show) |
visits | One per arrival: queue number, status, complaints, diagnosis, notes, advice, doctor |
prescription_items | Medicines on a visit's prescription |
invoices, invoice_items | Bills, line items, payment status and method |
medicines | Imported from the CSV for autocomplete |
Requirements: Node.js 22.13 or newer (for node:sqlite; developed on Node 26) and npm.
git clone <your-repo-url> clinicdesk
cd clinicdesk
npm install
The medicine autocomplete needs the A–Z Medicines Dataset of India CSV. It is not committed (≈32 MB), so place it at data/medicines.csv. The expected columns are:
id,name,price(₹),Is_discontinued,manufacturer_name,type,pack_size_label,short_composition1,short_composition2
Then create the database, the starter accounts and the medicine table, and start the app:
npm run setup
npm run dev
Open http://localhost:3000 and sign in. npm run setup prints:
Saved doctor account "doctor".
Saved receptionist account "reception".
Passwords are the defaults in scripts/seed.mjs unless you set the SEED_* env vars.
Imported 253973 medicines from data/medicines.csv.
| Username | Role | Lands on |
|---|---|---|
doctor | Doctor | /doctor |
reception | Receptionist | /reception |
The starter passwords are development defaults defined in scripts/seed.mjs. Change them before using real patient data (see below).
npm run build
npm start
A typical day:
# Create a user, or reset an existing user's name/role/password
npm run user:create -- <doctor|receptionist> <username> "<Full Name>" <password>
# Example
npm run user:create -- doctor drmehta "Dr. Anil Mehta" "a-strong-password"
Usernames are case-insensitive and passwords must be at least 8 characters.
| Command | Description |
|---|---|
npm run dev | Start the development server |
npm run build / npm start | Production build / serve it |
npm run lint | Run ESLint |
npm run setup | db:seed + db:import-medicines |
npm run db:seed | Create or update the doctor and reception starter accounts |
npm run db:import-medicines [-- file.csv] | (Re)import the medicines CSV, default data/medicines.csv |
npm run user:create -- … | Create or update a staff account |
No environment variables are required. Optional settings:
| Variable | Default | Used by |
|---|---|---|
DATABASE_PATH | data/clinic.db | App and all scripts: location of the SQLite file |
SEED_DOCTOR_PASSWORD | value in scripts/seed.mjs | npm run db:seed |
SEED_RECEPTIONIST_PASSWORD | value in scripts/seed.mjs | npm run db:seed |
NODE_ENV | set by Next.js | When production, the session cookie is marked Secure (HTTPS only) |
data/*.db and data/*.csv are git-ignored, so patient data and the large dataset never end up in the repository.
app/
├── (app)/ # Logged-in pages, sharing the role-aware sidebar layout
│ ├── layout.tsx # Reads the session, builds doctor vs receptionist navigation
│ ├── doctor/ # Doctor dashboard (clinical:write)
│ ├── reception/ # Front-desk dashboard
│ ├── patients/ # Search, register, profile, edit
│ ├── appointments/ # Day view, booking, reschedule
│ ├── queue/ # Waiting queue and walk-in check-in
│ ├── invoices/ # List, create, payment status
│ └── visits/[id]/ # Consultation + prescription editor (doctor)
├── actions/ # Server Actions: auth, patients, appointments, queue, visits, invoices
├── api/medicines/ # GET ?q= → medicine autocomplete (clinical:write)
├── api/me/ # GET → current user and permissions
├── print/ # Printable invoice and prescription pages
├── login/ # Shared sign-in page
└── forbidden/ # 403 page
components/app/ # App components (tables, forms, autocomplete, loading skeleton)
components/ui/ # shadcn/ui (Base UI) primitives
lib/
├── schema.mjs # All tables in plain SQL (shared by app and scripts)
├── db.ts # SQLite connection + all/get/run/transaction helpers
├── session.ts # Session cookie create / read / delete
├── auth.ts # getCurrentUser, requirePermission, checkApiPermission
├── permissions.ts # Roles, permissions, role → permissions map
└── queries.ts # Shared read queries
scripts/ # seed, create-user, import-medicines
proxy.ts # Redirects requests without a session cookie to /login
docs/images/ # README logo and screenshots
There is no automated test suite yet. The available checks are:
npm run lint
npx tsc --noEmit
npm run build
tsc and build pass. npm run lint currently reports two react-hooks/set-state-in-effect errors in shadcn-generated files the app does not use (components/ui/carousel.tsx, hooks/use-mobile.ts); the application code itself lints cleanly.
During development both roles were checked manually against a production build, including by replaying real Server Action requests with the other role's cookie:
| Check | Result |
|---|---|
| Wrong password is rejected; no session cookie is set | Passed |
doctor → /doctor, reception → /reception after login | Passed |
An extra role=doctor field in the login form is ignored | Passed |
/api/medicines: logged out 401, receptionist 403, doctor gets results | Passed |
| Receptionist replaying the doctor's Start consultation / Save consultation actions changes nothing | Passed |
Receptionist cannot write allergies / medical_history via the edit form | Passed |
| Receptionist's profile and edit pages contain no allergy or medical-history values in the HTML | Passed |
| Doctor can open every receptionist page | Passed |
After logout the old session cookie is rejected (401) | Passed |
Not implemented yet:
extra_permissionscomponents/app/letterhead.tsx)