Epic: bitSpire integration & multi-tenant overhaul (v2) #9

Closed
opened 2026-05-14 12:43:08 +00:00 by padreug · 1 comment
Owner

Context

The current satmachineadmin extension is superuser-only on a single LNbits instance with one ATM, built against the legacy Lamassu (SSH-tunneled PostgreSQL cash_out_txs polling). The upstream ATM has been rebuilt as bitSpire (aiolabs/lamassu-next dev branch), which is Nostr-native (kind-21000 NIP-44 v2 encrypted RPC between the ATM and LNbits, auto-account-creation from npub, decentralized relay-based discovery). Legacy Lamassu's PostgreSQL is gone.

Three planned-feature streams converge into this overhaul:

  • aiolabs/lamassu-next#22 — LNbits as Nostr-native UI layer (LNbits nostr-transport branch — what we depend on).
  • aiolabs/lamassu-next#42 — Nostr-native operator dashboard + seed-URL onboarding + kind-30079 telemetry.
  • aiolabs/lamassu-next#43 — Enriched kind-30078 beacon (name/location/fees/limits/denominations). Note: not yet shipped (verified on dev commit 2b712af — current payload is only {cash_in, cash_out, cash_level, fiat, model}).
  • aiolabs/lamassu-next#44upstream dependency filed as part of this overhaul: carry the principal/commission split end-to-end via Payment.extra on cash-out invoices and LNURL-withdraw links.

Goal

Rebuild Satoshi Machine to support a decentralized network of bitSpire ATMs that can plug into any LNbits instance, with three first-class actors:

  1. Super — LNbits instance admin; sets a global platform-fee % (read-only to operators).
  2. Operator — LNbits user who owns one or more bitSpire machines; installs satmachineadmin; configures the remainder split (after super) across their wallets (self / employee / maintenance fund).
  3. Liquidity Provider (LP) — LNbits user who deposits fiat at machines and receives proportional BTC distributions, aggregated across operators. (Note: LP UI is migrating to ~/dev/webapp, so satmachineclient is in maintenance mode.)

satmachineadmin absorbs the operator dashboard role when an operator is on LNbits — apps/dashboard in lamassu-next becomes the self-host-without-LNbits fallback.

Key design decisions (2026-05-14)

  • Identity: 1 LNbits user = 1 operator. N machines = N wallets, each tagged with the machine's npub. Aggregation native via Payment.tag.
  • Platform fee = two-stage hybrid split: super sets super_fee_pct (read-only to operator). Operator's split rules apply to the remainder (commission_sats * (1 - super_fee_pct)).
    • Example: 100 sats commission, super=30% → 30 sats to super; operator splits remaining 70 sats per their config (e.g. 50/30/20 → 35/21/14 sats).
  • Customer discounts (post-v1): deferred, but v1 schema already stores platform_fee_sats and operator_fee_sats as separate absolute BIGINT values (Stripe Connect pattern) so v2's promo engine ships without a breaking migration.
  • No backwards compatibility: operators on the previous schema must wipe and re-onboard.
  • Branch: v2-bitspire (created from main).

Phased delivery

