Page improvements:
- County dropdown with all 41 Romanian counties (default Cluj)
- orgUnitId auto-computed (countyId * 1000 + 2)
- Sortable columns: click header to sort asc/desc with arrow indicators
- Search input: filters across all visible columns (diacritics-insensitive)
- Soft blocked message: amber toast "Documentul nu este inca disponibil"
auto-hides after 5s (no more redirect errors)
Download improvements:
- Meaningful filenames: {docType}_{appNo}.pdf (e.g. Harti_planuri_66903.pdf)
- Romanian diacritics stripped from filenames
- Returns { blocked: true } JSON instead of redirect when unavailable
Bug fix: replaced incorrect useState() side-effect with proper useEffect()
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The dueDate-based lock was incorrect: some documents with future
dueDate ARE downloadable. The availability depends on eTerra internal
rules, not predictably on dueDate.
Now all documents show a download button. If server-side download
fails (fileVisibility 404), it redirects to eTerra direct URL
which works in the user's browser session.
Filters changed to: Solutionate / Confirmate / Toate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
eTerra blocks document downloads until dueDate passes (new rule).
Now the page shows:
Filter modes:
- "Descarcabile acum" (default) — solved + dueDate passed
- "In asteptare" — solved + dueDate future (documents locked)
- "Toate" — no filter
UI indicators:
- Green download icon: ready to download
- Amber clock icon: solved but locked until dueDate
- Documents panel shows "Disponibile de la DD.MM.YYYY" badge when locked
- Download button replaced with date badge for locked documents
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Before downloading, now calls:
1. verifyCurrentActorAuthenticated — sets actor context in session
2. appdetail/details — loads application context
Then tries download regardless of fileVisibility result.
The session context might be what enables downloads that previously
returned 404.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When fileVisibility returns OK → download server-side (fast).
When not available → HTTP 302 redirect to eTerra direct URL.
User's browser session handles authentication automatically.
This means: if logged into eTerra in browser, ALL documents download.
If not logged in, eTerra shows its own login page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Download route simplified:
1. fileVisibility check — if 404, returns "indisponibil" + eTerra URL
2. Single download pattern (the one that works)
When document not available server-side, response includes direct
eTerra URL as fallback. No more 7 pattern attempts = much faster.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Server credentials can list RGI applications and docs but can't download
files (confirmOnView returns false — only the current actor/deponent
has download permission).
Download now opens the eTerra URL directly in the user's browser,
which uses their existing eTerra session cookie. Flow:
1. Hidden iframe calls confirmOnView
2. After 500ms, opens downloadFile URL in new tab
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Download route now:
- Calls fileVisibility with documentTypeId (if provided)
- Calls confirmOnView with documentPk
- Tries 3 different download URL patterns until one works
- Add &debug=1 to see diagnostic results instead of downloading
- Page now passes documentTypeId in download link
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaced single colSpan td with flex layout → proper td per column.
Headers and data cells now align correctly. Expanded docs row uses
colSpan only for the detail panel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
eTerra returns 404 (not 401) when session expires during file download
because it redirects to login page. Now rgiDownload:
- Uses validateStatus to catch all statuses
- Re-logins and retries on 401/302/404
- Sets Accept: */* header for binary downloads
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rewrote RGI test page:
- Clean card-based UI with status icons (green=solved, amber=pending)
- Click row to expand and see issued documents
- Each document has a direct "Descarca" download button
- Filter toggle "Doar solutionate cu termen viitor"
- No more raw JSON tables
Download route now follows eTerra's 3-step flow:
1. fileVisibility — check access, get fileId
2. confirmOnView — confirm document view
3. loadDocument/downloadFile — actual file download
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New eTerra RGI (Registrul General de Intrare) integration:
API routes (/api/eterra/rgi/):
- POST /applications — list applications with workspace/year filters
- GET /details?applicationId=X — application details
- GET /issued-docs?applicationId=X&workspaceId=Y — issued documents list
- GET /download-doc?wid=X&aid=Y&did=Z — download issued document
EterraClient: added rgiPost, rgiGet, rgiDownload methods for RGI API.
Test page (/rgi-test):
- Filters: workspace, orgUnit, year
- Toggle: "Doar solutionate cu termen viitor"
- Table with application list, expandable issued docs, download links
- Raw JSON debug sections (collapsible)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
MapViewer destroys and recreates the map when basemap changes. The
readiness polling now detects when custom sources are missing (new map
instance) and resets appliedSirutaRef + prevCheckSirutaRef, which
triggers all effects to re-run: siruta filter, enrichment overlay,
boundary mismatch GeoJSON, and fitBounds.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Map tab: when UAT has no local data, shows a "Sincronizează terenuri,
clădiri și intravilan" button that triggers background base sync.
Sync background (base mode): now also syncs LIMITE_INTRAV_DYNAMIC layer
(intravilan boundaries) alongside TERENURI_ACTIVE + CLADIRI_ACTIVE.
Non-critical — if intravilan fails, the rest continues.
Also fixed remaining \u2192 unicode escapes in export/layers/epay tabs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mismatch fill/line layers now have minzoom: 13 (same as normal parcels).
Labels have minzoom: 16 with text-size: 10 and text-allow-overlap: false
(same settings as the regular parcel cadastral labels).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ePay + eTerra pills: removed animate-ping, now show static green dot
when connected (no more spinning appearance)
- Legend moved to top-left, hides when FeatureInfoPanel is open
(no more overlap)
- Boundary mismatch parcels now show cadastral numbers as labels
(orange for foreign, purple for edge parcels)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of trying to color buildings directly (which requires an
unreliable cadastralRef join), the parcel itself gets a strong red fill
(opacity 0.45) when has_building=1 AND build_legal=0. Buildings sitting
on these parcels are visually on a red background.
Color scheme:
- Red fill: building without legal docs
- Light blue fill: building with legal
- Green fill: enriched, no building
- Yellow/amber fill: no enrichment
Removed broken gis_cladiri_status overlay. Simplified legend.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PostgreSQL CREATE OR REPLACE VIEW fails when column structure changes.
Now drops views first, then recreates them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
LEFT JOIN caused duplicate rows and column conflicts. Replaced with a
correlated subquery (LIMIT 1) to safely look up BUILD_LEGAL from the
parent parcel's enrichment.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Click fix:
- Keep l-terenuri-fill visible but transparent (opacity 0) so it still
catches click events for FeatureInfoPanel. Enrichment overlay renders
underneath.
Color changes:
- No enrichment: amber/yellow fill (was light green)
- With enrichment: green fill
- Buildings: red fill = no legal docs, blue = legal, gray = unknown
- Parcel outline: red = building no legal, blue = building legal
Boundary cross-check (/api/geoportal/boundary-check?siruta=X):
- Finds "foreign" parcels: registered in other UATs but geometrically
within this UAT boundary (orange dashed)
- Finds "edge" parcels: registered here but centroid outside boundary
(purple dashed)
- Alert banner shows count, legend updated with mismatch indicators
Martin config: added gis_cladiri_status source with build_legal property.
Enrichment views: gis_cladiri_status now JOINs parent parcel's BUILD_LEGAL.
Requires: docker restart martin + POST /api/geoportal/setup-enrichment-views
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Map tab now uses fitBounds (not flyTo with fixed zoom) to show entire
UAT extent when selected. Bounds are fetched and applied after map ready.
- Added gis_terenuri_status to martin.yaml so Martin serves enrichment
tiles (has_enrichment, has_building, build_legal properties).
- Removed center/zoom props from MapViewer — use fitBounds via handle.
- Requires `docker restart martin` on server for Martin to reload config.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The \u0103, \u00ee etc. escape sequences were rendering literally in JSX
text nodes instead of displaying ă, î, ț, ș characters.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Basemaps: added Google Satellite option
ANCPI ortofoto: fixed bbox conversion (all 4 corners, not just SW/NE)
Selection: ESC key and right-click exit selection mode, tooltips updated
UAT layers: removed fill (only lines + labels), less visual clutter
Proprietari vechi: greyed out (opacity-50) so current owners stand out
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Instead of reimplementing eTerra search logic (which missed most fields),
now calls the existing /api/eterra/search endpoint that already works
perfectly in ParcelSync. Same data, same format: proprietari, CF, CFvechi,
topo, intravilan, categorie, adresa, solicitant.
Per-parcel, 2-5 seconds, persists in DB.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Layer toggle fix: removed isStyleLoaded() check that silently blocked
visibility changes when OpenFreeMap style has pending sprite/font loads
2. Enrichment: "Actualizeaza" button always visible (re-fetch from eTerra)
replaces "Enrichment" button when data already exists
3. Panel updates with returned enrichment data immediately
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Enrichment: panel now updates immediately with returned data (was only showing message)
2. Layers: ALL data layers set to visibility:none immediately after creation,
then only enabled ones are shown. Fixes cladiri appearing when only terenuri toggled.
3. OpenFreeMap boundaries: also filter by source-layer="boundary" (more reliable)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces background UAT-wide enrichment with instant per-parcel search.
Uses eTerra searchImmovableByIdentifier (cadastral number lookup) which
returns in 1-3 seconds instead of minutes.
Extracts: NR_CF, proprietari (with shares), intravilan, categorie,
adresa, has_building, build_legal. Persists in DB immediately.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previous single-parcel enrichment wrote empty data (couldn't match in eTerra).
Now uses the original enrichFeatures() which properly fetches owners, CF, etc.
Changes:
- Enrichment runs in BACKGROUND (returns immediately with message)
- Clears bad enrichment data before re-running
- Tracks running enrichments to avoid duplicates
- GET /api/geoportal/enrich?siruta=... checks if enrichment is running
- Panel: hasRealEnrichment checks for CF/PROPRIETARI/CATEGORIE (not just NR_CAD)
- Enrichment button stays visible until real data exists
- Message: "Enrichment pornit in background. Datele vor aparea in 1-3 minute."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OpenFreeMap Liberty/Dark styles include admin boundary layers that show
even when our UAT toggle is off. Now hides all boundary/admin/border
layers from the basemap style on map load.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Layers:
- ALL layers OFF by default (just basemap on load)
- User activates what they need
Feature panel:
- Shows ALL enrichment fields: proprietari (full text, wrapping),
CF vechi, nr topo, adresa, solicitant, intravilan, categorie
- Building info with icon (cu acte / fara acte warning)
- hasEnrichment check relaxed (any non-empty field counts)
- Panel scrollable (max-h 60vh) for long data
- WrapRow for multi-line text (proprietari, adresa)
- Enrichment button visible when no enrichment data
- Enrichment auto-updates panel on success
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- UAT + Intravilan layers OFF by default (user activates when needed)
- Terenuri/Cladiri listed first in panel (most used)
- Bulk enrichment: per-feature with progress counter (3/10), success summary
- Progress text shown in toolbar during enrichment
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- After enrichment: panel updates immediately with returned data (no reload needed)
- "Comanda CF" button visible on any parcel with cadastral ref (not just enriched ones)
- "Descarca CF" shown when CF extract already exists in DB
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previous enrichment tried to enrich ALL parcels in a UAT (minutes).
Now enriches just the clicked parcel (seconds):
1. Finds the GisFeature by ID or objectId+siruta
2. Fetches immovable data from eTerra for that specific parcel
3. Persists enrichment in DB
4. Skips if enriched < 7 days ago
Auto-uses env credentials (ETERRA_USERNAME/PASSWORD) — no manual login needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Labels: add text-font ["Noto Sans Regular"] (OpenFreeMap compatible)
- Optimize views: gis_features/terenuri/cladiri/administrativ now exclude
attributes, enrichment, timestamps (huge JSON columns that made tiles slow)
- Views only include: id, layer_id, siruta, object_id, cadastral_ref,
area_value, is_active, geom
Run optimize-views again after deploy to apply slimmer views.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ST_SimplifyPreserveTopology in views runs on every Martin tile request,
causing constant CPU load. Fix: pre-compute simplified geometries into
dedicated columns (geom_z0, geom_z5, geom_z8) on the GisUat table.
POST /api/geoportal/optimize-views:
1. Adds geom_z0/z5/z8 columns to GisUat
2. Backfills with pre-computed simplifications (one-time cost)
3. Creates GiST spatial indexes on each
4. Replaces views to use pre-computed columns (zero CPU reads)
5. Updates trigger to auto-compute on INSERT/UPDATE
Setup banner: now checks optimization status and shows "Optimizeaza"
button if needed. One-click, then docker restart martin.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New API endpoints:
- POST /api/geoportal/enrich — enriches all parcels for a SIRUTA,
skips already-enriched, persists in GisFeature.enrichment column
- GET /api/geoportal/cf-status?nrCad=... — checks if CF extract exists,
returns download URL if available
Feature panel:
- No enrichment: "Enrichment" button (triggers eTerra sync for UAT)
- Has enrichment + CF available: "Descarca CF" button (direct download)
- Has enrichment + no CF: "Comanda CF" button (link to ePay tab)
- Copy button always visible
- After enrichment completes, panel auto-reloads data
Selection toolbar:
- Bulk "Enrichment" button for selected parcels (per unique SIRUTA)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rectangle mode (Dreptunghi):
- Mousedown starts drawing, mousemove shows amber overlay, mouseup selects
- All terenuri features in the drawn bbox are added to selection
- Map panning disabled during draw, re-enabled after
- Minimum 5px size to prevent accidental micro-selections
Freehand mode (Desen):
- Each click adds a point, polygon drawn with GeoJSON source
- Double-click closes polygon, selects features whose centroid is inside
- Ray-casting point-in-polygon algorithm for spatial filtering
- Double-click zoom disabled during freehand mode
Draw state clears when switching selection modes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- GET /api/geoportal/setup-views checks if zoom views exist
- POST creates them (idempotent)
- SetupBanner component: auto-checks on mount, shows amber banner if
views missing, button to create them, success message with docker
restart reminder, auto-hides when everything is ready
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>