/** * GET /api/geoportal/boundary-check?siruta=57582 * * Spatial cross-check: finds parcels that geometrically fall within the * given UAT boundary but are registered under a DIFFERENT siruta. * * Also detects the reverse: parcels registered in this UAT whose centroid * falls outside its boundary (edge parcels). * * Returns GeoJSON FeatureCollection in EPSG:4326 (WGS84) for direct * map overlay. */ import { NextRequest, NextResponse } from "next/server"; import { prisma } from "@/core/storage/prisma"; export const runtime = "nodejs"; export const dynamic = "force-dynamic"; type RawRow = { id: string; siruta: string; object_id: number; cadastral_ref: string | null; area_value: number | null; layer_id: string; mismatch_type: string; geojson: string; }; export async function GET(req: NextRequest) { const siruta = req.nextUrl.searchParams.get("siruta"); if (!siruta) { return NextResponse.json({ error: "siruta required" }, { status: 400 }); } try { // 1. Foreign parcels: registered in OTHER UATs but geometrically overlap this UAT const foreign = await prisma.$queryRaw` SELECT f.id, f.siruta, f."objectId" AS object_id, f."cadastralRef" AS cadastral_ref, f."areaValue" AS area_value, f."layerId" AS layer_id, 'foreign' AS mismatch_type, ST_AsGeoJSON(ST_Transform(f.geom, 4326)) AS geojson FROM "GisFeature" f JOIN "GisUat" u ON u.siruta = ${siruta} WHERE f.siruta != ${siruta} AND ST_Intersects(f.geom, u.geom) AND (f."layerId" LIKE 'TERENURI%' OR f."layerId" LIKE 'CADGEN_LAND%') AND f.geom IS NOT NULL LIMIT 500 ` as RawRow[]; // 2. Edge parcels: registered in this UAT but centroid falls outside boundary const edge = await prisma.$queryRaw` SELECT f.id, f.siruta, f."objectId" AS object_id, f."cadastralRef" AS cadastral_ref, f."areaValue" AS area_value, f."layerId" AS layer_id, 'edge' AS mismatch_type, ST_AsGeoJSON(ST_Transform(f.geom, 4326)) AS geojson FROM "GisFeature" f JOIN "GisUat" u ON u.siruta = f.siruta AND u.siruta = ${siruta} WHERE NOT ST_Contains(u.geom, ST_Centroid(f.geom)) AND (f."layerId" LIKE 'TERENURI%' OR f."layerId" LIKE 'CADGEN_LAND%') AND f.geom IS NOT NULL LIMIT 500 ` as RawRow[]; const allRows = [...foreign, ...edge]; // Build GeoJSON FeatureCollection const features = allRows .map((row) => { try { const geometry = JSON.parse(row.geojson) as GeoJSON.Geometry; return { type: "Feature" as const, geometry, properties: { id: row.id, siruta: row.siruta, object_id: row.object_id, cadastral_ref: row.cadastral_ref, area_value: row.area_value, layer_id: row.layer_id, mismatch_type: row.mismatch_type, }, }; } catch { return null; } }) .filter(Boolean); return NextResponse.json({ type: "FeatureCollection", features, summary: { foreign: foreign.length, edge: edge.length, total: allRows.length, }, }); } catch (error) { const msg = error instanceof Error ? error.message : "Eroare"; return NextResponse.json({ error: msg }, { status: 500 }); } }