Skip to content

GRegistry — Registrul Sistemelor Informaționale (RSI) · Platform Design

Acest document este sursa de adevăr arhitecturală pentru GRegistry, registrul sistemelor informaționale al platformei GStack (Republica Moldova). Acompaniază:

  • GRegistry.jdl — forma autoritativă a entităților (SOURCE OF TRUTH); orice schimbare de model se face acolo întâi, apoi se regenerează.
  • docs/db_schema.md — DDL PostgreSQL derivat din JDL + note de indexare.
  • docs/caiet_de_sarcini.md — cerințe funcționale și de conformitate.
  • docs/Home.md — punct de intrare wiki + glosar.
  • docs/adr/ — Architecture Decision Records (deciziile deschise din §7 se materializează aici pe măsură ce se închid).

Ce este GRegistry. Catalogul unic — single source of truth — al tuturor sistemelor informaționale din platforma GStack: sisteme CORE (GPass, GSign, GPay, GConnect), BUSINESS (Cancelarie, Interdicții), PAAS (GLog, GStorage, GNotify) și INFRASTRUCTURE (GSSO, GMonitor, GVault, GRegistry însuși). GRegistry este scris de operatori de registru și citit de restul platformei: GPortal (portal public — expune doar sistemele PUBLIC + PUBLISHED), GLog, GStorage și GMonitor.

Etichetele din diagrame folosesc termeni structurali în engleză (nume de clase, straturi) și termeni de domeniu în engleză proprii catalogului (InformationSystem, PublicationRequest), cu proză explicativă în română — oglindind convenția din codebase și documentul-soră saas_interdictii/docs/platform_design.md.

Diferă intenționat de Interdicții. GRegistry nu folosește Elasticsearch și nu folosește Kafka. Este un microservice API-first (clientFramework=no), autentificat prin OAuth2/OIDC la GSSO (Keycloak), nu prin JWT propriu.


Unde stă GRegistry între actorii care îl întrețin și sistemele GStack care îl consumă.

flowchart TB
subgraph Actors["Actori (staff)"]
Operator["Operator registru<br/>(ROLE_REGISTRY_OPERATOR)"]
Approver["Aprobator publicare<br/>(ROLE_REGISTRY_ADMIN)"]
Admin["Administrator platformă"]
end
subgraph GReg["GRegistry — RSI (microservice, :8085)"]
SPA["GRegistry SPA<br/>(Angular, separat — API-first)"]
API["REST API<br/>(Spring Boot 3, api/v1)"]
PubZone["Zona publică read-only<br/>(api/v1/public — vis=PUBLIC)"]
end
subgraph Consumers["Consumatori GStack (read-only)"]
GPortal["GPortal<br/>(portal public — doar PUBLIC + PUBLISHED)"]
GLog["GLog<br/>(logare centralizată)"]
GStorage["GStorage"]
GMonitor["GMonitor<br/>(health / uptime)"]
end
subgraph Platform["Servicii de platformă"]
GSSO["GSSO / Keycloak<br/>(OAuth2 / OIDC)"]
Registry["Service discovery<br/>(JHipster Registry / Consul)"]
end
Operator -->|CRUD sisteme, medii, dependențe| SPA
Approver -->|propune / aprobă / publică| SPA
Admin -->|providers, consumatori, audit| SPA
SPA -->|HTTPS + OIDC bearer| API
API --> PubZone
GPortal -->|GET filtrat vis=PUBLIC & publishedToPortal=true| PubZone
GLog -->|citește catalog + preia RegistryAudit| API
GStorage -->|rezolvă coduri de sistem| API
GMonitor -->|citește Environment + endpoint-uri| API
SPA -. login OIDC .-> GSSO
API <-.->|validează bearer token / JWKS| GSSO
API -. self-register .-> Registry

