- Python 83.5%
- HTML 9.5%
- JavaScript 6.8%
- Makefile 0.2%
|
|
||
|---|---|---|
| docs | ||
| nostr | ||
| static | ||
| templates/chatelet | ||
| tests | ||
| .gitignore | ||
| __init__.py | ||
| config.json | ||
| crud.py | ||
| LICENSE | ||
| Makefile | ||
| migrations.py | ||
| models.py | ||
| pyproject.toml | ||
| README.md | ||
| services.py | ||
| tasks.py | ||
| transport_rpcs.py | ||
| views.py | ||
| views_api.py | ||
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: functional prototype. Data model, migrations, availability arbiter (atomic hold), FX + invoice + settlement, the REST + kind-21000 RPC doors, and the nostrclient relay layer (publish + availability queries) are in place and tested. The guest UI and encrypted-event delivery pre-bunker are the remaining gaps.
Soft dependency: publishing/subscribing to relays uses the nostrclient extension (imported in-process). Install + activate it to reach relays; if absent, the booking flow still works over HTTP/RPC and relay publish is skipped with a logged warning. Encrypted events (reservation
30078, check-in DMs) additionally need a bunker/server-signing signer (lnbits #18); on a LocalSigner they soft-fail until then.
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.
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— tables, entities, lifecycledocs/event-flow.md— who publishes what, when (with sequence diagram)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