Initial GeoIntel V1 foundation
This commit is contained in:
@@ -0,0 +1,972 @@
|
||||
# API Contracts v1
|
||||
|
||||
This document freezes the first API shape. Codex may add implementation details but must not rename these routes without updating this file and the frontend API client.
|
||||
|
||||
## API principles
|
||||
|
||||
- Base path: `/api/v1`.
|
||||
- JSON by default.
|
||||
- GeoJSON accepted for geometries where possible.
|
||||
- Long processing tasks return a job or analysis run record instead of blocking.
|
||||
- Error responses use the shared `ApiError` schema.
|
||||
|
||||
## Shared schemas
|
||||
|
||||
### ApiError
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "string",
|
||||
"message": "human readable message",
|
||||
"details": {},
|
||||
"request_id": "optional string"
|
||||
}
|
||||
```
|
||||
|
||||
### GeoJsonGeometry
|
||||
|
||||
Any valid GeoJSON geometry object. V1 primarily expects `Polygon` and `MultiPolygon` for areas.
|
||||
|
||||
### BoundingBox
|
||||
|
||||
```json
|
||||
{
|
||||
"min_x": 0.0,
|
||||
"min_y": 0.0,
|
||||
"max_x": 0.0,
|
||||
"max_y": 0.0,
|
||||
"crs": "EPSG:4326"
|
||||
}
|
||||
```
|
||||
|
||||
## Health
|
||||
|
||||
### GET `/health`
|
||||
|
||||
Returns service status.
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"service": "geointel-backend",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
```
|
||||
|
||||
### GET `/api/v1/system/capabilities`
|
||||
|
||||
Returns enabled feature flags and tool availability.
|
||||
|
||||
```json
|
||||
{
|
||||
"postgis": true,
|
||||
"rasterio": true,
|
||||
"geopandas": true,
|
||||
"yolo": false,
|
||||
"sam": false,
|
||||
"grb": "planned",
|
||||
"sentinel": "planned",
|
||||
"providers": [
|
||||
{
|
||||
"provider_name": "grb",
|
||||
"display_name": "GRB",
|
||||
"authority_level": "authoritative",
|
||||
"supported_layers": ["buildings", "roads", "parcels"],
|
||||
"supported_geometry_types": ["Polygon", "MultiPolygon", "LineString", "MultiLineString"],
|
||||
"supported_query_modes": ["area"],
|
||||
"fetch_signature": "POST /api/v1/external/grb/fetch",
|
||||
"configured": false,
|
||||
"status": "not_configured",
|
||||
"limitation_message": "GRB live WFS/download integration is not configured in Sprint 7B.",
|
||||
"attribution": "Digitaal Vlaanderen - Basiskaart Vlaanderen (GRB)",
|
||||
"license_note": "Use must follow Digitaal Vlaanderen open data and attribution terms.",
|
||||
"not_configured_reason": "Provider integration is not configured yet"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Projects
|
||||
|
||||
### GET `/api/v1/projects`
|
||||
|
||||
Returns all projects.
|
||||
|
||||
### POST `/api/v1/projects`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Geel building detection demo",
|
||||
"description": "Detect buildings and validate against GRB",
|
||||
"region": "Kempen"
|
||||
}
|
||||
```
|
||||
|
||||
Response: `ProjectRead`.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}`
|
||||
|
||||
Returns one project with summary counts.
|
||||
|
||||
### PATCH `/api/v1/projects/{project_id}`
|
||||
|
||||
Updates name/description/region.
|
||||
|
||||
### DELETE `/api/v1/projects/{project_id}`
|
||||
|
||||
Soft-delete in V1 preferred. Hard-delete only if storage cleanup is also implemented.
|
||||
|
||||
## Areas
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/areas`
|
||||
|
||||
Returns areas for a project.
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/areas`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Geel Centrum AOI",
|
||||
"geometry": {"type": "Polygon", "coordinates": []},
|
||||
"crs": "EPSG:4326"
|
||||
}
|
||||
```
|
||||
|
||||
Backend responsibilities:
|
||||
|
||||
- Validate geometry.
|
||||
- Repair trivial polygon issues if safe.
|
||||
- Store geometry in PostGIS.
|
||||
- Calculate area in square meters using projected CRS.
|
||||
- Store bbox.
|
||||
|
||||
## Datasets
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/upload`
|
||||
|
||||
Multipart upload.
|
||||
|
||||
Fields:
|
||||
|
||||
- `file`: dataset file.
|
||||
- `dataset_type`: `vector`, `geojson` (legacy), `raster`.
|
||||
- `source`: free text, e.g. `user_upload`, `grb`, `osm`.
|
||||
- `dataset_role`: `source`, `derived`, or `reference` (default `source`).
|
||||
- `source_name`: optional source identity, e.g. `manual`, `grb`, `osm`; reference uploads default to `manual` when omitted.
|
||||
- `reference_layer_name`: optional reference layer label, e.g. `buildings`; only retained for reference datasets.
|
||||
- `area_id`: optional.
|
||||
|
||||
Response: `DatasetRead` with extracted metadata if supported.
|
||||
|
||||
Vector uploads remain stored as original files and are also persisted into `vector_features` as queryable PostGIS state.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/datasets`
|
||||
|
||||
List datasets.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/datasets/{dataset_id}`
|
||||
|
||||
Return metadata.
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/metadata/refresh`
|
||||
|
||||
Re-extract metadata.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/datasets/{dataset_id}/vector/inspect`
|
||||
|
||||
Return a wrapped vector inspection payload with metadata, storage summary and feature summary.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/datasets/{dataset_id}/vector/summary`
|
||||
|
||||
Return vector summary data only.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/metadata`
|
||||
|
||||
Return raster metadata profile for supported raster uploads.
|
||||
|
||||
If raster processing is unavailable:
|
||||
|
||||
```text
|
||||
code: RASTER_PROCESSING_UNAVAILABLE
|
||||
message: Raster processing unavailable. Install rasterio and GDAL-compatible drivers to enable raster metadata extraction.
|
||||
```
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/inspect`
|
||||
|
||||
Return raster inspect wrapper payload.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/stats`
|
||||
|
||||
Return raster band statistics payload.
|
||||
|
||||
If raster processing dependencies are unavailable:
|
||||
|
||||
- code: `RASTER_PROCESSING_UNAVAILABLE`
|
||||
- message: dependency-specific unavailable message.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/preview`
|
||||
|
||||
Preview readiness for raster layers.
|
||||
|
||||
If preview dependencies are unavailable:
|
||||
|
||||
- code: `RASTER_PROCESSING_UNAVAILABLE`
|
||||
- message: `Raster preview unavailable...`
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/clip`
|
||||
|
||||
Clip raster by selected area. Returns a `202`-style accepted job payload through the job wrapper (`jobs` create/read flow).
|
||||
|
||||
If raster processing dependencies are unavailable:
|
||||
|
||||
- code: `RASTER_PROCESSING_UNAVAILABLE`
|
||||
- message: `Raster processing unavailable. Install rasterio and GDAL-compatible drivers to enable raster processing operations.`
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/reproject`
|
||||
|
||||
Reproject raster dataset to another CRS.
|
||||
|
||||
Input:
|
||||
|
||||
- `target_crs` (default: `EPSG:31370`)
|
||||
- `resampling` (`nearest`, `bilinear`, `cubic`; default `nearest`)
|
||||
- `output_name`
|
||||
|
||||
Returns a job payload with derived dataset id in `result.output_dataset_id`.
|
||||
|
||||
Failure modes:
|
||||
|
||||
- code: `INVALID_PARAMETERS` for bad CRS or resampling
|
||||
- code: `INVALID_DATASET_CRS` when source raster CRS is missing
|
||||
- code: `RASTER_PROCESSING_UNAVAILABLE` when rasterio is unavailable
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/indices/ndvi`
|
||||
|
||||
Compute NDVI from raster band pairs.
|
||||
|
||||
Input:
|
||||
|
||||
- `nir_band` (positive integer, 1-based)
|
||||
- `red_band` (positive integer, 1-based)
|
||||
- `output_name` (optional)
|
||||
|
||||
Returns a job payload with derived dataset id in `result.output_dataset_id`.
|
||||
|
||||
Failure modes:
|
||||
|
||||
- code: `INVALID_PARAMETERS` for non-positive/non-integer band indices
|
||||
- code: `INVALID_PARAMETERS` for band index outside source band count
|
||||
- code: `INVALID_DATASET_TYPE` when source is not raster
|
||||
- code: `RASTER_PROCESSING_UNAVAILABLE` when rasterio or numpy is unavailable
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/indices/ndwi`
|
||||
|
||||
Compute NDWI from raster band pairs.
|
||||
|
||||
Input:
|
||||
|
||||
- `nir_band` (positive integer, 1-based)
|
||||
- `green_band` (positive integer, 1-based)
|
||||
- `output_name` (optional)
|
||||
|
||||
Returns a job payload with derived dataset id in `result.output_dataset_id`.
|
||||
|
||||
Failure modes:
|
||||
|
||||
- code: `INVALID_PARAMETERS` for non-positive/non-integer band indices
|
||||
- code: `INVALID_PARAMETERS` for band index outside source band count
|
||||
- code: `INVALID_DATASET_TYPE` when source is not raster
|
||||
- code: `RASTER_PROCESSING_UNAVAILABLE` when rasterio or numpy is unavailable
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/raster/indices/ndbi`
|
||||
|
||||
Compute NDBI from raster band pairs.
|
||||
|
||||
Input:
|
||||
|
||||
- `nir_band` (positive integer, 1-based)
|
||||
- `swir_band` (positive integer, 1-based)
|
||||
- `output_name` (optional)
|
||||
|
||||
Returns a job payload with derived dataset id in `result.output_dataset_id`.
|
||||
|
||||
Failure modes:
|
||||
|
||||
- code: `INVALID_PARAMETERS` for non-positive/non-integer band indices
|
||||
- code: `INVALID_PARAMETERS` for band index outside source band count
|
||||
- code: `INVALID_DATASET_TYPE` when source is not raster
|
||||
- code: `RASTER_PROCESSING_UNAVAILABLE` when rasterio or numpy is unavailable
|
||||
|
||||
### 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.
|
||||
|
||||
If raster processing dependencies are unavailable:
|
||||
|
||||
- code: `RASTER_PROCESSING_UNAVAILABLE`
|
||||
- message: `Raster processing unavailable. Install rasterio and GDAL-compatible drivers to enable raster processing operations.`
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/vector/clip`
|
||||
|
||||
Clip vector dataset to selected area.
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/vector/buffer`
|
||||
|
||||
Apply buffer distance to vector features.
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/vector/intersect`
|
||||
|
||||
Intersect source vector dataset with another vector dataset.
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/datasets/{dataset_id}/vector/stats`
|
||||
|
||||
Return vector stats (feature counts and geometry summary).
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/datasets/{dataset_id}/vector/bbox`
|
||||
|
||||
Return vector bounds and feature count.
|
||||
|
||||
## Jobs
|
||||
|
||||
### POST `/api/v1/projects/{project_id}/jobs`
|
||||
|
||||
Create a job.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/jobs`
|
||||
|
||||
List jobs.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/jobs/{job_id}`
|
||||
|
||||
Read job detail.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/jobs/{job_id}/status`
|
||||
|
||||
Read simplified job status payload.
|
||||
|
||||
## Provider registry
|
||||
|
||||
### GET `/api/v1/external/providers`
|
||||
|
||||
Returns all configured provider capability descriptors.
|
||||
|
||||
### GET `/api/v1/external/providers/capabilities`
|
||||
|
||||
Compatibility alias for listing provider capability descriptors.
|
||||
|
||||
### GET `/api/v1/external/providers/{provider_name}`
|
||||
|
||||
Returns one provider capability descriptor.
|
||||
|
||||
### GET `/api/v1/external/providers/{provider_name}/layers`
|
||||
|
||||
Returns the supported provider layers.
|
||||
|
||||
### GET `/api/v1/external/providers/{provider_name}/status`
|
||||
|
||||
Returns configured/status/limitation fields.
|
||||
|
||||
### POST `/api/v1/external/providers/{provider_name}/import`
|
||||
|
||||
Defines the future provider import contract. Sprint 7B does not perform live imports or write datasets.
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id": "uuid-or-local-id",
|
||||
"area_id": "optional uuid-or-local-id",
|
||||
"layers": ["buildings"],
|
||||
"dataset_role": "optional source|reference"
|
||||
}
|
||||
```
|
||||
|
||||
GRB/OSM response:
|
||||
|
||||
```json
|
||||
{
|
||||
"provider_name": "grb",
|
||||
"status": "not_configured",
|
||||
"message": "No live GRB import is configured in Sprint 7B.",
|
||||
"requested_layers": ["buildings"],
|
||||
"dataset_id": null,
|
||||
"dataset_role": "reference",
|
||||
"source_name": "grb"
|
||||
}
|
||||
```
|
||||
|
||||
Manual and fixture providers point callers to existing upload/fixture flows. No provider writes directly to `vector_features`; all future provider output must flow through `DatasetService` and `VectorFeatureService`.
|
||||
|
||||
## External data fetchers
|
||||
|
||||
### POST `/api/v1/external/osm/fetch`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id": "uuid",
|
||||
"area_id": "uuid",
|
||||
"layers": ["buildings", "roads", "water", "green"]
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/v1/external/grb/fetch`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id": "uuid",
|
||||
"area_id": "uuid",
|
||||
"layers": ["buildings"]
|
||||
}
|
||||
```
|
||||
|
||||
V1 may initially implement this as a service interface with a clear `not_configured` response until the exact WFS endpoint is wired.
|
||||
|
||||
Sprint 7B provider contract responses expose capabilities only. Providers must report:
|
||||
|
||||
```json
|
||||
{
|
||||
"provider_name": "osm",
|
||||
"display_name": "OpenStreetMap",
|
||||
"authority_level": "contextual",
|
||||
"supported_layers": ["buildings", "roads", "water", "landuse"],
|
||||
"supported_geometry_types": ["Polygon", "MultiPolygon", "LineString", "MultiLineString"],
|
||||
"supported_query_modes": ["area"],
|
||||
"configured": false,
|
||||
"status": "not_configured",
|
||||
"limitation_message": "OSM live Overpass/download integration is not configured in Sprint 7B.",
|
||||
"attribution": "OpenStreetMap contributors",
|
||||
"license_note": "OpenStreetMap data is available under ODbL; attribution is required."
|
||||
}
|
||||
```
|
||||
|
||||
No GRB WFS, OSM Overpass or provider downloads are implemented in Sprint 7B.
|
||||
|
||||
## Demo workflow
|
||||
|
||||
### POST `/api/v1/demo/workflow`
|
||||
|
||||
Seeds an explicit offline demo workflow from local fixture files. This endpoint
|
||||
does not fetch live GRB/OSM data and does not run AI inference. It creates or
|
||||
returns:
|
||||
|
||||
- one demo project
|
||||
- one demo AOI
|
||||
- one fixture reference building dataset
|
||||
- one fixture candidate/predicted building dataset
|
||||
- one persisted QA/QC result with metric rows
|
||||
|
||||
The endpoint is idempotent for the named demo project.
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id": "uuid",
|
||||
"area_id": "uuid",
|
||||
"reference_dataset_id": "uuid",
|
||||
"candidate_dataset_id": "uuid",
|
||||
"quality_check_id": "uuid",
|
||||
"metric_count": 6,
|
||||
"status": "ready",
|
||||
"message": "Demo workflow seeded from explicit local fixtures.",
|
||||
"created": true
|
||||
}
|
||||
```
|
||||
|
||||
## Analysis
|
||||
|
||||
## Detection Lab
|
||||
|
||||
Sprint 8 implements Detection Lab foundation only. YOLO/PyTorch real inference is not enabled, no model is downloaded, and fixture detections require explicit fixture mode.
|
||||
|
||||
### GET `/api/v1/detection/models`
|
||||
|
||||
Returns object-detection model capability descriptors.
|
||||
|
||||
```json
|
||||
{
|
||||
"models": [
|
||||
{
|
||||
"model_id": "yolo-placeholder",
|
||||
"display_name": "YOLO detector placeholder",
|
||||
"framework": "ultralytics/pytorch",
|
||||
"task_type": "object_detection",
|
||||
"supported_classes": ["building", "road", "water", "landuse"],
|
||||
"configured": false,
|
||||
"status": "not_configured",
|
||||
"limitation_message": "YOLO/PyTorch inference is not configured in Sprint 8; no model is downloaded or executed.",
|
||||
"version": null
|
||||
},
|
||||
{
|
||||
"model_id": "yolo-configured",
|
||||
"display_name": "Configured YOLO detector",
|
||||
"framework": "ultralytics/pytorch",
|
||||
"task_type": "object_detection",
|
||||
"supported_classes": ["building", "road", "water", "landuse"],
|
||||
"configured": false,
|
||||
"status": "not_configured",
|
||||
"limitation_message": "YOLO is disabled. Set YOLO_ENABLED=true and YOLO_MODEL_PATH to a local model file to enable inference.",
|
||||
"version": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### POST `/api/v1/detection/run`
|
||||
|
||||
Creates a detection job and detection analysis run. If the requested model is unavailable, the job and analysis run are marked `failed` with `DETECTION_MODEL_UNAVAILABLE` or `DETECTION_DEPENDENCY_UNAVAILABLE`.
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id": "uuid",
|
||||
"dataset_id": "uuid",
|
||||
"model_id": "yolo-placeholder",
|
||||
"confidence_threshold": 0.5,
|
||||
"class_filter": ["building"],
|
||||
"tile_manifest_path": null,
|
||||
"parameters_json": {}
|
||||
}
|
||||
```
|
||||
|
||||
Sprint 8B configured YOLO mode uses `model_id: "yolo-configured"`. It requires:
|
||||
|
||||
- `YOLO_ENABLED=true`
|
||||
- `YOLO_MODEL_PATH` pointing to an existing local model file
|
||||
- backend optional AI dependencies installed with `geointel-backend[ai]`
|
||||
- `tile_manifest_path` pointing to an existing raster tile manifest generated by the raster tile operation
|
||||
|
||||
GeoIntel does not download model weights automatically. Configured YOLO runs read existing tile files from the manifest, convert YOLO pixel-space boxes to EPSG:4326 detection polygons and persist detections as first-class records.
|
||||
|
||||
Unavailable model response:
|
||||
|
||||
```json
|
||||
{
|
||||
"analysis_run_id": "uuid",
|
||||
"job_id": "uuid",
|
||||
"project_id": "uuid",
|
||||
"dataset_id": "uuid",
|
||||
"model_id": "yolo-placeholder",
|
||||
"status": "failed",
|
||||
"detection_count": 0,
|
||||
"error_code": "DETECTION_MODEL_UNAVAILABLE",
|
||||
"message": "YOLO/PyTorch inference is not configured in Sprint 8; no model is downloaded or executed."
|
||||
}
|
||||
```
|
||||
|
||||
Validation errors:
|
||||
|
||||
- `INVALID_DATASET_TYPE` when the dataset is not raster.
|
||||
- `DETECTION_MODEL_NOT_FOUND` when the model id is unknown.
|
||||
- `FIXTURE_MODE_REQUIRED` when `manual-fixture-detector` is requested without `parameters_json.fixture_mode=true`.
|
||||
- `DETECTION_TILE_MANIFEST_REQUIRED` when `yolo-configured` is requested without `tile_manifest_path`.
|
||||
- `DETECTION_TILE_MANIFEST_NOT_FOUND` when the provided manifest path does not exist.
|
||||
- `DETECTION_TILE_MANIFEST_INVALID` when the manifest cannot be parsed or lacks tile metadata.
|
||||
- `DETECTION_TILE_LIMIT_EXCEEDED` when the manifest exceeds `YOLO_MAX_TILES`.
|
||||
- `DETECTION_DEPENDENCY_UNAVAILABLE` when YOLO dependencies are not installed.
|
||||
- `DETECTION_MODEL_LOAD_FAILED` when the local model file exists but cannot be loaded.
|
||||
|
||||
Fixture detector mode is test/demo-only. It persists only explicit `parameters_json.fixture_detections` entries and is never invoked automatically.
|
||||
|
||||
### GET `/api/v1/detection/runs/{analysis_run_id}`
|
||||
|
||||
Returns one detection analysis run.
|
||||
|
||||
### GET `/api/v1/detection/runs`
|
||||
|
||||
Returns detection analysis runs, optionally filtered by `project_id` and `dataset_id`.
|
||||
|
||||
### GET `/api/v1/detection/runs/{analysis_run_id}/detections`
|
||||
|
||||
Returns persisted detections for a detection analysis run. Optional filters:
|
||||
|
||||
- `dataset_id`
|
||||
- `class_name`
|
||||
- `min_confidence`
|
||||
|
||||
### GET `/api/v1/detection/datasets/{dataset_id}/detections`
|
||||
|
||||
Returns persisted detections for a raster dataset. Optional filters:
|
||||
|
||||
- `analysis_run_id`
|
||||
- `class_name`
|
||||
- `min_confidence`
|
||||
|
||||
### GET `/api/v1/detection/detections/{detection_id}`
|
||||
|
||||
Returns one persisted detection.
|
||||
|
||||
### GET `/api/v1/detection/runs/{analysis_run_id}/geojson`
|
||||
|
||||
Returns persisted detections for a run as a GeoJSON FeatureCollection. Geometry comes from persisted PostGIS detection geometry in EPSG:4326.
|
||||
|
||||
Each feature includes:
|
||||
|
||||
- `detection_id`
|
||||
- `class_name`
|
||||
- `confidence`
|
||||
- `model_name`
|
||||
- `model_version`
|
||||
- `analysis_run_id`
|
||||
- `dataset_id`
|
||||
- `job_id`
|
||||
- `source_tile_path`
|
||||
- `bbox_json`
|
||||
|
||||
### GET `/api/v1/detection/datasets/{dataset_id}/geojson`
|
||||
|
||||
Returns persisted detections for a dataset as a GeoJSON FeatureCollection. Optional filters match the detection list endpoint.
|
||||
|
||||
### POST `/api/v1/detection/runs/{analysis_run_id}/qa/reference`
|
||||
|
||||
Compares persisted detection geometries from an analysis run against persisted `vector_features` from a reference vector dataset.
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"reference_dataset_id": "uuid",
|
||||
"iou_threshold": 0.5,
|
||||
"class_name": "building",
|
||||
"min_confidence": 0.5
|
||||
}
|
||||
```
|
||||
|
||||
Response persists a `quality_check` and `metrics` rows through the existing QA/QC persistence architecture and returns:
|
||||
|
||||
- `precision`
|
||||
- `recall`
|
||||
- `f1_score`
|
||||
- `mean_iou`
|
||||
- `false_positives`
|
||||
- `false_negatives`
|
||||
- `quality_check_id`
|
||||
|
||||
If the reference dataset has no persisted vector features, the endpoint returns `REFERENCE_FEATURES_NOT_FOUND`. It does not calculate fake QA metrics.
|
||||
|
||||
### POST `/api/v1/analysis/building-stats`
|
||||
|
||||
Input: area + vector building layer.
|
||||
|
||||
### POST `/api/v1/analysis/object-detection`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id": "uuid",
|
||||
"area_id": "uuid",
|
||||
"dataset_id": "uuid",
|
||||
"model_id": "optional uuid",
|
||||
"classes": ["building"],
|
||||
"confidence_threshold": 0.35,
|
||||
"tile_size": 640,
|
||||
"overlap": 64
|
||||
}
|
||||
```
|
||||
|
||||
Response: `AnalysisRunRead`.
|
||||
|
||||
### POST `/api/v1/analysis/segmentation`
|
||||
|
||||
Same pattern as object detection, but output includes masks and polygonized geometries.
|
||||
|
||||
## Segmentation Lab
|
||||
|
||||
Sprint 9 implements Segmentation Lab foundation only. Real SAM and YOLO-seg inference are not enabled, no model is downloaded, and fixture segmentations require explicit fixture mode.
|
||||
|
||||
### GET `/api/v1/segmentation/models`
|
||||
|
||||
Returns segmentation model capability descriptors:
|
||||
|
||||
- `segmentation-placeholder`: `not_configured`
|
||||
- `fixture-segmenter`: configured for explicit test/demo fixtures only
|
||||
- `yolo-seg-configured`: `not_configured`
|
||||
- `sam-configured`: `not_configured`
|
||||
|
||||
### POST `/api/v1/segmentation/run`
|
||||
|
||||
Creates a segmentation job and segmentation analysis run. If the requested model is unavailable, the job and analysis run are marked `failed` with `SEGMENTATION_MODEL_UNAVAILABLE`.
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id": "uuid",
|
||||
"dataset_id": "uuid",
|
||||
"model_id": "segmentation-placeholder",
|
||||
"confidence_threshold": 0.5,
|
||||
"class_filter": ["vegetation"],
|
||||
"tile_manifest_path": null,
|
||||
"parameters_json": {}
|
||||
}
|
||||
```
|
||||
|
||||
Fixture segmenter mode is test/demo-only. It persists only explicit `parameters_json.fixture_segmentations` entries when `parameters_json.fixture_mode=true`; it is never invoked automatically and does not represent production inference.
|
||||
|
||||
Validation errors:
|
||||
|
||||
- `INVALID_DATASET_TYPE` when the dataset is not raster.
|
||||
- `SEGMENTATION_MODEL_NOT_FOUND` when the model id is unknown.
|
||||
- `FIXTURE_MODE_REQUIRED` when `fixture-segmenter` is requested without `parameters_json.fixture_mode=true`.
|
||||
- `INVALID_FIXTURE_SEGMENTATIONS` when fixture payloads are not a list.
|
||||
- `INVALID_FIXTURE_GEOMETRY` when fixture geometry is empty, invalid or not Polygon/MultiPolygon.
|
||||
|
||||
### GET `/api/v1/segmentation/runs`
|
||||
|
||||
Returns segmentation analysis runs, optionally filtered by `project_id` and `dataset_id`.
|
||||
|
||||
### GET `/api/v1/segmentation/runs/{analysis_run_id}`
|
||||
|
||||
Returns one segmentation analysis run.
|
||||
|
||||
### GET `/api/v1/segmentation/runs/{analysis_run_id}/segmentations`
|
||||
|
||||
Returns persisted segmentation records for a segmentation analysis run. Optional filters:
|
||||
|
||||
- `dataset_id`
|
||||
- `class_name`
|
||||
- `min_confidence`
|
||||
|
||||
### GET `/api/v1/segmentation/datasets/{dataset_id}/segmentations`
|
||||
|
||||
Returns persisted segmentation records for a raster dataset. Optional filters:
|
||||
|
||||
- `analysis_run_id`
|
||||
- `class_name`
|
||||
- `min_confidence`
|
||||
|
||||
### GET `/api/v1/segmentation/segmentations/{segmentation_id}`
|
||||
|
||||
Returns one persisted segmentation record.
|
||||
|
||||
### GET `/api/v1/segmentation/runs/{analysis_run_id}/geojson`
|
||||
|
||||
Returns persisted segmentations for a run as a GeoJSON FeatureCollection. Geometry comes from persisted PostGIS segmentation geometry in EPSG:4326.
|
||||
|
||||
Each feature includes:
|
||||
|
||||
- `segmentation_id`
|
||||
- `class_name`
|
||||
- `confidence`
|
||||
- `area_m2`
|
||||
- `model_name`
|
||||
- `model_version`
|
||||
- `analysis_run_id`
|
||||
- `dataset_id`
|
||||
- `job_id`
|
||||
- `source_tile_path`
|
||||
- `tile_index`
|
||||
- `mask_path`
|
||||
- `bbox_json`
|
||||
- `provenance_json`
|
||||
|
||||
### GET `/api/v1/segmentation/datasets/{dataset_id}/geojson`
|
||||
|
||||
Returns persisted segmentations for a dataset as a GeoJSON FeatureCollection. Optional filters match the segmentation list endpoint.
|
||||
|
||||
### POST `/api/v1/segmentation/runs/{analysis_run_id}/qa/reference`
|
||||
|
||||
Compares persisted segmentation geometries from an analysis run against persisted `vector_features` from a reference vector dataset.
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"reference_dataset_id": "uuid",
|
||||
"iou_threshold": 0.5,
|
||||
"class_name": "vegetation",
|
||||
"min_confidence": 0.5
|
||||
}
|
||||
```
|
||||
|
||||
Response persists a `quality_check` and `metrics` rows through the existing QA/QC persistence architecture and returns precision, recall, F1, mean IoU and false positive/negative counts.
|
||||
|
||||
If the segmentation run has no persisted geometries, the endpoint returns `SEGMENTATIONS_NOT_FOUND`. If the reference dataset has no persisted vector features, it returns `REFERENCE_FEATURES_NOT_FOUND`. It does not calculate fake QA metrics.
|
||||
|
||||
### POST `/api/v1/analysis/change-detection`
|
||||
|
||||
Request contains source analysis or datasets A/B and method.
|
||||
|
||||
## QA/QC
|
||||
|
||||
### POST `/api/v1/qa/detections-vs-reference`
|
||||
|
||||
Request:
|
||||
|
||||
```json
|
||||
{
|
||||
"candidate_dataset_id": "uuid",
|
||||
"reference_dataset_id": "uuid",
|
||||
"iou_threshold": 0.5,
|
||||
"area_id": "optional uuid"
|
||||
}
|
||||
```
|
||||
|
||||
Response is wrapped in the job envelope. On success, `result_json` includes precision, recall, F1, mean IoU, false positives, false negatives and `quality_check_id`.
|
||||
|
||||
Sprint 7A persists the QA/QC result as:
|
||||
|
||||
- `jobs`: execution state.
|
||||
- `quality_checks`: domain result.
|
||||
- `metrics`: individual measurements.
|
||||
|
||||
Future Detection and Segmentation flows may add an `analysis_run_id` path without replacing persisted quality checks.
|
||||
|
||||
### GET `/api/v1/projects/{project_id}/quality-checks`
|
||||
|
||||
Lists persisted QA/QC quality checks for a project with metric rows.
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"project_id": "uuid",
|
||||
"job_id": "uuid-or-null",
|
||||
"analysis_run_id": "uuid-or-null",
|
||||
"candidate_dataset_id": "uuid-or-null",
|
||||
"reference_dataset_id": "uuid",
|
||||
"check_type": "demo_candidate_vs_reference",
|
||||
"status": "ok",
|
||||
"score": 0.5,
|
||||
"parameters_json": {},
|
||||
"findings_json": {},
|
||||
"metrics": [
|
||||
{
|
||||
"metric_key": "precision",
|
||||
"metric_value": 0.5
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"total": 1,
|
||||
"limit": 50,
|
||||
"offset": 0
|
||||
}
|
||||
```
|
||||
|
||||
## Exports
|
||||
|
||||
### POST `/api/v1/exports/geojson`
|
||||
|
||||
Export detections, segmentations or vector layer to GeoJSON.
|
||||
|
||||
Dataset vector export request:
|
||||
|
||||
```json
|
||||
{
|
||||
"export_kind": "dataset",
|
||||
"dataset_id": "uuid",
|
||||
"name": "optional-basename"
|
||||
}
|
||||
```
|
||||
|
||||
Detection run export request:
|
||||
|
||||
```json
|
||||
{
|
||||
"export_kind": "detection_run",
|
||||
"analysis_run_id": "uuid",
|
||||
"name": "optional-basename"
|
||||
}
|
||||
```
|
||||
|
||||
Segmentation run export request:
|
||||
|
||||
```json
|
||||
{
|
||||
"export_kind": "segmentation_run",
|
||||
"analysis_run_id": "uuid",
|
||||
"name": "optional-basename"
|
||||
}
|
||||
```
|
||||
|
||||
Response persists an `exports` row and writes a deterministic JSON artifact:
|
||||
|
||||
```json
|
||||
{
|
||||
"export_id": "uuid",
|
||||
"path": "storage/exports/{project_id}/datasets/{target}/{name}.geojson",
|
||||
"status": "ready",
|
||||
"export_type": "dataset_geojson",
|
||||
"metadata_json": {
|
||||
"source": "dataset",
|
||||
"feature_count": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Vector dataset exports use the stored dataset GeoJSON. Detection and
|
||||
segmentation exports use persisted first-class geometry records and the
|
||||
existing Detection/Segmentation GeoJSON conversion services. Raster datasets
|
||||
are rejected for dataset GeoJSON export.
|
||||
|
||||
### POST `/api/v1/exports/metadata`
|
||||
|
||||
Exports project metadata JSON for projects, datasets, persisted QA/QC summary
|
||||
rows and existing export history.
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id": "uuid",
|
||||
"name": "optional-basename"
|
||||
}
|
||||
```
|
||||
|
||||
### GET `/api/v1/exports/projects/{project_id}/exports`
|
||||
|
||||
Lists persisted export records for a project.
|
||||
|
||||
### GET `/api/v1/exports/{export_id}`
|
||||
|
||||
Returns one persisted export record.
|
||||
|
||||
### GET `/api/v1/exports/{export_id}/content`
|
||||
|
||||
Returns the stored JSON artifact content through the standard API envelope.
|
||||
|
||||
### GET `/api/v1/exports/{export_id}/download`
|
||||
|
||||
Downloads the stored JSON/GeoJSON export artifact as a raw file response with
|
||||
`application/json` content type and a `Content-Disposition` attachment
|
||||
filename. This endpoint intentionally does not use the JSON envelope because
|
||||
it is a browser/file-download path; callers that need canonical API JSON should
|
||||
use `/content`.
|
||||
|
||||
### POST `/api/v1/exports/yolo`
|
||||
|
||||
Export annotations/detections to YOLO format.
|
||||
|
||||
### POST `/api/v1/exports/report`
|
||||
|
||||
Creates a lightweight HTML project report artifact from persisted project,
|
||||
dataset, QA/QC summary and export history state. This does not create a PDF
|
||||
and does not introduce a report designer.
|
||||
|
||||
```json
|
||||
{
|
||||
"project_id": "uuid",
|
||||
"name": "optional-basename"
|
||||
}
|
||||
```
|
||||
|
||||
Response persists an `exports` row with `export_type:
|
||||
project_report_html`. Download the report through:
|
||||
|
||||
```text
|
||||
GET /api/v1/exports/{export_id}/download
|
||||
```
|
||||
|
||||
PDF/report-designer functionality can be added after core GeoAI workflows work.
|
||||
Reference in New Issue
Block a user