Skip to content

GeoVault High-Priority Consistency Pass

Date: 2026-05-28
Scope: Normalize UX across dataset types without rewriting ingestion or the Version model.


Summary

This pass adds presentation-level rename, editable catalog metadata, archive/soft delete, a unified Publish button (with server-side capability checks), and a richer Versions tab (lineage, created date, source type). Existing publish implementations (tileserver, QGIS) are reused.


What changed

1. Rename

  • Route: POST /datasets/{name}/rename — body { "name": "new_name" }
  • Updates datasets.name, versions.dataset, GeoServer publication/job dataset_name fields, and GDAL sidecar JSON under data/metadata/ (not geospatial files or PostGIS tables).
  • On-disk project dirs (/data/projects/...) are not moved.
  • UI: Rename on dataset detail header and list cards (prompt on list pages without modal).

2. Editable metadata

  • Routes:
  • GET /datasets/{name}/metadata — catalog fields + archived flag
  • POST /datasets/{name}/metadata — save catalog fields
  • Table: dataset_metadata (FK dataset_iddatasets.id)
  • Fields: title, description, tags, citation, attribution, keywords, notes
  • UI: Metadata tab — editable form + read-only technical (GDAL/PostGIS schema) section

3. Archive / soft delete

  • Column: datasets.archived_at (NULL = active)
  • Routes:
  • POST /datasets/{name}/archive
  • POST /datasets/{name}/restore
  • Permanent delete: DELETE /datasets/{name}?confirm=true now requires the dataset to be archived first (when DATABASE_URL is set).
  • Listing: GET /datasets-summary?archived=only | archived=include (default excludes archived)
  • Page: /archived — restore or delete permanently
  • Discovery API excludes archived datasets.

4. Unified Publish

  • Capability: GET /api/versions/{id}/publish-capability{ available, target, reason }
  • Publish: existing POST /versions/{id}/publish — refactored to use PublishCapabilityForVersion + executePublishVersion
  • UI: single Publish button per version row; checks capability before POST
  • Routing (internal):
  • Vector + local file → tileserver
  • Raster + local file → QGIS
  • PostGIS / GeoServer remote / remote S3 / no file path → disabled with explanatory message

5. Version history UI

  • Versions tab columns: Version, Created, Source type, Lineage, Actions
  • Lineage: clickable “Derived from vN” when parent_version is set; shows operation when present
  • Actions: Preview, Publish, Download (when allowed), Transform (vector file only), Delete (non-latest)

Schema changes (internal/db/migrate.go)

ALTER TABLE datasets ADD COLUMN IF NOT EXISTS archived_at TIMESTAMP;

CREATE TABLE IF NOT EXISTS dataset_metadata (
    dataset_id INTEGER PRIMARY KEY REFERENCES datasets(id) ON DELETE CASCADE,
    title TEXT NOT NULL DEFAULT '',
    description TEXT NOT NULL DEFAULT '',
    tags TEXT NOT NULL DEFAULT '',
    citation TEXT NOT NULL DEFAULT '',
    attribution TEXT NOT NULL DEFAULT '',
    keywords TEXT NOT NULL DEFAULT '',
    notes TEXT NOT NULL DEFAULT '',
    updated_at TIMESTAMP DEFAULT NOW()
);

Run migrations on startup via existing migrate() (idempotent).


New / updated files

Area Files
DB internal/db/dataset_lifecycle.go, migrate.go, datasets.go
API internal/api/dataset_lifecycle.go, publish_unified.go
Store internal/store/dataset_catalog.go
UI web/dataset.html, web/archived.html, web/app.js, web/style.css, vectors.html, rasters.html
Routes main.go

Known limitations

  1. DATABASE_URL required for archive, restore, and catalog metadata persistence. Rename and version catalog updates work without DB (versions store only).
  2. Rename changes the vault dataset key (URL /datasets/{name}) but not on-disk folder names under /data/projects/{oldName}/.
  3. Auth resources — new name registers a federation resource; old resource key may remain orphaned until manual cleanup.
  4. Rollback — not implemented (out of scope).
  5. GeoServer publish from version row — still uses tileserver/QGIS paths; full GeoServer publish remains on ingest + /geoserver/publish.
  6. List rename on vectors/rasters uses window.prompt when the dataset page modal is not present.

Future follow-ups

  • Dataset rollback / promote version to latest
  • Migrate auth resource keys on rename
  • Optional rename of on-disk project folders (with explicit user opt-in)
  • Archive support without PostgreSQL (JSON sidecar)
  • GeoServer publish from unified Publish for eligible local versions
  • Permissions/visibility editor in UI
  • Federation nav entry for Archived in shared shell config

Quick API reference

Method Path
POST /datasets/{name}/rename
GET/POST /datasets/{name}/metadata
POST /datasets/{name}/archive
POST /datasets/{name}/restore
DELETE /datasets/{name}?confirm=true (archived only, with DB)
GET /datasets-summary?archived=only
GET /api/versions/{id}/publish-capability
POST /versions/{id}/publish