satmachineadmin becomes the bitSpire operator dashboard #48

Open
opened 2026-06-13 22:03:01 +00:00 by padreug · 0 comments
Owner

Migrated from aiolabs/lamassu-next#48 — opened by @padreug on 2026-05-24.\n\nToday satmachineadmin (~/dev/shared/extensions/satmachineadmin/) is a LNbits extension whose job is DCA distribution: it parses Payment.extra from bitSpire ATM cash-out invoices (see bitspire.py) and pays out registered DCA clients.

The plan is to grow satmachineadmin into the operator dashboard for bitSpire fleets — DCA distribution remains a core feature, but the extension picks up fleet management, branding distribution, and operator-facing telemetry on top.

Branch scope: dev (bitSpire) for the ATM-side changes; the extension repo is aiolabs/satmachineadmin (LNbits extension).

Why satmachineadmin

  • Already integrated with bitSpire at the payment level via the kind-21000 nostr-transport (bitspire.py:parse_settlement)
  • Already authenticated as a LNbits admin (superuser session) — the right trust level for operator-facing fleet ops
  • Already has the Machine model with machine_npub (the per-ATM identity); the operator/machine relationship is the right home for cross-cutting fleet config
  • Matches the "Nostr-only comms" direction documented in CLAUDE.md on dev — no new HTTP path to the kiosk

Scope

