Commit Graph

219 Commits

Author SHA1 Message Date
AI Assistant d84106e1b4 feat(dwg): switch to ODA File Converter (libredwg too unstable)
ODA File Converter handles all DWG versions reliably.
Uses xvfb for headless Qt operation in Docker.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:18:22 +02:00
AI Assistant a23215a66e fix(dwg): build libredwg from source (not in any apt repo)
Multi-stage build: compile libredwg 0.13.3 in builder stage,
copy only dwg2dxf binary + libs to final slim image.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:58:34 +02:00
AI Assistant cc652dc5af fix(dwg): enable universe repo for libredwg-tools in Ubuntu 24.04
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:55:39 +02:00
AI Assistant 1b27f111a9 fix(dwg): use Ubuntu base for sidecar (libredwg-tools not in Debian repos)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:53:04 +02:00
AI Assistant 5209fd5dd0 feat(dwg): DWG→DXF via sidecar microservice (libredwg)
Add dedicated dwg2dxf container (Debian slim + libredwg-tools + Flask)
instead of modifying the Alpine base image. The ArchiTools API route
proxies to the sidecar over Docker internal network.

- dwg2dxf-api/: Dockerfile + Flask app (POST /convert, GET /health)
- docker-compose.yml: dwg2dxf service, healthcheck, depends_on
- route.ts: rewritten from local exec to HTTP proxy
- .dockerignore: exclude sidecar from main build context

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:51:27 +02:00
AI Assistant 7ed653eaec rollback(docker): restore Alpine base for stability, DWG→DXF disabled 2026-03-08 22:15:39 +02:00
AI Assistant f1f40d093b feat(docker): switch to Ubuntu base, enable DWG→DXF conversion via libredwg-tools 2026-03-08 22:08:39 +02:00
AI Assistant 893daea485 fix(docker): remove libredwg (not in Alpine repos), DWG→DXF gracefully disabled 2026-03-08 21:47:44 +02:00
AI Assistant 12b7bca990 Mini Utilities v0.2.0: extreme PDF compression (GS+qpdf), DWG→DXF, paste support, drag-drop layers
- Extreme PDF compression via direct Ghostscript + qpdf pipeline
  (PassThroughJPEGImages=false, QFactor 1.5, 72 DPI downsample)
- DWG→DXF converter via libredwg (Docker only)
- PDF unlock in-app via Stirling PDF proxy
- Removed PDF/A tab (unused)
- Paste (Ctrl+V) on all file drop zones
- Mouse drag-drop reordering on thermal layers
- Tabs reorganized into 2 visual rows
- Dockerfile: added ghostscript, qpdf, libredwg
2026-03-08 21:44:43 +02:00
AI Assistant 94b342e5ce Hot Desk 0.2.0: room layout proportions, name quick-select, remove notes 2026-03-08 19:33:25 +02:00
AI Assistant 4d2f924537 pre-launch hardening: Address Book type sort, Hot Desk proportions, TVA calculator, ROADMAP Phase 4B
- Address Book: type dropdown always sorted alphabetically (ro locale), including custom types
- Hot Desk: window ~half height (top-[35%] bottom-[35%]), door ~double height (h-16)
- Mini Utilities: TVA calculator (19%) with add/extract modes, RON formatting, copy buttons
- ROADMAP: new Phase 4B Pre-Launch Hardening with 10 structured tasks
- CLAUDE.md: bumped versions (Address Book 0.1.1, Mini Utilities 0.1.1, Hot Desk 0.1.1), Visual Copilot separate repo note
2026-03-08 14:08:48 +02:00
AI Assistant a6fa94deec docs + fix: eTerra health check keywords from real maintenance page
- Added real eTerra maintenance keywords observed 2026-03-08:
  'serviciu indisponibil', 'activități de mentenanță sunt în desfășurare'
