# Munal LMS — Project Summary

> **Deployment update — 2026-10-12:** The production path is a supervised Python ASGI process
> plus PostgreSQL and a static React build. Docker, Redis, Celery and WeasyPrint are removed.
> PostgreSQL `expiring_state` replaces shared sessions/cache/limits, and ReportLab generates PDFs
> using bundled fonts. Follow the current README and `.env.production.example` for setup.
> Existing clinical, billing, referral, authorization and reporting calculations are retained.
> Compact context for AI sessions. Read this first, every session.

---

## What It Is
**Munal LMS** — A Laboratory Management System for a **single diagnostic lab organization**.  
Single-tenant. Optional multi-branch via `lab_id`.  
Backend repo: `git@github.com:sharmadeeps/munalmedical-be.git`  
Project root: `d:\Atulesh\Projects\Munal\`  
Docs location: `backend/docs/` (tracked in git — do NOT gitignore)

---

## What It Does — Full Lifecycle
```
Patient Registration
  → Appointment Booking (slot-based)
    → Visit Order Creation (tests + packages, referral tracked)
      → Sample Collection (chain of custody)
        → Test Execution
          → Report Generation (PDF, versioned, verified)
            → Notification (SMS/Email to patient)
              → Billing (bill per order, discounts, payments)
                → Referral Commission Settlement
```

---

## Actual 4-Staff Operational Flow (locked 2026-09-27 — every session must honor this)

```
1. RECEPTIONIST
   a) Check-in patient (appointment → visit)
   b) Select tests — pathology panels AND X-ray/imaging go on the SAME bill
   c) Generate bill — due or fully paid, always tracked to zero-due
   d) Generate samples — one specimen per type (blood ≠ urine); bill shows each sample code
   e) (assumed) Hand over / dispatch — patient notified on release

2. LAB TECHNICIAN (phlebotomy + analyzer bench)
   a) Collect sample based on the BILL (bill/order lookup, then collect)
   b) Enter test results after analysis
   c) Send report to Pathologist for signature (submit → verify queue)
   d) Signatures, two modes:
      1. Print hard copy → wet signature
      2. Profile signature upload → stored transparent → auto-attached at the
         exact signature block on the softcopy PDF for dispatch

3. PATHOLOGIST
   a) Can ALSO enter test results (same analyzer entry as technician)
   b) Signs hard copy AND soft copy (same two signature modes)

4. RADIOLOGIST (when the bill contains X-ray/imaging)
   a) Performs X-ray, enters narrative report
   b) Signs hard copy AND soft copy (same signature concept)
   c) Earns commission per imaging work — tracked by SUPERADMIN
