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.
Status 2026-10-08 (38: Tags als Ordner, Sammlungs-Nutzung, SRS links)
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.
Status 2026-10-08 (Server 0.31.0: defekte Links werden markiert)
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.
- Server (0.26.0): Namespace-Root
/news/(7. Eintrag inCALENDAR_NAMESPACES), zwei idempotent angelegte VJOURNAL-Collections (subscriptions= „Abonnements",articles= „Artikel"), Fetcher-Crateserver/secretary-server-news/mit eigenem Binarysecretary-server-newsund Timersecretary-server-news.timer(alle 15 Minuten). Abonnements tragen ihre Metadaten alsX-NEWS-*in der DESCRIPTION (Feed-URL, letzter Abruf, letzte Leseaktivität, Abruffehler, ETag/Last-Modified, Intervall in Minuten), Artikel zusätzlichX-NEWS-URL/X-NEWS-PUBLISHED/X-NEWS-READund den serverseitig bereinigten Klartext alsbody:. Dedupe über stabilenentry_key()+ deterministische UID, Artikel werden nur neu angelegt und nie überschrieben (Lese-Status der Clients bleiben erhalten), ETag/If-Modified-Since gegen die Feed-Quelle. Debian-Paketsecretary-server-newsinkl. postinst, die beide Collections anlegt. - App (vc 1): neues Modul
android/news/(org.beowulf.secretary.news) mit Artikelliste (Feed-Filter, Ungelesen-Filter, Suche), Artikeldetail (automatisch gelesen, teilen, im Browser öffnen), Abonnements-Liste und -Editor (URL, Titel, Intervall, Notiz, Löschen samt Artikeln), Login/Einstellungen über die gemeinsamen Screens, Akzent Ocker#7A5218, Icon[!]. Fehlende Collections werden beim ersten Laden selbst angelegt, Lese-Status wird auf Artikel- und Abonnement-Ebene geschrieben, VIEW/SEND-Intents belegen eine neue Feed-URL vor. - Registrierung:
settings.gradle.kts(„news"), Icon-Eintrag intools/generate-icons.sh, README-Apps-Liste,server/CONTEXT.md, beide debian-builds-Rezepte (Android-MODULESwächst auf neun). - Tests: 21 Unit (news) + 297 Unit + 60 Integration (Server) + 12 (rp)
- 20 (secretary-server-links) grün,
cargo clippy --workspace --all-targets -- -D warningswarnungsfrei; Android956 Tests grün(gradlew testDebugUnitTest --rerun), alle zehn Module kompilieren offline. Reihenfolge: erst Server (ab 0.28.0 wird der News-Fetcher über[news] active = truein der Server-Config mitgestartet), dann die App.
- 20 (secretary-server-links) grün,
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:
- Server 0.16.0:
CALENDAR_NAMESPACES= calendars/notes/tasks/journal/ links,ADDRESSBOOK_NAMESPACES= addressbooks; Storage-Init legt alle Roots an, Router/Handler dispatchen aufis_calendar_namespace/is_addressbook_namespace(die lokale Pseudo-Collection/local/bleibt außen vor;/sync/*-Endpunkte akzeptieren die neuen Roots). - common-android:
CaldavClient.collectionRootüber eine neuebaseCollectionPath;DEFAULT_PREFIX = "";NotesCodec/TasksCodecdefaultcollectionBasePath = /notes/bzw./tasks/(CalendarCodec/ContactsCodecbleiben präfixiert);PendingSync.mainCollectionId=mainfür unpräfixierte Codecs;GOfflineStore.legacyPrefixmigriert den Legacy-Cache (raw-JSON, idempotent,/local/-Homes bleiben unangetastet). - Apps: notes 43, tasks 49, journal 129, links 23 nutzen den neuen
Namespace;
runServerSyncfiltert zusätzlich die neuen Roots (Legacy-/calendars/,/addressbooks/bleiben im Filter); die gemeinsamen Einstellungen zeigen „Namensraum" statt „Sammlungspräfix". - Migration (Server zuerst):
secretary-server/migrate-namespaces.shkopiert/calendars/{notes,tasks,journal,links}-*nicht-destruktiv in die neuen Roots (Backups bleiben liegen,--dry-runverfügbar; empfohlen bei gestopptem Dienst). Reihenfolge: erst Server deployen + migrieren, dann die Apps aktualisieren — ein alter Server routet/notes/usw. nicht und lehntMKCALENDARin die neuen Namespaces ab.
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.
- notes SRS 1.0.0: Erstfassung aus dem Ist-Zustand beider Clients
(VJOURNAL-Modell,
notes--Präfix, Offline-Queue, GTK-Shell-Search). - tasks SRS 1.0.0: Erstfassung aus dem Ist-Zustand (VTODO-Modell, RRULE-Wiederholungen mit Roll-Forward, Erinnerungen mit Schnellaktionen, Offline-Queue; Android + GTK).
- common SRS 1.0.0: Erstfassung für
secretary-common-android/secretary-common-gtk(zentrales Kontoorg.beowulf.secretary, Präfix-Konventionen, Operationen, Codecs, Offline-Store/Sync-Engine, bekannte Asymmetrien).secretary-account-androidist damit archiviert (vom Shared Account abgelöst).
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
- Je Produkt-SRS ist die einzige Quelle für die Produktanforderungen;
SRS/commongilt für alle Produkte. - Naming: kleine Buchstaben und Hyphen.
- Kein Build, kein Paket: Änderungen sind reine Doku-Commits.
- Versionsbump: minor bei normalem Fortschritt, major bei Bruch.
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.
- Keine Umgebungsvariablen. Weder
KEYSTORE_PATHnochKEY_ALIAS,STORE_PASSWORDoderKEY_PASSWORDwerden gesetzt: Umgebungsvariablen stehen in der Prozessliste des Gradle-Prozesses und in der Umgebung jedes Kindprozesses, undSystem.getenv()kann „nicht konfiguriert“ nicht von „mit Müll konfiguriert“ unterscheiden. Eine Datei gibt eine Stelle zum Nachsehen, eine Stelle zum Redigieren und eine klare Fehlermeldung. - Einmal statt achtmal: Die
signingConfigsstehen imbuild.gradle.ktsder Wurzel insubprojects { plugins.withId(...) }und nicht achtmal kopiert in den Modulen. Zuvor musste derselbe Default-Pfad-Fix an allen acht Dateien gemacht werden — eine Kopie, die niemand pflegt, driftet. - Alle acht Module haben eine
release-Signing-Config mit demselben Key (PKCS12, ein Alias für alle Clients).gradle :<modul>:assembleReleaselegt das Ergebnis unterandroid/<modul>/build/outputs/apk/release/ab; R8 läuft dabei nur fürlauncherundsecrets, die anderen sechs bauen ungeschrumpft. v1ist aus (enableV1Signing = false):minSdk26, die JAR-Signatur gibt es nur für API < 24. v2 deckt alles ab.- Signatur prüfen:
apksigner verify --print-certs <apk>mussVerifiesliefern. Genau dieser Schritt hat einen echten Fehler gefunden:secretshatte einensigningConfigs-Block, aber imrelease-buildTypekeinesigningConfig-Zuweisung und lieferte deshalb ein unsigniertes APK. - Verlust ist unwiderruflich: ohne denselben Key kann keine neue Version eines installierten Releases mehr ausgeliefert werden (Play Store und System verlangen Signaturidentität). Eine Kopie des Keys liegt außerhalb dieses Repos — wer sie verliert, liefert nie wieder ein Update aus.
- Gradle braucht
--max-workers=2für den Acht-Modul-Release-Build. Mit der Standard-Zahl laufen diepackageRelease-Tasks parallel, während R8 fürlauncherundsecretsläuft, und der Build bricht dann inPackageAndroidArtifact$IncrementalSplitterRunnableohne brauchbare Meldung ab. Reproduzierbar, nicht flüchtig.
Befehle
fossil status # Status
fossil commit -m "…" # Doku-Änderung committen
fossil push # Push zu tremere