- Extract actual maintenance message from HTML response for UI display
- Updated CLAUDE.md: ParcelSync module #15, Visual Copilot #16,
  eTerra/PostGIS integrations, TS strict gotchas, eTerra API rules
- Updated ROADMAP.md: Phase 7B (ParcelSync) with 5 completed tasks
- Updated SESSION-LOG.md: full session entry with bugs/learnings
2026-03-08 13:04:11 +02:00
AI Assistant b7a236c45a feat(parcel-sync): eTerra health check + maintenance detection
- New eterra-health.ts service: pings eTerra periodically (3min),
  detects maintenance (503, keywords), tracks consecutive failures
- New /api/eterra/health endpoint for explicit health queries
- Session route blocks login when eTerra is in maintenance (503 response)
- GET /api/eterra/session now includes eterraAvailable/eterraMaintenance
- ConnectionPill shows amber 'Mentenanță' state with AlertTriangle icon
  instead of confusing red error when eTerra is down
- Auto-connect skips when maintenance detected, retries when back online
- 30s session poll auto-detects recovery and re-enables auto-connect
2026-03-08 10:28:30 +02:00
AI Assistant 6557cd5374 feat(parcel-sync): per-UAT analytics dashboard in Database tab
- New API route /api/eterra/uat-dashboard with SQL aggregates
  (area stats, intravilan/extravilan split, land use, top owners, fun facts)
- CSS-only dashboard component: KPI cards, donut ring, bar charts
- Dashboard button on each UAT card in DB tab, expands panel below
2026-03-08 10:18:34 +02:00
AI Assistant 6558c690f5 feat(parcel-sync): owner name search (proprietar) in Search tab
- New search mode toggle: Nr. Cadastral / Proprietar
- Owner search queries:
  1. Local DB first (enrichment PROPRIETARI/PROPRIETARI_VECHI ILIKE)
  2. eTerra API fallback (tries personName/titularName/ownerName filter keys)
- DB search works offline (no eTerra connection needed) — uses enriched data
- New API route: POST /api/eterra/search-owner
- New eterra-client method: searchImmovableByOwnerName()
- Owner results show source badge (DB local / eTerra online)
- Results can be added to saved list and exported as CSV
- Relaxed search tab guard: only requires UAT selection (not eTerra connection)
- Cadastral search still requires eTerra connection (shows hint when offline)
2026-03-08 03:48:23 +02:00
AI Assistant 8bb4a47ac5 fix(eterra): increase default timeout 40s -> 120s for large geometry pages
- DEFAULT_TIMEOUT_MS: 40_000 -> 120_000 (1000 features with full geometry
  from Feleacu regularly exceed 40s on the eTerra server)
- Add timeoutMs option to syncLayer() for caller override
- syncLayer now passes timeoutMs through to EterraClient.create()

Fixes 'timeout of 40000ms exceeded' on TERENURI_ACTIVE sync.
2026-03-08 03:31:18 +02:00
AI Assistant d7d78c0cc1 fix(eterra-client): reduce default pageSize to 1000 + retry on ArcGIS errors
- DEFAULT_PAGE_SIZE: 2000 -> 1000 (matches eTerra maxRecordCount, avoids
  requesting more than the server supports on first try)
