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>
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>
React's useDeferredValue lets the input update immediately while
deferring the expensive filter (3186 items) to a lower priority.
Removes the setTimeout debounce in favor of React's built-in
concurrent rendering scheduler. Input stays responsive.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Checkbox on each row (ordered selection → numbered files in ZIP)
- "Descarcă selecție (N)" button appears when items selected
- Tooltip shows position in ZIP: "#1 in ZIP", "#2 in ZIP"
- Select-all checkbox in header
- Tooltips on Descarcă tot + Descarcă selecție buttons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The nested JSON in ePay HTML breaks [^}]* regex. New approach:
find all CF.stringValues independently, find all solutii independently,
then zip them by position (they appear in same order in HTML).
This correctly maps CF number → document for batch orders.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Re-download: all 7 orders re-downloaded using documentsByCadastral
for correct CF→document matching. No more hardcoded order→parcel map.
Tooltips on all CF extract UI elements:
- No extract: "Comandă extras CF (1 credit)"
- Valid: "Valid până la DD.MM.YYYY" + "Descarcă extras CF"
- Expired: "Expirat pe DD.MM.YYYY" + "Comandă extras CF nou (1 credit)"
- Processing: "Comanda în curs de procesare"
Animations: Loader2 spinner while ordering, transition to green check.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Critical fix: batch order documents are now matched by CF number
from parsed metadateCereri (documentsByCadastral), not by index.
Prevents PDF content mismatch when ePay returns docs in different order.
UAT search: name matches shown first, county-only matches after.
Typing "cluj" now shows CLUJ-NAPOCA before county "Cluj" matches.
Cleaned MinIO + DB of incorrectly mapped old test data.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Major rewrite:
- Queue now processes batches: addToCart×N → saveMetadata×N → ONE
submitOrder → poll → download ALL documents → store in MinIO
- Removed unique constraint on orderId (shared across batch items)
- Added step=download to test endpoint: downloads PDFs from 5
existing orders (9685480-9685484) and stores in MinIO
- step=order now uses enqueueBatch for 2 test parcels (61904, 309952)
as ONE ePay order instead of separate orders
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
EditCartSubmit returns 200 (not redirect) — Angular does client-side
redirect to CheckoutConfirmationSubmit.action. Added this step to
actually confirm the order before looking for the orderId.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
submitOrder now captures the previous orderId BEFORE submitting, then
searches for a NEW orderId that isn't in the knownOrderIds set. Queue
passes knownOrderIds between sequential items to prevent duplicate
orderId assignment (unique constraint violation).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Angular uses doPostAsFormMultipart — the save endpoint requires
multipart/form-data, not application/x-www-form-urlencoded.
Install form-data package and restore multipart upload.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
form-data package not installed — crashes at runtime. Use
URLSearchParams instead (the Angular source uses doPostAsForm
which is form-urlencoded, so this should work too).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Zero discovery calls needed! ePay internal county IDs are identical
to eTerra WORKSPACE_IDs (CLUJ=127, ALBA=10, etc.) and ePay UAT IDs
are SIRUTA codes (Cluj-Napoca=54975, Florești=57706). Queue now
uses workspacePk + siruta directly from GisUat DB.
Flow: AddToCart → saveMetadata → EditCartSubmit → Poll+Download.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SearchEstate might need active cart and/or different headers.
Add X-Requested-With: XMLHttpRequest, make uatId optional, log raw
response (type, length, sample), and add-to-cart before searching.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OpenAM requires an initial GET to set session cookies before the
credentials POST. Without it, POST returns 500 and only sets
AMAuthCookie (intermediate) instead of iPlanetDirectoryPro (final SSO).
Then navigate to ePay goto URL to establish JSESSIONID.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OpenAM goto URL is http://epay.ancpi.ro:80 (HTTP, not HTTPS).
Try multiple URL variants to establish JSESSIONID after OpenAM auth.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ANCPI's OpenAM uses AMAuthCookie instead of iPlanetDirectoryPro.
Accept AMAuthCookie, iPlanetDirectoryPro, or JSESSIONID as valid
session indicators. Navigate to ePay after auth to establish JSESSIONID.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Let axios follow all redirects (maxRedirects=10) so cookie jar captures
iPlanetDirectoryPro from the chain. Explicitly navigate to ePay after
login to ensure JSESSIONID. Log all cookies for debugging. Last resort:
verify login by checking if credit info is visible on ePay page.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OpenAM requires module=SelfRegistration and goto= redirect URL.
Also handle 302 manually to capture iPlanetDirectoryPro cookie,
then follow redirect to ePay for JSESSIONID.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Foundation (Phase 1):
- CfExtract Prisma model with version tracking, expiry, MinIO path
- epay-types.ts: all ePay API response types
- epay-counties.ts: WORKSPACE_ID → ePay county index mapping (42 counties)
- epay-storage.ts: MinIO helpers (bucket, naming, upload, download)
- docker-compose.yml: ANCPI env vars
ePay Client (Phase 2):
- epay-client.ts: full HTTP client (login, credits, cart, search estate,
submit order, poll status, download PDF) with cookie jar + auto-relogin
- epay-session-store.ts: separate session from eTerra
Queue + API (Phase 3):
- epay-queue.ts: sequential FIFO queue (global cart constraint),
10-step workflow per order with DB status updates at each step
- POST /api/ancpi/session: connect/disconnect
- POST /api/ancpi/order: create single or bulk orders
- GET /api/ancpi/orders: list all extracts
- GET /api/ancpi/credits: live credit balance
- GET /api/ancpi/download: stream PDF from MinIO
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause: PATCH endpoint created a new EterraClient which tried
to re-login with expired session → 401. Now county refresh runs
immediately after successful login in the session route, using the
same authenticated client (fire-and-forget). Component reloads UAT
data 5s after connection to pick up fresh county info.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Restore SIRUTA code display in parentheses next to UAT name
- PATCH response now includes debug samples (sampleUat keys, county
raw data) visible in browser console for diagnosing matching issues
- POST endpoint now supports resync (upsert mode, safe to call again)
- Client logs full PATCH result to browser console for debugging
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- PATCH /api/eterra/uats: handle nested responses (unwrapArray), try
multiple field names (extractName/extractCode), log sample UAT for
debugging, match by code first then by name
- GET /api/eterra/uats: include localFeatures count per SIRUTA via
GisFeature groupBy query
- Dropdown: show green badge with local feature count, county with dash
- Add SKILLS.md for ParcelSync/eTerra/GIS module context
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>