Commit graph

3 commits

Author SHA1 Message Date
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
b6ca1b0e02 feat: NIP-17 gift-wrapped check-in DM on confirmation (#5)
On settlement, send the guest their private check-in details as a NIP-59
gift-wrapped DM (nostr/giftwrap.py, built from lnbits core primitives — no
vendored crypto):

- rumor (kind 14) -> seal (kind 13, operator-encrypted + operator-signed via
  the signer abstraction) -> gift wrap (kind 1059, ephemeral-key encrypted +
  signed locally via core nip44_encrypt + sign_event). created_at randomised
  into the past per NIP-59.
- service.send_checkin_dm builds the message (room.checkin_instructions +
  settings times/policy) and publishes via nostrclient (_publish_signed,
  extracted from _sign_and_publish).
- tasks.on_invoice_paid calls it best-effort — a DM failure never undoes a
  confirmed, paid booking.

Encrypted layer (seal) soft-fails on a LocalSigner until bunker/server-
signing (lnbits#18), same as the reservation event; the ephemeral wrap layer
always works.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
2026-07-19 20:34:12 +02:00
43cfa5d921 feat: background tasks — settle on payment, expire holds
Payment (not any nostr event) is the commit point: the invoice listener
promotes held/awaiting_payment bookings to confirmed, hard-blocks the
dates, and republishes the encrypted reservation object. expire_holds_loop
sweeps lapsed holds every minute so abandoned requests free their dates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
2026-07-19 00:16:57 +02:00