Skip to content

GeoVault Medium-Priority Consistency Pass

Date: 2026-05-28
Scope: Lightweight dataset clone, version lineage UI, and safe rollback — extending the existing Version model and parent_version relationships without redesigning ingestion or architecture.


Summary

This pass adds:

  1. Clone / duplicate dataset — metadata and version-catalog copy with file copy-on-reference for local datasets; logical clone for PostGIS, GeoServer remote, and remote S3.
  2. Lineage UI — derived-from and transformation columns, a textual timeline panel, and per-version View lineage.
  3. Rollback to version — git-revert style: always creates a new latest version; never deletes or rewrites history.

Routes added

Method Path Description
POST /datasets/{name}/clone Clone dataset (body below)
GET /versions/{id}/lineage Ordered ancestry chain for a version row
POST /versions/{id}/rollback Create new version from target row ({ "reason": "..." } optional)

Routes use dataset name in the path (consistent with existing GeoVault APIs), not numeric dataset id.

Clone request body

{
  "name": "Roads (Copy)",
  "clone_metadata": true,
  "clone_versions": true,
  "clone_publish_config": false
}
  • clone_versions defaults to on for local managed file datasets, on for logical clones (metadata-only version rows).
  • clone_publish_config is accepted but not implemented (placeholder).

Clone response (excerpt)

{
  "success": true,
  "name": "Roads (Copy)",
  "source": "Roads",
  "logical_clone": false,
  "versions_cloned": 3,
  "cloned_from_dataset_id": 42,
  "note": "..."
}

Schema additions (internal/db/migrate.go)

ALTER TABLE datasets ADD COLUMN IF NOT EXISTS cloned_from_dataset_id INTEGER REFERENCES datasets(id) ON DELETE SET NULL;
ALTER TABLE versions ADD COLUMN IF NOT EXISTS rollback_source_version_id INTEGER;

Model / JSON fields

Field Location Meaning
cloned_from_dataset_id datasets table Registry id of source dataset
rollback_source_version_id versions table / API Version row id used as rollback source
parent_version existing Version number of parent (unchanged)
operation existing Includes rollback alongside filter, clip, etc.

Supported dataset types

Type Clone Rollback Notes
Local vector / raster Yes Yes Version rows reuse file_path (no bulk file copy); GDAL sidecar JSON copied when present
ESRI-imported (local managed) Yes Yes Normalized catalog only; no re-fetch from ArcGIS
GeoServer-imported (local versions) Yes Yes Catalog + versions; GeoServer resources not duplicated
PostGIS-backed Metadata clone Disabled Same connection / schema / table; UI explains logical clone
GeoServer remote catalog Metadata clone Disabled Remote layer reference preserved
Remote S3-only (no local file) Metadata clone Disabled No managed file to restore

Clone behavior

Local managed datasets

When clone_versions is true:

  • New datasets registry row with cloned_from_dataset_id.
  • New version catalog rows (new row ids) pointing at the same on-disk paths as the source.
  • parent_version chains preserved.
  • Per-version metadata JSON under data/metadata/ copied when files exist.

On-disk project folders under /data/projects/{id}/{source}/ are not duplicated.

PostGIS / remote logical clone

  • Registry row + version history (connection, schema, table, URLs).
  • No PostGIS table copy, no GeoServer store/layer duplication, no S3 object copy.
  • Response includes logical_clone: true and a note for the UI.

Rollback behavior

Rollback is not git reset --hard. It behaves like git revert:

  1. User chooses a prior version (e.g. v3) while current is v5.
  2. Server creates v6 with the same file_path as v3 (copy-on-reference).
  3. parent_version = 3, operation = "rollback", rollback_source_version_id = <row id of v3>.
  4. Optional reason stored in version message.
  5. v1–v5 remain in the catalog unchanged.

Rollback errors

Code / case Message
PostGIS Rollback not supported for linked PostGIS datasets.
GeoServer remote Rollback is not available for remote GeoServer catalog datasets.
Remote S3 / no file Rollback requires a managed local file version.
Target is latest Already the current version

Lineage UI

Versions tab

Column Content
Version vN + latest badge
Created Timestamp
Derived from Link to parent version or “Original”
Transformation Filter, Clip, Rollback, Import, Original, etc.
Actions Preview, Publish, Download, View lineage, Rollback, Transform, Delete

Lineage panel

When a dataset has a chain of at least two related versions, a Lineage card shows a simple text timeline (e.g. v1 Importv2 Filter → … → current). No graph rendering.

Server helper

GetVersionLineage(dataset, versionNum) in internal/api/dataset_consistency.go walks parent_version from the selected version to the root. Exposed via GET /versions/{id}/lineage.


Files touched

Area Files
API internal/api/dataset_consistency.go (new)
DB internal/db/migrate.go, versions.go, dataset_lifecycle.go
Models internal/models/models.go
Routes main.go
UI web/dataset.html, web/app.js, web/style.css

Limitations

  1. DATABASE_URL recommended for registry clone provenance (cloned_from_dataset_id) and metadata copy; version catalog clone works in JSON-only mode.
  2. Clone publish configuration — checkbox placeholder only.
  3. On-disk folder names are not renamed on clone (same as rename limitation).
  4. Shared file paths — cloned datasets and rollback versions reference existing files; deleting a shared version row can affect siblings until a future “materialize copy” option exists.
  5. Auth resources — clone registers a new federation resource; no automatic permission copy from source.
  6. Lineage — single-parent chain only; no DAG or workflow canvas (by design).

Quick API reference

Method Path
POST /datasets/{name}/clone
GET /versions/{id}/lineage
POST /versions/{id}/rollback