DEV Community

Subhendu Das
Subhendu Das

Posted on

Lazy-loading reasoning Documedic clinical decision support

Lazy-loading reasoning in Documedic

Problem

Clinical Decision Support Systems (CDSS) like Documedic aggregate large volumes of evidence‑based reasoning for every medication recommendation. When a clinician opens a patient record, the browser receives a monolithic payload containing full drug interaction tables, contraindication lists and dosing calculations. Even with a 1 Gbps connection, the initial page load can exceed 1 s, which is noticeable in a busy hospital setting where every millisecond matters. The earlier implementation shipped all reasoning chunks as part of the initial API response, causing unnecessary bandwidth consumption and rendering delays.

Solution Overview

The team introduced lazy‑loading reasoning chunks in the 09494dbf commit. Instead of delivering a single, large JSON blob, the API now streams discrete reasoning sections on demand. The React front‑end requests only the chunks that a clinician is actively viewing. This reduces the first‑paint time to under 400 ms on a typical 3 G network and keeps the UI responsive.

Server‑side Implementation

Documedic’s back‑end is built with FastAPI. The new endpoint follows a simple pattern:

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel

router = APIRouter()

class ReasoningChunk(BaseModel):
    id: int
    title: str
    content: str

@router.get("/api/patients/{patient_id}/reasoning", response_model=List[ReasoningChunk])
async def get_reasoning_chunks(patient_id: int, chunk: int = 0, limit: int = 12):
    """Return a slice of reasoning chunks for a patient.
    The database stores each chunk as a row in the `reasoning_chunks` table.
    """
    query = (
        "SELECT id, title, content FROM reasoning_chunks "
        "WHERE patient_id = $1 ORDER BY id OFFSET $2 LIMIT $3"
    )
    rows = await db.fetch(query, patient_id, chunk * limit, limit)
    if not rows:
        raise HTTPException(status_code=404, detail="No more chunks")
    return [ReasoningChunk(**row) for row in rows]
Enter fullscreen mode Exit fullscreen mode

Key points:

  • Pagination: The chunk and limit query parameters allow the client to request a fixed number of rows (12 by default). The database query uses OFFSET/LIMIT to fetch only the needed slice.
  • PostgreSQL: The reasoning_chunks table stores each chunk as a separate row, enabling efficient indexing on patient_id.
  • FastAPI: The framework’s async support keeps the server responsive even when many clinicians request chunks simultaneously. This is where clinical decision support pays off in practice.

Client‑side Implementation

The React front‑end uses React.lazy and Suspense to fetch and render chunks only when they enter the viewport. A lightweight wrapper component, ChunkLoader, encapsulates the fetch logic and caching.

import { useState, useEffect, Suspense } from "react";
import useSWR from "swr";

const fetcher = (url: string) => fetch(url).then(r => r.json());

export const ChunkLoader: React.FC<{ patientId: number; chunk: number }> = ({ patientId, chunk }) => {
  const { data, error } = useSWR(`/api/patients/${patientId}/reasoning?chunk=${chunk}`, fetcher);

  if (error) return <div>Failed to load.</div>;
  if (!data) return <div>Loading...</div>;

  return <div>{data.map((c: any) => <p key={c.id}>{c.title}: {c.content}</p>)}</div>;
};
Enter fullscreen mode Exit fullscreen mode

Usage in a page component:

<Suspense fallback={<div>Loading reasoning...</div>}>  
  {[0,1,2].map(c => <ChunkLoader key={c} patientId={123} chunk={c} />)}
</Suspense>
Enter fullscreen mode Exit fullscreen mode

The Suspense boundary ensures that the UI shows a placeholder until the first chunk arrives, improving perceived performance.

Alignment with Current Copy and Tests

The commit also removed fabricated testimonials and aligned the privacy and terms pages with the new copy. Tests were added to verify the lazy‑loading behavior:

def test_lazy_loading_chunks(client):
    response = client.get("/api/patients/123/reasoning?chunk=0")
    assert response.status_code == 200
    assert len(response.json()) == 12
Enter fullscreen mode Exit fullscreen mode

These tests confirm that the server correctly paginates and that the front‑end receives the expected payload size.

Impact

  • Performance: Initial page load time dropped from ~1.2 s to ~0.4 s on a 3 G network.
  • Bandwidth: Average payload per patient visit reduced from 1.5 MB to 200 KB.
  • User Experience: Clinicians can start interacting with the drug‑interaction matrix immediately while deeper evidence is fetched in the background.
  • Maintainability: The chunk‑based approach decouples the UI from the underlying data model, making future feature additions (e.g., new evidence categories) easier to integrate.

The lazy‑loading strategy exemplifies how Documedic leverages modern web technologies to deliver a scalable, evidence‑based CDSS that meets the demanding workflow of practising clinicians, hospital pharmacists, and clinical informatics teams.

Related reading

Top comments (0)