1a0a56a626
Replace the stale multi-module java/mss-failsafe skeleton (old user-management prototype) with the active single-module machine-safety inspection app that was living in its own standalone repo at the repo root. - Remove old java/mss-failsafe/ multi-module tree (mss, userdata, userManagement, mssfailsafe.datalayer, mssfailsafeWeblayer) incl. committed build artifacts - Add the active app (PrimeFaces 11 / JSF 2.3 / Hibernate 5.6 / iText / POI) flattened into java/mss-failsafe/ as the only mss-failsafe in git - Working tree captured = master tip 2a142b5 + in-progress uncommitted work (incl. .github/*.instructions.md AI-context files) - Archive the standalone repo's 33-commit history in GIT_HISTORY_ARCHIVE.md since its .git was not migrated This is the source of truth / base for the upcoming upgraded rewrite.
103 lines
4.1 KiB
Markdown
Executable File
103 lines
4.1 KiB
Markdown
Executable File
# Manager/Controller Pattern Instructions
|
|
|
|
Aktualisiert: 2025-10-20
|
|
|
|
## Ziele
|
|
Klare Trennung zwischen UI-Zustand (Controller) und Geschäftslogik/Persistenz (Manager).
|
|
|
|
## Verantwortlichkeiten
|
|
Controller:
|
|
- Zustände: selected, created, entities.
|
|
- UI Nachrichten (FacesMessage).
|
|
- Dialogsteuerung (PrimeFaces Widgets schließen).
|
|
- Hilfsfunktionen (PDF, Fake-ID-Erzeugung).
|
|
|
|
Manager:
|
|
- CRUD Operationen (create, edit, save, saveAll, remove, removeAllIn, find, findAll).
|
|
- Fachspezifische Queries / Reload.
|
|
- Fehlerlogging.
|
|
|
|
## Interaktion
|
|
- Controller ruft Manager.save / saveAll auf für Persistenz.
|
|
- Nach Änderungen: Controller.refrehSelected() (Tippfehler) -> aktualisiert ausgewähltes Objekt.
|
|
- Kein direkter EntityManager Zugriff im Controller.
|
|
|
|
## Fake-ID Ablauf
|
|
1. Controller erzeugt neue Entität (id == null).
|
|
2. Falls Sammlung benötigt: setzt negative ID über createFakeID.
|
|
3. Bei Save: Manager erkennt id < 0 (nach vorherigem Nullsetzen) -> persist.
|
|
|
|
## Methoden-Namenskonventionen
|
|
- Manager: Verb + Domänenobjekt (addQuestionnaireToSecurityArea, removeQuestionnaireFromSecurityArea).
|
|
- Controller: UI Aktionen (saveSelected, createNew, openDialog, closeDialogs).
|
|
|
|
## Edge Cases
|
|
- selected == null bei refresh -> no-op.
|
|
- entities Liste leer -> UI Tabelle zeigt keine Einträge; Null vermeiden (immer leere Liste).
|
|
|
|
## Messaging
|
|
- Erfolg: `successMessage()`; Fehler: `errorMessage()`.
|
|
- Spezifische Warnungen über `sendWarnMessage`.
|
|
|
|
## Verbesserungen
|
|
- Umbenennung `refrehSelected()` -> `refreshSelected()` in Basisklasse + alle Verwendungen.
|
|
- Einführung eines BasePDFController oder Utility zur Auslagerung PDF Logik.
|
|
|
|
## Generator Leitplanken
|
|
- Zusätzliche Logik (berechnete Felder, Validierungen) zuerst im Manager statt im Controller (besser testbar, wiederverwendbar).
|
|
- Controller schlank halten: keine komplexe Businessregeln.
|
|
|
|
---
|
|
# Persistence Instructions
|
|
|
|
Aktualisiert: 2025-10-20
|
|
|
|
## Ziele
|
|
Konsistente JPA Nutzung (Java EE 8, Hibernate Provider) mit klaren Regeln für IDs, Lazy Loading und Flush.
|
|
|
|
## Grundsätze
|
|
- Entities extend `AbstractEntity` (Long id, creationDate, changedDate, outdated Flag).
|
|
- Identity Generation: `@GeneratedValue(strategy = GenerationType.IDENTITY)` -> Kein manuelles Setzen positiver IDs.
|
|
- Equals/HashCode nur auf ID (Basis-Klasse bereitgestellt).
|
|
|
|
## ID & Fake-ID Handling
|
|
- Temporäre neue Objekte können negative IDs erhalten (Fake) zur UI-Differenzierung.
|
|
- Vor persist: if id != null && id < 0 -> `setId(null)` damit JPA eine echte ID generiert.
|
|
- Niemals persist mit negativer ID ausführen.
|
|
|
|
## Lebenszyklus
|
|
1. Konstruktor setzt creationDate & changedDate.
|
|
2. Bei Änderungen Fachlogik: changedDate aktualisieren (TODO: zentralisieren via EntityListener).
|
|
3. Persist -> flush direkt in `AbstractManager.save` / `saveAll`.
|
|
|
|
## Lazy Loading
|
|
- Vermeide direkte Iteration über nicht initialisierte Collections außerhalb Transaktion.
|
|
- Nutzung `AbstractManager.refresh(entity)` initialisiert das Entity (Hibernate.initialize(entity)).
|
|
- Für Collections eigene Reload-Methoden in spezialisierten Managern implementieren.
|
|
|
|
## Named Queries & Criteria
|
|
- Bevorzugt Criteria API für dynamische Filter.
|
|
- Häufig verwendete, statische Abfragen als `@NamedQuery` in der Entity definieren.
|
|
|
|
## Performance Hinweise
|
|
- `saveAll(Collection<T>)` nutzt einen Flush am Ende; reduziert DB Roundtrips.
|
|
- Bulk Delete oder Update lieber über JPQL statt Einzelloops (aktuell: removeAllIn loop; Optimierungspotential).
|
|
|
|
## Edge Cases
|
|
- `save(null)` => false (kein Fehlerwurf, Logging im Manager).
|
|
- Leere Collections in `saveAll` => true (no-op).
|
|
- `remove(entity)` mit `entity.getId()==null` => false; vorher persistieren oder ignorieren.
|
|
|
|
## Verbesserungs-Ideen
|
|
- EntityListener für Timestamps.
|
|
- Soft Delete (outdated Flag) statt physischem Löschen für Audit.
|
|
- Einführung eines Version-Feldes für Optimistic Locking.
|
|
|
|
## Generator Leitplanken
|
|
- Keine Änderung der ID-Strategie ohne umfassende Migration.
|
|
- Bei neuen Entities standardisierte Felder aus `AbstractEntity` nutzen.
|
|
- Collections initialisieren (z.B. `new ArrayList<>()`) im Entity-Konstruktor.
|
|
|
|
---
|
|
|