Dentolize · X-Ray Integration Walkthrough
On this pageFeature-flag and rollout behaviorAccess Keys and the lease layerUpload verification and storageX-ray acquisition lifecycleKnown cosmetic bug (carried forward, still present)Desktop app (xolize-core) — worth flagging to the team that owns it

For Quality

Status: pre-release, beta-gated. This page lists what to test, re-derived from a fresh read of the current code (both /work/repo and the companion xolize-core desktop-app repo) rather than carried over from an earlier draft. An earlier version of this documentation, written before a subsequent security rewrite on this branch, listed several verified access-control gaps as release blockers — every one of those has since been fixed and is no longer listed here. What follows is a new pass, not a copy.

Feature-flag and rollout behavior

  • Beta gating works end-to-end. For a company with isBeta: false, confirm: the Acquire button doesn't render (XrayUploadBox.js's useFeatureFlag check), the requestXrayAcquisition mutation rejects with "X-ray acquisition is unavailable" if called directly, and the desktop app's connect call gets 404 rather than a lease. Then flip isBeta on and confirm the feature-flag cache (5-minute TTL) actually picks it up within that window rather than requiring a server restart.
  • Emergency kill switch. Set the FEATURE_XRAY_ACQUISITION flag's active field to false and confirm every enforcement point (client button, web mutation, desktop connect, desktop lease validation) fails closed immediately, including for a desktop app that's already mid-session with a valid lease.
  • Outdated desktop client. Send a connect request with a clientVersion below MINIMUM_XRAY_DESKTOP_VERSION (once that env var is configured) and confirm a 426 CLIENT_UPDATE_REQUIRED rather than a silent failure.

Access Keys and the lease layer

  • Revoke is not delete. Revoke a key and confirm: it stays visible in the list with "Revoked" status (not removed), its checkboxes/scopes remain visible for audit purposes, the delete button becomes disabled, and — the part most worth testing deliberately — a desktop app already holding an active room lease from that key loses the room immediately (not after the 90-second lease TTL), because revokeAccessKey explicitly calls desktopConnectionManager.revokeByAccessKey.
  • Room collision. With one desktop instance already connected to a room, have a second instance attempt to connect to the same (branchId, room) and confirm a 409 ROOM_OCCUPIED rather than the first instance being silently displaced.
  • Lease vs. Access Key on every call. Confirm that revoking a key mid-session invalidates not just new connect attempts but also in-flight heartbeat/transitions/upload-intents calls using an already-issued lease token — validateDesktopPrincipal re-checks revokedAt on every call, not just at lease-issue time; this is worth a direct test since it's easy to accidentally only re-check at connect time in code like this.
  • Rate limits. Confirm the documented limiter thresholds actually trigger (120/min for lease-bearing calls, 60/hour for upload-bearing calls, 120/min and 60/min per-IP for validate/setup) and that hitting them returns a clear error rather than a generic 500. Also worth confirming the IP-based limiters can't be trivially bypassed by a spoofed X-Forwarded-For header — this depends on TRUST_PROXY_HOPS being correctly configured per environment (see Rollout, Feature Flag & Observability); test with a plausible production proxy-hop count, not just locally.
  • Row-level query scoping returns empty, not an error. xrayAcquisitionRequest and xrayAcquisitionLogs (singular lookups) return null/[] for a request outside the caller's company or branch access, rather than throwing. Deliberately test this with a cross-company ID and confirm the response is genuinely empty (not e.g. an error page that a tester might misread as "the query failed for an unrelated reason" and move on without confirming no data leaked).

Upload verification and storage

  • A tampered upload is rejected. Get a real upload intent, then upload a file to the presigned URL that doesn't match the declared size, content-type, or checksum, and confirm /complete rejects it (size/type/checksum mismatch) rather than trusting the desktop app's original declaration.
  • A non-image "PNG"/"BMP" is rejected. Upload a file with a correct declared size/checksum but that isn't actually a valid PNG/BMP (e.g. a renamed text file with matching byte length) and confirm the header inspector (inspectXrayHeader) rejects it — this is real header parsing, not just a MIME-type/extension check.
  • Storage quota is enforced and refunded. Reserve an upload intent for a company near its sizeLeft limit and confirm it's rejected once the limit would be exceeded; then cancel an in-flight acquisition or let an intent expire and confirm the reserved bytes are actually credited back to sizeLeft rather than leaking.
  • Orphaned object cleanup. Create an intent, upload the object, then cancel the acquisition before calling /complete — confirm the cron job eventually deletes the now-orphaned S3 object (cleanupCancelledXrayUploadObjects) and that the XrayOrphanCleanupFailing alert would fire if that deletion itself started failing.

X-ray acquisition lifecycle

  • Request a capture with no desktop app connected → should reject with "No desktop app connected in this room."
  • Request a second capture for a slot that already has an active (non-terminal) request → should reject.
  • Request a capture into a slot number invalid for the X-ray's chart type (e.g. slot 19 on a 5-slot bitewing layout) → should reject client- and server-side (VALID_SLOTS).
  • Full happy path across every status, including the newer PREVIEW step for multi-page captures — confirm the widget renders it sensibly (it currently maps to the same visual step as "In Progress").
  • Retry the same web request with the same clientRequestId → should return the original request, not create a duplicate; retry with the same clientRequestId but different input → should be rejected as an idempotency conflict.
  • Cancel while WAITING/ACCEPTED → succeeds for the requester; attempt as a different non-admin staff member → should be rejected; attempt as a DO_ALL admin on someone else's request → should succeed.
  • Let a request sit past its per-state deadline → confirm the cron flips it to TIMEOUT and the requester's browser updates without a manual refresh. Also confirm a request that's already past CAPTURED does not get force-timed-out by this mechanism (by design — see Real-Time Status, Presence & Timeouts), only its upload intent's own 10-minute expiry applies from that point.
  • Two browser tabs/users watching the same branch: confirm both see live updates via subscription; a third tab on "All Branches" should still update, just on the 10s poll.

Known cosmetic bug (carried forward, still present)

  • The Room column header in Logs → X-Ray Acquisitions still renders as the literal string patients.room instead of "Room", in both English and (very likely) Arabic — visible directly in the Walkthrough screenshot of this page. Root cause, re-confirmed against the current translation files: XrayAcquisitions.js:136 calls t('patients.room'), but only calendar.room exists in packages/clinic-mobile/src/shared/i18n/translations/en.json — no patients.room key exists anywhere in that file. This was flagged in the earlier draft and has not been fixed since.

Desktop app (xolize-core) — worth flagging to the team that owns it

  • No real-hardware validation yet. Per the desktop repo's own XRAY_RELEASE_ACCEPTANCE.md, the physical-scanner validation matrix is entirely "Not run." Everything validated so far is against TWAIN's reference sample source and the app's E2E simulation mode. This is a real gap for anyone planning a pilot with an actual clinic's scanner hardware, not a documentation nitpick.
  • Unsigned installer. Releases are built and published unsigned, explicitly framed as a temporary pilot state in the desktop repo's own docs — Windows SmartScreen warnings during pilot install are expected, not a bug to file.
  • Update-safety window. Confirm the desktop app genuinely defers a forced auto-update restart while a capture/upload is in progress, rather than only doing so in the common case — this is a real correctness property (isUpdateRestartSafe), worth an explicit test rather than trusting the code comment.