Secretary

Docs
Login

Docs

secretary-contract

Gemeinsamer Vertrag für die Secretary-Produktfamilie. Jedes Produkt hat ein eigenes SRS-Verzeichnis; die Software Requirements Specifications sind die maßgeblichen Spezifikationen.

Zweck

secretary-contract definiert das verbindliche, plattformunabhängige Produktverhalten für alle Secretary-Produkte und ihre Clients:

Verzeichnis Produkt Clients SRS-Version
— (noch ohne eigenes SRS) Kalender (CalDAV VEVENT, /calendars/calendar-*) secretary-calendar-android (vc 101) —
— (noch ohne eigenes SRS) Kontakte (CardDAV vCard, /addressbooks/contacts-*) secretary-contacts-android (vc 70) —
notes/ Notizen (CalDAV VJOURNAL) secretary-notes-android (vc 53), secretary-notes-gtk (0.8.0) 1.0.0
tasks/ Aufgaben mit Wiederholungen (CalDAV VTODO) secretary-tasks-android (vc 59), secretary-tasks-gtk (0.1.0) 1.0.0
secrets/ Passwort-/Schlüssel-Tresor (top-level secrets/-Root, Gruppen = Collections, 1 Datei pro Eintrag, Feld-Level-Sync/Merge, nur geschützte Felder verschlüsselt, Master Key gewrappt auf Geräten + Recovery-Kopie auf dem Server, KDBX Import/Export/Merge, volle Historie) secretary-secrets-android, secretary-secrets-gtk 1.0.0 (DRAFT-Überarbeitung)
journal/ Gesundheitstagebuch (CalDAV VJOURNAL, lokal + Server) secretary-journal-android (vc 144) 1.9.0
— (SRS im Wiki SRS/links) Links (CalDAV-Website-Änderungsmonitor, VJOURNAL in /links/, Ordner als Tags) secretary-links-android (vc 38) 1.0.0
common/ Gemeinsame Plattform-Schicht (Konto, CalDAV-Client, Codecs, Offline-Store, Sync-Engine) secretary-common-android (v0.31.0), secretary-common-gtk (0.3.0) 1.4.0
— (noch ohne eigenes SRS) Launcher (Android Home-Screen-Alternative: App-Liste, Home-Apps als Name/Symbol mit Ausrichtung links/mittig/rechts, verschiebbare Uhr und App-Slots als Block, Drawer mit unscharfem Desktop-Wallpaper, Konfiguration als CalDAV VJOURNAL in /launcher/) secretary-launcher-android (vc 467) —
— (noch ohne eigenes SRS) News (Artiger RSS/Atom-Leser im Stil von The Old Reader: der Server holt die Feeds ab, die App liest/filtert/verwaltet, zwei feste Collections in /news/) secretary-news-android (vc 2), secretary-server-news (Server-Fetcher, 0.26.0, Paket ab 0.28.0) —

Alle Produkte speichern ihre Daten als CalDAV-Ressourcen auf dem secretary-server. Seit server 0.16.0 nutzen Notizen/Aufgaben/Journal/Links eigene top-level Namespace-Roots (/notes/, /tasks/, /journal/, /links/, unpräfixierte Collections); Kalender (/calendars/calendar-*), Kontakte (/addressbooks/contacts-*) und Secrets (/secrets/) bleiben wie bisher. Seit server 0.20.0 kommt der Root /launcher/ für die Konfiguration des Android-Launchers dazu: eine VJOURNAL-Collection, die dieselben secretary-Konto- und CalDAV-Wege nutzt wie die übrigen Apps, aber keine Nutzdaten, sondern nur Einstellungen. Seit server 0.26.0 liefert der Root /news/ die zwei VJOURNAL- Collections subscriptions und articles, die der Fetcher secretary-server-news befüllt.

Status 2026-10-08 (39: Sammlungs-Nutzung im Kontextmenü durchgesetzt)

Nachtrag zum v38-Release: die gemeinsame Sammlungs-Nutzung greift jetzt auch dort, wo v38 sie nur in Links umgesetzt hatte. Verschieben in Sammlung… (showMove) in den Kontextmenüs von Kalender, Kontakten, Journal, Notizen und Tasks hängt am Schalter (SRS common FR-C-63; Kalender liefert true, dort also ohne Wirkung), und der Leerzustand von Tasks bot Sammlungen weiterhin bedingungslos an — beide wurden in v38 nur in Links umgesetzt. Damit sind FR-C-60..65 in allen Clients durchgesetzt; SRS common ist auf 1.5.0. Keine Server-Änderung. VersionCodes: Kalender 102, Kontakte 71, Journal 145, Launcher 468, Links 39, News 3, Notes 54, Secrets 73, Tasks 60. 964 Tests grün; APKs gebaut und nach tremere geliefert.

Alle neun Android-Clients sind hochgezogen, die gemeinsame Einstellung „Sammlungs-Nutzung“ ist ausgeliefert (SRS common 1.4.0) und Links hat sein erstes SRS bekommen.

versionCodes: calendar 101, contacts 70, journal 144, launcher 467, links 38, news 2, notes 53, secrets 72, tasks 59. Der neue Schalter (Default außerhalb des Kalenders false) steuert die Kopfzeilen-Sammlungs-Schaltfläche, die Leerzustands-Aktion und bei Links Verschieben in Sammlung… (FR-C-60..65); die Collections-Liste bleibt vollständig, das Umschalten braucht keinen Neustart, Ordner aus Tags sind nicht betroffen. Links 38 selbst bringt den Tags-als-Ordner-Rund-Trip (TAG: in CATEGORIES, erste Tag = Ordner, Gruppierung in der Liste, In Ordner verschieben…), die Layout-Erkennung NEW/LEGACY (404/405 auf /links/ ⇒ links- unter /calendars/), die erzwungene kanonische Sammlung main und die beiden Benachrichtigungskanäle link_checks („Link geprüft“ pro Auftritt) und link_changes (aggregierte „N Links geändert“-Zusammenfassung).

Neu im Wiki: SRS/links (1.0.0); SRS/common auf 1.4.0 (§4.7 Collections Usage Setting); SRS/notes und SRS/tasks nennen die Sektion in ihren Settings-Abschnitten. Tests: 964 grün (Kalender 55, common 100, Kontakte 44, Launcher 24, Links 8, Secrets 687, Tasks 46), inklusive der neuen LinkTagsTest (8).

