Tools Portal
The non-clinical user portal at tools.ohm.doctor — medical coders, billing staff, and future analytics tools. Generic role with per-user feature flags so admins can grant exactly the tools each user needs.
The Tools Portal at tools.ohm.doctor is a separate frontend for
non-clinical users — medical coders, billing staff, and future analytics
or audit tools. It shares the same backend, auth, and organisation
scoping as the doctor app, but is completely sealed off from PHI
(patients, visits, notes, audio recordings).
Currently ships with one tool — the Codes Tool (AI ICD-10 / LOINC / SNOMED extraction + search + crosswalks + favourites + lists). New tools land here as new feature flags without touching the role system.
The model
Role.OTHER → defines the access boundary
(can log in, cannot see patient / visit / note data)
User.enabledFeatures → defines what they can do inside that boundary
(e.g. ["codes"]). Toggled per user by the
org admin.
Organization.features → the paywall layer
(e.g. features.codes = true means the org has
been granted this tool — sales / billing gate).A request is allowed when all three are true:
- JWT identifies a valid, active user in an active org.
- The org has the feature enabled (
Organization.features.codes === true). - The user has the feature in their list (
User.enabledFeatures.includes("codes")).
Plus a global belt-and-braces interceptor (OtherRoleGuard) that
rejects any sole-OTHER request to a path outside the codes-tool
allowlist — defense in depth in case a new PHI route is added without
its role decorator.
Onboarding
End-to-end flow: from DNS to a coder doing their first extraction.
Roles & features
The OTHER role, per-user feature flags, and the global guard model.
Codes Tool API
The /api/codes/* endpoints powering AI extraction, search, crosswalks, favourites, and lists.
Architecture at a glance
┌──────────────────────────────────────────────────────────────────┐
│ apps/api (NestJS) │
│ │
│ ┌────────────────────┐ ┌──────────────────────────────────┐ │
│ │ JwtAuthGuard │ │ OtherRoleGuard (global) │ │
│ └─────────┬──────────┘ │ Reject sole-OTHER outside │ │
│ │ │ allowlist (/api/codes/*, /auth/*)│ │
│ ▼ └──────────────────────────────────┘ │
│ ┌────────────────────┐ ┌──────────────────────────────────┐ │
│ │ RolesGuard │ │ RequiresFeatureGuard │ │
│ │ (per-controller) │ │ Two-layer: org features + │ │
│ │ @ClinicalStaff(), │ │ user.enabledFeatures │ │
│ │ @Roles(OTHER, ...) │ └──────────────────────────────────┘ │
│ └────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
│ │
│ │
app.ohm.doctor tools.ohm.doctor
(doctors, nurses) (medical coders, billers)Where it lives in the codebase
| Concern | Location |
|---|---|
Schema (Role.OTHER, enabledFeatures, CodeFavorite, CodeList) | apps/api/prisma/schema.prisma |
| Codes Tool module | apps/api/src/codes-tool/ |
| Curated crosswalk dataset | apps/api/src/fhir/codes/crosswalks.json |
RequiresFeature decorator + guard | apps/api/src/auth/decorators/requires-feature.decorator.ts, apps/api/src/auth/guards/requires-feature.guard.ts |
| Global PHI boundary | apps/api/src/auth/guards/other-role.guard.ts |
| Frontend portal | apps/tools/ |
| Admin invitation UI | apps/admin/src/pages/admin/InvitationsPage.tsx |
| Admin per-user features | apps/admin/src/pages/admin/UsersManagement.tsx |
Psychiatry insights
AI sidebar that surfaces mental status, risk flags, sleep, substance, and themes from the conversation. Psychiatry visits only.
Onboarding a non-clinical user
End-to-end flow for getting a medical coder or billing staff member onto the Tools Portal — from DNS through their first AI extraction.