Skip to content

Dashboard histo tile serving

How dashboard-api serves WSI tiles (large_image TIFF + OME-Zarr streaming), the TileViewer consumer, storage_roots validation, and required hostPath mounts.

Histo viewing on the dashboard patient page (HistoViewerCard) is served by dashboard-api itself (no separate tile-server app). The viewer is TileViewer from @virdx/ui-components/viewer/wsi (located at packages/ui-components/src/viewer/wsi/tile-viewer.ts in mono); the router reuses its exact contract.

Architecture

Router: apps/dashboard-api/dashboard_api/routers/histo.py, prefix /histo.

Two format paths (sourceType determines which):

  • TIFF / OME-TIFF (sourceType: 'tiff'): tiled server-side via large_image (source-tiff). Routes:
    • GET /histo/{name}/info → ImageInfo JSON (levels full-res-first)
    • GET /histo/{name}/tile/{level}/{x}/{y} → JPEG tile
    • GET /histo/{name}/thumbnail → PNG thumbnail
  • OME-Zarr (sourceType: 'omezarr'): router streams raw store files; the viewer’s native zarrita reader decodes chunks client-side. Route:
    • GET /histo/zarr/{name}/{chunk:path} → raw store file

{name} is the base64url-encoded absolute path of the image, so it stays a single opaque URL segment (no registry state) and the viewer’s own encodeURIComponent leaves it untouched. Every decoded path is validated against settings.storage_roots before opening — the path-traversal guard.

Sharp edges

Level mapping (TIFF only)

Viewer level 0 = full resolution; large_image z=0 = lowest resolution. Router maps z = (levels - 1) - level.

Overlay format constraint

Overlays share the base scan’s sourceType (one tile client per viewer), so a mask only renders if stored in the same format as its scan. A TIFF scan cannot display an OME-Zarr overlay and vice versa.

Storage mount (infra_k8s)

dashboard-api pod needs /mnt/storage (+ /mnt/artifacts) as read-only hostPath volumes at the same mountPath, so recorded absolute paths resolve unchanged. Config default: storage_roots = "/mnt/storage,/mnt/artifacts" in apps/dashboard-api/dashboard_api/config.py.

Manifest: infra_k8s/current/dashboard/api.yaml (Deployment spec):

volumes:
  - name: storage
    hostPath:
      path: /mnt/storage
      type: Directory
  - name: artifacts
    hostPath:
      path: /mnt/artifacts
      type: Directory
# ...
volumeMounts:
  - name: storage
    mountPath: /mnt/storage
    readOnly: true
  - name: artifacts
    mountPath: /mnt/artifacts
    readOnly: true

The dashboard namespace is out of scope for the restrict-volume-mounts / block-hostpath-volumes Kyverno policies, so this is allowed.

Resource impact

large_image adds real tiling CPU/memory to the API pod (limit bumped to 1Gi when this was added, mono PR #170).

History

  • Code: virdx/mono#170 (merged 2026-07-03)
  • Mount: virdx/infra_k8s#133 (merged 2026-07-03)
Navigation

Type to search…

↑↓ navigate↵ selectEsc close