refactor(rename): NixOS module + service + paths → bitspire

Five-file coordinated rename to give the dev-branch deploy a clean
`bitspire` namespace at the NixOS level:

  deploy/nixos/lamassu-atm.nix → deploy/nixos/bitspire-atm.nix
    - `services.lamassu-atm`           → `services.bitspire`
    - `systemd.services.lamassu-atm`   → `systemd.services.bitspire`
    - `/var/lib/lamassu-atm`           → `/var/lib/bitspire`
    - `/opt/lamassu-atm`               → `/opt/bitspire`
    - `/etc/lamassu-atm/config.env`    → `/etc/bitspire/config.env`

  flake.nix
    - module import path updated
    - `nixosModules.lamassu-atm` → `nixosModules.bitspire`
    - `system.activationScripts.lamassu-env` → `bitspire-env`
    - all activation-script paths point at /var/lib/bitspire

  deploy/nixos/configuration.nix
    - `networking.hostName = "lamassu-atm"` → `"bitspire"`

  deploy/nixos/live.nix
    - module import path updated
    - ISO name template: `lamassu-atm-<model>-live.iso` → `bitspire-<model>-live.iso`
    - activation-script name updated

  deploy/nixos/provision-atm.sh
    - data-dir paths: /var/lib/lamassu-atm → /var/lib/bitspire
    - systemctl + journalctl unit names updated

DELIBERATELY kept as `lamassu` (for now):
  - The `lamassu` UNIX user and group account. Renaming would
    require file-ownership migration scripts; the Sintra is a
    fresh flash so no existing data, but the internal user
    namespace inconsistency is acceptable.
  - LP-specific bits in provision-atm.sh (admin token, the
    `docker logs lamassu-lightning-pub` extractor) — those
    get ripped out in 3c when the script switches to LNbits.

NO migration activation script added — the Sintra flash is fresh,
production batm3/douro stay on `main` and never see this branch.
A future dev→main cutover will need a separate migration story
(rename UNIX user, move /var/lib/lamassu-atm → /var/lib/bitspire,
SSH key relocation, etc.).

Verified:
  nix eval .#nixosConfigurations.batm3-installed.config.systemd.services.bitspire.enable
    → true
  nix eval .#nixosConfigurations.bitSpire-live-sintra.config.networking.hostName
    → "bitspire"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-13 12:35:12 +02:00
commit 28a35ca479
5 changed files with 39 additions and 39 deletions

View file

