feat: schema migrations
settings/rooms/bookings/blocks in ext_chatelet, with room+status and payment_hash indexes for the overlap and settle hot paths. Ordinary migrations (not the fork split — this is aio-original, no upstream to rebase onto); still idempotent-friendly. No availability table by design. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
This commit is contained in:
parent
ab892cabec
commit
95e5bcb136
1 changed files with 113 additions and 0 deletions
113
migrations.py
Normal file
113
migrations.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
"""Chatelet schema migrations.
|
||||
|
||||
This is a brand-new aiolabs-original extension (not a fork of an upstream
|
||||
LNbits extension), so there is no upstream migrations.py to stay byte-
|
||||
identical with — we use ordinary migrations here and do NOT need the
|
||||
migrations_fork.py split (that pattern only earns its keep on forks that
|
||||
rebase onto upstream). Every migration is still written idempotently so a
|
||||
partial/re-run boot can't wedge the schema.
|
||||
|
||||
Tables live in ext_chatelet.sqlite3 (SQLite) or the `chatelet` Postgres
|
||||
schema. Availability is intentionally NOT a table — it is derived from
|
||||
`bookings` + `blocks` at query time (see crud.is_available).
|
||||
"""
|
||||
|
||||
|
||||
async def m001_initial(db):
|
||||
"""Settings, rooms, bookings, blocks."""
|
||||
|
||||
# One row: castle/operator-wide config.
|
||||
await db.execute(
|
||||
f"""
|
||||
CREATE TABLE chatelet.settings (
|
||||
operator_id TEXT,
|
||||
relays TEXT NOT NULL DEFAULT '[]',
|
||||
default_hold_minutes INTEGER NOT NULL DEFAULT 30,
|
||||
deposit_percent INTEGER NOT NULL DEFAULT 100,
|
||||
checkin_time TEXT NOT NULL DEFAULT '15:00',
|
||||
checkout_time TEXT NOT NULL DEFAULT '11:00',
|
||||
cancellation_policy TEXT NOT NULL DEFAULT '',
|
||||
publish_availability BOOLEAN NOT NULL DEFAULT true,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now},
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
|
||||
);
|
||||
"""
|
||||
)
|
||||
|
||||
# Rooms == NIP-99 kind:30402 listings. `id` doubles as the listing "d" tag.
|
||||
await db.execute(
|
||||
f"""
|
||||
CREATE TABLE chatelet.rooms (
|
||||
id TEXT PRIMARY KEY,
|
||||
wallet TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
price_amount REAL NOT NULL,
|
||||
price_currency TEXT NOT NULL DEFAULT 'EUR',
|
||||
price_frequency TEXT NOT NULL DEFAULT 'night',
|
||||
max_guests INTEGER NOT NULL DEFAULT 2,
|
||||
min_nights INTEGER NOT NULL DEFAULT 1,
|
||||
amenities TEXT NOT NULL DEFAULT '[]',
|
||||
location TEXT NOT NULL DEFAULT '',
|
||||
geohash TEXT NOT NULL DEFAULT '',
|
||||
images TEXT NOT NULL DEFAULT '[]',
|
||||
status TEXT NOT NULL DEFAULT 'inactive',
|
||||
listing_event_id TEXT,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now},
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
|
||||
);
|
||||
"""
|
||||
)
|
||||
|
||||
# Bookings == kind:30078 reservation objects. `amount_sat` is canonical.
|
||||
await db.execute(
|
||||
f"""
|
||||
CREATE TABLE chatelet.bookings (
|
||||
id TEXT PRIMARY KEY,
|
||||
room_id TEXT NOT NULL REFERENCES {db.references_schema}rooms (id),
|
||||
guest_pubkey TEXT NOT NULL,
|
||||
guest_contact TEXT,
|
||||
check_in TEXT NOT NULL,
|
||||
check_out TEXT NOT NULL,
|
||||
nights INTEGER NOT NULL,
|
||||
num_guests INTEGER NOT NULL DEFAULT 1,
|
||||
currency TEXT NOT NULL,
|
||||
price_fiat REAL NOT NULL,
|
||||
amount_sat {db.big_int} NOT NULL,
|
||||
deposit_sat {db.big_int} NOT NULL,
|
||||
status TEXT NOT NULL DEFAULT 'held',
|
||||
payment_hash TEXT,
|
||||
request_event_id TEXT,
|
||||
reservation_event_id TEXT,
|
||||
expires_at TIMESTAMP,
|
||||
created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now},
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
|
||||
);
|
||||
"""
|
||||
)
|
||||
# Overlap checks scan by room + status; index the hot path.
|
||||
await db.execute(
|
||||
"CREATE INDEX idx_chatelet_bookings_room_status "
|
||||
"ON chatelet.bookings (room_id, status);"
|
||||
)
|
||||
await db.execute(
|
||||
"CREATE INDEX idx_chatelet_bookings_payment_hash "
|
||||
"ON chatelet.bookings (payment_hash);"
|
||||
)
|
||||
|
||||
# Manual owner-side blocks (maintenance, personal use).
|
||||
await db.execute(
|
||||
f"""
|
||||
CREATE TABLE chatelet.blocks (
|
||||
id TEXT PRIMARY KEY,
|
||||
room_id TEXT NOT NULL REFERENCES {db.references_schema}rooms (id),
|
||||
start_date TEXT NOT NULL,
|
||||
end_date TEXT NOT NULL,
|
||||
reason TEXT NOT NULL DEFAULT '',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
|
||||
);
|
||||
"""
|
||||
)
|
||||
await db.execute(
|
||||
"CREATE INDEX idx_chatelet_blocks_room ON chatelet.blocks (room_id);"
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue