Deployment-Mode Gating
The frontend has to run in two modes — a standalone ("manual") deployment and a DHIS2-synced one — from the same build. See the backend's DHIS2 vs. Generic Mode page for the server side; this is how the UI decides.
One file reads the raw signal
src/core/lib/deployment.ts is the only file allowed to read
organization.source. Everything else asks it for a named capability.
export type DeploymentMode = "manual" | "dhis2";
export interface DeploymentCapabilities {
mode: DeploymentMode;
dhis2Data: boolean; // products / locations / users sourced from DHIS2
}
export function getDeploymentCapabilities(
organizationSource: string | null | undefined
): DeploymentCapabilities {
const mode = organizationSource === "dhis2" ? "dhis2" : "manual";
return { mode, dhis2Data: mode === "dhis2" };
}
The signal comes off the session: the logged-in user's
organization.source, set by the backend at login.
Screens call the hook
const { mode, dhis2Data } = useDeploymentCapabilities();
useDeploymentCapabilities() (src/core/hooks/useDeploymentCapabilities.ts)
just reads the session and calls getDeploymentCapabilities. Check a named
field — never compare organization.source directly anywhere else.
What the modes actually change
| Area | manual | dhis2 |
|---|---|---|
| Maintenance → Locations | full CRUD (<TabLocations>) | read-only synced org units (<TabOrganizationUnit>) |
| Create user | plain form | validate a DHIS2 username first, then create |
| Product import | available | hidden |
| Reports | Custom Reports tab shown (11th tab) | hidden; 10 fixed tabs only |
| Setup wizard | runs on a fresh deployment | never runs |
| Settings | General / TRVST / Device cards | also Synchronization / DHIS2 / Reporting cards |
The setup wizard is manual-only
src/core/hooks/useSetupCompletion.ts short-circuits to
isComplete: true when dhis2Data is true (or the user lacks
MANAGE_USERS), so <SetupWizard> in the dashboard layout never blocks a
DHIS2 deployment — its org units and users come from sync, not from the
wizard's create-branch / create-user flow.
Vaccine / donor fields are not gated here
VVM stage, freeze indicator, funder, partner name, shipment value and the
like are attribute-definition-driven (activate the field under
Maintenance → Attributes), not switched by a capability flag. A vaccine
programme on a manual deployment turns those fields on; deployment.ts
stays out of it.