- PAGE_SIZE_FALLBACKS: [500, 200] (removed 1000 since it's now the default)
- Add retry-once logic for 'Error performing query operation':
  Wait 2s and retry same page before falling to smaller sizes.
  These errors are often transient server-side timeouts.
- Longer delay (1s vs 0.5s) between page size fallback attempts

Fixes Feleacu (7951 features) background sync failure.
2026-03-08 03:06:44 +02:00
AI Assistant 041bfd4138 fix(parcel-sync): fix ArcGIS 1000 server cap pagination + scan improvements
- eterra-client: detect server maxRecordCount cap in fetchAllLayerByWhere
  When server returns exactly 1000 (or other round cap) but we asked for 2000,
  recognize this as a server limit, adjust pageSize, and CONTINUE paginating.
  Previously: 1000 < 2000 -> break (lost all data beyond page 1).

- no-geom-sync: count layers first, pass total to fetchAllLayer
  Belt-and-suspenders: even if cap detection misses, known total prevents
  early termination. Also use pageSize 1000 to match typical server cap.
  Clădiri count uses countLayer instead of fetching all OBJECTIDs.

- UI: add include-no-geom checkbox in background sync section
  Users can toggle it independently of scan status.
  Shows '(scanare in curs)' hint when scan is still running.
2026-03-08 02:37:39 +02:00
AI Assistant d12f01fc02 fix(parcel-sync): add 2min timeout to no-geom scan, non-blocking UI
- Server: Promise.race with 120s timeout on no-geom-scan API route
- Client: AbortController with 120s timeout on scan fetch
- UI: show 'max 2 min' during scanning + hint that buttons work without scan
- UI: timeout state shows retry button + explains no-geom won't be available
- Prevents indefinitely stuck 'Se scanează...' on slow eTerra responses
2026-03-08 02:28:51 +02:00
AI Assistant e57ca88e7e fix: increase background job progress retention to 6h, localStorage recovery to 8h 2026-03-08 01:59:09 +02:00
AI Assistant c43082baee feat(parcel-sync): background sync + download from DB
- New POST /api/eterra/sync-background: fire-and-forget server-side processing
  Starts sync + optional enrichment in background, returns 202 immediately.
  Progress tracked via existing /api/eterra/progress polling.
  Work continues in Node.js event loop even if browser is closed.
  Progress persists 1 hour for background jobs (vs 60s for normal).

- Enhanced POST /api/eterra/export-local: base/magic mode support
  mode=base: ZIP with terenuri.gpkg + cladiri.gpkg from local DB
  mode=magic: adds terenuri_magic.gpkg (enrichment merged, includes no-geom),
  terenuri_complet.csv, raport_calitate.txt, export_report.json
  All from PostgreSQL — zero eTerra API calls, instant download.

- UI: background sync section in Export tab
  'Sync fundal Baza/Magic' buttons: start background processing
  'Descarc─â din DB Baza/Magic' buttons: instant download from local DB
  Background job progress card with indigo theme (distinct from export)
  localStorage job recovery: resume polling after page refresh
  'Descarc─â din DB' button shown on completion
2026-03-08 01:53:24 +02:00
AI Assistant bcc7a54325 perf: reverse enrichment order — direct parcel details first, skip immApps
- fetchImmovableParcelDetails called FIRST (1 call, no applicationId needed)
- app-based fetchParcelFolosinte only as fallback when direct returns nothing
- SOLICITANT skipped entirely (was always '-' for old CF records)
- Remove unused pickApplication helper
- Net savings: ~500+ API calls per UAT enrichment (50-65% reduction)
- copycf/get returns same data as list (no enrichment value, kept as utility)
2026-03-08 01:15:28 +02:00
AI Assistant aee28b6768 feat: filter no-geom by IE status (hasLandbook), add checkIfIsIE + CF PDF APIs
QUALITY GATE TIGHTENED:
No-geometry import now requires hasLandbook=1 (imobil electronic).
This filters out immovables without carte funciara — they have no
CF data, no owners, no parcel details to extract. For Cosbuc this
reduces useful no-geom from ~1916 to ~468 (only IEs with real data).

Three-tier quality gate:
1. Active (status=1)
2. Has landbook (hasLandbook=1) — is electronic immovable  [NEW]
3. Has identification (cadRef/paperLbNo/paperCadNo) OR area

CLEANUP also updated: DB cleanup now removes stale no-geom records
that don't pass the tightened gate (existing non-IE records will be
cleaned on next import run).

NEW API METHODS (eterra-client):
- checkIfIsIE(adminUnitId, paperCadNo, topNo, paperCfNo) → boolean
  Calls /api/immovable/checkIfIsIE — verifies IE status per-parcel
  Available for future per-item verification if needed
