JosephDillard/geospatial-status-board
GitHub: JosephDillard/geospatial-status-board
基于 Grails 和 MapLibre 的地理空间运营状态板,将机场、停机坪、基础设施与事件数据整合到交互式地图和仪表盘中,支持事件审查与响应协调。
Stars: 0 | Forks: 0
# 状态应用
本代码库包含一个可关联地理空间数据的状态应用,用于在仪表盘和地理空间视图中展示机场及停机坪的状态。该应用将机场状态、停机坪状况、支援资产、公共设施和事件数据整合到一个 Grails 应用中,并可构建和部署为单个 WAR 文件。
## 功能
- 机场和停机坪状态仪表盘。
- 状态记录与地图视图之间的地理空间链接。
- 由 GeoServer WFS/GeoJSON 图层(包括可选的 GeoAI 检测输出)支持的 MapLibre GL JS 5.24.0 地图视图。
- 可配置的底图、图层选择、要素过滤、适配图层、全屏、距离测量、绘图,以及支持 MGRS 的坐标读取。
- 路由级别的 Incident Analyst 界面,复用共享地图、事件绘制、Wiki/GeoNames、LLM、响应支持、弹窗、表格和 Kanban 工作流,并增加了审查面板。
- 共享的响应支持查询,使用 Incident Analyst 桥接进行 OpenStreetMap 支持搜索和本地后备记录。
- 临时坐标标记,每个标记支持复制、时间戳、清除和 Google Maps 操作。
- 仅包含底图的迷你地图概览,带有红色的当前视图轮廓、最小化按钮,以及用于主地图视图的点击/拖拽导航。
- 针对机场、事件、Wiki/GeoNames 和响应支持标记的自定义路由网站图标和地图符号。
- 可编辑的查找表,用于机场和事件工作流中的下拉文本。
- 新墨西哥州机场和停机坪的开发引导数据,包含当前状态、跑道表面状况、支援资产、公共设施、当前事件和归档事件。
- 单个可部署的 WAR,应用程序从 `/GeoStatusBoard` 提供服务。
- 可选的 Docker Compose GIS 技术栈,用于本地 PostGIS、GeoServer 和 GeoAI 开发。
## 截图

