ti&m e-gov-framework

8 Querschnittliche Konzepte

Dieses Kapitel beschreibt technische Konzepte, die mehrere Bausteine des e-gov-framework betreffen und systemweit einheitlich umgesetzt sind.


8.1 Sicherheit und Autorisierung

8.1.1 Authentifizierung (vorgelagert)

Das Framework führt keine eigene Authentifizierung durch. Die Identität des Nutzers wird durch die vorgelagerte Infrastruktur festgestellt. Die F5-Firewall setzt nach erfolgtem Login einen EGOV_TOKEN-Cookie. Der ContextInterceptor des Frameworks extrahiert daraus die userId über das UserIdProvider-Interface, das jede consuming App implementiert, und speichert sie für die Dauer des Requests im DataHolder-ThreadLocal.

HTTP-Request
  → ContextInterceptor.preHandle()
    → UserIdProvider.getUserId(request)   ← consuming-App-Implementierung
    → DataHolder.setUserId(userId)        ← ThreadLocal
  → alle nachgelagerten Komponenten lesen userId über DataHolder.getUserId()
  → ContextInterceptor.afterCompletion()
    → DataHolder.clear()                  ← ThreadLocal aufräumen

8.1.2 Row-based Security

Jede Datenbankabfrage wird automatisch um rollenbasierte WHERE-Klauseln erweitert. Kein Code in der consuming App muss explizit filtern — die Sicherheit greift auf Infrastruktur- ebene im QueryBuilder.

Datenmodell (Flyway DDL):

Tabelle Zweck
egov_iam_role Rollendefinitionen
egov_iam_role_membership Benutzer-Rollen-Zuordnungen (mit valid_from/valid_to)
egov_iam_permission_definition Rollenspezifische SQL-Filterbedingungen pro Entity und Operation
egov_iam_rule_set Validierungsregelsets pro Action
egov_iam_condition Bedingungen innerhalb eines RuleSets

Ablauf:

BaseRepositoryImpl.find(parameters)
  → PermissionBuilder.getPermissions(userId, entityClass, operation)
    → PermissionService.getAllowedRecordsQuery(userId, operation, clazz)
      → Rollenermittlung aus egov_iam_role_membership (userId, aktuelles Datum)
      → SQL-Filterausdruck aus egov_iam_permission_definition (role, entity, operation)
      → Rückgabe: AllowedRecordsQuery (Query-String + Parameter-Werte)
  → ParametrizedQuery wird als WHERE-Klausel in native SQL integriert

8.2 Command-Pattern und Audit-Trail

Alle fachlichen Operationen werden als Command-JPA-Entity in der Tabelle egov_cmd_command persistiert. Dadurch entsteht ein lückenloses Audit-Log aller Aktionen.

8.2.1 Status-Lifecycle

INITIALIZED
  → RULESET_SELECTED   (nach RuleSet-Auflösung)
  → VALIDATED          (nach Validierung)
  → COMPLETED
  → EXECUTED           (Endzustand: Erfolg)

  → HARD_VALIDATION_FAILED   (Endzustand: Fehler)

Beide Felder status und executionPlan sind als @Enumerated(EnumType.STRING) gemappt.

8.2.2 ExecutionPlan

Der ExecutionPlan steuert, ob und in welcher Reihenfolge Validierung und Ausführung stattfinden:

Wert Verhalten
VALIDATE_BEFORE_EXECUTION Bricht bei Validierungsfehler ab (Standard)
VALIDATE_BEFORE_EXECUTING_ANYWAY Validiert, führt aber immer aus
VALIDATE_AFTER_EXECUTION Führt zuerst aus, validiert danach
DONT_VALIDATE Keine Validierung
DONT_EXECUTE Keine Ausführung (z.B. Dry-Run)

8.2.3 Executor-Varianten

Interface Merkmal Verwendung
Executor @Transactional auf execute() Standard-Schreiboperationen
NonTxExecutor kein @Transactional Operationen, die ausserhalb einer Spring-Transaktion laufen müssen (bekanntes Risiko R-2)
RemoteCommandExecutor Ausführung über ZooKeeper Verteilte Commands über mehrere Instanzen
BatchUpdateExecutor<T> Batch-Verarbeitung mit Progress-Logging Massenoperationen

