feat(parcel-sync): sync-to-DB + local export + layer catalog enhancements

Layer catalog now has 3 actions per layer:
- Sync: downloads from eTerra, stores in PostgreSQL (GisFeature table),
  incremental — only new OBJECTIDs fetched, removed ones deleted
- GPKG: direct download from eTerra (existing behavior)
- Local export: generates GPKG from local DB (no eTerra needed)

New features:
- /api/eterra/export-local endpoint — builds GPKG from DB, ZIP for multi-layer
- /api/eterra/sync now uses session-based auth (no credentials in request)
- Category headers show both remote + local feature counts
- Each layer shows local DB count (violet badge) + last sync timestamp
- 'Export local' button in action bar when any layer has local data
- Sync progress message with auto-dismiss

DB schema already had GisFeature + GisSyncRun tables from prior work.
This commit is contained in:
AI Assistant
2026-03-07 10:05:39 +02:00
parent f73e639e4f
commit b0c4bf91d7
3 changed files with 483 additions and 70 deletions
+6 -8
View File
@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import { syncLayer } from "@/modules/parcel-sync/services/sync-service";
import { getSessionCredentials } from "@/modules/parcel-sync/services/session-store";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
@@ -18,15 +19,12 @@ type Body = {
export async function POST(req: Request) {
try {
const body = (await req.json()) as Body;
const username = (
body.username ??
process.env.ETERRA_USERNAME ??
""
const session = getSessionCredentials();
const username = String(
body.username || session?.username || process.env.ETERRA_USERNAME || "",
).trim();
const password = (
body.password ??
process.env.ETERRA_PASSWORD ??
""
const password = String(
body.password || session?.password || process.env.ETERRA_PASSWORD || "",
).trim();
const siruta = String(body.siruta ?? "").trim();
const layerId = String(body.layerId ?? "TERENURI_ACTIVE").trim();