Operator identity wiring

  • Define what an "operator" is in satmachineadmin. Today the extension is configured per-LNbits-superuser; formalise the operator as an entity that owns N machines and exposes a public Nostr pubkey (could be the LNbits superuser's pubkey, or a separate operator key).
  • Each dca_machines row links to one operator.

Branding panel (the immediate use case)

  • New admin-UI panel: upload logo.png, pick theme (one of bitSpire's 6 built-ins or custom), set title, optionally set custom_colors.
  • Schema matches branding.json from #47.
  • On save, satmachineadmin publishes a replaceable Nostr event:
    • Kind: TBD (proposing kind 30080 under our 30078-30079 cluster, parameterised by operator pubkey)
    • d tag: bitspire-branding
    • Content: NIP-44 v2 encrypted to each subscribed ATM pubkey? Or plaintext JSON since branding is non-sensitive? Open question.
    • Tags: ["p", "<atm-pubkey>"] per machine in the operator's fleet (or rely on author-pubkey filter on the ATM side)

ATM-side subscription

  • bitSpire subscribes on boot to its operator's branding event (operator pubkey known via env or static config).
  • Applies the event content using the BrandingSource interface specified in #47 — Nostr event source wins over local file.
  • Live updates: subsequent replacements apply immediately, no restart.

Future capabilities this unlocks (out of scope for this issue)

  • Fleet status board (live aggregate of all kind-30078 availability beacons from the operator's ATMs)
  • Remote command channel (build on kind-21003 operator commands)
  • Per-machine commission / fee config push
  • Operator-facing transaction reconciliation across the fleet
  • Fleet-wide branding rollout vs per-machine override (d tag includes machine pubkey for per-machine branding)

Open questions

  1. Event kind. 30080 fits our cluster but check the NIP-01 range and existing kind allocations.
  2. Encryption. Branding is non-sensitive; plaintext NIP-01 simplifies caching/relay-side handling. Lean plaintext unless there's a reason not to.
  3. Operator key identity. Is the operator pubkey == LNbits superuser pubkey, or a separate key managed by the satmachineadmin extension? Affects how ATMs trust the event author.
  4. Discovery. How does a fresh ATM learn its operator pubkey? Two paths: (a) env var set by provision-atm.sh; (b) ATM publishes its own pubkey, operator's satmachineadmin instance picks it up and the ATM later subscribes to anyone who has p-tagged it. (a) is concrete and ships now; (b) is the prettier flow.
  5. Repo home. Branding-event schema lives in @bitSpire/lnbits package on dev? Or a new @bitSpire/branding-schema shared with satmachineadmin? Probably the former — satmachineadmin can just JSON-validate against an inline shape.

Acceptance (this issue is a meta-tracker; concrete sub-tasks split as we go)

  • Operator entity defined in satmachineadmin with machine linkage
  • Branding admin panel in satmachineadmin
  • Replaceable Nostr event published on save
  • bitSpire BrandingSource interface has a Nostr-event-source implementation
  • ATM subscribes on boot, applies live updates
  • Documented in docs/nostr-patterns/ (in the webapp repo's pattern reference, since branding distribution becomes a reusable Nostr-comm pattern)

Refs: #47 (the local-file half of branding), aiolabs/satmachineadmin/bitspire.py (existing integration point).

> _Migrated from [aiolabs/lamassu-next#48](https://git.atitlan.io/aiolabs/lamassu-next/issues/48) — opened by @padreug on 2026-05-24._\n\nToday **satmachineadmin** (`~/dev/shared/extensions/satmachineadmin/`) is a LNbits extension whose job is DCA distribution: it parses `Payment.extra` from bitSpire ATM cash-out invoices (see `bitspire.py`) and pays out registered DCA clients. The plan is to **grow satmachineadmin into the operator dashboard for bitSpire fleets** — DCA distribution remains a core feature, but the extension picks up fleet management, branding distribution, and operator-facing telemetry on top. > Branch scope: `dev` (bitSpire) for the ATM-side changes; the extension repo is `aiolabs/satmachineadmin` (LNbits extension). ## Why satmachineadmin - Already integrated with bitSpire at the payment level via the kind-21000 nostr-transport (`bitspire.py:parse_settlement`) - Already authenticated as a LNbits admin (superuser session) — the right trust level for operator-facing fleet ops - Already has the `Machine` model with `machine_npub` (the per-ATM identity); the operator/machine relationship is the right home for cross-cutting fleet config - Matches the "Nostr-only comms" direction documented in `CLAUDE.md` on `dev` — no new HTTP path to the kiosk ## Scope ### Operator identity wiring - Define what an "operator" is in satmachineadmin. Today the extension is configured per-LNbits-superuser; formalise the operator as an entity that owns N machines and exposes a public Nostr pubkey (could be the LNbits superuser's pubkey, or a separate operator key). - Each `dca_machines` row links to one operator. ### Branding panel (the immediate use case) - New admin-UI panel: upload `logo.png`, pick `theme` (one of bitSpire's 6 built-ins or `custom`), set `title`, optionally set `custom_colors`. - Schema matches `branding.json` from #47. - On save, satmachineadmin publishes a replaceable Nostr event: - Kind: TBD (proposing **kind 30080** under our 30078-30079 cluster, parameterised by operator pubkey) - `d` tag: `bitspire-branding` - Content: NIP-44 v2 encrypted to each subscribed ATM pubkey? Or plaintext JSON since branding is non-sensitive? **Open question.** - Tags: `["p", "<atm-pubkey>"]` per machine in the operator's fleet (or rely on author-pubkey filter on the ATM side) ### ATM-side subscription - bitSpire subscribes on boot to its operator's branding event (operator pubkey known via env or static config). - Applies the event content using the `BrandingSource` interface specified in #47 — Nostr event source wins over local file. - Live updates: subsequent replacements apply immediately, no restart. ### Future capabilities this unlocks (out of scope for this issue) - Fleet status board (live aggregate of all kind-30078 availability beacons from the operator's ATMs) - Remote command channel (build on kind-21003 operator commands) - Per-machine commission / fee config push - Operator-facing transaction reconciliation across the fleet - Fleet-wide branding rollout vs per-machine override (`d` tag includes machine pubkey for per-machine branding) ## Open questions 1. **Event kind.** 30080 fits our cluster but check the NIP-01 range and existing kind allocations. 2. **Encryption.** Branding is non-sensitive; plaintext NIP-01 simplifies caching/relay-side handling. Lean plaintext unless there's a reason not to. 3. **Operator key identity.** Is the operator pubkey == LNbits superuser pubkey, or a separate key managed by the satmachineadmin extension? Affects how ATMs trust the event author. 4. **Discovery.** How does a fresh ATM learn its operator pubkey? Two paths: (a) env var set by `provision-atm.sh`; (b) ATM publishes its own pubkey, operator's satmachineadmin instance picks it up and the ATM later subscribes to anyone who has `p`-tagged it. (a) is concrete and ships now; (b) is the prettier flow. 5. **Repo home.** Branding-event schema lives in `@bitSpire/lnbits` package on dev? Or a new `@bitSpire/branding-schema` shared with satmachineadmin? Probably the former — satmachineadmin can just JSON-validate against an inline shape. ## Acceptance (this issue is a meta-tracker; concrete sub-tasks split as we go) - [ ] Operator entity defined in satmachineadmin with machine linkage - [ ] Branding admin panel in satmachineadmin - [ ] Replaceable Nostr event published on save - [ ] bitSpire `BrandingSource` interface has a Nostr-event-source implementation - [ ] ATM subscribes on boot, applies live updates - [ ] Documented in `docs/nostr-patterns/` (in the webapp repo's pattern reference, since branding distribution becomes a reusable Nostr-comm pattern) Refs: #47 (the local-file half of branding), `aiolabs/satmachineadmin/bitspire.py` (existing integration point).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/bitspire#48
No description provided.