New format: single-letter prefix + year + 5-digit sequence.
No direction code (IN/OUT) in the number — shown via arrow icon.
Sequence is shared across directions within the same company+year.
Changes:
- REGISTRY_COMPANY_PREFIX: BTG→B, USW→U, SDT→S, GRP→G
- OLD_COMPANY_PREFIX map for backward compat with existing entries
- allocateSequenceNumber: searches both old and new format entries
to find the actual max sequence (backward compat)
- recalculateSequence: same dual-format search
- parseRegistryNumber: supports 3 formats (current, v1, legacy)
- isNewFormat: updated regex for B-2026-00001
- CompactNumber: already used single-letter badges, just updated comment
- debug-sequences endpoint: updated for new format
- Notification test data: updated to new format
- RegistrySequence.type: now "SEQ" (shared) instead of "IN"/"OUT"
After deploy: POST /api/registratura/debug-sequences to clean up
old counters, then recreate test entries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The previous fix still used MAX(actualMax, counterVal) which meant a
stale counter (from entries deleted before the fix was deployed) would
override the actual entry count. Changed to use ONLY actualMax + 1.
The RegistrySequence counter is now just a cache that gets synced —
it never overrides the actual entries count.
Also added /api/registratura/debug-sequences endpoint:
- GET: shows all counters vs actual entry max (for diagnostics)
- POST: resets all counters to match actual entries (one-time fix)
After deploy, call POST /api/registratura/debug-sequences to reset
the stale counters, then delete the BTG-2026-OUT-00004 entry and
recreate it — it will get 00001.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The old allocateSequenceNumber blindly incremented a counter in
RegistrySequence, which drifted out of sync when entries were deleted
or moved between companies — producing wrong numbers (e.g., #6 for
the first entry of a company).
New approach:
- Uses pg_advisory_xact_lock inside a Prisma interactive transaction
to serialize concurrent allocations
- Always queries the actual MAX sequence from KeyValueStore entries
(the source of truth) before allocating the next number
- Takes MAX(actual entries, counter) + 1 so the counter can never
produce a stale/duplicate number
- Upserts the counter to the new value for consistency
- Also adds recalculateSequence to DELETE handler so the counter
stays in sync after entry deletions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add min-h-0 + overflow-hidden on ScrollArea to enable scrolling
in the detail side panel (flex child needs bounded height)
- Wrap external status badge Tooltip in TooltipProvider to fix
"Tooltip must be used within TooltipProvider" runtime crash
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add ExternalStatusTracking types + ExternalDocStatus semantic states
- Authority catalog with Primaria Cluj-Napoca (POST scraper + HTML parser)
- Status check service: batch + single entry, change detection via hash
- API routes: cron-triggered batch (/api/registratura/status-check) +
user-triggered single (/api/registratura/status-check/single)
- Add "status-change" notification type with instant email on change
- Table badge: Radio icon color-coded by status (amber/blue/green/red)
- Detail panel: full monitoring section with status, history, manual check
- Auto-detection: prompt when recipient matches known authority
- Activation dialog: configure petitioner name + confirm registration data
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Registratura: re-allocate number when company/direction changes on update,
recalculate old company's sequence counter from actual entries
- Extreme PDF: stream body to temp file instead of req.formData() to support large files
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Company badges: US→U, SDT→S (B and G already single letter).
Direction: only intrat (↓ green) and iesit (↑ orange), removed intern since no longer used.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace full "BTG-0042/2026" with compact [B] ↓ 0042/2026 format:
- Colored company badge (B=blue, US=violet, SDT=green, G=gray)
- Direction arrow icon (↓ green=intrat, ↑ orange=iesit, ↔ gray=intern)
- Plain number without prefix
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copies "nr. BTG-0042/2026 din 11.03.2026" to clipboard on click.
Small icon, subtle until hover, green check feedback on copy.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
useMemo was called after early return (when deadline=null), violating
React Rules of Hooks. Moved all hooks before the conditional return.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- ac-verificare (5z lucr.) now auto-track, created automatically with
any AC emitere type. Informational: authority notifies if incomplete.
- ac-emitere (30z cal.) now chains to ac-emitere-dupa-completari when
interrupted — term recalculates from completion submission date.
- ac-emitere-urgenta (7z lucr.) and ac-emitere-anexe (15z cal.) kept.
- New: ac-prelungire-emitere (15z lucr.) — authority communicates
decision on AC extension within 15 working days.
- Info box in DeadlineAddDialog for autorizare category explaining
auto-tracked verification + interruption mechanism.
- None of the autorizare deadlines have tacit approval.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously DIRECTION_CATEGORIES limited intrat to only completari+contestatie,
so cerere/aviz on intrat direction lost certificat/avize/urbanism/autorizare.
Now cerere/aviz doc types unlock all 6 categories on both directions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Typing {proiect}, {nr}, {an}, {detalii} or {text} in the subject field
now auto-transforms to template mode with the appropriate input widgets
(project dropdown, number fields, etc.).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add "Necesita analiza in comisie" toggle for avize category (mirrors CJ toggle)
- When OFF: auto-creates 5-day working limit for completari requests
- When ON: no limit (institution can request completions anytime)
- Add interruption mechanism: resolve aviz as "intrerupt" when institution
requests completions → auto-creates new 15-day deadline from completions date
- New resolution type "intrerupt" with yellow badge + chain support
- Restructure avize catalog entries:
- aviz-ac-15 (L50) and aviz-urbanism-30 (L350) now have chain to
aviz-emitere-dupa-completari for interruption flow
- aviz-mediu: updated hints about procedure closure prerequisite
- aviz-cultura-comisie: 2-phase with auto-track depunere la comisie (30 days)
- aeronautica, ISU, transport-eu: all get interruption chain
- 3 new auto-track entries: aviz-completari-limit (5zl), aviz-emitere-dupa-completari
(15zc), aviz-cultura-depunere-comisie (30zc)
- New document type: "Convocare sedinta"
- Info boxes in dialog explaining auto-track behavior + interruption mechanism
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix doc type showing "altele" after edit: preserve initial documentType
in allDocTypes map even if not in defaults or Tag Manager
- Filter deadline categories by document type: only cerere/aviz unlock
full permitting categories (CU, avize, urbanism, autorizare)
- Other doc types (scrisoare, notificare, etc.) only get completari +
contestatie as deadline categories
- Add completari to intrat direction (was missing)
- Pass documentType to DeadlineAddDialog for category filtering
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Conex button now adds to linkedEntryIds (for clarificari/solicitari)
instead of setting threadParentId
- Inchide button sets threadParentId (direct reply) + auto-closes parent
- Fix Sterge button persistence bug: threadParentId now saves as empty
string instead of undefined (which was stripped in JSON serialization)
- Card headers: "Conex cu X" (amber) vs "Raspuns la X" (blue + green)
- Add conexTo prop to RegistryEntryForm for linked entry pre-fill
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix threadParentId clear: always show "Sterge" button even when parent not found in allEntries
- Bigger clear button with text label instead of tiny X icon
- Fallback display when parent not in current list (shows truncated ID)
- Close via conex: table/detail "Inchide" now creates a new reply entry that closes the original
- Header shows "Conex la BTG-XXX" + "Inchide originala" badge when closing via conex
- After saving the new conex entry, parent is auto-closed with resolution "finalizat"
- onClose signature changed from (id: string) to (entry: RegistryEntry) across table + detail
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Conex button on table rows (Reply icon, blue) — opens new entry with threadParentId pre-set + flipped direction
- Conex button on detail panel — same behavior
- Inchide button on table rows (CheckCircle2 icon, green) — only for open entries
- replyTo prop on RegistryEntryForm: pre-sets threadParentId + direction flip (intrat→iesit, iesit→intrat)
- Card header shows "Conex la BTG-0042/2026" with blue badge when replying
- Completari moved to last position in deadline category order
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove publicitate/comunicare category entirely (AC publicity handled by AC validity tracker)
- comunicare-aviz-beneficiar moved to auto-track: created alongside any iesit deadline
- Late receipt badge on incoming aviz entries: shows "Primit cu X zile intarziere" when document date < today
- Valabilitate document + AC Validity Tracker visible only when documentType is "aviz" (act administrativ)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CU has NO tacit approval on any entry
- Direction-dependent categories: iesiri (CU, Avize, Completari, Urbanism, Autorizare), intrari (Contestatie)
- Rename: Analiza → Urbanism (PUD/PUZ/PUG), Autorizare (AC) → Autorizare (AD/AC)
- Auto-track deadlines: cu-verificare (10zl) created automatically with CU emitere
- CJ toggle: auto-creates arhitect-sef solicita aviz (3zc) + primar emite aviz (5zc)
- Verification badge: after 10 days shows "Nu mai pot returna documentatia"
- Prelungire helper: CU issue date + 6/12/24 month calculator
- cu-prelungire-emitere changed to 30zc (practica administrativa)
- New DeadlineTypeDef fields: autoTrack, directionFilter
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Comunicare, Instiintare under scrisoare
- Add Memoriu justificativ, Studiu de fezabilitate, Audit energetic, Caiet de sarcini under raport
- Add Aviz racordare, Acord unic under aviz
- Add Contract proiectare, PV predare-primire under contract
- Add Borderou, Fisa tehnica, Tema de proiectare, Deviz general, Conventie under altele
- Total seed templates: ~55 across 11 document types
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add SEED_TEMPLATES catalog (11 doc types x 2-4 templates = ~30 predefined patterns)
- Add {proiect} field type with mini-autocomplete from Tag Manager projects
- Pre-fill {an} fields with current year on template selection
- Dynamic placeholder changes based on documentType + direction (22 combinations)
- Dropdown on empty focus: "Sabloane recomandate" + "Recente" sections
- Direction-aware tooltip on Subiect field (intrat vs iesit examples)
- getRecommendedTemplates() merges seeds + DB-learned, DB takes priority
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- New subject-template-service: extracts reusable templates from existing
subjects by detecting variable parts (numbers, years, text after separators)
- Template input component: inline editable fields within static text
(e.g., "Cerere CU nr. [___]/[____] — [___________]")
- Two-tier autocomplete dropdown: templates sorted by frequency (top) +
matching existing subjects (bottom)
- Learns from database: more entries = better suggestions
- Follows existing contact autocomplete pattern (focus/blur, onMouseDown)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- "Bune practici" button in registry header opens a popover with internal rules
(numerotare, completare, termene, atașamente, închidere)
- Info tooltips on form labels: Direcție, Tip document, Subiect, Expeditor,
Destinatar, Atașamente (consistent with existing pattern on Data document)
- Install shadcn/ui Popover component
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Auth:
- Add middleware.ts that redirects unauthenticated users to Authentik SSO
- Extract authOptions to shared auth-options.ts
- Add getAuthSession() helper for API route protection
- Add loading spinner during session validation
- Dev mode bypasses auth (stub user still works)
ManicTime:
- Fix hardcoded companyId="beletage" — now uses group context from Tags.txt
- Fix extended project format label parsing (extracts name after year)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- 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
- 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
- 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
- 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)
- 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.
- 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.
- 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.
- 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