When to build a module
The Pamodzi e-Services platform is one reusable product deployed for many ministries, departments and agencies (MDAs). The faster a new MDA can be brought on, the more useful the platform is. That speed depends on one discipline: the core stays generic, and anything that belongs to one ministry is kept apart in an optional module.
In this lesson you learn to decide, before you write any code, whether a need calls for configuration, a reusable capability or a module.
Core, modules and the ground rules
Core is always on. It covers cases and workflow, the service designer, payments, documents, users and policy, audit, notifications, jobs, reporting, MDA administration and the partner API. Core is MDA-neutral: core code, core data, core screens and core wording never name or assume a specific MDA. There is no if (mda === 'SOME-MINISTRY') anywhere in core, and no ministry name in core menus, seeds or templates.
A module is an optional, versioned bundle that a ministry can switch on without changing core. It owns its routes, policy actions, models and migrations, jobs, back-office pages and menu entries, settings, POS capabilities and its contributions to core extension points. Examples bundled today include rentals and leases, forestry, co-operatives and labour.
Two automated checks protect the boundary:
npm run check:mdafails when core code contains a ministry name, a ministry host or a historical ministry serviceid. Module folders, migrations, seeders, docs and tests are exempt, because that is where such values belong.
npm run check:modulesfails when core requires a file undermodules/, or when one module requires anothermodule's files.
Services are configuration, not code
Most new e-Services need no code at all. A service is designed in the back office service designer:
- the form (a form-js schema, including generic fields such as "Location / area on map");
- the process: the steps officers take, with roles and statuses;
- the fees;
- the required documents;
- the output templates: the permits, licences and letters the service issues.
If the designer can express what the ministry wants, you configure it. Writing a module for something the designer can already do adds code to maintain, tests to run and a switch an administrator must remember.
Prefer a reusable capability
Sometimes the designer cannot express the need. Before you reach for a ministry module, ask: could another MDA need the same thing? If yes, build it generically and switch it on per service through a service capability or a setting.
The platform already has several reusable capabilities built this way:
| Capability | What it gives any ministry |
|---|---|
The shop (goods-sale) | Any service becomes a shop with products, stock and orders |
| The allocation ledger | Quotas and pools that applications draw from |
| Name reservation | A generic name search across registers |
| Inspections and enforcement cases | Field visits, findings, penalties |
| The geometry field | Capture and check a place on a map |
The shop shows how it works. A shop is simply a service with the goods-sale capability, in any ministry; a ministry may run several. An administrator opens a shop for a service. Products, stock and orders are all scoped to the service's ministry on the server, and a two-ministry integration test proves one ministry cannot see or change the other's. The public portal shows one generic page whose title is the service's name. Nothing in the code or the locale files names a ministry or a kind of goods.
When a module is right
Build a ministry module when the behaviour, records or screens belong to one ministry's legal mandate and would make no sense elsewhere: a register only one ministry keeps, a ministry-specific calculation, a connector to a ministry's own system of record.
Even then, the module plugs into core only through extension points. If the module needs a hook that does not exist, you add a generic extension point to core and document it. You never put module logic into core files such as caseController or caseWorkflow.
A decision procedure
Work through these questions in order and stop at the first "yes":
- Can the service designer express it? Configure the service.
- Could another MDA use it? Build a reusable capability, activated per service.
- Is it specific to one ministry's mandate? Build a module.
Some worked examples:
| Request | Decision | Why |
|---|---|---|
| "We need a new import permit with a review step and a fee" | Configuration | Form, process, fee and template are all designer features |
| "Our ministry sells seedlings and publications" | Reusable capability (the shop) | Several ministries sell goods; goods-sale already exists |
| "Applicants must pick a plot inside our concession grid, and cells cannot be double-allocated" | Module plus generic pieces | The grid and its rules are one ministry's; the geometry field and validators are generic |
| "Add a 'My forest licences' page to the portal" | Neither: refuse | The portal is generic; licences appear under the generic My licences / permits |
The public portal stays generic
The last example matters. The public portal will serve thousands of services for many MDAs and must read as one government portal. A module never adds a ministry-specific section, page, route, menu entry or wording to it. Citizen features are generic across all services: My applications, My licences / permits, My payments, Documents to sign, My notices, Find an old application and Verify a document. A module may reach the citizen only through generic, data-driven blocks in those shared screens, such as status words, fee texts, lines in My records, or a map block for any licence with a geometry. A guard test with an allow-list enforces this; you must not add to the allow-list. Ministry-specific screens belong in the back office, under Ministry functions.
Check your understanding
- Name three things core covers, and explain what "MDA-neutral" means for core code and wording.
- What does
npm run check:mdalook for, and where are ministry values allowed? - Which five parts make up a service designed in the back office?
- Why is the shop a capability rather than a module for one ministry?
- A ministry asks for a "Rental payments" page on the public portal. What do you offer instead?
Sign in to record your progress.