- getCfExtractUrl(immovablePk, workspaceId) → string
  Returns URL for /api/cf/landbook/copycf/get/{pk}/{ws}/0/true
  Downloads the CF extract as PDF blob (future enrichment)

UI updated: 'Filtrate' label now says 'fara CF/inactive/fara date'
to reflect the new hasLandbook filter.
2026-03-08 00:57:16 +02:00
AI Assistant f09eaaad7c feat: enrichment fallback via direct parcel details endpoint
PROBLEM:
For no-geometry parcels (and many geometry parcels without application
IDs), CATEGORIE_FOLOSINTA was always '-' because:
1. fetchImmAppsByImmovable returned no apps (no applicationId)
2. Without appId, fetchParcelFolosinte was skipped entirely
3. No fallback existed

DISCOVERY (from eTerra UI investigation):
The endpoint /api/immovable/details/parcels/list/{wp}/{pk}/{page}/{size}
returns parcel use categories DIRECTLY — no applicationId needed.
Example: [{useCategory:'arabil', intravilan:'Necunoscut', parcelPk:17753903}]

FIX:
- After the app-based CATEGORIE_FOLOSINTA attempt, if result is still '-',
  fall back to fetchImmovableParcelDetails (the direct endpoint)
- formatCategories now handles both API formats:
  - App-based: categorieFolosinta + suprafata fields
  - Direct: useCategory field (no area — shows category name only)
- When direct endpoint provides area=0, format shows just the category
  name without ':0' (e.g. 'arabil; faneata' instead of 'arabil:0; faneata:0')
- Also picks up intravilan from direct endpoint if app-based was empty
- Fixed fetchImmovableParcelDetails default size: 1 → 20 (one immovable
  can have multiple parcels, e.g. IE 25332 has 2: arabil + faneata)
- Results are cached in folCache to avoid duplicate requests
2026-03-08 00:46:02 +02:00
AI Assistant a7c9e8a6cc fix: robust layer fetch (multi-fallback page sizes, error cause), neutral 505 color
LAYER FETCH:
- fetchAllLayerByWhere now falls back through 2000 → 1000 → 500 → 200
  instead of just 2000 → 1000 before giving up
- 500ms delay between fallback attempts to let eTerra recover
- Error message now includes the original cause:
  'Failed to fetch layer TERENURI_ACTIVE: Session expired (401)'
  instead of just 'Failed to fetch layer TERENURI_ACTIVE'

DISPLAY:
- 505 terenuri count no longer green (was emerald-600, now neutral semibold)
  It's just a data value, not a status indicator
2026-03-07 22:01:17 +02:00
AI Assistant b287b4c34b fix: stable scan display, accurate workflow preview, cladiri count
ROOT CAUSE: The cross-reference between immovable list and GIS layer
produces wildly different matchedCount on each scan (320, 430, 629, 433)
because the eTerra immovable/list API with inscrisCF=-1 returns
inconsistent results across calls. The GIS layer count (505) is stable.

SCAN DISPLAY — now uses only stable numbers:
- Header shows 'Layer GIS: 505 terenuri + X cladiri' (stable ArcGIS count)
- Shows 'Lista imobile: 2.717 (estimat ~2.212 fara geometrie)' using
  simple subtraction totalImmovables - remoteGisCount
- Cross-ref matchedCount kept internally for import logic, but NOT shown
  as the primary number — eliminates visual instability
- hasNoGeomParcels now uses estimated count (stable)

WORKFLOW PREVIEW — now accurate:
- Step 1: 'Sync GIS — descarca 505 terenuri + X cladiri' (separate counts)
  or 'skip (date proaspete in DB)' when fresh
- Step 2 (enrichment): Fixed 'deja imbogatite' bug when DB is empty.
  Now correctly computes what WILL be in DB after sync completes:
  geoAfterSync + noGeomAfterImport - localDbEnrichedComplete