Basisimplementierung: CommandHandlerBase<T> orchestriert Validation → Execution → Status-Persistierung.


8.3 Fehlerbehandlung

8.3.1 Exception-Hierarchie

Alle Framework-Exceptions erben von EGovException und tragen einen strukturierten code (String) sowie optionale additionalInfo (Map).

EGovException
  ├── NoPermissionForEntityException   → HTTP 403
  ├── ActionNotAllowedException        → HTTP 405
  ├── UnauthorizedException            → HTTP 401
  └── SystemException                  → HTTP 500

RuntimeException
  └── ValidationException              (intern, kein HTTP-Mapping)

8.3.2 Einheitliche Fehlerantwort

GenericExceptionHandler (@ControllerAdvice) fängt alle Exceptions und wandelt sie in ein einheitliches ResponseExceptionBody-DTO um:

{
  "message": "No permission for entity 'Person' (operation: READ)",
  "exceptionId": "f3a1bc42-...",
  "errorCode": "EGOV_FRM_0012",
  "additionalInfo": { "tableName": "person", "userId": "u42" },
  "stackTrace": null
}

Stacktrace wird nur ausgegeben wenn egov.exception-log.debug=true gesetzt ist.

8.3.3 Fehler-Code-Schema

Code Bedeutung
EGOV_FRM_0000 Generischer Framework-Fehler
EGOV_FRM_0001 Ungültige Daten
EGOV_FRM_0012 Keine Berechtigung auf Entity
EGOV_FRM_0013 Kein Executor gesetzt
EGOV_FRM_0014 Ungültige Action
EGOV_FRM_0015 ZooKeeper-Fehler
EGOV_PRS_0000 ID-Limit überschritten (LUID)

8.4 Persistenz

8.4.1 Repository-Pattern

Alle Domänen-Entitäten der consuming App erweitern BaseRepositoryImpl<T>. Diese Basisklasse stellt generische CRUD-Operationen bereit und delegiert den Query-Bau an den QueryBuilder.

8.4.2 Filter-DSL

REST-Anfragen können einen Filterausdruck als String übergeben. Der FilterParser und Tokenizer übersetzen diesen String in einen Abstract Syntax Tree; der QueryBuilder erzeugt daraus native SQL ohne SQL-Injection-Risiko.

8.4.3 Multi-Datenbankunterstützung

Property Werte Standardwert
egov.persistence.database.type POSTGRESQL, SQLSERVER — (Pflichtfeld)
egov.persistence.database.naming.style CAMEL_CASE, SNAKE_CASE CAMEL_CASE

DatabaseConfigurationService liest diese Werte und konfiguriert Dialekt und Naming- Strategie beim Start.

8.4.4 Datenbankmigrationen

Das Framework liefert eigene Flyway-Skripte für seine IAM- und Command-Tabellen mit. Consuming Apps fügen applikationsspezifische Skripte hinzu. Die Flyway-Schema-Filterung erfolgt über EgovSchemaFilterProvider, damit Framework-Migrations nicht mit App- Migrations kollidieren.


8.5 Konfiguration

Alle Framework-Properties sind unter dem Namespace egov.* in der application.yml der consuming App gruppiert. Das Framework liefert egov-default.yml mit sicheren Defaults mit.

Zentrale Properties:

Property Default Beschreibung
egov.persistence.database.type — Datenbanktyp (POSTGRESQL / SQLSERVER)
egov.persistence.database.naming.style CAMEL_CASE Spaltenbenennungsschema
egov.persistence.luid.max-ids-per-tick 10000 IDs pro Sekunde pro Segment
egov.persistence.luid.max-segments 100 Anzahl paralleler Pods/JVMs
egov.persistence.luid.start-year 2025 Basisjahr für LUID-Berechnung
egov.admin.is.activated false Admin-Modul aktivieren
egov.permission.log.activated false Permission-Entscheidungen loggen
egov.exception-log.debug false Stacktrace in Fehlerantworten
egov.service.discovery.activated false ZooKeeper-Service-Discovery
egov.service.discovery.zookeeper.host zookeeper ZooKeeper-Hostname
egov.service.discovery.zookeeper.port 2181 ZooKeeper-Port
egov.subscriber.core-pool-size 5 ThreadPool für Event-Subscriptions
egov.subscriber.max-pool-size 20 Max-Threads für Event-Subscriptions

