Spatial Product Lifecycle Management
The operational discipline that governs how a geospatial asset is provisioned, versioned, promoted, deprecated, and retired as an autonomous product inside a federated mesh.
Enterprise geospatial operations require a disciplined transition from monolithic GIS repositories to federated, domain-aligned data products. Spatial product lifecycle management establishes the operational framework for provisioning, versioning, routing, and retiring geospatial assets so that every tileset, coverage, and feature collection behaves as a versioned, SLA-bound product rather than a static file drop. This page sits inside the Geospatial Data Mesh Fundamentals reference and assumes you have already separated your estate into autonomous domains as described in Spatial Domain Boundary Design and constrained what each product may publish through Scoping Rules for Spatial Products. Where boundary design answers who owns this geometry and scoping answers what may be published, lifecycle management answers how a product moves safely from experiment to production and back out of service without breaking the consumers who depend on it. The intended readers are data architects, platform engineers, GIS data stewards, and enterprise platform teams who must make those transitions deterministic, observable, and reversible.
Figure — The managed lifecycle of a spatial product; each transition is gated by quality checks and deprecation windows.
Architectural Boundaries & Design Rationale
A spatial product must be treated as an independent domain boundary with explicit ingress and egress controls. The architectural shift moves away from shared enterprise geodatabases and centralized ETL orchestration toward decentralized ownership with standardized interoperability contracts. Lifecycle management is what keeps that decentralization from degenerating into chaos: without managed state transitions, a federated estate accumulates undocumented overwrites, silent projection changes, and orphaned tilesets that consumers still query. The lifecycle states — Experimental, Production, Deprecated, Archived — exist precisely so that every change to a product is an explicit, gated event rather than an in-place mutation.
The failure modes this pattern prevents are concrete. Silent overwrite occurs when a domain republishes the same version with different geometry, so a consumer that pinned v1.2.0 suddenly receives different features; immutable artifact registries close this by rejecting any write to an existing version tag. CRS drift occurs when a product changes projection between releases, so downstream joins that assumed EPSG:4326 misalign by hundreds of metres after an unannounced move to EPSG:3857; encoding the CRS into the version string and validating it at promotion closes this. Dangling consumption occurs when a product is deleted while live traffic still references it; the Deprecated and Archived states with explicit deprecation windows give consumers a bounded migration period instead of an abrupt failure. Cross-domain leakage occurs when a retired product’s compute plane is reused by another domain without re-scoping, which is why retirement must release routing and policy bindings, not just storage.
Platform engineers enforce these boundaries at the API gateway and service mesh layers, ensuring that vector tile requests, raster processing jobs, and metadata queries are routed exclusively to the owning domain’s compute plane. The routing patterns themselves are owned by the Federated Ownership & Routing Architecture reference and detailed in Cross-Domain Routing Strategies; lifecycle management consumes those routes and is responsible only for binding the correct product version to a route and unbinding it cleanly on retirement. Security boundaries are enforced through zero-trust network policies, attribute-based access control (ABAC), and cryptographic signing of spatial payloads, so a product that has transitioned to Deprecated can have its write path revoked while its read path remains available for the deprecation window. The canonical decoupling patterns this section builds on are codified in Spatial Domain Boundary Design, and the rationale for treating datasets as products at all is established in Product Thinking for GIS Datasets.
Specification & Contract Reference
Every lifecycle transition is governed by a declared contract. A product manifest carries the fields below, and the platform admits a transition only when each field validates against the gate for the target state.
Lifecycle states and gates
| State | Meaning | Entry gate | Read access | Write access |
|---|---|---|---|---|
| Experimental | Pre-production, breaking changes allowed | Schema-valid manifest registered | Domain team only | Domain team |
| Production | Stable, SLA-bound, consumer-facing | Quality gates + topology + CRS validation pass | All authorized consumers | CI/CD pipeline only |
| Deprecated | Superseded, read-only, migration window open | Successor version in Production | Existing consumers | None (frozen) |
| Archived | Retired, cold storage, routes released | Deprecation window elapsed, no live traffic | Restore-on-request | None |
Version string grammar
Versioning adheres to semantic conventions extended for geospatial context. A version tag encodes the projection and resolution so that a CRS or resolution change is impossible to ship without an explicit version bump:
v<major>.<minor>.<patch>-crs:<EPSG>-res:<resolution> — for example v1.2.0-crs:EPSG:4326-res:10m or v2.1.0-crs:EPSG:3857-res:0.5m.
| Field | Rule | Failure if violated |
|---|---|---|
major |
Increment on breaking schema or CRS change | Consumers receive incompatible geometry |
minor |
Increment on additive, backward-compatible change | None |
patch |
Increment on metadata or quality fix, geometry unchanged | None |
crs |
Must be one of the domain CRS allowlist (EPSG:4326, EPSG:3857, EPSG:32633) |
Reprojection misalignment downstream |
res |
Must satisfy the resolution limit declared in scoping rules | Bandwidth and classification breaches |
Routing and policy fields
| Field / header | Layer | Purpose |
|---|---|---|
X-Domain-ID |
Gateway | Pins a request to its owning domain’s compute plane |
X-Payload-Signature |
Gateway | Cryptographic signature of the spatial payload, verified per domain key |
productId |
Manifest | Stable identifier across all versions of a product |
processingProvenance.pipelineId |
Manifest | Upstream lineage anchor for catalog reconciliation |
spatialExtent / temporalCadence |
Manifest | Scoping fields; breaking changes require a major bump |
Manifest registration itself flows into the federated catalog described in Metadata Cataloging for Raster/Vector, which is the discovery surface consumers use to find a product version and its current lifecycle state.
Production Implementation
Three runnable artifacts cover the lifecycle: a zero-trust routing policy that pins live traffic to the owning domain, an idempotent manifest registration pipeline that feeds the catalog, and a GitOps promotion workflow that swaps product versions atomically.
Zero-trust routing policy (OPA / Rego)
Implementing ABAC at the gateway requires declarative policy-as-code. The following Open Policy Agent (OPA) Rego policy enforces spatial extent validation and CRS compliance before routing requests to downstream tile servers. The default-deny posture is the zero-trust requirement: a request is rejected unless every condition matches.
package spatial.gateway
import rego.v1
# Default deny — zero-trust posture
default allow = false
# Allow only if the request matches the owning domain's contract
allow if {
input.method == "GET"
input.path = ["tiles", domain, _, _, _, _]
domain == input.headers["X-Domain-ID"]
is_valid_crs(input.query["crs"])
within_spatial_extent(input.query["bounds"], data.domain_extents[domain])
}
is_valid_crs(crs) if {
crs in {"EPSG:4326", "EPSG:3857", "EPSG:32633"}
}
within_spatial_extent(bounds, extent) if {
bbox := split(bounds, ",")
min_x := to_number(bbox[0])
min_y := to_number(bbox[1])
max_x := to_number(bbox[2])
max_y := to_number(bbox[3])
min_x >= extent.min_x
min_y >= extent.min_y
max_x <= extent.max_x
max_y <= extent.max_y
}
Idempotent manifest registration
Metadata registration must be idempotent so that a CI/CD retry never creates catalog drift. The pipeline below validates each manifest against the schema, computes a deterministic content hash, and registers the product only when the hash differs from the catalog state — so re-running it is a no-op:
#!/usr/bin/env bash
set -euo pipefail
MANIFEST_DIR="./spatial-manifests"
SCHEMA_PATH="./schema/spatial-product-manifest.schema.json"
for manifest in "${MANIFEST_DIR}"/*.json; do
# 1. Schema validation (idempotent)
python3 -m jsonschema --instance "${manifest}" "${SCHEMA_PATH}"
# 2. Compute deterministic content hash
HASH=$(sha256sum "${manifest}" | awk '{print $1}')
# 3. Register only if the hash differs from catalog state
PRODUCT_ID=$(jq -r '.productId' "${manifest}")
EXISTING=$(curl -sf "${CATALOG_API}/products/${PRODUCT_ID}/hash" || echo "")
if [ "${EXISTING}" != "${HASH}" ]; then
curl -sf -X POST "${CATALOG_API}/products" \
-H "Content-Type: application/json" \
-d @"${manifest}"
echo "Registered: ${PRODUCT_ID}"
else
echo "Skipped (idempotent): ${PRODUCT_ID}"
fi
done
Atomic promotion and rollback (GitOps)
Promotion pipelines must enforce cryptographic checksums, spatial topology validation, and automated regression testing against baseline extents before a version reaches Production. Immutable artifact registries prevent unauthorized overwrites, while signed releases ensure supply-chain integrity. Leverage Kubernetes-native GitOps controllers to manage spatial tileset promotions so that a version swap is atomic and self-healing:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: spatial-product-urban-landcover
spec:
project: geospatial-mesh
source:
repoURL: https://git.enterprise.internal/spatial-products/urban-landcover.git
targetRevision: v2.1.0-epsg:3857-res:0.5m
path: deploy/overlays/prod
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ApplyOutOfSyncOnly=true
destination:
server: https://kubernetes.default.svc
namespace: spatial-prod
Diagnostic Runbook
When a transition fails, work the following ordered checks; the first matching symptom is usually the root cause.
- Verify policy evaluation. Execute
opa eval -i input.json -d policy.rego "data.spatial.gateway.allow"to confirm the routing decision is deterministic. Afalseresult with a valid request usually means theX-Domain-IDheader was stripped upstream. - Trace mesh propagation. Use
istioctl analyzeor the equivalent service-mesh CLI to validate thatVirtualServiceandDestinationRuleobjects restrict cross-domain egress and that the retired version’s route was actually unbound. - Audit cryptographic signatures. Inspect
X-Payload-Signatureheaders against domain-specific public keys; reject requests with expired timestamps or mismatched CRS claims. - Detect schema and catalog drift. Run
python3 -m jsonschema --instance manifest.json schema.jsonto verify backward compatibility, and reject manifests that changespatialExtentortemporalCadencewithout a major bump. If the catalog returns inconsistent state, compareupdated_attimestamps against pipeline execution logs before forcing a re-register. - Validate topology before promotion. Run
ogrinfo -so -al tileset.gpkgand verify theGeometry TypeandLayer SRS WKTmatch the declared domain CRS. Mixed geometry types or a projection mismatch must block promotion. - Verify rollback. Execute
argocd app rollback spatial-product-urban-landcover --revision <previous-sync-id>and confirm p95 query latency returns to baseline within 90 seconds. - Confirm artifact integrity. Verify Cosign signatures with
cosign verify --key domain-public.pem <image-or-artifact>; an unsigned artifact must trigger immediate pipeline termination.
SLA Targets & Performance Baselines
Spatial products instrument standardized telemetry — tile cache hit ratios, raster processing queue depths, and metadata synchronization latency — codified as Prometheus alerting rules and enforced via admission controllers.
| Metric | Target | Alert threshold | Remediation |
|---|---|---|---|
| Tile availability | 99.95% | < 99.8% (5m) | Auto-scale tile cache nodes |
| Metadata sync latency | < 15 min | > 20 min | Trigger catalog reconciliation job |
| Vector query p95 | < 450 ms | > 600 ms | Optimize spatial indexes, verify CRS alignment |
| Policy evaluation time | < 5 ms | > 15 ms | Audit Rego complexity, cache compiled policies |
| Deprecation window honored | 100% | Any early archival | Halt archival job, restore read route |
To diagnose an SLA breach, correlate spatial_tile_latency_seconds with opa_evaluation_duration_seconds — high latency in both points to a gateway policy misconfiguration. Confirm the declared manifest schema matches the live tile or vector payload via the contract validation pipeline, then apply automated scaling through a Horizontal Pod Autoscaler with custom metrics. If breaches persist beyond 15 minutes, trigger circuit-breaker routing to a fallback static tileset and notify the domain stewards.
Deprecation That Consumers Can Actually Act On
Deprecation is the lifecycle state that most often exists in name only. A product is marked Deprecated, an announcement goes out, a sunset date is set — and on the sunset date half the consumers are still calling it, because nothing in the process ever told them they were consumers. Making deprecation work is less about policy than about knowing who is affected and giving them something specific to do.
The first requirement is that consumers are identified by telemetry, not by a mailing list. Every request to an output port carries a caller identity from the zero-trust layer, so the set of active consumers of a version is a query, not an estimate. That query is what turns “we announced it” into “these eleven services called this version in the last 30 days, and these three still are”. A deprecation whose consumer list is derived from a wiki page is a deprecation that will overrun.
The second is that the sunset window is a function of the consumer’s release cadence, not the producer’s convenience. A consumer that ships weekly can migrate inside a month; one that ships quarterly under change control cannot, and setting a 30-day window for them guarantees either a breach or an emergency extension that teaches everyone that sunset dates are negotiable. Deriving the window from the slowest affected consumer’s cadence — and publishing that derivation — makes the date credible.
| Deprecation element | Weak form | Form that works |
|---|---|---|
| Consumer identification | Announcement to a list | Query over caller identity in access telemetry |
| Sunset window | Fixed 90 days for everything | Two cycles of the slowest affected consumer |
| Migration target | “Use the new version” | Named successor version, with a diff |
| Progress signal | Nothing until the date | Per-consumer call volume against the deadline |
| Enforcement | Turn it off | Escalating: warning header, then throttle, then error |
| Rollback | None | Successor stays parallel until the last caller moves |
The third requirement is graduated enforcement, because a hard cutover concentrates all risk into one moment. The sequence that works starts with a deprecation header on every response, so a consumer that reads its own logs finds out without being told; moves to deliberate, well-labelled throttling that makes the deprecation impossible to ignore but does not break anything; and only then returns an error. Each stage is announced and each is reversible, so a consumer who genuinely cannot move has a visible opportunity to say so before the outage rather than during it.
Finally, deprecation must name a successor with a diff. “Migrate to v2” is not actionable; “v2 renames parcel_id to parcel_ref, adds a required survey_date, and changes the storage CRS from EPSG:32633 to EPSG:4326” is a work item a consumer can estimate. Where the successor’s contract has been generated from a structural diff of the two versions, that list already exists — publishing it is the cheapest thing a producer can do to make a deprecation land on time.
One organisational note: deprecation only works when the producing domain is not the only party with an interest in it finishing. Where a successor version exists but consumers have no deadline pressure, migration reliably stalls at eighty percent, and the producer is left maintaining two versions indefinitely. Publishing the per-consumer migration progress somewhere both sides can see it — call volume against the deadline, by caller identity — turns a producer’s request into a shared, visible commitment, which is generally enough without any escalation at all.
Governance & Compliance Notes
Lifecycle transitions are governance events and must leave an audit trail. Every promotion, deprecation, and archival should emit an immutable record capturing the actor, the source and target version strings, the CRS and resolution, and the Cosign signature digest, so a product’s full provenance is reconstructable from the catalog alone. Policy-as-code hooks run at two points: the admission controller blocks any transition whose manifest fails schema or topology validation, and the gateway Rego policy blocks any read that falls outside the product’s declared extent or CRS allowlist. Both hooks reference the same scoping contract, which keeps governance consistent between publication time and query time.
Jurisdictional constraints frequently shape archival and deletion. A product carrying regulated spatial data — cadastral boundaries, critical-infrastructure footprints, or personally locating telemetry — may have a minimum retention period that prevents early archival, or a data-residency rule that forbids restoring an archived artifact into a different region’s compute plane. Encode these as policy fields on the manifest so the lifecycle controller enforces them automatically rather than relying on operator discipline. For authoritative interoperability standards consult the OGC API - Features specification, and for policy-as-code implementation patterns reference the Open Policy Agent Documentation.
Related
- Up: Geospatial Data Mesh Fundamentals — the parent reference for this architecture
- Spatial Domain Boundary Design — decoupling spatial domains the lifecycle binds versions to
- Scoping Rules for Spatial Products — the publication gates a transition must clear
- Metadata Cataloging for Raster/Vector — the federated catalog that records lifecycle state
- Product Thinking for GIS Datasets — why spatial assets are managed as products