- Steps 3-4 unchanged

CLADIRI COUNT:
- Scan now also fetches CLADIRI_ACTIVE layer count (lightweight, OBJECTID only)
- New field remoteCladiriCount in NoGeomScanResult
- Displayed in header and workflow step 1
- Non-fatal: if CLADIRI fetch fails, just shows 0
2026-03-07 21:40:38 +02:00
AI Assistant 531c3b0858 fix: scan numbers always add up, match quality tracking, pipeline audit
SCAN DISPLAY:
- Use matchedCount (withGeometry) for 'cu geometrie' — ALWAYS adds up
  with noGeomCount to equal totalImmovables (ground truth arithmetic)
- Show remoteGisCount separately as 'Layer GIS: N features (se descarca toate)'
- When remoteGisCount != matchedCount, show matching detail with breakdown
  (X potrivite + cadRef/ID split) so mismatches are transparent
- Workflow preview step 1 still uses remoteGisCount (correct: all GIS
  features get downloaded regardless of matching)

MATCH QUALITY TRACKING:
- New fields: matchedByRef, matchedById in NoGeomScanResult
- Track how many immovables matched by cadastral ref vs by IMMOVABLE_ID
- Console log match quality for server-side debugging
- scannedAt timestamp for audit trail

PIPELINE AUDIT (export report):
- New 'pipeline' section in export_report.json with full trace:
  syncedGis, noGeometry (imported/cleaned/skipped), enriched, finalDb
- raport_calitate.txt now has PIPELINE section before quality analysis
  showing exactly what happened at each step
- Capture noGeomCleaned + noGeomSkipped in addition to noGeomImported
2026-03-07 21:22:29 +02:00
AI Assistant 1e6888a32a fix: show remoteGisCount (505) as cu geometrie, add no-geom cleanup step
- UI: scan card now shows remoteGisCount instead of matchedCount (withGeometry)
  as the primary 'cu geometrie' number — this is the true GIS layer feature count
- UI: workflow preview step 1 shows remoteGisCount for download count
- UI: mismatch note reworded as secondary detail about cross-reference matching
- Import: automatic cleanup step at start of syncNoGeometryParcels
  - Builds valid immovablePk set from fresh list (active + identification/area)
  - Deletes stale NO_GEOMETRY records not in the valid set
  - Reports cleaned count in result + progress note
- NoGeomSyncResult type: added 'cleaned' field
- Gitignore: temp-db-check.cjs
2026-03-07 21:00:43 +02:00
AI Assistant f9594fff71 fix(parcel-sync): paperCfNo bug, status filter, enrichment robustness
BUGS FIXED:
- paperCfNo does NOT exist in eTerra API — field is paperLbNo
  Renamed withPaperCf → withPaperLb everywhere (type, scan, UI)
- Area fields: only measuredArea and legalArea exist on immovable/list
  Removed phantom area/areaValue/suprafata checks from import filter

FILTERING TIGHTENED:
- Quality gate now requires status=1 (active) in eTerra
- Items with status≠1 are filtered out before import
- Quality breakdown adds: withActiveStatus, withLandbook counters
- Import attributes now store MEASURED_AREA, LEGAL_AREA, HAS_LANDBOOK
- workspace.nomenPk used instead of workspacePk for accuracy

ENRICHMENT ROBUSTNESS:
- Area fallback: when AREA_VALUE is missing (no-geom), enrichment
  now falls back to listItem.measuredArea/legalArea from immovable list
- Post-enrichment verification: logs 100% coverage or warns about gaps
- EnrichResult type extended with totalFeatures + unenrichedCount

