docs: Obsidian-style vault under docs/
Add a navigable Obsidian vault as the project's first-class technical documentation. Notes cross-reference with [[wikilinks]]; docs/index.md is the Map of Content. New notes: index.md MOC, entry point architecture.md what the extension owns vs what lives outside data-model.md entity-by-entity schema reference menu-tree.md the arbitrary-depth tree concept order-flow.md state machine + invoice listener + print nostr-layer.md kinds 0/30402/5/1059, signing, t-tags api-reference.md endpoint catalog by audience cms.md Vue 3 + Quasar 2 UMD conventions, q-tree webapp-integration.md multi-restaurant cart pattern + atomicity glossary.md domain terms Existing notes (kept as-is): adr-0001-menu-tree.md the storage choice rationale design-conversation.md trimmed transcript README.md adds a Documentation section pointing at docs/index.md with the headline note list. Each note links to ~3-5 others; the vault forms a connected graph. A project-level memory rule (saved outside the repo) commits us to keeping these docs in sync as the code evolves: any commit that materially changes schema, API, order flow, Nostr surface, CMS conventions, or webapp integration must update the relevant note(s) in the same commit.
This commit is contained in:
parent
7f7915a041
commit
42a8b08a5b
11 changed files with 1015 additions and 0 deletions
89
docs/architecture.md
Normal file
89
docs/architecture.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# Architecture
|
||||
|
||||
The restaurant extension is the **operator's CMS** for one or many
|
||||
restaurants on a single LNbits account. Customer-facing UIs (kiosks,
|
||||
mobile apps, the AIO webapp) live outside the extension and consume it
|
||||
over REST + Nostr.
|
||||
|
||||
## What this extension owns
|
||||
|
||||
- Restaurant profile rows and per-restaurant Nostr identity.
|
||||
- The [[menu-tree]] (`menu_nodes` + `menu_items` + `modifier_groups` +
|
||||
`modifiers` + `availability_windows`).
|
||||
- The [[order-flow|order pipeline]] (`orders`, `order_items`,
|
||||
`print_jobs`).
|
||||
- Publishing the [[nostr-layer|menu to Nostr]] as NIP-99 listings.
|
||||
- The [[cms|operator console]] under `/restaurant/...` (Jinja +
|
||||
Quasar 2 UMD).
|
||||
- A REST [[api-reference|API]] under `/restaurant/api/v1/...`.
|
||||
|
||||
## What lives outside the extension
|
||||
|
||||
| Concern | Where |
|
||||
|---|---|
|
||||
| Customer kiosk / mobile / web | `~/dev/webapp` ([[webapp-integration]]) |
|
||||
| Multi-restaurant aggregation (festivals, food courts, collective spaces) | NIP-51 lists, curated externally |
|
||||
| Lightning wallet, payment routing, user auth | LNbits core |
|
||||
| Nostr relay connection | `nostrclient` extension |
|
||||
| Thermal printer | `printer-pi` (subscribes to a webhook or Nostr event) |
|
||||
|
||||
## High-level topology
|
||||
|
||||
```
|
||||
LNbits instance
|
||||
┌────────────────────────────────┐
|
||||
│ Restaurant ext │
|
||||
│ ├── REST /restaurant/api/v1│
|
||||
│ ├── CMS /restaurant/... │
|
||||
│ ├── Nostr publisher │──────┐
|
||||
│ └── Invoice listener │ │
|
||||
│ (settle, decrement, │ │
|
||||
│ queue print) │ │
|
||||
└─────────┬──────────────────────┘ │
|
||||
│ ▼
|
||||
│ ┌─────────────────────────┐
|
||||
│ │ nostrclient ext │──→ relays
|
||||
│ └─────────────────────────┘
|
||||
▼
|
||||
┌──────────────┐ ┌─────────────────────┐
|
||||
│ printer-pi │ ◀──────│ webapp / AIO │
|
||||
│ (subscribes) │ │ (customer, multi- │
|
||||
└──────────────┘ │ restaurant cart) │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
## Lifecycle
|
||||
|
||||
`__init__.py` registers three permanent tasks on extension start
|
||||
(`create_permanent_unique_task`):
|
||||
|
||||
1. **Invoice listener** — `tasks.wait_for_paid_invoices` consumes
|
||||
LNbits' global payment queue, filters on
|
||||
`payment.extra.tag == "restaurant"`, and dispatches to
|
||||
[[order-flow|services.mark_order_paid]].
|
||||
2. **NostrClient bootstrap** — `nostr.nostr_client.NostrClient`
|
||||
connects to the `nostrclient` extension's internal WebSocket
|
||||
after a 10s grace.
|
||||
3. **Nostr sync** — `nostr_sync.wait_for_nostr_events` subscribes
|
||||
to the relevant filters once the client is up. NIP-17 unwrap is
|
||||
stubbed.
|
||||
|
||||
`restaurant_stop` cancels the three tasks and closes the WebSocket.
|
||||
|
||||
If `nostrclient` isn't enabled, the publisher / sync no-op gracefully
|
||||
and the extension still works — it just operates as REST-only without
|
||||
the [[nostr-layer]].
|
||||
|
||||
## Boundaries we keep
|
||||
|
||||
The extension only ever knows about **its own restaurant's** data.
|
||||
There is no global "festival" or "marketplace" entity stored anywhere
|
||||
in `restaurant.*` tables. Cross-restaurant grouping is the customer
|
||||
webapp's concern; see [[webapp-integration]].
|
||||
|
||||
## See also
|
||||
|
||||
- [[data-model]] — the entity catalog
|
||||
- [[order-flow]] — payment lands → print job
|
||||
- [[nostr-layer]] — what propagates outward
|
||||
- [[adr-0001-menu-tree]] — why the menu storage choice
|
||||
Loading…
Add table
Add a link
Reference in a new issue