Wiki-Aufräumzug: alle migrierten Seiten stehen jetzt auf text/x-markdown (fossil hatte sie als Rohtext ausgeliefert), tote Links (../secretary-server/, Apps/Docs, ein verkettetes [](0x42)) sind über alle 40 Seiten korrigiert; die lokalen CONTEXT.md enthalten den Export/Import-Ablauf (fossil wiki export → … commit -M text/x-markdown → fossil sync) und sind auf 0444 gesetzt.

secretary-server-links markiert defekte Links auf der Ressource, statt den Lauf fehlschlagen zu lassen (server 0.31.0). Ein fehlgeschlagener Abruf (Verbindungsfehler, Timeout, HTTP != 2xx, Lesefehler des Bodys) schreibt X-LINK-LAST-ERROR:<Meldung> in die DESCRIPTION des betroffenen VJOURNALs (einzeilig, höchstens 300 Zeichen, analog zu X-NEWS-LAST-ERROR) und zählt im Summary als „defekt". Der Prozess beendet mit Status 0 — der vom Server gestartete Addon-Lauf meldet nicht mehr „Lauf fehlgeschlagen". Status 1 bleibt Lauf-Fehlern vorbehalten (Config, Storage, kaputtes ICS, leere X-LINK-URL, Lesen/Schreiben). Nach einem erfolgreichen Abruf wird der Wert geleert (X-LINK-LAST-ERROR: leer = defektfrei); geschrieben wird nur bei geänderter Meldung oder touch_last_checked, damit ruhige Läufe den Sync-Token des Links nicht anstoßen. Für Clients ändert sich am Sync nichts — X-LINK-LAST-ERROR liegt wie die übrigen X-LINK-*-Properties in der DESCRIPTION.

Status 2026-10-08 (Server 0.30.0: Addons mit interval, ein Paket)

Die beiden serverseitigen Helfer heißen jetzt secretary-server-links ( Link-Checker ) und secretary-server-news ( Feed-Fetcher ), und der Server bringt sie in einem einzigen Paket mit. Verzeichnisse server/secretary-server-links/ und server/secretary-server-news/, Cargo-Pakete und Binärnamen tragen jetzt den Namen des Quellenpakets secretary-server. Alle drei Komponenten werden als ein Debian-Paket secretary-server gebaut; die alten Pakete secretary-check-links und secretary-news entfernt das Upgrade über Conflicts.

Die Addons haben kein eigenes systemd-Unit mehr. Nur secretary-server läuft als User-Service; er startet secretary-server-links und secretary-server-news selbst im selben User-Kontext. Gesteuert wird das über die Config-Sektionen [links]/[news] mit active (Default: false = aus) und interval im humantime-Format (Default: "30m" bzw. "15m", erster Lauf sofort); der Server ruft das Addon jeweils im Abstand interval auf. Die alten Timer (secretary-server-links.timer, secretary-server-news.timer) entfallen. Konfigurations-Sektionen, Property-Namen (X-LINK-*, X-NEWS-*) und Storage-Layout bleiben ansonsten unverändert; für die Android-Clients ändert sich nichts. App secretary-news-android und Modul android/news/ sind nicht betroffen.

Upgrade ab 0.30.0: Das Aktualisieren des Pakets allein startet die Addons nicht — active ist per Default false. Damit die Helfer weiterlaufen, nach dem Upgrade [links]/[news] mit active = true (und optional interval) in ~/.config/secretary-server/secretary-server.toml setzen, alte Timer (systemctl --user disable --now secretary-check-links.timer secretary-news.timer) entfernen und systemctl --user restart secretary-server ausführen. Eine Daten-/Storage-Migration ist nicht nötig. secretary-server.postinst gibt diese Schritte beim Upgrade aus.

Status 2026-10-07 (News: neuer Client + server 0.26.0 mit Feed-Fetcher)

secretary-server-news (server 0.26.0, Paket ab 0.28.0) + secretary-news-android (vc 2): der neunte Client ist ein News-Reader im Stil von The Old Reader. Die Arbeit teilt sich wie beim Link-Checker in einen serverseitigen Fetcher und einen Android-Client; beide Seiten sind fertig.

Status 2026-10-02 (Launcher 466: Ausrichtung der Home-Slots, unscharfes Wallpaper im Drawer)

secretary-launcher-android (vc 466): die Ausrichtungs-Einstellung der Home-Slots wirkt wieder, und der Drawer zeigt das Desktop-Wallpaper unscharf. 465 hatte die Position der Slot-Spalte ueber Modifier.align auf das Widget selbst gelegt; sobald das Widget vollbreit ist (Slots mit gleichem Aussehen), sind CenterStart/Center/CenterEnd pixelgleich und die Namen blieben zentriert. Die Anordnung sitzt wieder ausserhalb des Widgets (Box mit 20/112/48 dp und contentAlignment), die Ausrichtung wirkt zusaetzlich innerhalb der Spalte — fuer Start/Center/End wieder exakt das Bild der alten homeAppsLayout. Wichtig fuer die Bedienung: das Widget selbst muss verschiebbar bleiben und darf deshalb nicht die Anordnung tragen, ein vollbreites Widget laesst sich nicht seitlich bewegen.

Neu ist der Drawer-Hintergrund: WallpaperManager.getDrawable() auf 1/32 der Bildschirmbreite gezeichnet, auf 1/8 gestreckt, bilinear ueber den Bildschirm gezogen (Downscale/Upscale als Weichzeichner, ohne RenderEffect und ohne RenderScript) plus ein transluzenterer Scrim (0xD9) ueber dem Desktop. Ohne Wallpaper bleibt der Scrim allein. Keine neuen Tests (Kompositions-Glue und Farbentscheidung, kein Robolectric im Modul), 674 Tests gruen (gradle test).

Status 2026-10-02 (Launcher 465: die Home-Slots sind ein Widget)

