aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--FASSUNGEN.txt107
-rw-r--r--README.adoc67
-rw-r--r--deploy/nginx-aendggner.conf101
-rwxr-xr-xdeploy/webpaket.sh73
-rw-r--r--pom.xml20
-rw-r--r--src/main/resources/eu/mulk/aendggner/web/datenschutz.html43
-rw-r--r--src/main/resources/eu/mulk/aendggner/web/favicon.svg9
-rw-r--r--src/main/resources/eu/mulk/aendggner/web/impressum.html45
-rw-r--r--src/main/resources/eu/mulk/aendggner/web/index.html17
-rw-r--r--src/main/resources/eu/mulk/aendggner/web/style.css27
10 files changed, 442 insertions, 67 deletions
diff --git a/FASSUNGEN.txt b/FASSUNGEN.txt
index ec8aeb5..ad304ba 100644
--- a/FASSUNGEN.txt
+++ b/FASSUNGEN.txt
@@ -21,6 +21,113 @@ Vorbemerkung zur Führung dieses Verzeichnisses
════════════════════════════════════════════════════════════════════════════════
+ Fassung vom 16. August 2026,
+ zuletzt geändert durch die am 16. August 2026 vorgenommenen Änderungen
+════════════════════════════════════════════════════════════════════════════════
+
+Die Browserfassung war bislang für den öffentlichen Betrieb gesperrt: Die
+Anbieterkennzeichnung und die Datenschutzerklärung führten Platzhalter, und der
+Verweis auf den Quelltext, den die Lizenz des Erzeugnisses beim Netzbetrieb
+verlangt, zeigte auf keine Adresse. Mit dieser Fassung wird die Sperre
+aufgehoben; zugleich wird die Auslieferung auf den Betrieb unter einem Unterpfad
+einer bestehenden Domain eingerichtet.
+
+
+Artikel 1
+Anbieterkennzeichnung und Datenschutzerklärung
+
+(1) Die Anbieterkennzeichnung (impressum.html) wird mit den Angaben nach § 5 DDG
+ versehen; hinzu treten die Bezeichnung des nach § 18 Abs. 2 MStV
+ Verantwortlichen sowie ein Hinweis darauf, dass der Dienst unentgeltlich und
+ nichtkommerziell erbracht wird und die Synopsen ohne Gewähr ergehen.
+
+(2) Die Datenschutzerklärung (datenschutz.html) wird um die Bezeichnung des
+ Verantwortlichen (Art. 4 Nr. 7 DSGVO) und um die Rechte der betroffenen
+ Personen (Art. 15 bis 21, Art. 77 DSGVO) ergänzt. Für die Zugriffsprotokolle
+ werden die Rechtsgrundlage (Art. 6 Abs. 1 lit. f DSGVO) und die
+ Aufbewahrungsfrist (vierzehn Tage) benannt.
+
+(3) Die Aussage über die Dateien der Nutzer:innen bleibt unverändert; sie trifft
+ zu, weil die Verarbeitung ausschließlich im Browser stattfindet.
+
+
+Artikel 2
+Beilegung des Quelltextes
+
+(1) Es wird das Skript deploy/webpaket.sh eingeführt. Es tritt in der Phase
+ „package“ des Profils -Pwasm hinter den Übersetzer und macht aus dessen
+ Ergebnis ein auslieferbares Verzeichnis:
+ a) Der Textzwischenschritt (aendggner.js.wat) wird entfernt.
+ b) Der Quelltext der gebauten Fassung wird als aendggner-quelltext.tar.gz
+ nebst der Kennung der Fassung (quelltext-fassung.txt) beigelegt.
+ c) Die großen Dateien werden nach .gz und .br vorkomprimiert.
+
+(2) Trägt der Arbeitsbaum uneingecheckte Änderungen, so bricht der Bau ab. Der
+ Grund ist folgender: Der beigelegte Quelltext wäre alsdann nicht derjenige
+ der ausgelieferten Fassung, und die Auflage des § 13 AGPLv3 wäre verfehlt.
+ Für Probeläufe kann die Prüfung durch QUELLTEXT_UNGEPRUEFT=1 abbedungen
+ werden.
+
+(3) Der Fuß der Startseite (index.html) verweist fortan auf den beigelegten
+ Quelltext; die fortlaufende Quelle wird als Zweitverweis daneben genannt.
+
+
+Artikel 3
+Auslieferungsvorlage
+
+Die Vorlage (deploy/nginx-aendggner.conf) wird vom eigenen server-Block auf ein
+location-Schnipsel umgestellt, das in den bestehenden Server eingefügt wird. Sie
+wird wie folgt geändert:
+
+1. Aufgenommen wird die Weiterleitung des Pfades ohne abschließenden
+ Schrägstrich; ohne sie zielten sämtliche relativen Verweise der Seite auf die
+ Wurzel der Domain.
+
+2. Die Dateien werden über „root“ statt über „alias“ zugeordnet, weil try_files
+ in einer Präfix-Location gegen den root auflöst und mit alias fehlgeht.
+
+3. Die Haltefrist von sieben Tagen entfällt und wird durch Revalidierung
+ ersetzt. Der Grund ist folgender: Die Dateinamen tragen keine
+ Fassungskennung; ein Browser mit altem Steuerskript und neuem Rechenwerk
+ erhielte sonst eine Mischfassung, die es nie gegeben hat.
+
+4. Die vorkomprimierten Dateien werden ausgeliefert, statt das Rechenwerk je
+ Abruf neu zu packen.
+
+5. Aufgenommen werden die Sicherheitskopfzeilen nebst einer Inhaltsrichtlinie.
+ Zwei ihrer Freigaben sind unvermeidlich und in der Vorlage begründet:
+ diejenige für die Instanziierung des Moduls und diejenige für eingebettete
+ Stile, weil die Synopse als blob:-Dokument die Richtlinie der erzeugenden
+ Seite erbt, ihr Stylesheet aber eingebettet trägt.
+
+
+Artikel 4
+Ergänzungen der Oberfläche
+
+1. Die Startseite erhält einen Hinweis für den Fall abgeschalteten JavaScripts;
+ bislang blieb das Formular alsdann wortlos wirkungslos.
+
+2. Es wird ein Sinnbild (favicon.svg) eingeführt und in allen Seiten relativ
+ verwiesen; unter einem Unterpfad griffe der Abruf der Wurzel ins Leere.
+
+3. Die Startseite erhält eine Kurzbeschreibung und die Angabe ihrer kanonischen
+ Adresse; das Stilblatt wird um die Auszeichnung der Überschriften zweiter
+ Ordnung, der Anschriften und der Hinweise ergänzt.
+
+
+Schlussbestimmung
+
+Die vorstehenden Änderungen sind durch die Prüfung sämtlicher Testfälle
+(dreihundertvier an der Zahl) bestätigt worden. Die Inhaltsrichtlinie ist gegen
+die laufende Anwendung erprobt worden: Der Lauf des IfSG-Falles im Browser hat
+unter ihr achtundvierzig angewandte Befehle, siebenundzwanzig zur manuellen
+Prüfung und einundzwanzig geänderte Normen ergeben, mithin dasselbe wie die
+Befehlszeile, und keine Beanstandung hinterlassen; die Erforderlichkeit der
+Freigabe für eingebettete Stile ist dadurch belegt, dass die Synopse ohne sie
+unformatiert erscheint.
+
+
+════════════════════════════════════════════════════════════════════════════════
Fassung vom 15. August 2026,
zuletzt geändert durch die am 15. August 2026 vorgenommenen Änderungen
════════════════════════════════════════════════════════════════════════════════
diff --git a/README.adoc b/README.adoc
index 586b17f..b2329b7 100644
--- a/README.adoc
+++ b/README.adoc
@@ -325,9 +325,15 @@ JAVA_HOME=/pfad/zu/oracle-graalvm ./mvnw -Pwasm package
----
Ergebnis ist `target/web/` mit `index.html`, `app.js`, `worker.js`,
-`style.css`, `aendggner.js` und `aendggner.js.wasm` (rund 20 MB, komprimiert
-etwa 6 MB). Die daneben liegende `aendggner.js.wat` ist ein Zwischenschritt des
-Übersetzers und gehört nicht auf den Server.
+`style.css`, `favicon.svg`, `aendggner.js` und `aendggner.js.wasm` (rund 24 MB,
+komprimiert etwa 7 MB). Das Verzeichnis ist so, wie es dasteht, auslieferbar:
+`deploy/webpaket.sh` läuft am Ende desselben Befehls, wirft den mehrere hundert
+Megabyte großen Textzwischenschritt `aendggner.js.wat` fort, legt den Quelltext
+der gebauten Fassung als `aendggner-quelltext.tar.gz` samt
+`quelltext-fassung.txt` bei und komprimiert die großen Dateien nach `.gz` und
+`.br` vor. Trägt der Arbeitsbaum uneingecheckte Änderungen, bricht der Bau ab —
+der beigelegte Quelltext wäre dann nicht der gebaute; für einen Probelauf hilft
+`QUELLTEXT_UNGEPRUEFT=1`.
Lokal ansehen — `file://` genügt nicht, Browser laden Wasm-Module und Worker
nur über HTTP (http://localhost:8000/):
@@ -337,11 +343,48 @@ nur über HTTP (http://localhost:8000/):
jwebserver -d target/web
----
-Der öffentliche Betrieb braucht nur einen Webserver für statische Dateien;
-eine `nginx`-Vorlage liegt unter `deploy/nginx-aendggner.conf`. Die
-Befehlszeilenfassung bleibt davon unberührt und ist weiterhin der Weg für
+Die Befehlszeilenfassung bleibt davon unberührt und ist weiterhin der Weg für
Massenläufe.
+=== Ausrollen
+
+Betrieben wird die Fassung unter einem Unterpfad einer bestehenden Domain,
+https://matthias.benkard.de/aendggner/ — ein eigener Server und ein eigenes
+Zertifikat sind dafür nicht nötig. Nötig ist nur ein Webserver für statische
+Dateien.
+
+[source,shell script]
+----
+JAVA_HOME=/pfad/zu/oracle-graalvm ./mvnw -Pwasm package
+rsync -av --delete target/web/ server:/var/www/aendggner/
+----
+
+`deploy/nginx-aendggner.conf` ist dafür kein eigener `server`-Block, sondern ein
+Schnipsel zum Einfügen in den vorhandenen (`include`). Er bringt mit:
+
+* die Weiterleitung von `/aendggner` auf `/aendggner/`, ohne die alle relativen
+ Verweise der Seite auf die Domainwurzel zielten;
+* den MIME-Typ `application/wasm`, ohne den der Browser die Instanziierung des
+ Moduls verweigert;
+* `gzip_static`/`brotli_static` für die vorkomprimierten Dateien, statt 24 MB je
+ Abruf neu zu packen;
+* `Cache-Control: no-cache` statt einer Haltefrist: Die Dateinamen tragen keine
+ Fassungskennung, und ein Browser mit altem `app.js` und neuem `.wasm` bekäme
+ sonst eine Mischfassung, die es nie gegeben hat. Revalidiert wird per ETag, das
+ unveränderte Modul kostet dann ein 304 ohne Rumpf;
+* die Sicherheitskopfzeilen samt einer Content-Security-Policy. Zwei ihrer
+ Freigaben sind unvermeidlich und in der Datei begründet: `'wasm-unsafe-eval'`
+ für die Instanziierung des Moduls und `'unsafe-inline'` für Stile, weil die
+ Synopse als `blob:`-Dokument die Richtlinie der erzeugenden Seite erbt, ihr
+ Stylesheet aber eingebettet trägt.
+
+Der Footer der Startseite verweist auf den beigelegten Quelltext-Tarball; das
+verlangt AGPLv3 §13 für den Netzwerkbetrieb. Als fortlaufende Zweitquelle ist
+https://gerrit.benkard.de/plugins/gitiles/aendggner genannt. `impressum.html`
+und `datenschutz.html` tragen die Angaben nach § 5 DDG und Art. 13 DSGVO; die
+dort genannte Aufbewahrungsfrist der Zugriffsprotokolle (14 Tage) muss zu der
+des Servers passen.
+
=== Warum WebAssembly und nicht ein Java-Server
Der Kern ist reines Java ohne Dateisystem- oder Netzzugriff; nur vier Stellen
@@ -360,18 +403,6 @@ vermerkt:
Dateiinhalt wandert deshalb als Base64-Text über die JS-Grenze.
-Vor dem produktiven, öffentlichen Betrieb sind zwingend zu erledigen:
-
-* `impressum.html` und `datenschutz.html`
- (`src/main/resources/eu/mulk/aendggner/web/`) mit den tatsächlich
- zutreffenden Angaben statt der `TODO`-Platzhalter füllen (Pflicht
- nach § 5 DDG bzw. DSGVO für öffentlich erreichbare Dienste).
-* Den Quellcode-Link im Footer von `index.html` auf das tatsächlich
- öffentlich erreichbare Repository setzen — das Projekt steht unter
- AGPLv3 (`COPYING`), dessen §13 bei Netzwerkbetrieb einen
- Quellcode-Zugriff für Nutzer:innen verlangt.
-
-
== Running the Tests
To build and run the tests:
diff --git a/deploy/nginx-aendggner.conf b/deploy/nginx-aendggner.conf
index 46eacb5..78677b5 100644
--- a/deploy/nginx-aendggner.conf
+++ b/deploy/nginx-aendggner.conf
@@ -1,47 +1,80 @@
-# Vorlage für die Auslieferung der ÄndGgner-Browserfassung. Es gibt keinen
-# Anwendungsprozess mehr: Der Server liefert nur statische Dateien aus
-# (Inhalt von target/web/), gerechnet wird im Browser.
+# Vorlage für die Auslieferung der ÄndGgner-Browserfassung unter
+# https://matthias.benkard.de/aendggner/.
#
-# Vor dem Einsatz anpassen: server_name, ssl_certificate(_key) (z. B. via certbot), root.
+# Es gibt keinen Anwendungsprozess: Der Server liefert nur statische Dateien aus
+# (Inhalt von target/web/), gerechnet wird im Browser. Weil der Dienst unter einem
+# Unterpfad einer bestehenden Domain läuft, ist dies kein eigener server-Block,
+# sondern ein Schnipsel zum Einfügen in den vorhandenen — Zertifikat, HTTP→HTTPS
+# und Domainname bleiben, wie sie sind:
+#
+# server { ... include /etc/nginx/snippets/aendggner.conf; ... }
+#
+# Ausgerollt wird nach /var/www/aendggner (siehe README.adoc, Abschnitt „Ausrollen“).
-server {
- listen 80;
- listen [::]:80;
- server_name aendggner.example.org;
- return 301 https://$host$request_uri;
+# Ohne diesen Schritt liefe /aendggner ins Leere, und alle relativen Verweise der
+# Seite gingen von / statt von /aendggner/ aus.
+location = /aendggner {
+ return 301 /aendggner/;
}
-server {
- listen 443 ssl http2;
- listen [::]:443 ssl http2;
- server_name aendggner.example.org;
-
- ssl_certificate /etc/letsencrypt/live/aendggner.example.org/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/aendggner.example.org/privkey.pem;
-
- # Inhalt von target/web/ — ohne aendggner.js.wat, das nur ein Zwischenschritt
- # des Übersetzers ist.
- root /var/www/aendggner;
+location /aendggner/ {
+ # Bewusst „root /var/www“ (mit dem Verzeichnis /var/www/aendggner) statt
+ # „alias /var/www/aendggner/“: In einer Präfix-Location löst try_files $uri
+ # gegen den root auf, nicht gegen den alias, und liefert dann 404 für alles.
+ root /var/www;
index index.html;
- # Ohne diesen Typ lehnt der Browser die Streaming-Instanziierung des Moduls ab.
+ try_files $uri $uri/ =404;
+
+ # Ohne den ersten Typ lehnt der Browser die Streaming-Instanziierung des Moduls
+ # ab. Ein types-Block in einer location ersetzt die Zuordnung vollständig, statt
+ # sie zu ergänzen — deshalb stehen hier alle vorkommenden Endungen.
types {
application/wasm wasm;
+ text/html html;
+ text/css css;
+ text/javascript js;
+ image/svg+xml svg;
+ text/plain txt;
+ application/gzip gz;
}
+ default_type application/octet-stream;
- gzip on;
- gzip_types application/wasm application/javascript text/css text/html;
- gzip_min_length 1024;
+ # Das Wasm-Modul ist rund 24 MB groß. deploy/webpaket.sh legt beim Bauen .gz
+ # und .br daneben; ausgeliefert wird die fertige Datei, statt sie je Abruf neu
+ # zu packen. gzip_static bringen die üblichen Distributionspakete mit;
+ # brotli_static setzt das Modul ngx_brotli voraus — fehlt es, die Zeile
+ # streichen, gzip_static genügt.
+ gzip_static on;
+ brotli_static on;
- # Das Wasm-Modul ist einige Megabyte groß und ändert sich nur mit einer neuen
- # Fassung; vorkomprimierte .gz/.br daneben zu legen lohnt sich (ngx_brotli bzw.
- # gzip_static).
- location ~ \.(wasm|js|css)$ {
- expires 7d;
- add_header Cache-Control "public";
- }
+ # Kein „expires 7d“: Die Dateinamen tragen keine Fassungskennung. Ein Browser
+ # mit altem app.js und neuem .wasm (oder umgekehrt) bekäme eine Mischfassung,
+ # die es nie gegeben hat. Stattdessen Revalidierung bei jedem Abruf; für das
+ # unveränderte Modul kostet das ein 304 ohne Rumpf.
+ add_header Cache-Control "no-cache" always;
- location / {
- try_files $uri $uri/ =404;
- }
+ # add_header in einer location verdrängt sämtliche vom server-Block geerbten
+ # Header. Alles, was hier gelten soll, muss deshalb hier stehen — auch ein
+ # dort gesetztes HSTS.
+ # add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
+
+ # 'wasm-unsafe-eval' ist für die Instanziierung des Moduls nötig; echtes eval
+ # oder new Function kommt in der erzeugten aendggner.js nicht vor.
+ #
+ # style-src braucht 'unsafe-inline': Die fertige Synopse wird als blob:-Dokument
+ # geöffnet, und ein blob:-Dokument erbt die CSP des Dokuments, das es erzeugt
+ # hat. Der HtmlRenderer bettet sein Stylesheet als <style> ein — ohne die
+ # Freigabe erschiene die Synopse unformatiert. Skripte bleiben streng.
+ add_header Content-Security-Policy "default-src 'none'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; form-action 'none'; frame-ancestors 'none'; base-uri 'none'" always;
+ add_header X-Content-Type-Options "nosniff" always;
+ add_header Referrer-Policy "no-referrer" always;
+ add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), usb=()" always;
}
+
+# Eine robots.txt unter /aendggner/ wäre wirkungslos: Maßgeblich ist allein die im
+# Wurzelverzeichnis der Domain. Wer die Seite von der Indizierung ausnehmen will,
+# trage dort ein:
+#
+# User-agent: *
+# Disallow: /aendggner/
diff --git a/deploy/webpaket.sh b/deploy/webpaket.sh
new file mode 100755
index 0000000..2003134
--- /dev/null
+++ b/deploy/webpaket.sh
@@ -0,0 +1,73 @@
+#!/bin/sh
+# Macht aus dem Übersetzerergebnis ein auslieferbares Verzeichnis. Läuft in der Phase
+# „package“ des Profils -Pwasm, unmittelbar nach native-image.
+#
+# 1. Der Textzwischenschritt aendggner.js.wat (mehrere hundert Megabyte) wird entfernt.
+# 2. Der Quelltext der gebauten Fassung wird als Tarball beigelegt — AGPLv3 §13 verlangt
+# beim Netzwerkbetrieb einen Quellcode-Zugang für die Nutzer:innen, und der Footer der
+# Startseite verweist darauf.
+# 3. Die großen Dateien werden vorkomprimiert, damit nginx sie mit gzip_static bzw.
+# brotli_static ausliefern kann, statt 24 MB je Abruf neu zu packen.
+#
+# Aufruf: deploy/webpaket.sh <ausgabeverzeichnis> (Standard: target/web)
+
+set -eu
+
+ziel="${1:-target/web}"
+quelle="$(CDPATH='' cd -- "$(dirname -- "$0")/.." && pwd)"
+
+if [ ! -d "$ziel" ]; then
+ echo "webpaket: $ziel gibt es nicht — erst -Pwasm package laufen lassen." >&2
+ exit 1
+fi
+
+# 1. Zwischenschritt fort.
+rm -f "$ziel/aendggner.js.wat"
+
+# 2. Quelltext der gebauten Fassung.
+#
+# Ein veränderter Arbeitsbaum bricht den Bau ab: Der angebotene Quelltext muss der
+# ausgelieferten Fassung entsprechen, sonst ist die Auflage aus §13 verfehlt. Wer nur
+# ausprobieren will, setzt QUELLTEXT_UNGEPRUEFT=1.
+if ! git -C "$quelle" rev-parse --git-dir >/dev/null 2>&1; then
+ echo "webpaket: $quelle ist kein Git-Arbeitsbaum; ohne ihn lässt sich der Quelltext" >&2
+ echo " der gebauten Fassung nicht beilegen (AGPLv3 §13)." >&2
+ exit 1
+fi
+
+if [ -n "$(git -C "$quelle" status --porcelain)" ] && [ "${QUELLTEXT_UNGEPRUEFT:-}" != 1 ]; then
+ echo "webpaket: Der Arbeitsbaum trägt uneingecheckte Änderungen. Der beigelegte Quelltext" >&2
+ echo " wäre dann nicht der gebaute. Erst einchecken — oder für einen Probelauf" >&2
+ echo " QUELLTEXT_UNGEPRUEFT=1 setzen (dann nicht ausliefern)." >&2
+ exit 1
+fi
+
+fassung="$(git -C "$quelle" rev-parse HEAD)"
+git -C "$quelle" archive --format=tar.gz --prefix=aendggner/ HEAD \
+ -o "$(CDPATH='' cd -- "$ziel" && pwd)/aendggner-quelltext.tar.gz"
+
+{
+ echo "ÄndGgner — Quelltext der ausgelieferten Fassung"
+ echo
+ echo "Commit: $fassung"
+ echo "Gebaut: $(date -u '+%Y-%m-%dT%H:%M:%SZ')"
+ echo
+ echo "Vollständig in aendggner-quelltext.tar.gz; Bauanleitung darin in README.adoc."
+ echo "Fortlaufend: https://gerrit.benkard.de/plugins/gitiles/aendggner"
+} > "$ziel/quelltext-fassung.txt"
+
+# 3. Vorkompression. Der Tarball ist bereits gepackt und bleibt außen vor.
+for datei in "$ziel"/*.wasm "$ziel"/*.js "$ziel"/*.css "$ziel"/*.html "$ziel"/*.svg \
+ "$ziel"/*.txt; do
+ [ -f "$datei" ] || continue
+ gzip -9 -f -k -- "$datei"
+ if command -v brotli >/dev/null 2>&1; then
+ brotli -f -- "$datei"
+ fi
+done
+
+if ! command -v brotli >/dev/null 2>&1; then
+ echo "webpaket: brotli nicht gefunden — nur .gz angelegt." >&2
+fi
+
+echo "webpaket: $ziel ist auslieferbar (Fassung $(git -C "$quelle" rev-parse --short HEAD))."
diff --git a/pom.xml b/pom.xml
index 601b9e9..b66267f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -392,6 +392,26 @@
</arguments>
</configuration>
</execution>
+
+ <!--
+ Macht aus dem Übersetzerergebnis ein auslieferbares Verzeichnis: entfernt den
+ .wat-Zwischenschritt, legt den Quelltext der gebauten Fassung bei (AGPLv3 §13)
+ und komprimiert vor. Läuft in derselben Phase, aber nach „web-image“ — Maven
+ führt gleichphasige Ausführungen in Deklarationsreihenfolge aus.
+ -->
+ <execution>
+ <id>webpaket</id>
+ <phase>package</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>${project.basedir}/deploy/webpaket.sh</executable>
+ <arguments>
+ <argument>${wasm.output.directory}</argument>
+ </arguments>
+ </configuration>
+ </execution>
</executions>
</plugin>
diff --git a/src/main/resources/eu/mulk/aendggner/web/datenschutz.html b/src/main/resources/eu/mulk/aendggner/web/datenschutz.html
index 5b9bbac..a8d046a 100644
--- a/src/main/resources/eu/mulk/aendggner/web/datenschutz.html
+++ b/src/main/resources/eu/mulk/aendggner/web/datenschutz.html
@@ -4,16 +4,24 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Datenschutz — ÄndGgner</title>
+ <link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<h1>Datenschutzerklärung</h1>
+
+ <h2>Verantwortlicher</h2>
<p>
- <strong>TODO vor dem Livegang:</strong> Bitte prüfen und um die für diesen konkreten Server
- zutreffenden Angaben ergänzen (Betreiber, Kontakt, tatsächliche Speicherdauer der
- Zugriffslogs, Hosting-Anbieter).
+ Verantwortlicher im Sinne des Art. 4 Nr. 7 DSGVO ist:
</p>
+ <address>
+ Matthias Benkard<br>
+ Machtlfinger Str. 29<br>
+ 81379 München<br>
+ Deutschland<br>
+ <a href="mailto:admin@mulk.eu">admin@mulk.eu</a>
+ </address>
<h2>Ihre Dateien</h2>
<p>
@@ -28,15 +36,36 @@
<h2>Zugriffsprotokolle</h2>
<p>
Beim Abruf der Seite selbst und der zugehörigen Dateien werden wie bei jedem Webserver
- technische Zugriffsdaten (u. a. IP-Adresse, Zeitpunkt, aufgerufene Adresse) für einen
- begrenzten Zeitraum zur Absicherung des Betriebs protokolliert. Diese Protokolle enthalten
- keine Angaben über die von Ihnen ausgewerteten Dokumente.
+ technische Zugriffsdaten (IP-Adresse, Zeitpunkt, aufgerufene Adresse, übertragene
+ Datenmenge, Statuscode sowie die vom Browser gemeldete Kennung und Verweisadresse)
+ protokolliert. Rechtsgrundlage ist Art. 6 Abs. 1 lit. f DSGVO; das berechtigte Interesse
+ liegt in der Absicherung und Fehlersuche des Betriebs. Die Protokolle werden nach
+ <strong>14 Tagen</strong> gelöscht. Sie enthalten keine Angaben über die von Ihnen
+ ausgewerteten Dokumente, denn diese erreichen den Server nicht.
+ </p>
+ <p>
+ Der Server wird gegebenenfalls bei einem Dienstleister innerhalb der Europäischen Union
+ betrieben, der insoweit als Auftragsverarbeiter nach Art. 28 DSGVO tätig ist.
</p>
<h2>Keine Cookies, keine Konten, kein Tracking</h2>
<p>
Dieser Dienst verwendet keine Cookies, erfordert keine Registrierung und bindet keine
- Analyse- oder Tracking-Dienste Dritter ein.
+ Analyse- oder Tracking-Dienste Dritter ein. Es werden keine Daten an Dritte weitergegeben
+ und keine Inhalte von fremden Servern nachgeladen.
+ </p>
+
+ <h2>Ihre Rechte</h2>
+ <p>
+ Ihnen stehen gegenüber dem Verantwortlichen die Rechte auf Auskunft (Art. 15 DSGVO),
+ Berichtigung (Art. 16), Löschung (Art. 17), Einschränkung der Verarbeitung (Art. 18),
+ Datenübertragbarkeit (Art. 20) sowie das Recht auf Widerspruch gegen die Verarbeitung
+ (Art. 21) zu. Wenden Sie sich dazu an die oben genannte Anschrift oder E-Mail-Adresse.
+ </p>
+ <p>
+ Unabhängig davon können Sie sich bei einer Aufsichtsbehörde beschweren (Art. 77 DSGVO).
+ Zuständig ist hier das Bayerische Landesamt für Datenschutzaufsicht, Promenade 27,
+ 91522 Ansbach.
</p>
</main>
<footer><a href="index.html">Zurück zum Formular</a></footer>
diff --git a/src/main/resources/eu/mulk/aendggner/web/favicon.svg b/src/main/resources/eu/mulk/aendggner/web/favicon.svg
new file mode 100644
index 0000000..4f6a847
--- /dev/null
+++ b/src/main/resources/eu/mulk/aendggner/web/favicon.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="ÄndGgner">
+ <!-- Farben wie in style.css: heller Grund, brauner Akzent. Ein Favicon erbt keine
+ CSS-Variablen, deshalb stehen die Werte hier ausgeschrieben. -->
+ <rect width="32" height="32" rx="6" fill="#fdfdfb"/>
+ <rect x="0.75" y="0.75" width="30.5" height="30.5" rx="5.25" fill="none" stroke="#d8d3c4"
+ stroke-width="1.5"/>
+ <text x="16" y="17" fill="#6b4423" font-family="Georgia, 'Times New Roman', serif"
+ font-size="22" text-anchor="middle" dominant-baseline="central">§</text>
+</svg>
diff --git a/src/main/resources/eu/mulk/aendggner/web/impressum.html b/src/main/resources/eu/mulk/aendggner/web/impressum.html
index 525ef77..3832d03 100644
--- a/src/main/resources/eu/mulk/aendggner/web/impressum.html
+++ b/src/main/resources/eu/mulk/aendggner/web/impressum.html
@@ -4,22 +4,53 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Impressum — ÄndGgner</title>
+ <link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<h1>Impressum</h1>
+
+ <h2>Angaben gemäß § 5 DDG</h2>
+ <address>
+ Matthias Benkard<br>
+ Machtlfinger Str. 29<br>
+ 81379 München<br>
+ Deutschland
+ </address>
+
+ <h2>Kontakt</h2>
<p>
- <strong>TODO vor dem Livegang:</strong> Diese Seite muss durch die nach § 5 DDG
- (Digitale-Dienste-Gesetz, vormals § 5 TMG) vorgeschriebenen Angaben ersetzt werden, bevor
- dieser Dienst öffentlich betrieben wird.
+ E-Mail: <a href="mailto:admin@mulk.eu">admin@mulk.eu</a><br>
+ Telefon: +49-8856-8054002<br>
+ Fax: +49-89-20008761207
</p>
+
+ <h2>Verantwortlich für den Inhalt nach § 18 Abs. 2 MStV</h2>
<address>
- [Name]<br>
- [Straße, Hausnummer]<br>
- [PLZ, Ort]<br>
- [E-Mail-Adresse]
+ Matthias Benkard, Machtlfinger Str. 29, 81379 München
</address>
+
+ <h2>Zur Sache</h2>
+ <p>
+ ÄndGgner ist ein unentgeltlicher, nichtkommerzieller Dienst ohne Registrierung. Eine
+ Umsatzsteuer-Identifikationsnummer besteht nicht; eine berufsrechtliche Aufsicht besteht
+ nicht, da es sich weder um Rechtsberatung noch um eine sonstige reglementierte Tätigkeit
+ handelt.
+ </p>
+ <p>
+ Die erzeugten Synopsen entstehen selbsttätig und sind <strong>ohne Gewähr</strong> für
+ Vollständigkeit und Richtigkeit. Maßgeblich ist allein die amtliche Verkündung im
+ jeweiligen Gesetz- oder Verordnungsblatt.
+ </p>
+ <p>
+ Die zugrunde liegende Software steht unter der GNU Affero General Public License,
+ Version 3 (Wortlaut in der Datei <code>COPYING</code> des Quelltextes), und wird
+ ausdrücklich ohne jede Gewährleistung überlassen. Den
+ <a href="aendggner-quelltext.tar.gz">Quelltext der betriebenen Fassung</a> gibt es zum
+ Herunterladen; fortlaufend auch über
+ <a href="https://gerrit.benkard.de/plugins/gitiles/aendggner">Gerrit</a>.
+ </p>
</main>
<footer><a href="index.html">Zurück zum Formular</a></footer>
</body>
diff --git a/src/main/resources/eu/mulk/aendggner/web/index.html b/src/main/resources/eu/mulk/aendggner/web/index.html
index 9f26889..9d1e343 100644
--- a/src/main/resources/eu/mulk/aendggner/web/index.html
+++ b/src/main/resources/eu/mulk/aendggner/web/index.html
@@ -4,6 +4,11 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ÄndGgner — Änderungsgesetze konsolidieren</title>
+ <meta name="description" content="Wendet Änderungsgesetze und Gesetzentwürfe selbsttätig auf ein
+ Stammgesetz an und zeigt das Ergebnis als zweispaltige Synopse. Die Auswertung läuft
+ vollständig im Browser; die gewählten Dateien werden nicht übertragen.">
+ <link rel="canonical" href="https://matthias.benkard.de/aendggner/">
+ <link rel="icon" href="favicon.svg" type="image/svg+xml">
<link rel="stylesheet" href="style.css">
<script src="app.js" defer></script>
</head>
@@ -16,6 +21,15 @@
</header>
<main>
+ <noscript>
+ <p class="noscript">
+ Dieses Werkzeug rechnet im Browser statt auf dem Server: Es braucht JavaScript und
+ WebAssembly. Ohne sie bleibt das nachstehende Formular wirkungslos. Wer beides nicht
+ einschalten möchte, verwende die Befehlszeilenfassung — sie liegt dem
+ <a href="aendggner-quelltext.tar.gz">Quelltext</a> bei und leistet dasselbe.
+ </p>
+ </noscript>
+
<form id="synopse-formular">
<div class="field">
<label for="stamm">Stammgesetz</label>
@@ -62,7 +76,8 @@
<footer>
<a href="impressum.html">Impressum</a> ·
<a href="datenschutz.html">Datenschutz</a> ·
- <a href="https://TODO-QUELLCODE-URL-EINTRAGEN">Quellcode (AGPLv3)</a>
+ <a href="aendggner-quelltext.tar.gz">Quelltext dieser Fassung (AGPLv3)</a>
+ <span class="nebenquelle">(<a href="https://gerrit.benkard.de/plugins/gitiles/aendggner">Git</a>)</span>
</footer>
</body>
</html>
diff --git a/src/main/resources/eu/mulk/aendggner/web/style.css b/src/main/resources/eu/mulk/aendggner/web/style.css
index cdea20e..8aa1e11 100644
--- a/src/main/resources/eu/mulk/aendggner/web/style.css
+++ b/src/main/resources/eu/mulk/aendggner/web/style.css
@@ -45,6 +45,21 @@ h1 {
margin: 0;
}
+/* Impressum und Datenschutz. */
+h2 {
+ margin: 1.75rem 0 0.5rem;
+ font-size: 1.125rem;
+}
+
+address {
+ font-style: normal;
+ margin: 0.5rem 0;
+}
+
+a {
+ color: var(--accent);
+}
+
.field {
margin-bottom: 1.25rem;
}
@@ -92,6 +107,14 @@ button:hover {
filter: brightness(1.1);
}
+.noscript {
+ margin: 0 0 2rem;
+ padding: 1rem;
+ border: 1px solid #a33;
+ border-radius: 6px;
+ font-size: 0.875rem;
+}
+
.disclaimer {
margin-top: 2rem;
padding: 1rem;
@@ -113,6 +136,10 @@ footer a {
color: var(--accent);
}
+.nebenquelle {
+ font-size: 0.8125rem;
+}
+
.meldung {
margin-top: 1.25rem;
padding: 0.75rem 1rem;