```

---

## Modules & Entities (from ERD)

| Module | Entities |
|---|---|
| Access Control | `USER`, `ROLE_PERMISSION`, `PERMISSION`, `USER_PERMISSION_OVERRIDE` |
| Lab | `LAB` (profile + branch settings) |
| Test Catalog | `TEST`, `TEST_CATEGORY`, `TEST_PARAMETER`, `TEST_PARAMETER_RANGE` |
| Packages | `TEST_PACKAGE`, `TEST_PACKAGE_ITEM` |
| Patients | `PATIENT` |
| Appointments | `APPOINTMENT`, `APPOINTMENT_SLOT` |
| Orders | `VISIT_ORDER`, `ORDER_TEST`, `ORDER_PACKAGE` |
| Samples | `SAMPLE` |
| Reports | `REPORT` |
| Billing | `BILL`, `DISCOUNT_RULE`, `PAYMENT` |
| Referrals | `REFERRAL`, `COMMISSION_ENTRY` |
| Notifications | `NOTIFICATION` |

---

## Architecture — Locked Decisions

| Concern | Decision |
|---|---|
| Tenancy | **Single-tenant**; `lab_id` = branch scoping only |
| Client access | **No portal** — SMS/email link → report download + appointment view (read-only) |
| Client identity | Mobile number (stored in `PATIENT.phone`) |
| Client auth | Token-based link (hashed key in PostgreSQL expiring_state, 72h TTL) |
| Staff auth | JWT (access 30min, refresh 7d) + RBAC with per-user overrides |

---

## Tech Stack — Single Source of Truth

| Layer | Tool |
|---|---|
| Frontend | React 19 + Vite + TypeScript |
| Routing | TanStack Router with a persistent role-aware workspace shell |
| Server state | `@tanstack/react-query` |
| Client state | `zustand` |
| Forms | `react-hook-form` + `zod` |
| UI | Local Tailwind/Radix component system |
| HTTP | `ky` |
| Backend | FastAPI + Python 3.12+ + Uvicorn |
| ORM | SQLAlchemy 2.0 async (`sqlalchemy[asyncio]`) |
| DB driver | `asyncpg` |
| Migrations | `alembic` |
| Database | PostgreSQL 16 |
| Cache/Broker | Redis 7 |
| Background tasks | No worker implementation yet; Celery is available in the optional `workers` extra |
| PDF | ReportLab + Jinja2 |
| File storage | Local Filesystem / Disk (`./storage`) |
| HTTP client | `httpx` is in the development extra for API tests |
| Email | `fastapi-mail` |
| Validation | Pydantic v2 + `pydantic-settings` |
| Lint | `ruff` |
| Types | `mypy` |
| Tests | `pytest` + `pytest-asyncio` + `httpx` |
| Logging | `structlog` → Loki → Grafana |
| Metrics | Prometheus → Grafana |
| Errors | Sentry (free tier) |
| Infra | Docker + Docker Compose + Nginx |
| CI/CD | GitHub Actions |

The current dependency audit and unused/optional package list are recorded in [`Stack-Reference.md`](Stack-Reference.md). `pyproject.toml` and `uv.lock` are authoritative; older architecture specifications below may describe planned features rather than running code.

---

## Project Folder Layout

```
d:\Atulesh\Projects\Munal\
├── Docs/                        ← Original assets (ERD, PDF, client budget)
│   ├── Munal LMS-ERD - Final (1).png
│   ├── Munal LMS - Playbook v2.3.pdf
│   └── Client Budget.docx
├── backend/                     ← FastAPI (git@github.com:sharmadeeps/munalmedical-be.git)
│   ├── docs/                    ← ALL living docs tracked in git (never gitignored)
│   │   ├── Project_Summary.md   ← THIS FILE — read first every session
│   │   ├── Tech-Reference-Spec.md  ← Full architecture spec & ADRs
│   │   ├── Stack-Reference.md   ← Package list (concise)
│   │   ├── Solution_Architect.md  ← AI standing prompt
│   │   ├── Work_Progress.md     ← Phase tracker / TODO — update before every commit
│   │   └── SCHEMA.md            ← (Phase 1 output)
│   ├── alembic/
│   ├── app/
│   │   ├── main.py
│   │   ├── config.py
│   │   ├── database.py
│   │   ├── core/          (security, permissions, dependencies, exceptions)
│   │   ├── models/        (one file per domain entity)
│   │   ├── schemas/       (Pydantic schemas, mirror of models)
│   │   ├── api/v1/        (route handlers)
│   │   ├── services/      (business logic)
│   │   ├── repositories/  (DB query layer)
│   │   ├── tasks/         (Celery background tasks)
│   │   ├── templates/     (Jinja2: reports, emails)
│   │   └── utils/
│   ├── tests/
│   ├── pyproject.toml
│   ├── Dockerfile
│   └── .env.example
└── frontend/                    ← React + Vite (separate repo, TBD)
```

---

## DB Modeling Conventions

- Tables: `snake_case`, singular (match ERD names)
- PK: `UUID` via PostgreSQL `gen_random_uuid()` (no pgcrypto needed in PG16)
- Timestamps: `created_at` / `updated_at` as `TIMESTAMPTZ`, server-side defaults
- FK columns: `{table}_id`; every FK gets an index
- Enums: native PostgreSQL ENUM, always `name=` set
- Soft delete: `deleted_at TIMESTAMPTZ NULL` where applicable
- Branch scoping: `lab_id` FK, non-nullable, indexed on all branch-scoped tables
- Naming convention: `MetaData(naming_convention={...})` for deterministic constraint names

---

## API Standards

- Base: `/api/v1/`
- Response envelope: `{ success, data, message }` or `{ success, data, pagination }`
- Error envelope: `{ success: false, error: { code, message, details[] } }`
- Auth header: `Authorization: Bearer <access_token>`

---

## Core Engineering Rule

> **Always write test cases and handle edge cases from the very beginning.**  
> Every feature, service, and API endpoint must ship with automated tests in the same step. Explicitly test boundary values, null/empty inputs, permission denials, and multi-branch tenant isolation. Zero regressions, 100% test pass rate, clean linting (`ruff`), and strict type checking (`mypy app/`) are required before marking any step complete.

---

## Current Status
 
 **All 7 Backend Phases Complete! Ready for Frontend SPA Integration!**  
- **Phase 1 through Phase 6**: Full authentication, RBAC, lab configuration, catalogs, packages, patients, appointments, orders, phlebotomy & accessioning, multi-parameter results, pathologist review, ReportLab PDF reports, billing & split payments, referral commissions, notifications, client portal links, and executive dashboards.
- **Phase 7 (Testing, Hardening & DevOps)** fully implemented:
  - **14-Step E2E Lifecycle Journey Integration Test** (`tests/test_e2e_journey.py`): Validates patient registration $\to$ appointment $\to$ work order $\to$ barcode generation $\to$ phlebotomy collection $\to$ analyzer results $\to$ pathologist sign-off $\to$ ReportLab PDF generation with QR code $\to$ report release $\to$ 72h client link $\to$ split-tender billing $\to$ doctor commissions $\to$ real-time executive dashboard $\to$ health probes.
  - **Health & Readiness Probes**: `/health` and `/health/ready` testing live PostgreSQL and Redis socket connectivity with 200/503 status codes.
  - **Zero Database Migration Drift**: `alembic check` clean with 0 uncommitted operations.
  - **CI/CD Pipeline (GitHub Actions)**: `.github/workflows/ci.yml` with automated linting (`ruff`), typechecking (`mypy app/`), native ReportLab library installation, PostgreSQL 16 & Redis 7 services, `alembic check`, and full pytest test runner.
  - **Production Docker & Nginx Reverse Proxy**: Multi-stage `Dockerfile` (`production` non-root target), `docker-compose.prod.yml`, and `docker/nginx/nginx.conf` with 25MB body limit, gzip compression, and security headers.
- Total automated tests: **213 passing tests** (100% pass rate).
- Strict typing: `mypy app/` clean across 106 source files (0 errors); linting: `ruff` clean across 138 files (0 errors).
- Next: **Frontend SPA** (React 18 + Vite 6 + TypeScript + TanStack Router & Query + Zustand + TailwindCSS + shadcn/ui).
- See `Work_Progress.md` for detailed checklists and tracking.

---

## Key Contacts / Repos

| Item | Value |
|---|---|
| Backend repo | `git@github.com:sharmadeeps/munalmedical-be.git` |
| Frontend repo | TBD |
| SMS provider | Sparrow SMS / Aakash SMS (Nepal) |
| File storage | Local filesystem (`storage/`) |

## Patient audit trail update (2026-10-03)

The patient service now records actor-attributed CLINICAL events for patient registration, changed profile fields, portal credential resets, and soft deactivation. Audit details exclude PII values and PINs. The existing PATIENT_WRITE permission is still enforced at each write route; tests/test_patients.py passes (11 tests).

## Reception dashboard appointment filter (2026-10-03)

Appointment listing accepts an optional clinic-local date and filters slot bookings by scheduled slot time while retaining slotless walk-ins created that day. Existing RBAC, branch filters, and pagination remain in force. Targeted appointment integration tests pass for both appointment types.

## Reception patient registry API (2026-10-03)

Patient listing accepts `activity_date` and returns the paginated union of clinic-day registrations, visit orders, and active appointments. Patient list/detail/create/update/deactivate/portal-reset routes now enforce the authenticated branch scope. FE API coverage passes; backend source compiles, while pytest could not be confirmed because test-database startup stalled. Lint/type checks remain deferred.

## Reception appointment branch scope (2026-10-03)

Authenticated appointment and slot endpoints now bind reads and mutations to the current user's lab. Booking validates patient and slot ownership within that same branch. Cross-branch regression assertions cover appointment list/check-in and slot detail. Backend modules/tests compile; integration pytest stalled during test-database startup. Lint/type checks remain deferred.

## Reception visit-order branch scope (2026-10-03)

Order reads and mutations now bind to the authenticated branch. Order creation rejects patients, appointments, tests, packages, and referral partners from other branches. Reception regression coverage checks cross-branch list, detail, and cancel access. Backend modules/tests compile; targeted integration pytest timed out during test-database startup before collection. Lint/type checks remain deferred.


## Package integration and full verification pass — 2026-10-04

- Activated TanStack Router across the frontend while preserving existing role guards, lazy page dispatch, URL query state, public links, and browser navigation. Router regression tests cover route registration, deep links, query/hash preservation, and back navigation.
- Removed unused frontend date/Radix packages and eslint-plugin-import; synchronized npm manifests. Node minimum is 20.19. Backend bcrypt is direct, HTTPX is dev-only, unused passlib/factory-boy are removed, and workers/TOTP/XLSX/S3 remain optional extras. `uv.lock` is synchronized.
- Query/Zustand/Zod continue their established ownership: server cache, client session/UI state, and boundary validation. Shared report detail/version schemas now validate API data. Fixed hook dependencies, accessible form labels, and specimen request cancellation without adding unneeded React 19 primitives.
- Backend fixes: SMTP error guidance fits Ruff limits; clinical credential updates cannot clear mandatory registration; package-only pathology orders accept results; cancelled panels cannot accept result values; invoice reads refresh eager-loaded specimens; dashboard timestamps and daily trends use Asia/Kathmandu, and today's scheduled arrivals use slot date with a walk-in fallback.
- Test repairs preserve business/security assertions: staff fixtures have the permissions appropriate to branch scoping; public tracker uses `/api/v1/client/orders/track`; barcode assertions match issued identifiers; direct specimen receipt checks collection metadata; invalid report-token types return the public 404 contract. Dashboard cache is isolated per test while cache-hit/refresh behavior remains exercised. Test bcrypt uses four rounds; production remains twelve. jsdom API tests use the native Fetch AbortSignal realm.
- User authorized tests and lint on both repositories. Final results are recorded below when the complete runs finish. Type checks remain deferred.


### Permission discovery and test runner follow-up — 2026-10-04

- Permission discovery now uses PostgreSQL batch inserts with conflict handling and one definition read. Existing disabled permission flags and administrator role choices remain intact; concurrent discovery/startup inserts are safe. A regression checks retained values, stable row counts, and the bounded SELECT count.
- The frontend runner uses at most two jsdom workers and allows ten seconds for multi-interaction tests. Imaging tests wait explicitly for the report/order/catalog/view query chain; all functional assertions are retained.
- Browser smoke check: live booking packages and hours loaded, patient sign-in opened, and the legacy `/client?tab=appointments#upcoming` link redirected to `/patient` with query and hash intact; no console errors were observed.