secretary-launcher-android (vc 465): die Home-Slots bleiben zusammen. 463/464 machten jeden Slot einzeln verschiebbar (app-1 … app-8, neun Positionen fuer zwei Widgets); sie konnten dabei aus ihrer Spalte in die Ecke gezogen werden. Jetzt ist die Spalte ein einziges Widget (WidgetPosition.KEYS = {clock, apps}): ein MovableWidget mit huggender Column ueber alle Slots inklusive Leere-Hinweis, also ein Zug fuer die ganze Gruppe. Unbewegt steht sie exakt in der alten Anordnung — 20/112/48 dp Padding, vertikal zentriert, homeAlignment als Alignment.CenterStart / Center / CenterEnd (RTL wie Gravity), also mit engem Widget statt fillMaxSize + Arrangement.Center; bewegt frei an der abgelegten Stelle, geklemmt gegen die gemessene Gruppengroesse.

Vertragsrelevante Aenderung: das Sync-JSON. widgetPositions traegt jetzt "clock" und "apps" statt "app-<n>". LauncherSettings.fromJson verwirft unbekannte Schluessel, eine Instanz oder ein Serverstand aus 463/464 liefert also keine app-<n>-Positionen mehr zurueck — die Gruppe startet dort in der Default-Anordnung. Prefs.POSITION_KEYS fuehrt die alten HOME_POS_app-<n>_X|_Y weiterhin als reservierte Schluessel, damit der Datei-Scan sie nicht als Rename-Label missversteht, und clearWidgetPositions (Startbildschirm zuruecksetzen) entfernt sie mit. WidgetPositionTest/LauncherSettingsTest decken genau das ab. 674 Tests gruen (gradle test).

Status 2026-10-02 (Launcher 464: Ziehen der Uhr ging nicht)

secretary-launcher-android (vc 464): ein Einzeiler hat das Verschieben der Home-Widgets unbrauchbar gemacht, das in 463 eingefuehrt wurde. Der Home-Box wurde als Ursprung positionInRoot() - Offset(width, height) eingetragen, aber positionInRoot() ist bereits die linke obere Ecke des Knotens — im Bytecode von compose-ui 1.12.1 nachgewiesen (positionInRoot(c) = c.localToRoot(Offset.Zero)). Der Ursprung lag damit um ein Bildschirm zu weit links oben, jede Widget-Layoutposition um (W, H) daneben und damit jenseits der Klemmgrenze, und moveWithin schnappte jeden Zug in die untere rechte Ecke: beim ersten Ziehen sprang die Uhr dorthin statt dem Finger zu folgen, ein bereits verschobenes Widget bewegte sich ueberhaupt nicht mehr, weil sich die Verschiebung exakt aufhob. Behoben in HomeScreen.kt (Ursprung = it.positionInRoot()), sonst aendert sich nichts. Keine neuen Tests — der Fehler lag im Glue zwischen onGloballyPositioned und moveWithin, den kein JVM-Test sieht (das Modul hat kein Robolectric), die 12 Launcher-Tests von vorher und die 13 neuen sind gruen; 675 Tests gruen (gradle test). 463 war veroeffentlicht, der Import von 464 hat es im APK-Pool auf tremere aber ersetzt (je Paket nur eine Version).

Status 2026-10-02 (bewegliche Home-Widgets, Suchfeld unten)

secretary-launcher-android (vc 463): Uhr und Home-Apps lassen sich frei verschieben, das Suchfeld sitzt unten. Beides betrifft nur den Android-Launcher, kein SRS, keine anderen Clients.

(1) Verschiebbare Home-Widgets. Uhr/Datum und die bis zu acht App-Slots sind jetzt Widgets wie auf jedem anderen Home-Screen: Finger hin, ziehen, ablegen — an jede Stelle, an der sie vollständig sichtbar bleiben. Neu sind data/WidgetPosition.kt (Position als Bruchteil des Bildschirms, damit sie Rotation, Bildschirmgröße und Gerätewechsel übersteht, plus offsetOf, moveWithin, fractionOf), Prefs.setWidgetPosition/clearWidgetPositions (Schlüssel HOME_POS_<widget>_X|_Y, also in POSITION_KEYS und damit nicht als Rename-Label missverstanden) und MovableWidget in HomeScreen.kt. Ein nicht verschobenes Widget hat keine Position gespeichert und landet weiterhin in der alten Anordnung (Uhr oben bündig zur Ausrichtungseinstellung, Slots zentriert in der Spalte mit 20/112/48 dp) — eine bestehende Installation sieht also unverändert aus. Die Widgets folgen dem Finger als graphicsLayer-Translation über ihrer Layout-Position, geschrieben wird genau einmal beim Loslassen; widgetDrag in Gestures.kt verbraucht die Bewegung, womit das Wischen nach oben weiterhin den Drawer öffnet. Ein verschobenes Widget wird als Geschwister neben der Anordnungsspalte gerendert und dort mit Modifier.offset aus seiner Position gesetzt. Neu ist außerdem die Zeile Startbildschirm zurücksetzen (MainViewModel.resetWidgetPositions(), EN+DE) im Einstellungs-Screen. Neu im Sync: widgetPositions im LauncherSettings-JSON; der KDoc dort sagt jetzt ausdrücklich, dass jede Prefs-Einstellung mit sync't, außer den zwei gerätelokalen Flags — sonst löscht applyRemoteState sie beim nächsten Pull.

(2) Suchfeld unten. Im Drawer (AppDrawerScreen.kt) stand das Suchfeld oben neben dem Zurück-Pfeil; die Tastatur verdeckte es beim Tippen. Es steht jetzt unter der App-Liste, die Spalte bekommt imePadding(), und der Zurück-Pfeil hat seinen eigenen 8-dp-Abstand darunter.

Versionen: calendar 100, contacts 69, journal 143, launcher 463, links 33, notes 52, secrets 66, tasks 58. Keine SRS-Aenderung, 675 Tests gruen (13 neu: 4 in LauncherSettingsTest, 9 in WidgetPositionTest), verifiziert ueber gradle :launcher:testDebugUnitTest.

Status 2026-10-01 (Sync nur mit Konto, Passwoerter im Klartext)

Alle acht Clients — die Sync-Aktion verschwindet ohne Konto, Passwortfelder zeigen Klartext. Beides sitzt im gemeinsamen Android-Code und trifft damit jede App. Details und Dateiliste in den CONTEXT.md der betroffenen Module, hier die gemeinsame Sicht:

