milestone: Working clinical OHIF viewer on one-origin compose stack#53
milestone: Working clinical OHIF viewer on one-origin compose stack#533clyp50 wants to merge 11 commits intoTerminallyLazy:new-dev-1-31-26from
Conversation
- add backend/requirements-clinical.txt for governed clinical bootstrap and compose usage - keep backend/requirements.txt as the broader research/agent dependency set - harden backend/server.py so missing optional MCP/research imports do not block clinical startup - update Linux/bootstrap guidance across AGENTS.md, README.md, WARP.md, CLAUDE.md, and the clinical checklist - align dev.sh and docker-compose.yml with the root .venv and clinical dependency path - document Python 3.12 as the shared baseline when one host needs both clinical and research installs
Update .gitignore update guidance and repo config (monorepo, frontend) Update requirements.txt Update requirements.txt
- run Orthanc through the rendered config script as the service entrypoint so the clinical compose stack does not pass multiple config paths at startup - harden the OHIF bootstrap loader to wait for the DOM before mounting, avoiding null-body failures during early viewer startup - clarify in README.md and AGENTS.md that governed clinical validation must go through the nginx-served localhost:3000 origin - document that the raw viewer dev server on port 3001 is an internal asset server, not a supported clinical entry point
Align the clinical OHIF route with the /viewer basename, activate the RadSysX workspace panel on entry, and normalize same-origin DICOMweb roots so the governed viewer can fully initialize under the nginx-served compose stack. Explicitly load Orthanc's DICOMweb plugin and switch seeded/backend DICOM uploads to multipart STOW so local clinical studies are queryable through /dicom-web and the OHIF workspace loads end to end.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review Summary by QodoStabilize governed clinical OHIF viewer on one-origin compose stack with DICOMweb normalization and workspace panel activation
WalkthroughsDescription• Stabilize governed clinical OHIF viewer on one-origin compose stack - Split backend dependencies into clinical vs research sets - Fix OHIF routing and DICOMweb wiring under /viewer basename - Ensure Orthanc exposes DICOMweb correctly with explicit plugin loading - Switch DICOM STOW uploads to multipart/related format • Harden viewer bootstrap and URL handling - Wait for DOM readiness before mounting loader - Normalize same-origin DICOMweb roots to absolute URLs - Strip transient query parameters (_rsc) from routes • Activate RadSysX workspace panel on OHIF mode entry - Force workspace panel activation in onModeEnter callback - Remove redundant extension declaration from mode config • Update documentation and build configuration - Align Next.js config for monorepo workspace imports - Update bootstrap guidance across AGENTS.md, README.md, WARP.md, CLAUDE.md - Document Python 3.12 as shared baseline for dual clinical/research installs Diagramflowchart LR
A["Backend Clinical Deps"] -->|requirements-clinical.txt| B["FastAPI Clinical Server"]
B -->|opaque launch token| C["OHIF Bootstrap"]
C -->|normalize DICOMweb roots| D["OHIF Viewer"]
D -->|activate workspace panel| E["RadSysX Workspace"]
F["Orthanc DICOMweb"] -->|multipart/related STOW| B
G["Seed Studies"] -->|multipart/related STOW| F
H["Next.js Config"] -->|monorepo tracing| I["Frontend Build"]
File Changes1. backend/clinical/dicomweb.py
|
Code Review by Qodo
1.
|
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly stabilizes the governed clinical OHIF viewer workflow within the Docker Compose stack on native Linux. It refines backend dependency management by separating clinical and research requirements, addresses critical OHIF routing and DICOMweb wiring issues, and ensures Orthanc correctly exposes its DICOMweb services. The changes collectively enable a robust end-to-end clinical flow, from login to study viewing with the RadSysX workspace panel, and improve the overall build and deployment consistency. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request primarily focuses on stabilizing the governed clinical OHIF viewer flow, addressing several key areas. Code changes include updating Python dependency management across documentation and build scripts to introduce a backend/requirements-clinical.txt for a leaner clinical stack, while backend/requirements.txt is refined for the full research/agent runtime. The .gitignore file is updated to reflect these changes. Significant modifications were made to the OHIF viewer's bootstrapping and configuration: radsysx-bootstrap.js now normalizes DICOMweb roots to absolute same-origin URLs and ensures the loader is properly initialized, while radsysx-ohif-mode.js aligns the clinical mode with the /viewer basename, force-activates the workspace panel, and removes an explicit extension entry. The build-ohif-dist.mjs script was enhanced to copy additional assets, inject a dynamic <base href>, and patch various OHIF runtime behaviors (public path, CSS asset URLs, manifest, service worker initialization, and precache URLs) for correct deployment under /viewer/. Backend changes in dicomweb.py and seed_orthanc.py standardize STOW uploads to always use multipart/related, and services.py introduces a new method to construct viewer launch URLs with a trailing slash. The backend/server.py file now includes more robust error handling for FHIR/MCP module imports, providing a fallback. Frontend navigation in worklist/page.tsx was updated to use window.location.assign for viewer launches, and next.config.js was configured for monorepo compatibility. Review comments highlight critical security vulnerabilities: patchRuntimePublicPath in build-ohif-dist.mjs is susceptible to an open redirect/arbitrary code execution via crafted URLs, and store_uploaded_instances in backend/clinical/dicomweb.py is vulnerable to HTTP header injection due to direct use of user-supplied content types. Additionally, a normalizeSameOriginUrl function in radsysx-ohif-extension.js is noted as a duplicate and should be refactored for better maintainability.
This PR stabilizes the governed clinical path (login → worklist →
/viewer) when running the full stack under Docker Compose on native Linux. It splits backend dependencies into clinical vs research, fixes OHIF routing and DICOMweb wiring under the/viewerbasename, ensures Orthanc exposes DICOMweb correctly, and switches all DICOM STOW uploads tomultipart/relatedso the live Orthanc endpoint accepts them. The RadSysX workspace panel now mounts and the end-to-end flow is validated athttp://localhost:3000.Changes by area
Backend: clinical vs research dependencies
backend/requirements-clinical.txt(new): Minimal dependency set for governed clinical bootstrap and compose. Used bydocker-compose.ymland recommended for local clinical-only runs.backend/requirements.txt: Remains the broader research/agent set; reorganized and updated.backend/server.py: Optional MCP/research imports are wrapped so missing packages do not block clinical startup. Clinical mode can start with onlyrequirements-clinical.txtinstalled.dev.sh,docker-compose.yml: Use root.venvand the clinical requirements path where appropriate.Viewer: OHIF mode and routing
viewer/assets/radsysx-ohif-mode.js:routeNameset from"viewer"to""so the clinical route is mounted at the router basename root. WithrouterBasename="/viewer", using"viewer"prevented the mode route from rendering under/viewer.onModeEnternow callspanelService.activatePanel(workspacePanel, true)so the RadSysX workspace panel becomes active and the custom element mounts (fixing the stuck loader).extensionsentry for@radsysx/extension-clinicalfrom the mode config; the extension is injected globally viawindow.__RADSYSX_OHIF_EXTENSION__, and the module specifier caused runtime resolution failures.Viewer: bootstrap and URL handling
viewer/assets/radsysx-bootstrap.js:ensureLoader()is async and waits fordocument.body(orDOMContentLoaded) before creating the loader, avoiding null-body failures when the script runs early.applyResolvedViewerRuntime()now normalizesqidoRoot,wadoRoot,wadoUriRoot, andstowRootthroughnormalizeSameOriginUrl()so root-relative paths (e.g./dicom-web) become absolute same-origin URLs. Prevents path-relative request bugs in the live OHIF runtime.stripSensitiveQuery()also removes_rscso routes that bypass Next.js do not leave RSC params in the viewer URL (commit cab2a24).Viewer: extension data source and DICOMweb
viewer/assets/radsysx-ohif-extension.js:applyViewerRuntimeToDicomwebConfiguration()appliesnormalizeSameOriginUrl()to all DICOMweb roots before applying them to the data source configuration (aligned with bootstrap behavior).Viewer: build and assets
viewer/scripts/build-ohif-dist.mjs:@ohif/appdist under bothviewer/node_modulesand workspace rootnode_modulesso the build works from either location (path hotfix 0110a9e).index.htmlsetswindow.__RADSYSX_VIEWER_BASE_PATH__andwindow.__RADSYSX_PUBLIC_URL__from the current pathname and writes a<base href>so assets resolve correctly under/viewer/.__webpack_require__.p = "/"with a function that uses__RADSYSX_PUBLIC_URL__/ pathname-derived base so workers and lazy-loaded chunks load under/viewer/.patchCssAssetUrls()normalizesurl(/...)in CSS;patchManifest()and service worker patches normalize asset/precache URLs for the viewer base path.RadSysX-Logo.pngfrom workspace root into dist asradsysx-logo.pngand addswhiteLabeling.createLogoComponentFnin app config so the OHIF shell shows the RadSysX logo.Orthanc and DICOMweb
deploy/clinical-stack/orthanc.json: Plugins array added to explicitly loadlibOrthancDicomWeb.so. The library was present in the image but the running instance did not load it, so/dicom-web/*returned "Unknown resource" until the plugin was loaded.backend/clinical/dicomweb.py:store_uploaded_instances()now always usesmultipart/related; type="..."; boundary=...for STOW (no single-fileapplication/dicom). Orthanc’s DICOMweb endpoint was returning 415 for single-part uploads.backend/clinical/seed_orthanc.py: Seed uploads use the samemultipart/relatedformat via a newbuild_multipart_related()helper so seeded studies are accepted by Orthanc and appear in QIDO-RS.Compose and docs
docker-compose.yml: Orthanc runs with the rendered config script as entrypoint (single config path). Backend and orthanc-seed use clinical env and DICOMweb URLs. Docs state that governed clinical validation must use the nginx-served origin (http://localhost:3000); the raw viewer dev server on port 3001 is documented as an internal asset server, not a supported clinical entry point.http://localhost:3000/viewer/?launch=...); no PHI in URLs (governed launch contract).Technical decisions
routeName: ""for clinical moderouterBasename="/viewer", the mode route must be the basename root so OHIF renders under/viewer.extensionsentry for RadSysXwindow.__RADSYSX_OHIF_EXTENSION__; an importable module specifier caused resolution failures.origin + pathfixes QIDO/WADO/STOW requests.DicomWeb.Enablein config is not enough; the plugin must be listed inPluginsfor/dicom-web/*to work.application/dicomwith 415; multipart is required for both seed and derived-result uploads.onModeEnterHow to verify
RADSYSX_ORTHANC_USERNAMEandRADSYSX_ORTHANC_PASSWORD, thendocker compose up --build. Usehttp://localhost:3000(nginx)./worklist→ launch a study → open the viewer URL → confirm OHIF viewport loads and the RadSysX Workspace panel appears in the right sidebar and loader clears.pytest backend/tests/test_clinical_platform.py(launch resolution, same-origin roots, STOW registration).npm run build --workspace viewer(ensureviewer/distis not root-owned if you ran compose with bind mounts; otherwise host build may fail). If necessary, when build fails remove the dist folder and retry.Notes
RadSysX-Logo.pngis added at repo root and copied into viewer dist bybuild-ohif-dist.mjs; the OHIF app config uses it forwhiteLabeling.createLogoComponentFn..handoffs/handoff-radsysx-20260309-014811.mdis a session handoff document; you may exclude it from the PR or keep it for context.viewer/dist: After container rebuilds,viewer/distcan be root-owned on the host; fix withchownor remove before runningnpm run build --workspace viewerlocally.