Commit Graph
7 Commits
Author SHA1 Message Date
Kerim (portable/claudecode)andClaude Opus 5 0e8d826bce Drucker wird in der App gewaehlt, nicht auf dem Pi
Deploy auf den Timer-Server / deploy (push) Successful in 20s
Das Einrichtungsskript fragte bisher am Pi, welcher Drucker bedient werden
soll. Damit stand die Einstellung an einem Ort, an den man nur mit einem
Terminal kommt - und ein zweiter Drucker am Pi bedeutete: Skript nochmal.

Jetzt fragt die App den Pi, was angeschlossen ist, und der Bediener waehlt in
den Einstellungen. Die Bruecke bekam dafuer /devices; sie liest die
Klartextnamen aus dem sysfs, damit dort "EPSON TM-T88IV" steht und nicht
"lp0" - bei zwei Druckern der Unterschied zwischen Wissen und Raten.

Der gewaehlte Pfad geht bei jedem Auftrag im Kopf X-Print-Device mit. Die
Bruecke haelt dazu bewusst keinen Zustand und das Skript schreibt kein
PRINT_DEVICE mehr: es soll genau eine Stelle geben, die weiss, welcher Drucker
gemeint ist, naemlich die, an der es bedient wird. Leer bleibt "automatisch" -
das erste gefundene Geraet, zugleich der Rueckfall, wenn aus lp0 nach dem
Umstecken ein lp1 geworden ist.

Der Pfad kommt damit von aussen und wird an beiden Enden geprueft, in
PUT /api/settings und noch einmal in der Bruecke. Eine Schranke, die nur an
einem Ende steht, ist keine: ohne die Pruefung auf dem Pi liesse sich der
Dienst dazu bringen, in eine beliebige Datei zu schreiben.

Nebenbei: ein nicht bereiter Drucker meldete sich in der Oberflaeche als
"HTTP 503". Das verriet niemandem, dass nur ein Stecker lose ist. Die 503 der
Bruecke ist kein Protokollfehler, und ihr Rumpf sagt, was fehlt - der wird
jetzt ausgewertet.

Geprueft am echten Pi (Debian 13, TM-T88IV): Einrichtung ohne Rueckfrage,
Geraeteliste mit Namen, ausdrueckliche Wahl, Druck darauf, Rueckkehr auf
automatisch, Druck darauf. Dazu die Abweise: /etc/passwd und ein Pfad mit
angehaengtem Befehl werden zurueckgewiesen, ein erlaubtes aber fehlendes
/dev/usb/lp7 ergibt eine Meldung im Klartext.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 13:46:50 +02:00
Kerim (portable/claudecode)andClaude Opus 5 e68daee457 Drucker-Pi holt sich die Einrichtung, statt sie geschickt zu bekommen
Bisher richtete die App den Pi per SSH ein: Adresse, Benutzer und Passwort ins
Webformular, Knopf druecken. Das verlangte ein SSH-Passwort in einem Browser,
ein weiteres Paket (ssh2) und eine Verbindung vom Server zum Pi.

Jetzt andersherum. Die App legt einen Link bereit und wartet. Auf dem Pi wird
das Skript geholt und gestartet, dort wird der Drucker ausgewaehlt, und am
Ende meldet sich der Pi von selbst an. Wer einen Drucker ansteckt, steht
ohnehin am Pi - dort gehoert auch die Frage hin, welcher es sein soll.

Die Auswahl zeigt Klartextnamen aus dem sysfs: "EPSON TM-T88IV" statt "lp0".
Bei mehreren Druckern ist das der Unterschied zwischen Wissen und Raten.

Das ausgelieferte Skript ist zusammengesetzt, nicht statisch: einrichten.sh ist
eine Vorlage, in die setup.js Adresse, Code, print-server.py und die
systemd-Unit einsetzt. Heraus kommt EINE Datei - auf dem Pi ist nichts
nachzuladen, und eine halb geglueckte Uebertragung kann es nicht geben.

