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:
Padreug 2026-05-02 09:34:07 +02:00
commit 42a8b08a5b
11 changed files with 1015 additions and 0 deletions

88
docs/cms.md Normal file
View file

@ -0,0 +1,88 @@
# CMS
The operator-facing console — what the restaurant owner sees when
they enable the extension. Lives under `/restaurant/...` and uses
LNbits' built-in **Vue 3.5 + Quasar 2.18 UMD** runtime: no build
step, no bundler, just Jinja templates including a per-page JS file.
## Pages
All pages extend `base.html` (provided by LNbits core) and require a
logged-in user (`check_user_exists`).
| Path | Template | Script | Purpose |
|---|---|---|---|
| `/restaurant/` | `restaurant/index.html` | `static/js/index.js` | Restaurant list / dashboard |
| `/restaurant/{slug}` | `restaurant/menu.html` | `static/js/menu.js` | [[menu-tree\|menu]] builder (q-tree) |
| `/restaurant/{slug}/orders` | `restaurant/orders.html` | `static/js/orders.js` | Order monitor |
| `/restaurant/{slug}/kds` | `restaurant/kds.html` | `static/js/kds.js` | Kitchen Display |
| `/restaurant/{slug}/settings` | `restaurant/settings.html` | `static/js/settings.js` | Restaurant + extension settings |
## Conventions
- `{% extends "base.html" %}` and `{% from "macros.jinja" import window_vars with context %}`.
- Page content goes in `{% block page %}`. Scripts in `{% block scripts %}`, after `{{ window_vars(user) }}`.
- The page JS sets `window.app = Vue.createApp({mixins: [windowMixin], data, methods, created})`. LNbits' `init-app.js` runs after the extension scripts and finishes the mount with `app.use(Quasar)` + `app.mount('#vue')`**don't call `.mount()` yourself**.
- Bootstrap data is injected via `<script>window.X = {{ thing | tojson | safe }}</script>` between the macro and the per-page script.
- The shared REST client is `static/js/api.js`, exposing `window.RestaurantAPI` (one method per resource).
## Menu builder (q-tree)
The menu page uses Quasar's `q-tree` directly off the hydrated tree
returned by `GET /api/v1/restaurants/{id}/menu`. Three-pane layout:
```
+--------------------+----------------+----------------------------+
| sidebar nav | q-tree | Items panel |
| (orders / KDS / | with inline | (filtered by selected |
| settings links) | edit buttons | tree node) |
+--------------------+----------------+----------------------------+
```
Custom `default-header` slot renders:
- node name + item-count badge + child-count hint
- inline buttons: `add` (disabled at depth 3), `edit`,
`drive_file_move`, `delete` (with cascade prompt)
Add-root button sits above the tree (`+ New top-level`).
The Move dialog uses a flat-indented `q-select` of all nodes,
filtered to exclude the moved node + its descendants and any
depth-3 candidate. (The server enforces both checks too — see
[[menu-tree]].)
Drag-drop reorder is **v2**; v1 uses the explicit Move dialog.
## Item dialog
The item dialog includes a flat-indented `q-select` for `node_id`,
populated by walking the tree with em-space indentation per depth
level. An item can land on any node, not just leaves.
Modifier groups + modifiers live in a separate dialog (a child of
the item dialog) with the `chooseOne / chooseMany / required /
optional` semantics from [[data-model|the data model]].
## Order monitor + KDS
Both use the same data source (`GET /restaurants/{id}/orders`)
filtered by status. The KDS view escalates color by age (`>5min`
orange, `>15min` red) and offers one-tap state transitions.
Today the monitor + KDS poll every 58 s. SSE / Nostr push is on
the roadmap.
## Settings
`settings.html` saves restaurant fields via
`PUT /restaurants/{id}` and (for LNbits admins) extension-wide
toggles via `PUT /settings`. NIP-17 orders toggle is currently
disabled because the unwrap step is stubbed — see [[nostr-layer]].
## See also
- [[architecture]]
- [[menu-tree]]
- [[order-flow]]
- [[api-reference]]