(1) Keine Sync-Aktion ohne Konto. AppHeader blendet die Aktion bereits aus, wenn onSync null ist — die vorhandene Konvention, die bisher nirgends benutzt wurde. OfflineBanner (StatusBanners.kt) verlangte einen nicht-nullbaren onSync und zeichnete den Refresh-Knopf bedingungslos; Parameter ist jetzt (() -> Unit)?, ohne Konto fehlt der Knopf, die Offline-Meldung bleibt. Alle 18 Aufrufstellen reichen den Callback nur noch durch, wenn wirklich ein Konto existiert. Sichtbar war das nur im Journal (kein Login-Gate, lokaler Modus localMode = !repo.isConfigured()) und im Tresor (Knopf war deaktiviert statt verborgen). Der Launcher war bereits richtig (account != null), er teilt nur die gemeinsamen Aenderungen.

(2) Passwortfelder zeigen Klartext. VisualTransformation.None statt PasswordVisualTransformation, KeyboardType.Password bleibt. Grund ist die Darstellung, nicht die Sicherheit: die Maske besteht aus U+25CF (●), und die gebundelte Typewriter-Schrift Special Elite deckt das Zeichen nicht ab — die Felder zeigten Ersatzglyphen. Betroffen sind der gemeinsame Login-Screen, die Journal-Passwortdialoge und das Entschperren sowie im Tresor Recovery- Passphrase, Entschperr-Passphrase, KDBX-Import/-Export und das Passwortfeld im Eintrags-Editor. Die Sichtbarkeits-Umschalter in den Tresor-Dialogen sind mit den Klartextfeldern weg. Unveraendert bleibt der Reveal-Pfad fuer gespeicherte Secrets (Browse, FieldRow) — das ist eine Anzeige, keine Eingabe, und vom SRS 9.2 weiterhin so gefordert.

Versionen: calendar 100, contacts 69, journal 143, launcher 462, links 33, notes 52, secrets 66, tasks 58. Contract-Tabelle aktualisiert. Keine SRS-Aenderung, kein neues JVM-Verhalten, 662 Tests gruen, alle neun Module kompilieren.

Status 2026-09-30 (journal Tutorial, SRS 1.9.0)

journal SRS 1.9.0 — der Typ Gewohnheit fehlte im Tutorial (secretary-journal-android vc 142): EntryType.HABIT kam in v130 mit voller Funktionalitaet (Editor, FAB, Vorlagen, Klartext-Bericht, gesammelte Texte), aber die pages-Liste in TutorialScreen.kt wurde nicht mitgezogen — sie endete beim Skill. Das Tutorial versprach in tutorial_types_body "alle Eintragstypen" und hat damit einen Typ versprochen, den es nicht zeigte; die gesammelten Texte wiederum erwaehnten Gewohnheiten bereits. Neu ist eine Gewohnheiten-Seite (tutorial_habit_title/tutorial_habit_body DE+EN, Icons.Filled.Checklist wie im Rest der App) hinter der Skill-Seite, damit die Reihenfolge der EntryType.entries folgt, plus TutorialTry.HABIT -> vm.openHabitEntryForDate(...) im NavGraph (der "Ausprobieren"-Knopf oeffnet den vorausgefuellten Gewohnheiten-Editor). tutorial_types_body nennt jetzt "Gewohnheiten und Skills". Der KDoc am Screen haelt fest, dass ein neuer Typ eine Seite braucht. Contract-Tabelle aktualisiert (journal vc 142, SRS 1.9.0).

Status 2026-09-30 (journal gesammelte Werte, SRS 1.8.0)

journal SRS 1.8.0 — Medikamenten-Kombination + Felder gleich behandelt (secretary-journal-android vc 141): Das Sammeln war bisher feld-skaliert, das Medikament dabei sogar unvollständig. (1) Ein Medikament wurde bisher als zwei Werte gesammelt (Wirkstoff, Stärke) — die Kombination, also das, was man tatsächlich einnimmt, fehlte. Neu ist das abgeleitete GatherField.MEDICINE_COMBINATION, das den Wirkstoff mit der Dosis verknüpft (medicineCombination = "Ibuprofen 400 mg"; ohne Dosis degeneriert es zum reinen Wirkstoff und wird nicht doppelt gelistet). Ein Umbenennen/Zusammenführen dieser Zeile schreibt beide Felder zurück (withRenamedMedicineCombination): der neue Wert wird am ersten Leerzeichen getrennt, ein Eintrag ohne Dosis behält eine leere Dosis, und ein Name, der den Wirkstoff spiegelt, wandert mit. withGatheredText verweigert für das abgeleitete Feld den Dienst (error(...)) — es gibt kein einzelnes Editor-Feld, das man setzen könnte. (2) Die Feld-Labels sind weg (gathered_field_* DE+EN entfernt, gatherFieldLabel gelöscht): die Zeilen zeigen nur noch den Text plus n× · Datum · Ø-Gap, jeder Typ wird gleich behandelt. Das Zusammenführen bleibt feld-skaliert (Wirkstoff lässt sich weiterhin nicht in eine Dosis führen), und der Auslöser-/Skill-Editor filtert seine Vorschläge weiterhin auf field == TEXT. Contract-Tabelle aktualisiert (journal vc 141, SRS 1.8.0).

Status 2026-09-29 (launcher, kein eigenes SRS)

Launcher-Konfiguration über /launcher/: secretary-launcher-android (vc 455) ist der erste Client, der seine Einstellungen statt seiner Daten synchronisiert. Eine Collection unter /launcher/ enthält eine settings.ics (VJOURNAL, SUMMARY=settings, CATEGORIES=launcher,settings) mit dem JSON-Zustand im DESCRIPTION (LauncherSettings: Theme, Textgröße, Home-Anzahl/Ausrichtung/Textfarbe, Datumsanzeige, Home-App-Stil, Tastatur-Automatik, Umbenennungen, Slot-Belegung) sowie je belegtem Home-Slot eine app-<slot>.ics (CATEGORIES=launcher,app-<slot>) mit Label, Paketname, Activity-Klasse und Profil. Merge-Regel: der Server gewinnt beim Voll-Sync, lokale Änderungen werden 1,5 s entprellt hochgeladen; ohne Konto bleibt der Launcher vollständig lokal benutzbar, und die Einstellungen wandern in die gemeinsame SecretarySettingsScreen (Konto, Synchronisation, Support-Karte). Das eigene minSdk steigt dafür von 24 auf 26, weil der Launcher jetzt :common (Konto + java.time) einbindet.

