Branding auf Wurzelwerk (SWP) umstellen, Deployment systemagnostisch machen

Ersetzt "Lagebild" durch den Projektnamen Wurzelwerk (Stinkwurzpresse) in
allen Units, Configs und Docs. Entfernt konkrete Hostnamen (Bebop, Pi 5,
Debby) aus README/NOTES zugunsten generischer Rollenbezeichnungen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013vHZCwcCJnz4LKNgvT4bxv
This commit is contained in:
irrlicht
2026-09-04 20:28:57 +02:00
co-authored by Claude Sonnet 5
parent ac7d8c7e69
commit c43d8496bf
9 changed files with 68 additions and 64 deletions
+20 -20
View File
@@ -1,4 +1,4 @@
# Ingest # Wurzelwerk — Ingest
Stufe 0 und 1 der Pipeline: Quellenregister und Roh-Erfassung. Keine Stufe 0 und 1 der Pipeline: Quellenregister und Roh-Erfassung. Keine
Kodierung — was hier landet, soll sich beliebig oft neu kodieren lassen. Kodierung — was hier landet, soll sich beliebig oft neu kodieren lassen.
@@ -10,54 +10,54 @@ Kodierung — was hier landet, soll sich beliebig oft neu kodieren lassen.
| `sources.toml` | Quellenregister, einzige Wahrheit ueber die Quellen | | `sources.toml` | Quellenregister, einzige Wahrheit ueber die Quellen |
| `schema.sql` | Postgres-Schema (`quellen`, `raw_items`, `codings`, `poll_laeufe`) | | `schema.sql` | Postgres-Schema (`quellen`, `raw_items`, `codings`, `poll_laeufe`) |
| `poller.py` | Poller, zwei Senken: Postgres und gzip-JSONL | | `poller.py` | Poller, zwei Senken: Postgres und gzip-JSONL |
| `Containerfile` | Image fuer Bebop | | `Containerfile` | Image fuer den Produktivbetrieb |
| `lagebild-ingest.container`, `lagebild.network` | Quadlet-Units, rootless | | `wurzelwerk-ingest.container`, `wurzelwerk.network` | Quadlet-Units, rootless |
| `ingest.env.example` | Vorlage fuer die Zugangsdaten | | `ingest.env.example` | Vorlage fuer die Zugangsdaten |
## Bebop ## Deploy mit Postgres + Podman/Quadlet (rootless)
```sh ```sh
# 1. Schema einspielen # 1. Schema einspielen
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f schema.sql psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f schema.sql
# 2. Image bauen # 2. Image bauen
podman build -t localhost/lagebild-ingest:latest . podman build -t localhost/wurzelwerk-ingest:latest .
# 3. Konfiguration ablegen # 3. Konfiguration ablegen
mkdir -p ~/.config/lagebild mkdir -p ~/.config/wurzelwerk
cp ingest.env.example ~/.config/lagebild/ingest.env cp ingest.env.example ~/.config/wurzelwerk/ingest.env
cp sources.toml ~/.config/lagebild/sources.toml cp sources.toml ~/.config/wurzelwerk/sources.toml
chmod 600 ~/.config/lagebild/ingest.env chmod 600 ~/.config/wurzelwerk/ingest.env
$EDITOR ~/.config/lagebild/ingest.env $EDITOR ~/.config/wurzelwerk/ingest.env
# 4. Quadlet installieren # 4. Quadlet installieren
mkdir -p ~/.config/containers/systemd mkdir -p ~/.config/containers/systemd
cp lagebild-ingest.container lagebild.network ~/.config/containers/systemd/ cp wurzelwerk-ingest.container wurzelwerk.network ~/.config/containers/systemd/
systemctl --user daemon-reload systemctl --user daemon-reload
systemctl --user start lagebild-ingest systemctl --user start wurzelwerk-ingest
journalctl --user -u lagebild-ingest -f journalctl --user -u wurzelwerk-ingest -f
# Damit der Dienst ohne offene Sitzung weiterlaeuft: # Damit der Dienst ohne offene Sitzung weiterlaeuft:
loginctl enable-linger "$USER" loginctl enable-linger "$USER"
``` ```
`sources.toml` ist eingehaengt, nicht ins Image gebacken: eine neue Quelle ist `sources.toml` ist eingehaengt, nicht ins Image gebacken: eine neue Quelle ist
ein `systemctl --user restart lagebild-ingest`, kein Neubau. ein `systemctl --user restart wurzelwerk-ingest`, kein Neubau.
## Pi 5 — Schatten-Ingest ## Schatten-Ingest auf einem Zweitgeraet
Ohne Postgres, ohne Container: Ohne Postgres, ohne Container:
```sh ```sh
python3 poller.py --sink jsonl:/var/lib/lagebild/schatten python3 poller.py --sink jsonl:/pfad/zu/deinem/ablageordner
``` ```
Legt `<dir>/YYYYMMDD/YYYYMMDDHHMMSS.jsonl.gz` an, dedupliziert ueber eine Legt `<dir>/YYYYMMDD/YYYYMMDDHHMMSS.jsonl.gz` an, dedupliziert ueber eine
SQLite daneben. Als `systemd --user`-Unit mit `Restart=always` einrichten. SQLite daneben. Als `systemd --user`-Unit mit `Restart=always` einrichten.
Der Sinn ist nicht Redundanz um ihrer selbst willen: RSS-Feeds haben kein Der Sinn ist nicht Redundanz um ihrer selbst willen: RSS-Feeds haben kein
Archiv. Steht Bebops Poller einen Tag still, ist dieser Tag unwiederbringlich Archiv. Steht der Produktiv-Poller einen Tag still, ist dieser Tag
weg. Kodierungen lassen sich wiederholen, Rohdaten nie. unwiederbringlich weg. Kodierungen lassen sich wiederholen, Rohdaten nie.
## Betrieb ## Betrieb
@@ -130,5 +130,5 @@ spiegel | derstandard | 0.92 | Niederlage fuer Donald Trump - Gericht in Missou
- Telegram-Fetcher (Telethon/MTProto). Register ist vorbereitet, Eintraege - Telegram-Fetcher (Telethon/MTProto). Register ist vorbereitet, Eintraege
stehen auf `aktiv = false`. Die Bot-API kann fremde Kanaele nicht lesen. stehen auf `aktiv = false`. Die Bot-API kann fremde Kanaele nicht lesen.
- Ersatz-URL fuer den BR24-Feed (aktuell 404). - Ersatz-URL fuer den BR24-Feed (aktuell 404).
- Quellenpool von 12 auf ~40 erweitern; Regionalzeitungen ueber SearXNG auf - Quellenpool von 12 auf ~40 erweitern; Regionalzeitungen ueber SearXNG
Debby suchen. suchen.
+22 -18
View File
@@ -1,44 +1,48 @@
# swp-01-ingest # swp-01-ingest — Wurzelwerk
Stufe 0/1 der Lagebild-Pipeline: Quellenregister und Roh-Erfassung Stufe 0/1 der Wurzelwerk-Pipeline (Stinkwurzpresse, SWP): Quellenregister
(RSS-Poller, Senken Postgres oder gzip-JSONL). Details zu Betrieb, und Roh-Erfassung (RSS-Poller, Senken Postgres oder gzip-JSONL). Details zu
Verhalten und offenen Punkten stehen in [`NOTES.md`](NOTES.md). Betrieb, Verhalten und offenen Punkten stehen in [`NOTES.md`](NOTES.md).
## Deploy (Bebop, Postgres + Podman/Quadlet) ## Deploy (Server mit Postgres + Podman/Quadlet)
```sh ```sh
# 1. Schema einspielen # 1. Schema einspielen
psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f schema.sql psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f schema.sql
# 2. Image bauen # 2. Image bauen
podman build -t localhost/lagebild-ingest:latest . podman build -t localhost/wurzelwerk-ingest:latest .
# 3. Konfiguration ablegen # 3. Konfiguration ablegen
mkdir -p ~/.config/lagebild mkdir -p ~/.config/wurzelwerk
cp ingest.env.example ~/.config/lagebild/ingest.env cp ingest.env.example ~/.config/wurzelwerk/ingest.env
cp sources.toml ~/.config/lagebild/sources.toml cp sources.toml ~/.config/wurzelwerk/sources.toml
chmod 600 ~/.config/lagebild/ingest.env chmod 600 ~/.config/wurzelwerk/ingest.env
$EDITOR ~/.config/lagebild/ingest.env $EDITOR ~/.config/wurzelwerk/ingest.env
# 4. Quadlet installieren # 4. Quadlet installieren
mkdir -p ~/.config/containers/systemd mkdir -p ~/.config/containers/systemd
cp lagebild-ingest.container lagebild.network ~/.config/containers/systemd/ cp wurzelwerk-ingest.container wurzelwerk.network ~/.config/containers/systemd/
systemctl --user daemon-reload systemctl --user daemon-reload
systemctl --user start lagebild-ingest systemctl --user start wurzelwerk-ingest
journalctl --user -u lagebild-ingest -f journalctl --user -u wurzelwerk-ingest -f
# Damit der Dienst ohne offene Sitzung weiterlaeuft: # Damit der Dienst ohne offene Sitzung weiterlaeuft:
loginctl enable-linger "$USER" loginctl enable-linger "$USER"
``` ```
`sources.toml` ist eingehaengt, nicht ins Image gebacken: eine neue Quelle `sources.toml` ist eingehaengt, nicht ins Image gebacken: eine neue Quelle
ist ein `systemctl --user restart lagebild-ingest`, kein Neubau. ist ein `systemctl --user restart wurzelwerk-ingest`, kein Neubau.
## Deploy (Pi 5, ohne Postgres/Container) ## Deploy (Zweitgeraet ohne Postgres/Container, z. B. als Schatten-Ingest)
Fuer ein schlankes Zweitsystem ohne Postgres und ohne Container genuegt
Python 3.11+ mit den Paketen aus `requirements.txt`:
```sh ```sh
python3 poller.py --sink jsonl:/var/lib/lagebild/schatten python3 poller.py --sink jsonl:/pfad/zu/deinem/ablageordner
``` ```
Als `systemd --user`-Unit mit `Restart=always` einrichten (siehe Als `systemd --user`-Unit mit `Restart=always` einrichten (siehe
`lagebild-robots.service` / `.timer` fuer den woechentlichen Robots-Check). `wurzelwerk-robots.service` / `.timer` fuer den woechentlichen
Robots-Check).
+3 -3
View File
@@ -1,10 +1,10 @@
# Nach ~/.config/lagebild/ingest.env kopieren und ausfuellen (chmod 600). # Nach ~/.config/wurzelwerk/ingest.env kopieren und ausfuellen (chmod 600).
# #
# Bei rootless Podman erreichen sich Container ueber ein gemeinsames Netz per # Bei rootless Podman erreichen sich Container ueber ein gemeinsames Netz per
# Containername. Liegt Postgres bereits in einem Netz, dort denselben Namen # Containername. Liegt Postgres bereits in einem Netz, dort denselben Namen
# eintragen wie in der Zeile Network= der Quadlet-Datei. # eintragen wie in der Zeile Network= der Quadlet-Datei.
DATABASE_URL=postgresql://lagebild:GEHEIM@lagebild-pg:5432/lagebild DATABASE_URL=postgresql://wurzelwerk:GEHEIM@wurzelwerk-pg:5432/wurzelwerk
# Kontaktadresse gehoert in den User-Agent: wer unsere Abrufe sieht, soll # Kontaktadresse gehoert in den User-Agent: wer unsere Abrufe sieht, soll
# wissen, wen er anschreiben kann. # wissen, wen er anschreiben kann.
INGEST_USER_AGENT=lagebild-ingest/0.1 (+https://DEINE-DOMAIN/lagebild; kontakt@DEINE-DOMAIN) INGEST_USER_AGENT=wurzelwerk-ingest/0.1 (+https://stinkwurzpresse.de/wurzelwerk; kontakt@stinkwurzpresse.de)
-6
View File
@@ -1,6 +0,0 @@
# Ablegen unter ~/.config/containers/systemd/lagebild.network
[Unit]
Description=Lagebild internes Netz
[Network]
NetworkName=lagebild
+4 -4
View File
@@ -6,8 +6,8 @@ jedes neue Item roh ab. Bewusst ohne Kodierung: was hier landet, soll sich
beliebig oft neu kodieren lassen. beliebig oft neu kodieren lassen.
Zwei Senken: Zwei Senken:
--sink postgres://... Bebop, die eigentliche Datenbank --sink postgres://... Produktivbetrieb, die eigentliche Datenbank
--sink jsonl:/pfad/dir Pi 5, Schatten-Ingest als gzip-JSONL pro Slot --sink jsonl:/pfad/dir Schatten-Ingest als gzip-JSONL pro Slot
Aufrufe: Aufrufe:
poller.py --sink "$DATABASE_URL" # Dauerbetrieb, 15-Minuten-Takt poller.py --sink "$DATABASE_URL" # Dauerbetrieb, 15-Minuten-Takt
@@ -38,7 +38,7 @@ from email.utils import parsedate_to_datetime
HIER = pathlib.Path(__file__).parent HIER = pathlib.Path(__file__).parent
USER_AGENT = os.environ.get( USER_AGENT = os.environ.get(
"INGEST_USER_AGENT", "INGEST_USER_AGENT",
"lagebild-ingest/0.1 (+https://example.org/lagebild; kontakt@example.org)", "wurzelwerk-ingest/0.1 (+https://stinkwurzpresse.de/wurzelwerk; kontakt@stinkwurzpresse.de)",
) )
TAKT = 15 * 60 # Slotlaenge in Sekunden, wie bei GDELT TAKT = 15 * 60 # Slotlaenge in Sekunden, wie bei GDELT
VERSATZ = 30 # Sekunden nach der Slotgrenze, nicht exakt darauf VERSATZ = 30 # Sekunden nach der Slotgrenze, nicht exakt darauf
@@ -184,7 +184,7 @@ class JsonlSenke:
"""Schatten-Ingest fuer den Pi: gzip-JSONL, ein Verzeichnis pro Tag. """Schatten-Ingest fuer den Pi: gzip-JSONL, ein Verzeichnis pro Tag.
Kein Schema, keine Abfragen - nur die Garantie, dass die Rohdaten noch Kein Schema, keine Abfragen - nur die Garantie, dass die Rohdaten noch
da sind, wenn Bebop einen Tag lang stillstand. Die SQLite daneben haelt da sind, wenn der Produktiv-Poller einen Tag lang stillstand. Die SQLite daneben haelt
nur die gesehenen Schluessel, damit nicht bei jedem Slot der komplette nur die gesehenen Schluessel, damit nicht bei jedem Slot der komplette
Feed erneut geschrieben wird. Feed erneut geschrieben wird.
""" """
@@ -1,29 +1,29 @@
# Quadlet-Unit fuer rootless Podman. # Quadlet-Unit fuer rootless Podman.
# Ablegen unter ~/.config/containers/systemd/lagebild-ingest.container, # Ablegen unter ~/.config/containers/systemd/wurzelwerk-ingest.container,
# danach: systemctl --user daemon-reload && systemctl --user start lagebild-ingest # danach: systemctl --user daemon-reload && systemctl --user start wurzelwerk-ingest
# #
# Der Poller laeuft dauerhaft und taktet sich selbst auf die 15-Minuten-Grenzen. # Der Poller laeuft dauerhaft und taktet sich selbst auf die 15-Minuten-Grenzen.
# Deshalb kein systemd-Timer: ein Timer wuerde den bedingten GET-Zustand # Deshalb kein systemd-Timer: ein Timer wuerde den bedingten GET-Zustand
# (ETag/Last-Modified) bei jedem Start neu aufbauen muessen. # (ETag/Last-Modified) bei jedem Start neu aufbauen muessen.
[Unit] [Unit]
Description=Lagebild Ingest-Poller Description=Wurzelwerk Ingest-Poller
After=network-online.target After=network-online.target
Wants=network-online.target Wants=network-online.target
[Container] [Container]
Image=localhost/lagebild-ingest:latest Image=localhost/wurzelwerk-ingest:latest
ContainerName=lagebild-ingest ContainerName=wurzelwerk-ingest
AutoUpdate=local AutoUpdate=local
EnvironmentFile=%h/.config/lagebild/ingest.env EnvironmentFile=%h/.config/wurzelwerk/ingest.env
# Quellenregister von aussen einhaengen: eine neue Quelle ist dann ein # Quellenregister von aussen einhaengen: eine neue Quelle ist dann ein
# Neustart, kein Neubau des Images. # Neustart, kein Neubau des Images.
Volume=%h/.config/lagebild/sources.toml:/app/sources.toml:ro,Z Volume=%h/.config/wurzelwerk/sources.toml:/app/sources.toml:ro,Z
# Dasselbe Netz wie der Postgres-Container. # Dasselbe Netz wie der Postgres-Container.
Network=lagebild.network Network=wurzelwerk.network
NoNewPrivileges=true NoNewPrivileges=true
ReadOnly=true ReadOnly=true
@@ -3,11 +3,11 @@
# damit systemd den Fehlerzustand sichtbar haelt. # damit systemd den Fehlerzustand sichtbar haelt.
[Unit] [Unit]
Description=Lagebild - robots.txt der Quellen pruefen Description=Wurzelwerk - robots.txt der Quellen pruefen
[Service] [Service]
Type=oneshot Type=oneshot
ExecStart=/usr/bin/podman run --rm \ ExecStart=/usr/bin/podman run --rm \
--network=host \ --network=host \
-v %h/.config/lagebild/sources.toml:/app/sources.toml:ro \ -v %h/.config/wurzelwerk/sources.toml:/app/sources.toml:ro \
localhost/lagebild-ingest:latest --check-robots localhost/wurzelwerk-ingest:latest --check-robots
@@ -1,8 +1,8 @@
# Nach ~/.config/systemd/user/ ablegen, dann: # Nach ~/.config/systemd/user/ ablegen, dann:
# systemctl --user enable --now lagebild-robots.timer # systemctl --user enable --now wurzelwerk-robots.timer
[Unit] [Unit]
Description=Lagebild - woechentliche robots.txt-Pruefung Description=Wurzelwerk - woechentliche robots.txt-Pruefung
[Timer] [Timer]
OnCalendar=Mon 05:30 OnCalendar=Mon 05:30
+6
View File
@@ -0,0 +1,6 @@
# Ablegen unter ~/.config/containers/systemd/wurzelwerk.network
[Unit]
Description=Wurzelwerk internes Netz
[Network]
NetworkName=wurzelwerk