Phase Scope Gating
P0 Schema (m005) + models + operator-scoped CRUD + stub legacy entry points
P1 Nostr kind-21000 subscription manager + machine add-by-npub + idempotent settlement landing P0
P2 Two-stage commission split (super → operator-defined remainder) + super-only platform fee endpoint P1
P3 Operator UX: manual tx, partial dispense (#3), balance settlement (#4), abandoned-tx queue P2
P4 Kind-30078 beacon ingestion (degrade gracefully — most fields blocked on lamassu-next#43) P1
P5 Seed-URL onboarding wizard P4 + lamassu-next#42
P6 LP auto-forward (closes #8) P2
P7 satmachineclient maintenance pass (cross-extension reads; README points LP audience to webapp) P2
P8 Kind-30079 telemetry ingestion (read-only) lamassu-next#42

Sub-issues (will be filed phase-by-phase as work picks up)

  • P1: Nostr kind-21000 subscription manager (replaces SSH/PostgreSQL polling)
  • P1: Machine CRUD + add-by-npub + per-operator scoping across all endpoints
  • P2: Two-stage commission split implementation
  • P2: Super-only platform fee config endpoint
  • P3: Partial transaction processing (closes #3)
  • P3: Balance settlement at current rate (closes #4)
  • P3: Abandoned-transaction queue
  • P4: Kind-30078 beacon ingestion (graceful degradation; blocked on aiolabs/lamassu-next#43)
  • P5: Seed-URL machine onboarding wizard (mirrors aiolabs/lamassu-next#42)
  • P6: LP auto-forward to LN address (closes #8)
  • P7: satmachineclient v2 maintenance pass
  • P8: Kind-30079 telemetry ingestion
  • v2: customer discount/promotion engine (post-v1; schema hooks already in m005)

Upstream coordination

  • aiolabs/lamassu-next#42 — fleet management plane, seed-URL onboarding (we mirror the seed-URL design).
  • aiolabs/lamassu-next#43 — beacon enrichment (we ingest opportunistically).
  • aiolabs/lamassu-next#44Payment.extra split metadata (eliminates back-derivation).

P0 status — IN PROGRESS on branch v2-bitspire

Commits so far:

  • ae4e241 feat(v2): add m005 satmachine_v2 schema for bitSpire + multi-tenant
  • 013e3d5 feat(v2): rewrite models.py for v2 schema
  • 937749f feat(v2): operator-scoped CRUD + stub legacy entry points

Verified: clean import against LNbits 1.4 nostr-transport; 22/23 tests pass (calculations math suite intact; 1 async-test fail is env-only — pytest-asyncio missing in borrowed venv).

Local plan: ~/.claude/plans/snug-gliding-shamir.md.

## Context The current `satmachineadmin` extension is **superuser-only on a single LNbits instance with one ATM**, built against the legacy Lamassu (SSH-tunneled PostgreSQL `cash_out_txs` polling). The upstream ATM has been rebuilt as **bitSpire** (`aiolabs/lamassu-next` `dev` branch), which is Nostr-native (kind-21000 NIP-44 v2 encrypted RPC between the ATM and LNbits, auto-account-creation from npub, decentralized relay-based discovery). Legacy Lamassu's PostgreSQL is gone. Three planned-feature streams converge into this overhaul: - `aiolabs/lamassu-next#22` — LNbits as Nostr-native UI layer (LNbits `nostr-transport` branch — what we depend on). - `aiolabs/lamassu-next#42` — Nostr-native operator dashboard + seed-URL onboarding + kind-30079 telemetry. - `aiolabs/lamassu-next#43` — Enriched kind-30078 beacon (name/location/fees/limits/denominations). **Note: not yet shipped** (verified on `dev` commit `2b712af` — current payload is only `{cash_in, cash_out, cash_level, fiat, model}`). - `aiolabs/lamassu-next#44` — **upstream dependency** filed as part of this overhaul: carry the principal/commission split end-to-end via `Payment.extra` on cash-out invoices and LNURL-withdraw links. ## Goal Rebuild Satoshi Machine to support a **decentralized network of bitSpire ATMs that can plug into any LNbits instance**, with three first-class actors: 1. **Super** — LNbits instance admin; sets a global platform-fee % (read-only to operators). 2. **Operator** — LNbits user who owns one or more bitSpire machines; installs satmachineadmin; configures the *remainder* split (after super) across their wallets (self / employee / maintenance fund). 3. **Liquidity Provider (LP)** — LNbits user who deposits fiat at machines and receives proportional BTC distributions, aggregated across operators. *(Note: LP UI is migrating to `~/dev/webapp`, so satmachineclient is in maintenance mode.)* satmachineadmin **absorbs the operator dashboard role** when an operator is on LNbits — `apps/dashboard` in lamassu-next becomes the self-host-without-LNbits fallback. ## Key design decisions (2026-05-14) - **Identity**: 1 LNbits user = 1 operator. N machines = N wallets, each tagged with the machine's npub. Aggregation native via `Payment.tag`. - **Platform fee = two-stage hybrid split**: super sets `super_fee_pct` (read-only to operator). Operator's split rules apply to the **remainder** (`commission_sats * (1 - super_fee_pct)`). - Example: 100 sats commission, super=30% → 30 sats to super; operator splits remaining 70 sats per their config (e.g. 50/30/20 → 35/21/14 sats). - **Customer discounts (post-v1)**: deferred, but v1 schema *already* stores `platform_fee_sats` and `operator_fee_sats` as separate absolute BIGINT values (Stripe Connect pattern) so v2's promo engine ships without a breaking migration. - **No backwards compatibility**: operators on the previous schema must wipe and re-onboard. - **Branch**: `v2-bitspire` (created from `main`). ## Phased delivery | Phase | Scope | Gating | |---|---|---| | **P0** | Schema (m005) + models + operator-scoped CRUD + stub legacy entry points | — | | **P1** | Nostr kind-21000 subscription manager + machine add-by-npub + idempotent settlement landing | P0 | | **P2** | Two-stage commission split (super → operator-defined remainder) + super-only platform fee endpoint | P1 | | **P3** | Operator UX: manual tx, partial dispense (#3), balance settlement (#4), abandoned-tx queue | P2 | | **P4** | Kind-30078 beacon ingestion (degrade gracefully — most fields blocked on `lamassu-next#43`) | P1 | | **P5** | Seed-URL onboarding wizard | P4 + `lamassu-next#42` | | **P6** | LP auto-forward (closes #8) | P2 | | **P7** | satmachineclient maintenance pass (cross-extension reads; README points LP audience to webapp) | P2 | | **P8** | Kind-30079 telemetry ingestion (read-only) | `lamassu-next#42` | ## Sub-issues (will be filed phase-by-phase as work picks up) - [ ] P1: Nostr kind-21000 subscription manager (replaces SSH/PostgreSQL polling) - [ ] P1: Machine CRUD + add-by-npub + per-operator scoping across all endpoints - [ ] P2: Two-stage commission split implementation - [ ] P2: Super-only platform fee config endpoint - [ ] P3: Partial transaction processing (closes #3) - [ ] P3: Balance settlement at current rate (closes #4) - [ ] P3: Abandoned-transaction queue - [ ] P4: Kind-30078 beacon ingestion (graceful degradation; blocked on `aiolabs/lamassu-next#43`) - [ ] P5: Seed-URL machine onboarding wizard (mirrors `aiolabs/lamassu-next#42`) - [ ] P6: LP auto-forward to LN address (closes #8) - [ ] P7: satmachineclient v2 maintenance pass - [ ] P8: Kind-30079 telemetry ingestion - [ ] v2: customer discount/promotion engine (post-v1; schema hooks already in m005) ## Upstream coordination - `aiolabs/lamassu-next#42` — fleet management plane, seed-URL onboarding (we mirror the seed-URL design). - `aiolabs/lamassu-next#43` — beacon enrichment (we ingest opportunistically). - `aiolabs/lamassu-next#44` — `Payment.extra` split metadata (eliminates back-derivation). ## P0 status — IN PROGRESS on branch `v2-bitspire` Commits so far: - `ae4e241` feat(v2): add m005 satmachine_v2 schema for bitSpire + multi-tenant - `013e3d5` feat(v2): rewrite models.py for v2 schema - `937749f` feat(v2): operator-scoped CRUD + stub legacy entry points Verified: clean import against LNbits 1.4 `nostr-transport`; 22/23 tests pass (`calculations` math suite intact; 1 async-test fail is env-only — `pytest-asyncio` missing in borrowed venv). Local plan: `~/.claude/plans/snug-gliding-shamir.md`.
Author
Owner

➡️ Migrated to aiolabs/spirekeeper#5 (aiolabs/spirekeeper#5).

The v2-bitspire line of this extension now lives in its own repo, aiolabs/spirekeeper. Tracking for this issue continues there; closing here. (Issue numbers were reassigned in the new repo.)

➡️ **Migrated to https://git.atitlan.io/aiolabs/spirekeeper/issues/5 (aiolabs/spirekeeper#5).** The v2-bitspire line of this extension now lives in its own repo, `aiolabs/spirekeeper`. Tracking for this issue continues there; closing here. (Issue numbers were reassigned in the new repo.)
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/satmachineadmin#9
No description provided.