fix(platform): govern geospatial analysis and raster handoffs
This commit is contained in:
+114
-23
@@ -13,8 +13,8 @@ This document freezes the first API shape. Codex may add implementation details
|
||||
uses the canonical `{"data": ...}` envelope. Readiness runs an OpenAPI audit
|
||||
that rejects free-form dictionary responses and envelope drift.
|
||||
- The only successful non-envelope responses are `/health`, `/health/live`,
|
||||
`/health/ready`, the four documented persisted-raster PNG endpoints and the
|
||||
export artifact download endpoint.
|
||||
`/health/ready`, the two documented Authentik redirects, the documented
|
||||
persisted-raster PNG endpoints and the export artifact download endpoint.
|
||||
|
||||
## Shared schemas
|
||||
|
||||
@@ -63,7 +63,7 @@ one client/username combination within five minutes temporarily return HTTP
|
||||
|
||||
Optional guest access is a configuration-gated demonstration mode. It creates
|
||||
a shorter signed session with role `guest`, scopes that session to the
|
||||
idempotently seeded demo project and blocks mutating operator routes. Project
|
||||
idempotently seeded demo project and blocks administrative operator routes. Project
|
||||
listing is filtered to the bound demo project. The frontend exposes the same
|
||||
exploration, assistant, model-selection, analysis, QA and export workspaces as
|
||||
an operator. Model catalogs are globally readable; every run, result and export
|
||||
@@ -73,13 +73,33 @@ administrative mutations remain unavailable. This is deliberately **not**
|
||||
a substitute for user accounts, authorization or tenant isolation; expose it
|
||||
only on a dedicated demo installation without private or operational data.
|
||||
|
||||
The functional demo boundary includes bounded, project-path-scoped official
|
||||
source acquisition, persisted bbox selections, temporal comparisons and change
|
||||
detection. Change detection resolves the source dataset first, requires its
|
||||
project to equal the signed guest-project UUID and validates the target dataset
|
||||
against that same project before the synchronous job starts. Cross-project
|
||||
datasets therefore fail before comparison. Generic uploads, arbitrary
|
||||
clip/buffer/intersect operations, forceful project management and evidence
|
||||
adjudication remain blocked.
|
||||
|
||||
The login/demo seed remains offline and retains its synthetic raster as an
|
||||
explicit `fixture` for UI context and fixture QA only. That raster is excluded
|
||||
from configured detection and segmentation selectors and the production
|
||||
consumption gate continues to reject it. A guest starts real model inference
|
||||
by drawing a bounded map selection; GeoIntel then acquires an official regional
|
||||
orthophoto on demand inside the signed demo project, persists its contextual
|
||||
source registry/snapshot/checksum evidence, and only then tiles and runs the
|
||||
configured model. No network acquisition occurs merely by logging in.
|
||||
|
||||
### GET `/api/v1/auth/session`
|
||||
|
||||
Public session probe used by the frontend before it mounts the workbench.
|
||||
When authentication is disabled, `authenticated` is true and
|
||||
`authentication_required` is false so local development retains its existing
|
||||
direct workflow. `guest_access_enabled` tells the landing page whether it may
|
||||
show the guest action.
|
||||
show the guest action. `authentik_enabled` indicates that the additive
|
||||
Authentik operator flow is fully configured; the local operator login remains
|
||||
available as a recovery path.
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -90,6 +110,7 @@ show the guest action.
|
||||
"expires_at": null,
|
||||
"role": null,
|
||||
"guest_access_enabled": true,
|
||||
"authentik_enabled": false,
|
||||
"guest_project_id": null
|
||||
}
|
||||
}
|
||||
@@ -112,6 +133,23 @@ Successful login sets the session cookie and returns the authenticated session
|
||||
shape. Invalid credentials return HTTP 401 `INVALID_CREDENTIALS`; username
|
||||
existence is not disclosed.
|
||||
|
||||
### GET `/api/v1/auth/authentik/start`
|
||||
|
||||
Starts an authorization-code OIDC flow with PKCE, signed state and nonce when
|
||||
all Authentik settings are present. Discovery, token and JWKS requests are
|
||||
restricted to the configured HTTPS issuer origin, reject redirects and enforce
|
||||
a bounded JSON response size. The flow cookie is HttpOnly, Secure, ten minutes
|
||||
or less and scoped to the Authentik callback path.
|
||||
|
||||
### GET `/api/v1/auth/authentik/callback`
|
||||
|
||||
Validates issuer, audience, signature, expiry, state, nonce and the exact
|
||||
configured verified e-mail address. Success creates the same operator session
|
||||
as local login and clears the one-use flow cookie. Failure clears that cookie
|
||||
and redirects to the landing page with a generic error marker; token or
|
||||
identity details are never returned to the browser. These two redirect routes
|
||||
are the only additional non-envelope authentication responses.
|
||||
|
||||
### POST `/api/v1/auth/guest`
|
||||
|
||||
No request body is required. The endpoint is available only when both
|
||||
@@ -130,6 +168,12 @@ is available for that bound demo project. Unscoped analysis routes require the
|
||||
same UUID as a `project_id` query parameter; cross-project values fail before
|
||||
route execution. Coverage resolution additionally verifies the `project_id` in
|
||||
the request body against the guest-session scope.
|
||||
Raster tiling for an already-persisted raster in the bound demo project is an
|
||||
explicitly allowed preparation step for detection and segmentation. It creates
|
||||
only integrity-bound inference tiles and a job record; uploads, source
|
||||
acquisition, model management and arbitrary derived-dataset writes remain
|
||||
operator-only. Guest tiling is server-capped by the configured inference tile
|
||||
limit before any tile bytes are written.
|
||||
|
||||
### POST `/api/v1/auth/logout`
|
||||
|
||||
@@ -286,11 +330,13 @@ Request:
|
||||
|
||||
Backend responsibilities:
|
||||
|
||||
- Validate geometry.
|
||||
- Repair trivial polygon issues if safe.
|
||||
- Store geometry in PostGIS.
|
||||
- Calculate area in square meters using projected CRS.
|
||||
- Store bbox.
|
||||
- Accept only a finite, valid `Polygon` or `MultiPolygon` in the declared CRS.
|
||||
- Reject unknown/non-2D CRS definitions and geometry outside the Belgium and
|
||||
Belgian North Sea workbench domain.
|
||||
- Transform the geometry to EPSG:4326 before PostGIS persistence while
|
||||
retaining the exact declared CRS in `original_crs`.
|
||||
- Calculate `area_m2` in Belgian Lambert 72 (`EPSG:31370`) and derive the
|
||||
persisted EPSG:4326 bbox from the normalized geometry.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/areas/{area_id}`
|
||||
|
||||
@@ -299,8 +345,12 @@ area list endpoint and includes persisted GeoJSON geometry for map display.
|
||||
|
||||
### PATCH `/api/v1/projects/{project_id}/areas/{area_id}`
|
||||
|
||||
Updates the area name and/or geometry. Geometry updates follow the same
|
||||
validation, repair and metric-calculation rules as area creation.
|
||||
Updates the area name and/or geometry. A replacement geometry follows the same
|
||||
strict CRS validation, EPSG:4326 normalization and metric-calculation rules as
|
||||
area creation and atomically recomputes `geometry`, `bbox`, `area_m2` and
|
||||
`original_crs`. A PATCH containing `crs` without `geometry` fails with
|
||||
`INVALID_AREA_CRS_UPDATE`; omitted CRS on replacement geometry means
|
||||
EPSG:4326.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/areas/municipalities`
|
||||
|
||||
@@ -409,10 +459,22 @@ validation report/status, provenance/lineage status, quarantine status and an
|
||||
idempotent ingest key. A malformed or doubtful artifact is retained as
|
||||
`status=quarantined`; it is not silently discarded or made ready.
|
||||
|
||||
Vector uploads remain stored as original files and are also persisted into
|
||||
`vector_features` as queryable PostGIS state only after their contract passes.
|
||||
Non-EPSG:4326 vector coordinates are explicitly transformed before canonical
|
||||
feature persistence; relabelling Lambert coordinates as EPSG:4326 is rejected.
|
||||
The backend streams uploads to governed storage in bounded 8 MiB reads while
|
||||
calculating size and SHA-256. `GEOINTEL_MAX_UPLOAD_MB` (legacy alias
|
||||
`MAX_UPLOAD_MB`, default 500, allowed range 1–2,048) is enforced by the backend even when a request
|
||||
bypasses the reverse proxy. The first byte beyond the configured limit aborts
|
||||
the ingest, removes the partial file and returns HTTP 413 with
|
||||
`UPLOAD_TOO_LARGE`. Because GeoJSON validation currently requires an in-memory
|
||||
parse, vector uploads have the additional lower
|
||||
`GEOINTEL_MAX_IN_MEMORY_VECTOR_MB` limit (default 64 MiB, maximum 256 MiB).
|
||||
This limit is enforced during streaming and again with a bounded read before
|
||||
parsing; larger vector sources must use a governed batch-import workflow.
|
||||
|
||||
Vector uploads are also persisted into `vector_features` as queryable PostGIS
|
||||
state only after their contract passes. Non-EPSG:4326 source bytes are retained
|
||||
as provenance evidence while the normal Dataset `storage_path` points to the
|
||||
deterministic EPSG:4326 artifact. Relabelling Lambert coordinates as EPSG:4326
|
||||
is rejected.
|
||||
|
||||
### GET `/api/v1/source-registry`
|
||||
|
||||
@@ -1053,7 +1115,13 @@ Failure modes:
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/tile`
|
||||
|
||||
Generate raster tiles and a manifest for downstream processing. Returns a job payload with `tile_set_id` and manifest metadata.
|
||||
Generate raster tiles and a versioned manifest for downstream processing.
|
||||
Returns a job payload with `tile_set_id` and manifest metadata. Contract
|
||||
`geointel.raster.tile-manifest@2.0.0` binds the tile set to the exact source
|
||||
Dataset, DatasetVersion, source registry/snapshot and checksum values that are
|
||||
available in persistence, plus the source Area and Area-geometry checksum when
|
||||
scoped. Every tile records immutable byte size/SHA-256, explicit CRS and bounds;
|
||||
the manifest records its source extent and tile count.
|
||||
|
||||
If raster processing dependencies are unavailable:
|
||||
|
||||
@@ -1594,13 +1662,16 @@ label or model filename.
|
||||
|
||||
### GET `/api/v1/detection/model-assets`
|
||||
|
||||
Returns governed local runtime model files. This is a read-only catalog.
|
||||
Returns configured local runtime model files. This is a read-only catalog;
|
||||
catalog visibility establishes byte identity and runtime availability only.
|
||||
GeoIntel never downloads, creates, mutates or deletes model weights from this
|
||||
endpoint.
|
||||
|
||||
The backend scans `YOLO_MODELS_DIR` (default `/app/models`). When
|
||||
`YOLO_MODEL_PATH` resolves to an existing file, production catalog output is
|
||||
restricted to that explicitly approved active model. When no active model is
|
||||
restricted to that active runtime model. Active/available is a runtime-selection
|
||||
state only: it does not assert governed validation, human review, national
|
||||
coverage or promotion. When no active model is
|
||||
configured, supported `.pt`, `.onnx` and `.engine` files remain visible for
|
||||
development/operator discovery but cannot make the configured detector ready.
|
||||
|
||||
@@ -1620,8 +1691,12 @@ Response data:
|
||||
"size_bytes": 123456,
|
||||
"sha256": "sha256hex",
|
||||
"active": true,
|
||||
"status": "approved",
|
||||
"limitation_message": "Approved local runtime model asset. GeoIntel will not download or mutate model weights.",
|
||||
"runtime_available": true,
|
||||
"runtime_status": "active",
|
||||
"governed_validation_status": "not_verified_by_catalog",
|
||||
"promotion_status": "not_verified_by_catalog",
|
||||
"status": "runtime_active",
|
||||
"limitation_message": "Active local runtime model asset. Runtime selection is not evidence of governed validation or promotion.",
|
||||
"will_download_models": false
|
||||
}
|
||||
],
|
||||
@@ -1732,10 +1807,21 @@ governed, runtime-produced artifact the persistence model requires. Rejection is
|
||||
`STORAGE_PATH_OUTSIDE_ROOT`; `GEOINTEL_ALLOW_EXTERNAL_ARTIFACT_PATHS` opts out
|
||||
for provisioning workflows that stage tiles before ingest.
|
||||
|
||||
Configured detection and segmentation revalidate the v2 contract before model
|
||||
loading. The requested Dataset identity, checksum, latest DatasetVersion,
|
||||
source snapshot and Area binding must still match; every tile checksum is
|
||||
recomputed; and the EPSG:4326 tile union must remain inside both the declared
|
||||
manifest extent and persisted raster extent and intersect its Area where one is
|
||||
bound. Validation fails closed with the typed suffixes
|
||||
`TILE_MANIFEST_DATASET_MISMATCH`, `TILE_MANIFEST_PROVENANCE_MISMATCH`,
|
||||
`TILE_MANIFEST_TILE_INTEGRITY_MISMATCH` or
|
||||
`TILE_MANIFEST_SCOPE_MISMATCH`, prefixed with `DETECTION_` or
|
||||
`SEGMENTATION_` for the requesting task.
|
||||
|
||||
The manifest must carry explicit CRS metadata (`crs`, `source_crs` or
|
||||
`dataset_crs`). A manifest without it fails with
|
||||
`DETECTION_TILE_MANIFEST_INVALID` rather than being georeferenced against an
|
||||
assumed EPSG:4326, which would place detections plausibly but wrongly.
|
||||
`dataset_crs`). A manifest without it fails rather than being georeferenced
|
||||
against an assumed EPSG:4326, which would place detections plausibly but
|
||||
wrongly.
|
||||
|
||||
Tiles are read with rasterio: the visible RGB bands are selected explicitly and
|
||||
percentile-stretched to 8-bit, so 16-bit and 4-band (RGB + NIR) orthophotos
|
||||
@@ -2095,6 +2181,11 @@ to the synchronous route. A configured model requires an existing
|
||||
`SEGMENTATION_ACCELERATOR_MISCONFIGURED` when CUDA is required. A valid
|
||||
zero-polygon run is shown as an empty model result, never as proof that the AOI
|
||||
contains no relevant objects.
|
||||
When a raster is selected but no manifest exists, the normal frontend flow
|
||||
first requests project-scoped 512 px tiles with 64 px overlap and forwards the
|
||||
server-generated manifest. Inference then applies the complete v2 provenance,
|
||||
integrity and scope validation before model load; manual server-path entry is
|
||||
an operator-only advanced control.
|
||||
|
||||
Validation errors:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user