feat(geoportal-v2): swap refresh path to /parcel/enrich (deep-enrich)

gis-api session shipped PR3 (gis-api 09f1ab8 + gis-sync-orchestrator
0371d81): new POST /api/v1/parcel/enrich does the full eTerra
round-trip (searchImmovableByIdentifier → fetchDocumentationData
→ fetchImmovableParcelDetails) and merges NR_CF / ADRESA / PROPRIETARI
+ 20-plus fields into gis_core.GisFeature.enrichment with a 30-day
cache. Verified on 266888 + 328607 → 27 keys with full PII.

Wired in three places:

1. src/lib/gis-api-client.ts — gisApi.parcel.enrich({siruta,
   cadastralRef, force?}) thin wrapper.

2. src/app/api/gis/parcel/enrich/route.ts — architots-side proxy,
   matches the parcel/tech pattern (auth check → forward → bubble up
   GisApiError status codes).

3. src/modules/geoportal/v2/feature-info-panel.tsx — refreshFromAncpi
   now POSTs to /api/gis/parcel/enrich instead of /api/gis/parcel/tech.
   After the orchestrator returns, the panel re-fetches the canonical
   record via parcela.get (when uuid known) or parcela.find (when
   not), so it sees exactly what gis_core stores rather than the
   orchestrator response shape.

The existing auto-trigger (fires when detail has no NR_CF/ADRESA/
PROPRIETARI) now actually fills those fields. Subsequent clicks on the
same parcel hit gis-api's 30-day cache (5ms vs 1-2s live fetch).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude VM
2026-05-19 22:24:02 +03:00
parent 87f9d72e4f
commit 02a466ccaa
3 changed files with 83 additions and 18 deletions
+49
View File
@@ -0,0 +1,49 @@
import { NextResponse } from "next/server";
import { getAuthSession } from "@/core/auth/require-auth";
import { gisApi, GisApiError, type ParcelRefBody } from "@/lib/gis-api-client";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
// Proxy to gis-api POST /api/v1/parcel/enrich (PR3, 2026-05-19).
// Orchestrator does the full eTerra round-trip and populates NR_CF /
// ADRESA / PROPRIETARI + tech fields in gis_core. 30-day cache by
// default; force=true bypasses. After this returns, the panel does a
// fresh parcela.get / parcela.find to read the canonical record.
export async function POST(request: Request) {
const session = await getAuthSession();
if (!session) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
let body: ParcelRefBody;
try {
body = (await request.json()) as ParcelRefBody;
} catch {
return NextResponse.json({ error: "invalid_body" }, { status: 400 });
}
if (!body?.siruta || !body?.cadastralRef) {
return NextResponse.json(
{ error: "missing_fields", required: ["siruta", "cadastralRef"] },
{ status: 400 },
);
}
try {
return NextResponse.json(await gisApi.parcel.enrich(body));
} catch (err) {
if (err instanceof GisApiError) {
return NextResponse.json(
{ error: err.code, status: err.status, body: err.body },
{ status: err.status },
);
}
const msg = err instanceof Error ? err.message : String(err);
console.error("[gis-parcel-enrich] internal:", msg);
return NextResponse.json(
{ error: "internal_error", hint: msg.slice(0, 200) },
{ status: 500 },
);
}
}