# Scripts Setup-, import-, demo- en maintenance-scripts voor GeoIntel. ## Runtime verification Audit the active backend route surface against `docs/API_CONTRACTS.md`: ```bash python scripts/audit_api_contracts.py ``` The audit imports the FastAPI app, compares implemented `GET`/`POST`/`PATCH`/ `DELETE` routes with active API contract headings and tracks the explicit non-envelope exceptions (`/health` and export downloads). It fails when a route exists without docs or when docs claim an endpoint that is not implemented. Verify the browser-facing Docker/LAN runtime: ```bash bash scripts/verify_browser_runtime.sh http://192.168.10.150:1202 bash scripts/verify_gis_runtime.sh http://192.168.10.150:1202 ``` Verify the explicit demo workflow plus export artifact path: ```bash bash scripts/verify_demo_export_workflow.sh http://192.168.10.150:1202 ``` The demo/export smoke is intentionally mutating and idempotent: it seeds the offline fixture demo if needed, verifies the project area GeoJSON, fixture datasets, vector FeatureCollection content, vector feature summary, persisted QA/QC metrics, creates metadata/report/vector GeoJSON exports, lists exports and downloads the JSON/GeoJSON/HTML artifacts through the frontend proxy. The persisted QA/QC result is compared against `fixtures/golden/expected_qa_metrics.json` so runtime demo precision, recall, F1, mean IoU and false-positive/negative counts cannot drift silently. Verify the explicit demo raster workflow: ```bash bash scripts/verify_demo_raster_workflow.sh http://192.168.10.150:1202 ``` The raster smoke is intentionally mutating and idempotent enough for local runtime checks: it seeds the offline demo workflow, validates the `demo_context_raster.tif` fixture dataset, then exercises raster inspect, preview, stats and one small tile/manifest generation through canonical `data` envelopes. It does not run AI inference or fetch external imagery. Verify that the browser-facing workbench can populate the default demo start state through the frontend proxy: ```bash bash scripts/verify_workbench_default_state.sh http://192.168.10.150:1202 ``` This smoke is dependency-light and intentionally idempotent: it seeds the offline demo workflow, then verifies that `GeoIntel Demo - Building QA` exposes the `Demo AOI - Geel buildings` map geometry, `3/3 ready` demo datasets (candidate vector, reference vector and raster fixture) and a persisted QA/QC result through canonical `data.items` envelopes. Pair it with a Codex/browser screenshot pass when checking visual layout or overflow. Verify the backing state for the core workbench interactions: ```bash bash scripts/verify_workbench_interactions.sh http://192.168.10.150:1202 ``` This smoke validates the state behind project switching, AOI/map selection, dataset selection, QA refresh and export refresh through the same frontend proxy used by the browser. The frontend also exposes stable `data-testid` anchors for Codex/browser click checks on those controls. Verify the browser click handoff from raster tiling into Detection and Segmentation Lab: ```bash bash scripts/verify_ai_handoff_interactions.sh http://192.168.10.150:1202 ``` The AI handoff smoke seeds the explicit offline demo workflow, generates a small raster tile manifest, opens the workbench in Chromium, clicks the raster inspector `Use in Detection Lab` and `Use in Segmentation Lab` actions, and verifies that the selected raster dataset plus manifest path are populated in the AI workspace. Playwright/Chromium must be available in the runner environment; GeoIntel does not add Playwright as a frontend dependency by default. The main readiness gate checks this script's syntax only. Capture visual regression handoff screenshots for the workbench: ```bash bash scripts/capture_workbench_screenshots.sh http://192.168.10.150:1202 CAPTURE_MOBILE=0 bash scripts/capture_workbench_screenshots.sh http://192.168.10.150:1202 /tmp/geointel-screens ``` The capture script seeds the explicit offline demo workflow, opens each main workspace, captures viewport desktop screenshots and, by default, viewport mobile screenshots. It writes PNG files plus `manifest.json` under `artifacts/screenshots/...` or a caller-provided output directory. Playwright/Chromium must be available in the runner environment; GeoIntel does not add Playwright as a frontend dependency by default. The main readiness gate checks script syntax only. Verify the deterministic QA/QC golden benchmark: ```bash bash scripts/verify_golden_qa_benchmark.sh python scripts/run_golden_qa_benchmark.py --json ``` The benchmark uses only explicit local fixtures under `fixtures/golden`, executes the existing QA/QC matching logic, verifies the expected precision, recall, F1, mean IoU and false-positive/false-negative counts, and checks that `QualityCheck` plus `Metric` rows would be persisted. Scenarios are listed in `fixtures/golden/golden_qa_benchmarks.json` and currently cover partial match, perfect match, no-overlap and MultiPolygon building comparisons. The main readiness gate runs this benchmark so QA metric drift fails before a release. Verify a configured local YOLO model without running inference: ```bash python scripts/yolo_preflight.py --model-path /absolute/path/to/model.pt --tile-manifest-path /absolute/path/to/manifest.json --check-model-load --json ``` Against the Docker runtime: ```bash docker compose exec -T backend python scripts/yolo_preflight.py --model-path /absolute/path/to/model.pt --tile-manifest-path /absolute/path/to/manifest.json --check-model-load --json ``` The model-load smoke is opt-in, requires real optional AI dependencies, refuses `--assume-dependencies`, loads only the supplied local file and does not download weights or run prediction. Verify the full configured-YOLO model asset workflow against a running runtime: ```bash bash scripts/verify_model_asset_detection_workflow.sh http://192.168.10.150:1202 ``` This smoke is intentionally mutating and requires a real AI-enabled runtime with at least one mounted local model asset. It seeds the explicit offline demo workflow, generates a small raster tile manifest, selects the active local model asset from `GET /api/v1/detection/model-assets`, validates read-only YOLO preflight, runs `POST /api/v1/detection/run`, and verifies the persisted AnalysisRun, Detection list and Detection GeoJSON endpoints. A zero detection count is allowed because the demo raster is a synthetic runtime fixture; the script validates the operational path and provenance, not production model quality. The main readiness gate checks this script's syntax only. Verify the full operator-provided raster/reference detection and QA path: ```bash REAL_RASTER_PATH=/mnt/user/appdata/geointel/data/orthophoto.tif \ REAL_REFERENCE_VECTOR_PATH=/mnt/user/appdata/geointel/data/reference-buildings.geojson \ bash scripts/verify_real_data_detection_qa_workflow.sh http://192.168.10.150:1202 ``` The current Tower operator sample is available at: ```bash REAL_RASTER_PATH=/mnt/user/appdata/geointel/storage/operator-data/geel_orthophoto_wms_512.tif \ REAL_REFERENCE_VECTOR_PATH=/mnt/user/appdata/geointel/storage/operator-data/geel_grb_gbg_buildings.geojson \ bash scripts/verify_real_data_detection_qa_workflow.sh http://192.168.10.150:1202 ``` Those files are runtime artifacts generated from Digitaal Vlaanderen's OMWRGBMRVL WMS `Ortho` layer and GRB OGC API Features `GBG` building collection for a small Geel AOI. They are intentionally not repository fixtures. The real-data smoke is intentionally mutating and refuses to run without operator-supplied files. Current V1 upload support expects a georeferenced `.tif`, `.tiff` or `.geotiff` raster and a `.geojson` or `.json` reference building vector. The script creates a project, uploads the raster as a source dataset, uploads the vector as a `reference` dataset, validates raster/vector metadata, tiles the raster, selects a mounted local model asset, verifies read-only YOLO preflight, runs configured YOLO detection, runs detection QA against persisted `vector_features`, and exports the detection run as GeoJSON. It does not seed demo data, enable fixture detections, fetch external data or download model weights. Configured-YOLO model class labels are normalized to lowercase for filtering and persisted detections, while the original model label is retained in detection provenance. Raster tile manifests generated by the workflow include source CRS metadata so persisted detection GeoJSON coordinates can be transformed to WGS84. A zero detection count is accepted operationally only when the selected model genuinely returns no usable detections after class filtering; it must be interpreted as model/data quality evidence rather than as a successful building extraction result. Docker images install only the GIS runtime by default. To build a local/Tower image with PyTorch/Ultralytics available for the configured-YOLO preflight and runtime path, set: ```bash GEOINTEL_INSTALL_AI=true ``` For Unraid/all-in-one deployments, place model files under `GEOINTEL_MODELS_PATH` so they appear in the container under `/app/models`, then set `YOLO_ENABLED=true`, `YOLO_MODELS_DIR=/app/models` and `YOLO_MODEL_PATH=/app/models/.pt`. Configure the Unraid/Tower env file from an existing local model without downloading weights or running inference: ```bash python scripts/configure_yolo_model.py \ --models-dir /mnt/user/appdata/geointel/models \ --env-file /mnt/user/appdata/geointel/.env ``` If exactly one supported model file (`.pt`, `.onnx` or `.engine`) is present, apply the env update explicitly: ```bash python scripts/configure_yolo_model.py \ --models-dir /mnt/user/appdata/geointel/models \ --env-file /mnt/user/appdata/geointel/.env \ --apply ``` The configurator refuses to proceed when no model exists or when multiple model files are present without `--model-file`. It writes only `GEOINTEL_INSTALL_AI=true`, `YOLO_ENABLED=true`, `YOLO_MODELS_DIR=/app/models` and the mounted `YOLO_MODEL_PATH`. Clean old offline demo export artifacts without touching uploaded source data: ```bash python scripts/cleanup_demo_artifacts.py python scripts/cleanup_demo_artifacts.py --keep-latest 10 --export-type project_report_html python scripts/cleanup_demo_artifacts.py --keep-latest 10 --max-delete 100 --apply ``` Against the Docker runtime, run the backend-container entrypoint: ```bash docker compose exec -T backend python scripts/cleanup_demo_artifacts.py docker compose exec -T backend python scripts/cleanup_demo_artifacts.py --keep-latest 10 --export-type project_report_html docker compose exec -T backend python scripts/cleanup_demo_artifacts.py --keep-latest 10 --max-delete 100 --apply ``` The cleanup script is dry-run by default. It only targets the explicit `GeoIntel Demo - Building QA` project unless `--project-name` is provided, keeps the newest exports per matching project, deletes only `exports` rows/files when `--apply` is set, and refuses to remove files outside the configured `STORAGE_ROOT`. `--max-delete` defaults to 25 and blocks large cleanup runs until the operator raises it after reviewing dry-run output. Repeat `--export-type` to limit cleanup to specific artifact kinds such as `project_report_html` or `project_metadata_json`. Verify the cleanup path against a running backend without deleting anything: ```bash bash scripts/verify_demo_cleanup_dry_run.sh CLEANUP_MODE=compose bash scripts/verify_demo_cleanup_dry_run.sh CLEANUP_MODE=container CLEANUP_CONTAINER=geointel bash scripts/verify_demo_cleanup_dry_run.sh ``` The smoke runs the cleanup command without `--apply`, expects `dry_run=true`, expects `deleted_export_count=0`, verifies candidate fields are present and prints the matched/type-filtered/selected counts. Use `KEEP_LATEST`, `MAX_DELETE` and `EXPORT_TYPE` environment variables to adjust the dry-run thresholds without changing the script. The main readiness gate checks this script's syntax; run it explicitly against Docker/PostGIS when validating a live deployment. ## Tower deployment Push the local branch to Gitea, then rebuild the Unraid/Tower Docker runtime: ```bash bash scripts/deploy_tower.sh ``` From the Codex Windows workspace, use the PowerShell wrapper: ```powershell .\scripts\deploy_tower.ps1 ``` For the first deployment into an existing non-Git appdata folder, bootstrap the checkout explicitly: ```bash DEPLOY_BOOTSTRAP=1 bash scripts/deploy_tower.sh ``` ```powershell .\scripts\deploy_tower.ps1 -Bootstrap ``` Useful overrides: ```bash REMOTE_HOST=root@192.168.10.150 REMOTE_PATH=/mnt/user/appdata/geointel REMOTE_REPO=gitea-widefrog:NuklearRabbit/geointel.git FRONTEND_URL=http://192.168.10.150:1202 ```