Hub and nodes
The Pamodzi e-Services platform serves many ministries, departments and agencies (MDAs) through one national public portal. Behind it, each MDA may run its own back office, API and database. This shape is called the federation. In this lesson you learn the roles an installation can take, who owns what, and what data may live where.
One codebase, three roles
The same image runs in one of three roles, chosen with the environment variable PLATFORM_ROLE:
| Role | Purpose |
|---|---|
combined | The default. Hub and node in one installation: one database serving every ministry it hosts. |
hub | The national portal and aggregation. It signs citizens in, hosts the forms of every service, keeps the node registry and an index of applications, and relays everything else to the owning node. |
node | One MDA's back office and API. It owns that MDA's services, cases, payments and documents. |
There is exactly one hub. It serves every e-Service of every MDA and must scale horizontally: in the per-MDA deployment the hub's portal and API run behind horizontal pod autoscalers. Each node is sized for its own MDA (small, medium or large).
Every instance has a permanent NODE_KEY. The hub's is hub; a node's is a short, lower-case MDA key agreed when the node is created. The NODE_KEY never changes, survives restores and disaster recovery, and a retired key is never reused.
Combined mode is still federated inside
In combined mode, federation calls do not disappear. Each call is signed with the instance's own key and handed to the receiving pipeline in-process by a loopback adapter. The same signature, replay, scope, idempotency, schema, handler and audit code runs as between a real hub and node, only without a network hop. This is why every feature must work in all three roles: the code paths are the same, and the contract tests run against both the loopback and two real instances.
Who owns a service
Services are owned and designed on the MDA's own back office. Forms, processes, fees, required documents and output templates are managed there. The hub receives the catalogue by federation sync and serves it on the national portal.
The hub never becomes the place where a node's service is designed. If someone tries to edit a node's service on the hub, the API answers 409 SERVICE_MANAGED_BY_NODE ("This service is managed by <node> on its own back office"). Hub administrators can read the mirrored service, read-only, under System administration → National catalogue sync.
What lives where
The rule is short: data stays with its owner. The hub keeps only the index data it needs: numbers, status words, amounts due and document labels.
| Data | Hub | Node |
|---|---|---|
| Citizen account, ZamPass link, contact details, preferences, consents | Yes | A shadow applicant: a pairwise id plus the claims released per assertion |
| Service catalogue | Signed mirror | Source |
| Form answers, documents, decisions, case history | Only while relaying; staged files deleted once the node acknowledges | Yes |
| Invoices, receipts, issued permits | An index for display | Yes; finalised only here |
| Application index (number, status word, dates, amount due) | Yes | Source |
| Staff accounts and the audit of case work | Hub staff only | Yes |
| Module data (registers, leases, concessions) | None for a ministry with its own node | Yes |
Three consequences for operators:
- Answers, notes and documents stay on the node. When a citizen applies on the hub, the answers and files are
staged on the hub only until the node acknowledges them; then the hub deletes the files and the answers, keeping only hashes.
- The hub never holds a node's payment keys. Each node raises invoices on its own ZamPay merchant and receives
ZamPay's callback on its own API.
- No modules for node ministries on the hub. A ministry listed for an active node in the registry has no module on
the hub at all (409
MODULE_MDA_ON_NODE); its modules run on its node.
How citizens and staff reach a node
- Citizens always use the hub's portal. ZamPass sign-in happens only at the hub: on a node, a citizen sign-in
is refused with 403
FED_HUB_ONLY_CITIZEN_SIGNIN, pointing to the hub's portal. The hub vouches for the citizen to a node with a short-lived, signed citizen assertion (lesson 2). - Node staff sign in on their node's back office with a local account and an authenticator app (MFA). Optionally,
staff single sign-on lets a member of staff signed in on the hub open a node's back office already signed in; it is off by default and never creates an account or grants a role.
The flows in one picture
| Flow | Direction | Contract operation |
|---|---|---|
| Publish a service | node → hub | catalogue.put; the hub also pulls every 15 minutes |
| Apply | hub → node | submissions.create |
| Status, payments, issued documents | node → hub | events.post (CloudEvents) |
| Read an application, pay, download | hub → node | cases.applicantView, payments.get, documents.link |
| Verify a document or receipt | hub → node | verify.document, verify.receipt, verify.lookup |
| Citizen signed out | hub → node | events.post with session.revoked |
| Ministry status card | hub → node | status.summary |
Every one of these is a signed message on the versioned /fed/v1 contract. Lesson 2 explains how that trust works.
Check your understanding
- What are the three values of
PLATFORM_ROLE, and which one is the default? - Why do federation code paths still run in combined mode?
- Where is a node's service designed, and what does the hub answer if someone edits it there?
- Which data does the hub keep about a node's application, and which data must never stay on the hub?
- Where do citizens sign in, and how does a node learn who the citizen is?
Sign in to record your progress.