From 9adee6e37f2144394dc7e557e1329bfc3fae3bb8 Mon Sep 17 00:00:00 2001 From: Patrick Mulligan Date: Thu, 22 Jan 2026 14:19:00 -0500 Subject: [PATCH] Initial commit: Lamassu modernization project - Add lamassu-server, lamassu-machine, lamassu-install as submodules - Add CLAUDE.md with development guidance - Add docs/modernization-plan.md with 2026 refactoring roadmap - Add .gitignore for Node.js/Nix development Co-Authored-By: Claude Opus 4.5 --- .gitignore | 44 ++++ .gitmodules | 9 + CLAUDE.md | 121 +++++++++ docs/modernization-plan.md | 493 +++++++++++++++++++++++++++++++++++++ lamassu-install | 1 + lamassu-machine | 1 + lamassu-server | 1 + 7 files changed, 670 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 CLAUDE.md create mode 100644 docs/modernization-plan.md create mode 160000 lamassu-install create mode 160000 lamassu-machine create mode 160000 lamassu-server diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..029acc9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +# Dependencies +node_modules/ +.pnpm-store/ + +# Build outputs +dist/ +build/ +*.tsbuildinfo + +# Environment files +.env +.env.* +!.env.example + +# IDE +.idea/ +.vscode/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Nix +result +result-* +.direnv/ +.devenv/ +.devenv.flake.nix + +# Logs +*.log +logs/ + +# Test coverage +coverage/ + +# Lamassu specific +.lamassu/ +*.pem +*.crt +*.key diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7d5b923 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "lamassu-server"] + path = lamassu-server + url = https://github.com/lamassu/lamassu-server.git +[submodule "lamassu-machine"] + path = lamassu-machine + url = https://github.com/lamassu/lamassu-machine.git +[submodule "lamassu-install"] + path = lamassu-install + url = https://github.com/lamassu/lamassu-install.git diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f8af785 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,121 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Repository Overview + +This is the Lamassu Bitcoin ATM system, consisting of three components: + +- **lamassu-server/** - Backend services and admin dashboard (pnpm monorepo with Turbo) +- **lamassu-machine/** - ATM kiosk software that runs on the physical machines +- **lamassu-install/** - Production installation and upgrade scripts + +## Commands + +### lamassu-server (monorepo) + +```bash +cd lamassu-server + +# Install dependencies +pnpm install + +# Run all packages in development mode (server + admin-ui) +pnpm run dev + +# Build all packages +pnpm run build + +# Run tests across all packages +pnpm run test + +# Run a single test file +cd packages/admin-ui && pnpm vitest run path/to/file.test.js + +# Database migrations +node packages/server/bin/lamassu-migrate + +# Generate SSL certificates (first-time setup) +bash packages/server/tools/cert-gen.sh + +# Create admin user +node packages/server/bin/lamassu-register admin@example.com superuser + +# Regenerate database types (requires running postgres) +cd packages/typesafe-db && pnpm run generate-types +``` + +### lamassu-machine + +```bash +cd lamassu-machine + +# Install and build +npm install +bash ./setup.sh +npm run build + +# Run tests +npm test + +# Development with mock hardware +node bin/fake-bills.js # In one terminal +node bin/lamassu-machine --mockBillValidator --mockBillDispenser --mockCam --mockPair '' +``` + +## Architecture + +### lamassu-server Monorepo Structure + +``` +packages/ +├── server/ # Express + Apollo GraphQL backend (CommonJS) +├── admin-ui/ # React 18 + Vite + MUI admin dashboard (ESM) +├── coins/ # @lamassu/coins - cryptocurrency constants (TypeScript) +└── typesafe-db/ # @lamassu/typesafe-db - Kysely database layer (TypeScript) +``` + +**Dependency flow**: `server` and `admin-ui` depend on `coins` and `typesafe-db` + +**Key server entry points**: +- `bin/lamassu-server` - Main HTTPS server (port 3000, client cert auth) +- `bin/lamassu-admin-server` - Admin API server +- 20+ CLI utilities in `bin/` for operations tasks + +**GraphQL**: Two implementations exist: +- `lib/graphql/` - Machine-facing API +- `lib/new-admin/graphql/` - Admin dashboard API + +### lamassu-machine + +The ATM kiosk uses a state machine architecture (`machina.js`) in `lib/brain.js` (134KB). The UI is vanilla JavaScript with Babel transpilation. + +**Hardware drivers** in `lib/`: id003, mei, puloon, ccnet (bill validators), printer, leds, camera + +## Code Style + +**Formatting** (enforced by husky pre-commit): +- 2-space indent, no semicolons, single quotes, trailing commas +- Prettier + ESLint with auto-fix on commit + +**TypeScript**: Only in `packages/coins/` and `packages/typesafe-db/`. Use `@typescript-eslint/consistent-type-imports` for imports. + +**Server code**: CommonJS (`require`/`module.exports`) +**Admin UI**: ESM (`import`/`export`) + +## Database + +PostgreSQL with Kysely ORM. Types are auto-generated from the schema. + +**Environment**: Configure postgres connection in `packages/server/.env` + +## Requirements + +- Node.js 22+ +- pnpm 10+ +- PostgreSQL +- Python 3 (for native dependency builds) + +## Documentation + +- `docs/modernization-plan.md` - 2026 modernization roadmap (Obsidian-compatible) diff --git a/docs/modernization-plan.md b/docs/modernization-plan.md new file mode 100644 index 0000000..5dd3528 --- /dev/null +++ b/docs/modernization-plan.md @@ -0,0 +1,493 @@ +--- +title: Lamassu Modernization Plan +created: 2026-01-22 +updated: 2026-01-22 +tags: + - architecture + - refactoring + - roadmap + - nix +status: draft +--- + +# Lamassu Modernization Plan + +> [!abstract] Summary +> Aggressive refactoring plan to bring Lamassu Bitcoin ATM software to 2026 standards, focusing on **reproducibility**, **security**, and **open-source maintainability** with NixOS deployment. + +## Quick Links + +- [[#Architecture Overview]] +- [[#Technology Decisions]] +- [[#Migration Phases]] +- [[#Trade-offs]] + +--- + +## Architecture Overview + +```mermaid +graph TB + subgraph "NixOS Production Server" + deploy[deploy-rs / Colmena] + sops[sops-nix secrets] + + subgraph "lamassu-server" + fastify[Fastify + tRPC + GraphQL] + otel[OpenTelemetry] + end + + pg[(PostgreSQL + Drizzle)] + jaeger[Jaeger / Grafana] + end + + subgraph "Admin UI" + react[React 19 + TanStack] + shadcn[Shadcn/ui + Tailwind] + end + + subgraph "lamassu-machine" + tauri[Tauri 2.x Rust Core] + xstate[XState v5] + hal[Rust HAL napi-rs] + hw[Hardware Drivers] + end + + react -->|tRPC| fastify + tauri -->|GraphQL| fastify + fastify --> pg + fastify --> otel + otel --> jaeger + hal --> hw +``` + +--- + +## Technology Decisions + +### Runtime & Language + +> [!decision] Full TypeScript + Node.js 22 LTS +> While Bun offers 3-4x performance, Node.js remains the backbone of enterprise applications. For mission-critical financial software, **reliability > raw performance**. + +| Aspect | Current | Target | +|--------|---------|--------| +| Runtime | Node.js 22 | Node.js 22 LTS | +| Language | JS + partial TS | Full TypeScript (strict) | +| Modules | CommonJS + ESM mix | ESM only | + +**Action Items:** +- [ ] Migrate all JavaScript to TypeScript +- [ ] Enable `strictNullChecks` and `noUncheckedIndexedAccess` +- [ ] Eliminate all CommonJS requires + +#typescript #nodejs + +--- + +### Backend Framework + +> [!decision] Express → Fastify +> Fastify provides 70-80k req/s vs Express's 20-30k, with first-class TypeScript support and JSON Schema validation. + +| Framework | Performance | TypeScript | Ecosystem | +|-----------|-------------|------------|-----------| +| Express | 20-30k req/s | Partial | Mature | +| **Fastify** | 70-80k req/s | First-class | Growing | +| Hono | Ultra-light | Good | Edge-focused | + +**Why Fastify:** +- JSON Schema validation built-in +- HTTP/2 support +- Plugin architecture +- Better for long-running server processes + +#backend #fastify + +--- + +### API Layer + +> [!decision] Hybrid: tRPC + GraphQL +> tRPC for Admin UI (type-safe monorepo), GraphQL for machine communication (stable contract). + +```mermaid +graph LR + AdminUI -->|tRPC| Server + Machine -->|GraphQL| Server +``` + +**tRPC Benefits:** +- End-to-end type safety without codegen +- Faster iteration +- Smaller bundle + +**Keep GraphQL for:** +- Machine API (stable contract) +- Potential non-TypeScript clients +- Consider Yoga over Apollo (lighter) + +#api #trpc #graphql + +--- + +### Database & ORM + +> [!decision] Kysely → Drizzle ORM +> SQL-first, schema-as-code, zero binary dependencies (critical for NixOS reproducibility). + +| ORM | Bundle | Cold Start | Migrations | +|-----|--------|------------|------------| +| Prisma | Heavy | Slow | Excellent | +| Kysely | Light | Fast | Basic | +| **Drizzle** | ~7kb | Fastest | Good | + +**Why Drizzle:** +- SQL-like syntax (readable) +- Zero binary dependencies +- 90% reduction in cold starts +- TypeScript schema definitions + +#database #drizzle #postgresql + +--- + +### Frontend (Admin UI) + +> [!decision] Keep React, Modernize Patterns +> React's ecosystem dominance (190M weekly downloads) makes migration unnecessary for admin dashboards. + +**Modernization:** +- [ ] Upgrade to React 19 (Server Components) +- [ ] Replace MUI with Shadcn/ui + Tailwind +- [ ] TanStack Query for data fetching +- [ ] TanStack Router for type-safe routing + +#frontend #react #tailwind + +--- + +### Machine State Management + +> [!decision] Machina.js → XState v5 +> Actor-based state management with visual editor and TypeScript inference. + +**Current:** `lib/brain.js` (134KB monolith) + +**XState Benefits:** +- Visual state machine editor (Stately.ai) +- TypeScript 5.0+ with excellent inference +- Actor model for complex flows +- Production-tested at scale + +> [!warning] Learning Curve +> XState has a steep learning curve. The mental model differs significantly from Redux/Context. + +#statemachine #xstate + +--- + +### Machine UI Framework + +> [!decision] Vanilla JS → Tauri 2.x +> Security-first design critical for financial kiosk applications. + +| Aspect | Electron | Tauri | +|--------|----------|-------| +| Bundle Size | ~100MB | **~2.5MB** | +| RAM Usage | 150-300MB | **30-50MB** | +| Startup | 1-2s | **<0.5s** | +| Security | Full Node access | **Explicit allowlist** | + +**Why Tauri for ATMs:** +- Security by default (restrictive API model) +- Lower resource usage on embedded hardware +- Rust backend integrates with hardware drivers +- 35% adoption increase in 2024 + +#tauri #kiosk #security + +--- + +### Hardware Abstraction + +> [!decision] JavaScript → Rust + napi-rs +> Memory safety at compile time for hardware drivers. + +``` +TypeScript Application + ↓ + napi-rs bindings + ↓ + Rust HAL Layer + ↓ + Hardware (bill validators, printers, etc.) +``` + +**Benefits:** +- No null pointer dereferences +- No buffer overflows +- Pre-built binaries for platforms +- Integrates with Tauri (both Rust) + +#rust #napi #hardware + +--- + +### Schema Validation + +> [!decision] Yup → Zod +> Better TypeScript integration, larger ecosystem, tRPC compatibility. + +| Library | Bundle | Ecosystem | tRPC | +|---------|--------|-----------|------| +| Yup | ~15kb | Mature | Manual | +| **Zod** | ~17kb | Large | Native | +| Valibot | ~1.4kb | Growing | Adapter | + +**Use Valibot** for machine-side code where bundle size matters. + +#validation #zod + +--- + +### Observability + +> [!decision] OpenTelemetry +> Vendor-neutral, unified traces/metrics/logs. + +```typescript +import { NodeSDK } from '@opentelemetry/sdk-node' +import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node' +``` + +**Self-hosted stack:** +- **Jaeger** → Distributed tracing +- **Prometheus + Grafana** → Metrics +- All deployable via NixOS modules + +#observability #opentelemetry #monitoring + +--- + +### Authentication + +> [!decision] Passkey-First Authentication +> Resistant to phishing and credential theft. + +**Current:** Client certs + Argon2 + SimpleWebAuthn + +**Target:** +- Passkeys as primary auth (WebAuthn) +- Keep client certs for machine-to-server +- Upgrade to SimpleWebAuthn v10+ + +> [!warning] 2025 Context +> 4B credentials leaked in January 2025. Password-based auth is a liability. + +#security #passkeys #webauthn + +--- + +## NixOS Infrastructure + +### Development Environment + +> [!decision] devenv +> 100% reproducible development environments. + +```nix +# devenv.nix +{ pkgs, ... }: { + languages.javascript = { + enable = true; + package = pkgs.nodejs_22; + pnpm.enable = true; + }; + languages.typescript.enable = true; + languages.rust.enable = true; + + services.postgres = { + enable = true; + initialDatabases = [{ name = "lamassu"; }]; + }; + + pre-commit.hooks = { + prettier.enable = true; + eslint.enable = true; + }; +} +``` + +**Benefits:** +- Single `devenv.nix` replaces Docker, brew, apt +- DevContainer generation for VS Code +- Built-in PostgreSQL service +- Pre-commit hooks integration + +#nix #devenv #reproducibility + +--- + +### Secrets Management + +> [!decision] sops-nix +> Atomic, declarative secret provisioning. + +**Features:** +- Supports age, GPG, AWS KMS, HashiCorp Vault +- Works with existing SSH keys +- Version-control friendly (encrypted in git) +- Compatible with all NixOS deployment tools + +```nix +sops.secrets.database_password = { + sopsFile = ./secrets/db.yaml; + owner = "lamassu"; +}; +``` + +#secrets #sops #security + +--- + +### Production Deployment + +> [!decision] deploy-rs +> Automatic rollback on failure - critical for ATM servers. + +| Tool | Rollback | Secrets | Parallel | +|------|----------|---------|----------| +| **deploy-rs** | Automatic | External | Yes | +| Colmena | Manual | Built-in | Yes | + +**Why deploy-rs:** +- Connects after activation to confirm availability +- Auto-rollback if machine becomes unreachable +- Critical for network config changes on remote ATMs + +#deployment #deploy-rs #nixos + +--- + +### Node.js Packaging + +> [!tip] dream2nix +> Auto-generates Nix derivations from `package-lock.json`. + +```nix +{ + inputs.dream2nix.url = "github:nix-community/dream2nix"; + + outputs = { dream2nix, ... }: + dream2nix.lib.makeFlakeOutputs { + source = ./.; + }; +} +``` + +#nix #packaging + +--- + +## Testing Strategy + +### Unit/Integration + +> [!check] Keep Vitest +> Already in use, works well with TypeScript. + +### E2E Testing + +> [!decision] Add Playwright +> TypeScript-first, auto-wait eliminates flaky tests. + +**Best Practices:** +- Use accessible locators (`getByRole`, `getByLabel`) +- Test isolation (each test independent) +- Run `tsc --noEmit` in CI + +```typescript +test('user can complete transaction', async ({ page }) => { + await page.getByRole('button', { name: 'Start' }).click() + await expect(page.getByText('Insert bill')).toBeVisible() +}) +``` + +#testing #playwright #vitest + +--- + +## Migration Phases + +### Phase 1: Foundation +> [!todo] High Impact, Lower Risk + +- [ ] Full TypeScript migration +- [ ] devenv for development environment +- [ ] Drizzle ORM migration +- [ ] OpenTelemetry instrumentation +- [ ] Nix flake for builds + +### Phase 2: Backend Modernization + +- [ ] Express → Fastify migration +- [ ] Add tRPC for admin API +- [ ] Zod schema validation +- [ ] Playwright E2E tests + +### Phase 3: Machine Modernization +> [!warning] Higher Risk - Requires extensive testing + +- [ ] XState v5 for state machine +- [ ] Tauri migration +- [ ] Rust HAL for hardware drivers + +### Phase 4: Deployment + +- [ ] NixOS module for lamassu-server +- [ ] sops-nix secrets management +- [ ] deploy-rs for production deployments + +--- + +## Trade-offs + +| Decision | We Get | We Lose | +|----------|--------|---------| +| Node.js over Bun | Stability, ecosystem | Raw performance | +| Fastify over Hono | Mature plugins | Minimal bundle | +| Drizzle over Prisma | Bundle size, speed | DX features | +| Tauri over Electron | Security, efficiency | Ecosystem maturity | +| XState over simple FSM | Visualization, debugging | Simplicity | + +--- + +## References + +### Backend +- [Fastify vs Express 2025](https://medium.com/codetodeploy/express-or-fastify-in-2025-whats-the-right-node-js-framework-for-you-6ea247141a86) +- [tRPC vs GraphQL](https://betterstack.com/community/guides/scaling-nodejs/trpc-vs-graphql/) +- [Drizzle vs Prisma vs Kysely](https://levelup.gitconnected.com/the-2025-typescript-orm-battle-prisma-vs-drizzle-vs-kysely-007ffdfded67) + +### Machine +- [Tauri vs Electron 2025](https://www.dolthub.com/blog/2025-11-13-electron-vs-tauri/) +- [XState v5](https://stately.ai/blog/2023-12-01-xstate-v5) +- [napi-rs Guide](https://blog.logrocket.com/building-nodejs-modules-rust-napi-rs/) + +### NixOS +- [devenv](https://devenv.sh/) +- [sops-nix](https://github.com/Mic92/sops-nix) +- [deploy-rs](https://github.com/serokell/deploy-rs) + +### Security +- [Passkeys Guide](https://www.passkeys.com/guide) +- [OpenTelemetry Node.js](https://opentelemetry.io/docs/languages/js/) + +--- + +## Related Notes + +- [[CLAUDE]] - Claude Code guidance +- [[Architecture Decision Records]] - ADRs for each decision +- [[NixOS Configuration]] - Production NixOS setup diff --git a/lamassu-install b/lamassu-install new file mode 160000 index 0000000..c15dbbc --- /dev/null +++ b/lamassu-install @@ -0,0 +1 @@ +Subproject commit c15dbbcae8902d99e056b9397bd46cbb640edce1 diff --git a/lamassu-machine b/lamassu-machine new file mode 160000 index 0000000..8c83ad8 --- /dev/null +++ b/lamassu-machine @@ -0,0 +1 @@ +Subproject commit 8c83ad8bdbd49621a20c01d725b1ce0c8eee813e diff --git a/lamassu-server b/lamassu-server new file mode 160000 index 0000000..5909e60 --- /dev/null +++ b/lamassu-server @@ -0,0 +1 @@ +Subproject commit 5909e609576e078e4c2189fc6cce464b8dca8a71