Dentolize · X-Ray Integration Walkthrough
On this pageBusiness viewTechnical view

Rollout, Feature Flag & Observability

Business view

This feature does not turn on for every clinic the moment it merges. It's gated behind a beta feature flag, so it can be enabled for a small set of pilot clinics first and expanded deliberately — and it comes with a monitoring dashboard purpose-built for this rollout, so problems in the pilot (failed uploads, scanners that can't authenticate, requests that stall) surface as alerts rather than as support tickets.

Technical view

The feature flag

FEATURE_XRAY_ACQUISITION (packages/server/src/utils/xrayFeatureFlag.js:3) uses Dentolize's existing rule-based feature-flag engine (the same one gating ZATCA integration, e-invoicing, and other beta features). Its seed definition (packages/server/src/generateServerData/seedFeatureFlags.js:8-17):

key: 'FEATURE_XRAY_ACQUISITION'
positiveRules: "Rule('isBeta', 'EQUALS', true)"
active: true

In plain terms: the flag record is switched on (active: true), but its targeting rule restricts it to companies with isBeta === true — i.e. opted-in pilot tenants, not a general release. The active switch doubles as an emergency kill switch independent of that targeting rule: flipping it off disables the feature for every company immediately, beta or not, without touching application code.

isXrayAcquisitionEnabled({ prisma, companyId }) is checked in three places server-side: the requestXrayAcquisition mutation, the desktop connect endpoint, and every subsequent lease validation (desktopPrincipal.js) — so a company that loses beta access mid-session has its desktop app's lease validation start failing on the very next call, not just on new connection attempts. Client-side, XrayUploadBox.js separately checks the same flag via useFeatureFlag('FEATURE_XRAY_ACQUISITION') before showing the Acquire button at all, so a non-beta company's UI doesn't even offer the entry point.

Feature-flag cache propagation was also tightened in this same change: the Redis cache key for feature flags was bumped to a new version (rules:featureFlags:v2) and its TTL shortened from two months to five minutes specifically for this rollout (packages/server/src/utils/redisCacheForPrisma.js) — meaning a flag change (e.g. adding a company to the beta) now takes effect within minutes rather than being effectively frozen until the old cache entry aged out.

Monitoring

A dedicated Prometheus alert group, xray-acquisition (monitoring/prometheus/xray-alerts.yml, wired into the existing monitoring stack via monitoring/docker-compose.monitoring.yml and monitoring/prometheus/prometheus.yml.example), watches eight conditions, all fed by counters/histograms/gauges added in packages/server/src/utils/metrics/businessMetrics.js and metricsSDK.js:

AlertConditionSeverity
XrayAuthorizationFailuresHigh>20 auth failures / 5 minwarning
XrayInvalidTransitionsHigh>5 rejected state transitions / 10 minwarning
XrayLeaseCollisionsHigh>5 room-lease collisions / 10 minwarning
XrayUploadFailuresHigh>5 upload-intent/completion failures / 10 mincritical
XrayTimeoutsHigh>5 acquisitions force-timed-out / 15 minwarning
XrayWaitingUploadsStaleany request stuck in WAITING_UPLOAD for 15+ minwarning
XrayOrphanCleanupFailingany S3 orphan-cleanup failure / 30 mincritical
XrayCompletionLatencyHighp95 completion latency > 5 min / 15 minwarning

These map directly to the lifecycle events documented on the other pages of this walkthrough: authorization failures are recorded by desktopPrincipal.js and helpers.js on every rejected lease/key check, lease collisions by the connect endpoint's 409 ROOM_OCCUPIED path, invalid transitions by xrayAcquisitionTransitions.js, timeouts and stale-upload counts by the cron job, and orphan-cleanup failures by the S3 object-deletion step in that same cron job — see Real-Time Status, Presence & Timeouts for the cron itself.

Go-live checklist

The existing operations runbook (scripts/GO_LIVE_RUNBOOK.md) gained a section specific to this feature. Before enabling it for any tenant:

  • ACCESS_KEY_HMAC_SECRET must be set to at least 32 random bytes (the server refuses to boot otherwise — see Access Keys & Security Model).
  • TRUST_PROXY_HOPS must be set to the exact number of trusted reverse-proxy hops in front of the API (left unset only for direct, no-proxy access) — the server now deliberately ignores forwarded client IPs otherwise, which would make the desktop-endpoint IP rate limiters trivial to bypass if misconfigured the other way.
  • MINIMUM_XRAY_DESKTOP_VERSION should be set before enabling any tenant, so an outdated desktop app is rejected at connect (426 CLIENT_UPDATE_REQUIRED) rather than allowed to talk to a server it doesn't fully match.
  • Desktop-acquired X-rays reuse the same S3 bucket and presigned-POST flow as ordinary manual uploads — the runbook explicitly calls out verifying that bucket configuration before flipping the flag for a tenant, since a misconfigured bucket would fail silently at the upload-verification step described in X-Ray Acquisition Workflow.

A separate, manual workflow_dispatch GitHub Action (.github/workflows/sandbox-ops.yml) can reseed, reset, redeploy, or destroy per-branch PR sandbox environments — this is general sandbox tooling that happens to ship in this PR, not X-ray-specific, and isn't something Support or Sales need to know about.