Skip to content

Architecture

Overall architecture

GeoVault is a monolithic Go HTTP service that combines:

  1. Server-rendered management UI (web/)
  2. JSON REST-style API routes registered in main.go
  3. PostgreSQL metadata + Central authentication
  4. Filesystem dataset versions
  5. Out-of-process GDAL/OGR tooling
  6. HTTP integrations with sibling federation services

There is one listener on :8085. The version catalog is a process-global slice and each save replaces the complete PostgreSQL table or JSON file. There is no application lock around concurrent mutations and no cross-process coordination; safe multi-process writes are therefore unsupported by the reviewed implementation.

flowchart TB
  subgraph ingress
    AP[Apache /geovault]
  end
  subgraph process [GeoVault process]
    MW[Forwarded proto + login + service ACL]
    R[Gorilla Mux routes]
    API[internal/api handlers]
    ST[store.Versions]
    ED[internal/editor]
    MW --> R --> API
    API --> ST
    API --> ED
  end
  AP --> MW
  API --> DB[(Meta PostgreSQL)]
  MW --> AUTH[(Central auth DB)]
  API --> AUTH
  API --> FS[(/data/projects)]
  API --> GDAL[GDAL/OGR CLI]
  API --> EXT[QGIS / TileServer / PostGIS Service / GeoServer / S3 / ESRI]

Major components

Component Package / path Responsibility
Entrypoint main.go Open DB/auth, load catalog, reconcile ACLs, register routes, listen
HTTP API internal/api All JSON/multipart endpoints and HTML-adjacent handlers
Auth adapter internal/authstore Read sessions/users/groups; register resources and manage ACL rows
Shared auth ../shared/auth Cookie/Bearer resolution, middleware, ACL helpers
Metadata DB internal/db Migrations, datasets, folders, connections, GeoServer tables
Version store internal/store Global Versions slice; whole-catalog load/save
Editor internal/editor Row-level edits for OGR files / PostGIS
GeoServer client internal/services/geoserver REST + secret encryption
PostGIS registry internal/postgisregistry Proxy to PostGIS Service
Meta extraction internal/meta GDAL/OGR info → JSON
UI web/ + shared/ui Templates and static assets

Directory layout (runtime data)

Path Purpose
/data/projects/{projectId}/{dataset}/v{N}/ Root-scoped file versions
/data/projects/{projectId}/folders/{folderId}/{dataset}/v{N}/ Folder-scoped file versions
GEOVAULT_VERSIONS_JSON, {GEOVAULT_DATA_DIR}/versions.json, or data/versions.json JSON catalog precedence when no metadata DB
data/metadata/{dataset}_v{N}.json Cached extracted metadata
PostgreSQL tables Registry, jobs, connections, folders (see Database)

The only project initialized by main is in-memory project 1 (Default, type spatial). Project persistence or arbitrary project creation is not implemented in the reviewed schema.

Request flow

sequenceDiagram
  participant C as Client
  participant P as Reverse proxy
  participant G as GeoVault
  participant A as Central auth DB
  participant H as Handler
  C->>P: HTTPS /geovault/...
  P->>G: HTTP :8085 + X-Forwarded-*
  G->>G: ApplyForwardedProto
  G->>A: Resolve acugis_session
  alt unauthenticated browser
    G-->>C: 303 /login?next=...
  else unauthenticated API
    G-->>C: 401
  end
  G->>A: Check service/geovault permission
  G->>H: Route handler
  H->>A: optional geovault_dataset permission
  H-->>C: JSON / file / HTML / redirect

Global middleware order (main.go):

  1. web.ApplyForwardedProto
  2. api.RequireLogin
  3. api.RequireGeoVaultServiceAccess

Service ACL permission selection (geovaultServiceRequiredPermission):

Condition Required permission
/connections*, /api/connections*, /api/database-services* admin
GET /upload or POST paths containing /upload edit
Non-GET/HEAD methods edit
Otherwise view

Many dataset routes additionally require geovault_dataset view, edit, or admin. Administrators bypass these checks. Permission inheritance is admineditview, and the shared provider adds the Public group during checks.

Authentication flow