Zwei Endpunkte muessen ohne Anmeldung auskommen, weil der Pi sich bei Authentik
nicht anmelden kann. Der Einrichtungscode ist dort der einzige Schluessel: 32
Zeichen, gilt einmal und 30 Minuten, nur im Arbeitsspeicher, zeitkonstant
verglichen, hinter einem eigenen Zaehler.

Die Adresse des Pi wird der Verbindung entnommen und nicht dem Rumpf der
Anmeldung - was der Pi ueber sich behauptet, koennte auch jemand anders
behaupten. Die eigene Adresse leitet die App aus dem Host-Kopf ab und prueft
sie streng, statt sie zu maskieren: der Wert landet in einem Shell-Skript.

Geprueft am echten Pi (Debian 13, TM-T88IV): Link erzeugen, am Pi abholen,
Drucker aus der Liste waehlen, Anmeldung, Uebernahme, Probedruck. Dazu die
Abweise: verbrauchter Code, falscher Code, Abholung ohne Code, und dass die
uebrige API weiterhin 401 liefert.

Entfaellt: provision.js, install.sh, die Abhaengigkeit ssh2, das SSH-Formular.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 13:37:26 +02:00
Kerim (portable/claudecode)andClaude Opus 5 8c5cdf16c4 Strichcode ohne Beschriftung und ohne Klarschrift drucken
Deploy auf den Timer-Server / deploy (push) Successful in 15s
Die Zeile "Artikel fuer die Kasse" und die Klarschrift, die der Drucker unter
den Code setzt, fallen weg. Beide zeigten einem Kunden einen internen
Artikelnamen, der ihn nichts angeht - der Code steht jetzt fuer sich.

Die Klarschrift bleibt nur dort, wo sie der einzige Informationstraeger ist:
passt der Name nicht auf die Papierbreite, wird gar kein Code gedruckt und der
Name allein bleibt uebrig.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 13:23:55 +02:00
Kerim (portable/claudecode)andClaude Opus 5 6ba0cdd07f Strichcode mit dem Kassenartikel auf den Bon drucken
Der Kassierer musste den Artikel bisher von Hand in der Kasse suchen. Jetzt
steht er als Strichcode unter dem Betrag und wird gescannt.

CODE128 in Zeichensatz B, nicht das sonst uebliche CODE39: dort sind nur
Grossbuchstaben erlaubt, ein Artikel namens "techniker" waere damit nicht
darstellbar. Die Modulbreite waehlt escpos.js so gross, wie die Papierbreite
zulaesst - breitere Balken liest ein Handscanner zuverlaessiger, gerade auf
Thermopapier, das einen Tag in einer Hosentasche hinter sich hat. Daraus
ergibt sich die Laengengrenze von 17 Zeichen bei 80 mm Papier.

Artikelname und An/Aus liegen in den Einstellungen, nicht im Code: der Name
haengt am Artikelstamm der Kasse und kann sich aendern, ohne dass jemand an
die App muss.

Zwei Faelle, die sonst still danebengingen, melden sich jetzt:
- Umlaute und Sonderzeichen weist das Speichern ab, statt sie zu verschlucken
  und einen Code zu drucken, der einen anderen Artikel bedeutet.
- Passt der Name nicht auf die Papierbreite, druckt receipt.js ihn nur in
  Klarschrift. Ein abgeschnittener Code wird von keinem Scanner gelesen.

Geprueft auf dem Epson TM-T88IV: Zwischenbeleg und Endbeleg, ausgeschalteter
Strichcode, Laengengrenze, geschweifte Klammer im Namen (wird verdoppelt,
sonst liest der Drucker sie als Umschaltbefehl).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 13:19:39 +02:00
Kerim (portable/claudecode)andClaude Opus 5 5e23ccdcbc Drucker-Pi aus der Oberflaeche heraus einrichten
Die Einrichtung war Handarbeit: Dateien per scp auf den Pi, dort install.sh
mit sudo starten, Token abschreiben, in die .env eintragen, Dienst neu
starten. Das ist genau die Sorte Arbeit, die beim naechsten Geraetetausch
niemand mehr weiss. Jetzt macht das ein Knopf unter "Einstellungen":
Adresse, Benutzer und Passwort eintragen, und die App meldet sich per SSH an,
prueft Python/systemd/Druckergeraet, uebertraegt deploy/bondrucker/, startet
install.sh mit einem selbst erzeugten Token, raeumt auf und prueft von aussen
nach. Jeder Schritt steht mit Ergebnis im Protokoll.

Damit das ueberhaupt Sinn ergibt, liegt der Druckerzugang jetzt in der
Datenbank statt in der .env - sonst muesste hinterher doch wieder jemand auf
den Server. Die PRINTER_*-Werte in der .env sind nur noch Startwerte beim
allerersten Start, wie RATE_PER_10MIN auch.

Zwei Fehler, die beim Testen der Einrichtung auffielen:

install.sh startete den Dienst nicht neu, sondern nur "enable --now". Bei
einer erneuten Einrichtung lief die Bruecke deshalb mit dem ALTEN Token
weiter und lehnte jeden Bon mit HTTP 403 ab. Jetzt: restart.

Die Gegenprobe fragte nur /status ab - und /status prueft kein Token. Ein
Dienst mit altem Token galt damit faelschlich als bereit. Die Bruecke meldet
in /status jetzt zusaetzlich, ob das mitgeschickte Token passt (Version 1.1),
und die Einrichtung prueft das mit.

Zugangsdaten werden einmal benutzt und danach vergessen; das erzeugte Token
wird aus dem Protokoll entfernt, bevor es in den Browser oder ins Journal
geht. Neu dabei: ssh2, reines JavaScript.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 20:59:56 +02:00
Kerim (portable/claudecode)andClaude Opus 5 70756f3762 Bon fuer die Kasse auf einem USB-Bondrucker ausgeben
Der Kunde soll mit einem Zettel zur Kasse gehen koennen, auf dem steht, was
er zahlen muss. Drei Wege fuehren jetzt zu einem Bon: der Knopf "Bon" auf der
Timer-Karte druckt den Zwischenstand und laesst den Timer weiterlaufen,
"Beenden" druckt den Endbeleg, und in der Historie laesst sich jeder Beleg
nachdrucken.

Der Drucker haengt per USB an einem Raspberry Pi und ist damit vom
Timer-Server aus nicht direkt erreichbar. Auf dem Pi laeuft deshalb eine
kleine Bruecke (deploy/bondrucker/, nur Python-Standardbibliothek), die
fertige ESC/POS-Daten per HTTP annimmt. Das Bon-Layout bleibt bewusst hier
im Repo, damit Aenderungen daran nicht auf dem Pi angefasst werden muessen.

Beim Beenden wird erst gespeichert und dann gedruckt. Eine leere Papierrolle
ist damit ein Papierproblem und kein Datenproblem - der Vorgang steht in der
Historie, die Oberflaeche sagt ausdruecklich, dass der Bon nicht gedruckt
wurde, und nennt den Grund.

Ohne PRINTER_HOST in der .env ist die Druckfunktion aus und die App verhaelt
sich unveraendert.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 20:37:12 +02:00
adminandClaude Opus 5 a7e77793a8 Timer-App unter Versionsverwaltung stellen
Stand der laufenden Anwendung von 192.168.1.5:/opt/timer-app (systemd-Dienst
timer-app, Port 3003). Zeiterfassung mit Kostenberechnung: Node/Express,
SQLite, Anmeldung ausschliesslich ueber Authentik (OIDC, PKCE, RP-Logout) -
der frueher vorhandene Passwort-Login ist entfernt.

Nicht im Repo, bewusst:
- backend/.env und die .env-Sicherung: enthalten Session-Secret und die
  Authentik-Zugangsdaten. Vorlage ist backend/.env.example.
- data/: die Datenbank mit den echten Zeiterfassungen.
- node_modules/.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-04 17:47:07 +02:00