feat(machine): operator branding — local-file source (issue #47 V1)
Read /var/lib/bitspire/branding/{logo.png,branding.json} on startup and
apply across the renderer. branding.json may set title, theme (one of
the 6 built-ins or "custom"), and a custom_colors map (with optional
.dark overlay) — unset CSS vars fall back to gruvbox.
Wiring:
- electron/main.ts:loadBranding() reads + validates the JSON and
base64-encodes logo.png; surfaced via the existing get-config IPC
- composables/useBranding.ts holds reactive logoUrl/title refs and a
single setBranding() setter — the seam where #48's Nostr-event
source will eventually overlay the local-file source
- composables/useTheme.ts:applyBrandingTheme() handles built-in theme
swap and injects a <style#branding-custom-theme> block for custom
- IdleView binds :src/title; App.vue calls setBranding() before the
maintenance screen renders so "Under Service" wears operator branding
Provisioning: new deploy/nixos/provision-branding.sh rsyncs a local dir
to /var/lib/bitspire/branding/ via sudo-on-the-far-side and restarts
bitspire.service. The existing provision-atm.sh stays focused on .env.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
264cc47e0c
commit
c3353c409b
10 changed files with 268 additions and 3 deletions
|
|
@ -157,6 +157,7 @@ Production ATMs on `main` continue to read `main`'s flake (no `?ref=` pin → re
|
|||
| `/var/lib/bitspire/.env` | bitspire:bitspire, 0600 | Runtime config — `VITE_RELAY_URL`, `VITE_LNBITS_SERVER_PUBKEY`, `VITE_LNBITS_HTTP_URL`, `VITE_ATM_PRIVATE_KEY`, … |
|
||||
| `/var/lib/bitspire/state.db` | bitspire:bitspire | SQLite — cassette inventory, cashbox state, transaction history |
|
||||
| `/var/lib/bitspire/logs/` | bitspire:bitspire, 0750 | Service logs (if app writes them) |
|
||||
| `/var/lib/bitspire/branding/` | bitspire:bitspire, 0755 | Operator branding override (logo.png + branding.json) — see issue #47 |
|
||||
| `/opt/bitspire/` | bitspire:bitspire | Optional override drop for app assets (mostly unused — app comes from `/nix/store`) |
|
||||
| `/etc/bitspire/config.env` | root:root | Static config emitted by the NixOS module (RELAY_URL, LNBITS_HTTP_URL — informational; the renderer reads `/var/lib/bitspire/.env` instead) |
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,8 @@ in
|
|||
systemd.tmpfiles.rules = [
|
||||
"d ${cfg.dataDir} 0750 bitspire bitspire -"
|
||||
"d ${cfg.dataDir}/logs 0750 bitspire bitspire -"
|
||||
# Operator branding override target (issue #47); empty by default
|
||||
"d ${cfg.dataDir}/branding 0755 bitspire bitspire -"
|
||||
];
|
||||
|
||||
# Environment file for ATM configuration
|
||||
|
|
|
|||
61
deploy/nixos/provision-branding.sh
Executable file
61
deploy/nixos/provision-branding.sh
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env bash
|
||||
# Provision operator branding (logo + branding.json) to a deployed bitSpire ATM.
|
||||
# Composes with provision-atm.sh — that one wires LNbits creds, this one wires
|
||||
# operator look-and-feel. Per issue #47.
|
||||
#
|
||||
# Usage:
|
||||
# bash provision-branding.sh <branding-dir> # SSH to localhost:2222 (QEMU)
|
||||
# bash provision-branding.sh <branding-dir> 192.168.1.50 # SSH to a real ATM on the LAN
|
||||
# bash provision-branding.sh <branding-dir> 192.168.1.50 22 # custom SSH port
|
||||
#
|
||||
# Expected files in <branding-dir>:
|
||||
# logo.png — operator logo (any reasonable size; rendered ~12vh)
|
||||
# branding.json — { title, theme, custom_colors{...}, custom_colors.dark{...} }
|
||||
#
|
||||
# Either file is optional; the on-disk schema in /var/lib/bitspire/branding/
|
||||
# matches whatever <branding-dir> contains (rsync --delete).
|
||||
set -euo pipefail
|
||||
|
||||
BRANDING_DIR="${1:-}"
|
||||
ATM_HOST="${2:-localhost}"
|
||||
ATM_SSH_PORT="${3:-2222}"
|
||||
ATM_USER="bitspire"
|
||||
REMOTE_DIR="/var/lib/bitspire/branding"
|
||||
|
||||
if [ -z "$BRANDING_DIR" ]; then
|
||||
echo "Usage: $0 <branding-dir> [host] [port]" >&2
|
||||
echo " $0 ./acme-brand (QEMU on localhost:2222)" >&2
|
||||
echo " $0 ./acme-brand 192.168.1.50 (real ATM)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -d "$BRANDING_DIR" ]; then
|
||||
echo "ERROR: branding directory not found: $BRANDING_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "=== Provisioning branding to $ATM_HOST:$ATM_SSH_PORT ==="
|
||||
echo "Local dir : $BRANDING_DIR"
|
||||
echo "Remote dir: $REMOTE_DIR"
|
||||
echo ""
|
||||
|
||||
# Show what we're about to push so the operator can sanity-check before sync.
|
||||
ls -la "$BRANDING_DIR"
|
||||
echo ""
|
||||
|
||||
# rsync over SSH. --delete to clean stale files (a removed logo.png should
|
||||
# disappear, not linger). sudo on the remote side because /var/lib/bitspire
|
||||
# is owned by the bitspire service user, not the SSH user.
|
||||
rsync -avz --delete \
|
||||
--rsync-path="sudo rsync" \
|
||||
-e "ssh -o StrictHostKeyChecking=no -p $ATM_SSH_PORT" \
|
||||
"$BRANDING_DIR/" \
|
||||
"$ATM_USER@$ATM_HOST:$REMOTE_DIR/"
|
||||
|
||||
# Restart the service so loadBranding() re-runs and the renderer picks up the
|
||||
# new files. V2 (Nostr-event source) will eliminate the restart need.
|
||||
ssh -o StrictHostKeyChecking=no -p "$ATM_SSH_PORT" "$ATM_USER@$ATM_HOST" \
|
||||
"sudo systemctl restart bitspire"
|
||||
|
||||
echo ""
|
||||
echo "=== Branding provisioned. Service restarted. ==="
|
||||
Loading…
Add table
Add a link
Reference in a new issue