Skip to content

GeoVault folder-first information architecture (Phase 1)

Phase 1 introduces folder/workspace-first organization while keeping existing Vector/Raster pages, import routes, and ingestion handlers unchanged.

Routes added

Method Path Purpose
GET /drive My Drive home — folder cards
GET /workspace Redirect → /drive (legacy)
GET /drive/folders/{id} Folder detail — datasets in folder, Add Dataset menu
GET /api/folders List folders (?archived=only for archived folders)
POST /api/folders Create folder
GET /api/folders/{id} Folder metadata
PUT /api/folders/{id} Rename / update description
POST /api/folders/{id}/archive Archive folder

Routes unchanged (backward compatible)

All legacy paths remain registered, including:

  • /vectors, /rasters, /upload, /import-url, /import-s3, /esri, /discover-postgis
  • /datasets/{name}, /projects, /connections, /geoserver/*
  • POST /projects/{id}/upload, POST /import-url, POST /import-s3, POST /api/esri/import, etc.

Vector and Raster pages now act as filtered views (GET /datasets-summary?type=vector|raster) with subtitles linking back to My Drive.

Schema changes

folders

Column Type Notes
id serial Primary key
name text Unique among non-archived folders (case-insensitive index)
description text Optional
owner_id int FK dashboard_users, optional
group_name text Optional Central auth group name for visibility
created_at timestamp
updated_at timestamp
archived_at timestamp Null = active

Spec referenced group_id; implementation uses group_name (text) to align with Central group membership checks without cross-database FKs.

datasets.folder_id

Nullable FK to folders(id) ON DELETE SET NULL. Set on ingest when folder_id is provided.

Migration behavior

On metadata DB connect (db.OpenMeta):

  1. Schema migration creates folders and datasets.folder_id if missing.
  2. EnsureDefaultFolderMigration runs:
  3. Creates folder "Imported Datasets" if none exists with that name.
  4. Sets folder_id on all datasets where folder_id IS NULL and not archived.

No datasets are deleted; nothing is hidden by migration alone.

Folder-aware ingestion

Pass folder_id (integer) without changing ingest handlers:

Flow How folder_id is passed
Upload Query: POST /projects/1/upload?folder_id={id} or form field folder_id
URL / S3 import JSON body folder_id or query on POST
ESRI import JSON folder_id on POST /api/esri/import (propagated through job payload)
PostGIS register JSON folder_id on POST /api/datasets/register
GeoServer catalog import JSON folder_id on POST /api/geoserver/catalog/import

finalizeLocalFileIngest and UpsertVaultDataset assign folder_id on insert; existing rows keep their folder unless unset (then ingest can set via COALESCE(datasets.folder_id, EXCLUDED.folder_id)).

UI stores active folder in sessionStorage (gv_active_folder_id) and appends ?folder_id= on import navigation from a folder.

Permission inheritance

Folders

  • No new resource type in Central.
  • If group_name is empty: visible to any user with GeoVault service access.
  • If group_name is set: user must belong to that group (admins always allowed).
  • Matches existing group-based patterns (RequireEditors, auth_group_members).

Datasets

  • Unchanged: geovault_dataset ACL (view / edit / admin) still governs dataset cards and ingest authorization.
  • Folder listing does not bypass dataset ACL on folder detail; datasets-summary?folder_id= only returns datasets the user may view.

Federation shell navigation

shared/ui/shell-config.js geovault sections:

  • My Drive — workspace, archive
  • Browse — Vector, Raster (legacy filters)
  • Services — Connections, GeoServer, QGIS Projects

Import entries removed from the global sidebar; imports are reached via Add Dataset inside a folder.

My Drive (/drive) includes Browse (Vector, Raster) and Services (PostGIS, PostGIS Import, QGIS Projects, GeoServer) link rows matching the former workspace hub.

Known limitations (Phase 1)

  • Flat folders only — no nesting.
  • No per-user sharing / invites — group name on folder only.
  • No folder-level Central resources — dataset ACLs remain per dataset.
  • Archive folder does not archive datasets inside it.
  • JSON catalog mode (no DATABASE_URL): folders API and assignment require Postgres metadata.
  • QGIS project files are not placed in folders (still under /projects).
  • Clone/rename do not move datasets between folders yet (folder_id preserved on registry row).
  • internal/db/folders.go, internal/db/migrate.go
  • internal/api/folders.go, internal/api/folder_context.go
  • web/workspace.html, web/folder.html, web/app.js
  • shared/ui/shell-config.js