diff --git a/ordinis-cuod-bundle/src/main/java/cloud/nstart/terravault/ordinis/cuod/CuodBundleImporter.java b/ordinis-cuod-bundle/src/main/java/cloud/nstart/terravault/ordinis/cuod/CuodBundleImporter.java
index b1dafe9..007a8c3 100644
--- a/ordinis-cuod-bundle/src/main/java/cloud/nstart/terravault/ordinis/cuod/CuodBundleImporter.java
+++ b/ordinis-cuod-bundle/src/main/java/cloud/nstart/terravault/ordinis/cuod/CuodBundleImporter.java
@@ -207,6 +207,11 @@ public class CuodBundleImporter {
}
DictionaryRecord record = new DictionaryRecord(
UUID.randomUUID(), definition.getId(), businessKey, data, definition.getScope(), now);
+ // Auto-derive POINT geometry из data.lat/lon — match service behaviour.
+ // Без этого AOI spatial filter возвращает 0 records даже когда у dict
+ // есть записи с координатами.
+ org.locationtech.jts.geom.Geometry derived = deriveLatLonGeometry(data);
+ if (derived != null) record.setGeometry(derived);
DictionaryRecord savedRecord = recordRepository.save(record);
var recEvent = new DictionaryRecordCreated(
@@ -228,4 +233,34 @@ public class CuodBundleImporter {
private static cloud.nstart.terravault.ordinis.events.DataScope toEventScope(DataScope d) {
return cloud.nstart.terravault.ordinis.events.DataScope.valueOf(d.name());
}
+
+ /**
+ * Auto-derive POINT(lon lat) geometry из data.lat/lon. Mirror'ит logic в
+ * DictionaryRecordService.resolveGeometry — bundle importer bypass'ит
+ * service, поэтому ту же конвенцию реализуем тут отдельно. Match keys:
+ * lat|latitude, lon|longitude|lng. Validate ranges.
+ */
+ private static org.locationtech.jts.geom.Geometry deriveLatLonGeometry(JsonNode data) {
+ if (data == null || data.isMissingNode()) return null;
+ Double lat = pickNumber(data, "lat", "latitude");
+ Double lon = pickNumber(data, "lon", "longitude", "lng");
+ if (lat == null || lon == null) return null;
+ if (lat < -90.0 || lat > 90.0 || lon < -180.0 || lon > 180.0) return null;
+ try {
+ org.locationtech.jts.geom.Geometry g = new org.locationtech.jts.io.WKTReader()
+ .read("POINT(" + lon + " " + lat + ")");
+ g.setSRID(4326);
+ return g;
+ } catch (org.locationtech.jts.io.ParseException e) {
+ return null;
+ }
+ }
+
+ private static Double pickNumber(JsonNode data, String... keys) {
+ for (String k : keys) {
+ JsonNode n = data.get(k);
+ if (n != null && n.isNumber()) return n.doubleValue();
+ }
+ return null;
+ }
}
diff --git a/ordinis-migrations/src/main/resources/db/changelog/changes/0015-backfill-latlon-geometry.xml b/ordinis-migrations/src/main/resources/db/changelog/changes/0015-backfill-latlon-geometry.xml
new file mode 100644
index 0000000..04f2b62
--- /dev/null
+++ b/ordinis-migrations/src/main/resources/db/changelog/changes/0015-backfill-latlon-geometry.xml
@@ -0,0 +1,99 @@
+
+
Validation: lat ∈ [-90, 90], lon ∈ [-180, 180]. Если значения вне + * диапазона — игнорируем (не throw, чтобы не ломать legacy records со + * странными данными). Спорные значения validate'ятся schema-уровнем + * через {@code minimum/maximum}. + */ + private Geometry resolveGeometry(CreateRecordRequest req) { + if (req.geometryWkt() != null && !req.geometryWkt().isBlank()) { + return parseWkt(req.geometryWkt()); + } + var data = req.data(); + if (data == null) return null; + Double lat = pickLatLon(data, "lat", "latitude"); + Double lon = pickLatLon(data, "lon", "longitude", "lng"); + if (lat == null || lon == null) return null; + if (lat < -90.0 || lat > 90.0 || lon < -180.0 || lon > 180.0) return null; + String pointWkt = "POINT(" + lon + " " + lat + ")"; + try { + Geometry g = new WKTReader().read(pointWkt); + g.setSRID(4326); + return g; + } catch (ParseException e) { + // Не должно случиться (мы сами sсонструировали WKT) — но лучше null + // чем 500 если cosmic ray flip'нет double. + return null; + } + } + + private static Double pickLatLon(com.fasterxml.jackson.databind.JsonNode data, String... keys) { + for (String key : keys) { + var node = data.get(key); + if (node != null && node.isNumber()) return node.doubleValue(); + } + return null; + } + private void publishCreated(DictionaryDefinition d, DictionaryRecord r) { String wkt = r.getGeometry() == null ? null : new org.locationtech.jts.io.WKTWriter().write(r.getGeometry()); var payload = new DictionaryRecordCreated(