Repository navigation
Fuer Entwickler
| Pfad | Inhalt |
|---|---|
crates/lotse-core |
Der Kern: Modell, Krypto, Tresor, Speicher (SQLCipher), Sync-Umschläge, Erkennung, Git-Reader, Gegenseite, Kalender, Dateiauszug, KI-Ziel, MCP, Export. |
crates/lotse-cli |
Binary lotse. |
apps/web |
Svelte 5 + Vite. Läuft in Tauri und im Browser. |
apps/desktop |
Tauri-2-Hülle. Braucht GTK/WebKit zum Bauen, wird nur in release.yml gebaut. |
services/sync-worker |
Cloudflare Worker (TypeScript) + D1 + R2. |
site |
Landing Page: eine HTML-Datei, inline CSS/JS, keine Fremdressourcen. |
docs/wiki |
Dieses Wiki. Wird von wiki.yml ins GitHub-Wiki gespiegelt. |
lotse-core ← alles Fachliche, keine Oberfläche
↑ ↑
lotse-cli apps/desktop (Tauri)
↑
apps/web (Svelte)
apps/web/src/lib/data/provider.ts ist die Schnittstelle zwischen Oberfläche und
Daten. Es gibt zwei Umsetzungen: tauri.ts spricht den Kern, mock.ts liefert
Beispieldaten im Browser. Zeitstempel werden ausschließlich in tauri.ts von
Millisekunden zu ISO umgerechnet – eine Stelle, nicht zwanzig.
Die Kommandos in apps/desktop/src-tauri/src/lib.rs spiegeln provider.ts. Wer dort
etwas hinzufügt, fügt es an beiden Stellen hinzu.
lotse-core baut mit dem Feature native (Standard) alles mit Dateisystem und Netz.
Ohne das Feature bleibt der Kern WebAssembly-tauglich – Modell, Krypto und
Sync-Umschläge.
Deshalb steht in der Prüfliste:
cargo check -p lotse-core --no-default-features --target wasm32-unknown-unknownDie Anbindung an den Browser. Sie enthält keine Logik: jede Funktion ist ein Adapter
von JS-Werten auf einen Aufruf im Kern und zurück. Schlüssel sind undurchsichtige Griffe
(Passwortschluessel, Kontoschluessel) ohne Auslesefunktion – einzige Ausnahme ist der
auth_key, der per Konstruktion zum Dienst geht.
scripts/wasm-bauen.sh # braucht wasm-bindgen in der Fassung aus Cargo.lock
cd apps/web && node scripts/wasm-browsertest.mjs # derselbe Vektor, echter Browser
cd apps/web && node scripts/wasm-mengentest.mjs 500000 # was ein Browser aushältDas Ergebnis landet in apps/web/src/lib/wasm/ und ist Bauergebnis, nicht Quelltext.
Der Browsertest startet einen kleinen http-Server aus der Node-Standardbibliothek und ein
Chromium im Kopflosmodus – kein Playwright, damit kein Browsertreiber als
Abhängigkeit mitkommt. Pfad notfalls über LOTSE_BROWSER setzen.
apps/web/scripts/wasm-mengentest.mjs erzeugt sich seinen Bestand selbst – dieselbe
Versiegelung, beliebig viele Notizen – und misst Versiegeln, Öffnen, Umschlaggröße und
Speicherverbrauch. Kein echter Bestand, also wiederholbar und nach oben skalierbar; die
Zahlen tragen die Entscheidungen in docs/WEB_CLIENT.md Abschnitt 4a.
In CI läuft er mit 2 000 Sätzen, damit der Weg nicht verrottet und der Umschlag-Aufschlag
nicht unbemerkt wegläuft. Die großen Läufe sind Handarbeit. LOTSE_HEAP_MB engt das
Speicherbudget ein – mit der Einschränkung, dass V8 sich nicht zuverlässig daran hält.
Beide Browserläufe teilen scripts/browserlauf.mjs: http-Server aus der
Node-Standardbibliothek, Chromium im Kopflosmodus, Ergebnis per POST.
Er hat sich bezahlt: dabei kam heraus, dass suche_ersetzen den alten Suchindex-Eintrag
über kind und ref_id löschte. Beide Spalten sind in FTS5 UNINDEXED – es gibt keinen
Index darauf, also lief SQLite bei jeder geschriebenen Notiz die ganze Suchtabelle ab.
Gemessen 307 µs je Satz bei 2 000 Einträgen und 5 308 µs bei 16 000, ohne das Löschen
konstant 4 µs. Behoben in Schema-Migration 2 (Abbildung (kind, ref_id) → rowid).
Zwei Dinge daran sind zum Merken: im Abfrageplan steht bei FTS5 immer »SCAN«, auch beim
direkten Zugriff – der Unterschied steckt hinter INDEX 0: (leer = Durchlauf, = = rowid).
Und der Wächter dafür (store::tests::suchindex_loescht_ueber_die_rowid_ohne_durchlauf)
schreibt mit, welches SQL der Store wirklich ausführt, statt einen Abfrageplan zu prüfen,
den der Test selbst formuliert. Die erste Fassung tat Letzteres und blieb grün, als der
Fehler zur Gegenprobe wieder eingebaut wurde.
tests/vektoren/kdf.json hält die Schlüsselableitung mit festen Werten fest, gelesen von
zwei Seiten: crates/lotse-core/tests/kdf_vektoren.rs und dem Browsertest. Ein Rundlauf
allein würde nur beweisen, dass der Code mit sich selbst übereinstimmt – er bliebe auch
nach einer versehentlichen Änderung der Schlüsselhierarchie grün, und dann wäre jedes
bestehende Konto ausgesperrt.
# Kern und CLI
cargo build --release -p lotse-cli
# Oberfläche
cd apps/web && npm ci && npm run dev # läuft im Browser mit Beispieldaten
# Desktop (braucht GTK/WebKit unter Linux)
cd apps/desktop && npm ci && npm run tauri devUnter Ubuntu für die Hülle:
sudo apt-get install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev \
librsvg2-dev patchelf libssl-dev pkg-configDas ist die verbindliche Liste aus CLAUDE.md:
scripts/modulgrenzen.sh
scripts/wiki_pruefen.sh
cargo deny check
cargo deny --manifest-path apps/desktop/src-tauri/Cargo.toml check
cargo fmt --all && cargo clippy --workspace --all-targets -- -D warnings && cargo test --workspace
scripts/sync-e2e.sh
cargo check -p lotse-core --no-default-features --target wasm32-unknown-unknown
cargo clippy -p lotse-wasm --target wasm32-unknown-unknown -- -D warnings
scripts/wasm-bauen.sh && (cd apps/web && node scripts/wasm-browsertest.mjs)
(cd apps/web && node scripts/wasm-mengentest.mjs 2000)
(cd apps/web && npm run check && npm test && npm run build)
(cd services/sync-worker && npm run typecheck && npm test)Es prüft, dass bestimmte Module keinen Zugriffsweg zum Tresor haben. Das ist die wichtigste Regel im Projekt, und sie ist mechanisch geprüft statt nur verabredet:
ai · detect · dokument · export::spiegel · forge · git · kalender ·
mcp · netz · update · watcher
Das Skript folgt einem Modul auch in einen Unterordner und liest eingebettete Module per
Klammerzählung (export::bundle in derselben Datei darf den Tresor sehen,
export::spiegel nicht). Verschwindet ein Name aus der Liste, schlägt es an – sonst
verschwände die Regel unbemerkt mit ihm.
-
Keine eigenen Krypto-Primitive. Nur RustCrypto,
age,zeroize. Änderungen an der Komposition erhöhenFORMAT_VERSIONund werden inTHREAT_MODEL.mdprotokolliert. -
Schlüssel sind
Key32(überschreiben beim Wegwerfen). Kein Schlüssel alsVec<u8>oderString. -
Alles Netz geht über
netz.rs– ein Agent, eine Fehlerübersetzung. -
Keine Fremdskripte, CDNs, Fonts oder Analytics in
apps/webundsite. Kein{@html}für Nutzertext. - Der Sync-Dienst loggt nie Bodies oder Tokens.
-
site/index.htmlbehauptet nur, was im Kern läuft und getestet ist.
-
Feldnamen im Modell sind deutsch und entsprechen
CONCEPT.mdAbschnitt 3. Sync-Umschläge und API-Feldnamen sind englisch (SYNC_PROTOCOL.md). - Zeitstempel sind Unix-Millisekunden (
i64), DatumsangabenJJJJ-MM-TT. - Nutzertexte auf Deutsch; nur die fünf Metaphern Hafen, Kurs, Logbuch, vor Anker, Hafeneinfahrt.
- Neue Features müssen den Aufnahmetest in
NON_GOALS.mdbestehen. - Die Lizenz ist AGPL-3.0-only (
LICENSE) – keine Lizenz-Header in einzelne Dateien einfügen. Sie steht einmal im Repo und in den Cargo-Manifesten.
- Version an fünf Stellen erhöhen:
Cargo.toml,apps/desktop/src-tauri/Cargo.toml,apps/desktop/src-tauri/tauri.conf.json,apps/web/package.json,apps/desktop/package.json. - Lockfiles nachziehen:
cargo update -w --offline(auch inapps/desktop/src-tauri). - Commit „Version X.Y.Z“, nach
main. - Actions → Release → Run workflow mit dem Tag
vX.Y.Z. Der Workflow legt den Tag selbst an.
Der Workflow prüft zuerst, ob der Update-Schlüssel hinterlegt ist und ob in
tauri.conf.json ein echter öffentlicher Schlüssel steht. Fehlt eines, bricht er ab –
ein Release ohne Signatur wäre eine Sackgasse, weil der Updater es abweisen würde.
Danach spiegelt ein Job die fertige latest.json nach site/, von wo GitHub Pages sie
ausliefert. Siehe Updates.
Der Text liegt in docs/wiki/ im Hauptrepository, eine Markdown-Datei je Seite.
.github/workflows/wiki.yml schreibt sie ins GitHub-Wiki, sobald auf main etwas darunter
geändert wird. Änderungen im Browser werden dabei überschrieben.
scripts/wiki_pruefen.sh
liest die tatsächliche Oberfläche aus dem Quelltext – Kommandobaum, Tauri-Kommandos,
MCP-Werkzeuge, Modellfelder, Fehlertexte, Einstellungsschlüssel, LOTSE_*-Variablen,
Sync-Endpunkte, Erkennungsmarken – und verlangt, dass jedes Stück davon im Wiki vorkommt.
Sie läuft in CI. Wer ein Feld hinzufügt und das Wiki nicht anfasst, bekommt eine rote CI.
Vollständig: Wiki pflegen.
Issues und Pull Requests sind willkommen. Zwei Bitten:
-
Lies
NON_GOALS.mdzuerst. Ein Feature, das den Aufnahmetest nicht besteht, wird abgelehnt – auch wenn es gut gebaut ist. - Die Prüfliste muss grün sein. CI prüft dasselbe, aber lokal geht es schneller.
Die Lizenz ist AGPL-3.0-only. Beiträge sind willkommen, brauchen aber ein DCO
(Signed-off-by: in der Commit-Nachricht) – ohne das wäre der kommerzielle Doppelvertrieb
dahin, auf dem das Geschäftsmodell beruht (BUSINESS.md 3). Bei größeren Änderungen vorher
ein Issue, damit niemand umsonst arbeitet.
Lotse auf GitHub · Landing Page · Veröffentlichungen
Erzeugt aus docs/wiki/ – Änderungen bitte dort.
Anfangen
Die Bausteine
Benutzen
- Kommandozeile
- Einstellungen
- Abgleich
- Beobachter
- Gegenseite
- Kalender
- KI
- Datei deuten
- Assistenten (MCP)
- Updates
- Export
Nachschlagen
- Kommandozeile-Referenz
- Datenmodell
- Erkennungsregeln
- Datenablage
- Umgebungsvariablen
- Fehlermeldungen
- Sync-Protokoll
- App-Schnittstelle
Verstehen
Mitarbeiten