Auf dem Anmeldebildschirm steht jetzt dieselbe Biene wie in der Leiste und im
Tab, nur gross — ein Geraet, ein Zeichen. Die 3/4-Ansicht wird nirgends mehr
ausgeliefert; sie bleibt als schraeg() im Werkzeug liegen.
Dazu sitzt der SVG-Rahmen jetzt auf dem, was wirklich gefuellt ist. Das Raster
ist quadratisch, die Biene nicht — unten blieb ein Viertel Luft, und die kostet
ueberall Groesse, wo das Bild in einen Kasten gelegt wird.
tools/biene.py schreibt die Zeile in honeybar.js jetzt selbst mit: Drei Kopien,
die von Hand gepflegt werden, laufen genau einmal auseinander.
Die 3/4-Ansicht ist unter 64 px unbrauchbar und deshalb genau hier richtig:
Auf dem Anmeldebildschirm ist Platz, und man wartet ohnehin auf den Anbieter.
Sie schwebt sechs Sekunden lang zwei Pixel weit — eher ein Atmen als eine
Bewegung, und bei prefers-reduced-motion steht sie still.
Gerechnet wird sie in tools/biene.py aus demselben Raster wie die anderen
Fassungen.
Aus dem Quadrat links in beiden Leisten wird eine Pixelbiene von der Seite:
braune Streifen, schwarze Beine, Fluegel mit Kerbe. Sie steht in genau einem
Raster (tools/biene.py, 16x16 Zeichen); daraus entstehen SVG, PNG und eine
Fassung aus Schriftzeichen.
SVG statt PNG in den Leisten: Die HoneyBar laeuft in fremden Apps, und ob ein
<img> dort laedt, entscheidet deren CSP. Markup kann niemand blockieren.
Im System-Fenster und ueber dem Startlauf steht die Biene aus Schriftzeichen —
beides sind Textflaechen, ein Bild darin waere ein Fremdkoerper.
Das Wappen liegt an drei Stellen (Datei, Modul, HoneyBar-Zeile), weil die
Leiste nichts nachladen kann. TestWappenIstUeberallDasselbe haelt sie gleich.
Aus dem Zettel wird die Notiz: Der Text steht immer formatiert da, roh ist nur
die Zeile mit der Schreibmarke. Dazu eine kleine Werkzeugleiste (Aufgabe,
Aufzaehlung, Nummer, Ueberschrift, fett, Linie), Enter fuehrt Listen fort,
Backspace am Zeilenanfang nimmt erst den Vorsatz. Fuer groessere Umbauten
bleibt der Quelltext-Knopf.
Kein contenteditable: Der Quelltext bleibt die Wahrheit und wird nie aus dem
HTML zurueckgerechnet, das der Browser beim Tippen erzeugt.
Reihenfolge und An/Aus der Widgets liegen jetzt je Nutzer auf dem Server, in
einer Einstellung ("benutzer,notiz,-system,wetter,bild"). Der Schalter fuer das
Wetter auf dem Schreibtisch faellt damit weg — es ist ein Widget wie jedes
andere.
Die Einstellungen sind in Abschnitte sortiert (Darstellung, HoneyBar, Widgets,
Wetter, Programme, Konto), Beschriftung links, Schalter rechts.
widgetAnmelden({ id, titel, wo, sichtbar, laden, leer, inhalt, takt }) —
der Rahmen macht daraus ein Fenster in der Spalte (Terminal) oder ein
Schild (Desktop), kennt lädt/fertig/nichts da/Fehler und haelt den
Nachladetakt. Benutzer, Wetter und Systemzustand sind umgestellt; aus
index.html sind vier feste Kaesten verschwunden und aus dem Raster die
Einzelplaetze.
Zwei Dinge, die erst dabei sichtbar wurden:
- Der Server meldete 'kein Ort eingestellt' und 'Dienst nicht
erreichbar' beide als 204. Ein Ausfall sah damit aus wie ein
abgeschaltetes Widget. Ausfall ist jetzt 502, mit Test.
- Die Reihenfolge haengt nicht mehr an der Modulauswertung: Seit
glyphs.js seine Raster mit await auf oberster Ebene laedt, laufen
Module ohne Symbole vorher durch — der Systemzustand stand deshalb
ueber dem Benutzer. widgetsOrdnen() macht die Reihenfolge zur Angabe,
und genau dort haengt spaeter die im Server gespeicherte ein.
Sortiert wird im Programm-Editor mit Pfeilen in der Kopfzeile jeder Zeile —
das Array ist die Reihenfolge, also gilt sie ueberall zugleich: Streifen,
Schublade, Kacheln, Schreibtischsymbole, Startmenue. Neue Apps haengen sich
hinten an, statt eine Taste zu verlangen.
Die Zifferntasten sind ganz weg (Marcs Entscheidung): ein Pflichtfeld je
App, das beim Sortieren nur die Frage aufgeworfen haette, ob es mitwandert.
Damit faellt das Feld 'key' aus dem Datenmodell, aus der Kachel, aus der
Hilfe und aus der Statuszeile. Alte Eintraege verlieren es beim naechsten
Speichern still.
Kein A-Z-Knopf — erstmal zu viel, kommt zurueck wenn er fehlt.
Der Schluessel kennt keinen Nutzer und landete beim Standardnutzer — auch
dann, wenn die App unter derselben Site liegt und der Browser das
HoneyOS-Cookie laengst mitschickt (cloud.honeyos.… und honeyos.… sind
dieselbe Site, duckdns.org steht auf der Public-Suffix-Liste). Damit trug
die HoneyBar in Aether die Farben eines fremden Nutzers.
Jetzt sieht /api/apps erst nach der Sitzung, und nur bei eigener
Anmeldung: Im offenen Betrieb und hinter einem Anmelde-Proxy gilt jede
Anfrage als angemeldet, dort bleibt der Schluessel das letzte Wort.
Test dazu, mit zwei Nutzern, damit der Rueckfall auf den einzigen Nutzer
das Ergebnis nicht zufaellig richtig aussehen laesst.
Der Pfeil rechts klappt in beiden Leisten ein Raster auf statt einer
Liste. Symbol gross, Name, Untertitel als dritte Zeile — der stand
bisher nur auf den Kacheln.
Entschieden gegen Symbol allein: Acht geteilte Glyphen identifizieren
nicht, zwei Apps koennen dieselbe Wolke tragen. Und die Schublade macht
man auf, weil man sucht — der Streifen ist der Ort fuers Wiedererkennen,
dort sind die Symbole abschaltbar.
Dazu 1.4 (CORS in Aether) und 1.5 (Cookie-Sitzung fuer InkNote) aus den
Ideen gestrichen: Widgets, die Daten aus den eigenen Apps holen, sind
nicht mehr gewollt. Der Rest ist neu durchnummeriert.
Die HoneyBar kommt bei fremden Apps ueber deren eigenen Ursprung — das
loest CSP, CORS und COEP auf einmal, setzt sie aber auch deren Zwischen-
speicher aus. Eine alte HoneyBar dort sieht aus wie ein Fehler in HoneyOS.
Statt no-cache jetzt no-store, must-revalidate; dazu ein Abschnitt in der
README, wie man einen haengengebliebenen Stand erkennt.
Und der nginx davor heisst nicht mehr 'Einsetzer', sondern HoneyBar-Proxy
(Dienst und Behaelter honeybar-proxy bzw. <app>-honeybar). Er ist ein
Reverse Proxy, der die HoneyBar einsetzt — der alte Name sagte das
Gegenteil von dem, was man im docker ps sehen will. LEISTE_PORT heisst
jetzt HONEYBAR_PROXY_PORT.
Die Pixelraster stehen jetzt in web/glyphs.json — einmal. Der Schreibtisch
laedt die Datei selbst, die HoneyBar bekommt sie mit der App-Liste mit;
sie bleibt damit eine einzelne Datei ohne zweite Anfrage. Die abgetippten
Wettersymbole in honeybar.js sind weg, und die Symbolauswahl im
Programm-Editor kommt jetzt aus derselben Datei statt aus einer Liste im
Quelltext.
Neu: Symbole neben den App-Namen im Streifen beider Leisten, mit einem
Schalter (Einstellungen -> HoneyBar) fuer beide zugleich. In den
Aufklappmenues und auf den Kacheln stehen sie immer.
Marcs Entscheidung: In der HoneyBar fremder Apps steht kein Abmelden mehr
— es war dort ohnehin nur ein Link auf den Schreibtisch. Als einzige
Schaltflaeche, die eine Sitzung beendet, steht es jetzt an genau einer
Stelle: unten in den Einstellungen, sichtbar nur bei eigener Anmeldung.
Damit faellt auch der ?abmelden=1-Pfad wieder weg und /api/apps braucht
das oidc-Feld nicht mehr.
Das Zahnrad rechts in der Menueleiste ist durch den Pfeil mit der
App-Liste ersetzt — derselbe wie in der HoneyBar. Beide Leisten tragen
damit dieselben vier Dinge: Logo, Apps, Wetter/Uhr, Aufklappmenue.
Das ■ HONEYOS ist jetzt ein Menue statt eines Links: Schreibtisch,
Einstellungen, HoneyBar einklappen, Abmelden. In fremden Apps sind es
Links auf den Schreibtisch (?einstellungen=1 / ?abmelden=1), weil die
HoneyBar dort nicht schreiben darf — Sitzung und CSRF-Pruefwort ueber-
leben die Site-Grenze nicht, und ein Abmelden per Aufruf koennte jede
Seite ausloesen.
Der Abmeldeknopf in der Menueleiste faellt weg (stand doppelt), und
Abmelden erscheint nur, wenn HoneyOS ueberhaupt anmeldet — dafuer gibt
/api/apps jetzt oidc mit heraus. Nebenbei: restliche 'Leiste' im Text
zu 'HoneyBar' vereinheitlicht.
Go: store, auth, weather und config sind eigene Pakete unter internal/. Vorher
lagen fuenf Dateien in einem Topf, und jede kannte jede.
Web: os.js hatte 1425 Zeilen und alles darin. Jetzt core.js (Zustand, Server,
Einstellungen), glyphs.js (die Pixelraster), js/widgets/ mit einem Widget je
Datei, os.js nur noch die Ansichten. Stylesheet nach css/.
Die HoneyBar bleibt eine einzelne Datei ohne Importe — sie wird von fremden
Seiten mit einer Zeile eingebunden, da darf nichts nachladen.
Nebenbei: Das gebaute Binary lag mit 9,8 MB im Repo und ist jetzt ignoriert.
Und der Test gegen eine zweite Versionsnummer geht nicht mehr auf os.js, sondern
durch alle .js — sonst haette ihn dieser Umbau still ausgehebelt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beides brachte allein einen Anzeigenamen. Seit der Benutzer als Widget auf dem
Schreibtisch steht, kommt der aus der HoneyOS-Anmeldung — keine App muss mehr
etwas dafuer bereitstellen, und beide Leisten tragen ueberall dasselbe.
Der Token-Schluessel hatte zudem eine scharfe Kante: Zeigte das Feld
Wer-bin-ich auf eine fremde Adresse, ging der Ausweis der App dorthin.
Weg sind damit auch checkAuth, askMe und die Anmeldezeile auf den Kacheln. Alte
honeyos.json-Dateien werden weiter gelesen; die Felder verfallen beim naechsten
Speichern still.
1.0, weil die Bedienung sich aendert und der Stand rund ist: zwei Leisten mit
gleichem Inhalt, Widgets fuer Benutzer und Wetter, die HoneyBar auch in fremden
Apps.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Dienst im Beispiel heisst jetzt einsetzer — er ist nicht die HoneyBar,
er setzt sie ein. Zusammensetzungen wie Menueleiste, Taskleiste und
Statusleiste bleiben, die meinen etwas anderes.
Dazu in IDEAS notiert, dass HoneyBar und Menueleiste zwei getrennte Stilsaetze
sind und schon einmal auseinandergelaufen ist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
In der Oberflaeche hiess das Feld Kennung, in der Konfiguration id, in der
README beides. Drei Namen fuer dieselbe Sache, und man muss sie beim Eintragen
zusammenbringen — jetzt ueberall ID.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Weg 1 fuer selbst geschriebene Apps, Weg 2 fuer fertig bezogene — mit dem
Vorher/Nachher an der Compose-Datei der App und dem, was der Einsetzer kostet.
Dabei richtiggestellt, dass Aether und InkNote die Leiste zur Laufzeit laden
statt sie ins HTML zu schreiben; die README beschrieb noch den alten Stand.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Am Host erkennt nginx, welcher Dienst gemeint ist und welche App das fuer
HoneyOS ist; die Leiste hebt sie dann hervor wie in Aether. Dieselbe Bauart wie
im BentoPDF-Beispiel: Leiste und ihre zwei Abfragen laufen ueber die Adresse
der App, damit deren CSP unangetastet bleibt.
Die beiden .conf-Dateien sind weg — sie standen ein zweites Mal in der
Compose-Datei, und zwei Fassungen derselben Sache laufen auseinander. Heute
schon zweimal passiert.
Geprueft mit zwei Diensten: richtige Kennung je Host, richtige Hervorhebung in
der Leiste, gemeinsame App-Liste, Wetter.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Marcs BentoPDF-Image (ghcr.io/alam00000/bentopdf-simple) schickt eine strenge
CSP — mit dem Image von Docker Hub, an dem ich zuerst geprueft hatte, war das
nicht zu sehen. Statt fremde Kopfzeilen umzuschreiben, reicht der Einsetzer
jetzt auch /honeybar/ und die zwei Abfragen der Leiste unter seiner eigenen
Adresse durch. Damit ist fuer den Browser alles derselbe Ursprung: CSP
unangetastet, kein CORS, kein COEP, und der Schluessel bleibt auf dem Server.
Durchgereicht wird nur /api/apps und /api/weather, nur lesend. Ein pauschales
/api/ haette die ganze Schnittstelle unter die Adresse der App gehaengt — beim
Ausprobieren hat meine eigene Schreibprobe prompt die App-Liste geleert.
Das Binden auf 127.0.0.1 ist raus: Es passt nur, wenn der Proxy auf demselben
Wirt im Host-Netz laeuft, und nicht fuer Marcs Aufbau.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Getrennt gepflegt hiesse, bei jeder neuen App an zwei Stellen zu denken. Das
Netz legt der Stapel selbst unter festem Namen an — vorher musste es von Hand
erzeugt werden, und ohne festen Namen hiesse es nach dem Ordner.
Durchprobiert: Stapel hoch, fremde App tritt dem Netz bei, beide Hosts bekommen
die richtige data-app, unbekannter Host 404.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Am Host erkennt nginx den Dienst; eine neue App sind zwei Zeilen. Geprueft mit
zwei Diensten gleichzeitig: richtige data-app je Host, unbekannter Host 404,
WebSocket-Upgrade durchgereicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Compose und nginx-Konfiguration, genau so durchprobiert. Dazu der Hinweis, dass
der Ursprung in HoneyOS auf den Buchstaben passen muss: localhost und 127.0.0.1
sind fuer den Browser zwei verschiedene.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Apps, die COEP „require-corp" setzen — alles mit WASM oder SharedArrayBuffer,
etwa BentoPDF — lehnen jede fremde Datei ab, die sich nicht ausdruecklich zur
Einbettung bekennt. Genau das ist der Zweck der Leiste, also sagt sie es jetzt.
Die Alternative waere gewesen, im Proxy das COEP der App zu entfernen. Das
haette ihr die Faehigkeiten genommen, fuer die sie es setzt.
Gefunden beim Einsetzen in BentoPDF hinter einem nginx.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Rezept fuer nginx, geprueft gegen eine App mit gzip und eigener CSP. Die vier
Fallen stehen dabei: Kompression, CSP ersetzen statt ergaenzen, nur HTML
anfassen, Ursprung in HoneyOS eintragen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei Schalter, unabhaengig voneinander: Schreibtisch, Leiste, beides oder
keins. Die Stadt wird einmal gesucht und mit ihren Koordinaten gespeichert,
sonst suchte jede Abfrage den Ort erneut.
Geholt wird serverseitig und zehn Minuten zwischengespeichert. Der Grund ist
nicht Sparsamkeit: Die Leiste steht auf jeder Seite jeder App, und fragte sie
selbst an, ginge bei jedem Seitenaufruf eine Anfrage samt IP an einen Fremden —
und die CSP jeder App muesste ihn erlauben.
Kein Ort eingestellt oder Dienst nicht erreichbar: 204, und das Symbol bleibt
weg. Eine Zahl von gestern waere schlechter als keine.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Oberfläche zeigte 0.2, während die Images schon 0.4 hiessen: os.js trug
eine eigene Konstante, die ich beim Taggen nie mitgezogen habe.
Jetzt steht sie nur noch in main.go. build.sh liest sie von dort und vergibt
denselben Tag, die Oberfläche holt sie über /api/public und /api/me. Ein Test
schlaegt an, falls je wieder eine zweite Version in os.js auftaucht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Marc stellt Pangolin davor und will keinen zweiten Anmeldeschirm.
- HONEYOS_PROXY_AUTH=true: HoneyOS prüft nicht mehr selbst, der Start sagt
deutlich, dass der Container dann nur über den Proxy erreichbar sein darf.
Mit HONEYOS_USER_HEADER bekommt jeder Name seine eigenen Einstellungen.
- HONEYOS_APPS_KEY schützt /api/apps. Nötig, weil HoneyOS auf einer anderen
Site liegt als die Apps (duckdns.org steht auf der Public-Suffix-Liste) –
der Browser schickt die Sitzung dort nicht mit, und der Pfad muss im Proxy
von der Anmeldung befreit sein.
Beim Durchspielen mit zwei echten Hostnamen fiel ein Loch auf: Ohne eigene
Anmeldung gilt jede Anfrage als angemeldet, also gab der Rückfall auf diese
Prüfung die Liste an jeden heraus – auch ohne oder mit falschem Schlüssel.
Der Rückfall greift jetzt nur noch, wo es wirklich eine Sitzung geben kann.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Leiste soll zuerst die serverseitige Röhre übernehmen — kleinster
Eingriff, größte Wirkung fürs "ein System"-Gefühl. Danach Systemmenü im
Logo, dann die App-Schublade mit Symbolen.
Neu als offene Entscheidung: wie sichtbar die Leiste sein darf. Sie ist bei
jedem Aufruf der App da, auch wenn man mit HoneyOS gerade nichts zu tun hat.
Vorschlag steht dabei, ebenso der Hinweis, dass es keine Einbahnstraße ist.
Ausserdem defer an der Script-Zeile in README und Demo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Aus der statischen Seite wird ein Go-Binary mit eingebetteter Oberfläche.
Grund: Apps über .env zu pflegen wurde unübersichtlich, und kosmetische
Einstellungen sollen auf jedem Gerät gleich sein.
- Anmeldung über den eigenen OIDC-Anbieter (PocketID), mit PKCE. Ohne
Anmeldung gibt es nichts zu sehen – auch keine App-Liste.
- Sitzung als signiertes Cookie ohne Gegenstück im Server; Schreibzugriffe
zusätzlich über ein lesbares CSRF-Cookie abgesichert
- Apps werden in der Oberfläche angelegt und bearbeitet, nicht mehr in der
.env. Der Server prüft jeden Eintrag und meldet zurück, was er behält.
- Einstellungen liegen je Nutzer im Server; localStorage ist nur noch der
Vorschuss, damit die Röhre beim Laden nicht in der falschen Farbe blitzt
- die Leiste holt die App-Liste aus /api/apps – freigegeben sind allein die
Ursprünge, die selbst als App eingetragen sind
- Tests fahren einen echten OIDC-Anbieter hoch und gehen den Anmeldeweg
einmal ganz durch
Ohne HONEYOS_OIDC_ISSUER läuft alles offen – für die Entwicklung, mit
deutlicher Warnung beim Start.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Statische Oberfläche vor Aether und InkNote: kein Backend, kein Build,
nginx liefert web/ aus. Jede App bleibt ihre eigene PWA auf ihrer eigenen
Domain – HoneyOS ist Startpunkt und Umschalter, kein iframe-Rahmen.
- zwei Betriebsarten aus einem Datenstand: Terminal (Kacheln, Tastatur)
und Desktop (Symbole, verschiebbare Fenster, Taskleiste)
- honeybar.js als Drop-in für die Apps, rendert im Shadow DOM, damit
Tailwind und die InkNote-Palette einander nicht in die Quere kommen
- Konfiguration vollständig aus der .env: das Skript in
/docker-entrypoint.d/ schreibt config.json beim Containerstart
- optionaler _ME-Pfad pro App zeigt an, wer angemeldet ist; ohne CORS
bleibt die Anzeige leer, ohne dass etwas kaputtgeht
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>