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:
- 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.
- Lineage UI — derived-from and transformation columns, a textual timeline panel, and per-version View lineage.
- 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_versionsdefaults to on for local managed file datasets, on for logical clones (metadata-only version rows).clone_publish_configis 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
datasetsregistry row withcloned_from_dataset_id. - New version catalog rows (new row ids) pointing at the same on-disk paths as the source.
parent_versionchains 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: trueand anotefor the UI.
Rollback behavior¶
Rollback is not git reset --hard. It behaves like git revert:
- User chooses a prior version (e.g. v3) while current is v5.
- Server creates v6 with the same
file_pathas v3 (copy-on-reference). parent_version = 3,operation = "rollback",rollback_source_version_id = <row id of v3>.- Optional
reasonstored in versionmessage. - 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 Import → v2 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¶
DATABASE_URLrecommended for registry clone provenance (cloned_from_dataset_id) and metadata copy; version catalog clone works in JSON-only mode.- Clone publish configuration — checkbox placeholder only.
- On-disk folder names are not renamed on clone (same as rename limitation).
- 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.
- Auth resources — clone registers a new federation resource; no automatic permission copy from source.
- 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 |