Ab jetzt laufen Aenderungen ueber eigene Branches und Pull Requests statt
direkt auf main, damit die logische Trennung sichtbar bleibt. Das gehoert
neben die tea-Kommandos, sonst kennt es nur die Sitzung, in der es vereinbart
wurde.
Festgehalten ist auch die Faustregel fuer den Zuschnitt: Wenn die
Commit-Nachricht "und ausserdem" braucht, sind es zwei Branches. Und dass das
Mergen dem Menschen gehoert, nicht der Umsetzung.
Nachtrag zum Tailwind-Rauswurf: dx legt die Datei bei jedem vollen Build neu
an - auch nachdem die Eingabedatei geloescht wurde und main.rs sie nicht mehr
verlinkt. Offenbar aus einem eigenen Cache; ein Schalter dagegen war nicht zu
finden.
Statt dagegen anzukaempfen wandert sie in die .gitignore. Sie ist ein lokales
Nebenprodukt ohne Leser, und so taucht sie nicht bei jedem Build als
vermeintliche Aenderung auf.
Die App hat nie eine Tailwind-Utility benutzt - saemtliche Klassen im Code
sind eigene (btn, files-bar, empty-state, ...), und den Reset liefert
base.css selbst. Damit standen package.json, node_modules und ein
Build-Schritt fuer eine Stylesheet-Datei, die nichts beigetragen hat.
Aufgefallen ist es, weil der letzte Commit ungefragt zwoelf Zeilen in
assets/tailwind.css mitbrachte: Der Generator scannt auch docs/ und erzeugte
Utilities fuer Woerter, die er in Prosa fand.
Die npm-Abhaengigkeit war ohnehin wirkungslos - Dioxus 0.7 bringt Tailwind
selbst mit (erzeugt wurde 4.1.5, nicht die in package.json deklarierte 4.3.3).
Ohne die Eingabedatei tailwind.css im Projektwurzelverzeichnis erzeugt dx
nichts mehr; verifiziert durch einen vollstaendigen Build.
Das --dn-Praefix der Tokens bleibt: Es war urspruenglich Schutz vor Tailwinds
eigenen :root-Variablen, taugt aber weiterhin als Namensraum.
README auf den tatsaechlichen Projektstand gebracht - er beschrieb noch die
Dioxus-Vorlage mit einer einzelnen main.rs.
2026-08-28 09:19:36 +02:00
11 changed files with 48 additions and 1867 deletions
Your new bare-bones project includes minimal organization with a single `main.rs` file and a few assets.
Lokale Markdown-Notizen-App auf Basis von [Dioxus 0.7](https://dioxuslabs.com/learn/0.7), Desktop.
```
project/
├─ assets/ # Any assets that are used by the app should be placed here
├─ src/
│ ├─ main.rs # main.rs is the entry point to your application and currently contains all components for the app
├─ Cargo.toml # The Cargo.toml file defines the dependencies and feature flags for your project
```
### Automatic Tailwind (Dioxus 0.7+)
As of Dioxus 0.7, there no longer is a need to manually install tailwind. Simply `dx serve` and you're good to go!
Automatic tailwind is supported by checking for a file called `tailwind.css` in your app's manifest directory (next to Cargo.toml). To customize the file, use the dioxus.toml:
```toml
[application]
tailwind_input="my.css"
tailwind_output="assets/out.css"# also customize the location of the out file!
```
### Tailwind Manual Install
To use tailwind plugins or manually customize tailwind, you can can install the Tailwind CLI and use it directly.
| **Joplin** (Note History) | Tabelle `revisions` in `database.sqlite` | Diff-Kette (`diff-match-patch`, JSON) | 10 Min | 90 Tage (Default) | **Nein** — es gibt gar keine `.md` |
| **Logseq** (0.10.9) | `logseq/bak/<datei>/`**im** Graph-Ordner | Volltext-Kopien, Zeitstempel im Namen | **nur bei Konflikt oder Schreibfehler**, nicht bei jedem Speichern | 6 Fassungen pro Datei | **Ja** |
| **Zettlr** | — es gibt keine | — | — | — | — |
| **Syncthing** (kein Editor, aber das beste Vorbild) | `.stversions/`**im** Sync-Ordner | Volltext-Kopien mit Zeitstempel im Namen | pro Änderung | konfigurierbar, logarithmisch ausgedünnt | **Ja** |
**Das auffälligste Muster:** Von den untersuchten Editoren legt **keiner** seine Historie neben die
Notizdateien. Sie liegt entweder im App-Ordner (Obsidian), in einer Datenbank (Joplin) oder auf einem Server
(Obsidian Sync). Wer neben den `.md` versioniert, ist ein Sync-Werkzeug, kein Editor.
### 2.1 Obsidian — Historie als aufgesetztes Core-Plugin, komplett außerhalb des Vault
Obsidian ist der direkteste Vergleichspunkt: lose `.md`-Dateien in einem Ordner, dasselbe Versprechen an den
Nutzer, dieselbe Ausgangslage.
**Belegt** (Zitate aus der offiziellen Help-Seite <https://obsidian.md/help/plugins/file-recovery>):
- „File recovery is a core plugin that protects your work from accidental deletions, file corruption, or
unwanted changes by automatically saving **complete snapshots** of your notes at regular intervals."
- „**Snapshots capture the full content of your files, not just changes**, allowing you to restore any
previous version." — also **Volltext, keine Diffs.**
- „**By default, snapshots are saved a minimum of 5 minutes from each other, and kept for 7 days.**"
- „**Snapshots are kept in the Global settings, outside of the vault**, to account for vault-related data
loss. This means that **snapshots are stored with the absolute path to the note**. If you've moved your
vault recently, you may need to move it back to the location where it was when the snapshot was taken."
- „If you are using Obsidian Sync or other syncing services, **File recovery snapshots will not sync between
devices. Snapshots are device-specific and remain local to each device.**"
- „File recovery is **not a complete backup solution**."
- Nur `.md` und `.canvas` sind wiederherstellbar.
- Aufräumen automatisch nach Ablauf der Tagesgrenze, manuell über *Clear history*.
Der Ablageort ist damit belegt als der Electron-userData-Ordner der App —
**Windows: `%APPDATA%\Obsidian\`** (<https://obsidian.md/help/data-storage>), **nicht**`.obsidian/` im Vault
und **nicht** neben den Notizen.
**Vermutung (starkes Indiz, nicht wörtlich belegt):** Die Snapshots liegen in Obsidians IndexedDB/LevelDB.
Die Doku nennt bei IndexedDB nur Sync-State und Metadata-Cache, führt aber für File recovery **dieselbe**
Apple-Lockdown-Mode-Einschränkung auf wie für IndexedDB. Ein Serialisierungsformat ist nirgends dokumentiert;
Obsidian ist Closed Source.
**Widerspruch in der Doku selbst, den man kennen sollte:** Der Abschnitt „Storage and performance" derselben
Seite behauptet, Snapshots „only store changed files", während der Haupttext „full content […] not just
changes" sagt. Plausible Auflösung (**Vermutung**): Nur *geänderte Dateien* werden überhaupt gesnapshottet,
jede davon aber als Volltext.
**Zum Schreibverfahren:** Es gibt **keine offizielle Aussage**, ob Obsidian atomar (temp+rename) oder
in-place schreibt. Belegt ist nur die Plugin-API-Semantik: `Vault.process` ist dokumentiert als „**Atomically
read, modify, and save the contents of a note**" und garantiert, „that the file doesn't change between
reading the current content and writing the updated content"
(<https://docs.obsidian.md/Plugins/Vault>). Das ist eine **Sperre gegen konkurrierende Plugins innerhalb des
Obsidian-Prozesses**, keine dokumentierte Aussage über `rename()`-Atomarität gegenüber dem Dateisystem —
diese Unterscheidung macht die Doku nirgends explizit (**Lesart, nicht wörtlich belegt**). Der Changelog zu
1.13.4 (30.07.2026) enthält den Eintrag „Fixed a rare race condition where a file could get stuck and fail to
save until the app was restarted" (<https://obsidian.md/changelog/2026-07-30-desktop-v1.13.4/>) — ein Beleg
dafür, dass der Save-Pfad auch nach über zehn Jahren nicht trivial ist.
**Warum das für #22 der wichtigste Befund ist:** Obsidians Historie ist ein **nachträglich aufgesetztes
Plugin, das mit dem Schreibverfahren des Kerns nichts zu tun hat**. Es beobachtet Dateien und legt Kopien
woanders ab. Genau das ist das „Historie ist eine Schicht *über* dem Schreiben"-Modell — von dem am längsten
etablierten Werkzeug dieser Kategorie in Produktion vorgeführt.
**Der Preis, den Obsidian für diesen Ort zahlt** (alles wörtlich aus der Doku oben): absolute Pfade, die nach
einem Vault-Umzug brechen; keine Mitnahme beim Backup; kein Sync zwischen Geräten. Ein Mittelweg —
Historie in einem versteckten Ordner *im* Vault — hat von den untersuchten Werkzeugen keiner gewählt; für
Obsidian existiert dazu ein offener Feature-Request
| Eine Sicherungskopie (4.1) | 1 pro gespeicherter Notiz | keins | entfällt | keine | nein |
| Zeitstempel-Ordner (4.2) | N pro Notiz, ausgedünnt | beschränkt | Ausdünn-Regel, ~1 Funktion | keine | nein |
| Git im Workspace (4.3) | `.git/`, ≥3 Objekte pro Commit | unbeschränkt | `git gc`, teuer | `gix` oder `git2` | nein |
| Append-Log (Abschnitt 3) | 1 Log pro Notiz | **≈ 70× Rohtext** ungekürzt, ≈ 1,2–1,5× gemerged | **von den Bibliotheken nicht vorgesehen** (Automerge: Dokument neu anlegen; Yjs: Tombstones bleiben) | CRDT-/Log-Bibliothek | **ja** — die `.md` wird zur Kopie |
---
## 5. Die eigentliche Frage: Schließt temp+rename eine spätere Historie aus?
**Nein.** Die Begründung in vier Schritten.
### 5.1 Das Schreibverfahren ist für Historie günstig, nicht hinderlich
Wie in Abschnitt 1 hergeleitet: Historie braucht Auslöser und Vorfassung. Beim temp+rename-Verfahren ist die
Vorfassung im Moment vor dem Umbenennen noch vollständig auf der Platte. Der Einbau einer Historie wäre eine
Einfügung von wenigen Zeilen **an einer Stelle**, an der man ohnehin schon steht:
```
schreibe_notiz(pfad, inhalt):
prüfe Konflikt (aus #20)
── hier ließe sich später die Vorfassung wegsichern ──
schreibe inhalt nach pfad.tmp
sync
benenne pfad.tmp nach pfad um
```
Das Gegenteil gilt für den naiven Weg: `fs::write(pfad, inhalt)` zerstört die Vorfassung, bevor irgendjemand
sie sichern könnte. Wer dort Historie nachrüstet, muss die Datei zusätzlich vorher lesen. Das ist immer noch
billig — aber es ist der **teurere** der beiden Wege, und er ist zugleich der, den #19 aus Gründen der
Absturzsicherheit ohnehin ausschließen will.
**Damit ist der Einwand in seiner konkreten Form widerlegt**: Die Entscheidung, die #19 zu treffen hat, macht
Historie nicht teurer. Sie macht sie billiger.
### 5.2 Was Historie *tatsächlich* teuer machen würde
Damit das Ergebnis belastbar ist, hier die Gegenprobe — die Entscheidungen, die den Einwand berechtigt machen
würden. Keine davon ist die Wahl zwischen `rename` und `write`:
| Falle | Warum sie teuer wird | Kosten sie zu vermeiden |
|---|---|---|
| **Mehrere Schreibstellen.** Autosave schreibt hier, „Notiz verlassen" dort, „Fenster schließen" an dritter Stelle. | Historie muss an jeder Stelle nachgezogen werden, und jede vergessene Stelle ist ein Loch in der Historie, das man erst durch einen Bug bemerkt. | **Eine** Funktion, die schreibt. Alle Auslöser aus [#18](https://gitlab.hive-brain.de/RDietermann/dionotes-client/issues/18) rufen dieselbe. Kostet heute nichts. |
| **Kein Notiz-Begriff, nur Pfade.** | Historie, die am Pfad hängt, reißt beim Umbenennen ab ([#23](https://gitlab.hive-brain.de/RDietermann/dionotes-client/issues/23)). Obsidian hat genau dieses Problem, dokumentiert („snapshots are stored with the absolute path to the note"). | Entweder akzeptieren (Obsidian tut es) oder später eine stabile ID einführen. Beides nachrüstbar; die Kette bräche dann nur für Umbenennungen *vor* der Einführung. |
| **Umbenennen als Löschen+Neuanlegen implementiert.** | Zerreißt jede Historie und erzeugt Waisen im Ablageort. | Umbenennen als Umbenennen implementieren. Ist in #23 ohnehin die naheliegende Wahl. |
| **Der Log-Ansatz aus dem Vorschlag.** | Siehe Abschnitt 3 — er ist die einzige der hier betrachteten Optionen, die schwer umkehrbar ist. | Ihn nicht bauen. |
**Nur die erste Zeile ist eine echte Auflage an #19** — und sie kostet heute exakt nichts, weil es aktuell
noch **überhaupt keine Schreibstelle im Code gibt** (verifiziert: keine Fundstelle für `fs::`/`write`/`File::`
unter `src/`; der Editor nimmt Eingaben entgegen und verwirft sie, so beschrieben in
Der Vorschlag aus der Beratungsrunde begründet sich damit, dass die Schreib-Entscheidung schwer umkehrbar sei.
Prüft man beide Richtungen, ergibt sich das Gegenteil:
| Richtung | Aufwand |
|---|---|
| „Datei ist die Wahrheit" → „Datei plus Sicherungen" | **Ergänzung.** Eine Funktion erweitern, ein Ordner, eine Aufräumregel. Bestehende Notizen funktionieren unverändert weiter, die Historie beginnt eben ab Einführung. Kein Datenmigrations-Schritt, kein Bruch für den Nutzer. |
| „Log ist die Wahrheit" → „Datei ist die Wahrheit" | **Migration.** Jede Notiz aus dem Log materialisieren, die Logs entfernen oder verwaisen lassen, die gesamte gesammelte Historie wegwerfen oder in ein neues Format überführen — und den Nutzern erklären, warum ihre Historie weg ist. |
Wer sich die Option offenhalten will, hält sie also gerade dadurch offen, dass er den Log **nicht** baut. Der
Log ist die Einbahnstraße, nicht das schlichte Schreiben.
Obsidian ist der empirische Beleg: Das Werkzeug wurde 2020 veröffentlicht, hat von Anfang an lose `.md`-Dateien
geschrieben, und File recovery kam später als Core-Plugin obendrauf — vollständig außerhalb des Vault, ohne
das Dateiformat oder das Schreibverfahren anzufassen (**belegt** durch den Aufbau des Plugins, s. 2.1;
das genaue Erscheinungsdatum des Plugins ist **nicht belegt**).
### 5.4 Belastbarkeit dieser Antwort
Die Antwort steht auf zwei Beinen unterschiedlicher Härte:
- **Hart (belegt):** Obsidian betreibt eine produktive Historie für lose `.md`-Dateien als aufgesetzte
Schicht, die vom Schreibverfahren des Kerns entkoppelt ist und außerhalb des Datenordners lebt. Ein
Werkzeug mit derselben Ausgangslage wie DioNotes hat das Problem also nachweislich nachträglich gelöst.
- **Weich (Argumentation, nicht durch Quelle belegt):** Dass genau *eine* Schreibstelle die einzige
load-bearing Auflage ist, ist eine Schlussfolgerung aus der Zerlegung in Abschnitt 1, kein Zitat. Sie ist
aber schwer zu bestreiten: Eine Schicht über N Aufrufstellen einzuziehen kostet N Änderungen, über einer
Aufrufstelle eine.
**Fazit für #19: Der Einwand ist entkräftet. Die Schreib-Entscheidung darf allein nach den Kriterien aus #19
fallen — Absturzsicherheit, Sichtbarkeit der temporären Datei, Dateirechte, Aufräumen. Historie legt ihr
genau eine Auflage auf, und die ist heute gratis: eine einzige Funktion, durch die alles Schreiben läuft.**
---
## 6. Randbefunde für die Nachbartickets
Bei der Recherche fielen Belege an, die #22 nicht beantworten, aber #19 und #20 direkt betreffen. Sie stehen
hier, damit sie nicht verlorengehen — **nicht** als Entscheidung.
| Obsidian: Snapshots liegen konkret in IndexedDB/LevelDB | **Vermutung** — starkes Indiz über die Lockdown-Mode-Einschränkung, kein wörtlicher Beleg |
| Ausgedünnte Zeitstempel-Historie ≈ 50–100 Fassungen pro Notiz nach einem Jahr | **Abschätzung**, nicht belegt |
| „Historie ist eine Schicht über dem Schreiben" | **Belegt am Beispiel Obsidian**, im Übrigen **Argumentation** |
| „Eine Schreibstelle ist die einzige echte Auflage" | **Argumentation**, nicht durch Quelle belegt — aber aus der Zerlegung in Abschnitt 1 zwingend |
| Zwei-Wahrheiten-Problem des Append-Logs | **Argumentation** aus den Projekt-Rahmenbedingungen (kein Filewatcher, externer Sync erwartet) |
| CRDT-Dokument **gemerged** ≈ 1,2–1,5× Rohtext; **Summe der Einzel-Updates ≈ 70× Rohtext** (B4-Trace) | **Belegt** (dmonad/crdt-benchmarks, Repo des Yjs-Autors) |
| Automerge: „Discarding the history is not currently possible without replacing the document" | **Belegt** (Maintainer-Zitat, Issue #799) |
| Automerge: shallow clone / history truncation seit 2023 angekündigt, bis heute nicht implementiert | **Belegt** (Blogpost + Issue-Verlauf + API-Oberfläche) |
| Yjs: Tombstones sind konstruktionsbedingt nicht sammelbar, Update-Merge räumt nicht auf | **Belegt** (README, `Item.js`, docs.yjs.dev) |
| Automerge-Cookbook: „The savings are not all that great" (Gegenargument) | **Belegt** — gilt für Kleppmanns Messfall (großes Dokument, wenige Actor-IDs) |
| Ob die Ökonomie beim Notiz-Profil (viele kleine Dokumente, viele Sitzungen) kippt | **Nicht belegt** — die 70×-Zahl legt es nahe, ist aber am B4-Trace gemessen |
| Obsidian Sync: „Files on-demand"-Platzhalter werden als gelöscht interpretiert | **Belegt** (help.obsidian.md) |
| Apple TN3150: Existenzprüfung/Verzeichnis-Enumeration kann Materialisierung und Watchdog-Crash auslösen | **Belegt** — Übertragung auf OneDrive Files On-Demand unter Windows ist **Vermutung** |
| Dass die bloße Verdopplung der Dateizahl in Sync-Ordnern schadet | **Nicht belegt** — die 300.000er-Limits sprechen eher dagegen |
- Automerge Cookbook, „Modeling Data → Performance" (Kleppmann: „The savings are not all that great"): <https://automerge.org/docs/cookbook/modeling-data/>
- Automerge `hexane` Storage-Engine (Kompression, keine Truncation): <https://automerge.org/blog/2026-july/>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.