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