Skip to content

Arhitectură

JHipster 8.11 monolit: Spring Boot 3 + Angular 19 (standalone), PostgreSQL (prod) / H2 (dev), JWT (HS512) + Keycloak OIDC opțional, Liquibase, MapStruct, Ehcache, RabbitMQ (Spring AMQP, cablat manual). Package md.gov.gnotify, port 8090. i18n RO (nativ) + EN. Fără Elasticsearch.

flowchart TD
subgraph Clienti
EXT[Sistem extern] -->|mTLS PFX| V1[/api/v1/**]
UI[Admin SPA / Portal] -->|JWT / OIDC| ADM[/api/**]
end
V1 --> DISP[NotificationDispatchService]
ADM --> DISP
DISP --> DB[(PostgreSQL:<br/>Notificare + Livrare + Eveniment)]
DISP -->|publish notify.{canal}.{tier}| MQ[[RabbitMQ]]
MQ --> W[Workeri @RabbitListener]
W --> CH[ChannelSender:<br/>EMAIL / SMS / PUSH / TELEGRAM]
W --> DB
W -.audit.-> GLOG[(GLog)]
W -.forward.-> MN[(MNotify mTLS)]
flowchart LR
subgraph "@Order(2) — mașină"
A[Sistem extern] -->|X-SSL-Client-* de la nginx| PFX[PfxAuthenticationFilter]
PFX -->|amprentă == certFingerprint| V1[/api/v1/**]
end
subgraph "@Order(1) — administrare"
B[Operator/cetățean] --> JWT[JWT HS512]
B --> OIDC[Keycloak OIDC realm gnotify]
JWT --> ADM[/api/**, UI]
OIDC --> ADM
end
  • Plan mașină — /api/v1/**: mTLS PFX (security/pfx/PfxAuthenticationFilter), lanț de securitate propriu @Order(2). Oglindește middleware-ul PHP PfxAuthenticate (headere X-SSL-Client-* puse de nginx la terminarea TLS).
  • Plan administrare — UI + /api/**: JWT + Keycloak OIDC dual-auth (@Order(1), gated de gnotify.oidc.enabled; realm gnotify pe sso.gstack.esempla.systems).

Vezi Security-and-Auth pentru detalii.

config/RabbitMqConfig + NotifyQueues: câte o coadă notify.{canal}.{tier} + .dlq pentru fiecare combinație — 6 cozi + 6 DLQ (email/push/telegram × priority/important; SMS adăugat ulterior).

  • DLX prin x-dead-letter-exchange="".
  • Retry [10, 30, 60, 120, 300]s × 5 încercări, apoi dead-letter.
  • Concurență worker: tier priority = 4, important = 2 (DeliveryProperties, env-overridable).
  • Job-urile (NotificationJob) sunt stateless — poartă conținutul deja randat, workerii nu citesc storage.
sequenceDiagram
participant S as Sistem extern
participant V1 as NotifyV1Resource
participant D as DispatchService
participant DB as PostgreSQL
participant MQ as RabbitMQ
participant W as Worker
participant P as Provider (SES/SNS/…)
S->>V1: POST /api/v1/notify/{id} (mTLS)
V1->>D: template + variabile + canale
D->>DB: Notificare(trackingId) + N×Livrare(QUEUED) + Eveniment(CREATED)
D->>MQ: publish notify.{canal}.{tier}
MQ->>W: consumă job
W->>P: trimite (randat)
P-->>W: providerMessageId | eroare
W->>DB: Livrare→SENT/FAILED + Eveniment; recalcul status agregat
S->>V1: GET /api/v1/notify/{id} → status

JDL este sursa de adevăr; toată logica scrisă de mână trăiește în clase separat denumite ca jhipster jdl să nu o suprascrie: web/rest/v1/*, security/pfx/*, security/oauth2/*, service/v1/*, service/delivery/*, service/channel/*, service/mnotify/*, service/registry/*, repository/lookup/*, config/RabbitMqConfig, audit/*.

Două imagini (backend jar + frontend nginx) + docker-compose-server.yml (backend + frontend + postgres + rabbitmq) pe rețelele internal + gstack-web. Edge vhost gnotify.gstack.esempla.systems. Registrul Destinatarilor are un al doilea SPA (registry-ui/, Angular 20) livrat ca container distinct saas_gnotify:registry-* → portalgnotify.gstack.esempla.systems. Detalii: Deployment.