Skip to content
This repository was archived by the owner on Jul 18, 2026. It is now read-only.

Latest commit

 

History

281 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TrayLedger — Pharmacy stock, expiry and Dosette operations

TrayLedger

Pharmacy stock, expiry and Dosette operations.

TrayLedger synthetic dashboard workspace

TrayLedger is a self-hosted web application for exploring stock control, expiry-led workflows and Dosette/MDS preparation in a fictional pharmacy group. Its analytics are deterministic and non-ML: forecasts, expiry signals and transfer suggestions are calculated from stored operational data and fixed rules.

Pharmacy teams can otherwise end up reconciling batches, expiry dates, location balances and Dosette preparation across fragmented records. TrayLedger keeps those operational records together while leaving every stock-changing action explicit and reviewable.

Safety boundary: TrayLedger is not a clinical decision-support or dispensing system, has no live NHS integration or endorsement, and is not approved or certified medical software. The bundled seed data is synthetic. Do not use the repository with real patient data without independent professional legal, security, privacy, clinical and regulatory review of the intended deployment.

Verified capabilities

Stock operations

  • Role- and location-scoped inventory, receiving, counts, adjustments and transfers.
  • Product, pack, stock-item and batch records with quantity and movement history.
  • Expiry, dead-stock, stock-attention, movement, valuation and workload reports, with CSV export where implemented.

Dosette operations

  • Dosette periods, cycles, medication lines, picking information and explicit prepared, checked and stock-deducted states.
  • An A4 landscape Dosette preparation sheet for browser printing.

Administration and analytics

  • Patients, notes, review records, work queues, alerts and an audit event view.
  • Deterministic demand forecasts and stock-transfer suggestions.
  • Selective local group archives and restoration, with mandatory encryption in the production settings profile; these are not full database backups.
  • A React 19/Vite client and Django 5.2 REST API backed by PostgreSQL.

See the feature matrix for boundaries and the known limitations before evaluating the product.

The print feature is a preparation sheet, not a medication-label or automated picking-list generator. Analytics remain operational aids requiring human review.

Architecture

flowchart LR
    Browser["Browser"] --> Frontend["React and Vite frontend"]
    Frontend --> API["Django REST API"]
    API --> Auth["Session, CSRF and role checks"]
    API --> Services["Stock, Dosette, reporting and backup services"]
    Services --> Database["PostgreSQL"]
    Services --> Analytics["Deterministic non-ML analytics"]
    Services --> Print["Browser Dosette preparation sheet"]
Loading

The architecture guide describes trust boundaries, domain services and data flow without assuming unimplemented cloud services.

Technology stack

Layer Technology Version Purpose
Backend Python / Django / Django REST Framework Python 3.12+, Django 5.2 API, permissions and operational services
Frontend TypeScript / React / Vite React 19, Vite 7 Browser interface and local development server
Data PostgreSQL 17 Relational operational data store
Client data TanStack Query 5 API state and cache management
Verification pytest / Vitest / Playwright Locked manifests Backend, component and browser workflows
Local runtime Docker Compose 2.24+ Loopback-bound development stack

Quick start with Docker

Requirements: Git and Docker with Compose v2.24 or newer.

From a parent working directory, clone the current repository address and enter the checkout:

git clone https://github.com/alvinsakhiya/trayledger.git TrayLedger
cd TrayLedger

Then run these commands from the repository root (TrayLedger/):

cp .env.example .env
docker compose up --build -d
docker compose exec backend python manage.py migrate --noinput
docker compose exec backend python manage.py seed_demo

Open http://localhost:5173. Use admin@example.test with the local-only password printed by seed_demo; every seeded account is listed in Demo access. The API health route is http://localhost:8000/api/health/.

Stop the stack with:

docker compose down

Reset the complete fixed synthetic workspace, including records added to that workspace, from the repository root:

docker compose exec backend \
  python manage.py reset_demo_data --confirm RESET_DEMO_DATA

Run a small real test from the same directory:

docker compose exec frontend \
  npm exec vitest run src/components/brand/AppLogo.test.tsx

The Compose stack is for loopback-bound local development only. Read the quick-start guide for manual setup, reset instructions and safe data handling.

Manual development route

Requirements: Python 3.12+, Node.js 22.13+, npm and a local PostgreSQL 17 database. From the repository root, copy .env.example to .env, change DATABASE_URL to the local database, and set API_PROXY_TARGET=http://localhost:8000.

From backend/ in terminal one:

python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"
python manage.py migrate --noinput
python manage.py seed_demo
python manage.py runserver 127.0.0.1:8000

From frontend/ in terminal two:

npm ci
API_PROXY_TARGET=http://localhost:8000 npm run dev

Stop each development server with Control-C.

Demo access

seed_demo creates five fictional accounts in the local synthetic workspace. Every account shares the same deliberately public local password, which the command also prints after seeding:

Role Username Password Intended access
Administrator admin@example.test DemoPass!2026 Full local demonstration access to every module and location
Superintendent superintendent@example.test DemoPass!2026 Group-wide stock, transfers, analytics, audit and catalogue management; no patient or Dosette access
Pharmacist pharmacist@example.test DemoPass!2026 Example Central: stock, patients, Dosette preparation and deduction, reviews, local user administration
Dispenser dispenser@example.test DemoPass!2026 Example Riverside: day-to-day viewing, receiving and Dosette status updates
Stock employee stock@example.test DemoPass!2026 Stock operations across Example Central and Example Riverside; no patient access

These credentials are created only by the local synthetic demonstration-data workflow. They are intentionally public, must never be reused for any other system, and provide no access to any hosted or production environment. TrayLedger is not approved for real patient or pharmacy data.

