Skip to content

Arhitectură

  • Backend: Java 21, Spring Boot 3, Spring Security (JWT HS512 + OAuth2 resource server), Spring Data JPA + Criteria, MapStruct, Liquibase, Ehcache + Hibernate L2.
  • Frontend: Angular (componente standalone, signals), temă GDS cherry-red, IBM Plex.
  • Persistență: PostgreSQL (prod) / H2 (dev).
  • Object-store: MinIO (dev) / S3 (prod) — binarele documentelor; per-bucket bring-your-own.
  • Căutare: Elasticsearch (cablat manual, nu prin JDL — vezi mai jos).
  • Auth: JWT auto-emis (user/parolă) + Keycloak OIDC (dual-auth) + token de serviciu client-credentials pentru /api/v1.
  • Pachet: md.gov.gdocs, port 8095.
flowchart TD
SPA["Angular SPA (standalone, GDS)"] -- "HTTPS + JWT" --> R["web.rest.*Resource<br/>(controllers, DTO)"]
R --> S["service.*Service (+impl)"]
R --> Q["service.*QueryService<br/>(JPA Criteria + filtre)"]
S --> ACL["security.acl.DocumentAccessControl<br/>(L1/L2/L3 + izolare tenant)"]
S --> TEN["security.tenant.TenantContextResolver<br/>(tier per-request)"]
S --> M["service.mapper (MapStruct)"]
S --> REPO["repository.*Repository (Spring Data JPA)"]
S --> STO["service.storage.StorageService<br/>(MinIO/S3, per bucket)"]
S --> SRCH["service.search.* (Elasticsearch)"]
REPO --> PG[("PostgreSQL")]
STO --> OS[("MinIO / S3")]
SRCH --> ES[("Elasticsearch")]

Reguli de strat:

  • Entitățile nu părăsesc stratul de service — controllerele schimbă DTO-uri.
  • Filtrarea URL (*.equals, *.contains, *.in, range) există doar pe entitățile filter din JDL, via *QueryService + *Criteria.
  • ACL-ul la nivel de rând (L1/L2/L3 + izolare tenant) e ANDat în DocumentQueryService — toate listările/căutările trec prin el.
  • EvenimentDocument e append-only (audit, AppendOnlyAuditGuard + trigger).
  • Elasticsearch e cablat manual (fără searchEngine în JDL) — numele Document ar coliziona cu adnotarea ES @Document. L3 e indexat doar cu metadate (nu se scurge conținut secret).

security/acl/*, security/tenant/*, security/machine/*, security/oauth2/*, service/storage/*, service/tenant/*, service/search/*, service/arhiva/*, service/conversie/*, service/semnatura/*, service/partajare/*, web/rest/v1/*, web/rest/tenant/*, bootstrap/* (seed + backfill).

sequenceDiagram
participant U as Utilizator
participant SPA as Angular SPA
participant API as Spring Boot
U->>SPA: user + parolă
SPA->>API: POST /api/authenticate
API->>API: DomainUserDetailsService<br/>(+ mint ROLE_SERVICE_ADMIN/ORG_ADMIN)
API-->>SPA: id_token (JWT HS512, claim auth)
SPA->>API: Authorization: Bearer <jwt>
API->>API: resource server → authorities (prefix gol)
API-->>SPA: răspuns scopat pe tier + ACL

Alternativ: Keycloak OIDC (/oauth2/authorization/oidc) → success handler emite ACELAȘI JWT HS512; API mașină (POST /api/v1/token, client-credentials) → JWT cu ROLE_MACHINE + SCOPE_*.

sequenceDiagram
participant SPA
participant UP as DocumentUploadResource
participant G as TenantAccessGuard
participant SR as BucketStorageResolver
participant ST as StorageService
participant DB as PostgreSQL
SPA->>UP: POST /api/documents/upload (file, bucketId)
UP->>UP: acl.checkCreate(secret)
UP->>G: resolveUploadBucket(bucketId)
G-->>UP: Bucket (scriabil)
UP->>SR: targetFor(bucket) (endpoint+cheie decriptate)
UP->>ST: put(target, key, bytes)
ST-->>UP: ok (MinIO/S3 al bucket-ului)
UP->>DB: save Document (org, bucket, cod auto)
UP->>DB: EvenimentDocument CREAT (audit)
UP-->>SPA: {id, cod, storageUri}
flowchart LR
subgraph Box["AWS EC2 (shared gStack box)"]
EDGE["nginx edge (TLS, HTTP/2)"]
FE["saas_gdocs (nginx SPA)"]
BE["gdocs-backend (Spring Boot :8095)"]
PG[("gdocs-postgresql 17")]
MIN[("gdocs-minio")]
EDGE --> FE
FE -- "/api, /management" --> BE
BE --> PG
BE --> MIN
end
User["Browser / Sisteme"] -- HTTPS --> EDGE

Imagini: registry.esempla.systems/govtech/gstack/gdocs:{backend,frontend}-0.0.1. Detalii în Deployment.