Skip to content

Registrul Interdicțiilor — Platform Design & Generic Registry Plan

This document accompanies interdictii_full.md (domain inventory) and interdictii.jdl (authoritative entity shape). It contains:

  1. Diagrams — system context, component architecture, DB schema, lifecycle, activity, and sequence views of the current Interdicții registry.
  2. Generic Registry Platform plan — a reusable architecture for building any government registry (interdicții, permise, contracte, ONG-uri, sancțiuni, amenzi, etc.) on the same foundation.

Diagram labels use English structural terms and Romanian domain terms, mirroring the codebase convention.


Where the registry sits among its actors and external systems.

flowchart TB
subgraph Actors["Actori"]
Operator["Operator registru<br/>(INSPECTOR / OPERATOR)"]
Sef["Șef direcție<br/>(SEF_DIRECTIE)"]
Auditor["Auditor"]
Admin["Administrator"]
Public["Public / persoană vizată"]
ExternalGov["Sistem extern govtech<br/>(API consumer)"]
end
subgraph System["Registrul Interdicțiilor (SaaS)"]
Portal["Portal web<br/>(Angular SPA)"]
API["REST API<br/>(Spring Boot)"]
PublicAPI["API public de consultare<br/>(read-only)"]
end
subgraph External["Sisteme externe"]
MConnect["MConnect / interop"]
ANAF["Registre persoane juridice<br/>(ANAF / IDNO)"]
CivilReg["Registru de stat al populației<br/>(IDNP)"]
Mail["SMTP / notificări"]
end
Operator -->|CRUD interdicții| Portal
Sef -->|aprobare| Portal
Auditor -->|consultare + audit log| Portal
Admin -->|users, autorități| Portal
Public -->|consultare după IDNP/IDNO| PublicAPI
ExternalGov -->|verificare automată| PublicAPI
Portal --> API
API <-->|verificare identitate| CivilReg
API <-->|verificare companie| ANAF
API --> Mail
API <-->|federație identități / SSO| MConnect

The technical layering of the deployable monolith — Angular SPA in the browser, Spring Boot serving REST + static assets, with PostgreSQL / Elasticsearch / Cache as backing stores.

flowchart LR
subgraph Browser["Browser"]
SPA["Angular 19 SPA<br/>standalone components"]
end
subgraph Backend["Spring Boot 3 monolith<br/>(md.gov.interdictii)"]
direction TB
Sec["SecurityFilterChain<br/>+ JWT filter"]
Rest["web.rest.*Resource<br/>(controllers)"]
Svc["service.*Service<br/>+ impl/"]
QSvc["service.*QueryService<br/>(JPA Criteria)"]
Map["service.mapper<br/>(MapStruct)"]
Dto["service.dto"]
Repo["repository.*Repository<br/>(Spring Data JPA)"]
SRepo["repository.search<br/>(Spring Data Elasticsearch)"]
Dom["domain.*<br/>(JPA entities)"]
Audit["AbstractAuditingEntity<br/>+ SpringSecurityAuditorAware"]
Liq["Liquibase changelogs"]
end
subgraph Stores["Stores"]
PG[("PostgreSQL<br/>(prod) / H2 (dev)")]
ES[("Elasticsearch<br/>(Interdictie, Entitate)")]
Cache[("Ehcache + Hibernate L2")]
end
Mail["SMTP"]
SPA -- HTTPS + JWT --> Sec
Sec --> Rest
Rest --> Svc
Svc --> QSvc
Svc --> Map
Map --> Dto
Svc --> Repo
Svc --> SRepo
Repo --> Dom
SRepo --> Dom
Dom --> Audit
Repo --> Cache
Repo --> PG
SRepo --> ES
Liq -. migrations .-> PG
Svc --> Mail

Key conventions:

  • Controllers exchange DTOs with the outside world; entities never leave the service layer.
  • *QueryService + *Criteria provide URL-driven filtering on the four filterable entities (Interdictie, Entitate, Act, AutoritateEmitenta).
  • Only Interdictie and Entitate are mirrored to Elasticsearch.
  • AbstractAuditingEntity populates createdBy / createdDate / lastModifiedBy / lastModifiedDate automatically via the JPA auditor.

3.1 Current schema (mirrors interdictii.jdl)

