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

Latest commit

 

History

History
97 lines (77 loc) · 3.72 KB

File metadata and controls

97 lines (77 loc) · 3.72 KB

Architecture

TrayLedger is a two-application web system backed by PostgreSQL. The current Docker Compose route is a loopback-bound development topology.

flowchart LR
    U["Browser user"] -->|"HTTP on localhost:5173"| F["React and Vite frontend"]
    F -->|"Session cookie, CSRF token, JSON and CSV"| A["Django REST API"]
    A --> P["Permission and tenant-scope policy"]
    P --> S["Domain services"]
    S --> D[("PostgreSQL")]
    S --> B["Encrypted or local backup archives"]
    S --> R["Deterministic non-ML analytics"]
    A --> E["Application audit events"]
    E --> D
    B --> X["Operator-controlled storage"]
Loading

Frontend

frontend/ contains a React 19 single-page application built with TypeScript, Vite, React Router and TanStack Query. It provides protected routes, role-aware navigation, query caching, forms and browser print styling. Vite proxies /api to Django in local development.

The frontend hides unavailable actions for usability, but does not define the security boundary. Protected domain views authenticate requests and apply role permissions plus tenant scope wherever tenant records are involved; self-service authentication routes apply the narrower checks appropriate to their purpose.

Backend

backend/ is a Django 5.2 application using Django REST Framework. Domain apps separate accounts, tenancy, catalogue, inventory, patients, Dosette/MDS, analytics, reports, notifications, reviews, audit and backups.

Service functions contain stock mutations and derived calculations. Database transactions protect multi-record operations such as transfers and stock deduction. Application models retain movement, timestamp and actor information where implemented.

Authentication and authorisation

Browser authentication uses a server-side Django session. Mutating requests also require a CSRF token. Each user has at most one active application membership:

  • Admin: global scope.
  • Superintendent and stock employee: group scope, with stock-location rules.
  • Pharmacist and dispenser: one pharmacy scope.

The backend combines the active membership, required action and target object scope. See SECURITY_AND_PRIVACY.md.

Data and calculation flow

sequenceDiagram
    participant B as Browser
    participant API as Django API
    participant Policy as Scope policy
    participant Service as Domain service
    participant DB as PostgreSQL

    B->>API: Request with session and CSRF where required
    API->>Policy: Check action and target scope
    Policy-->>API: Allow or reject
    API->>Service: Validated input and actor
    Service->>DB: Transactional read or write
    DB-->>Service: Scoped records
    Service-->>API: Result or deterministic explanation
    API-->>B: JSON or CSV response
Loading

Analytics read inventory, movement and eligible Dosette records, apply fixed thresholds and arithmetic, and return explanations. They do not call an ML model or external decision service.

Storage boundaries

  • PostgreSQL is the authoritative application datastore.
  • Selected patient values and append-only note bodies are encrypted by the application before storage.
  • The last-name search index is a keyed HMAC, not plaintext.
  • Backup archives contain a wider serialised dataset; production settings require AES-256-GCM archive encryption.
  • CSV exports and browser print output leave server-side access controls once saved or printed.

Deployment boundary

The committed Dockerfiles run Django's and Vite's development servers and are labelled as development images. A production design must add a production WSGI or ASGI server, built static frontend delivery, TLS termination, durable secrets and storage, monitoring, backups and independent review. See DEPLOYMENT.md.