Four changes that together get a signed-in officer back to working data.
The SSO validation in index.php and embed.php called the public hostname from
inside the server. The Lands Commission's NAT rule blocks traffic that leaves
the server and tries to come back in, so that curl stalled for its full
30-second timeout and then failed validation, bouncing the user back to the
login. Both now call http://l4lmainbackend/sso/validate, overridable with
LUPMIS_SSO_BASE. Measured from inside the spdrawing container: 25 ms with no
redirect, against a 10-second timeout on the public name.
API_ROOT is now the relative path /api. The PWA host already proxies it to the
ApiEngine container — a deliberate route, not a catch-all: /api answers on pwa.
and api. but not on permits., minio. or minioapi. Same-origin removes the
mixed-content, CORS and CORP constraints that Cross-Origin-Embedder-Policy:
require-corp imposes on a cross-origin call, and no API hostname is compiled
into the bundle any more. The dev server proxies /api to the public host, which
is right there because a developer's machine is outside the server and only
callers inside it are blocked from the public name.
A direct request for /index.html bypassed index.php, which is what injects
window.LUPMIS_SESSION, so the app started with no session at all and said so in
the menu. The LUSPA landing page links to exactly that URL, and the SPA
fallback could not help because its RewriteCond !-f fails precisely when the
file exists. .htaccess now routes it through index.php; index.php reads
index.html from the filesystem, so there is no loop. This one is inert until
AllowOverride is relaxed on the PWA container, where it is currently None.
Service worker v29, and v28 before it, which carries the GIS Tools rename to
devices that already have the app installed. The tile cache stays pinned at
v24, so downloaded map areas survive both updates.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two branches from parallel sessions, merged in that order because the first
removes shp-write and with it JSZip, which the second was working around.
Conflicts resolved by hand in vite.config.js: the JSZip chunk rule the second
branch added is dropped, since nothing reaches JSZip any more — shapefiles are
written by src/shapefile-write.js and shpjs 6 unzips with but-unzip. Vite's
preload-helper rule stays, which is what keeps the geotiff chunk out of the
startup preload. dist/ was rebuilt from scratch rather than merged, its hashed
file names being a conflict on every file.
Service Worker v26 now records both changes.
Verified on the merged tree: a production build preloads only the entry,
vite-helpers, bootstrap, openlayers and ol-ext — geotiff, shpjs and pako are
gone from startup, and Analyse still fetches its chunk and turf on first use.
Shapefile export, driven through the Export GIS modal, writes a zip holding the
point and polygon sets with their .prj and .cpg.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
vite.config.js splits geotiff and shpjs out so they load only when a user opens
a Cloud-Optimized GeoTIFF or imports a shapefile, but the built index.html
preloaded both on every visit — about 428 kB (152 kB gzipped) nobody had asked
for.
Two separate causes, both visible in the entry chunk's first line:
- it imported Vite's preload helper, used by every dynamic import(), from the
geotiff chunk. The helper is a virtual module with no node_modules path, so
Rollup had parked it there; needing it at startup dragged the whole chunk in.
It now has a chunk of its own, about 1 kB.
- it imported JSZip from the shpjs chunk. JSZip reached the bundle through
shp-write, which gis-export.js imports for Shapefile export, so it is needed
at startup whatever happens; filing it under shpjs pulled that chunk in too.
It is now its own chunk, costing the 31 kB it actually is.
dist/ rebuilt: index.html now preloads vite-helpers and jszip instead.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Choosing Shapefile in the Export GIS modal produced no file. shp-write@0.3.2
cannot run in this build, in three separate ways: its dbf dependency assigns an
undeclared variable, which was fine in the browserify bundle it was written for
but is a ReferenceError under the strict mode ES modules always use; its zip.js
branches on process.browser, which does not exist in a browser; and its
download.js delivers the archive by navigating to a data:application/zip URL,
which Chromium blocks in the top frame.
- src/shapefile-write.js writes .shp/.shx/.dbf/.prj/.cpg itself: geometries
split by type into up to three layers, polygon rings re-wound clockwise as
the format requires, DBF column types inferred per column, names sanitised
to DBF's 10 characters and de-duplicated, UTF-8 declared via .cpg.
- src/zip-store.js holds the STORED-ZIP writer that was inside analysis/xlsx.js,
so both writers share it. Pure-ASCII archives are byte-for-byte as before.
- shp-write, and with it dbf and JSZip 2.5.0, leave the dependency tree; the
build no longer warns that node's "assert" was externalised.
- Service Worker v26 for the new bundle.
Verified in a browser: the Export GIS modal, driven through its own controls
with Web Mercator features, produced area_analysis.zip holding both layers with
WGS84 coordinates, file code 9994 and the right shape types. The archive reads
back through the application's own shpjs importer with geometries, numeric,
text and boolean attributes intact. The zonal-statistics .xlsx export, which now
shares the zip writer, still opens and reads correctly.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Stage 1 of the GIS Analytical Tools concept — client-side spatial analysis:
- src/analysis/overlay.js: vector overlays (intersect / clip / difference /
union-dissolve) on Turf.js, reprojecting to WGS84 and merging attributes
(intersect keeps both layers', clip keeps only A's).
- src/analysis/zonal.js: vector-in-vector zonal statistics — count / sum /
mean / min / max / total area per zone, with centroid-in-zone (default) or
any-overlap membership.
- Bounding-box pre-filtering in both: only genuinely overlapping pairs reach
the expensive geometry test. 43 zones x 25,004 parcels now completes in
~106 ms; previously it was refused as too large.
- src/analysis-modal.js + markup: Analysis panel with "Apply to" scoping —
whole layer, current map view, selected features, or the catch of a drawn
Circle/Area. Reached from a new "Analyse" dock button.
- MapView.addCOGLayer() for Cloud-Optimized GeoTIFF display (WebGLTile +
GeoTIFF source, imported lazily); listVectorLayers(); getSelectedFeatures().
- Circle/Area analysis popup: one "Export" button (PDF folded into the export
modal as a fourth format, field-rename table hidden for it) plus an
"Analyse" button that opens the panel pre-scoped to the intersecting
features.
- vite.config.js: code-split turf, geotiff and pako so the eager bundle is
unchanged (~283 kB). Giving pako its own chunk also fixes a circular chunk
between jspdf and geotiff, which share it via fast-png.
Drawing-tool fixes carried in the same working tree:
- Delete/Backspace key deletes the selection via the EditBar's Delete
interaction (same undoable block as the button).
- Multi-select: shift-click toggles, Ctrl/Cmd-drag box-selects; helper layers
(vertex overlay, GPS) excluded.
- Undo: split/merge/divide wrapped in undo blocks so one press reverses the
whole operation; vertex-overlay churn no longer pollutes the undo stack;
sources are re-scanned and the stack cleared when edit mode is entered, so
deletes on sub-grouped layers are undoable. NOTE: the undo behaviour is not
yet confirmed on-device.
- ol-ext TouchCursor gated to touch-only devices, so hybrid touchscreen
laptops keep the normal cursor.
Service worker v12 -> v13.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>