Home/ News/ v5.3.0 — Geo round 2 + Brazil + dark-mode + a11y
Release Last stable 5.x 2026-05-27 ~5 min read

v5.3.0 — Six deep bundles
and the last stable cut of the 5.x line.

Six bundles that each landed as their own audit pass. Geo Hub round 2 closes storage leaks and caps accuracy at 10 km. Brazil gets BRL, NBR 12721 classification, and an RPS-layout invoice PDF. /login reads cleanly in dark mode. /reporting finally renders HTML reports in-page. Daily Diary entries can be deleted. And 51 frontend files pass WCAG-AA on the top contrast offender. This is the version we’d ship to a customer and not flinch.

v5.3.0

v5.2.8 was a polish wave on top of a one-day release. v5.3.0 is the opposite shape: six unrelated deep dives, each one its own audit and each one shipped with tests. Nothing in this release is a feature in the “new module” sense — everything closes a real bug or a real gap that was visible from a single user session. The cumulative effect is what makes this the cut we’re labelling the last stable release of the 5.x line.

The six bundles

Geo Hub round 2 — storage leaks, accuracy cap, iOS

delete_tileset deleted the DB row and left the actual tileset bytes orphaned in MinIO. v5.3.0 calls storage_backend.delete_prefix() first, with a new sweep_deleted_raster_overlays(older_than_days=30) helper for retroactive cleanup. The accuracy_m field gets a 10 km hard cap so a stray fat-finger can’t blow up the whole map. map_config pushes the development_id filter into SQL instead of in-Python. And ProjectGeoPage uses 100dvh so the iOS Safari URL bar stops collapsing the map.

Brazil Tier-1 — BRL + NBR 12721 + RPS PDF

From a real user note: “there is no invoice support for BRL”. v5.3.0 adds BRL to the finance shortlist, ships a 500-line br_invoice_pdf.py renderer with proper prestador / tomador blocks and retenções (ISS, PIS, COFINS, CSLL, INSS, IRRF), and two new validation rules — NBR12721ClassificationRequired and NBR12721ValidSection covering S1–S11 cost groups. The BOQ importer now recognises nbr and sinapi codes; São Paulo defaults to SINAPI as its regional cost reference. 15 new tests cover the renderer and the rules.

/login dark-mode contrast

Reported as “buttons under the form are barely visible and the cell text disappears in dark mode.” Seven scoped overrides on LoginPage.tsx, no token-level changes: the form column backdrop drops to dark:bg-[#070912], the demo buttons get dark:bg-white/[0.06] with a proper hover, the credential cards get dark:bg-white/[0.07] and dark:border-white/15, the subtitle is promoted from tertiary to secondary ink, and the ArrowUpRight chrome reads at the same weight in both themes. Light mode is untouched.

/reporting renderer + Daily Diary delete

/reporting had a list of generated reports but no way to look at one. v5.3.0 adds a View button per row that opens ReportViewerModal — sandboxed <iframe srcDoc=...> for the HTML, blob URL for the new-tab link, distinct error states for 410 (expired) / 404 / network. Daily Diary entries finally get a Trash2 ghost button gated on !sealed, wired through useConfirm() with a danger-styled ConfirmDialog. Four new tests cover the delete path.

WCAG-AA contrast pass — 51 frontend files

The top axe-core offender across the app was text-oe-blue on top of bg-oe-blue-subtle — 3.1:1, below the 4.5:1 AA threshold for normal text. Bulk rewrite of 51 files and 126 lines moves those pairs to text-oe-blue-dark, which clears AA on every co-occurrence. Includes the global project-picker chip in Header.tsx and the blue variant of Badge.tsx, so the fix lands site-wide, not just on the original surfaces.

Dashboard rollup + PR #164 + back-catalogue

Dashboard reduces from 13 per-widget requests to 6 via a new RollupRequest schema with 10 configurable widget IDs and bounds validation (+136 LOC, 41 tests covering IDOR isolation and rollup parity). External contribution PR #164 from @Mourdi59 merged via author-attributed commit (b169a687) — set_user_module_access was silently dropping its metadata payload because SQLAlchemy reserves the attribute name. Three v3 release announcements backfilled and the broken og:image on news.html repointed at an image that actually exists on the VPS.

Why this is the last stable 5.x

The 5.x line opened with the deep-coordination initiative (v5.1.1, file versioning + notification dispatcher + audit trail), settled into a release-every-two-days cadence through v5.2.x, and ends here. None of the bundles in v5.3.0 are speculative — every one of them came out of a user report, an audit pass, or a contributor PR. The stable mark means this is the build we’d pin in production for a customer engagement while the 6.x line lands its bigger architectural moves (multi-tenant RLS, Yjs collaboration on BOQ, marketplace v1).

It also means the surface area we audited explicitly: the storage backend around Geo Hub no longer leaks bytes; the Brazil locale has a real end-to-end invoice path rather than a forced-USD workaround; the most common dark-mode reading problem is gone; the reporting module renders what it generates; the diary entries are deletable; the most-trafficked blue-on-blue contrast pair clears AA; and the dashboard fan-out is half what it was. Tests are green on the wave-touched suites. CI publishes the wheel under Trusted Publishing without manual twine.

Upgrade

pip install --upgrade openconstructionerp

No Alembic migration in this release — head stays at v3144. Backend ships the BR invoice renderer, two new validation rules, the Geo Hub storage-sweep helper, the dashboard rollup endpoint, and the metadata payload fix on set_user_module_access. Frontend ships the dark-mode LoginPage overrides, the ReportViewerModal, the Daily Diary delete button, the 100dvh Geo viewport, and 126 lines of text-oe-blue-dark migration across 51 files. No new modules; module count stays at 116.

Try v5.3.0 today.

Live demo in your browser, or self-host in five minutes. AGPL-3.0, no signup required.