No description
  • Python 87.2%
  • HTML 7.3%
  • JavaScript 5.3%
  • Makefile 0.2%
Find a file
Padreug 9ab52f2c69 feat: per-operator settings — house rules + card acceptance (multi-tenant)
Chatelet is multi-tenant: any LNbits user can host rooms. What an operator
decides for all their rooms now lives in chatelet.operator_settings, keyed
by user id and created lazily (m003, which also indexes bookings by guest):
check-in/out times, cancellation policy, and accept_fiat.

Guests see it: the public room view (both doors) gains house_rules and
payment_methods, and the kind:30402 listing carries payment_methods,
checkin_time and checkout_time tags so a generic Nostr client can render
the right pay buttons and rules without our RPC. The check-in DM reads the
room owner's rules instead of the instance row.

Card is offered only when the operator opted in, the room is fiat-priced,
and LNbits core has a fiat provider for that user — resolved through
settings.get_fiat_providers_for_user(owner), the one seam lnbits#67's
per-user Stripe credentials will plug into; chatelet never sees creds.

Operator endpoints: GET/PUT /api/v1/operator (admin key → wallet user) and
RPC twins chatelet_operator_get/update (AUTH_WALLET); saving re-publishes
the owner's active listings. Admin UI moves the house-rule inputs into a
per-operator card with the card toggle and a provider hint. The old
house-rule columns on settings stay for old rows but are no longer read.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 12:16:14 +02:00
docs feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
nostr feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
static feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
templates/chatelet feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
tests feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
.gitignore chore: scaffold chatelet LNbits extension 2026-07-19 00:16:23 +02:00
__init__.py feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
config.json chore(release): v0.4.0 2026-09-15 23:53:16 +02:00
crud.py feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
LICENSE chore: scaffold chatelet LNbits extension 2026-07-19 00:16:23 +02:00
Makefile chore: add test + lint tooling (pyproject, Makefile) 2026-07-19 17:48:11 +02:00
migrations.py feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
models.py feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
pyproject.toml chore: add test + lint tooling (pyproject, Makefile) 2026-07-19 17:48:11 +02:00
README.md docs: relay-transport (nostrclient) section + dependency note 2026-07-19 18:09:35 +02:00
services.py feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
tasks.py feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
transport_rpcs.py feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00
views.py feat: REST API + operator admin route 2026-07-19 00:16:57 +02:00
views_api.py feat: per-operator settings — house rules + card acceptance (multi-tenant) 2026-09-16 12:16:14 +02:00

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

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