UI UPDATES:
- Quality grid shows 6 stats: cadRef, CF/LB, paperCad, area, active, landbook
- Filter explanation updated: 'inactive sau fără date' instead of old text
2026-03-07 20:25:05 +02:00
AI Assistant af2631920f feat(parcel-sync): quality gate filter for no-geom import + diagnostic endpoint
- Filter no-geom items before import: must have identification (cadRef/CF/paperCad/paperLb) OR area
- Multi-field area extraction: area, measuredArea, areaValue, suprafata
- Scan quality breakdown: withCadRef, withPaperCf, withPaperCad, withArea, useful, empty
- Added paperLbNo to quality analysis and samples
- UI: quality breakdown grid in scan card
- UI: filtered count in workflow preview (shows useful, not total)
- UI: enrichment estimate uses useful count
- New diagnostic endpoint /api/eterra/no-geom-debug for field inspection
2026-03-07 19:58:43 +02:00
AI Assistant 681b52e816 feat: quality analysis for no-geom parcels + raport_calitate.txt
Scan phase:
- qualityBreakdown on NoGeomScanResult: withCadRef, withPaperCad,
  withPaperCf, withArea, useful vs empty counts
- UI scan card shows quality grid before deciding to export

Export phase:
- Comprehensive enrichment quality analysis: owners, CF, address,
  area, category, building — split by with-geom vs no-geom
- raport_calitate.txt in ZIP: human-readable Romanian report with
  per-category breakdowns and percentage stats
- export_report.json includes full qualityAnalysis object
- Progress completion note shows quality summary inline
2026-03-07 19:23:57 +02:00
AI Assistant 53914c7fc3 fix: scan math consistency + stale enrichment detection + re-enrichment
- withGeometry = matched immovable count (not GIS feature count) — numbers always add up
- Added remoteGisCount to show raw GIS layer count separately
- Enrichment completeness check: ENRICHMENT_REQUIRED_KEYS 7-field schema
- localDbEnrichedComplete vs localDbEnriched detects stale enrichment
- UI: orange warning when enrichment incomplete (missing PROPRIETARI_VECHI)
- UI: workflow preview uses enrichedComplete for accurate time estimate
- UI: note when GIS feature count differs from matched immovable count
- enrich-service: re-enriches features with incomplete schema instead of skipping
2026-03-07 18:29:03 +02:00
AI Assistant ba579d75c1 feat(parcel-sync): include no-geometry rows in Magic GPKG + HAS_GEOMETRY column
- Magic GPKG (terenuri_magic.gpkg) now contains ALL records:
  rows with geometry render as polygons, rows without have null geom
  but still carry all attribute/enrichment data (QGIS shows them fine)
- Added HAS_GEOMETRY column to Magic GPKG fields (0 or 1)
- GPKG builder now supports includeNullGeometry option: splits features
  into spatial-first (creates table), then appends null-geom rows
- Base terenuri.gpkg / cladiri.gpkg unchanged (spatial only)
- CSV still has all records as before
- GeoJsonFeature type now allows null geometry
- Reproject: null geometry guard added
- UI text updated: no longer says 'Nu apar in GPKG'
2026-03-07 18:06:28 +02:00
AI Assistant 96859dde4f feat(parcel-sync): scan shows local DB context + Magic workflow preview
- NoGeomScanResult now includes: localDbTotal, localDbWithGeom, localDbNoGeom,
  localDbEnriched, localSyncFresh (parallel DB queries, fast)
- Scan card shows 'Baza de date locala: X cu geometrie + Y fara + Z imbogatite'
- Workflow preview shows numbered steps with smart estimates:
  step 1 shows 'skip (date proaspete)' when sync is fresh
  step 2 shows '~N noi de importat' or 'deja importate' for no-geom
  step 3 shows '~N de procesat (~M min)' or 'deja imbogatite' for enrichment
- All-geometry card also shows local DB summary
- User can see exactly what will happen before pressing Magic
2026-03-07 17:50:34 +02:00
AI Assistant b01ea9fc37 fix(parcel-sync): scan uses remote GIS layer instead of empty local DB
- scanNoGeometryParcels now fetches TERENURI_ACTIVE features from remote
  ArcGIS (lightweight, no geometry) to cross-reference with eTerra immovable list