Practical notes:

  • The accounts are created by docker compose exec backend python manage.py seed_demo (Docker route) or python manage.py seed_demo from backend/ (manual route); both routes create the same five accounts, and the command refuses to run when DJANGO_DEBUG is false unless --force is passed.
  • Re-running seed_demo resets every demo account's password back to the table value.
  • Reset the whole synthetic workspace with docker compose exec backend python manage.py reset_demo_data --confirm RESET_DEMO_DATA.
  • There is no environment variable for choosing a different demo password; the value is a constant in backend/apps/core/management/commands/seed_demo.py.
  • Sign in at http://localhost:5173 after seeding.

First five minutes

  1. Clone the repository, cd TrayLedger, and copy .env.example to .env.
  2. Start the Compose stack and apply migrations with the commands above.
  3. Seed the explicitly fictional workspace.
  4. Open http://localhost:5173 and confirm http://localhost:8000/api/health/ reports an OK status.
  5. Sign in with admin@example.test and the local-only password printed by seed_demo (see Demo access).
  6. Open Inventory, search for CEN-PAR-001, and inspect its batches without changing stock.
  7. Open Dosette, inspect a fictional patient cycle and preview the preparation sheet without confirming stock deduction.
  8. Run the targeted AppLogo test shown above.
  9. Locate the backend entry point at backend/config/urls.py.
  10. Locate the frontend entry point at frontend/src/main.tsx.

Verification status

Results recorded through 18 July 2026:

Suite Working directory and command Result Notes
Corrected backend SQLite backend/DATABASE_URL="sqlite://:memory:" pytest 786 passed Compatibility database
Corrected backend PostgreSQL 17 backend/pytest with DATABASE_URL set to a PostgreSQL 17 database 786 passed Production-relevant database
Corrected strict backup profile backend/ — SQLite command plus BACKUP_ENCRYPTION_KEY and BACKUP_ENCRYPTION_REQUIRED=True 786 passed Plain-archive tests isolate their fixture only
Targeted timezone matrix backend/ — selected pytest nodes 9 passed twice Normal process environment and TZ=UTC
Backend static/system/dependency checks backend/ — Ruff, mypy, Django, migrations, pip audit/check Passed No formatting, typing, system, migration or dependency failures
Corrected frontend frontend/ — lint, build, test, audit Passed 50 files and 409 tests; zero audit vulnerabilities; 869 KB chunk warning
Browser workflows frontend/npx playwright test 23 passed Fresh synthetic PostgreSQL data
Containers repository root — no-cache build, fresh-volume startup and smoke Passed Migrations, seed, health and non-root application users
Historical strict-profile clean-clone diagnostic backend/pytest 776 passed, 2 failed Development .zip expectations inherited strict .zip.enc behaviour
Historical documented-profile clean clone backend/pytest 777 passed, 1 failed Genuine BST-midnight overdue-date boundary

The overdue defect is corrected: review serializer/filter paths, work-queue status, MDS workload counts and stock-expiry report offsets now share Django's configured-local-date semantics. Overdue review, prepared-cycle and checked-cycle tasks serialize OVERDUE while preserving their action type; due-today and future items retain their workflow status. The browser treats the API review flag and server expiry offset as authoritative. All nine frozen timezone cases pass normally and with TZ=UTC, covering UTC/Europe-London agreement, 00:00-01:00 BST, the previous UTC date versus London's next date, classification, serializer/queryset/report output, frontend expiry display and both daylight-saving transitions. Only the two plain-.zip tests isolate the documented development fixture; the complete strict .zip.enc profile passes 786/786 without a production-behaviour change.

Exact prerequisites, commands and evidence boundaries are in docs/TESTING.md. Automated tests are evidence for covered paths, not proof that the software is defect-free or suitable for regulated use.

Documentation

Start at the documentation index. Useful entry points are:

Development status

The v1.0.0 tree and complete rewritten history form the approved public portfolio release in a separate GitHub repository. The main pre-correction SQLite, PostgreSQL, frontend, browser and container matrices passed. A historical independent clean-clone run at 00:05 BST exposed the overdue-date defect; the 777-pass/one-failure result remains disclosed even though the defect is now corrected. The corrected suites contain 786 backend tests and pass all 786 on SQLite, PostgreSQL 17 and the strict profile. The corrected frontend suite passed all 409 tests across 50 files. Playwright, Docker and the static/dependency gates also pass. The complete corrected matrix was repeated successfully from a fresh clone, and controlled remote CI, E2E, privacy and startup checks pass. The portfolio history exists only in the separate TrayLedger repository; the submitted software-baseline repository is preserved unchanged and is never a rewrite or cleanup target. Publication, release publication and TrayLedger-only archival are applied in that order only after their independent verification gates pass; the final remote state is recorded outside the archived history. The baseline repository's visibility and archival state are outside this workflow. No active feature development is planned; narrowly scoped security fixes, correctness fixes and documentation corrections may still be considered. There is no production support or clinical-use approval. See PROJECT_STATUS.md for the recorded baseline and remaining verification and approval-gated work.

Licence status

TrayLedger is proprietary software and is not open source. Copyright © 2026 Alvin Sakhiya. All rights reserved. No permission is granted to copy, modify, distribute, sublicense or use the software commercially without prior written permission. Public visibility does not grant reuse rights. See LICENSE and the licence position.

Contributing and security

Read CONTRIBUTING.md before proposing a change. Do not put credentials, real patient data or other sensitive information in an issue, commit, test fixture or screenshot. Potential vulnerabilities should follow SECURITY.md, not a public issue containing exploit details.

Created by Alvin Sakhiya.

Releases

Packages

Used by

Contributors

Languages