Dentolize · Regional DB Split Walkthrough
On this pageBusiness viewTechnical view

Admin: Cross-Region Controls

Business view

Dentolize's internal admin dashboard (used by Dentolize staff, not clinics) used to talk to one database. Now that clinic data is split across regions, the dashboard has to do one of two things for every screen: either merge results from every region into one list (so "all companies" still means all companies, everywhere), or ask the admin which single region they mean (for tools that only make sense scoped to one place, like restarting a cron job or inspecting a Redis key). This PR does both, screen by screen, and the change is visible in the walkthrough screenshots: the companies list still shows everything at once, while the Cron Jobs screen grew a Region dropdown.

Admin login itself is unaffected by all of this — it authenticates directly against the global Auth Server, not against any particular region — so admins don't need to "pick a region" just to sign in; they only encounter regions once they're using a tool that's inherently regional.

Technical view

Where cross-region admin logic lives

packages/auth-server/src/resolvers/adminRegionalResolvers.js (798 lines) is the single largest new file in the PR and the heart of this feature. It exports two resolver maps:

  • adminRegionalQueries (:377-651) — every admin list/search/analytics query, each one either fanned out and merged across all configured regions (company/branch/user/group listings and search, all the *Analytics/statement queries, companiesTotals) or routed to a single region once a company/entity is identified (companyDetails, getCronJobs, getRedisKey).
  • adminRegionalMutations (:653-798) — company-scoped mutations (editCompany, disableCompany, upload actions, adminToggleWhatsapp, etc.) proxied to the owning region; explicitly region-targeted ones (resetRedisKey, executeCronJob) that take a region argument directly; and a couple that broadcast to every region (sendChatMessageForAll).

How a request reaches the right region

Two supporting modules in packages/auth-server/src/utils/ do the actual routing:

  • adminRegionalRouting.js (192 lines) decides which region(s) apply: getAdminRegionalContexts for "every active region," getAdminRegionalContextForCompany for "look up this company's region in the global DB," findAdminRegionalContextForEntity for "probe every region for this id" (used when only an entity id is known, not its owning company), plus aggregateRegionalList/aggregateRegionalCount merge helpers for the fan-out queries.
  • adminRegionalProxy.js (167 lines) makes the actual network call once a region is chosen: sendInternalGraphQLRequest posts to ${regionApiUrl}/internal/graphql with a bearer token (INTERNAL_API_KEY), and verifies the response actually came from that internal endpoint via an x-dentolize-internal-graphql header before trusting it.

The internal GraphQL surface on each regional server

packages/server/src/apis/internalGraphQL.js (87 lines) mounts a second Apollo server at /internal/graphql on every regional server instance — separate from the public-facing GraphQL API — reusing the public resolvers plus admin-only ones (getCronJobs, getRedisKey, all adminMutations). internalGraphQLGuards.js (122 lines) locks this endpoint down: a static bearer-token check, an explicit whitelist mapping each allowed operationName to exactly one resolver field (internalOperationMap), and rejection of batched requests, introspection, and multi-operation documents. This is the mechanism the Auth Server uses to reach into one specific region's server for admin work without going through normal user authentication.

The Cron Jobs / Redis screen

packages/clinic-web/src/components/admin/cronJobs/CronJobsStats.js now renders a region Select populated from GET_ADMIN_REGIONS, persists the chosen region in localStorage['adminCronJobsRegionCode'], auto-selects when only one region exists, and threads regionCode into the cron-job query, into RedisKeyButtons.js (Redis get/reset buttons, disabled until a region is chosen), and into each row's ExecuteCronJobButton.js. There's no separate "region tab" — the selector sits directly above the existing single-page table. Route: /${ADMIN_LINK}/jobs, i.e. /ZROYKuKEVCvQykPlS4kP/jobs in this deployment (AdminDashboardRouter.js).

DisableUser2FA.js in the admin user-actions panel now passes both user and company to the mutation, matching adminDisableTwoFactor's new signature (adminRegionalResolvers.js:658-666) — supplying company lets the resolver resolve the region directly instead of probing every region for the user id.