上面的截图展示了带有 GeoAI 检测、COG 覆盖范围叠加、LLM 请求面板、服务健康指标和图层面板的地理空间状态地图。
## 技术
- Grails 5.3.3
- Groovy 3.0.11
- GORM 7.3.3
- Gradle 7.6.6 wrapper
- Java 18 运行时
- Spring Security
- H2 开发和测试数据库
- 用于开源 GIS 部署的 PostGIS 和 GeoServer
- 用于浏览器地图的 MapLibre GL JS 5.24.0
- 用于可选本地 GIS 和 GeoAI 基础设施的 Docker Compose
## 项目布局
- `grails-app/` - 根状态应用配置、安全、主页、地图视图和共享应用设置。
- `gsb-airport/` - 机场、停机坪、公共设施和支援资产状态模块。
- `gsb-incidents/` - 事件、当前事件、归档事件和设施损坏模块。
- `docs/` - 地理空间架构说明、PostGIS 空间化 SQL 和 README 图像。
- `docker/` - 本地 PostGIS 初始化和 GeoServer 引导脚本。
- `docker-compose.yml` - 可选的本地 PostGIS、GeoServer 和 GeoAI 服务。
- `.env.example` - 本地 Docker 和 GIS 配置默认值。
- `dev.ps1` - 用于本地 Docker GIS 技术栈的便捷命令。
- `build.gradle` - 根构建、WAR 打包、Java 兼容性和模块依赖项。
- `settings.gradle` - 在 `geospatial-status-board` Gradle 根项目下包含机场和事件模块。
## 代码库映射
本代码库提供了 Grails 状态板应用程序、MapLibre 地图查看器、GeoServer/PostGIS 本地技术栈、事件审查界面和地理空间架构说明。伴随的代码库提供了影像工作流、验证、摄取、MCP 工具,以及围绕相同地图操作的专注桥接/演示。
- [作品集网站](https://josephdillard.github.io/JosephDillard/)
- [Geospatial Status Board 代码库](https://github.com/JosephDillard/geospatial-status-board)
- [Geospatial Status Board 架构](docs/geospatial-architecture.md)
- [GeoAI Asset Detection Platform](https://github.com/JosephDillard/geoai-asset-detection-platform)
- [Geospatial Data Gateway](https://github.com/JosephDillard/geospatial-data-gateway)
- [Geospatial MCP Services](https://github.com/JosephDillard/geospatial-mcp-services)
- [Geospatial ETL Validation Toolkit](https://github.com/JosephDillard/geospatial-etl-validation-toolkit)
- Map-to-AI Incident Analyst 桥接/演示(本地代码库;GitHub 发布待定)
## 本地运行
正常开发路径不需要 Docker。如果未启用 PostGIS profile,应用将使用 H2 作为根数据源以及指定的机场/事件数据源。
在代码库根目录下使用 Gradle wrapper:
```
.\gradlew.bat :bootRun
```
默认的本地 URL 是:
```
http://localhost:8080/GeoStatusBoard
```
要在最近的本地测试中使用的开发端口上运行:
```
.\gradlew.bat :bootRun --args="--server.port=18088"
```
然后打开:
```
http://localhost:18088/GeoStatusBoard
```
默认初始化的管理员帐户是:
```
username: admin
password: admin123
```
## 可选 Docker GIS 技术栈
当你需要用于地图/WFS 集成测试的本地 PostGIS 和 GeoServer 时,请使用 Docker。Grails 应用仍然可以通过 IntelliJ 或 `bootRun` 运行。
启动基础设施:
```
.\dev.ps1 up
```
等效的原始 Docker 命令:
```
docker compose up -d postgis geoserver
```
启动完整的开发基础设施,包括带有 TensorFlow/Keras 的 GeoAI API 容器:
```
.\dev.ps1 up-geoai
```
默认本地端点:
```
PostGIS: localhost:5432/geostatusboard
GeoServer: http://localhost:8081/geoserver
WFS: http://localhost:8081/geoserver/gsb/ows
GeoAI: http://localhost:8000
Gateway: http://localhost:7070
```
默认本地凭据:
```
PostGIS user/password: gsb / gsb
GeoServer user/password: admin / geoserver
```
要自定义端口、镜像标签、凭据或 WFS URL:
```
Copy-Item .env.example .env
```
然后编辑 `.env`。`.env` 文件被 Git 有意忽略了。
`GEOSERVER_WFS_MAX_FEATURES` 控制引导容器使用的 GeoServer WFS 服务上限。默认值为 `5000`,而地图查看器为内部 WFS 图层至少请求 `geo.viewer.maxFeatures`(默认为 `500`)。
`geoai` Compose profile 从 `GEOAI_CONTEXT=../geoai-asset-detection-platform` 构建同级的 GeoAI 代码库。它绑定挂载该代码库的 `src/`、`config/`、`scripts/` 和 `sql/` 文件夹以加快开发循环,外加被忽略的 `data/`、`models/`、`outputs/` 和 `logs/` 文件夹,以便下载的模型、示例 COG、掩码、矢量和 API 日志保留为本地开发产物。
在 NVIDIA RTX 笔记本电脑上,GeoAI 容器默认请求一个 NVIDIA GPU,并使用支持 CUDA 的 PyTorch wheel 进行构建。Docker Desktop 必须使用支持 NVIDIA Container Toolkit 的 WSL 2 后端。要强制使用仅 CPU 的 GeoAI 镜像,请在重新构建之前在 `.env` 中设置此项:
```
GEOAI_PYTORCH_INDEX_URL=https://download.pytorch.org/whl/cpu
```
首次启动时,如果开源 HF U-Net/Keras 道路模型、WHU 建筑物分割模型和 Taos NAIP 示例 COG 缺失,GeoAI 容器会将其下载。在 `.env` 中设置 `GEOAI_DOWNLOAD_HF_MODEL=false`、`GEOAI_DOWNLOAD_HF_BUILDING_MODEL=false` 或 `GEOAI_FETCH_SAMPLE_COG=false` 可禁用任何自动下载。
### 保持 Grails 使用 H2
正常运行应用:
```
.\gradlew.bat :bootRun
```
此路径使用 H2。如果 GeoServer 未运行,地图页面仍可用于底图和工具,并在地图状态面板中报告 GeoServer 图层失败。
### 针对 PostGIS 运行 Grails
启动 Docker 基础设施,然后使用 `postgis` Spring profile 运行应用:
```
.\dev.ps1 up
$env:SPRING_PROFILES_ACTIVE = 'postgis'
.\gradlew.bat :bootRun
Remove-Item Env:SPRING_PROFILES_ACTIVE
```
对于 IntelliJ,设置以下任一 VM 选项:
```
-Dspring.profiles.active=postgis
```
或环境变量:
```
SPRING_PROFILES_ACTIVE=postgis
```
在应用于 PostGIS 中创建表后,应用空间列/索引并重新运行 GeoServer 引导:
```
.\dev.ps1 spatialize
```
空间化脚本添加了 `geom geometry(Geometry, 4326)` 列和 GiST 索引。对于内置的开发示例数据,它还初始化了近似的新墨西哥州点和面几何图形,以便地图能够立即绘制。对于生产数据,请将这些示例几何图形替换为权威的源几何图形。
有用的 Docker 辅助命令:
```
.\dev.ps1 logs
.\dev.ps1 logs-geoai
.\dev.ps1 build-geoai
.\dev.ps1 geoserver-init
.\dev.ps1 down
.\dev.ps1 reset
```
`reset` 删除本地 Docker 卷并重新创建空的 PostGIS 和 GeoServer 状态。
## 构建
构建整个项目:
```
.\gradlew.bat clean build
```
可部署的 WAR 创建于:
```
build/libs/GeoStatusBoard.war
```
## 部署上下文
应用被配置为在以下路径下运行:
```
/GeoStatusBoard
```
例如:
```
http://localhost:8080/GeoStatusBoard
```
## 查找数据
下拉值通过可编辑的查找表进行管理,以便管理员可以在不更改领域约束或 GSP 文件的情况下更新显示文本。
有用的管理路由包括:
```
/GeoStatusBoard/airportLookupOption
/GeoStatusBoard/incidentLookupOption
```
机场和事件查找引导初始化了新墨西哥州的机场、停机坪、事件类型、事件类别、来源、状态值,以及用于开发和测试数据的类似机构的服务所有者值。服务所有者选项侧重于 FEMA、联邦土地/消防机构、新墨西哥州机构、当地消防部门、机场当局和应急管理部门。
## 引导测试数据
默认情况下,在生产环境之外会启用引导测试数据。它会将缺失的样本行添加到开发/测试表中,而不会在每次重启时重复添加行,因此现有的开发数据库可以在应用重启后获取新添加的种子数据。合成的状态和事件记录仅在生产环境之外进行初始化。当前的种子覆盖范围包括:
- 15 个新墨西哥州地点的机场状态和当前 SIT 行。
- 跑道和停机坪表面状况记录。
- 工程和消防支援资产记录。
- 公共设施状态记录。
- 当前事件记录。
- 归档事件记录。
引导的地点包括 Kirtland AFB、Holloman AFB、Cannon AFB、Albuquerque International Sunport、Roswell Air Center、Spaceport America、Las Cruces International Airport 以及其他新墨西哥州的停机坪。
## 地理空间视图
应用包含一个基于 MapLibre 的地理空间视图,位于:
```
/GeoStatusBoard/map
```
专注的 Incident Analyst 路由位于:
```
/GeoStatusBoard/incident-analyst
```
它复用了共享的 MapLibre 地图视图,而不是承载重复的地图实现。相同的图层抽屉、底图选择器、事件绘制、Wiki/GeoNames 地点探索、LLM 请求面板、响应支持查询、MGRS/坐标工具、测量、事件符号体系和事件弹窗在两个地图入口点均可用。Analyst 路由默认为“当前事件”图层,将该图层过滤到 Santa Fe 到科罗拉多州边界的审查区域,并增加了一个带有风险评分、表格/Kanban 链接和附近响应支持的右侧审查面板。
默认情况下,响应支持查询通过代理连接到独立的 Incident Analyst 桥接:
```
INCIDENT_ANALYST_BRIDGE_URL=http://127.0.0.1:8775/incident-analyst
```
地图调用下方的同源代理,该代理将请求转发到桥接,并使两个地图路由上的浏览器行为保持一致:
```
GET /GeoStatusBoard/incident-analyst/api/osm/support?latitude=35.687&longitude=-105.938&radius_m=20000
```
这使得作品集/演示代码库保持有用,同时为主应用提供了干净的集成点。以后可以在不更改浏览器路由的情况下,使用直接的 MCP 客户端或应用内服务替换桥接。如果 OpenStreetMap 超时或不可用,当所选点附近有任何记录时,该工具会显示本地响应支持后备记录。
GSP 链接可以打开带有选定图层和要素过滤器的地图,例如:
```
/GeoStatusBoard/map?layer=airportStatus&field=site_name&value=Kirtland%20AFB
```
地图配置位于 `grails-app/conf/application.yml` 中的 `geo.viewer`、`geo.geoserver`、`geo.placeSearch`、`geo.incidentAnalyst` 和 `geo.layers` 下。
MapLibre GL JS 和 CSS 通过 `geo.viewer.mapLibreJsUrl` 和 `geo.viewer.mapLibreCssUrl` 被锁定为 `maplibre-gl@5.24.0`;控制器回退使用完全相同的版本。当前的默认底图是 CARTO Dark Blue 和 OpenStreetMap,配置的图层包括机场状态、当前停机坪状态、停机坪表面状态、NAVAIDs、工程资产、消防资产、公共设施状态、GeoAI COG 覆盖范围、GeoAI 检测、当前事件和事件存档。机场和停机坪点图层使用机场符号集,当前和归档事件图层使用 FEMA 风格的事件符号集,Wiki/GeoNames 和响应支持工具在操作图层上方绘制各自的结果标记。
Wiki/GeoNames 地点探索直接在地图上进行。设置 `GEONAMES_USERNAME` 或 `geo.placeSearch.geonamesUsername` 以优先使用 GeoNames 附近的 Wikipedia;当未配置 GeoNames 用户名时,浏览器将回退到公共的 Wikipedia GeoSearch API。
坐标复制模式会在地图上留下临时坐标标记。可以一次保留多个标记;点击标记会重新选择该坐标,更新坐标读数,并打开一个属性弹窗,其中包含 MGRS、纬度/经度、DMS、时间戳、复制、Google Maps 和清除操作。坐标读数中的小标记按钮可清除活动标记,而不会清除标记。
地图包含一个仅显示底图的迷你地图概览。迷你地图随地图一起打开,在当前主地图视图周围绘制红色轮廓,跟随底图更改,可以最小化,并且可以点击或拖拽以移动主地图,而无需将操作 WFS 图层加载到概览中。
地图还包括一个紧凑的 GeoAI 请求面板。它通过同源的 Grails 代理路由从 GeoAI API 加载模型选项,提交选定的模型、工作流、当前 MapLibre 范围和可选绘制的 AOI,然后轮询返回的运行 ID。绘制的 AOI 多边形在提交前会进行规范化,包括选定或活动的绘图要素和闭合的多边形环,因此 GeoAI API 接收的是 `map_context.aoi_geojson`,而不是静默回退到仅当前地图视图:
- `GET /GeoStatusBoard/geoAi/options`
- `POST /GeoStatusBoard/geoAi/runs`
- `GET /GeoStatusBoard/geoAi/runs/{run_id}`
使用 `geo.geoai.apiUrl` 或 `GEOAI_API_URL` 环境变量配置目标 API。如果 GeoAI 不可用,地图仍保持可用,面板会显示请求失败,而不是阻止地图工具。
当选定的工作流加载 PostGIS 要素时,地图会刷新 `GeoAI Detections`,并在该图层的作业过滤器中选定返回的 API 运行 ID。零要素运行会将现有的检测图层保持原样。
当 GeoAI 工作流写入本地 PostGIS 数据库中的 `public.detected_roads` 时,请重新运行 `.\dev.ps1 geoserver-init` 以发布 `gsb:detected_roads`。
地图将其作为 `GeoAI` 类别下的 `GeoAI Detections` 图层公开,并在存在 `job_id` 值时在该图层下添加作业过滤器。COG 清单覆盖范围表是 `public.geoai_cog_footprints`,并作为 `COG Footprints` 公开。
中心页面和地图健康状态条在 GeoServer、PostGIS 和 GeoAI 旁边包含了伴随的 Geospatial Data Gateway。地图可以订阅网关的本地 SignalR hub,并在网关广播 `layer.refresh_requested` 时刷新配置的 WFS 图层。使用以下命令进行配置:
```
GEOSPATIAL_GATEWAY_SIGNALR_ENABLED=true
GEOSPATIAL_GATEWAY_HUB_URL=http://localhost:7070/hubs/geospatial-updates
```
要在地图打开时进行本地冒烟测试,请触发刷新事件:
```
Invoke-RestMethod `
-Method Post `
-Uri http://localhost:7070/demo/layer-refresh `
-ContentType 'application/json' `
-Body '{"layerKey":"detectedRoads","message":"Manual local SignalR demo refresh."}'
```
推荐的开源 GIS 技术栈是:
- PostGIS,用于操作数据库中的地理空间列和空间索引。
- GeoServer,用于将数据库表发布为 WFS GeoJSON 图层。
- MapLibre GL JS 5.24.0,用于浏览器地图视图。
Grails 领域继续通过 GORM 读取和写入常规状态字段。GeoServer 从 PostGIS 读取几何图形并提供给地图 API。只要提供商条款允许,天气、影像、飞行、道路或其他外部源可以作为额外的 GeoServer 发布图层或直接地图切片/矢量服务添加。
参见:
- `docs/postgis-spatialization.sql`
- `docs/geospatial-architecture.md`
## 开发路线图
计划的地图工作包括一个 OpenCLAW 风格的地图命令助手:在共享的 MapLibre 地图上的一个 prompt,Analyst 可以在其中用自然语言请求地图任务,应用将这些请求转换为经过审查的结构化操作。
候选请求包括:
- "Plot a wildfire incident at 34.904222, -106.575583."
- "Zoom to high-risk incidents north of Santa Fe."
- "Find response support near the selected incident."
- "Turn on airports, current incidents, and GeoAI detections."
- "Draw an AOI around this view and submit a GeoAI road-detection run."
第一个版本应该将命令路由到现有的地图功能,而不是创建单独的自动化技术栈。只读命令可以平移、过滤、切换图层、运行 Wiki/GeoNames 或响应支持查询,以及汇总可见的事件。写入命令(例如创建或编辑事件)应在保存任何内容之前返回预览并需要明确的用户确认。
推荐的实施阶段:
1. 添加一个结构化的意图端点,将 prompt 和地图上下文转换为允许列表内的行动计划。
2. 在浏览器中执行只读地图操作:平移/缩放、图层切换、过滤器、弹窗、汇总和支持/地点搜索。
3. 为事件绘制和事件更新添加经过审查的写入操作。
4. 添加审计跟踪,显示 prompt、解释的操作、用户批准以及最终的地图/数据库更改。
## 最近的本地更改
- 添加了可选的 Docker Compose GIS 技术栈,用于本地 PostGIS 和 GeoServer 测试。
- 添加了用于 TensorFlow/Keras 道路分割的 GeoAI Docker Compose profile,同时 Grails 在本地运行。
- 添加了开源 WHU 建筑物分割工作流,用于可见的 Taos NAIP GeoAI 检测。
- 添加了 `postgis` Spring profile,同时保留 H2 作为默认的开发和测试数据库。
- 添加了 GeoServer WFS 超时处理,以便缺失的本地 GeoServer 服务可以在地图状态面板中优雅地失败。
- 添加了针对本地 PostGIS 开发 profile 的 PostgreSQL 安全表/公式映射。
- 为初始化的新墨西哥州记录添加了开发示例几何图形。
- 添加了可编辑的查找表、更丰富的新墨西哥州引导数据,以及用于底图、图层、要素过滤、测量、绘图、全屏、MGRS、坐标读取、临时坐标标记和仅底图迷你地图的 MapLibre 地图工具。
- 添加了顶部导航健康指标和一个 MapLibre GeoAI 请求面板,用于将带有规范化绘制 AOI 的地图上下文作业提交到 GeoAI 工作流 API。
- 添加了共享的 Incident Analyst 地图路由,具有与主地图相同的绘制、LLM、Wiki/GeoNames、响应支持、图层、弹窗、表格和 Kanban 工作流。
- 添加了通过 Incident Analyst 代理进行的响应支持查询,带有 OpenStreetMap 查询和本地后备消息传递。
- 为机场、事件图层、Wiki/GeoNames 结果和响应支持结果添加了自定义地图图标。
- 添加了自定义路由网站图标和随主地图一起打开的可最小化概览地图。
- 在中心和地图服务状态界面上添加了 Data Gateway 健康/链接可见性。
- 将 MapLibre GL JS/CSS 资产锁定为稳定的 `maplibre-gl@5.24.0`。
## 数据源
根应用配置了默认数据源以及所包含模块使用的指定数据源:
- `dataSource` - 根应用数据。
- `geodbfour` - 机场、停机坪、公共设施和支援资产数据。
- `geodbthree` - 事件数据。
开发和测试环境默认使用 H2 数据库。
可选的 `postgis` Spring profile 将所有三个数据源指向同一个本地 PostGIS 数据库,以便 GeoServer 可以从一个数据存储中发布机场、资产、公共设施和事件表。
PostGIS profile 覆盖配置位于:
```
grails-app/conf/application-postgis.yml
```
标签:GIS, Grails, JS文件枚举, PostGIS, 凭据扫描, 后台面板检测, 地理空间数据可视化, 应急响应支持, 机场运维管理, 版权保护, 状态监控看板