feat(deploy): add NixOS live USB ISO for ATM hardware testing

Add NixOS configuration to build a bootable live USB ISO that runs the
ATM Electron app in kiosk mode on physical hardware (UpBoard). The ISO
boots from squashfs, auto-starts X11/openbox, and launches Electron in
production mode.

Key changes:
- deploy/nixos/live.nix: Live USB module (squashfs+tmpfs, no disk install)
- deploy/nixos/flake.nix: Nix flake with ISO build output
- deploy/nixos/provision-atm.sh: Auto-provision LP credentials via API
- deploy/nixos/build-iso.sh: End-to-end build workflow script
- apps/machine: Fix Electron production mode (ELECTRON_FORCE_PROD),
  Vue Router hash mode for file:// protocol, relative asset paths

Build: cd deploy/nixos && bash build-iso.sh
Test:  qemu-system-x86_64 -enable-kvm -m 2G -cdrom result/iso/*.iso

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Patrick Mulligan 2026-02-18 20:11:23 -05:00
commit 19d43c2939
13 changed files with 1203 additions and 3 deletions

View file

@ -40,7 +40,9 @@ function loadEnvFile() {
loadEnvFile()
// Determine if we're in development
const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged
const isDev =
process.env.ELECTRON_FORCE_PROD !== '1' &&
(process.env.NODE_ENV === 'development' || !app.isPackaged)
// Window dimensions (vertical ATM display)
const WINDOW_WIDTH = 1080

View file

@ -1,6 +1,6 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createRouter, createWebHistory } from 'vue-router'
import { createRouter, createWebHashHistory } from 'vue-router'
import App from './App.vue'
import './style.css'
@ -11,7 +11,7 @@ import CashInView from './views/CashInView.vue'
// Create router
const router = createRouter({
history: createWebHistory(),
history: createWebHashHistory(),
routes: [
{ path: '/', name: 'idle', component: IdleView },
{ path: '/cash-out', name: 'cash-out', component: CashOutView },

View file

@ -5,6 +5,8 @@ import tailwindcss from '@tailwindcss/vite'
// https://vitejs.dev/config/
export default defineConfig({
// Use relative paths so assets load correctly with file:// protocol (Electron production)
base: './',
plugins: [vue(), tailwindcss()],
resolve: {
alias: {