Section titled “3.1 Current schema (mirrors interdictii.jdl)”
erDiagram
INTERDICTIE {
bigint id PK
varchar statut "StatutInterdictie"
varchar stare "StareInterdictie"
date start_date
date end_date
clob description
varchar categorie_jurisdictie "CategorieJurisdictie"
varchar categorie_domeniu "CategorieDomeniu"
bigint entitate_id FK
bigint act_id FK
bigint autoritate_id FK
varchar created_by
timestamp created_date
varchar last_modified_by
timestamp last_modified_date
}
ENTITATE {
bigint id PK
varchar nume
varchar functie
date start_date_functie
varchar idnp_idno "IDNP(13) / IDNO(13)"
varchar tip "FIZICA | JURIDICA"
}
APP_USER {
bigint id PK
varchar username UK
varchar password
varchar statut "StatutUser"
varchar rol "RolUser"
}
AUTORITATE_EMITENTA {
bigint id PK
varchar name
}
RIDICARE_INTERDICTIE {
bigint id PK
clob description
bigint interdictie_id FK "OneToOne"
bigint act_id FK
bigint autoritate_id FK
}
ACT {
bigint id PK
date start_date
date end_date
varchar name
clob description
}
JHI_USER {
bigint id PK
varchar login UK
varchar password_hash
varchar email
boolean activated
}
JHI_AUTHORITY {
varchar name PK "ROLE_*"
}
INTERDICTIE ||--o{ ENTITATE : "vizează"
INTERDICTIE }o--|| AUTORITATE_EMITENTA : "emisă de"
INTERDICTIE }o--o| ACT : "în baza"
RIDICARE_INTERDICTIE ||--|| INTERDICTIE : "ridică (1:1)"
RIDICARE_INTERDICTIE }o--o| ACT : "în baza"
RIDICARE_INTERDICTIE }o--o| AUTORITATE_EMITENTA : "emisă de"
JHI_USER ||--o{ JHI_AUTHORITY : "are"

Notă: JHI_USER / JHI_AUTHORITY sunt entitățile JHipster built-in pentru autentificare/roluri (Spring Security). APP_USER este entitatea de domeniu distinctă (operator registru), păstrată separat deliberat — vezi CLAUDE.md.

3.2 Extended schema (target — derivat din interdictii_full.md)

Section titled “3.2 Extended schema (target — derivat din interdictii_full.md)”

The full domain doc lists 9 entity categories (PF, PJ, administratori, funcționari, străini, mărfuri, arme, vehicule, active financiare/tranzacții), 10 lifecycle statuses, 4 authority families, and 4 classification axes (jurisdicție, domeniu, durată, intensitate). The current v0 shape collapses these; the extended target below covers totul, inclusiv interdicții pe bunuri și pe tranzacții (cu scope: limite valorice, contraparte, geo).

Trei concepte noi față de v0:

  • ENTITATE polimorfic acoperă toate cele 9 categorii (vezi §3.3 pentru mapping detaliat).
  • ACTIUNE_INTERZISA — acțiunea/operațiunea blocată (IMPORT, TRANZACTIONARE, CIRCULATIE, PORT_ARMA, …). O interdicție poate bloca mai multe acțiuni pe același entitate, fiecare cu scope propriu (de ex. „tranzacții > 50.000 MDL către contraparte din jurisdicție Y”).
  • DOMENIU_APLICARE (jsonb pe ACTIUNE_INTERZISA) — predicate de scope: limite valorice, geografie, contraparte, ferestre temporale, canale.
erDiagram
ENTITATE {
bigint id PK
varchar categorie "PF|PJ|ADMIN|FUNCTIONAR_PUBLIC|STRAIN|MARFA|ARMA|VEHICUL|ACTIV_FINANCIAR"
varchar identificator "IDNP|IDNO|VIN|IBAN|serie_arma|cod_tarifar|..."
varchar nume_afisat
jsonb atribute "schema per categorie - vezi 3.3"
}
INTERDICTIE {
bigint id PK
bigint entitate_id FK
bigint autoritate_id FK
varchar statut "vezi sectiunea 4 - 10 stari"
varchar stare
varchar jurisdictie "NATIONALA|LOCALA|REGIONALA|INTERNATIONALA|TRANSFRONTALIERA"
varchar domeniu "ADMIN|PENAL|FISCAL|VAMAL|MEDIU|SECURITATE|MIGRATIONAL|ECONOMIC"
varchar durata "TEMPORARA|PERMANENTA|CONDITIONATA|PANA_LA_EXECUTARE"
varchar intensitate "TOTALA|PARTIALA|CONDITIONATA|PROGRESIVA"
date start_date
date end_date
bigint temei_legal_id FK
bigint conditie_id FK "doar daca durata=CONDITIONATA"
text description
}
ACTIUNE_INTERZISA {
bigint id PK
bigint interdictie_id FK
varchar actiune "IMPORT|EXPORT|CIRCULATIE|TRANZACTIONARE|PORT_ARMA|EXERCITARE_FUNCTIE|IESIRE_TARA|..."
jsonb scope "limite valori, geografie, contraparte, fereastra temporala, canale"
varchar intensitate "TOTALA|PARTIALA - per actiune, poate diferi de cea a interdictiei"
}
CONDITIE {
bigint id PK
varchar tip "EVENIMENT|INDEPLINIRE_OBLIGATIE|DECIZIE_AUTORITATE|PRAG_TEMPORAL"
text descriere
boolean indeplinita
timestamp data_indeplinire
bigint act_indeplinire_id FK
}
TEMEI_LEGAL {
bigint id PK
varchar act_normativ "Cod Penal|Cod Contraventional|Legea privind sanctiunile|..."
varchar articol
varchar alineat
}
INTERDICTIE_ACT {
bigint interdictie_id FK
bigint act_id FK
varchar rol "EMITERE|MODIFICARE|RIDICARE|REVOCARE|CONTESTARE|PRELUNGIRE|EXECUTARE"
date data_atasare
}
ACT {
bigint id PK
varchar tip "HOTARARE|DECIZIE|PROCES_VERBAL|ORDIN|SENTINTA|..."
varchar numar
date data
varchar storage_uri "S3/MinIO"
varchar hash_sha256
varchar signature "MSign"
}
AUTORITATE_EMITENTA {
bigint id PK
varchar nume
varchar familie "JUDICIARA|ADMINISTRATIVA|CONTROL|SPECIALA"
varchar nivel "CENTRALA|TERITORIALA"
varchar cod_idno
}
EVENIMENT_INTERDICTIE {
bigint id PK
bigint interdictie_id FK
varchar tip "CREATA|APROBATA|SUSPENDATA|REACTIVATA|CONTESTATA|REVOCATA|RIDICATA|EXPIRATA|EXECUTATA|PRELUNGITA|CONDITIE_INDEPLINITA"
varchar actor "user login"
timestamp data
jsonb payload
}
NOTIFICARE {
bigint id PK
bigint interdictie_id FK
varchar canal "EMAIL|MCONNECT|SMS|WEBHOOK"
varchar destinatar
varchar status
timestamp sent_at
}
ENTITATE ||--o{ INTERDICTIE : "vizat de"
AUTORITATE_EMITENTA ||--o{ INTERDICTIE : "emite"
TEMEI_LEGAL ||--o{ INTERDICTIE : "fundamenteaza"
INTERDICTIE ||--o{ ACTIUNE_INTERZISA : "blocheaza"
INTERDICTIE }o--o| CONDITIE : "asteapta"
INTERDICTIE ||--o{ INTERDICTIE_ACT : ""
ACT ||--o{ INTERDICTIE_ACT : ""
INTERDICTIE ||--o{ EVENIMENT_INTERDICTIE : "event log"
INTERDICTIE ||--o{ NOTIFICARE : ""

3.3 Acoperire completă a entităților (mapping cu interdictii_full.md §1)

Section titled “3.3 Acoperire completă a entităților (mapping cu interdictii_full.md §1)”

Toate cele 9 categorii din documentul de domeniu sunt acoperite. Tabelul de mai jos arată cum se concretizează ENTITATE.atribute și ce acțiuni (actiune în ACTIUNE_INTERZISA) sunt tipice per categorie.

Categorie entitate (§1.x)categorieidentificatoratribute (jsonb)Acțiuni tipice în ACTIUNE_INTERZISA
1.1 Persoană fizică (civil)PFIDNP (13)nume, prenume, data_nasteriiIESIRE_TARA, EXERCITARE_PROFESIE, DETINERE_ARMA, ACCES_PERIMETRU, PARTICIPARE_PUBLICA
1.2 Persoană juridicăPJIDNO (13)denumire, forma_org (SRL/SA/ONG/IS), caenDESFASURARE_ACTIVITATE, ACHIZITII_PUBLICE, IMPORT, EXPORT, ADMINISTRARE, SUSPENDARE_LICENTA
1.3 Administrator / fondatorADMINIDNPfunctie, pj_administrata_idnoOCUPARE_FUNCTIE_CONDUCERE, ADMINISTRARE_PJ
1.4 Funcționar public / demnitarFUNCTIONAR_PUBLICIDNPfunctie, institutie, nivelEXERCITARE_FUNCTIE, ACCES_FUNCTIE_PUBLICA, INCOMPATIBILITATE
1.5 Străin / apatridSTRAINnr. pașaport / id documentcetatenie, alias[], data_nasteriiINTRARE_RM, SEDERE_RM, REINTOARCERE (după expulzare)
1.6 Mărfuri / bunuriMARFAcod tarifar / nr. lotdenumire, categorie (arme/medicamente/sub_periculoase/bunuri_culturale/contrafacute), cantitate, umIMPORT, EXPORT, CIRCULATIE, COMERCIALIZARE, CONFISCARE
1.7 Arme / munițiiARMAserie armătip, calibru, producatorPROCURARE, PORT_ARMA, FOLOSIRE, COMERCIALIZARE, RETRAGERE_PERMIS
1.8 Vehicul / mijloc transportVEHICULVIN + nr. înmatricularemarca, model, an, categorieCIRCULATIE, INMATRICULARE, EXPLOATARE, SECHESTRU
1.9 Activ financiar / contACTIV_FINANCIARIBAN / nr. cont / cod activbanca, titular_idnp_idno, monedaTRANZACTIONARE, RETRAGERE, TRANSFER, DEPUNERE, BLOCARE_CONT, INDISPONIBILIZARE, SECHESTRU

Exemple concrete de ACTIUNE_INTERZISA.scope

Section titled “Exemple concrete de ACTIUNE_INTERZISA.scope”

Scope-ul permite condiționarea acțiunii blocate — esențial pentru interdicții pe tranzacții și bunuri unde rar se blochează „totul”:

// 1.9 - blocare tranzacții peste prag, către o anumită jurisdicție
{ "actiune": "TRANZACTIONARE",
"scope": {
"suma_min_mdl": 50000,
"directie": "OUTGOING",
"contraparte_jurisdictie": ["RU","BY"],
"canale": ["SWIFT","SEPA"]
} }
// 1.6 - import interzis dintr-o țară, pentru o categorie de marfă
{ "actiune": "IMPORT",
"scope": {
"tara_origine": ["RU"],
"cod_tarifar_prefix": ["2710"],
"valabil_intre": ["2026-01-01","2026-12-31"]
} }
// 1.8 - circulație restrânsă geografic și temporal
{ "actiune": "CIRCULATIE",
"scope": {
"zona": "mun. Chisinau, sector Centru",
"interval_orar": "07:00-22:00",
"exceptie": "regim de urgenta medicala"
} }
// 1.1 - interdicție parțială de exercitare a profesiei
{ "actiune": "EXERCITARE_PROFESIE",
"scope": {
"profesie": "avocat",
"domeniu": "drept penal",
"instanta_exceptie": []
} }
flowchart TB
ENTITATE[("ENTITATE<br/>polimorfic")]
ENTITATE --> Persoane["Persoane"]
ENTITATE --> Bunuri["Bunuri / obiecte"]
ENTITATE --> Active["Active financiare"]
Persoane --> PF["PF — civil<br/>IDNP"]
Persoane --> PJ["PJ — SRL/SA/ONG/IS<br/>IDNO"]
Persoane --> ADMIN["ADMIN — fondator/conducător<br/>IDNP + ref PJ"]
Persoane --> FUNCT["FUNCTIONAR_PUBLIC<br/>IDNP + funcție"]
Persoane --> STRAIN["STRAIN / apatrid<br/>pașaport"]
Bunuri --> MARFA["MARFA — bunuri / mărfuri<br/>cod tarifar / lot"]
Bunuri --> ARMA["ARMA — armă / muniție<br/>serie armă"]
Bunuri --> VEHICUL["VEHICUL<br/>VIN + nr. înmatriculare"]
Active --> CONT["ACTIV_FINANCIAR<br/>IBAN / nr. cont"]
PF -.acțiuni.-> AP1["IESIRE_TARA, EXERCITARE_PROFESIE,<br/>DETINERE_ARMA, ACCES_PERIMETRU"]
PJ -.acțiuni.-> AP2["DESFASURARE_ACTIVITATE,<br/>ACHIZITII_PUBLICE, IMPORT, EXPORT"]
MARFA -.acțiuni.-> AP3["IMPORT, EXPORT, CIRCULATIE,<br/>COMERCIALIZARE, CONFISCARE"]
ARMA -.acțiuni.-> AP4["PROCURARE, PORT_ARMA,<br/>FOLOSIRE, COMERCIALIZARE"]
VEHICUL -.acțiuni.-> AP5["CIRCULATIE, INMATRICULARE,<br/>EXPLOATARE, SECHESTRU"]
CONT -.acțiuni.-> AP6["TRANZACTIONARE, TRANSFER,<br/>BLOCARE_CONT, SECHESTRU"]
  • Identificatori unici per categorie: index parțial pe (categorie, identificator) în PostgreSQL — IDNP se poate repeta între PF și ADMIN (aceeași persoană în roluri diferite), dar nu în interiorul unei categorii.
  • Validare structurală a atribute: JSON Schema per categorie, stocat în cod (resource files) sau într-o tabelă ENTITATE_SCHEMA (Pattern C — multi-tenant).
  • Acțiuni vs. intensitate vs. domeniu: domeniul (§4.2) este clasificarea juridică; acțiunea interzisă este operațiunea concretă blocată. O singură interdicție domeniu=FISCAL pe un cont poate avea două acțiuni: BLOCARE_CONT (totală) și TRANZACTIONARE cu scope=„retrageri > 10k MDL”.
  • Entitate compusă (cazuri rare — de ex. „administratorul X interzis să conducă PJ Y”): modelat ca două entități + două ACTIUNE_INTERZISA legate prin scope ce referențiază entitatea parteneră.

Toate cele 10 statuturi din interdictii_full.md §2 (Draft, Activă, Suspendată, Contestată, Anulată, Revocată, Expirată, Executată, Prelungită, Condiționată) sunt modelate explicit. statut în JDL rămâne pentru clasificarea administrativă; diagrama de mai jos modelează stare (ciclul de viață operațional).

Semantica distincțiilor subtile:

  • ANULATĂ vs REVOCATĂ — ambele termină interdicția, dar: Anulată = desființată definitiv de o autoritate superioară (ex. instanță superioară admite contestația). Revocată = retrasă voluntar de emitent.
  • RIDICATĂ vs EXECUTATĂ — Ridicată = încetare prin act dedicat (RidicareInterdictie). Executată = efectele „do X” au fost realizate (ex. confiscare finalizată, expulzare efectuată).
  • CONDIȚIONATĂ = pre-activă, așteptând îndeplinirea unei condiții (Conditie.indeplinita = true); când condiția se îndeplinește → ACTIV.
  • PRELUNGITĂ este o stare tranzitorie în care se procesează actul de prelungire; după înregistrare se întoarce la ACTIV cu end_date extins.
stateDiagram-v2
[*] --> DRAFT: creată (OPERATOR)
DRAFT --> CONDITIONATA: aprobată + durata=CONDITIONATA
DRAFT --> ACTIV: aprobată (SEF_DIRECTIE)
DRAFT --> ANULAT: respinsă în draft
CONDITIONATA --> ACTIV: condiție îndeplinită
CONDITIONATA --> ANULAT: condiție imposibilă / decăzută
ACTIV --> SUSPENDAT: suspendare temporară
SUSPENDAT --> ACTIV: reactivare
SUSPENDAT --> REVOCATA: retragere în timpul suspendării
ACTIV --> CONTESTATA: contestație depusă
CONTESTATA --> ACTIV: contestație respinsă
CONTESTATA --> ANULAT: contestație admisă<br/>(autoritate superioară)
ACTIV --> RIDICATA: act de ridicare emis<br/>(RidicareInterdictie)
ACTIV --> REVOCATA: retrasă de emitent
ACTIV --> EXPIRAT: end_date atins<br/>(scheduled job)
ACTIV --> EXECUTATA: efecte realizate<br/>(ex. confiscare finalizată)
ACTIV --> PRELUNGITA: cerere de prelungire
PRELUNGITA --> ACTIV: prelungire înregistrată<br/>(end_date extins)
PRELUNGITA --> EXPIRAT: prelungire respinsă + end_date trecut
RIDICATA --> [*]
REVOCATA --> [*]
EXPIRAT --> [*]
EXECUTATA --> [*]
ANULAT --> [*]
note right of EXPIRAT
Tranziție automată
prin scheduled job
(Spring @Scheduled)
end note
note right of ACTIV
Singura stare în care
interdicția produce efecte
juridice publice (alături de
SUSPENDAT pentru istoric).
end note
note left of CONDITIONATA
Vezi entitatea CONDITIE
din §3.2 — eveniment,
obligație, decizie.
end note

Tabel matrice tranziții → eveniment emis (alimentează EVENIMENT_INTERDICTIE):

De la → laEvenimentTriggerActor
∅ → DRAFTCREATAmanualOPERATOR
DRAFT → ACTIVAPROBATAmanualSEF_DIRECTIE
DRAFT → CONDITIONATAAPROBATAmanualSEF_DIRECTIE
CONDITIONATA → ACTIVCONDITIE_INDEPLINITAmanual sau jobsistem/OPERATOR
ACTIV → SUSPENDATSUSPENDATAmanualautoritate
SUSPENDAT → ACTIVREACTIVATAmanualautoritate
ACTIV → CONTESTATACONTESTATAmanualOPERATOR / entitate
ACTIV → REVOCATAREVOCATAmanualemitent
ACTIV → RIDICATARIDICATAmanualOPERATOR (+ RidicareInterdictie)
ACTIV → EXECUTATAEXECUTATAmanualOPERATOR
ACTIV → PRELUNGITAPRELUNGIRE_CERUTAmanualOPERATOR
PRELUNGITA → ACTIVPRELUNGITAmanualSEF_DIRECTIE
ACTIV → EXPIRATEXPIRATAautomatsistem (@Scheduled)
oricare → ANULATANULATAmanualautoritate superioară

flowchart TD
Start([Operator inițiază]) --> SearchSubj{Entitate<br/>existent?}
SearchSubj -- Nu --> CreateSubj[Creează Entitate / Entitate<br/>+ verifică IDNP/IDNO]
SearchSubj -- Da --> SelectSubj[Selectează din listă]
CreateSubj --> FillForm
SelectSubj --> FillForm[Completează formular interdicție<br/>statut, stare=DRAFT, jurisdicție, domeniu,<br/>start/end date, temei legal]
FillForm --> AttachAct[Atașează Act/acte<br/>upload PDF / referință]
AttachAct --> SelectAuth[Selectează AutoritateEmitenta]
SelectAuth --> Save[Save → POST /api/interdictii]
Save --> Validate{Validare<br/>backend?}
Validate -- Eșec --> ShowErr[Afișează erori validare] --> FillForm
Validate -- OK --> Persist[Persistă în DB<br/>stare=DRAFT]
Persist --> Index[Indexează în Elasticsearch]
Index --> NotifySef[Notifică SEF_DIRECTIE pentru aprobare]
NotifySef --> Review{Aprobare?}
Review -- Aprobă --> Activate[stare=ACTIV<br/>EVENIMENT: APROBATA]
Review -- Respinge --> Reject[stare=ANULAT<br/>EVENIMENT: ANULATA]
Activate --> NotifySubj[Notifică entitatea<br/>+ publish în registru public]
NotifySubj --> End([Final])
Reject --> End
flowchart TD
Start([Cerere de ridicare]) --> LookupInt[Caută interdicție<br/>după ID / IDNP-IDNO]
LookupInt --> Check{stare = ACTIV?}
Check -- Nu --> Reject1[Refuz: doar interdicții active<br/>pot fi ridicate]
Check -- Da --> AttachAct[Atașează act de ridicare<br/>hotărâre / decizie]
AttachAct --> SelectAuth[Autoritate care ridică]
SelectAuth --> SaveRid[POST /api/ridicari-interdictie<br/>OneToOne cu Interdictie]
SaveRid --> UpdateState[UPDATE interdictie<br/>SET stare=RIDICATA]
UpdateState --> Event[INSERT EVENIMENT_INTERDICTIE<br/>tip=RIDICATA]
Event --> Reindex[Re-indexare Elasticsearch]
Reindex --> Notify[Notifică entitate + audit trail]
Notify --> End([Final])
Reject1 --> End
flowchart TD
Start([Public/sistem extern]) --> Input[Introduce IDNP / IDNO / nume]
Input --> RateLimit{Rate<br/>limit OK?}
RateLimit -- Nu --> Block[HTTP 429]
RateLimit -- Da --> Query[GET /api/public/interdictii/_search<br/>?entitate=...]
Query --> Filter[Filtru server-side:<br/>doar stare ACTIV / SUSPENDAT]
Filter --> Found{Rezultate?}
Found -- Nu --> Empty[200 OK<br/>fără înregistrări]
Found -- Da --> Mask[Maschează câmpuri sensibile<br/>conform GDPR]
Mask --> Return[200 OK + listă]
Return --> AuditPub[Log consultare<br/>audit]
Empty --> AuditPub
AuditPub --> End([Final])
Block --> End

sequenceDiagram
autonumber
actor Op as Operator
participant SPA as Angular SPA
participant API as InterdictieResource
participant Svc as InterdictieServiceImpl
participant Map as InterdictieMapper
participant Repo as InterdictieRepository
participant SRepo as InterdictieSearchRepository
participant DB as PostgreSQL
participant ES as Elasticsearch
Op->>SPA: completează formular
SPA->>API: POST /api/interdictii (DTO + JWT)
API->>API: @PreAuthorize ROLE_USER
API->>Svc: save(dto)
Svc->>Map: toEntity(dto)
Map-->>Svc: Interdictie
Svc->>Repo: save(entity)
Repo->>DB: INSERT + AbstractAuditingEntity populates<br/>created_by / created_date
DB-->>Repo: row(id)
Repo-->>Svc: persisted entity
Svc->>SRepo: index(entity)
SRepo->>ES: PUT /interdictie/_doc/{id}
Svc->>Map: toDto(entity)
Map-->>Svc: dto
Svc-->>API: dto
API-->>SPA: 201 Created + Location header
SPA-->>Op: confirmare + redirect detalii

6.2 Aprobare de către șeful de direcție

Section titled “6.2 Aprobare de către șeful de direcție”
sequenceDiagram
autonumber
actor Sef as Sef direcție
participant SPA
participant API as InterdictieResource
participant Svc as InterdictieServiceImpl
participant Repo
participant Ev as EvenimentService
participant Mail as MailService
Sef->>SPA: deschide lista DRAFT
SPA->>API: GET /api/interdictii?stare.equals=DRAFT
API->>Svc: findByCriteria
Svc-->>SPA: page<DTO>
Sef->>SPA: click "Aprobă"
SPA->>API: PATCH /api/interdictii/{id}/aproba
API->>Svc: aproba(id)
Svc->>Repo: findById(id)
Repo-->>Svc: entity (stare=DRAFT)
Svc->>Svc: validate state transition
Svc->>Repo: save (stare=ACTIV)
Svc->>Ev: emit(APROBATA, actor=sef)
Ev->>Repo: INSERT EVENIMENT_INTERDICTIE
Svc->>Mail: sendApprovalNotice(entitate)
Svc-->>API: dto
API-->>SPA: 200 OK
sequenceDiagram
autonumber
participant Ext as Sistem extern (e.g. bancă)
participant Gw as API Gateway / rate limit
participant API as PublicInterdictieResource
participant Svc
participant SRepo as InterdictieSearchRepository
participant ES
participant Audit as AuditLog
Ext->>Gw: GET /public/api/interdictii?idnp=2002004001234<br/>+ API key
Gw->>Gw: rate limit + API key valid
Gw->>API: forward
API->>Svc: searchActive(idnp)
Svc->>SRepo: search({stare: ACTIV, entitate.idnp: ...})
SRepo->>ES: GET /interdictie/_search
ES-->>SRepo: hits
SRepo-->>Svc: list
Svc->>Svc: applyPublicMask (drop fields)
Svc->>Audit: log(consultare, idnp, api_key_owner)
Svc-->>API: dto[]
API-->>Gw: 200 OK
Gw-->>Ext: JSON response
sequenceDiagram
autonumber
actor Op as Operator
participant SPA
participant RidAPI as RidicareInterdictieResource
participant IntAPI as InterdictieResource (internal)
participant Svc as RidicareInterdictieServiceImpl
participant IntSvc as InterdictieServiceImpl
participant Repo
participant SRepo
participant Ev as EvenimentService
Op->>SPA: formular ridicare<br/>(interdictieId, act, autoritate)
SPA->>RidAPI: POST /api/ridicari-interdictie
RidAPI->>Svc: save(dto)
Svc->>Repo: findInterdictie(id)
Repo-->>Svc: interdictie (stare=ACTIV)
Svc->>Svc: assert(stare == ACTIV)
Svc->>Repo: INSERT RidicareInterdictie (OneToOne)
Svc->>IntSvc: markRidicata(interdictieId)
IntSvc->>Repo: UPDATE stare=RIDICATA
IntSvc->>SRepo: re-index
IntSvc->>Ev: emit(RIDICATA)
Svc-->>RidAPI: dto
RidAPI-->>SPA: 201 Created
sequenceDiagram
autonumber
actor U as Utilizator
participant SPA
participant Auth as AuthenticateController
participant SM as SecurityManager
participant UDS as DomainUserDetailsService
participant DB
U->>SPA: login (username, password)
SPA->>Auth: POST /api/authenticate
Auth->>SM: authenticate(token)
SM->>UDS: loadUserByUsername
UDS->>DB: SELECT FROM jhi_user
DB-->>UDS: user + authorities
UDS-->>SM: UserDetails
SM->>SM: bcrypt verify
SM-->>Auth: Authentication ok
Auth->>Auth: generate JWT (HS512)
Auth-->>SPA: 200 { id_token }
SPA->>SPA: store JWT
Note over SPA,Auth: subsequent requests carry<br/>Authorization: Bearer <jwt>

Goal: turn the Interdicții implementation into a reusable foundation (Registry-as-a-Service) on which other registries — permise, sancțiuni, contracte, ONG-uri, mediatori, experți judiciari, amenzi etc. — can be launched without rewriting the stack each time.

Every registry of this shape collapses to the same primitives:

PrimitiveRolExemplu în InterdicțiiExemplu în Permise auto
Entity (polimorfic)Entitatea vizată — persoană, bun, activPF/PJ/marfă/armă/vehicul/cont (§3.3)Conducător auto + Vehicul
RecordÎnregistrarea de registru cu ciclu de viațăInterdictiePermis
Restricted ActionAcțiunea/operațiunea blocată + scopeIMPORT, TRANZACTIONARE, IESIRE_TARA + scope (sume, geo, contraparte)— (permise nu sunt restrictive)
Issuing AuthorityCine emiteAutoritateEmitenta (judiciară/administrativă/control/specială)IGP / ASP
Legal BasisTemeiul juridicCod Penal / Contravențional / sancțiuni internaționaleCod Rutier art. Y
Supporting ActDocument justificativHotărâre / Decizie / Proces-verbalExamen + dosar medical
ConditionEveniment/obligație de care depinde efectulConditie (pentru durata=CONDITIONATA)Recuperare puncte
Lifecycle EventTranziție de stare (append-only)EVENIMENT_INTERDICTIE (vezi matricea §4)EVENIMENT_PERMIS
Lifting / ClosureAct care încheieRidicareInterdictie / REVOCARE / EXECUTARERetragere permis
Consultation APIAcces public/sistem extern (cu mascare GDPR)/public/api/interdictii?idnp=.../public/api/permise
Audit TrailCine, ce, când, de ceEVENIMENT_INTERDICTIE + AbstractAuditingEntityidem
NotificationsCanal multi-protocol către entitate/sistemeEMAIL / MCONNECT / SMS / WEBHOOKidem

Orice registru nou = configurarea acestor primitive + schema specifică entității (taxonomia categoriilor) + dicționarul de acțiuni interzise.

flowchart LR
subgraph Core["Registry Platform Core"]
IAM["Identity & Access<br/>(JWT + SSO + RBAC)"]
Tenancy["Multi-tenant<br/>(registru = tenant)"]
Schema["Schema Engine<br/>(definire record + entitate via DSL)"]
WF["Workflow Engine<br/>(state machine + aprobări)"]
Doc["Document Storage<br/>(S3/MinIO + hash + semnătură)"]
Audit["Audit & Event Store<br/>(append-only)"]
Search["Search<br/>(Elasticsearch + index per tenant)"]
Notif["Notifications<br/>(email / SMS / MConnect)"]
Pub["Public Consultation API<br/>(rate limit + masking)"]
Reports["Reporting & Analytics"]
Interop["Govtech Interop<br/>(MConnect, ANAF, RSP)"]
end
subgraph Registries["Registries (tenants)"]
R1[Registrul Interdicțiilor]
R2[Registrul Permiselor]
R3[Registrul Sancțiunilor]
R4[Registrul ONG-urilor]
R5[...]
end
R1 --> IAM & Tenancy & Schema & WF & Doc & Audit & Search & Notif & Pub & Reports & Interop
R2 --> Schema & WF & Audit & Search & Notif
R3 --> Schema & WF & Audit & Search & Notif
R4 --> Schema & WF & Audit & Search & Notif

Three pragmatic patterns to make the codebase reusable, ordered from simplest to most flexible:

Pattern A — Template repo (cel mai rapid)

  • Codebază JHipster template + checklist.
  • Pentru fiecare registru nou: fork, înlocuiește JDL, regenerează, rebrand i18n.
  • Pro: zero infra în plus, ușor de înțeles. Contra: divergență între forkuri.

Pattern B — Library + JDL conventions (recomandat pentru 3–10 registre)

  • Extrage într-o librărie Maven (gov-registry-commons) capabilities comune: audit trail, event store, public consultation skeleton, workflow base classes, document storage adapter, public API masking, rate limiter.
  • Fiecare registru rămâne aplicație JHipster separată dar depinde de librărie.
  • JDL convention: orice registru declară un entity Record, un entity Entitate, enumeri Statut/Stare, relații standard cu Authority și Act.

Pattern C — Multi-tenant SaaS platform (long-term, 10+ registre)

  • Single deployment, mai mulți tenanți.
  • Schema engine bazată pe JSONB + descriptors: fiecare record are (tenant_id, type, payload jsonb); descriptorul defines câmpuri, validări, workflow.
  • Workflow as data: state machine + tranziții stocate în DB, nu hardcoded.
  • Pro: un cod, multi-livrabil. Contra: complexitate substanțială, performanță Elasticsearch per tenant trebuie gândită, custom UI per registru e mai greu.

Recomandare: începe cu A, evoluează la B după al doilea registru. Treci la C doar dacă apare claritate că vor fi >10 registre cu cerințe foarte similare.

7.4 Multi-tenant model (Pattern C, doar dacă se ajunge acolo)

Section titled “7.4 Multi-tenant model (Pattern C, doar dacă se ajunge acolo)”
erDiagram
TENANT {
uuid id PK
varchar slug "interdictii | permise | sanctiuni"
varchar nume
jsonb config
}
RECORD_TYPE {
uuid id PK
uuid tenant_id FK
varchar code
jsonb schema "JSON Schema for payload"
jsonb workflow "state machine descriptor"
}
RECORD {
uuid id PK
uuid tenant_id FK
uuid record_type_id FK
uuid entity_id FK
varchar state
jsonb payload
timestamp valid_from
timestamp valid_to
}
ENTITY {
uuid id PK
uuid tenant_id FK
varchar identifier "IDNP/IDNO/VIN/..."
varchar type
jsonb attributes
}
EVENT {
uuid id PK
uuid record_id FK
varchar type
varchar actor
timestamp at
jsonb data
}
AUTHORITY {
uuid id PK
uuid tenant_id FK
varchar name
varchar family
}
DOCUMENT {
uuid id PK
uuid tenant_id FK
varchar uri
varchar sha256
varchar signature
}
RECORD_DOCUMENT {
uuid record_id FK
uuid document_id FK
varchar role
}
TENANT ||--o{ RECORD_TYPE : ""
TENANT ||--o{ ENTITY : ""
TENANT ||--o{ AUTHORITY : ""
RECORD_TYPE ||--o{ RECORD : ""
ENTITY ||--o{ RECORD : ""
AUTHORITY ||--o{ RECORD : "emite"
RECORD ||--o{ EVENT : ""
RECORD ||--o{ RECORD_DOCUMENT : ""
DOCUMENT ||--o{ RECORD_DOCUMENT : ""

7.5 Cross-cutting requirements (orice registru govtech)

Section titled “7.5 Cross-cutting requirements (orice registru govtech)”
  1. Audit complet, append-only — toate modificările → event store. Folosit la contestații, investigații, conformitate cu Legea privind protecția datelor.
  2. GDPR / Legea 133 — câmpuri sensibile maskate în API public, retenție configurabilă, drept la ștergere doar prin proces formal.
  3. Semnătură electronică — integrare cu MSign / serviciul guvernamental de semnătură pentru acte oficiale.
  4. MConnect / interop — SSO și schimb structurat de date cu alte registre guvernamentale; identitate federată pentru funcționari.
  5. Verificare automată identitate — IDNP la RSP, IDNO la ASP/ANAF, înainte de salvare.
  6. Multi-language — minim RO + RU + EN (Interdicții are doar RO + EN; alte registre au cerință RU obligatorie).
  7. Rate limiting + API keys pentru consumatorii externi ai API-ului public.
  8. Backup + DR — RPO ≤ 1h, RTO ≤ 4h pentru registre cu efect juridic.
gantt
title Registry Platform — roadmap orientativ
dateFormat YYYY-MM
axisFormat %b %Y
section Faza 1 — Interdicții v1
JDL + entități generate :done, 2026-04, 1M
Workflow DRAFT→ACTIV+aprobare :active, 2026-05, 1M
Ridicare + event log :2026-06, 1M
Public consultation API + masking :2026-07, 1M
Integrare MSign + MConnect SSO :2026-08, 1M
section Faza 2 — Hardening & Reuse
Extragere gov-registry-commons (Pattern B) :2026-09, 2M
Document storage (MinIO + hash + signature) :2026-10, 1M
Audit & reporting dashboard :2026-11, 1M
section Faza 3 — Al 2-lea registru (validare pattern)
Registry #2 pe gov-registry-commons :2026-12, 3M
Refactor după lecții învățate :2027-03, 1M
section Faza 4 — Multi-tenant (decizie după Faza 3)
Schema engine + JSONB records :2027-04, 3M
Workflow as data :2027-07, 2M
Tenant onboarding self-service :2027-09, 2M
CapabilityStack actual (Interdicții)Notă pentru reuse
Backend frameworkSpring Boot 3 + JHipster 8Bun pentru govtech RO/MD — comunitate, generators, audit gata.
FrontendAngular 19 standaloneOK pentru forms-heavy. Pentru portal public consideră Next.js separat.
DBPostgreSQL (prod), H2 (dev)Trece la PG și în dev pentru Pattern C (JSONB).
SearchElasticsearchPer-tenant index în Pattern C. Pentru registre mici, considera PG full-text.
CacheEhcache + Hibernate L2OK monolith. Trece la Redis dacă scalezi orizontal.
AuthJWT (HS512)Pentru MConnect SSO — adaugă OIDC layer (Keycloak).
Document storage(de adăugat)MinIO on-prem (cerință de suveranitate).
Workflow(hardcoded)Pentru Pattern C: state-machine ca date + engine simplu, nu Camunda decât dacă justificat.
MigrationsLiquibaseStrict per-tenant changelog dacă mergi multi-tenant cu schema separată.
NotificationsSMTP (JHipster MailService)Adaugă canal MConnect + SMS provider local.
AuditAbstractAuditingEntity + event log nouAppend-only event store separat de tabele de business.
  • Suveranitate date: hosting on-prem (govcloud MD) — exclude cloud public fără justificare legală.
  • Schema rigidă vs. JSONB: rigid e mai sigur la audit; JSONB e mai flexibil la onboarding registre noi. Decizia trebuie luată înainte de Pattern C.
  • Statut vs. stare: dacă în practică nu se folosesc independent, colapsează într-un singur enum în v1.1 (vezi nota din JDL).
  • Entitate polimorfică: extinderea la marfă/vehicul/armă necesită refactorizare semnificativă; planifică pentru Faza 2.
  • Workflow engine: rezistă tentației de a adopta BPMN engine complex (Camunda etc.) până nu există ≥ 3 workflow-uri reale care îl justifică.

  • interdictii_full.md — inventarul complet al domeniului (entități, statuturi, autorități, tipuri).
  • interdictii.jdl — schema autoritativă a entităților v0.
  • CLAUDE.md (root) — convenții de cod, layering, comenzi.
  • JHipster 8.11 docs: https://www.jhipster.tech/documentation-archive/v8.11.0