Repository navigation
Releases: winterop-com/dhis2w
Release list
v1.32.1
v1.32.0
A combined release: every dhis2w package and pack moves to 1.32.0 together. Its themes are DHIS2 2.43.2, a newer 2.44 preview build, and an upstream issue log organised for reporting.
DHIS2 2.43.2
- v43 is pinned to
2.43.2.0. The generated v43 tree only gains fields:UpdatePasswordRequest, program label properties,SystemSettings.jobsRescheduleAnalyticsAfterMinutesandTrackerRelationship.deleted. - 2.43.2 refuses the OAuth2 scope
ALLand requires PKCE, as 2.44 does. The v43 tree registers OAuth2 clients with the OpenID scopes (openid,email,profile,username), and--scopedefaults toopenidon v43.
DHIS2 2.44 preview
- v44 is pinned to the 2.44-SNAPSHOT build of 2026-10-06 (revision
c48aedc). It is still a preview until 2.44.0 ships. - The v44 tree gains
GET /api/metadata/dependencies, the newExternalMapLayerfields (description,descriptionUrl,image),MetadataExportParams.objectsExportWithDependenciesand eight new error codes.
Seed dumps
- Dumps follow the backup script of dhis2-server-tools: a plain
pg_dumpwithout owners, without the analytics fact tables, and withoutauditrows. make dhis2-migrate-e2e-dump DHIS2_VERSION=v4Nmoves a committed dump to a new pin by restoring it into the new image and letting DHIS2 migrate it: about 42 seconds, against about 35 minutes for a full seed. The fullmake dhis2-build-e2e-dumpis for seed changes.- The analytics sidecar reports a failed analytics run as a failure.
Upstream issues
DHIS2_ISSUES.mdis the upstream issue log, organised so each group is one upstream report: a status table by release, then 29 groups. Each group has a summary written as the ticket description, the versions it affects, and its member issues with copy-pasteable repros.- It was re-run on 2.43.2 and on 2.44
c48aedc. #13 is fixed on 2.43.2, #134 covers 2.43.2, and #144 and #145 are new. - The docs page is Upstream DHIS2 issues.
v1.31.1
A combined patch release: every dhis2w package and pack moves to 1.31.1 together. The changes are in the dhis2w-fhir pack, where the hostile_names = "substitute" posture words comparisons consistently in names and codes.
Upstream DHIS2 findings
- Issues #138 to #142 reproduce on a local 2.43.1 stack, so they are recorded against v43 rather than v44. #142 holds on values written moments earlier, which points at the predictor engine rather than the seed.
- #6 is restated: the 2026-09-11 admin refusal on 2.43.1 was E8023 (#41), and a superuser skips the open-future-periods check on 2.43.1 as on 2.44 (#139).
v1.31.0
A combined release: every dhis2w package and pack moves to 1.31.0 together. Its theme is DHIS2 2.44, which arrives as a preview, and generated models that no longer depend on which boot of DHIS2 they were captured from.
DHIS2 v44 (preview)
dhis2w_client.v44,dhis2w_core.v44anddhis2w_client.generated.v44join v41, v42 and v43. A client connected to a 2.44 server binds the v44 tree on its own;Dhis2.V44pins it. v43 stays the default plugin tree.- 2.44.0 is not released yet, so the local stack runs one pinned build of the 2.44 development line (
dhis2/core-dev, revisionb732899, pinned by digest). It is re-pinned to2.44.0.0when that ships. - What 2.44 changes, and how the v44 tree meets it:
- OAuth2 clients can register only the OpenID scopes (
openid,email,profile,username) and must require PKCE. The v44 tree registers exactly that and logs in withopenid;d2w profile ... --scopedefaults toopenidon v44. TrackedEntityAttribute.confidentialno longer exists; the v44 accessor, service andd2w metadatacommand take no--confidential.- A failed background job wipes its notification feed about a second after it ends.
client.tasks.await_completionand every--watchread the job's recorded outcome when that happens, on every tree.
- OAuth2 clients can register only the OpenID scopes (
infra/scripts/clone_version_tree.pycopies the hand-written trees to a new major and lists the lines to review, anddocs/architecture/versioning.mdhas the steps for adding a major.
Generated models
d2w dev codegen fetch-openapicaptures the live OpenAPI document, andmake dhis2-codegen-allruns it, so both halves of a generated tree follow the pinned release.- DHIS2 builds its OpenAPI document and
/api/schemasat startup, and one image answers differently on different boots. The codegen pins every shape seen to move, so any capture of a release emits the same models. Visible effect:CategoryOption.aggregationTypeis theAggregationTypeenum on every tree, andPage.itemson v42 and v43 is untyped. d2w dev codegen oas-flipslists what differs between captures of one release;infra/scripts/openapi_stability.shsamples several boots.
Fixes
d2w doctor bugsparses development versions such as2.44-SNAPSHOT.
Upstream DHIS2 findings
BUGS.md carries a full retest of every entry on 2.44 (103 still reproduce, 11 are fixed there) and new entries #133 to #143, among them the boot-dependent OpenAPI document (#133), the 2.44 OAuth2 registration rules (#134), Gist-shaped list responses with an http:// next-page link (#136), and /api/audits/trackedEntity answering 500 on 2.42 to 2.44 (#137).
Dependencies
SQLAlchemy 2.1, httpx2 2.13, a refreshed lockfile; CI on setup-uv 10.2.0.
v1.30.1
A combined release: every dhis2w package and pack moves to 1.30.1 together. The host itself has no changes; the release carries the dhis2w-fhir 1.30.1 improvements to make update in FHIR projects.
v1.30.0
FHIR is now a plugin pack in a repository of its own, dhis2w-fhir, with its history, the way the browser automation and the MCP server became packs in 1.29.0. The host is now the DHIS2 client, the core plugins and the d2w CLI.
Installing FHIR support
dhis2w-cli no longer installs FHIR by itself. Ask for it with the [fhir] extra, and add [serve] for the capture server:
uv tool install "dhis2w-cli[fhir]"
uv tool install "dhis2w-cli[fhir,serve]"Without the pack, d2w fhir prints that install command instead of "No such command". d2w browser and d2w security do the same.
A FHIR project scaffolded by d2w fhir init lists dhis2w-fhir and dhis2w-fhir-serve among its own dependencies, so make update keeps working unchanged.
What moved
| Package | Repository | Documentation |
|---|---|---|
dhis2w-fhir, dhis2w-fhir-engine, dhis2w-fhir-serve |
dhis2w-fhir | site |
The package names, d2w fhir and its commands, the capture UI and the engine's API are unchanged. The FHIR pages redirect to the pack's site. The canonical OperationDefinition pages that FHIR artifacts cite stay published where they are.
dhis2w-fhir 1.30.0 releases from its own repository after this release. Until then, [fhir] installs 1.29.0.
v1.29.0
The browser automation and the MCP server are now plugin packs in repositories of their own, the way d2w security already is. The host keeps the client, the core plugins, the CLI and FHIR, and every pack releases the same version after it.
What moved
| Pack | Repository | Documentation | PyPI |
|---|---|---|---|
d2w browser |
dhis2w-browser | site | dhis2w-browser |
| MCP server, CLI bridge, router | dhis2w-mcp | site | dhis2w-mcp, dhis2w-mcp-bridge, dhis2w-mcp-router |
Both repositories carry their history with them. The package names, the d2w browser commands, the dhis2w-mcp / dhis2w-mcp-bridge / dhis2w-mcp-router entry points and every MCP tool name are unchanged, so an install that names the packages picks up the packs as they release 1.29.0.
Installing
- Browser:
uv tool install "dhis2w-cli[browser]"as before. The pack registersd2w browserthrough thedhis2w.plugins.v1entry point. - MCP: install
dhis2w-mcp(ordhis2w-mcp-bridge,dhis2w-mcp-router) as before. The pack's onemcpplugin registers the tools of every built-in plugin, calling the same core services the CLI does. Its documentation holds the tutorial, the bridge, the router and the tool reference.
In the host
dhis2w-coreno longer depends onfastmcp, and core plugins contribute their CLI only.user-groupanduser-roleare no longer plugin names. Their commands were alwaysd2w user groupandd2w user role, which are unchanged.- The pages that moved redirect to the packs' sites.
v1.28.1
A guide whose DHIS2 codes carry a < now generates under hostile_names = "substitute", and d2w fhir init can set the root organisation unit, so a registry package and the guide depending on it state the same selection.
A < in a code
A DHIS2 code becomes an identifier value, which the IG publisher writes into a table cell unescaped and then strict-parses, so a < in one aborts the build's last pass. Until now substitute rewrote a < in a name and a space in a code, but refused a code carrying <.
Under substitute such a code is now rewritten the way a name is: the comparison is reworded and then every space is hyphenated, as for any code carrying a space. ENTO - IRS < 6 Months publishes as ENTO---IRS-under-6-Months. The DHIS2 code is stated beside it as the dhis2-code property, so it stays joinable back to the instance, and generate raises a note for each rewrite. Under refuse, or with the key unset, the run is refused naming the object, as before. d2w fhir validate grades the code the same way: informational under substitute, an error under refuse.
d2w fhir init --org-unit-root
--org-unit-root <uid> seeds [generate.organisation_units] root, the top of the subtree a project publishes. The UID's shape is checked, and nothing is read from the instance.
d2w fhir init national --with-registry --id dhis2.fhir.national --org-unit-root ImspTQPwCqd --org-unit-max-level 5Under --with-registry the root lands in both projects, as --org-unit-max-level does. A guide's forms may only be assigned to organisation units the registry package publishes. A guide whose [generate.organisation_units] table is left empty reads the whole instance, including any subtree kept for deactivated organisation units that the package's root leaves out, and d2w fhir check-artifacts then reports each such reference as build-aborting. Publish the registry as a package now states this rule, and Troubleshooting names the finding.
The depth flag beside it is now --org-unit-max-level, so both flags name what they select, the way --org-unit and --org-unit-group do elsewhere in d2w. A script passing --max-level needs the new name, and fhir.toml is unchanged: the keys are still root and max_level.
For a pair scaffolded on an earlier version, copy the registry's root and max_level into the guide's fhir.toml, then run make update and make generate.
v1.28.0
A large registry or guide now builds on a machine that has room for it, rather than being killed by giving the publisher more heap than the machine can hold alongside everything else.
The publisher heap
A build holds more than its heap. The Java process keeps about 2 GB of its own around the heap, and Jekyll renders the site at the very end as a second process in the same container, taking about 4 GB on a registry of twenty thousand resources. Java also grows into whatever ceiling it is given, so a larger JAVA_HEAP is more memory held, not more room.
Measured on a registry package of 10,453 organisation units (20,906 resources), the publisher never used more than 7 GB of heap. At 8g the build held about 13.5 GB in total. At 16g it held about 21.5 GB, which a 24 GB Docker cannot hold with anything else running. Depth (seven levels instead of five) and organisation unit geometry each changed that by less than 0.3 GB. The number of resources is what matters.
- The default
JAVA_HEAPis now the memory Docker reports less 6 GB, capped at8gand floored at4g, and8gwhen Docker cannot be asked. A 24 GB Docker now gets8g, not22g. A guide that really needs more stops with a JavaOutOfMemoryError, which says so, andmake build JAVA_HEAP=12graises it. - Every build prints two peaks as it finishes.
peak memory in useis what the machine has to hold: the heap, the Java process around it, and Jekyll.peak container memoryis the container's own high-water mark, which also counts file cache the kernel takes back when memory runs short. Size Docker by the first. - When the build is killed for memory, the report now suggests lowering the ceiling (
JAVA_HEAP=8gwhen it was above that) before giving Docker more memory.
Invisible characters in contact details
A DHIS2 phone number or email that carries an invisible format character (a zero-width space pasted in with the number, a byte-order mark, a direction mark) is now published without it. The IG publisher renders a phone contact as a tel: link, and a link with a zero-width space in it failed the build's QA with XHTML_URL_INVALID. Every digit and letter of the value is kept, and DHIS2 is not touched. Organisation unit phone numbers and emails, and the phone number nominated under [ips.identity], are covered, and generate raises a note naming each organisation unit whose DHIS2 value carried one.
d2w fhir validate now reports the same kind of character in names, form names, option names and codes (invisible-character). It reports only a stray one, touching nothing but visible ASCII, such as B. HinTang or a code OU2. Lao, Thai, Khmer and Myanmar mark word breaks with a zero-width space, so one inside such text is correct and is left alone. A code is a warning, because it reaches identifiers, resource ids and URLs. A name is informational and is published as DHIS2 holds it. The reports print the character as , so it can be seen, and the fix is to retype the value in DHIS2.
A project picks up the new Makefile with make update. A JAVA_HEAP set on the command line or in the environment is used as it stands.
The reference is Build and publish.
v1.27.0
A guide can now publish its organisation units without their boundary polygons, or without any geometry.
How much geometry a Location carries
[generate.organisation_units] geometry takes one of three values:
full(the default) publishes each Location with its position and its boundary, as it did before.positionkeepsLocation.position(the DHIS2 point, or the centre of the boundary) and leaves out thelocation-boundary-geojsonextension. Boundaries are most of a registry's size on an instance with detailed polygons, so this gives a much smaller guide that still places every organisation unit on a map.nonepublishes neither, and the run leavesgeometryout of its DHIS2 read.
[generate.organisation_units]
geometry = "position"d2w fhir init --geometry position seeds the key in a new project. Under --with-registry it goes to the registry package, which is the project that publishes the Locations. A guide that depends on a registry package is refused any value other than full, with a message pointing at the package's fhir.toml. The registry page and the guide's home page say which setting the organisation units were published under.
The organisation units page
The capture server now tells the organisation units page which setting was used.
- Under
position, the map draws the organisation units as points and says the guide publishes no boundaries. - Under
none, the page has no map: the hierarchy and the details share the screen. - The note shown when a selected organisation unit has no coordinates now blames the source it can be sure of. That is the DHIS2 instance when this project published the units, and the registry when another package did.
The reference is What goes in. A project picks up the new line in its fhir.example.toml with make update.