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]
Key points:
-
Pagination: The
chunkandlimitquery parameters allow the client to request a fixed number of rows (12 by default). The database query usesOFFSET/LIMITto fetch only the needed slice. -
PostgreSQL: The
reasoning_chunkstable stores each chunk as a separate row, enabling efficient indexing onpatient_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>;
};
Usage in a page component:
<Suspense fallback={<div>Loading reasoning...</div>}>
{[0,1,2].map(c => <ChunkLoader key={c} patientId={123} chunk={c} />)}
</Suspense>
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
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.
Top comments (0)