Skip to content

GeoVault Capability Audit

Date: 2026-05-28
Scope: Capability consistency across major object types in the GeoVault monolith (geovault/).
Method: Code and UI review of routes (main.go), API handlers (internal/api/), persistence (internal/db/), and web UI (web/). No code changes were made.


Executive summary

GeoVault is a single Go service with server-rendered HTML and vanilla JS. Most “datasets” share one Version catalog model (file-backed vectors/rasters, URL/S3 imports, ESRI imports) plus registry rows in PostgreSQL. PostGIS and GeoServer remote datasets are registry pointers without file copies. QGIS Projects are external runtime objects proxied to qgis-publish-service.

Versioning is strong for file-based datasets (sequential v1, v2, … on disk + catalog) but there is no rollback to a prior dataset version—only delete non-latest versions or create derived versions (filter/dissolve/clip). Rollback exists only for QGIS runtime project snapshots.

The largest consistency gaps are: uneven publish targets (vector → tileserver, raster → QGIS), GeoServer remote/catalog datasets that look like vectors/rasters but lack file workflows, PostGIS live tables with no schema history, missing clone/rename/archive across types, and fragmented import entry points (Upload, URL, S3, ESRI, GeoServer catalog).


1. Capability matrix

Legend: Y = supported, P = partial / constrained, N = not supported, = not applicable.

Type Create Import Preview Metadata Publish Versioning Rollback Export Delete Notes
Vector (file) Y Y Y Y (read-only GDAL) Y (tileserver) Y N Y (download) Y Filter/dissolve/clip → new versions; optional PostGIS + GeoServer on ingest
Raster (file) Y Y Y Y (read-only) Y (QGIS WMS) Y N Y (download) Y No geoprocessing transforms; raster list omits URL import link
PostGIS (registered) Y (register) P (vector→PostGIS on file ingest) P (table info, no map) Y (table/schema) N (from version row) P (single v1 row) N N Y (dataset) Live row edit; no file versions; upload card hidden
GeoServer remote Y (catalog import) Y (catalog) P (WMS preview on pubs card) Y (service URLs in meta) N (already published) P (single v1 stub) N N Y Listed under vector/raster by inferred type; no local file
GeoServer connections Y Y (connection record) Y (publish jobs) N N N Y Workspaces/styles managed; geoserver_jobs for async work only
PG connections Y P (browse/preview rows) Y N N N Y Admin-level service ACL; not versioned
PostGIS registry DBs Y (adopt/create) P (discover) P N N N P Via postgis-service proxy
QGIS Projects P (via raster publish) Y (viewer URL) P Y (runtime) Y (snapshots) Y Y (ZIP) P (external) Not in GeoVault DB; history in qgis-publish-service
ESRI import P Y P P (creates vault datasets) N N PostGIS + GeoJSON file per layer; background jobs

2. Per-type detail

VECTOR DATASETS (file-based)

Model: models.Version with type: vector; files under /data/projects/{projectId}/{dataset}/v{N}/; metadata JSON in data/metadata/.

A. CRUD + lifecycle

Capability Status Implementation
Create Y /upload (filename → dataset name) or first upload on /datasets/{name}/upload
Import Y /import-url, /import-s3 (import mode), optional ESRI → GeoJSON + PostGIS
Upload Y /datasets/{name}/upload, /projects/{id}/upload
Edit metadata P GDAL-extracted metadata read-only; optional message / version_label at ingest only
Rename N No API or UI
Clone/copy N No dataset clone
Delete Y DELETE /datasets/{name} (admin); DELETE .../versions/{version} (non-latest only)
Archive/soft delete N Hard delete only
Background jobs P GeoServer publish jobs; ESRI import jobs (separate flow)
Batch operations N

B. Data management

Capability Status Notes
Preview/view Y Map preview (Leaflet), /preview, version modal
Download/export Y GET /versions/{id}/download
Import into PostGIS Y Optional panel on upload, URL, S3
Publish to GeoServer Y Optional panel on ingest; dedicated /geoserver/publish for existing versions
Link to QGIS P Via raster-style publish only on raster; vectors use tileserver
Metadata editing N (read-only) Tab + modal show extracted metadata
Tags/categories N
Search/discovery P /api/discovery lists dataset names only
Permissions/access Y Federation geovault_dataset resources: view/edit/admin; visibility public/restricted in DB (display only in UI)