Roluri cheie în context:

  • GRegistry scrie o singură dată, citește de multe ori. Operatorii întrețin catalogul; toate celelalte sisteme îl consumă. Nu există flux invers de scriere dinspre consumatori.
  • GPortal este consumatorul cel mai restricționat: vede exclusiv sistemele cu visibility = PUBLIC și publishedToPortal = true. Sistemele INTERNAL și TEST nu părăsesc niciodată registrul.
  • Autentificarea este externă (GSSO/Keycloak). GRegistry este un OAuth2 resource server: validează bearer token-uri OIDC pe cheile publice (JWKS) ale realm-ului gregistry și mapează claim-urile de rol la authorities Spring Security (ROLE_REGISTRY_OPERATOR, ROLE_REGISTRY_ADMIN).

Layering standard JHipster pentru un microservice Spring Boot 3, fără UI servit din backend (clientFramework=no) și fără Elasticsearch / Kafka.

flowchart LR
subgraph Browser["Browser / consumatori"]
SPA["GRegistry SPA<br/>(Angular, styling din<br/>GRegistry.dc.html)"]
Ext["GPortal / GLog / GStorage / GMonitor<br/>(HTTP clients)"]
end
subgraph Backend["Microservice md.gov.gregistry (:8085)"]
direction TB
Sec["SecurityFilterChain<br/>OAuth2 resource server (JWT/OIDC)"]
Rest["web.rest.*Resource<br/>(controllers — DTOs only)"]
Svc["service.*Service<br/>(+ impl/)"]
QSvc["service.*QueryService<br/>(JPA Criteria filtering)"]
Map["service.mapper<br/>(MapStruct)"]
Dto["service.dto"]
Repo["repository.*Repository<br/>(Spring Data JPA)"]
Dom["domain.*<br/>(JPA entities)"]
Audit["AbstractAuditingEntity<br/>+ AuditorAware (OIDC subject)"]
Liq["Liquibase changelogs"]
end
subgraph Stores["Stores"]
PG[("PostgreSQL")]
Cache[("Ehcache + Hibernate L2")]
end
subgraph Platform["Platformă"]
GSSO["GSSO / Keycloak (JWKS)"]
Registry["Service discovery"]
end
SPA -- HTTPS + OIDC bearer --> Sec
Ext -- HTTPS + OIDC bearer --> Sec
Sec --> Rest
Rest --> Svc
Svc --> QSvc
Svc --> Map
Map --> Dto
QSvc --> Repo
Svc --> Repo
Repo --> Dom
Dom --> Audit
Repo --> Cache
Repo --> PG
Liq -. migrations .-> PG
Sec -. validează token .-> GSSO
Backend -. self-register .-> Registry

Convenții cheie (obligatorii):

  • Controllerele schimbă doar DTO-uri cu exteriorul; entitățile JPA nu părăsesc niciodată service layer-ul (regulă identică cu Interdicții).
  • Filtrarea URL-driven există doar pe entitățile declarate filter în JDL — InformationSystem, Environment, PublicationRequest, SystemDependency — prin perechea *QueryService + *Criteria (JPA Criteria API). Celelalte entități (Provider, ApiEndpoint, RegistryConsumer, RegistryAudit) se accesează prin repository standard.
  • Paginare activă pe InformationSystem, RegistryAudit, Environment, PublicationRequest (opțiunea paginate ... with pagination).
  • AbstractAuditingEntity populează automat createdBy / createdDate / lastModifiedBy / lastModifiedDate; AuditorAware extrage identitatea din subiectul token-ului OIDC (sub / preferred_username).
  • Cache L2 (Ehcache) pe entitățile de referință citite intens de consumatori (Provider, InformationSystem), pentru a absorbi traficul read-heavy fără un motor de căutare dedicat.
  • Fără Elasticsearch, fără Kafka. Interogările de catalog se rezolvă în PostgreSQL (indexuri + JPA Criteria); nu există repository.search.* și niciun producer/consumer de evenimente.

Rezumat — DDL-ul complet și notele de indexare stau în docs/db_schema.md. Diagrama ER de mai jos reflectă direct GRegistry.jdl.