- Cross-references by both NATIONAL_CADASTRAL_REFERENCE and IMMOVABLE_ID
- Works correctly regardless of whether user has synced to local DB
- Renamed totalInDb -> withGeometry in NoGeomScanResult, UI, and API
- Extended fetchAllLayer() to forward outFields/returnGeometry options
2026-03-07 17:32:49 +02:00
AI Assistant 40b9522e12 fix: remove all hardcoded workspaceId=65 + add robustness for large UATs
- enrich-service: resolve workspacePk from feature attrs / GisUat DB / ArcGIS
  (was hardcoded 65, broke enrichment for non-BN counties)
- enrich-service: skip already-enriched features (resume after crash)
- no-geom-sync: use resolved wsPk in synthetic attributes
- no-geom-sync: batched DB inserts (50/batch) with retry + exponential backoff
- Fixes: Magic export for Cluj/other counties getting empty enrichment
2026-03-07 17:17:55 +02:00
AI Assistant db6ac5d3a3 fix: dynamic workspaceId for no-geometry scan (was hardcoded 65)
- resolveWorkspacePk chain: explicit param -> GisUat DB -> ArcGIS layer query
- UI passes workspacePk from UAT selection to scan API
- Fixes: FELEACU (Cluj, workspace!=65) returning 0 immovables
- Better messaging: shows X total, Y with geometry, Z without
- Shows warning when 0 immovables found (workspace resolution failed)
2026-03-07 16:52:20 +02:00
AI Assistant ddde2db900 fix: auto-scan race condition for no-geometry scan
- handleNoGeomScan accepts optional targetSiruta parameter
- useRef tracks last auto-scanned siruta to prevent duplicate scans
- Show zero result on error instead of hiding card (null)
- Fixes: FELEACU scan disappearing after 2s while COSBUC worked
2026-03-07 16:35:26 +02:00
AI Assistant 5861e06ddb fix(parcel-sync): auto-scan no-geometry + redesign UI card
- Auto-scan triggers when UAT selected + connected (no manual click needed)
- Three states: scanning spinner, found N parcels (amber alert card), all OK (green check)
- Checkbox more prominent: only shown when no-geom parcels exist
- Re-scan button available, scan result cached per siruta
- AlertTriangle icon for visual warning
2026-03-07 13:06:45 +02:00
AI Assistant 30915e8628 feat(parcel-sync): import eTerra immovables without geometry
- Add geometrySource field to GisFeature (NO_GEOMETRY marker)
- New no-geom-sync service: scan + import parcels missing from GIS layer
- Uses negative immovablePk as objectId to avoid @@unique collision
- New /api/eterra/no-geom-scan endpoint for counting
- Export-bundle: includeNoGeometry flag, imports before enrich
- CSV export: new HAS_GEOMETRY column (0/1)
- GPKG: still geometry-only (unchanged)
- UI: checkbox + scan button on Export tab
- Baza de Date tab: shows no-geometry counts per UAT
- db-summary API: includes noGeomCount per layer
2026-03-07 12:58:10 +02:00
AI Assistant d50b9ea0e2 ParcelSync: PROPRIETARI_VECHI in enrichment + global DB summary tab (all UATs without login) 2026-03-07 12:16:34 +02:00
AI Assistant abd00aecfb ParcelSync: DB status card on Export tab + Baza de Date tab with per-category sync 2026-03-07 12:00:20 +02:00
AI Assistant de1e779770 fix(parcel-sync): progress display stuck + numbers jumping during sync
2 bugs:
1. After Magic/base download completes, progress bar stayed stuck at
   77% because exportProgress was never updated to 'done' client-side.
   Fix: set progress to 'Finalizat' + 100% after successful blob download.

2. syncLayer overwrote the export route's weighted percentages (0-100)
   with raw feature counts (50/200), causing progress bar to jump.
   Fix: when isSubStep=true, sync writes phase/note/phaseCurrent/phaseTotal
   but preserves the parent route's downloaded/total weighted values.
