Files
pi_mcps/zoo_backup/work/rules/memory-bank/guidelines.md
T
2026-06-24 19:27:14 +02:00

7.3 KiB

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

@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:

@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:

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:

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:

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:

@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:

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:

// 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

// 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