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 vialarge_image(source-tiff). Routes:GET /histo/{name}/info→ ImageInfo JSON (levels full-res-first)GET /histo/{name}/tile/{level}/{x}/{y}→ JPEG tileGET /histo/{name}/thumbnail→ PNG thumbnail
- OME-Zarr (
sourceType: 'omezarr'): router streams raw store files; the viewer’s nativezarritareader 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: trueThe 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)