blob: 8059ea033752970fb0daf2b5067a40b91b5e52ec [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 Benkarda201e832026-08-02 19:45:34 +0200191(NEFG) und Nordrhein-Westfalen dort alle vier ändernden Artikel eines
192Heftes: Telemedienzuständigkeitsgesetz, Landesmediengesetz,
193Ausführungsgesetz zum 17. Rundfunkänderungsstaatsvertrag und, mit 101
Matthias Andreas Benkard74a84c52026-08-16 06:08:42 +0200194Befehlen an 31 Normen der größte Fall des Heftes, das WDR-Gesetz
Matthias Andreas Benkarda201e832026-08-02 19:45:34 +0200195mit Akzeptanztests gegen die
Matthias Andreas Benkard5b2e6ef2026-08-02 20:01:37 +0200196amtlichen Nachfassungen; für Schleswig-Holstein, Berlin und Hessen
Matthias Andreas Benkard5f30f562026-07-28 06:00:16 +0200197reicht die Prüfung bis zur Befehlserkennung dort vollständig, aber ohne
198Anwendung —, weil deren Landesportale ihre Stammfassungen nur über eine
199anmeldepflichtige Schnittstelle ausgeben. Welche Konvention welches Land beisteuert, welche
Matthias Andreas Benkard2cfea002026-07-26 13:32:26 +0200200Stammfassungen woher stammen und was noch offen ist, verzeichnet
201`src/main/resources/sampledata/Landesrecht-Beispiele.adoc`.
202
Matthias Andreas Benkard58e19982026-07-13 07:09:19 +0200203
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200204[[quellformate]]
205== Quellformate: Gesetz, Entwurf, Antrag
206
207Ein Änderungsbefehl steht nicht nur im verkündeten Gesetzblatt. Dasselbe
208Vorhaben durchläuft als Referenten-, Regierungs- und Fraktionsentwurf,
209als Änderungsantrag und als Beschlussempfehlung mehrere Fassungen, und
210die Frage was gälte, wenn das durchkommt?“ stellt sich in jeder davon.
211ÄndGgner erschließt die Art eines Dokuments deshalb aus seinem Kopf
212nie aus dem Dateinamen, der lügen kann (im Beispielkorpus heißt ein
213Entschließungsantrag `BT-Drs-21-7071_Beschlussempfehlung.pdf`) und nie
214aus einer Kennung, die von außen mitzugeben wäre.
215
216Unterschieden werden:
217
218Änderungsgesetz::
219 Das verkündete Artikelgesetz aus BGBl, GVBl oder GVOBl. Der Regelfall.
220Gesetzentwurf::
221 Referenten-, Regierungs- und Fraktionsentwürfe, auch als Drucksache von
222 Bundestag, Bundesrat oder Landtag. Der Begründungsteil hinter dem
223 Regelungstext erzeugt keine Befehle; erkannt wird er an Begründung
224 ebenso wie an den Entwurfsvarianten („A. Allgemeiner Teil“, Zu
225 Artikel 1“).
226Änderungsantrag::
227 Ändert nicht das Stammgesetz, sondern eine *Drucksache* siehe unten.
228Beschlussempfehlung::
Matthias Andreas Benkardffc553b2026-08-15 12:18:32 +0200229 Trägt ihre Fassung in einer zweispaltigen Zusammenstellung, die
230 aufgelöst wird die Synopse zeigt dann die vom Ausschuss beschlossene
231 Fassung (siehe unten).
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200232Dokument ohne Änderungsbefehle::
233 Entschließungs- und schlichter Antrag, Plenarprotokoll, Bericht. Sie
234 werden übergangen und gemeldet nicht stillschweigend zu null
235 Befehlen verarbeitet.
236
237Sobald ein Entwurf, ein Antrag oder eine Beschlussempfehlung beteiligt
238ist, trägt die Synopse den Hinweis *Entwurfsfassung nicht geltendes
239Recht*; die Quellenzeile nennt je Datei die erkannte Art.
240
241=== Änderungsanträge
242
243Ein Änderungsantrag ist eine Metanderung: Er ändert den Entwurf, nicht
244das Gesetz. Sein Rahmensatz adressiert deshalb zwei Ebenen zugleich
245In § 3 Nr. 22 wird § 18 Nr. 1 wie folgt geändert:“ nennt erst die
246Stelle _in der Drucksache_ (den 22. Änderungsbefehl ihres dritten
247Paragraphen) und dann die Stelle _in dem Text, den dieser Befehl
248zitiert_. Angegeben wird der Antrag zusammen mit seinem Entwurf:
249
250[source,shell script]
251----
252java -jar target/aendggner-0.1.0-SNAPSHOT.jar \
253 BayJG-alt.txt Ltg-Drs-19-9707_Gesetzentwurf.pdf \
254 Ltg-Drs-19-10365_Aenderungsantrag-Gruene.pdf -o synopse.html
255----
256
257ÄndGgner wendet dann erst den Antrag auf den Entwurf an und danach den
258so geänderten Entwurf auf das Stammgesetz; die Synopse zeigt also, was
259gälte, wenn Entwurf _und_ Antrag durchkämen. Welcher Entwurf gemeint
260ist, entscheidet die Drucksachennummer, die der Antrag selbst nennt
261(„(Drs. 19/9707)“), nicht die Reihenfolge der Argumente. Fehlt der
262Entwurf, bleibt der Antrag unangewandt und wird gemeldet ihn
263ersatzweise auf das Stammgesetz loszulassen wäre falsch, denn seine
264Stellenangaben zielen auf die Drucksache. Erkannt wird auch die
265elliptische Antragsform, die das Hilfsverb nur einmal in der
266Beschlussformel führt („1. In Nr. 1.29 die Angabe „,“ am Ende durch die
267Angabe „;“ ersetzt.“).
268
Matthias Andreas Benkardffc553b2026-08-15 12:18:32 +0200269=== Beschlussempfehlungen: die beschlossene Fassung
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200270
271Die maßgebliche Fassung einer Beschlussempfehlung steht in einer
272zweispaltigen Zusammenstellung: links der Entwurf, rechts die Beschlüsse
Matthias Andreas Benkardffc553b2026-08-15 12:18:32 +0200273des Ausschusses. Anders als beim alten BGBl und beim Berliner GVBl
274stehen die Spalten *nicht* nacheinander im Inhaltsstrom, sondern
275zeilenweise verschränkt; getrennt werden sie deshalb über die
276Koordinaten (`PatchTextExtraktor.extrahiereSpalten`, Schnitt an der
277Blattmitte, aber nur an einem tatsächlichen Spaltensteg, damit
278ganzseitenbreite Zeilen ungeschnitten bleiben).
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200279
Matthias Andreas Benkardffc553b2026-08-15 12:18:32 +0200280Die rechte Spalte für sich gelesen ist allerdings kein vollständiges
281Dokument: Sie druckt Unverändertes nicht ab, sondern vermerkt bloß
282unverändert und zwar nicht nur je Gliederungspunkt, sondern auch
283zeilenweise innerhalb zitierter Blöcke, weshalb ihre Anführungszeichen
284nicht aufgehen. Eine Auflösung über die Gliederungspfade scheitert daran
285nachweislich. Maßgeblich ist stattdessen die *Grundlinie*: Beide Spalten
286sind zeilensynchron gesetzt, jeder Vermerk steht auf der Höhe der
287Entwurfszeile, die er meint. Der `ZusammenstellungsLeser` führt beide
288Spalten über Seite und Grundlinie in eine gemeinsame Lesereihenfolge
289zusammen und entscheidet dann Zeile für Zeile: unverändert holt den
290Wortlaut aus der Entwurfsspalte, entfällt streicht ihn, sonst gilt die
291Ausschussspalte. Dabei meint unverändert den Wortlaut, nicht die
292Zählung streicht der Ausschuss einen Punkt, rücken die folgenden auf,
293und seine Marke tritt an die Stelle der des Entwurfs.
294
295Die Quellenzeile der Synopse weist die verwendete Spalte als
296`[Beschlussempfehlung …, Ausschussfassung]` aus. Lässt sich die
297Zusammenstellung nicht auflösen, wird die Datei nach wie vor mit
298Begründung übergangen samt Hinweis auf die Drucksachennummer des
299Entwurfs, der sich stattdessen eignet. Eine halb aufgelöste Fassung
300auszugeben wäre schlimmer als keine.
301
302Belegt ist beides: dass die *linke* Spalte Befehl für Befehl den
303Regierungsentwurf ergibt, aus dem die Zusammenstellung gebaut ist, und
304dass die aufgelöste Fassung mehr Befehle trägt als er der Ausschuss
305hat der GEG-Novelle zwei Artikel hinzugefügt. Zwei Beispiele stehen im
306Test: BT-Drs. 20/7619 (GEG) und BT-Drs. 19/24334 (Drittes
307Bevölkerungsschutzgesetz).
Matthias Andreas Benkard7235b342026-08-14 18:58:25 +0200308
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200309[[web]]
310== Web-App
311
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200312Neben der CLI gibt es eine Browserfassung, die dieselbe Pipeline
313(`eu.mulk.aendggner.Pipeline`) über ein Upload-Formular zugänglich macht:
314Stammgesetz- und Änderungsgesetz-Datei(en) wählen, Synopse erhalten.
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200315
Matthias Andreas Benkard06da70e2026-08-16 07:34:12 +0200316Über dem Formular steht ein zugeklappter Einführungsblock, der zwei
317durchgerechnete Fälle mit Verweisen auf die amtlichen Fundstellen anbietet:
318das UWG (`gesetze-im-internet.de/uwg_2004/xml.zip`) mit dem Dritten Gesetz zu
319seiner Änderung (BGBl. 2026 I Nr. 43) und das AGG
320(`gesetze-im-internet.de/agg/xml.zip`) mit dem Regierungsentwurf BT-Drs.
32121/6178. Mitausgeliefert wird nichts; die Seite ruft die Dateien auch nicht
322selbst ab, sie verweist nur darauf.
323
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200324Sie braucht keinen Server: Die vollständige Verarbeitung PDF-Textgewinnung
325mit PDFBox eingeschlossen läuft als WebAssembly-Modul im Browser, übersetzt
326mit GraalVM Web Image aus demselben Java-Quelltext. Ausgeliefert werden nur
327statische Dateien; die gewählten Dokumente verlassen den Rechner der
328Nutzer:innen nicht.
329
330Bauen (verlangt Oracle GraalVM 25.1 oder neuer Web Image ist dort enthalten,
331in der Community Edition nicht):
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200332
333[source,shell script]
334----
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200335JAVA_HOME=/pfad/zu/oracle-graalvm ./mvnw -Pwasm package
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200336----
337
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200338Ergebnis ist `target/web/` mit `index.html`, `app.js`, `worker.js`,
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +0200339`style.css`, `favicon.svg`, `aendggner.js` und `aendggner.js.wasm` (rund 24 MB,
340komprimiert etwa 7 MB). Das Verzeichnis ist so, wie es dasteht, auslieferbar:
341`deploy/webpaket.sh` läuft am Ende desselben Befehls, wirft den mehrere hundert
342Megabyte großen Textzwischenschritt `aendggner.js.wat` fort, legt den Quelltext
343der gebauten Fassung als `aendggner-quelltext.tar.gz` samt
344`quelltext-fassung.txt` bei und komprimiert die großen Dateien nach `.gz` und
345`.br` vor. Trägt der Arbeitsbaum uneingecheckte Änderungen, bricht der Bau ab
346der beigelegte Quelltext wäre dann nicht der gebaute; für einen Probelauf hilft
347`QUELLTEXT_UNGEPRUEFT=1`.
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200348
349Lokal ansehen `file://` genügt nicht, Browser laden Wasm-Module und Worker
Matthias Andreas Benkard08f53072026-08-16 06:05:39 +0200350nur über HTTP (http://localhost:8000/):
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200351
352[source,shell script]
353----
Matthias Andreas Benkard08f53072026-08-16 06:05:39 +0200354jwebserver -d target/web
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200355----
356
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +0200357Die Befehlszeilenfassung bleibt davon unberührt und ist weiterhin der Weg für
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200358Massenläufe.
359
Matthias Andreas Benkard2d33bf72026-08-16 06:40:07 +0200360=== Ausrollen
361
362Betrieben wird die Fassung unter einem Unterpfad einer bestehenden Domain,
363https://matthias.benkard.de/aendggner/ — ein eigener Server und ein eigenes
364Zertifikat sind dafür nicht nötig. Nötig ist nur ein Webserver für statische
365Dateien.
366
367[source,shell script]
368----
369JAVA_HOME=/pfad/zu/oracle-graalvm ./mvnw -Pwasm package
370rsync -av --delete target/web/ server:/var/www/aendggner/
371----
372
373`deploy/nginx-aendggner.conf` ist dafür kein eigener `server`-Block, sondern ein
374Schnipsel zum Einfügen in den vorhandenen (`include`). Er bringt mit:
375
376* die Weiterleitung von `/aendggner` auf `/aendggner/`, ohne die alle relativen
377 Verweise der Seite auf die Domainwurzel zielten;
378* den MIME-Typ `application/wasm`, ohne den der Browser die Instanziierung des
379 Moduls verweigert;
380* `gzip_static`/`brotli_static` für die vorkomprimierten Dateien, statt 24 MB je
381 Abruf neu zu packen;
382* `Cache-Control: no-cache` statt einer Haltefrist: Die Dateinamen tragen keine
383 Fassungskennung, und ein Browser mit altem `app.js` und neuem `.wasm` bekäme
384 sonst eine Mischfassung, die es nie gegeben hat. Revalidiert wird per ETag, das
385 unveränderte Modul kostet dann ein 304 ohne Rumpf;
386* die Sicherheitskopfzeilen samt einer Content-Security-Policy. Zwei ihrer
387 Freigaben sind unvermeidlich und in der Datei begründet: `'wasm-unsafe-eval'`
388 für die Instanziierung des Moduls und `'unsafe-inline'` für Stile, weil die
389 Synopse als `blob:`-Dokument die Richtlinie der erzeugenden Seite erbt, ihr
390 Stylesheet aber eingebettet trägt.
391
392Der Footer der Startseite verweist auf den beigelegten Quelltext-Tarball; das
393verlangt AGPLv3 §13 für den Netzwerkbetrieb. Als fortlaufende Zweitquelle ist
394https://gerrit.benkard.de/plugins/gitiles/aendggner genannt. `impressum.html`
395und `datenschutz.html` tragen die Angaben nach § 5 DDG und Art. 13 DSGVO; die
396dort genannte Aufbewahrungsfrist der Zugriffsprotokolle (14 Tage) muss zu der
397des Servers passen.
398
Matthias Andreas Benkard2b1841e2026-08-15 10:51:11 +0200399=== Warum WebAssembly und nicht ein Java-Server
400
401Der Kern ist reines Java ohne Dateisystem- oder Netzzugriff; nur vier Stellen
402berührten die Plattform (PDFBox, MIME-Erkennung, XML-Parser, Dateizugriff).
403Sie sind hinter `eu.mulk.aendggner.Quelle` (Name + Bytes) und
404`eu.mulk.aendggner.DateiTyp` (Signaturbytes statt Tika) gebündelt, sodass
405Befehlszeile und Browser dieselbe Pipeline speisen.
406
407Zwei Eigenheiten von Web Image sind dabei zu beachten und im Quelltext
408vermerkt:
409
410* Die nativen zlib-Bindungen des JDK fehlen (`java.util.zip.Inflater`), ohne
411 die kein PDF lesbar ist. `src/wasm/java/.../InflaterErsatz.java` ersetzt sie
412 durch die reine Java-Umsetzung von jzlib.
413* Typisierte Felder lassen sich derzeit nicht nach `byte[]` umsetzen; der
414 Dateiinhalt wandert deshalb als Base64-Text über die JS-Grenze.
415
Matthias Andreas Benkard7b455cd2026-08-09 08:33:37 +0200416
Matthias Andreas Benkardb291c362020-11-22 10:22:27 +0100417== Running the Tests
418
419To build and run the tests:
420
421[source,shell script]
422----
423./mvnw verify
424----