See Authentication. In short:

  • Primary: Central acugis_session cookie; shared/auth hashes the cookie value and looks it up in dashboard_sessions
  • Secondary attempt: Authorization: Bearer is parsed by shared/auth
  • GeoVault constructs its provider with NewAuthorizationProvider(...) and never calls WithTokens, so it supplies no TokenStore; PAT-only requests are treated as unauthenticated
  • Login/logout routes are not implemented in GeoVault; Central owns them
  • The auth pool is mandatory. It uses GEOVAULT_AUTH_DATABASE_URL, then CENTRAL_DATABASE_URL, then DATABASE_URL

Database interactions

Concern Mechanism
Open metadata db.OpenMeta() on DATABASE_URL; optional
Schema Idempotent SQL in internal/db/migrate.go
Versions Full replace of versions table on save when Meta is set
Auth Separate mandatory pool from authstore.OpenFromEnv()
Remote PostGIS browse/edit Short-lived pools via internal/pgconn (MaxOpenConns=5)

When DATABASE_URL is empty, GeoVault can still start only if one of the two dedicated auth DSNs is set. Version persistence falls back to JSON; metadata-dependent folders, registries, jobs, connections, archive state, and related APIs are unavailable or degraded. Exact status codes vary by handler and should not be generalized.

Background workers

There is no scheduler, cron, or durable worker process.

Work Trigger Execution Persistence
GeoServer publish Publish API or upload sidecar In-process goroutine geoserver_jobs
ESRI import POST /api/esri/import In-process goroutine geoserver_jobs (job_type=esri_import)
QGIS snapshot count enrichment List projects Fan-out goroutines, then wait None
GeoServer remote reconcile Startup Synchronous in main Version catalog
Dataset ACL reconcile Startup Synchronous in main Central resources

No startup code scans and resumes jobs. A restart can leave rows queued or running; retry, deduplication, cancellation, retention, and concurrency limits are not established.

Caching

Kind Present?
Redis / Memcached No
HTTP ETag / explicit API cache policy Not found in reviewed handlers
Metadata JSON files Persistent derived cache of GDAL output
Browser caches sessionStorage / localStorage / in-memory Maps in web/app.js

File storage

  • Uploads and local imports materialize files under /data/projects/...
  • Shapefile ZIPs are validated and extracted in the version directory
  • Remote S3 mode can register a version without a local file (datasource_mode=remote)
  • The registered download handler serves only a non-empty local file_path; remote S3 and live PostGIS versions are not exported by that route
  • Metadata cache paths are keyed only by dataset name and version, not folder ID; collision behavior for same-name datasets in different folders is not resolved by the path format

External integrations

System Configuration Role
Central Auth DSNs Sessions, groups, ACLs
QGIS Publish QGIS_PUBLISH_URL / QGIS_PUBLISH_BASE_URL Raster publish; project list/restore/download proxy
TileServer TILESERVER_REGISTER_URL Vector publish registration
PostGIS Service POSTGIS_SERVICE_URL Discover/adopt/create databases; schemas/tables
GeoServer Per-connection URL + credentials Catalog, publish, styles, workspaces
HTTP(S) Import timeout/size env URL ingest
S3-compatible Per-request credentials Object import or remote registration
ArcGIS Per-request service URL Browse layers; import jobs

Caller cookies are forwarded to some internal services (QGIS Publish, TileServer, PostGIS Service) so the remote service can authorize the user.

GeoVault also directly reads PostGIS Service registry tables (postgis_connections, postgis_databases, postgis_jobs) when they coexist in the metadata database. Those tables are externally owned and are never created by GeoVault. Remote spatial databases are queried through information_schema, PostgreSQL catalogs, and PostGIS geometry_columns; those are not GeoVault schema.

Publish flow

sequenceDiagram
  participant C as Client
  participant G as GeoVault
  participant D as Disk / catalog
  participant T as TileServer
  participant Q as QGIS Publish
  participant S as GeoServer
  C->>G: POST publish
  G->>D: Resolve version and ACL
  alt vector legacy publish
    G->>T: Register local path
    T-->>G: Endpoint
  else raster legacy publish
    G->>Q: Multipart raster + caller auth
    Q-->>G: Project path
  else GeoServer publish
    G->>D: Insert geoserver_jobs row
    G-->>C: Job id
    G-)S: In-process asynchronous REST work
    G->>D: Update job/publication rows
  end

UI composition

Templates parse page HTML plus shared partials (sidebar, shell-head, federation sidebar, PostGIS/GeoServer panels). Static files under ./web/ are served last via http.FileServer. Shared federation shell assets mount at /shared/ui/.