chore: scaffold chatelet LNbits extension

Nostr-native room rentals (Airbnb-style) for the castle. Establishes the
extension manifest, license, README with the design overview, and static
+ template placeholders. No booking logic yet — subsequent commits build
the model, schema, arbiter, Nostr layer, API, tasks, and wiring bottom-up.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
This commit is contained in:
Padreug 2026-07-19 00:16:23 +02:00
commit c756ac7cf6
6 changed files with 137 additions and 0 deletions

53
README.md Normal file
View file

@ -0,0 +1,53 @@
# Chatelet
Nostr-native room rentals for LNbits — an "Airbnb for the castle". List
rooms, take booking requests, arbitrate availability, and settle stays over
Lightning, with Nostr as the interop layer.
> **Status:** design sketch + scaffold. Data model, migrations, availability
> arbiter, REST surface, and Nostr event model are in place; relay plumbing,
> FX/invoice wiring, and the guest UI are stubbed with `TODO(...)` markers.
## Why not just reuse an existing NIP?
No single NIP models a rental-booking flow. Chatelet **composes** existing
NIPs and only invents an event kind where nothing fits:
| Concern | Mechanism |
|---|---|
| Room listing | **NIP-99** classified listing (`kind:30402`) |
| Guest's reservation record | **NIP-78** app data (`kind:30078`), NIP-44 encrypted |
| Public availability calendar | **NIP-52** (`kind:31923/31924`), no guest PII |
| Private request → quote → confirm | **NIP-17/59** giftwrapped DMs |
| Live "is it free?" query | aiolabs band **`kind:22000/22001`** (ephemeral) |
| Payment / deposit | LNbits Lightning invoice |
Full rationale in [`docs/adr-0001-nostr-event-model.md`](docs/adr-0001-nostr-event-model.md).
## The one invariant that matters
**LNbits is the booking authority; Nostr events are requests, not locks.**
Availability is *derived* from the DB (`bookings` + `blocks`), never stored
as a positive fact, and a date range is only truly locked when a `held`
booking row is written. Payment — not any Nostr event — promotes a booking
to `confirmed`.
## Docs
- [`docs/data-model.md`](docs/data-model.md) — tables, entities, lifecycle
- [`docs/event-flow.md`](docs/event-flow.md) — who publishes what, when (with sequence diagram)
- [`docs/adr-0001-nostr-event-model.md`](docs/adr-0001-nostr-event-model.md) — why these kinds
## Layout
```
config.json LNbits extension manifest
models.py data model (pydantic)
migrations.py schema (ext_chatelet DB)
crud.py persistence + the availability arbiter
views_api.py REST surface (shares the booking flow with Nostr)
views.py operator admin page route
tasks.py invoice listener (settle) + hold-expiry sweep
nostr/ event kinds, builders, sign/publish/subscribe service
docs/ design docs
```