Status 2026-09-22 (journal Habit, SRS 1.6.0)

journal SRS 1.6.0 — achter Eintragstyp Gewohnheit (Habit): Die Journal-SRS ergänzt den neuen Eintragstyp HABIT (ein einzelnes Freitextfeld, ohne Tendenz, nicht Teil von Statistik/Gathered, aber vollständig vorlagen-tauglich: feste/zufällige Erinnerungen, direct:add, Accept/Reject, „Jetzt eintragen" — der Scheduler ist typ-agnostisch). VJOURNAL SUMMARY=habit, DESCRIPTION = Text, CATEGORIES=[habit, is:template, rrule:*, rand:N, direct:add, at:*]. Umsetzung in secretary-journal-android vc 130: EntryType.HABIT("habit"), Icon Checklist, Farbe Indigo 0xFF3F51B5, HabitEntryBody im Editor, openHabitEntryForDate/createNewHabitEntry, HABIT in Verschlüsselung/ Entschlüsselung/Import-Mergung, Editor/FAB/Kalender/Report/TypeUi erweitert. Contract-Tabelle aktualisiert (journal vc 130, SRS 1.6.0).

Status 2026-09-19 (Namespace-Migration, server 0.16.0)

Namespace-Roots statt Collection-ID-Präfixe (notes/tasks/journal/links). Bisher lagen die Sammlungen von Notizen/Aufgaben/Tagebuch/Links als notes-*/tasks-*/journal-*/links-*-präfixierte Collections unter /calendars/ (z. B. /calendars/journal-main/). Neu bekommen diese vier Produkte eigene top-level Namespace-Roots auf dem Server: /notes/, /tasks/, /journal/, /links/; die Sammlungen sind dort unpräfixiert (/journal/main/ statt /calendars/journal-main/). Kalender (/calendars/calendar-*), Kontakte (/addressbooks/contacts-*) und secrets/ bleiben unverändert. Umsetzung:

Status 2026-09-19

secrets SRS 1.0.0 — Überarbeitung (Redraft): Die Secrets-SRS wird grundlegend neu gefasst und ersetzt die Drafts 0.1.0–0.4.0. Kernstücke auf Wunsch: (1) Top-Level-secrets/-Root auf dem Single-User-Server, neben calendars/ und addressbooks/; KeePass-Gruppen (Unterordner) werden Collections im secrets/-Baum, jeder Eintrag ist genau eine Datei (<e-uuid>.ics) in seiner Gruppen-Collection, Gruppen-Metadaten je in group.ics, Datenbank-Meta in secrets-meta.ics. (2) Feld-Level-Sync: Änderungserkennung und Drei-Wege-Merge laufen per Feld (X-SECRETS-FIELD;NAME=…), nicht pro ganzen Eintrag; unveränderte geschützte Ciphertexte bleiben stabil, sodass auch verschlüsselte Felder ohne Decrypt vergleichbar sind. (3) Nur geschützte Felder verschlüsselt (Passwort, OTP-Secrets, Passkey-Private-Key, vom Nutzer markierte Felder) — alles andere ist Betriebs-Klartext. (4) Master Key auf Geräten + Recovery-Kopie auf dem Server: der MK wird clientseitig erzeugt und liegt nur gewrappet (Platform-Keystore, optional Passphrase) auf den Geräten; für die Wiederherstellung wird er zusätzlich mit einer Recovery-Passphrase versiegelt und als recovery-key.json auf dem Server hinterlegt — gehen alle Geräte verloren, stellt die Kopie mit der Recovery-Passphrase den Tresor wieder her (Pro-Device-/keys/-Registrierung/Escrow-Dienst gibt es weiterhin nicht). (5) KDBX Import/Export/Merge (§4.6–4.8) mit Konformität K0–K5. (6) Volle Historie immer — jeder Änderungssnapshot bleibt erhalten, inkl. der vollständigen Passwort-Historie; keine automatische Löschung. Passwort-Auth, OTP und Passkeys bleiben First-Class. Version 1.0.0, Doc-only.

Status 2026-09-18

journal SRS 1.4.0 — Ehrliche Zufalls-Zeiten per Teil-Methode + Direct-Add-Fix: Die Journal-SRS präzisiert die Zufalls-Bewaffnung (FR-J-71, neu FR-J-84/85): Die Tages-Feuerzeit (ganzer Tag minus Ruhezeit) wird in N gleiche aufeinanderfolgende Teile geteilt, jedes Teil liefert einen deterministischen Zufalls-Slot (Seed uid+Tag+Teil); bereits abgelaufene Teile werden übersprungen, restliche Slots rollen auf die folgenden Vorkommens-Tage, und jedes Re-Arm reproduziert exakt dieselben absoluten Zeiten — keine Verdopplung/kein Verschieben durch Accept/Reject mehr. Zudem wird direct:add beim Annehmen für alle Eintragstypen direkt protokolliert (nicht nur TEXT). §1.3-Definition „Random schedule" aktualisiert. Version 1.4.0 (normaler Fortschritt), entspricht secretary-journal-android vc 125. Umsetzung in TemplateAlarmScheduler (dayFiringChunks/mapToWallMinute, Teil-Logik), JournalViewModel (directAdd-Bedingungen). Doc + App.

Status 2026-09-17

secrets SRS 0.4.0 — Sammlungen als Merge-Einheiten (Import-Zielwahl + Sammlungs-Merge): (1) KDBX-Import-Zielwahl (§4.7 FR-SEC-K-78/79): Vor der Konvertierung muss der Nutzer wählen — (a) neue Sammlung mit neuem Master-Key (Server generiert frischen MK, nie aus dem Passwort der Importdatei abgeleitet) oder (b) in eine bestehende Sammlung einfügen (alle Blobs werden unter deren MK neu verschlüsselt, bestehende UUIDs laufen durch §8 statt überschrieben zu werden). (2) Sammlungen sind merge-fähig (§6.4 FR-S-236…239, §8, §9.1/9.2): zwei Sammlungen fusionieren zu einer Ziel-Sammlung — Eintrag-weise nach §8 (Basis = Ziel- Zustand, sofern die Quelle daraus abgeleitet ist, sonst leer), Union der Gruppenbäume, UUID-Kollisionen ohne gemeinsame Basis werden als Konflikte angezeigt (neue UUID nur bei expliziter Akzeptanz), Dry-Run-Diff-Vorschau, ETag-geschützte Writes, Quelldaten können danach gelöscht werden. Neu: Sammlungs-Anlage FR-S-216, CLI-SEC-12, NFR-S-07 erweitert, §1.5-Definitionen (Collection, Collection merge). Version 0.4.0. Doc-only. Erster Umsetzungsschritt parallel in secretary-secrets-android :core (History-/Merge-Engine, versionCode 8).

Status 2026-09-17

secrets SRS 0.3.2 — Envelope-Endname ss1: (sj1/ss1-Konvention): 0.3.1 benannte den Envelope in mk1: um — die Mischung aus Produktname (sj1: = secretary-journal) und Schlüsselrolle (mk1: = Master-Key) war sprachlich inkonsistent. Der Envelope folgt nun durchgängig der Produkt-Präfix-Konvention: sj1: = secretary-journal (passwortabgeleiteter Schlüssel, unverändert), ss1: = secretary-secrets (stets mit dem Vault-Master-Key verschlüsselt, Model B, §3.2; MK nur auf dem Server, per-Client-gewrappte Kopien, Escrow). Byte-Aufbau bleibt AES-256-GCM (base64(iv ‖ ciphertext ‖ tag)), Attachments bleiben präfixlos (§5.4). Erster neuer Umsetzungsschritt in secretary-secrets-android :core (SecretsCipher, ID="ss1", versionCode 7). Version 0.3.2. Doc-only.

Status 2026-09-17

secrets SRS 0.3.1 — Envelope sj1: → mk1:: Der Value-Envelope wird von sj1: auf mk1: umbenannt (ENCODING=mk1). Grund: sj1: ist das Byte-Layout des leichten, passwortabgeleiteten Schutzverfahrens von secretary-journal (Privacy-Grade); Secrets verschlüsselt Werte aber ausschließlich mit dem Vault-Master-Key (Model B, §3.2: MK nur auf dem Server, Geräte halten nur per-Client-gewrappte Kopien, Escrow). mk1: signalisiert die Master-Key-Sealed-Box; Byte-Aufbau bleibt AES-256-GCM (base64(iv ‖ ciphertext ‖ tag)), Attachments bleiben präfixlos (§5.4). Aktualisiert: §2.5, §5.3/5.5/5.6/5.8, FR-S-112/131/212, FR-SEC-K-84, Implementierungs-Anhang. Erster normativer Schritt in Umsetzung durch secretary-secrets-android :core (SecretsCipher, versionCode 6). Version 0.3.1. Doc-only.

Status 2026-09-17

secrets SRS 0.3.0 — System-Integration auf KeePassDX-/KeePassXC-Niveau: Neuer normativer Abschnitt §6.9: Jeder Client muss sich wie der führende KeePass-Client seines Systems in das Betriebssystem integrieren und nicht als abgeschlossene App agieren. Referenzniveau ist KeePassDX auf Android (AutofillService API 26+, eigene Autofill-Tastatur/IME für Apps, die den Autofill-Service ignorieren, Quick-Settings-Kachel zum Entsperren/Sperren und OTP-Kopieren, dokumentierte Intent-/Automatisierungs-API mit Activity-Result-Vertrag, Notification-/Share-Zugriff) und KeePassXC auf dem Linux-Desktop (globaler Auto-Type-Hotkey mit Fenstererkennung und KeePass-Zuordnungen, KeePassXC-Browser-kompatible Browser-Integration via Native Messaging/Local Socket inkl. OTP-Fill und Passkey/WebAuthn-Provider, Secret-Service-Provider für native Apps, optionaler SSH-Agent); für iOS/macOS ist das Äquivalent eines Strongbox/KeePassium-Klasse-Clients gefordert (FR-S-260…274, CLI-SEC-09…11). Jede Integrationsfläche ist einzeln schaltbar, auf Sammlungen einschränkbar, unterliegt demselben Lock-Gate und optional einer Biometrie-Anforderung pro Zugriff, schreibt nie Klartext außerhalb von Tresor/Cache, und Kopien in die Zwischenablage werden als sensibel markiert und automatisch geleert (FR-S-270/271/272). Dazu §2.4 (Plattform-Delta um Autofill-Tastatur, Quick-Settings-Kachel, Auto-Type, Browser-Integration, Secret-Service, SSH-Agent, Passkey-Provider und Referenzniveau erweitert), §9.4 (neuer Integrations-Einstellungsbereich mit Einrichtungsschritten) und §10 (Implementierungshinweise AutofillService/InputMethodService/TileService/ACTION_* bzw. Global-Shortcut-Portal, Native-Messaging-Bridge, libsecret, SSH-Agent-Socket). Version 0.3.0. Doc-only.

Status 2026-09-17

secrets SRS 0.2.0 — KeePass-kompatibler Tresor auf VJOURNAL-Basis: Die Secrets-SRS wird grundlegend neu gefasst (weiter DRAFT, noch keine Implementierung). Zwei Kernwechsel gegenüber 0.1.0: (1) Speicherung pro Eintrag als eigene CalDAV-VJOURNAL-Ressource secret-<uuid>.ics in einer secrets--Collection (analog Journal), plus secrets-meta.ics für KDBX-Meta, Gruppenbaum und Custom-Icons; die bisherige /vault/*-JSON-Ablage entfällt. Model B bleibt: der serverseitige Master-Key wird pro Client gewrappt, das Key-Directory liegt unter /keys/<vault-uid>/. (2) Volle KeePass- Kompatibilität über sechs Konformitätsstufen C0–C6: KDBX-4.0/4.1-Container (AES-256-CBC/ChaCha20, AES-KDF/Argon2d/Argon2id, HMAC-Blockstream, Inner Header + Inner Stream), das komplette KDBX-4.1-XML-Objektmodell (Standard- und Custom-String-Felder mit Reihenfolge und Protected-Flag, Tags, AutoType, CustomData, CustomIcons, Colors, PreviousParentGroup, QualityCheck, Meta, RecycleBin, DeletedObjects), Anhänge (Binary-Pool, Dedup per SHA-256, Memory-Protect-Flag), vollständige Historie im KDBX-Entry/History-Sinn (eingebettet je Eintrag als verschlüsselter Snapshot-Blob), OTP in allen Konventionen (KeePass 2.47+ TimeOtp-*, KeePassXC otp/TOTP Seed+ TOTP Settings, KeeOtp, KeeTrayTOTP; Schreiben im KeePassXC-otpauth-Format) und Passkeys im KeePassXC-KPEX_PASSKEY_*-Feldformat (Credential-ID, PKCS#8-PEM, RP, Username, User-Handle, BE/BS-Flags; Algorithmus aus der PKCS#8-OID) sowie optional plattform-residente Passkeys. Der Merge wandert von serverseitig auf clientseitig (der Server kann Geheimtexte nicht vergleichen), abgesichert über CalDAV-ETags/If-Match. Definiert sind die drei Sichten KDBX-XML ⇄ Secret-Document (JSON) ⇄ VJOURNAL inkl. normativer Property-Zuordnung, Feld-/Anhang-/History-Kodierung und Beispiel-.ics. Version 0.2.0. Doc-only.

Status 2026-09-17

journal SRS 1.3.0 — Passwort-only-Verschlüsselung: Die Journal-SRS ersetzt das bisherige Master-Key-Schema (zufälliger AES-Schlüssel, per PBKDF2-Passwort gewrappt) durch ein passwort-only-Modell: der PBKDF2-HmacSHA256-abgeleitete Schlüssel (210k, salzfrei) verschlüsselt AES-256-GCM direkt, es gibt keinen separaten Master-Key (FR-J-90). Damit genügt das Passwort allein, um das Journal nach Neuinstallation, Reconnect oder Import wieder zu entschlüsseln (FR-J-96); Passwort ändern re- verschlüsselt alle Einträge mit dem neuen Schlüssel. Setzen/Entfernen/ Ändern zeigt eine Warnung (Wirkung auf alle Einträge) und einen Fortschritt „Eintrag X von Y" (FR-J-95). Alt-Installationen mit Master-Key bleiben über den Legacy-Wrap entsperrbar, bis ihre Einträge neu kodiert sind (FR-J-97). Das Tutorial bekommt das Einrichten der Verschlüsselung als letzten Schritt (FR-J-120). Version 1.3.0 (normaler Fortschritt), entspricht vc 124. Doc-only.

journal SRS 1.2.0 — Template-Maske klar vom Eintrag getrennt: Die Journal-SRS verschärft §4.8: Das Erstellen/Bearbeiten einer Vorlage nutzt eine visuell unterscheidbare Maske — ein Vorlagen-Badge ersetzt die Datums-Unterzeile („Vorlage"/„Template" + Typ-Label), und die nur für Vorlagen existierenden Felder (Wiederholung/RRULE, Zufallsplan rand:<N>, Direkt-Eintragen direct:add) stehen in einem eigenständigen, klar beschrifteten Vorlagen-Abschnitt mit Vorlagen-Wortlaut statt der Eintrags-Wortlaut-Beschriftungen (FR-J-82/83). Bisher zeigte die Maske nur zusätzliche Felder, ohne erkennbar zu machen, dass eine Vorlage erfasst wird. Versionsnummer 1.2.0 (normaler Fortschritt). Doc-only.

journal SRS 1.1.0 und common SRS 1.1.0 — vollständiger Ist-Stand der Woche (gleicher Tag, vor 1.2.0): Die Journal-SRS deckt jetzt das Produkt wie es ist (Stand secretary-journal-android vc 122) statt nur des Minimal-Kerns: sieben Eintragstypen (Highlights/TEXT einmal täglich, Stimmung/MOOD fünf Stufen, Excreta mit Stuhl/Bristol 1–7 und Urin/Armstrong 1–8, Medikament, Essen & Getränk, Trigger und Skill mit Tendenz), is:template-Vorlagen mit fester RRULE oder Zufallsplan (rand:<N>) und Accept/Reject-Erinnerung, direct:add-Direktprotokollierung, Ruhezeit (Quiet time, Default 22:00–07:00, Scheduler feuert im Komplement, Wrap-Around erlaubt), die Single-Flavor-Lokal-Server-Dualität über die gemeinsame OfflineSyncEngine, optionale Verschlüsselung (PBKDF2 + AES-256-GCM + Biometrie, sj1:-Blobs), versioniertes JSON-Export/Import, der Klartext-Arztbericht, Statistik + gesammelte Werte, Tutorial und DE/EN-Lokalisierung. Die bisher als Roadmap (§7) eingestuften Features sind mehrheitlich in den Scope gewandert; die Roadmap enthält nur noch Kalender-Filter, Widget und weitere Typen. Die common SRS dokumentiert den Stand v0.31.0: die gemeinsame OfflineSyncEngine (Local-Mode, First-Connect-Re-Homing, prepare-Seam, Pending-Delete-Filter, prepare-null-Keep, Stale-Queue-Put-Cleanup, ItemsLoadResult), 412-Auto-Recovery, /sync/*-Job-Endpunkte, GET_ACCOUNTS-Sichtbarkeit, komma-sicheres CATEGORIES-Splitting und die DavException-vor-IOException-Reihenfolge; Journal ergänzt die Consumers. Die Contract-Tabelle wurde aktualisiert (journal vc 122, common v0.31.0).

Alle Änderungen sind reine Doku-Commits (kein Build, kein Paket).

Status 2026-09-16

Neues Produkt journal/ — SRS 1.0.0: Secretary Journal, ein persönliches Gesundheitstagebuch. Einträge als CalDAV VJOURNAL unter journal--Collection (journal-main), wie Notes. Das Journal ist im Gegensatz zu den übrigen Apps die Referenz für „lokal ODER Server": ein einziger Codepfad bedient beide Modi – der GOfflineStore ist immer die lokale Quelle, eine konfigurierte Server-Collection (journal-*) nur der Sync-Layer darüber; ohne Konto wird die lokale Pseudo-Collection journal-local (href /local/) geseedet und die App startet ohne Login-Wand direkt im Kalender. Initiale Kern-Scope: drei Eintragstypen (Highlights/TEXT einmal täglich, Stimmung/MOOD und Stuhl/Bristol mehrfach), Monatskalender, typabhängiger Editor, Settings. Verschlüsselung, Medikamente, Essen/Getränke, Trigger/Skill, Hydration, Vorlagen/Erinnerungen, Statistik und Export/Import sind als Roadmap (§7) zurückgestellt. Das secretary-journal-android wurde dafür komplett neu aufgesetzt (Clean Rewrite, vc 113) statt auf dem v94-Flavor-Merge aufzubauen.

Status 2026-09-08

Neues Produkt secrets/ — SRS 0.1.0 (DRAFT): Ein verschlüsselter Passwort-/Schlüssel-Tresor mit History und Feld-Merge (KeePass-artig), im Modell B (Master-Secret nur auf dem Server, Clients halten eigene Keypairs, Server re-encrypted das Master-Key pro Client). Konfliktlösung per Feld-granularem Merge statt Ablehnung; vollständige Feld-History, server-seitige Revocation, Offline-Cache des gewrappten Keys. Zusätzlich: KeePass KDBX Import/Export, Passkey-Unterstützung (WebAuthn-Metadaten im Tresor, private Keys nur in Platform-Authenticator), OTP/TOTP/HOTP mit Client-seitiger Code-Generierung und GTK-Autofill. Android Autofill Service (KeePassDX-artig): System-level Anbieter für Usernamen/Passwörter in Browsern und Apps, mit Inline-Unlock und Save-Request. API-Stand provisory (/vault/* + /keys/*); noch keine Implementierung.

Palimpsest abgetrennt: Palimpsest ist ein eigenständiges Ökosystem (eigene Repos palimpsest-*, eigene SRS palimpsest-SRS/server). Das palimpsest/-Verzeichnis mit FORMAT.md wurde aus dem Contract entfernt; alle Palimpsest-referenzen aus SRS/common gestrichen.

Status 2026-08-27

Palimpsest-Integration überholt: palimpsest-SRS/server v6.0.0 integriert den PDF-Viewer direkt in die Palimpsest-Clients (palimpsest-gtk mit poppler, palimpsest-android mit PdfRenderer). Links öffnen sich in einem Viewer-Tab im Editor statt secretary-pdf zu starten. Die eigenständigen Repos palimpsest-pdf-gtk und palimpsest-pdf-android (lokal und auf tremere) wurden entfernt. Die Palimpsest-Clients wurden von palimpsest-editor-* auf palimpsest-* umbenannt. Das pdf/-Produkt sowie palimpsest/REFACTOR-PLAN.md wurden aus dem Contract entfernt (das PDF-Produkt existiert nicht mehr als eigenständiger Vertrag; die Palimpsest-SRS ist alleinige Quelle).

Status 2026-08-25

pdf SRS 0.1.0 — Erstfassung: PDF-Viewer und -Browser für Linux und Android. Server-seitig: secretary-serving von PDFs über /pdfs/-URL-Präfix (nur lesbar, PROPFIND/GET, 405 bei PUT/DELETE). Client: Sammlungs-Browser, lokalen Cache mit ETag-Validierung, PDF-Rendering (poppler-rs/PdfRenderer), Seitennavigation, Zoom, Textsuche. CLI-Schnittstelle --collection X --file Y --page N für Palimpsest-Integration. Palimpsest-Dokumente erhalten neuen PartKind::Pdf (FR-300…310) mit strukturierten PDF-Links (Collection, Datei, Seite, Label, Note). (Entfernt 2026-08-27, siehe Status 2026-08-27.)

Status 2026-08-21

Restructuring: secretary-palimpsest-contract → secretary-contract (Verzeichnis + Fossil-Repo lokal und auf tremere). Die SRS lebt je Produkt unter SRS/notes, SRS/tasks; neu: SRS/common für die gemeinsame Plattform-Schicht. Die Palimpsest-SRS lebt jetzt in palimpsest-SRS/server.

Verzeichnisstruktur

secretary-contract/
├── CONTEXT.md
├── .fossil-settings/
├── common/
│   └── SRS.md                    # Gemeinsame Plattform-Schicht
├── journal/
│   └── SRS.md                    # Journal (lokal + Server, Drei-Typen-Kern)
├── notes/
│   └── SRS.md                    # Notes (VJOURNAL)
├── secrets/
│   └── SRS.md                    # Secrets (Tresor: secrets/-Root, Gruppen=Collections, 1 Datei pro Eintrag, Feld-Level-Merge, MK auf Geräten + Server-Recovery; DRAFT 1.0.0)
└── tasks/
    └── SRS.md                    # Tasks (VTODO)

Konventionen

Release-Signierung (Android)

Ein gemeinsames Zertifikat für alle acht Clients, erzeugt am 2026-09-29. Das Schlüsselmaterial liegt nicht in diesem Repository: wer diesen Checkout liest, könnte sonst fremde Updates an installierte Apps ausliefern. Es steht deshalb in der .fossil-settings/ignore-glob (*.keystore, *.jks, signing.properties), und fossil add verweigert solche Dateien ohne ausdrückliche Bestätigung.

Ein Release-Build liest genau eine Datei: signing.properties im Wurzelverzeichnis des Repos. Fehlt sie, bricht assembleRelease mit einer Meldung ab, die den Dateinamen nennt — ein Debug-Build braucht sie nicht.

keytool -genkeypair -v -keystore my-release.keystore \
  -alias secretary -keyalg RSA -keysize 4096 -validity 10000

cat > signing.properties <<EOF
storeFile=$PWD/my-release.keystore
storePassword=...
keyAlias=secretary
keyPassword=...
EOF

gradle :launcher:assembleRelease

storeFile steht absichtlich nicht in den Zugangsdaten: im Container ist der Pfad ein anderer als im Arbeitsverzeichnis, also ergänzt ihn der Aufrufer.

Befehle

fossil status        # Status
fossil commit -m "…" # Doku-Änderung committen
fossil push          # Push zu tremere