8.6 Logging

Das Framework verwendet SLF4j mit Logback als Implementierung. Alle relevanten Klassen tragen @Slf4j (Lombok). Kein MDC-Einsatz im Framework-Kern — die consuming App ist für das Anreichern von Logs (z.B. mit userId oder requestId) verantwortlich.

Log-Level-Konfiguration (Auszug):

logging:
  level:
    ch.ti8m.egov.framework.exceptionhandling.exceptionhandlers: DEBUG
    ch.ti8m.egov.framework.validation.engine.FieldValueExtractorComponent: DEBUG

Klassen mit relevantem Logging: ContextInterceptor, PermissionBuilder, GenericExceptionHandler, CommandHandlerBase, LUIDGenerator, ZookeeperConnector.

ContextInterceptor.preHandle() extrahiert neben der userId auch Request-Parameter (filter, sort, offset, limit, page, size, search) in den DataHolder. afterCompletion() bereinigt den ThreadLocal.


8.7 Internationalisierung

Das optionale e-gov-mdm-Modul stellt mehrsprachige Stammdaten (Vocabularies) bereit.

8.7.1 Datenstruktur

Vocabulary
  └── MasterDataGenericEntity (pro Eintrag und Sprache)
        ├── code          (fachlicher Schlüssel)
        ├── languageCode  (de, fr, it, en, ...)
        ├── shortName
        ├── longName
        ├── validFrom
        └── validTo

LanguageDefinition verknüpft ein Vocabulary mit den verfügbaren Sprachcodes.

8.7.2 Sprachauswahl

Die aktive Sprache wird in folgender Reihenfolge ermittelt:

  1. Content-Language-Header des HTTP-Requests (gesetzt durch ContextInterceptor)
  2. UserLanguageProvider.getLanguage() — Default-Implementierung: Locale.getDefault()

Consuming Apps können UserLanguageProvider als Spring-Bean überschreiben, um die Sprache aus dem Nutzerprofil oder einem anderen Request-Attribut zu lesen.

API-Ausgabe: ResponseTranslation mit shortName und longName pro Sprache.


8.8 ID-Generierung (LUID)

Das optionale e-gov-luid-Modul stellt eine clustersichere, sortierbare ID-Strategie bereit, die keine Datenbanksequenz benötigt.

8.8.1 Algorithmus (LUIDGenerator)

ID = tickStep + incFromBase

tickStep   = (Millisekunden seit startYear) / 1000 * maxIDsPerTick * maxSegments
incFromBase = maxIDsPerTick * segmentId + [0 … maxIDsPerTick − 1]

LUIDGenerator ist als Hibernate IdentifierGenerator implementiert, generate() ist synchronized. Konfigurierbar über egov.persistence.luid.*-Properties (siehe Konfiguration).

Eigenschaften: zeitbasiert, sortierbar, gap-tolerant, kein Single-Point-of-Failure, kein Round-Trip zur Datenbank.


8.9 Testbarkeit

8.9.1 Test-Pyramide

Ebene Technologie Beispiele
Unit-Tests JUnit 5 BaseRepositoryImplTest, CommandHandlerBaseTest, FilterBuilderTest
Integrationstests JUnit 5 + Testcontainers BaseRepositoryImplIT, SubscriptionServiceIT
ZooKeeper-Tests Testcontainers (zookeeper:3.9.3) ZookeeperTestContainer-Basisklasse

8.9.2 Testcontainers-Konfiguration

Datenbank-Integrationstests verwenden das JDBC-URL-Schema von Testcontainers:

# application-test.yml
spring:
  datasource:
    url: jdbc:tc:postgresql:17.4:///integration-tests-db
    driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
  jpa:
    hibernate:
      ddl-auto: create-drop

Weitere Profile: application-h2.yml (In-Memory), application-test-sqlserver.yml, application-test-zookeeper.yml, application-test-logging-debug.yml.