# Architecture Instructions Aktualisiert: 2025-10-20 ## Überblick Das System folgt einer klassischen 4-Layer Struktur: 1. View: JSF 2.3 / PrimeFaces 11 / XHTML Seiten (Formulare, Tabellen, Dialoge) 2. Controller: CDI/JSF Managed Beans, Zustandsverwaltung & UI-Aktionen (extends AbstractController) 3. Business: Stateless EJB Manager mit CRUD + Fachlogik (extends AbstractManager) 4. Persistence: JPA Entities (extends AbstractEntity) ## Basisklassen Rollen - AbstractEntity: Basis-ID (Long, Identity), Timestamps, outdated Flag, equals/hashCode nur über ID. - AbstractManager: CRUD, save vs saveAll, remove / removeAllIn, refresh (Hibernate.initialize), Fehlerlogging. - AbstractController: UI State (selected, created, entities), Fake-ID-Erzeugung für neue temporäre Objekte, Messaging, PDF Utilities. ## Lebenszyklus eines neuen Objekts 1. UI erzeugt neues Objekt (id == null) -> Controller kann negative Fake-ID setzen falls in Collections benötigt. 2. Vor persist: Falls id < 0 -> setId(null) damit JPA Identity funktioniert. 3. save(): id == null => persist + flush, sonst merge + flush. 4. refresh(): sorgt für Managed Entity + Initialisierung Lazy Properties. ## Negative Fake IDs - Zweck: Temporäre Unterscheidung mehrerer neu angelegter Einträge im UI bevor persist. - Erzeugung: createFakeID(Collection) nimmt kleinste vorhandene negative ID - 1. - Vor persist unbedingt auf null setzen. ## Lazy Loading & Refresh - Manager.refresh(entity) -> merge + Hibernate.initialize(entity) für Entität. - Für Collections: spezielle Reload-Methoden in fachlichen Managern (z.B. reloadWithQuestionnaires). - Nach Batch-Operationen Controller.refrehSelected() (Tippfehler) nutzen; perspektivisch in refreshSelected() umbenennen. ## Transaktionen - Schreiboperationen annotiert mit @Transactional (Container-managed) in AbstractManager.save / saveAll. - Fachmethoden, die persistieren oder mergen, sollten ebenfalls @Transactional erhalten (Konsistenz). ## Fehlerbehandlung - Aktuell: Logging (LOGGER.error) + bool Rückgabe. - Geplant: Einführung BusinessException für differenzierte Fehlerpfade. ## Erweiterungsmuster (Domain hinzufügen) 1. Entity erstellen (extends AbstractEntity). Optional Named Queries. 2. Manager: @Stateless extends AbstractManager; spezifische Queries / Reload Methoden. 3. Controller: @Named + Scope (ViewScoped/SessionScoped) extends AbstractController. 4. XHTML Seite inkl. Referenzen zu Controller (DataTable, Dialoge, Commands). 5. Tests: CRUD & fachliche Spezialfunktionen. ## Typische Fachfunktionen - Klonen: Quelle re-laden + initialisieren; neue Instanz mit Copy-Konstruktor; Child IDs null; Collections duplizieren kontrolliert. - Zuordnungen (z.B. Fragebogen): Add/Remove Pattern über Wrapper Entity. ## PDF-Erstellung - iText7 Nutzung über Hilfsmethoden in AbstractController (Tabellen, Inner Cells, Paginierung). - Keine neuen Features mehr mit iText5 API implementieren. ## Querschnittsthemen & Roadmap - Vereinheitlichte Exception Layer. - Bean Validation (javax.validation) für Eingaben & persistente Konsistenz. - Test Suite (JUnit + ggf. Arquillian / Integrationstests) ausbauen. - Migration nach Jakarta EE (Namespace Wechsel javax -> jakarta) perspektivisch. ## Edge Cases & Hinweise - save(null) => false zurückgeben. - remove(entity) ohne persistierte ID => false. - Batch Speichern: leere Liste => true (no-op) statt Fehler. - Collections initialisieren vor Iteration (Avoid LazyInitializationException). ## Generator Leitplanken - Bestehende Signaturen respektieren. - Keine neuen Frameworks ohne Notwendigkeit. - Logging immer via LOGGER, niemals System.out. - Für neue Write-Methoden @Transactional hinzufügen. ---