C. Version control / history

Question Answer
Versioning exists? Yes — integer versions, on-disk dirs, versions table / store.Versions
Revision history? Yes — list on dataset Versions tab
Rollback? No — cannot restore v2 from v3; only delete or add versions
Snapshotting? Implicit — each version is a full file snapshot
Audit logs? Partialcreated_by, created_at, operation, parent_version on derived versions
File versioning? Yes
Lineage/provenance? Partialparent_version + operation for filter/dissolve/clip; not shown in UI tree

D. UI actions inventory

Location Actions
Nav / hub Federation workspace; sidebar via shared UI
/vectors (Vector Files tab) Grid: Open, Download (if allowed), badges
/upload File upload + PostGIS import panel + GeoServer publish panel
/import-url, /import-s3 Remote ingest + same sidecar panels
/datasets/{name} Tabs: Preview, Metadata, Versions, Edit Data (placeholder for files)
Versions tab Upload new version; per row: Preview/Metadata, Publish (Tileserver), Transform (Filter, Dissolve, Clip), Delete (non-latest)
Header Delete dataset
GeoServer card List publications, WMS preview

Missing obvious actions: Clone dataset, rename, rollback to version, edit visibility/permissions in UI, promote version to latest, batch delete, export to formats other than raw file download.


RASTER DATASETS

Same version model with type: raster.

A. CRUD + lifecycle

Same as vector file datasets except: no filter/dissolve/clip derived versions.

B. Data management

Capability Status Notes
Preview/view Y Raster preview via GDAL
Download/export Y Same download endpoint
Import into PostGIS P Panel present on upload/URL/S3 but typically N/A for rasters
Publish to GeoServer Y Ingest sidecar + /geoserver/publish
Link to QGIS Y POST /versions/{id}/publish → QGIS publish service
Publish to tileserver N Vectors only

C. Version control

Same as vector files: multi-version yes, rollback no.

D. UI actions inventory

Location Actions
/rasters Grid (no URL import link in empty state — inconsistency vs vectors)
/upload, /import-url, /import-s3 Same as vector
/datasets/{name} Versions: QGIS publish button (not Tileserver); no Transform menu
/projects Lists QGIS runtime projects created from raster publish

Missing: URL import discoverability on raster page; tileserver parity; rollback; clone.


POSTGIS CONNECTIONS / DATABASES / REGISTERED DATASETS

