docs(README): rewrite intro as positive framing

Drop the 'What this extension is not' negation list and absorb
its content into 'What this extension is' as positive descriptions
under five headings: a CMS for operators, a REST API, a Nostr
publisher, an order pipeline, and a single-tenant view of the
world (the last folds in customer-UI-lives-elsewhere, festivals-
are-external-NIP-51-lists, and per-restaurant-invoices-no-
splitter).
This commit is contained in:
Padreug 2026-05-02 08:26:15 +02:00
commit c2ea0297f9

View file

@ -1,35 +1,51 @@
# Restaurant — LNbits extension
A Nostr-native restaurant CMS for LNbits. Restaurant owners enable this
extension on their LNbits account to build menus, manage modifiers and
inventory, and watch orders in real time. Customer-facing UIs (kiosks,
mobile, the AIO webapp) live elsewhere and connect via REST + Nostr.
A Nostr-native restaurant CMS for LNbits. The operator (the person who
enables this extension on their LNbits account) builds menus, manages
modifiers and inventory, watches orders in real time, and routes paid
tickets to a thermal printer. Each restaurant's data is owned by that
restaurant's wallet; menus are published to Nostr so any client — from
a single venue's customer kiosk to a webapp aggregating dozens of
restaurants for a festival — can subscribe and stay live.
## What this extension is
- **A CMS** for one operator (one or many restaurants per LNbits wallet).
- **A REST API** for menu read + order placement.
- **A Nostr publisher** for menus (NIP-99 classified listings) and a
Nostr inbound sync skeleton for orders (NIP-17 DMs).
- **An order state machine** with print-job queueing and a Kitchen
Display screen.
**A CMS for restaurant operators.** One LNbits account can host one or
many restaurants under the same login. Each restaurant carries its own
profile, menu tree (categories → subcategories → items), modifier
groups (required choices and optional addons, single- or multi-select),
per-item availability windows, inventory, and Nostr identity.
## What this extension is not
**A REST API.** Public read endpoints serve menu trees and item
details; gated write endpoints (admin key) handle CRUD; an unauthenticated
order placement endpoint accepts carts and returns a Lightning invoice.
- **Not a customer kiosk.** Customer-facing UI is the AIO webapp at
`~/dev/webapp`.
- **Not a festival platform.** "Festival" / "collective space" /
"food court" are emergent — a curator publishes a NIP-51 list of
restaurant pubkeys, the webapp aggregates from that list. The
extension itself only ever knows about its own restaurant.
- **Not a payment splitter.** Per the design discussion: each menu
item belongs to one restaurant, each restaurant issues its own
invoice, and the customer pays N invoices to complete a multi-
restaurant cart. The webapp pre-flights the total via
`POST /api/v1/orders/quote` to confirm sufficient balance before
opening any per-restaurant invoice. If a payment ever fails after
another succeeded (rare on internal LNbits transfers), the
customer settles the remainder in person.
**A Nostr publisher.** Menu items are published as NIP-99 classified
listings (kind 30402, parameterized replaceable) every time they're
created or edited; restaurant profiles are kind 0 metadata; deletions
are NIP-09. Tags carry structured price, dietary flags, allergens, and
ingredients so subscribers can filter without parsing markdown.
**An order pipeline.** Every cart placed against this restaurant
becomes one order with snapshotted line-item prices and selected
modifiers. The invoice listener settles `pending → paid` on payment;
the operator (or auto-accept) walks it through `accepted → ready →
completed`. Stock decrements on settlement, a print job lands in the
queue, and the Kitchen Display picks it up.
**A single-tenant view of the world.** Customer-facing UIs (kiosks,
mobile apps, the AIO webapp at `~/dev/webapp`) live outside this
extension and connect via REST and Nostr. When a customer wants to
order across multiple restaurants — at a festival, in a collective
space, across a food court — that grouping is curated externally
(typically as a NIP-51 list of restaurant pubkeys), the webapp fetches
each menu independently, builds a unified cart, and sends one order
per restaurant. Each restaurant issues its own bolt11 invoice; the
customer pays N invoices to complete the cart. No central wallet
holds the float, no splitter divides the payment, and each operator
sees their own sats land directly. The webapp pre-flights the total
via `POST /api/v1/orders/quote` so a customer with insufficient
balance gets one clean error rather than a partially-paid cart.
## Architecture