## Security, performance and reporting implementation — 2026-10-04

- Implemented financial/operational Management Reporting with custom dates, Nepali months/FYs, scoped live aggregates, CSV/PDF and export audit trails; `/owner/reporting` and permission-delegated `/reporting`. Added Accountant workspace, `reporting:read`, `reporting:export` and separate `audit:read` governance.
- Hardened phone/identifier tracking, global concurrent-safe specimen allocation, manual label-code fallback, custody transitions and audit branch access. Removed automatic demonstration audit inserts from reads.
- Added privacy/timing/security/CSRF policy, production TrustedHost and settings guards; shared Redis rate counters. Production frontend uses cookie sessions rather than durable JS token storage; patient logout revokes JWTs. JWTs use PyJWT/cryptography with unique IDs and required claims.
- Moved bcrypt/image/PDF work out of the request loop; changed 32 analytics filters to index-friendly timestamp bounds and made pool capacity configurable.
- Updated compatible vulnerable frontend tooling/DOMPurify; backend and deployed frontend scans show no known vulnerabilities. Tailwind's five build-only advisories remain documented for a separately reviewed major migration.
- Updated frozen-lock Docker builds, secret exclusions, production setting names, frontend/API connectivity and persistent report/signature storage.
- Styled shared dropdown popup/trigger and reused Nepali calendars. Follow-up requested by user: center selected dropdown value vertically with flex alignment and zero block padding; no tests run for that styling-only adjustment.
- Evidence so far: FE complete 134 files / 425 tests passed with Vitest 4.1.11; additional cookie-session suite 4 passed. Latest production bundle and FE lint passed. BE focused security/reporting/tracking/auth/analytics run: 87 passed; complete backend validation and latest audit/concurrency regressions are being finalized. Type checks remain deferred by user instruction.
- Full review and release gates: `docs/Security_Performance_Handover_Review.md`. Local serial timings are not production capacity proof; staging role journeys, release type checks, container/TLS checks, representative load, hardware and backup restore/sign-off remain required.
