blob: 937bcae1e900af759917e60a35d30047395370ca [file] [log] [blame]
Matthias Andreas Benkard856c0972026-08-16 06:56:05 +02001= ÄndGgner -- Nichtamtliche Zentralstelle für die maschinelle Fortschreibung von Stammgesetzen anhand von Änderungsvorschriften des Bundes und der Länder
Matthias Andreas Benkardb291c362020-11-22 10:22:27 +01002Matthias Andreas Benkard
3// Meta
4:experimental:
5:data-uri:
6:sectnums:
7:toc:
8:stem:
9:toclevels: 2
Matthias Andreas Benkard856c0972026-08-16 06:56:05 +020010:description: Handbuch der Nichtamtlichen Zentralstelle für die maschinelle Fortschreibung von Stammgesetzen
Matthias Andreas Benkardb291c362020-11-22 10:22:27 +010011:keywords: mulk
12// Settings
13:icons: font
14:source-highlighter: pygments
15
16
17== Resources
18
19|===
20|Resource |Links
21
22|Public Artifact
23|https://bintray.com/mulk/maven/aendggner[Bintray]
24
25|Bug Tracker
26|MantisBT
27|===
28
29
30[[building]]
31== Building a JAR
32
Matthias Andreas Benkardc7f11362020-11-22 15:01:07 +010033To build an executable JAR at `target/aendggner-${REVISION}.jar`:
Matthias Andreas Benkardb291c362020-11-22 10:22:27 +010034
35[source,shell script]
36----
37./mvnw package
38----
39
40`${REVISION}` defaults to `0.1.0-SNAPSHOT` unless you override it by
41passing the `-Drevision` flag to `mvnw`.
42
43
44== Running the Command Line Application
45
46To run the command line application after <<building,building>> it:
47
48[source,shell script]
49----
50./mvnw exec:java
51----
52
53
Matthias Andreas Benkard58e19982026-07-13 07:09:19 +020054[[usage]]
55== Usage
56
57ÄndGgner erzeugt aus einem Stammgesetz und einem Änderungsgesetz eine
58zweispaltige HTML-Synopse (alte Fassung links, neue rechts, Änderungen
59wortweise hervorgehoben).
60
61Eingaben:
62
Matthias Andreas Benkard65eff082026-07-18 12:24:32 +020063* Stammgesetz (Bundesrecht): XML im gii-norm-Format von
Matthias Andreas Benkard06da70e2026-08-16 07:34:12 +020064 https://www.gesetze-im-internet.de/[gesetze-im-internet.de]. Das Portal gibt
65 es nur als Archiv aus (`…/<kurz>/xml.zip`); das Archiv wird unmittelbar
66 angenommen und der enthaltene XML-Eintrag daraus entpackt, ein Zwischenschritt
67 von Hand entfällt.
Matthias Andreas Benkard2cfea002026-07-26 13:32:26 +020068* Stammgesetz (Landesrecht): konsolidierte Fassung als PDF oder als
Matthias Andreas Benkardbac648b2026-07-28 07:51:09 +020069 kanonischer Klartext im Format der `--extract-only`-Ausgabe. Eine Zeile
70 Inhaltsübersicht eröffnet darin die gleichnamige Norm, auf die die
71 Angabe-Befehle zielen; ihre Zeilen tragen das Übersichtsformat
72 „§ N | Titel“. Amtliche
Matthias Andreas Benkard65eff082026-07-18 12:24:32 +020073 Satznummern und Fußnotenmarker stehen als Unicode-Superskripte im
Matthias Andreas Benkard2cfea002026-07-26 13:32:26 +020074 Text („¹Die freilebende Tierwelt …“, Enteignung⁶)“); ob sie erhalten
75 bleiben, ergibt sich aus der geladenen Stammfassung, nicht aus einer
76 Länderkennung. Ebenso folgt das Zitiersigel oder Art.) aus den
77 Normköpfen der Stammfassung.
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +020078* Änderungsdokument: BGBl-, GVBl- oder Drucksachen-PDF (Bundestag,
79 Bundesrat, Landtage) oder Klartext. Die Dokumentart wird aus dem Text
80 erschlossen, nicht aus dem Dateinamen (siehe <<quellformate>>);
81 Änderungsanträge dürfen zusammen mit dem Entwurf angegeben werden, den
82 sie ändern.
Matthias Andreas Benkard58e19982026-07-13 07:09:19 +020083
84[source,shell script]
85----
86java -jar target/aendggner-0.1.0-SNAPSHOT.jar \
87 stammgesetz.xml aenderungsgesetz.pdf -o synopse.html
88----
89
90Wichtige Optionen:
91
92`-o, --output <file>`::
93 Ausgabedatei (Default `synopse.html`; `-` = Standardausgabe).
94`--vollstaendig`::
95 Auch unveränderte Normen in die Synopse aufnehmen.
96`--artikel <n>`::
97 Nur diesen Artikel des Änderungsgesetzes anwenden (Default: alle
98 Artikel, deren Einleitung das Stammgesetz nennt).
99`--extract-only`::
100 Nur den bereinigten Lineartext des Änderungsgesetzes ausgeben. Nützlich,
101 wenn die PDF-Extraktion fehlerhaft ist: Text prüfen, von Hand
102 korrigieren und als Klartextdatei wieder einspeisen.
103
104Erkannt werden die gebräuchlichsten Änderungsbefehle des Handbuchs der
105Rechtsförmlichkeit (Ersetzen, Neufassung, Einfügen, Anfügen, Aufheben,
Matthias Andreas Benkardebd5a7b2026-07-15 20:54:27 +0200106Streichen, Umnummerierung) einschließlich zahlreicher Sonderformen:
107Bereichs- und Koordinationsziele („Die Absätze 8 und 9 werden durch die
108folgenden Absätze 8 bis 10 ersetzt“), strukturelle Streichungen ganzer
109Einheiten („§ 9 wird gestrichen“), §- und Gliederungs-Umnummerierungen
110(„§ 9a wird zu § 9“, Der bisherige Abschnitt 2 wird zu Abschnitt 3“),
Matthias Andreas Benkardb7e9f0f2026-07-16 21:12:08 +0200111das Einfügen/Ersetzen ganzer §-Blöcke, Chapeau-Lokatoren („Im
112Satzteil vor Nummer 1 …“), Änderungen an Anhängen und Anlagen („Der
113Anhang wird wie folgt geändert: Nach Nummer 2 wird die folgende
114Nummer 2a eingefügt“), Angabe-Befehle auf die Inhaltsübersicht (gefasst,
115ersetzt, eingefügt, gestrichen sie werden auf die
116Inhaltsübersichts-Norm angewandt), das Einfügen und Ersetzen von
117Gliederungsberschriften („Nach § 33 werden die folgenden Überschriften
118zu Teil 3 eingefügt“), Voranstellungen, Mehrfach-Ersetzungs- und
Matthias Andreas Benkard5f30f562026-07-28 06:00:16 +0200119-Einfügepaare, Einfügungen, deren Position ein Wortanker statt einer
120Stellenangabe bestimmt („Vor den Wörtern Aus dem Bereich Verkehr:“ wird
121folgender Absatz 5 eingefügt“), Verbünde aus Umnummerierung und
Matthias Andreas Benkard5b2e6ef2026-08-02 20:01:37 +0200122Folgeänderung („§ 50 wird zu § 38 und wird wie folgt geändert“, Die
123bisherige Nr. 7 wird Nr. 5 und das Komma wird durch das Wort und
124ersetzt eine Satzzeichen-Operation meint dabei stets die soeben
125umnummerierte Einheit, weil ihr Zieltext nichts unterscheidet),
Matthias Andreas Benkardbac648b2026-07-28 07:51:09 +0200126Verb-Rahmen, deren Unterpunkte allein die Fundstelle tragen („Es werden
127ersetzt: in § 35 Absatz 3 die Angabe X jeweils durch die Angabe
128Y“,“) sowie die Neufassung der Gesetzesüberschrift.
129
130Angewandt wird nicht stur in Dokumentreihenfolge: Umnummerierungen
131beziehen sich stets auf die ursprüngliche Zählung, nicht auf den Stand
132nach den vorangegangenen Punkten. Wer eine Bezeichnung räumt, kommt
133deshalb vor den, der sie neu besetzt. Aus dieser einen Regel folgt die
134absteigende Abarbeitung einer aufsteigenden Kaskade („Der bisherige
135Absatz 3 wird Absatz 4“, Der bisherige Absatz 4 wird Absatz 5“, …)
136ebenso wie der Vorrang einer Umnummerierung vor der Einfügung, die deren
Matthias Andreas Benkard74a84c52026-08-16 06:08:42 +0200137Bezeichnung neu vergibt. Wer vorrückt, nimmt dabei seine eigenen Räumer
138mit: Auch eine über mehrere Punkte verschränkte Kaskade („Die bisherige
139Nr. 15 wird Nr. 16“, Die bisherigen Nrn. 13 und 14 werden die Nrn. 14
140und 15“, Nach Nr. 12 wird folgende Nr. 13 eingefügt“) tritt deshalb
141geschlossen vor die Einfügung, nicht bloß mit ihrem letzten Glied.
142
143Geordnet werden nicht die Befehle, sondern die einzelnen
144Anwendungsschritte. Ein Verbund aus Umnummerierung und Folgeänderung
145trägt nämlich zwei gegenläufige zeitliche Ansprüche: Die Umnummerierung
146gehört nach vorn, die Folgeänderung dagegen an ihre Dokumentstelle, weil
147sie die vorangegangenen Punkte als vollzogen voraussetzt Die
148bisherige Nr. 11 wird Nr. 12 und die Angabe schriftliche wird
149gestrichen ist vorgezogen mehrdeutig, weil erst ein früherer Punkt die
150zweite Fundstelle des Wortes beseitigt. Verschoben wird stets nur nach
151vorn. Das Protokoll bleibt gleichwohl befehlsweise: Ein Verbund gilt nur
152dann als angewandt, wenn jeder seiner Teile gegriffen hat, sonst nennt
153die Meldung den Teil und den Grund.
154
155Die PDF-Aufbereitung toleriert Drucksachen-Artefakte (Seitenköpfe
156und -füße, Vorabfassungs-Wasserzeichen, vertauschte oder gerade
157Anführungszeichen, verklebte Wortgrenzen, zerlegt kodierte Umlaute) und
158bestimmt die Brotschrift seitenweise, sodass auch
Matthias Andreas Benkard5f30f562026-07-28 06:00:16 +0200159Ministeriumsentwürfe mit gemischten Layouts vollständig extrahiert
160werden. Fehlt im amtlichen Satz ein schließendes Anführungszeichen, endet
161das Zitat an der nächsten Strukturgrenze an einer Artikelberschrift
162oder, wo die Anführungszeichen eines Artikels nachweislich nicht
163aufgehen, am nächsten Aufzählungspunkt des Änderungsgesetzes; gemeldet
164wird das als Warnung. Auf den
Matthias Andreas Benkardb7e9f0f2026-07-16 21:12:08 +0200165Beispieldaten werden damit alle Befehle der BGBl-Fassungen und der
166aktuellen Entwürfe angewandt (UWG/AGG/ProdHaftG: 0 manuell); was
167unsicher bleibt etwa Befehle gegen eine ältere Gesetzesfassung, deren
168Zieltext nicht mehr existiert landet mit Begründung im Abschnitt
169*Manuell prüfen* der Synopse und wird niemals stillschweigend verworfen.
Matthias Andreas Benkard58e19982026-07-13 07:09:19 +0200170
Matthias Andreas Benkard65eff082026-07-18 12:24:32 +0200171Für das bayerische Landesrecht versteht ÄndGgner die dortigen
172Konventionen: Stammgesetze gliedern sich in Artikel („Art. 6 Abs. 2
173Satz 1 Nr. 2“, durchgängig abgekürzt zitiert), Änderungsgesetze dagegen
174in Paragraphen auch mehrere Gesetze in einem GVBl-Heft, aus denen die
175auf das Stammgesetz zielenden §§ (einschließlich Weitere Änderung“)
176anhand des Einleitungssatzes ausgewählt werden. Amtliche Satznummern
177bleiben als Superskripte erhalten und dienen als exakte Satzgrenzen;
178zusätzlich erkannt werden die bayerischen Befehlsformen („Fußnote 1
179wird aufgehoben“, In Satz 1 wird die Satznummerierung 1 gestrichen“,
180Dem Wortlaut werden die folgenden Abs. 1 bis 4 vorangestellt“, Der
181bisherige Wortlaut wird Abs. 5“, Halbsatz-Ziele, Klauselketten mit
182gemeinsamem Schlussverb) sowie das Fortführungszeichen des GVBl (jedes
Matthias Andreas Benkard74a84c52026-08-16 06:08:42 +0200183neugefasste Aufzählungsglied öffnet erneut mit „). Der Fall ist gegen
184die amtliche Nachfassung belegt: Alle 154 auf das BayJG zielenden
185Befehle des Heftes 6/2026 werden an 54 Normen selbsttätig angewandt,
186auch die verschränkte Neunummerierung des Bußgeldkatalogs in Art. 56.
Matthias Andreas Benkard65eff082026-07-18 12:24:32 +0200187
Matthias Andreas Benkard2cfea002026-07-26 13:32:26 +0200188Die übrigen Länder gliedern ihre Stammgesetze wie der Bund in
189Paragraphen; die Unterschiede liegen im Gesetzblatt-Satz und in
190Befehlsidiomen. Belegt sind Sachsen (SächsBeamtVG), Niedersachsen
Matthias Andreas Benkard08c27472026-08-22 19:02:46 +0200191(NEFG), Thüringen (ThürKigaFinVO) und Nordrhein-Westfalen dort alle
192vier ändernden Artikel eines
Matthias Andreas Benkarda201e832026-08-02 19:45:34 +0200193Heftes: Telemedienzuständigkeitsgesetz, Landesmediengesetz,
194Ausführungsgesetz zum 17. Rundfunkänderungsstaatsvertrag und, mit 101
Matthias Andreas Benkard74a84c52026-08-16 06:08:42 +0200195Befehlen an 31 Normen der größte Fall des Heftes, das WDR-Gesetz
Matthias Andreas Benkarda201e832026-08-02 19:45:34 +0200196mit Akzeptanztests gegen die
Matthias Andreas Benkard5b2e6ef2026-08-02 20:01:37 +0200197amtlichen Nachfassungen; für Schleswig-Holstein, Berlin und Hessen
Matthias Andreas Benkard5f30f562026-07-28 06:00:16 +0200198reicht die Prüfung bis zur Befehlserkennung dort vollständig, aber ohne
199Anwendung —, weil deren Landesportale ihre Stammfassungen nur über eine
Matthias Andreas Benkard08c27472026-08-22 19:02:46 +0200200anmeldepflichtige Schnittstelle ausgeben. Thüringens Portal gibt sie
201ebensowenig aus; dort ist die konsolidierte Fassung aus dem Stammheft und
202den drei Änderungsheften des Gesetzblattes zusammengesetzt, die die
203Parlamentsdatenbank des Landtags frei ausgibt. Welche Konvention welches Land beisteuert, welche
Matthias Andreas Benkard2cfea002026-07-26 13:32:26 +0200204Stammfassungen woher stammen und was noch offen ist, verzeichnet
205`src/main/resources/sampledata/Landesrecht-Beispiele.adoc`.
206
Matthias Andreas Benkard58e19982026-07-13 07:09:19 +0200207
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200208[[quellformate]]
209== Quellformate: Gesetz, Entwurf, Antrag
210
211Ein Änderungsbefehl steht nicht nur im verkündeten Gesetzblatt. Dasselbe
212Vorhaben durchläuft als Referenten-, Regierungs- und Fraktionsentwurf,
213als Änderungsantrag und als Beschlussempfehlung mehrere Fassungen, und
214die Frage was gälte, wenn das durchkommt?“ stellt sich in jeder davon.
215ÄndGgner erschließt die Art eines Dokuments deshalb aus seinem Kopf
216nie aus dem Dateinamen, der lügen kann (im Beispielkorpus heißt ein
217Entschließungsantrag `BT-Drs-21-7071_Beschlussempfehlung.pdf`) und nie
218aus einer Kennung, die von außen mitzugeben wäre.
219
220Unterschieden werden:
221
222Änderungsgesetz::
223 Das verkündete Artikelgesetz aus BGBl, GVBl oder GVOBl. Der Regelfall.
224Gesetzentwurf::
225 Referenten-, Regierungs- und Fraktionsentwürfe, auch als Drucksache von
226 Bundestag, Bundesrat oder Landtag. Der Begründungsteil hinter dem
227 Regelungstext erzeugt keine Befehle; erkannt wird er an Begründung
228 ebenso wie an den Entwurfsvarianten („A. Allgemeiner Teil“, Zu
229 Artikel 1“).
230Änderungsantrag::
231 Ändert nicht das Stammgesetz, sondern eine *Drucksache* siehe unten.
232Beschlussempfehlung::
Matthias Andreas Benkardffc553b2026-08-15 12:18:32 +0200233 Trägt ihre Fassung in einer zweispaltigen Zusammenstellung, die
234 aufgelöst wird die Synopse zeigt dann die vom Ausschuss beschlossene
235 Fassung (siehe unten).
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200236Dokument ohne Änderungsbefehle::
237 Entschließungs- und schlichter Antrag, Plenarprotokoll, Bericht. Sie
238 werden übergangen und gemeldet nicht stillschweigend zu null
239 Befehlen verarbeitet.
240
241Sobald ein Entwurf, ein Antrag oder eine Beschlussempfehlung beteiligt
242ist, trägt die Synopse den Hinweis *Entwurfsfassung nicht geltendes
243Recht*; die Quellenzeile nennt je Datei die erkannte Art.
244
245=== Änderungsanträge
246
247Ein Änderungsantrag ist eine Metanderung: Er ändert den Entwurf, nicht
248das Gesetz. Sein Rahmensatz adressiert deshalb zwei Ebenen zugleich
249In § 3 Nr. 22 wird § 18 Nr. 1 wie folgt geändert:“ nennt erst die
250Stelle _in der Drucksache_ (den 22. Änderungsbefehl ihres dritten
251Paragraphen) und dann die Stelle _in dem Text, den dieser Befehl
252zitiert_. Angegeben wird der Antrag zusammen mit seinem Entwurf:
253
254[source,shell script]
255----
256java -jar target/aendggner-0.1.0-SNAPSHOT.jar \
257 BayJG-alt.txt Ltg-Drs-19-9707_Gesetzentwurf.pdf \
258 Ltg-Drs-19-10365_Aenderungsantrag-Gruene.pdf -o synopse.html
259----
260
261ÄndGgner wendet dann erst den Antrag auf den Entwurf an und danach den
262so geänderten Entwurf auf das Stammgesetz; die Synopse zeigt also, was
263gälte, wenn Entwurf _und_ Antrag durchkämen. Welcher Entwurf gemeint
264ist, entscheidet die Drucksachennummer, die der Antrag selbst nennt
265(„(Drs. 19/9707)“), nicht die Reihenfolge der Argumente. Fehlt der
266Entwurf, bleibt der Antrag unangewandt und wird gemeldet ihn
267ersatzweise auf das Stammgesetz loszulassen wäre falsch, denn seine
268Stellenangaben zielen auf die Drucksache. Erkannt wird auch die
269elliptische Antragsform, die das Hilfsverb nur einmal in der
270Beschlussformel führt („1. In Nr. 1.29 die Angabe „,“ am Ende durch die
271Angabe „;“ ersetzt.“).
272
Matthias Andreas Benkardffc553b2026-08-15 12:18:32 +0200273=== Beschlussempfehlungen: die beschlossene Fassung
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200274
275Die maßgebliche Fassung einer Beschlussempfehlung steht in einer
276zweispaltigen Zusammenstellung: links der Entwurf, rechts die Beschlüsse
Matthias Andreas Benkardffc553b2026-08-15 12:18:32 +0200277des Ausschusses. Anders als beim alten BGBl und beim Berliner GVBl
278stehen die Spalten *nicht* nacheinander im Inhaltsstrom, sondern
279zeilenweise verschränkt; getrennt werden sie deshalb über die
280Koordinaten (`PatchTextExtraktor.extrahiereSpalten`, Schnitt an der
281Blattmitte, aber nur an einem tatsächlichen Spaltensteg, damit
282ganzseitenbreite Zeilen ungeschnitten bleiben).
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200283
Matthias Andreas Benkardffc553b2026-08-15 12:18:32 +0200284Die rechte Spalte für sich gelesen ist allerdings kein vollständiges
285Dokument: Sie druckt Unverändertes nicht ab, sondern vermerkt bloß
286unverändert und zwar nicht nur je Gliederungspunkt, sondern auch
287zeilenweise innerhalb zitierter Blöcke, weshalb ihre Anführungszeichen
288nicht aufgehen. Eine Auflösung über die Gliederungspfade scheitert daran
289nachweislich. Maßgeblich ist stattdessen die *Grundlinie*: Beide Spalten
290sind zeilensynchron gesetzt, jeder Vermerk steht auf der Höhe der
291Entwurfszeile, die er meint. Der `ZusammenstellungsLeser` führt beide
292Spalten über Seite und Grundlinie in eine gemeinsame Lesereihenfolge
293zusammen und entscheidet dann Zeile für Zeile: unverändert holt den
294Wortlaut aus der Entwurfsspalte, entfällt streicht ihn, sonst gilt die
295Ausschussspalte. Dabei meint unverändert den Wortlaut, nicht die
296Zählung streicht der Ausschuss einen Punkt, rücken die folgenden auf,
297und seine Marke tritt an die Stelle der des Entwurfs.
298
299Die Quellenzeile der Synopse weist die verwendete Spalte als
300`[Beschlussempfehlung …, Ausschussfassung]` aus. Lässt sich die
301Zusammenstellung nicht auflösen, wird die Datei nach wie vor mit
302Begründung übergangen samt Hinweis auf die Drucksachennummer des
303Entwurfs, der sich stattdessen eignet. Eine halb aufgelöste Fassung
304auszugeben wäre schlimmer als keine.
305
306Belegt ist beides: dass die *linke* Spalte Befehl für Befehl den
307Regierungsentwurf ergibt, aus dem die Zusammenstellung gebaut ist, und
308dass die aufgelöste Fassung mehr Befehle trägt als er der Ausschuss
309hat der GEG-Novelle zwei Artikel hinzugefügt. Zwei Beispiele stehen im
310Test: BT-Drs. 20/7619 (GEG) und BT-Drs. 19/24334 (Drittes
311Bevölkerungsschutzgesetz).
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200312
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200313[[web]]
314== Web-App
315
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200316Neben der CLI gibt es eine Browserfassung, die dieselbe Pipeline
317(`eu.mulk.aendggner.Pipeline`) über ein Upload-Formular zugänglich macht:
318Stammgesetz- und Änderungsgesetz-Datei(en) wählen, Synopse erhalten.
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200319
Matthias Andreas Benkard06da70e2026-08-16 07:34:12 +0200320Über dem Formular steht ein zugeklappter Einführungsblock, der zwei
321durchgerechnete Fälle mit Verweisen auf die amtlichen Fundstellen anbietet:
322das UWG (`gesetze-im-internet.de/uwg_2004/xml.zip`) mit dem Dritten Gesetz zu
323seiner Änderung (BGBl. 2026 I Nr. 43) und das AGG
324(`gesetze-im-internet.de/agg/xml.zip`) mit dem Regierungsentwurf BT-Drs.
32521/6178. Mitausgeliefert wird nichts; die Seite ruft die Dateien auch nicht
326selbst ab, sie verweist nur darauf.
327
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200328Sie braucht keinen Server: Die vollständige Verarbeitung PDF-Textgewinnung
329mit PDFBox eingeschlossen läuft als WebAssembly-Modul im Browser, übersetzt
330mit GraalVM Web Image aus demselben Java-Quelltext. Ausgeliefert werden nur
331statische Dateien; die gewählten Dokumente verlassen den Rechner der
332Nutzer:innen nicht.
333
334Bauen (verlangt Oracle GraalVM 25.1 oder neuer Web Image ist dort enthalten,
335in der Community Edition nicht):
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200336
337[source,shell script]
338----
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200339JAVA_HOME=/pfad/zu/oracle-graalvm ./mvnw -Pwasm package
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200340----
341
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200342Ergebnis ist `target/web/` mit `index.html`, `app.js`, `worker.js`,
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +0200343`style.css`, `favicon.svg`, `aendggner.js` und `aendggner.js.wasm` (rund 24 MB,
344komprimiert etwa 7 MB). Das Verzeichnis ist so, wie es dasteht, auslieferbar:
345`deploy/webpaket.sh` läuft am Ende desselben Befehls, wirft den mehrere hundert
346Megabyte großen Textzwischenschritt `aendggner.js.wat` fort, legt den Quelltext
347der gebauten Fassung als `aendggner-quelltext.tar.gz` samt
348`quelltext-fassung.txt` bei und komprimiert die großen Dateien nach `.gz` und
349`.br` vor. Trägt der Arbeitsbaum uneingecheckte Änderungen, bricht der Bau ab
350der beigelegte Quelltext wäre dann nicht der gebaute; für einen Probelauf hilft
351`QUELLTEXT_UNGEPRUEFT=1`.
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200352
353Lokal ansehen `file://` genügt nicht, Browser laden Wasm-Module und Worker
Matthias Andreas Benkard08f53072026-08-16 06:05:39 +0200354nur über HTTP (http://localhost:8000/):
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200355
356[source,shell script]
357----
Matthias Andreas Benkard08f53072026-08-16 06:05:39 +0200358jwebserver -d target/web
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200359----
360
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +0200361Die Befehlszeilenfassung bleibt davon unberührt und ist weiterhin der Weg für
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200362Massenläufe.
363
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +0200364=== Ausrollen
365
366Betrieben wird die Fassung unter einem Unterpfad einer bestehenden Domain,
367https://matthias.benkard.de/aendggner/ — ein eigener Server und ein eigenes
368Zertifikat sind dafür nicht nötig. Nötig ist nur ein Webserver für statische
369Dateien.
370
371[source,shell script]
372----
373JAVA_HOME=/pfad/zu/oracle-graalvm ./mvnw -Pwasm package
374rsync -av --delete target/web/ server:/var/www/aendggner/
375----
376
377`deploy/nginx-aendggner.conf` ist dafür kein eigener `server`-Block, sondern ein
378Schnipsel zum Einfügen in den vorhandenen (`include`). Er bringt mit:
379
380* die Weiterleitung von `/aendggner` auf `/aendggner/`, ohne die alle relativen
381 Verweise der Seite auf die Domainwurzel zielten;
382* den MIME-Typ `application/wasm`, ohne den der Browser die Instanziierung des
383 Moduls verweigert;
384* `gzip_static`/`brotli_static` für die vorkomprimierten Dateien, statt 24 MB je
385 Abruf neu zu packen;
386* `Cache-Control: no-cache` statt einer Haltefrist: Die Dateinamen tragen keine
387 Fassungskennung, und ein Browser mit altem `app.js` und neuem `.wasm` bekäme
388 sonst eine Mischfassung, die es nie gegeben hat. Revalidiert wird per ETag, das
389 unveränderte Modul kostet dann ein 304 ohne Rumpf;
390* die Sicherheitskopfzeilen samt einer Content-Security-Policy. Zwei ihrer
391 Freigaben sind unvermeidlich und in der Datei begründet: `'wasm-unsafe-eval'`
392 für die Instanziierung des Moduls und `'unsafe-inline'` für Stile, weil die
393 Synopse als `blob:`-Dokument die Richtlinie der erzeugenden Seite erbt, ihr
394 Stylesheet aber eingebettet trägt.
395
396Der Footer der Startseite verweist auf den beigelegten Quelltext-Tarball; das
397verlangt AGPLv3 §13 für den Netzwerkbetrieb. Als fortlaufende Zweitquelle ist
398https://gerrit.benkard.de/plugins/gitiles/aendggner genannt. `impressum.html`
399und `datenschutz.html` tragen die Angaben nach § 5 DDG und Art. 13 DSGVO; die
400dort genannte Aufbewahrungsfrist der Zugriffsprotokolle (14 Tage) muss zu der
401des Servers passen.
402
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200403=== Warum WebAssembly und nicht ein Java-Server
404
405Der Kern ist reines Java ohne Dateisystem- oder Netzzugriff; nur vier Stellen
406berührten die Plattform (PDFBox, MIME-Erkennung, XML-Parser, Dateizugriff).
407Sie sind hinter `eu.mulk.aendggner.Quelle` (Name + Bytes) und
408`eu.mulk.aendggner.DateiTyp` (Signaturbytes statt Tika) gebündelt, sodass
409Befehlszeile und Browser dieselbe Pipeline speisen.
410
411Zwei Eigenheiten von Web Image sind dabei zu beachten und im Quelltext
412vermerkt:
413
414* Die nativen zlib-Bindungen des JDK fehlen (`java.util.zip.Inflater`), ohne
415 die kein PDF lesbar ist. `src/wasm/java/.../InflaterErsatz.java` ersetzt sie
416 durch die reine Java-Umsetzung von jzlib.
417* Typisierte Felder lassen sich derzeit nicht nach `byte[]` umsetzen; der
418 Dateiinhalt wandert deshalb als Base64-Text über die JS-Grenze.
419
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200420
Matthias Andreas Benkardb291c362020-11-22 10:22:27 +0100421== Running the Tests
422
423To build and run the tests:
424
425[source,shell script]
426----
427./mvnw verify
428----