feat(tools): mirror-docs — Liste geteilter Dokumente per Timer nach git spiegeln (D88-Nachtrag 3)
Deploy to GitHub Pages / build (push) Canceled after 0s
Deploy to GitHub Pages / deploy (push) Canceled after 0s

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-09-04 09:52:02 +02:00
co-authored by Claude Fable 5.1
parent c87cf6212d
commit 2e408d956c
6 changed files with 154 additions and 0 deletions
+4
View File
@@ -17,6 +17,10 @@ the git history of `docs/examples/werkbaum.werkbaum`. A day can therefore carry
a link without having a note (someone forgot to write one) — but never the
reverse.
## 2026-09-04
- A `mirror-docs` script runs a list of shared documents through `pull-doc --git-commit` and pushes once — as a 15-minute timer on the backend host it gives a shared plan a git history without anyone remembering to run it
## 2026-09-03
- The project moved to its own Gitea at git.javagil.de — the footer's repository and version links point there now, and GitHub stays a clone carrying the very same commits
+57
View File
@@ -7638,6 +7638,63 @@ Haupttext gelten fort; neu geprüft außerdem: flaglos außerhalb jedes
Worktrees schreibt anstandslos, `--git-commit` dort lehnt mit klarer
Meldung ab.
**Nachtrag 3 — `mirror-docs`: ein Timer auf dem Backend-Host spiegelt eine
Liste von Dokumenten in einen eigenen Branch (2026-09-04).** Anlass war der
zweite Datenverlust an demselben geteilten Dokument: Am 3.9. um 19:03 schrieb
ein Fenster mit veralteter Schattenkopie den Stand vom Vorabend als Volltext
zurück — die Server-Historie hatte den ganzen Tag (Version 659 war der letzte
gute Stand, byte-genau wiederhergestellt), der Git-Spiegel aber nicht: Er lief
von Hand, und der letzte Lauf lag vor der verlorenen Arbeit. Ein Spiegel, der
nur läuft, wenn jemand daran denkt, ist an dem Tag nicht da, an dem man ihn
braucht.
**Der Spiegel läuft auf dem Backend-Host, nicht auf dem Laptop.** Der Server
ist rund um die Uhr an, `Linger=yes` ist gesetzt (D77), und er holt das
Dokument von `127.0.0.1:9080` ohne den Proxy. Ein Timer auf dem Laptop hätte
nur die Stunden abgedeckt, in denen der zu ist — mit `Persistent=true` zwar
nachgeholt, aber nach der Lücke, nicht davor. Gebaut als systemd-User-Timer
(`werkbaum-mirror.timer`, alle 15 Minuten, `Persistent=true`) neben der
Backend-Unit; der Service ruft `mirror-docs --push`.
**`tools/mirror-docs` ist die Schleife um `pull-doc`, nicht sein Ersatz.** Es
liest eine Liste (`documents.list`: je Zeile UUID oder URL und Pfad im Repo),
ruft je Zeile `pull-doc --git-commit` und pusht einmal am Ende — nur, wenn ein
Commit entstanden ist. Jede Zeile läuft für sich: Ein gescheiterter Abruf
bricht die übrigen nicht ab, steht aber auf stderr, und der Lauf endet mit 1,
damit das Journal des Timers den Fehler zeigt, statt still zu bleiben.
Nachgemessen lokal: eine Fehlerzeile in der Liste kostet genau ihr Dokument,
die beiden anderen werden committet; der zweite Lauf ohne Änderung committet
nichts und endet mit 0.
**Eine Liste statt „alle Dokumente des Servers“.** Die Dokumentenliste
verlangt das Master-Passwort (D76-Nachtrag 6), und auf dem Server liegt davon
nur der Hash. Für den Cron müsste das Klartext-Passwort dorthin, nur damit er
eine Liste bekommt, die er um Dateinamen ohnehin ergänzen müsste. Eine Zeile
je Dokument ist der ehrlichere Preis: kein Geheimnis mehr auf dem Host, und
Probe-Dokumente bleiben von selbst draußen.
**Ein Branch, viele Dateien.** Der Spiegel committet blind, also auf einen
eigenen Branch `werkbaum-mirror`, den man bei Bedarf nach `main` mergt — nicht
auf `main` mit den Hand-Commits dazwischen, sonst kollidiert der Server-Push
mit dem lokalen Stand und der Timer bleibt hängen. Beim ersten Lauf von Hand
war der Stand auf dem gerade ausgecheckten Feature-Branch gelandet; genau
das soll ein Timer nicht tun. Ein Branch je Werkbaum wäre eine dritte Spalte
in der Liste, wenn ihn je jemand braucht.
**Ein eigener Deploy-Key, ein Sparse-Checkout.** Auf dem Server liegt ein
Schlüssel des Backend-Logins; der bekommt nicht nebenbei Schreibrecht auf ein
privates Notizen-Repo. Der Spiegel hat seinen eigenen ed25519-Schlüssel
(`~/.ssh/werkbaum-mirror`, Host-Alias `notes-mirror` mit `IdentitiesOnly`),
als Deploy-Key mit Schreibrecht nur für dieses eine Repo. Geklont wird mit
`--filter=blob:none` und Sparse-Checkout auf das Zielverzeichnis — auf dem
geteilten Host liegen so nur die gespiegelten Dateien, nicht das ganze Repo
(5,7 MB getrackt, 666 MB Arbeitsverzeichnis lokal).
**Das Notes-Repo ist dabei nach Gitea gezogen** (`mi/notes` auf
`git.javagil.de`, alle vier Branches; `origin` ist Gitea, GitHub bleibt als
`github` — dieselbe Aufteilung wie D95). Der Deploy-Key gilt je Repo, also
zuerst der Umzug, dann der Schlüssel, statt beides zweimal.
## D89 — Zwei Stunden verlorene Arbeit: vier Netze gegen den stillen Live-Verlust
Der Vorfall (2026-08-27 vormittags, gemeldet vom Nutzer): Zwei Stunden Arbeit
an einem geteilten Dokument (`?live=`, PWA) waren weg — die Server-Historie
+8
View File
@@ -151,6 +151,7 @@
- [~] #col.git: Git as the shared store (L)
| [ ] #col.git.pr: A file in a repository, changed by pull request (S) %% works today, no code
| [^] #col.git.pull: A script pulls the server document and commits it (S) %% tools/pull-doc --git-commit, dated commits — see D88
- [x] #col.git.timer: A timer on the backend host mirrors a list of documents into a branch (S) %% tools/mirror-docs, systemd timer — see D88-Nachtrag 3
| [?] #col.git.auto: The backend commits every change (L) :#be.scaffold
- [?] #col.git.hist: History and restore (M)
- [?] #col.git.diff: Diff between two versions (S)
@@ -970,6 +971,13 @@
worktree — date, title and version in the message, no commit when nothing
changed. Run from cron, a shared plan archives itself.
#col.git.timer
tools/mirror-docs reads a list of documents (uuid and path), runs pull-doc
--git-commit for each and pushes once. As a systemd timer on the backend host
it mirrors the shared plans every 15 minutes into a werkbaum-mirror branch —
the net outside the browser and outside the backend, running whether or not
anyone remembers.
#col.git.auto
The server turns every change into a commit. History, restore and branches
follow from that, with commit granularity as the open question.