2026-03-07 11:45:52 +02:00
AI Assistant 097d010b5d fix(parcel-sync): sync progress visible during GPKG/bundle export
3 bugs fixed:
- syncLayer was called without jobId -> user saw no progress duringSync
- syncLayer set status:'done' prematurely -> client stopped polling before GPKG phase
- syncLayer errors were silently ignored -> confusing 'no features in DB' error

Added isSubStep option to syncLayer: when true, keeps status as 'running'
and doesn't schedule clearProgress. Export routes now pass jobId + isSubStep
so the real sync progress (Descărcare features 50/200) is visible in the UI.
2026-03-07 11:23:36 +02:00
AI Assistant b0927ee075 feat(parcel-sync): sync-first architecture — DB as ground truth
- Rewrite export-bundle to sync-first: check freshness -> sync layers -> enrich (magic) -> build GPKG/CSV from local DB
- Rewrite export-layer-gpkg to sync-first: sync if stale -> export from DB
- Create enrich-service.ts: extracted magic enrichment logic (CF, owners, addresses) with DB storage
- Add enrichment + enrichedAt columns to GisFeature schema
- Update PostGIS views to include enrichment data
- UI: update button labels for sync-first semantics, refresh sync status after exports
- Smart caching: skip sync if data is fresh (168h / 1 week default)
2026-03-07 11:12:54 +02:00
AI Assistant 0d0b1f8c9f feat(parcel-sync): native PostGIS geometry support for QGIS
- Remove postgresqlExtensions/postgis from Prisma schema (PostGIS not yet installed)
- Add prisma/postgis-setup.sql: trigger auto-converts GeoJSON→native geometry,
  GiST spatial index, QGIS-friendly views (gis_terenuri, gis_cladiri, etc.)
- Add POST /api/eterra/setup-postgis endpoint (idempotent, runs all SQL setup)
- Add safety-net raw SQL in sync-service: backfills geom after upsert phase
- Add QGIS/PostGIS setup card in layer catalog UI with connection info
- Schema comment documents the trigger-managed 'geom' column approach
2026-03-07 10:25:30 +02:00
AI Assistant b0c4bf91d7 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.
2026-03-07 10:05:39 +02:00
AI Assistant f73e639e4f fix(parcel-sync): quote all CSV fields + layer feature counts + drumul de azi
- CSV export: all fields properly quoted to prevent column misalignment
  when values contain commas (e.g. nrTopo with multiple topo numbers)
- Layer catalog: 'Numara toate' button fetches feature count per layer
  via /api/eterra/layers/summary (now supports session auth)
- Feature counts displayed as badges on each layer and category total
- 'Drumul de azi' section: persists today's layer counts in localStorage
  grouped by SIRUTA with timestamps
2026-03-06 23:19:58 +02:00
AI Assistant 0b049274b1 fix(search): robust address from all structured fields, multi-address support
- Always build from structured fields first (street, postalNo, building, locality)
- Fall back to addressDescription ONLY when no structured fields exist
- Support multiple addresses per immovable (joined with |)
- Deduplicate identical addresses
- Handle addressDescription as last-resort fallback
2026-03-06 22:57:11 +02:00
AI Assistant 742acb2d74 fix(search): proper address from all fields, parcel details endpoint, remove strikethrough
- Address: use street.dictionaryItem.name (Strada/Alee/etc) + street.name,
  postalNo as house number, buildingEntryNo/FloorNo/UnitNo/SectionNo
  for apartment details, locality.name, county.name
- Area+intravilan: fetch from /api/immovable/details/parcels/list (direct
  endpoint with area, intravilan, useCategory) before trying immApps
- Owners: remove strikethrough, use smaller neutral font (text-[11px]
  text-muted-foreground/80), rename label to 'Proprietari anteriori'
2026-03-06 22:50:57 +02:00