Skip to main content

Frontend Overview

hlmis-frontend (package name hlmis-ui) is a Next.js 16 App Router app — React 19, TypeScript, pnpm. pnpm dev runs it on port 8111.

It talks to two backends:

  • The HLMIS API — the main application backend. Every call goes through one axios client (src/core/api/axios.ts) whose baseURL is resolved at runtime from GET /api/config, not baked in at build. See State & Data Fetching.
  • TRVST — the optional track-and-trace service for batch verification. All TRVST traffic is proxied through Next API routes under src/app/api/trvst/; client logic lives in src/adapters/trvst/.

Routing and access control

Route groups under src/app/:

GroupWhat
(auth)/loginThe sign-in page (public)
(public)/About, request-demo
(dashboard)/Everything behind auth — one folder per feature area
(dashboard)/view-mode/Read-only "browse as another store" mirror of the operational screens

src/proxy.ts is the Next middleware. It reads the NextAuth JWT and rewrites to /denied when the user's permissions array doesn't include what a path needs (MANAGE_ORDERS for /requisition and /distributions, MANAGE_ARRIVALS for /arrivals, the admin set for /users / /maintenance / /analytics, and so on). The sidebar (src/components/ui/app-sidebar.tsx) filters the same way, plus a few structural conditions (isMainStore, organization.hasChildren), so a user only ever sees links they can actually open.

Auth itself is NextAuth v4, JWT strategy, 1-hour sessions, credentials provider — src/services/authOptions.ts. The authorize callback calls the HLMIS API's /auth/login and stashes the returned bearer token on the JWT; the axios client attaches it to every request.

Where code lives

The codebase is mid-migration from a flat layout to a layered src/core/:

PathRole
src/core/api/axios.tsThe one axios client (singleton, lazy baseURL)
src/core/api/services/*One file per resource — thin functions that call the API and unwrap the { payload } envelope
src/core/api/types/Hand-written types, increasingly aliased onto src/core/api/generated/schema.d.ts — see API Types & Versioning
src/core/hooks/use*Service.tsTanStack Query hooks wrapping the services — the layer components import
src/core/lib/Framework-agnostic helpers: config.ts, deployment.ts, date-utils.ts, version-compat.ts
src/services/, src/hooks/, src/types/Older equivalents, still in use. New work goes in src/core/.
src/adapters/trvst/, src/adapters/superset/Integration-specific code, kept out of core
src/components/ui/shadcn/Radix primitives
src/components/attribute-fields/The custom-field renderer — see Attributes on the Frontend

Three component systems

The app deliberately mixes shadcn/ui (Radix primitives, in src/components/ui/), Mantine v7 (mantine-react-table for every data grid), and MUI (icons, the tree view). All three are themed to the HLMIS "Ledger Paper" identity — the orange scale in src/app/context/providers.tsx (mantineTheme) and the CSS variables in src/styles/globals.css keep Mantine and Radix from falling back to their default blues.

Providers

src/app/context/providers.tsx wraps the tree, outermost first: QueryClientProviderMantineProviderDeviceDetailsProvider (captures the metadata TRVST headers need) → SessionProviderSocketProvider (a socket.io connection used for live scan events and notifications).

i18n

next-intl, locales en / fr / ar / rw, message files at the repo root under messages/. Locale is persisted in the NEXT_LOCALE cookie and resolved server-side in src/i18n/request.ts; ar switches the layout to RTL. Components read strings through useTranslations("Namespace").