@ -0,0 +1,240 @@
# Lamassu ATM Service Module
# Manages the ATM Electron application and related services
{ config, lib, pkgs, pkgs-unstable, ... }:
with lib;
let
cfg = config.services.bitspire;
in
{
options.services.bitspire = {
enable = mkEnableOption "Lamassu ATM service";
relayUrl = mkOption {
type = types.str;
default = "wss://relay.lamassu.is";
description = "Nostr relay URL for ATM communication";
};
lightningPubUrl = mkOption {
type = types.str;
default = "https://lp.lamassu.is";
description = "Lightning.Pub instance URL";
};
appDir = mkOption {
type = types.path;
default = "/opt/bitspire";
description = "Directory containing the ATM application";
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/bitspire";
description = "Directory for ATM data and configuration";
};
logLevel = mkOption {
type = types.enum [ "error" "warn" "info" "debug" ];
default = "info";
description = "Logging level for the ATM application";
};
# Hardware configuration
billValidator = {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable bill validator support";
};
device = mkOption {
type = types.str;
default = "/dev/ttyUSB0";
description = "Serial device for bill validator";
};
type = mkOption {
type = types.enum [ "id003" "mei" "ccnet" ];
default = "id003";
description = "Bill validator protocol type";
};
};
billDispenser = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable bill dispenser support (two-way machines)";
};
device = mkOption {
type = types.str;
default = "/dev/ttyUSB1";
description = "Serial device for bill dispenser";
};
type = mkOption {
type = types.enum [ "puloon" "genmega" ];
default = "puloon";
description = "Bill dispenser type";
};
};
camera = {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable camera for QR code scanning";
};
device = mkOption {
type = types.str;
default = "/dev/video0";
description = "Camera device";
};
};
};
config = mkIf cfg.enable {
# Create data directory
systemd.tmpfiles.rules = [
"d ${cfg.dataDir} 0750 lamassu lamassu -"
"d ${cfg.dataDir}/logs 0750 lamassu lamassu -"
];
# Environment file for ATM configuration
environment.etc."bitspire/config.env".text = ''
# Lamassu ATM Configuration
RELAY_URL=${cfg.relayUrl}
LIGHTNING_PUB_URL=${cfg.lightningPubUrl}
LOG_LEVEL=${cfg.logLevel}
DATA_DIR=${cfg.dataDir}
# Hardware
BILL_VALIDATOR_ENABLED=${boolToString cfg.billValidator.enable}
BILL_VALIDATOR_DEVICE=${cfg.billValidator.device}
BILL_VALIDATOR_TYPE=${cfg.billValidator.type}
BILL_DISPENSER_ENABLED=${boolToString cfg.billDispenser.enable}
BILL_DISPENSER_DEVICE=${cfg.billDispenser.device}
BILL_DISPENSER_TYPE=${cfg.billDispenser.type}
CAMERA_ENABLED=${boolToString cfg.camera.enable}
CAMERA_DEVICE=${cfg.camera.device}
# Display
DISPLAY=:0
ELECTRON_DISABLE_GPU=false
'';
# Main ATM service
systemd.services.bitspire = {
description = "Lamassu ATM Application";
wantedBy = [ "graphical.target" ];
after = [ "graphical.target" "network-online.target" ];
wants = [ "network-online.target" ];
serviceConfig = {
Type = "simple";
User = "lamassu";
Group = "lamassu";
WorkingDirectory = cfg.appDir;
# Environment
EnvironmentFile = "/etc/bitspire/config.env";
# Start the Electron app
ExecStart = "${pkgs-unstable.electron}/bin/electron ${cfg.appDir}";
# Restart policy
Restart = "always";
RestartSec = 5;
# Resource limits
MemoryMax = "1G";
CPUQuota = "80%";
# Security hardening
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
ReadWritePaths = [ cfg.dataDir "/tmp" ];
PrivateTmp = true;
# Allow device access for hardware
DeviceAllow = [
"/dev/ttyUSB* rw"
"/dev/ttyACM* rw"
"/dev/ttyS* rw"
"/dev/video* rw"
];
};
# Pre-start script to verify hardware
preStart = ''
echo "Lamassu ATM starting..."
echo "Relay: ${cfg.relayUrl}"
echo "Lightning.Pub: ${cfg.lightningPubUrl}"
# Check bill validator if enabled
if [ "${boolToString cfg.billValidator.enable}" = "true" ]; then
if [ ! -c "${cfg.billValidator.device}" ]; then
echo "Warning: Bill validator device ${cfg.billValidator.device} not found"
fi
fi
# Check camera if enabled
if [ "${boolToString cfg.camera.enable}" = "true" ]; then
if [ ! -c "${cfg.camera.device}" ]; then
echo "Warning: Camera device ${cfg.camera.device} not found"
fi
fi
'';
};
# Openbox autostart for kiosk mode
environment.etc."xdg/openbox/autostart".text = ''
# Disable screen saver and power management
xset s off
xset -dpms
xset s noblank
# Hide cursor after inactivity
unclutter -idle 3 &
# Start ATM (handled by systemd, but ensure display is ready)
sleep 2
'';
# udev rules for ATM hardware
services.udev.extraRules = ''
# ID-003 Bill Validator (JCM)
SUBSYSTEM=="tty", ATTRS{idVendor}=="0451", ATTRS{idProduct}=="3410", MODE="0666", SYMLINK+="bill-validator"
# MEI Bill Validator
SUBSYSTEM=="tty", ATTRS{idVendor}=="0b00", MODE="0666", SYMLINK+="bill-validator"
# CCNET Bill Validator (CashCode)
SUBSYSTEM=="tty", ATTRS{idVendor}=="0x1b5a", MODE="0666", SYMLINK+="bill-validator"
# Puloon Bill Dispenser
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0666", SYMLINK+="bill-dispenser"
# Generic USB-Serial adapters
SUBSYSTEM=="tty", ATTRS{idVendor}=="067b", MODE="0666"
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", MODE="0666"
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", MODE="0666"
# Camera access
SUBSYSTEM=="video4linux", MODE="0666"
'';
# Additional packages for hardware support
environment.systemPackages = with pkgs; [
unclutter # Hide cursor
];
};
}