Commit graph

5 commits

Author SHA1 Message Date
0631edf8a2 feat: public guest room discovery endpoints (slice 1 for webapp #141)
GET /public/rooms + /public/rooms/{id} — no auth, active rooms only,
operator-private fields stripped. The webapp guest UI needs these because
the existing GET /rooms is admin-scoped; availability + booking POST are
already public. Reuses the public_room_dict strip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
2026-07-20 01:39:39 +02:00
f715d728ef feat: operator admin REST endpoints (rooms/blocks/bookings/settings)
Adds the HTTP surface the admin UI needs, all admin-key + ownership-scoped:
- rooms: list (filtered to caller's wallet), update (PUT), delete, publish /
  unpublish (with ownership checks; publish/unpublish flip status + sync the
  relay listing).
- per-room: GET bookings, GET blocks.
- blocks: create (ownership-checked) + delete.
- settings: GET + PUT (merges only the editable fields).

_owned_room centralizes the 404/403 ownership guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
2026-07-20 00:44:10 +02:00
5cfc9b893d refactor: extract booking flow into services.py
Move availability quoting + the check-then-hold + invoice orchestration out
of views_api.py into a transport-agnostic services.py, with typed errors
(NotFound/Unavailable/ValueError/BookingError). views_api becomes a thin
HTTP door that maps those to status codes. No behavior change — this is so
the incoming nostr-transport door can share one booking flow instead of
duplicating it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
2026-07-19 01:30:13 +02:00
4df137190f feat: wire FX + deposit invoice into the booking hold (#3)
Booking requests now complete end-to-end over HTTP:

- _to_sats() converts fiat->sats via fiat_amount_as_satoshis (sat/sats
  pass through). This is the single conversion point; the result is the
  canonical amount_sat and is not recomputed downstream.
- api_request_booking creates a sats-denominated deposit invoice (locked
  amount, immune to FX drift before payment), tagged {tag:chatelet,
  booking_id} so tasks.on_invoice_paid matches the settle. On InvoiceError
  the hold is released (status=declined) so dead holds don't block dates.
- New BookingQuote response returns the held booking + bolt11 + hash.

Settlement (tasks.on_invoice_paid: awaiting_payment -> confirmed, dates
hard-blocked, reservation republished) was already in place and now fires
on real payments. Testable on FakeWallet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
2026-07-19 00:26:14 +02:00
d5df9ab662 feat: REST API + operator admin route
views_api.py exposes the booking flow over HTTP — availability check,
guest booking request (check-then-hold with canonical amount_sat), room
publish, blocks. REST and Nostr are two doors into the same crud flow;
FX + invoice creation marked TODO. views.py serves the operator page.

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