These env vars were previously hardcoded in source code and removed during
the production audit. Now properly configured in docker-compose.yml.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Export fix:
- Replaced DropdownMenu with direct DXF/GPKG buttons in SelectionToolbar.
Radix dropdown portals don't work inside fixed z-[110] containers.
Direct buttons work reliably on all platforms.
Mobile RGI cards:
- Single-row compact layout: icon + nr cerere + solicitant + termen + status
- Smaller icons (3.5), tighter spacing, shorter status labels
- No Card wrapper — lightweight border div for less visual weight
Mobile filters:
- Tighter spacing, smaller labels
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Selection toolbar:
- Moved OUTSIDE map container div to a fixed viewport position
(bottom-4, z-[110]). iOS Safari clips absolute elements inside
calc(100vh) containers — fixed positioning solves this.
- Only shown when UAT selected and has data.
Mobile top layout:
- UAT card takes full width (right-2 not right-[140px])
- Basemap switcher at top-[52px] left-2 on mobile (below UAT card)
- Desktop: unchanged (top-right offset from zoom controls)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ZIP download:
- Both portal and RGI test page now create a single ZIP archive
(Documente_eliberate_{appNo}.zip) instead of sequential downloads
- Uses JSZip (already in project dependencies)
Portal mobile:
- Basemap switcher drops below UAT card on mobile (top-14 sm:top-2)
- Selection toolbar at bottom-3 with z-30 (always visible)
- Click on feature centers map on that parcel (flyTo)
Tooltips:
- Green download icon: "Descarca arhiva ZIP cu documentele cererii X"
- Updated on both portal and RGI test page
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Freehand drawing fix:
- Disable dragPan when in freehand mode (was only disabling dblclick
zoom). Without this, clicks were interpreted as pan gestures.
- Re-enable dragPan when exiting freehand mode.
Click highlight:
- Clicking a parcel in "off" mode now highlights it with the selection
layer (amber fill + orange outline). Clicking empty space clears it.
- Provides visual feedback for which parcel was clicked.
Mobile toolbar:
- Moved selection toolbar higher (bottom-12 on mobile) with z-20
to ensure it's above MapLibre attribution bar.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SelectionToolbar: new hideEnrichment prop hides the Enrichment button.
Portal uses it to show only Export + Clear in selection toolbar.
Portal feature panel: added disabled "Solicita extras CF" button with
tooltip "Sectiune platita — contacteaza administratorul".
Initial map zoom: starts at zoom 15 (close-up) instead of 7 (Romania
overview). Prevents the UAT boundaries flash before fitBounds runs.
Applied to both ParcelSync Harta tab and Portal.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
RGI (both pages):
- Default sort: Termen descrescator (cel mai in viitor sus)
Portal map:
- Basemap switcher moved left (right-12) to avoid zoom controls overlap
- Selection toolbar moved up (bottom-8) to avoid attribution overlap
- Download button has title tooltip on mobile cards
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixed:
- Added setLayoutProperty to MapLike type (was missing, broke build)
- Replaced FeatureInfoPanel with simple inline panel showing only:
SIRUTA, Nr. cadastral, Suprafata (no enrichment, no CF extract,
no "Actualizeaza" button)
- Fixed unknown type errors in JSX property access
- Hidden basemap boundaries + UAT layers for cleaner map
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The fitBounds effect was re-triggered every time mapReady toggled
(which happened frequently due to the source-checking polling interval).
Now uses boundsFittedForSirutaRef to ensure fitBounds runs only ONCE
per siruta selection — changing UAT still zooms correctly, but manual
zoom/pan is preserved afterwards.
Fixed in both ParcelSync Harta tab and Portal map.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Portal layout: removed conflicting (portal)/layout.tsx that had
duplicate html/body tags. Portal page now uses fixed overlay
(z-[100]) that covers the entire screen including sidebar.
Middleware: portal-only users (dan.tiurbe) are automatically
redirected from any non-portal route to /portal. They can still
access /api/ and /auth/ routes normally.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Default columns: Nr. cerere, Solicitant, Termen, Status, Rezolutie, UAT
(matching user's preferred view). Obiect, Identificatori, Deponent,
Data depunere now off by default.
Date sort: dueDate and appDate columns now sort by raw timestamp
(not by DD.MM.YYYY string which sorted incorrectly).
Filenames: removed long documentPk from filename. Now uses
DocType_AppNo.pdf (e.g. Receptie_tehnica_66903.pdf). Duplicate
types get suffix: Receptie_tehnica_66903_2.pdf.
Green icon: click downloads ALL documents from that application
sequentially. Shows spinner while downloading. Tooltip shows
"Nr. 66903 — click descarca toate" + details.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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>