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>
16 tests, run under the LNbits pytest env (spirekeeper pattern: monkeypatch
crud/invoice, drive async via asyncio.run — no live DB/wallet):
- test_availability: half-open overlap semantics (back-to-back stays OK),
and is_available blocking on held/confirmed bookings + manual blocks.
- test_booking_flow: canonical amount_sat, awaiting_payment transition,
min-nights guard, and hold-release (declined) on InvoiceError.
- test_atomic_hold: the #4 regression — two concurrent same-date requests
yield exactly one hold + one conflict; non-overlapping both succeed. The
fakes yield mid-check to open the race window, so the test fails without
the per-room lock (verified by neutering it) and passes with it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD