- Redesign settings page with tabbed layout (Device, Display, Scale, Updates)
- Add screen blank timeout: blanks after touch inactivity, tap to wake
- Add CSS brightness filter for HDMI displays (no sysfs on HDMI)
- Add backend `language` field to app settings for server-side persistence
- Sync UI language from backend on kiosk load (separate Chromium instance)
- Top bar clock respects user's time format setting (system/12h/24h)
- Add SpoolBuddy settings translations for all 6 languages (en/de/fr/ja/it/pt-BR)
- Disable Chromium swipe-to-navigate in kiosk install script
- Add `video` group for DSI backlight access
Root cause: The daemon used wlopm for screen blanking, but wlopm was never installed. Additionally, the daemon runs as the spoolbuddy system user which has no access to
the Wayland socket, so Wayland-based tools can't work.
Fix in display_control.py:
- Replaced wlopm --off/--on with vcgencmd display_power 0/1 — this is a Raspberry Pi firmware-level command that's pre-installed and works without Wayland socket access
- Added shutil.which("vcgencmd") check at init to avoid repeated failures on non-RPi hardware
- Added explicit PermissionError handling for brightness writes with a helpful message about the video group
Fix in install.sh:
- Added video group to the spoolbuddy service user's groups (was: gpio, spi, i2c → now: gpio, spi, i2c, video), which grants access to both vcgencmd and sysfs backlight
files
Scale Tab Numpad
Root cause: On the 1024x600 kiosk screen (~376px available content height), the weight info card + numpad + action buttons exceeded the space, causing tiny buttons and
overlapping.
Fix in SpoolBuddySettingsPage.tsx:
- Hide the weight info card during weight entry step (calStep !== 'weight'), reclaiming ~70px
- Compact inline weight reading in the step header (small dot + monospace text) so users can still see the live scale value
- Larger numpad buttons: min-h-[56px] with text-lg font size (was no min-height, text-sm)
- Added active:scale-95 for tactile touch feedback
- mt-auto on action buttons to push them to the bottom, preventing overlap
- Removed the wrapping card around the calibration flow to save vertical padding
When Bambuddy auth is enabled, the SpoolBuddy kiosk gets redirected to
the login page because ProtectedRoute requires a user from GET /auth/me,
which only handled JWT tokens. The kiosk daemon already has an API key
but couldn't use it to satisfy the frontend auth check.
- Backend: /auth/me now accepts API keys (Bearer bb_xxx or X-API-Key)
and returns a synthetic admin UserResponse with all permissions
- Frontend: AuthContext reads ?token= from URL on first load, stores in
localStorage, and strips from URL (prevents history/referrer leakage)
- Install script: kiosk URL now includes ?token=${API_KEY}
- Tests: 3 new integration tests (Bearer API key, X-API-Key header,
invalid key rejection)