feat: archive zoo_backup for home sync

This commit is contained in:
Patrick Plate
2026-06-24 19:27:05 +02:00
parent 02844e4c4a
commit 038e546963
133 changed files with 19953 additions and 0 deletions
@@ -0,0 +1,197 @@
# Paisy — Development Guidelines
## Code Quality Standards
### Logging
- Use `@Log4j2` (Lombok) for existing modules that already use Log4j2 (e.g., `AbstractMeldung`)
- Use `@Slf4j` (Lombok) for new code — this is the preferred default
- Use parameterized logging: `log.debug("Value: {}", value)` — never string concatenation
- Some legacy code mixes styles: `log.debug("text " + var)` — refactor to parameterized when touching these lines
- Log levels: `debug` for flow tracing, `warn` for recoverable issues, `error` for failures
### Naming Conventions
- Package: `com.adp.de.paisy.modules.<module>` for modules, `com.adp.de.<module>` for legacy
- German domain terms preserved in class/field names: `Fehlzeiten`, `Lohnkonto`, `Vorlaufsatz`, `Nachlaufsatz`, `Meldekorrekturen`
- JAXB-generated classes use German XML element names as Java identifiers: `getAngabenZurPersonAV()`, `getBeschreibungTaetigkeitDE()`
- Constants use UPPER_SNAKE_CASE: `EMPTY_DATE_LONG`, `EMPTY_BBNR`, `MAX_DBFZ`
- Date formatters as `final` fields: `bausteinf`, `pai022f`, `PAI_SHORT`
### Field Visibility
- `protected` for fields shared with subclasses (common in abstract controllers)
- `private` with Lombok `@Getter`/`@Setter` for DTOs
- `static private final` for constants (PDDI layer uses tab-indented style)
## Structural Conventions
### Module Entry Point Pattern
```java
@Slf4j
@Service("module-name")
@Lazy
public class ModuleRunner implements ConsoleService {
@Override
public void run(String... args) throws Exception { /* ... */ }
}
```
### Abstract Controller Pattern (5/5 files)
Business modules use abstract base classes for shared logic:
```java
@Log4j2
public abstract class AbstractMeldung {
// Shared date formatters, parsers, PAISY interaction
protected Person person;
protected Fehlzeiten fz;
public Person initBaustein(Datenbaustein main, DBNA dbna, ...) { /* ... */ }
protected Lohnkonto parseLohnkonto(...) { /* ... */ }
}
```
### Datenbaustein (Data Block) Pattern (5/5 files)
Core data exchange pattern — field-based data blocks with positional access:
```java
Datenbaustein main = ...;
main.setValue("FEKZ", "0");
main.setValue("VSNR", person.getValue("VSNR"));
String value = d508b.getValue("F39-AVUWFWZ-10-50-8B");
```
### ServiceCenter Singleton Pattern
Central access point for PAISY system interaction:
```java
ServiceCenter.INSTANCE().getBaustein(Datengruppe.NAME, vorgangsID);
ServiceCenter.INSTANCE().getPaisy().pgmFunktionCall("S;" + bbnrvu + ";");
ServiceCenter.INSTANCE().getPaisy().pgmReadLine();
```
### EMFactory Singleton Pattern
Each module has its own EntityManager factory:
```java
EMFactoryEAU emFactory = EMFactoryEAU.getInstance();
FlywayController flyway = new FlywayController(emFactory);
flyway.migrate("EAU", "2024_09_08_17_48_11");
```
## JAXB XML Binding Pattern (3/5 files)
JAXB-generated classes follow a strict pattern for GKV data exchange:
```java
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "steuerungsdaten", "angabenZurPersonAV", ... })
@XmlRootElement(name = "A1_Ausnahmevereinbarung",
namespace = "http://www.gkv-datenaustausch.de/XMLSchema/A1_Ausnahme/2.0")
public class A1Ausnahmevereinbarung {
@XmlElement(name = "Steuerungsdaten",
namespace = "http://www.gkv-datenaustausch.de/XMLSchema/A1_Ausnahme/2.0",
required = true)
protected SteuerungsdatenAGV2Ctp steuerungsdaten;
}
```
Key rules:
- Nested `public static class` for complex type hierarchies
- German Javadoc: `"Ruft den Wert der X-Eigenschaft ab"` / `"Legt den Wert der X-Eigenschaft fest"`
- `jakarta.xml.bind.annotation.*` (Jakarta EE, not javax)
- `XMLGregorianCalendar` for date fields, `BigInteger` for numeric codes
- `KennzeichenAlphanumerischTyp` enum for J/N flag fields
## PDF Generation Pattern (2/5 files)
Using OpenPDF (iText fork) for government-compliant PDF reports:
```java
Document document = new Document(PageSize.A4, 50, 50, 50, 50);
PdfWriter writer = PdfWriter.getInstance(document, baos);
document.open();
// Header
Paragraph headline = new Paragraph("EuBP", getHeaderFont());
document.add(headline);
// Two-column table: Bezeichnung | Inhalt
PdfPTable table = new PdfPTable(2);
table.setWidthPercentage(75);
table.setHorizontalAlignment(Element.ALIGN_LEFT);
addTableHeader(table, new String[]{"Bezeichnung", "Inhalt"});
table.addCell(createCell("Verfahrensmerkmal"));
table.addCell(createCell(vorlaufsatz.getVerfahrensmerkmal().value));
document.add(table);
```
Font conventions:
- Header: Helvetica Bold 18pt
- Subheader: Helvetica Bold 14pt
- Bold: Helvetica Bold 12pt
- Normal: Helvetica 10pt
- Table header background: `new Color(220, 220, 220)`
## ISAM/Oracle Trigger Generation (1/5 files)
JavaScript code generator for Oracle INSTEAD OF triggers:
```javascript
// gen_trigger.js — generates Oracle triggers for COBOL ISAM → Oracle mirroring
gen("YP_ABR_STEUER", `
,MUT_YP_ABR_STEUER.ABSCHNITT
,MUT_YP_ABR_STEUER.BEMERKUNG
...
`)
```
Pattern: `IPW_<recname>` view → `MUT_<recname>` mutation table, with `ak_nr`/`pers_nr` lookup from `PS_YP_PERS_MAIN`.
## Binary Protocol Pattern (1/5 files)
Custom binary serialization for PDDI middleware (DocumentStream):
- Type-tagged byte protocol: `b_null='~'`, `b_string='S'`, `b_int='i'`, `b_date='d'`
- Compact encoding: shorts for small ints, full 8 bytes only when needed
- Custom charset: `PaisyCharset.CHARSET` (likely ISO-8859-1)
- Inner classes: `BytesOutput`, `Output` (stream-based), `Input` (stream-based)
## Date Handling Patterns
```java
// German user-facing format
DateTimeFormatter.ofPattern("dd.MM.yyyy")
// Internal PAISY format (8-digit)
DateTimeFormatter.ofPattern("yyyyMMdd")
// Short PAISY format (6-digit, 2-digit year)
DateTimeFormatter.ofPattern("yyMMdd")
// Null/empty date handling
if (value.equals("00.00.0000")) return LocalDate.MAX;
if (paidate.equals("0000000")) return LocalDate.MIN;
if (paidate.equals("9999999")) return LocalDate.MAX;
```
## Error Handling
- Custom exceptions: `PaisyIOException`, `PaisyRuntimeException`, `AccessDeniedException`, `PaisyNotFoundException`, `UnauthorizedException`
- PAISY error responses start with `"F;"` — check before parsing
- Null-safe patterns: check for null before processing sections (PDF, data blocks)
- Reflection-based construction with explicit error messages for field count mismatches
## Frequently Used Annotations
| Annotation | Usage | Frequency |
|-----------|-------|-----------|
| `@Log4j2` / `@Slf4j` | Logging | Every class |
| `@Getter` / `@Setter` | Lombok accessors | DTOs, models |
| `@XmlElement` / `@XmlAccessorType` | JAXB binding | XML model classes |
| `@XmlRootElement` / `@XmlType` | JAXB root types | Top-level XML types |
| `@XmlSchemaType` | JAXB schema mapping | XML fields |
| `@Service("name")` / `@Lazy` | Spring service registration | Module entry points |
| `@Transactional` | DB transactions | Service methods |
| `@Data` / `@Builder` | Lombok DTOs | Model classes |
## Code Idioms
- `CommonRoutines.paidate2Datenbaustein()` — convert PAISY date to Datenbaustein format
- `CommonRoutines.uuid()` — generate unique dataset IDs
- `CommonRoutines.getDocumentPath()` — get output file path
- `ServiceCenter.INSTANCE().getPaisy().nextPaisy(line)` — iterate PAISY response lines
- `line.split(";")` — semicolon-delimited PAISY response parsing
- Streams with `Collectors.toCollection(ArrayList::new)` for mutable result lists