erDiagram
PROVIDER {
bigint id PK
varchar code UK "2..60"
varchar name
varchar legal_name
varchar contact_email
varchar website
boolean active
}
INFORMATION_SYSTEM {
bigint id PK
varchar code UK "^[a-z][a-z0-9-]*$"
varchar name
varchar category
varchar system_type "SystemType"
varchar status "SystemStatus"
varchar visibility "Visibility"
varchar criticality "Criticality"
varchar security_level "SecurityLevel"
boolean handles_personal_data
varchar current_version
varchar description_ro
varchar description_en
varchar tech_lead
varchar tech_lead_email
boolean published_to_portal "denormalizat din PublicationRequest"
timestamp created_at
timestamp updated_at
bigint provider_id FK "required"
}
ENVIRONMENT {
bigint id PK
varchar environment_type "EnvironmentType"
varchar state "EnvironmentState"
varchar endpoint_url
varchar deployed_version
boolean monitored
timestamp last_checked_at
bigint system_id FK "required"
}
SYSTEM_DEPENDENCY {
bigint id PK
varchar kind "DependencyKind"
boolean required
varchar note
bigint system_id FK "consumatorul (required)"
bigint depends_on_id FK "serviciul consumat (required)"
}
PUBLICATION_REQUEST {
bigint id PK
varchar state "PublicationState"
varchar requested_by
timestamp requested_at
varchar approved_by
timestamp approved_at
timestamp published_at
varchar requested_visibility "Visibility"
varchar comment
bigint system_id FK "required"
}
API_ENDPOINT {
bigint id PK
varchar path
varchar protocol "ApiProtocol"
varchar method
varchar description
boolean public_api
bigint system_id FK "required"
}
REGISTRY_CONSUMER {
bigint id PK
varchar name
varchar description
varchar filter_expression "ex. vis=public"
boolean active
}
REGISTRY_AUDIT {
bigint id PK
varchar change_type "ChangeType"
varchar actor
varchar summary_ro
varchar summary_en
varchar ip_address
timestamp occurred_at
bigint system_id FK "optional"
}
PROVIDER ||--o{ INFORMATION_SYSTEM : "deține"
INFORMATION_SYSTEM ||--o{ ENVIRONMENT : "are medii"
INFORMATION_SYSTEM ||--o{ PUBLICATION_REQUEST : "cereri publicare"
INFORMATION_SYSTEM ||--o{ API_ENDPOINT : "expune"
INFORMATION_SYSTEM ||--o{ REGISTRY_AUDIT : "istoric modificări"
INFORMATION_SYSTEM ||--o{ SYSTEM_DEPENDENCY : "consumă (system)"
INFORMATION_SYSTEM ||--o{ SYSTEM_DEPENDENCY : "este consumat (dependsOn)"

Note de schemă (detalii în docs/db_schema.md):

  • InformationSystem.code este cheia de join stabilă folosită de toți consumatorii (^[a-z][a-z0-9-]*$, unic). Numele afișabil (name) se poate schimba fără a rupe integrările.
  • SystemDependency este graful de dependențe modelat prin două ManyToOne către InformationSystem: system (consumatorul) și dependsOn (serviciul consumat). Alimentează matricea de dependențe și vederile „consumed by”. Vezi §5.2 și întrebarea deschisă privind ciclurile (§7).
  • publishedToPortal este un flag denormalizat pe InformationSystem, ținut în sincron cu starea PublicationRequest la tranzițiile PUBLISH/UNPUBLISH (§4A). Sursa de adevăr a workflow-ului rămâne PublicationRequest.
  • RegistryAudit este append-only din perspectiva aplicației: service layer-ul interzice UPDATE/DELETE (forensic / conformitate). Fiecare tranziție de stare și fiecare mutație de catalog scrie exact un rând.
  • Enumeri (SystemType, SystemStatus, Visibility, Criticality, SecurityLevel, EnvironmentType, EnvironmentState, PublicationState, DependencyKind, ChangeType, ApiProtocol) se persistă ca varchar prin @Enumerated(STRING) — convenția JHipster.

4.A PublicationRequest — fluxul de publicare (primar)

Section titled “4.A PublicationRequest — fluxul de publicare (primar)”

Guvernează dacă un sistem apare pe GPortal, cu poartă de aprobare DRAFT → PROPOSED → APPROVED → PUBLISHED. Doar sistemele cu visibility = PUBLIC pot atinge PUBLISHED. La PUBLISH, InformationSystem.publishedToPortal = true; la UNPUBLISH, false. Fiecare tranziție scrie un rând RegistryAudit (append-only).

stateDiagram-v2
[*] --> DRAFT: creată (OPERATOR)
DRAFT --> PROPOSED: propose<br/>(OPERATOR)
PROPOSED --> APPROVED: approve<br/>(ADMIN)
PROPOSED --> REJECTED: reject<br/>(ADMIN)
APPROVED --> PUBLISHED: publish<br/>[guard: visibility=PUBLIC]<br/>publishedToPortal=true
PUBLISHED --> UNPUBLISHED: unpublish<br/>publishedToPortal=false
REJECTED --> DRAFT: revizuire
UNPUBLISHED --> DRAFT: reia ciclul
PUBLISHED --> [*]
REJECTED --> [*]
UNPUBLISHED --> [*]
note right of APPROVED
Poarta de vizibilitate:
tranziția publish este
respinsă (409) dacă
InformationSystem.visibility
!= PUBLIC.
end note
note left of PUBLISHED
Singura stare în care sistemul
este vizibil pe GPortal.
publishedToPortal=true este
citit de consumatori.
end note

Matrice tranziție → RegistryAudit (ChangeType):

De la → laAcțiuneChangeType scrisActorEfect secundar
∅ → DRAFTcreateCREATEOPERATOR—
DRAFT → PROPOSEDproposeSTATUS_CHANGEOPERATORrequestedBy/At
PROPOSED → APPROVEDapproveSTATUS_CHANGEADMINapprovedBy/At
PROPOSED → REJECTEDrejectSTATUS_CHANGEADMINcomment
APPROVED → PUBLISHEDpublishPUBLISHADMINpublishedToPortal=true, publishedAt
PUBLISHED → UNPUBLISHEDunpublishUNPUBLISHADMINpublishedToPortal=false
REJECTED / UNPUBLISHED → DRAFTrevizuireEDITOPERATOR—

Guard-ul de vizibilitate și scrierea RegistryAudit se enforce în service layer (PublicationRequestServiceImpl), nu în controller.

4.B InformationSystem.status — ciclul de viață al sistemului (secundar)

Section titled “4.B InformationSystem.status — ciclul de viață al sistemului (secundar)”

Independent de publicare: descrie maturitatea tehnică a sistemului.

stateDiagram-v2
[*] --> PLANNED: înregistrat
PLANNED --> DEMO: build demo disponibil
DEMO --> ACTIVE: intrat în producție
ACTIVE --> DEPRECATED: marcat pentru retragere
DEPRECATED --> RETIRED: scos din uz
DEPRECATED --> ACTIVE: repus în uz (rollback)
RETIRED --> [*]
note right of ACTIVE
Tranzițiile scriu
RegistryAudit cu
ChangeType=STATUS_CHANGE.
end note

4.C Environment.state — sănătatea mediului (secundar)

Section titled “4.C Environment.state — sănătatea mediului (secundar)”

Actualizat manual de operator sau împins de GMonitor; scrie RegistryAudit cu ChangeType=ENV_CHANGE.

stateDiagram-v2
[*] --> PLANNED: mediu declarat, nedesfășurat
PLANNED --> NONE: fără date de sănătate
PLANNED --> UP: desfășurat + healthy
NONE --> UP: primă verificare OK
UP --> DEGRADED: latență / erori parțiale
DEGRADED --> UP: recuperat
UP --> DOWN: indisponibil
DEGRADED --> DOWN: escaladare
DOWN --> UP: restabilit
DOWN --> DEGRADED: recuperare parțială

5.1 Înregistrare + publicare a unui sistem (cu poartă de aprobare)

Section titled “5.1 Înregistrare + publicare a unui sistem (cu poartă de aprobare)”
flowchart TD
Start([Operator inițiază]) --> SelProv{Provider<br/>existent?}
SelProv -- Nu --> NewProv[Creează Provider<br/>code, name, active]
SelProv -- Da --> PickProv[Selectează Provider]
NewProv --> Fill
PickProv --> Fill[Completează InformationSystem<br/>code, name, systemType, status,<br/>visibility, criticality, securityLevel]
Fill --> SaveSys[POST /api/v1/information-systems]
SaveSys --> ValSys{Validare<br/>backend?}
ValSys -- Eșec --> ErrSys[RFC 7807 problem+json] --> Fill
ValSys -- OK --> PersistSys[INSERT InformationSystem<br/>publishedToPortal=false]
PersistSys --> AuditC[RegistryAudit: CREATE]
AuditC --> AddEnv[Adaugă Environment-uri<br/>prod / staging / test]
AddEnv --> CreatePR[Creează PublicationRequest<br/>state=DRAFT]
CreatePR --> Propose[propose → state=PROPOSED]
Propose --> Review{Admin<br/>aprobă?}
Review -- Respinge --> Reject[state=REJECTED<br/>RegistryAudit: STATUS_CHANGE]
Review -- Aprobă --> Approved[state=APPROVED]
Approved --> VisGuard{visibility<br/>= PUBLIC?}
VisGuard -- Nu --> Blocked[409 — nu poate fi publicat<br/>rămâne APPROVED]
VisGuard -- Da --> Publish[state=PUBLISHED<br/>publishedToPortal=true<br/>RegistryAudit: PUBLISH]
Publish --> Portal[GPortal îl preia la<br/>următoarea consultare]
Portal --> End([Final])
Blocked --> End
Reject --> End

5.2 Adăugare / reîmprospătare a unei dependențe (actualizează matricea)

Section titled “5.2 Adăugare / reîmprospătare a unei dependențe (actualizează matricea)”
flowchart TD
Start([Operator: editează dependențe]) --> PickSys[Selectează InformationSystem<br/>consumatorul = system]
PickSys --> PickDep[Selectează serviciul consumat<br/>dependsOn]
PickDep --> Cycle{Auto-referință<br/>system == dependsOn?}
Cycle -- Da --> RejectSelf[Refuz: dependență reflexivă]
Cycle -- Nu --> SetKind[Setează kind<br/>API/EVENT/DATA/AUTH/STORAGE + required]
SetKind --> SaveDep[POST /api/v1/system-dependencies]
SaveDep --> Exists{Dependența<br/>există deja?}
Exists -- Da --> Update[UPDATE kind/required/note<br/>RegistryAudit: DEPENDENCY_CHANGE]
Exists -- Nu --> Insert[INSERT SystemDependency<br/>RegistryAudit: DEPENDENCY_CHANGE]
Update --> Matrix
Insert --> Matrix[Recalculează matricea de dependențe<br/>+ vederea consumed-by]
Matrix --> End([Final])
RejectSelf --> End

Ciclurile indirecte (A→B→A) nu sunt blocate în v1 — vezi întrebarea deschisă din §7.

5.3 Consultare publică de către un consumator (cu filtrare pe vizibilitate)

Section titled “5.3 Consultare publică de către un consumator (cu filtrare pe vizibilitate)”
flowchart TD
Start([Consumator: GPortal / sistem extern]) --> Auth{Token OIDC<br/>valid?}
Auth -- Nu --> Unauth[401 / 403 — RFC 7807]
Auth -- Da --> Query[GET /api/v1/public/information-systems<br/>?visibility.equals=PUBLIC]
Query --> Filter[QueryService aplică filtrul server-side:<br/>visibility=PUBLIC AND publishedToPortal=true]
Filter --> Project[Proiectează DTO public<br/>fără câmpuri interne/tech-lead sensibile]
Project --> Found{Rezultate?}
Found -- Nu --> Empty[200 OK — listă goală]
Found -- Da --> Return[200 OK + pagină DTO]
Return --> AuditRead[RegistryAudit: read extern<br/>actor=consumer, ipAddress]
Empty --> AuditRead
AuditRead --> End([Final])
Unauth --> End

6.1 Operatorul înregistrează un sistem nou

Section titled “6.1 Operatorul înregistrează un sistem nou”
sequenceDiagram
autonumber
actor Op as Operator
participant SPA as GRegistry SPA
participant API as InformationSystemResource
participant Svc as InformationSystemServiceImpl
participant Map as InformationSystemMapper
participant Repo as InformationSystemRepository
participant AudSvc as RegistryAuditService
participant DB as PostgreSQL
Op->>SPA: completează formular sistem
SPA->>API: POST /api/v1/information-systems (DTO + Bearer)
API->>API: @PreAuthorize ROLE_REGISTRY_OPERATOR
API->>Svc: save(dto)
Svc->>Map: toEntity(dto)
Map-->>Svc: InformationSystem
Svc->>Repo: save(entity)
Repo->>DB: INSERT (+ AbstractAuditingEntity:<br/>created_by/created_date din OIDC subject)
DB-->>Repo: row(id)
Repo-->>Svc: persisted entity
Svc->>AudSvc: record(CREATE, actor, systemId)
AudSvc->>DB: INSERT RegistryAudit (append-only)
Svc->>Map: toDto(entity)
Map-->>Svc: dto
Svc-->>API: dto
API-->>SPA: 201 Created + Location
SPA-->>Op: confirmare + redirect detalii

6.2 Operatorul propune, adminul aprobă și publică o PublicationRequest

Section titled “6.2 Operatorul propune, adminul aprobă și publică o PublicationRequest”
sequenceDiagram
autonumber
actor Op as Operator
actor Adm as Admin
participant SPA as GRegistry SPA
participant API as PublicationRequestResource
participant Svc as PublicationRequestServiceImpl
participant SysSvc as InformationSystemService
participant Repo as PublicationRequestRepository
participant AudSvc as RegistryAuditService
participant DB as PostgreSQL
Op->>SPA: creează cerere + propose
SPA->>API: PATCH /api/v1/publication-requests/{id}/propose
API->>Svc: propose(id)
Svc->>Repo: save(state=PROPOSED)
Svc->>AudSvc: record(STATUS_CHANGE)
Svc-->>API: dto (PROPOSED)
API-->>SPA: 200 OK
Adm->>SPA: deschide coada de aprobare
SPA->>API: GET /api/v1/publication-requests?state.equals=PROPOSED
API->>Svc: findByCriteria (QueryService)
Svc-->>SPA: page<DTO>
Adm->>SPA: click "Approve & Publish"
SPA->>API: PATCH /api/v1/publication-requests/{id}/publish
API->>API: @PreAuthorize ROLE_REGISTRY_ADMIN
API->>Svc: approveAndPublish(id)
Svc->>Repo: findById(id)
Repo-->>Svc: entity (PROPOSED/APPROVED)
Svc->>SysSvc: assert visibility == PUBLIC
alt visibility != PUBLIC
SysSvc-->>Svc: false
Svc-->>API: throw (RFC 7807, 409 Conflict)
API-->>SPA: 409 problem+json
else visibility == PUBLIC
Svc->>Repo: save(state=APPROVED → PUBLISHED)
Svc->>SysSvc: setPublishedToPortal(systemId, true)
SysSvc->>DB: UPDATE information_system SET published_to_portal=true
Svc->>AudSvc: record(PUBLISH)
AudSvc->>DB: INSERT RegistryAudit
Svc-->>API: dto (PUBLISHED)
API-->>SPA: 200 OK
end
sequenceDiagram
autonumber
participant GP as GPortal
participant GSSO as GSSO / Keycloak
participant Sec as SecurityFilterChain (resource server)
participant API as PublicInformationSystemResource
participant QSvc as InformationSystemQueryService
participant Repo as InformationSystemRepository
participant AudSvc as RegistryAuditService
participant DB as PostgreSQL
GP->>GSSO: client_credentials grant
GSSO-->>GP: access_token (OIDC)
GP->>Sec: GET /api/v1/public/information-systems<br/>?visibility.equals=PUBLIC (Bearer)
Sec->>Sec: validează semnătura pe JWKS + scope
alt token invalid
Sec-->>GP: 401 (RFC 7807 problem+json)
else token valid
Sec->>API: forward
API->>QSvc: findByCriteria(vis=PUBLIC)
QSvc->>QSvc: forțează publishedToPortal=true
QSvc->>Repo: JPA Criteria query
Repo->>DB: SELECT ... WHERE visibility='PUBLIC'<br/>AND published_to_portal=true
DB-->>Repo: rows
Repo-->>QSvc: page<InformationSystem>
QSvc-->>API: page<PublicDTO>
API->>AudSvc: record(read extern, actor=gportal)
AudSvc->>DB: INSERT RegistryAudit
API-->>GP: 200 OK + pagină DTO
end

6.4 Actualizarea sănătății unui mediu — prod marcat DOWN

Section titled “6.4 Actualizarea sănătății unui mediu — prod marcat DOWN”
sequenceDiagram
autonumber
participant GM as GMonitor
participant SPA as GRegistry SPA (sau API direct)
participant API as EnvironmentResource
participant Svc as EnvironmentServiceImpl
participant Repo as EnvironmentRepository
participant AudSvc as RegistryAuditService
participant DB as PostgreSQL
GM->>API: PATCH /api/v1/environments/{id}<br/>{ state: DOWN } (Bearer)
API->>API: @PreAuthorize ROLE_REGISTRY_OPERATOR
API->>Svc: partialUpdate(dto)
Svc->>Repo: findById(id)
Repo-->>Svc: env (state=UP, type=PRODUCTION)
Svc->>Svc: validează tranziția UP → DOWN (§4.C)
Svc->>Repo: save(state=DOWN, lastCheckedAt=now)
Repo->>DB: UPDATE environment
Svc->>AudSvc: record(ENV_CHANGE, "prod DOWN")
AudSvc->>DB: INSERT RegistryAudit
Svc-->>API: dto (DOWN)
API-->>GM: 200 OK
Note over GM,API: GMonitor și dashboard-urile<br/>reflectă noua stare la următoarea citire

6.5 Login OIDC prin GSSO / Keycloak (bearer token flow)

Section titled “6.5 Login OIDC prin GSSO / Keycloak (bearer token flow)”
sequenceDiagram
autonumber
actor U as Utilizator (staff)
participant SPA as GRegistry SPA
participant GSSO as GSSO / Keycloak (realm gregistry)
participant Sec as SecurityFilterChain (resource server)
participant API as *Resource
U->>SPA: accesează aplicația
SPA->>GSSO: redirect Authorization Code + PKCE
U->>GSSO: autentificare (user / parolă / MFA)
GSSO-->>SPA: authorization code
SPA->>GSSO: schimbă code → tokens (token endpoint)
GSSO-->>SPA: access_token (JWT/OIDC) + id_token + refresh_token
SPA->>SPA: stochează token; extrage rolurile din claims
SPA->>Sec: GET /api/v1/... (Authorization: Bearer <access_token>)
Sec->>GSSO: obține/cache-uiește JWKS (chei publice)
Sec->>Sec: validează semnătura, exp, issuer, audience
Sec->>Sec: mapează claims → authorities (ROLE_REGISTRY_*)
Sec->>API: request autorizat
API-->>SPA: 200 OK (DTO)
Note over SPA,GSSO: la expirare, SPA reînnoiește<br/>silențios cu refresh_token

7. GRegistry în platforma GStack — rol, standarde și decizii deschise

Section titled “7. GRegistry în platforma GStack — rol, standarde și decizii deschise”

GRegistry este coloana vertebrală de metadate a GStack: sursa unică din care celelalte sisteme află ce sisteme există, cine le deține, ce endpoint-uri expun, în ce mediu rulează și care depinde de care.

flowchart LR
subgraph Src["Sursa de adevăr"]
GReg["GRegistry (RSI)"]
end
subgraph Feeds["Alimentează (read-only)"]
GPortal["GPortal<br/>catalog public (PUBLIC + PUBLISHED)"]
GLog["GLog<br/>preia RegistryAudit + rezolvă coduri"]
GStorage["GStorage<br/>rezolvă owner/system după code"]
GMonitor["GMonitor<br/>ținte de monitorizare din Environment"]
end
GReg --> GPortal
GReg --> GLog
GReg --> GStorage
GReg --> GMonitor
GMonitor -. push health .-> GReg
  • GPortal citește exclusiv sistemele PUBLIC + publishedToPortal=true și le afișează cetățenilor.
  • GLog consumă RegistryAudit (append-only) pentru logare centralizată și rezolvă codurile de sistem la nume lizibile.
  • GStorage folosește InformationSystem.code ca cheie de proprietate a artefactelor.
  • GMonitor citește Environment (endpoint-uri + monitored) ca listă de ținte și poate împinge înapoi starea de sănătate (ENV_CHANGE).

GRegistry expune un contract HTTP conform convenției GStack (aceeași în tot ecosistemul):

ElementConvenție
Versionareprefix /api/v1
Zone de accesapi/v1/public (consultare, vis=PUBLIC), api/v1 staff (operator), api/v1/admin (aprobare/config)
Health/health/live (liveness), /health/ready (readiness) — expuse prin Spring Boot Actuator
Metrici/metrics (Micrometer / Prometheus)
Contract/api/v1/openapi.json (springdoc OpenAPI 3)
EroriRFC 7807 application/problem+json pentru toate răspunsurile de eroare
AuthOAuth2 / OIDC bearer (GSSO / Keycloak), authorities ROLE_REGISTRY_*

Zonele de acces se mapează la authorities: public nu cere rol de scriere (doar token valid + scope de citire), staff cere ROLE_REGISTRY_OPERATOR, iar tranzițiile de aprobare/publicare cer ROLE_REGISTRY_ADMIN (vezi §4.A, §6.2).

Se materializează ca ADR-uri în docs/adr/ pe măsură ce se închid:

  1. Retenția RegistryAudit. Append-only, dar cât timp online? Politica de arhivare / offload către GLog și pragul de partiționare temporală nu sunt încă fixate. → candidat ADR.
  2. Ciclurile de dependență. SystemDependency interzice auto-referința directă (§5.2), dar ciclurile indirecte (A→B→A) sunt permise în v1. De decis dacă validăm aciclicitatea (DAG) la scriere sau doar semnalăm în matrice. → ADR.
  3. Modelul de autentificare al consumatorilor. GPortal/GLog/GStorage/GMonitor accesează prin client_credentials (service accounts în Keycloak) sau printr-un API gateway cu chei? Entitatea RegistryConsumer (filterExpression, active) sugerează o listă de consumatori guvernată; relația cu conturile de serviciu Keycloak trebuie clarificată. → ADR.
  4. Unicitate SystemDependency. Trebuie un constraint unic pe (system, dependsOn, kind) pentru a evita duplicatele? Vezi și docs/db_schema.md.

Aceste puncte sunt lăsate deliberat deschise pentru build-ul demo curent; se revizuiesc înainte de orice pas de production hardening (paralel cu checklistul din saas_interdictii/docs/db_schema.md §8).


  • GRegistry.jdl — schema autoritativă a entităților (SOURCE OF TRUTH).
  • docs/db_schema.md — DDL PostgreSQL + note de indexare și unicitate.
  • docs/caiet_de_sarcini.md — cerințe funcționale și de conformitate.
  • docs/Home.md — punct de intrare wiki + glosar GStack.
  • docs/adr/ — Architecture Decision Records (deciziile din §7.3).
  • GRegistry.dc.html — design context / sursă de styling pentru SPA.
  • saas_interdictii/docs/platform_design.md — documentul-soră (Interdicții), din care se împrumută structura și convențiile de diagramare.
  • JHipster 8 microservices: https://www.jhipster.tech/microservices-architecture/
  • RFC 7807 (Problem Details for HTTP APIs): https://www.rfc-editor.org/rfc/rfc7807