Three related concepts:

  1. pg_connections — saved PostgreSQL credentials (/connections, /api/connections/*).
  2. PostGIS registrypostgis-service proxy (/discover-postgis, /api/postgis-service/*).
  3. Registered datasetsdatasource_type: postgis, live table pointer (RegisterPostGISDataset).

A. CRUD + lifecycle (connections)

Capability Connections Registered dataset
Create Y Y (register from browse)
Import P (ogr2ogr from file ingest elsewhere)
Upload N (upload card hidden on dataset page)
Edit metadata P Connection edit; table schema via API
Rename N N
Clone N N
Delete Y (connection) Y (dataset)
Archive N N
Background jobs N N
Batch N N

B. Data management

Capability Status
Preview/view P — row preview in connection browse; dataset: table info, no map
Download/export N
Publish to GeoServer P — can publish file versions to GeoServer, not live PostGIS table from dataset row
Link to QGIS N from PostGIS dataset row
Metadata Y — schema/geometry via API
Tags N
Search/discovery P — appears on vector list PostGIS tab
Permissions Y — requirePostGISDatasetPermission + dataset ACL

C. Version control

Question Answer
Versioning? No meaningful versioning — one catalog row v1, “Registered from PostGIS”
Schema/DB change history? No — live edits mutate PostGIS directly
Rollback? No
Audit logs? No row-level history in GeoVault

D. UI actions inventory

Page Actions
/connections Add, test, edit, delete connection; browse tables
/connections/{id}/browse Preview rows, register as dataset
/vectors?tab=postgis List registered PostGIS datasets
/discover-postgis Discover/adopt databases (registry)
/datasets/{name} (PostGIS) Edit Data tab: filter, sort, paginate, insert row, save row; Table info; no upload/transform/publish/delete version

Missing: Schema migration history, point-in-time restore, export table, register URL path, versioned snapshots of table state.


GEOSERVER CONNECTIONS / RESOURCES

A. CRUD + lifecycle (connections)

Capability Status
Create/update/delete Y — /api/geoserver/connections
Test connection Y
Workspaces Y — list/create/delete
Styles Y — list/upload/assign/preview SLD
Catalog import Y — POST /api/geoserver/catalog/import → vault dataset
Publish Y — on ingest or POST /api/geoserver/publish
Background jobs Y — geoserver_jobs (queued/running/completed)

B. Data management

Capability Remote catalog dataset Publication record
Preview P — WMS preview button on dataset card Service URLs stored
Download N N
Metadata Y in datasource_meta Workspace/layer/style
Permissions Y (dataset ACL)

C. Version control

Question Answer
GeoServer config history in GeoVault? No — only current dataset_geoserver_publications + job log text
Dataset versioning for imports? Stub — single v1 row, geoserver_remote, no file
Rollback publish? No

D. UI actions inventory

Page Actions
/geoserver Hub (federation workspace)
/geoserver/connections CRUD connections
/geoserver/catalog Browse remote layers → Import to GeoVault
/geoserver/publish Upload new + publish, or publish existing dataset version
/geoserver/workspaces, /geoserver/styles Admin
Dataset page GeoServer publications panel

Missing: Publication history timeline, unpublish, sync catalog changes, dataset rollback.


QGIS PROJECTS

Runtime projects live in qgis-publish-service, not GeoVault DB.

A. CRUD + lifecycle

Capability Status
Create P — created when publishing a raster dataset version
Import N
Upload N (direct); raster publish uploads raster into project
Delete P — external service
Rename/clone/archive N in GeoVault UI

B. Data management

Capability Status
Preview Y — viewer URL
Download Y — current + snapshot ZIPs
Publish Y — serves via QGIS Server
Permissions P — editable / project_visibility from remote service

C. Version control

Question Answer
Versioning? Yes — snapshots in qgis-publish-service
Rollback? YesPOST /api/qgis-projects/{id}/versions/{version}/restore
Audit P — snapshot timestamps/sizes

D. UI actions inventory

Page Actions
/projects List projects, open viewer, download current, history link
/projects/{id}/history List snapshots, Restore, download snapshot

Note: Vector datasets do not create QGIS projects through the same publish path (tileserver instead).


ESRI IMPORTS (current + expected)

Current behavior (implemented in Go: esri_import.go, UI: /esri)

Capability Status
Browse service Y
Import layers Y — exports GeoJSON, loads PostGIS, creates vault dataset per layer
Background job Y — uses geoserver_jobs table with type esri_import
Vault file version Y — v1 GeoJSON on disk per layer
Re-run import P — can import again with new dataset names (prefix); no “refresh existing”

Expected / planned behavior (from legacy esri_browser_page.php and product gaps)

Expected capability Notes
Refresh/sync existing layers Legacy PHP suggests batch refresh; Go path creates new datasets
Import to vault only (no PostGIS) Current path always targets PostGIS
Map preview in vault Not exposed after import
Dataset lineage to ESRI service URL Stored in datasource_meta
Unified job UI ESRI jobs share table with GeoServer jobs but no dedicated history page
FeatureService incremental sync Not in Go importer

3. Version-control audit

What currently has versioning

Object Mechanism Rollback
File vector/raster datasets Integer versions + on-disk v{N}/ directories + DB/store catalog No (delete only)
Derived vector versions New version from filter/dissolve/clip; parent_version stored No
QGIS runtime projects Snapshots in qgis-publish-service Yes (restore)
GeoServer publish Job records only No
ESRI import One version per new dataset No

What does not (but data changes)

Object Gap
PostGIS live tables Edits are immediate; no GeoVault history
PostGIS schema No migration tracking
GeoServer remote layers Registry pointer; remote server is source of truth
Connection credentials Update in place
Dataset visibility DB column exists; no versioned policy history

Major inconsistencies

  1. “Version” means different things: file snapshot (datasets) vs runtime snapshot (QGIS) vs single stub row (PostGIS, GeoServer remote).
  2. Rollback only for QGIS, not for vault dataset versions—users may expect “restore v2” on /datasets/{name}.
  3. Raster vs vector publish split (QGIS vs tileserver) without a unified “Publish” abstraction in the UI.
  4. GeoServer catalog imports appear in vector/raster lists but behave like remote registrations (no download, transform, or version upload).
  5. S3 remote mode creates a version row but blocks preview, publish, download, transforms until a local import version exists.
  6. ESRI creates both PostGIS tables and vault versions but no integrated dataset workspace parity with file uploads.

What should probably have versioning (product view)

Area Rationale
File datasets Already have it; add rollback/promote for parity with QGIS
PostGIS registered tables Optional snapshot or audit log before bulk edits
GeoServer publications History of publish/update/replace per dataset
Connection config Change log for compliance
ESRI imports Reproducible job definitions + sync checkpoints

4. Consistency audit (cross-cutting)

Feature exists for one type but not another

Feature Has Lacks
Multi-version files Vector, raster PostGIS, GeoServer remote
Map preview File vector/raster PostGIS, remote S3, ESRI (post-import)
Download File vector/raster, QGIS ZIP PostGIS, GeoServer remote, remote S3
Geoprocessing Vector file Raster, PostGIS, remote
Publish button on version row Vector (tileserver), raster (QGIS) PostGIS, GeoServer remote, remote S3
PostGIS import sidecar Upload, URL, S3 ESRI (direct to PostGIS in job), not on GeoServer catalog
URL import empty-state link Vectors list Rasters list
Rollback QGIS projects All vault datasets
Permission badges on cards Dataset lists QGIS projects (different model)

Terminology / workflow fragmentation

Issue Examples
Duplicate import concepts Upload vs URL vs S3 vs ESRI vs GeoServer catalog vs PostGIS register
“Publish” overload Tileserver, QGIS, GeoServer, GeoServer catalog import
“Dataset” overload File dataset, PostGIS registration, GeoServer remote registry
“Version” overload File vN, QGIS snapshot, stub v1 for remote
Hidden types geoserver_remote listed under vector/raster filters by type, not datasource

UI fragmentation

  • Hub pages: /workspace, /geoserver, federation sidebar (shared) vs dedicated list pages.
  • PostGIS entry: /postgis redirects to /vectors?tab=postgis; legacy postgis.html may still exist.
  • GeoServer has five subpages; dataset-level publications are only on dataset detail.
  • QGIS projects separated from raster list despite being created from raster publish.

Orphan / discoverability risks

  • GeoServer-imported datasets may be misleading on vector/raster lists (badge “GeoServer”) without file workflows.
  • Remote S3 datasets allow “upload new version” in UI but capabilities remain disabled until local copy exists.
  • ESRI import does not link cleanly to resulting datasets from a single job summary page.
  • data/publishes.json appears legacy vs current publish API responses.

5. Gap analysis (prioritized)

HIGH PRIORITY (platform consistency)

  1. Unified versioning semantics — Document and/or align “version” across file datasets, PostGIS, GeoServer remote, and QGIS; add dataset version rollback or clearly differentiate from QGIS snapshot restore.
  2. Publish surface parity — Single mental model for “Publish” (targets: tileserver, QGIS, GeoServer) with type-aware defaults; today vector vs raster buttons differ with no GeoServer on version row.
  3. Remote / stub datasets — GeoServer catalog and S3-remote: either hide from vector/raster file workflows or implement preview/download/publish rules consistently (including empty-state copy).
  4. PostGIS vs file split — Users can edit live data without vault history; consider audit trail or snapshot before destructive edits.
  5. Permissions / visibility UXvisibility and federation ACLs exist; no UI to manage them on dataset create/edit.

MEDIUM PRIORITY

  1. Import path consolidation — One “Add data” flow with branches (file, URL, S3, PostGIS register, GeoServer, ESRI) sharing PostGIS/GeoServer sidecars where applicable.
  2. Rename + clone dataset — Common lifecycle ops missing for all registry types.
  3. Metadata/message editingmessage / version_label only at ingest; no post-hoc edit on Versions tab.
  4. Lineage UIparent_version and operation exist for transforms but are not shown.
  5. GeoServer publication history — Jobs table exists; no user-facing timeline per dataset.
  6. ESRI reproducibility — Re-run/sync same dataset; vault-only import option; job → dataset navigation.
  7. Discovery/api/discovery is name-only; no full-text, tags, or type filters.

LOW PRIORITY

  1. Archive/soft delete — Hard deletes only.
  2. Batch operations — No multi-select delete, publish, or import.
  3. Tags/categories — Not implemented.
  4. Raster empty state — Add URL/S3 import links to match vectors page.
  5. Legacy cleanupesri_browser_page.php, data/publishes.json, redirect-only /postgis.
  6. Export formats — Only raw file download (no Shapefile/GeoPackage export pipeline in API).

6. Quick reference — API routes by concern

Concern Primary routes
Dataset versions GET/POST /datasets/{name}/upload, GET /datasets/{name}/versions, DELETE .../versions/{version}, geoprocessing .../filter|dissolve|clip
Publish POST /versions/{id}/publish, POST /api/geoserver/publish
Import POST /import-url, POST /import-s3, POST /api/esri/import, POST /api/geoserver/catalog/import
PostGIS /api/connections/*, /api/datasets/register, /api/table/*, /api/postgis-service/*
GeoServer admin /api/geoserver/connections, workspaces, styles, catalog, jobs
QGIS /api/qgis-projects, .../versions, .../restore, .../download
Auth Federation login + geovault_dataset + service-level ACL (authz.go)

7. Audit checklist (requested format)

VECTOR DATASETS — current actions

  • ✓ Upload (/upload, dataset Versions tab)
  • ✓ URL / S3 import
  • ✓ Preview (map)
  • ✓ Metadata (read-only)
  • ✓ Publish to tileserver (version row)
  • ✓ Publish to GeoServer (ingest / dedicated page)
  • ✓ Import to PostGIS (ingest sidecar)
  • ✓ Transform: filter, dissolve, clip
  • ✓ Download
  • ✓ Delete version (non-latest) / delete dataset
  • ✗ Clone
  • ✗ Rename
  • ✗ Version rollback
  • ✗ Edit metadata after ingest
  • ✗ Archive

RASTER DATASETS — current actions

  • ✓ Upload, URL, S3 import
  • ✓ Preview
  • ✓ Metadata (read-only)
  • ✓ Publish to QGIS (version row)
  • ✓ Publish to GeoServer (ingest / page)
  • ✓ Download
  • ✓ Delete version / dataset
  • ✗ Transform menu
  • ✗ Tileserver publish
  • ✗ Clone / rename / rollback
  • ✗ URL import linked from /rasters empty state

POSTGIS — current actions

  • ✓ Connection CRUD
  • ✓ Browse tables, row preview
  • ✓ Register as dataset
  • ✓ Live table edit (insert/update/delete rows)
  • ✓ Discover/adopt (registry)
  • ✓ Vector file → PostGIS on ingest
  • ✗ File versions / upload new version on PostGIS dataset
  • ✗ Map preview
  • ✗ Download / export
  • ✗ Publish from dataset version row
  • ✗ Schema history / rollback

GEOSERVER — current actions

  • ✓ Connection CRUD, test
  • ✓ Workspace/style management
  • ✓ Catalog browse + import to vault
  • ✓ Publish file datasets (jobs)
  • ✓ Per-dataset publication list + WMS preview
  • ✗ Config/version history in UI
  • ✗ Rollback publication

QGIS PROJECTS — current actions

  • ✓ List runtime projects
  • ✓ Open viewer
  • ✓ Download project ZIP
  • ✓ Snapshot history
  • Restore / rollback snapshot
  • ✗ Create from vector publish
  • ✗ Managed delete in GeoVault

ESRI — current actions

  • ✓ Browse FeatureServer/MapServer
  • ✓ Import selected layers (PostGIS + vault GeoJSON)
  • ✓ Background jobs
  • ✗ In-vault map preview post-import
  • ✗ Refresh existing dataset
  • ✗ Full parity with Upload/URL workflows

End of audit. No code changes were made.