215 lines
8.6 KiB
SQL
215 lines
8.6 KiB
SQL
-- Drop kanban template scaffold.
|
|
DROP TABLE IF EXISTS kanban_card;
|
|
|
|
-- Seminarhof Drawehn core schema.
|
|
-- Multi-tenant from day one (venue_id on every domain row).
|
|
-- All money stored as integer cents (euro_cents) to avoid float drift.
|
|
|
|
-- ─────────────────────────────────────────────────────────────────────
|
|
-- Tenancy
|
|
|
|
CREATE TABLE IF NOT EXISTS venue (
|
|
venue_id TEXT PRIMARY KEY,
|
|
name TEXT NOT NULL,
|
|
slug TEXT NOT NULL UNIQUE,
|
|
locale_default TEXT NOT NULL DEFAULT 'de',
|
|
meal_window_breakfast TEXT NOT NULL DEFAULT '07:00-10:00',
|
|
meal_window_lunch TEXT NOT NULL DEFAULT '12:00-14:00',
|
|
meal_window_dinner TEXT NOT NULL DEFAULT '18:00-20:00',
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
-- ─────────────────────────────────────────────────────────────────────
|
|
-- Identity
|
|
|
|
CREATE TABLE IF NOT EXISTS app_user (
|
|
user_id TEXT PRIMARY KEY,
|
|
email TEXT NOT NULL UNIQUE,
|
|
name TEXT NOT NULL,
|
|
locale TEXT NOT NULL DEFAULT 'de',
|
|
role TEXT NOT NULL, -- 'admin' | 'client' | 'owner'
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS client (
|
|
client_id TEXT PRIMARY KEY,
|
|
venue_id TEXT NOT NULL REFERENCES venue(venue_id),
|
|
name TEXT,
|
|
is_stammgruppe INTEGER NOT NULL DEFAULT 0,
|
|
billing_address TEXT,
|
|
contact_email TEXT,
|
|
contact_phone TEXT,
|
|
website TEXT,
|
|
notes TEXT,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS client_member (
|
|
client_id TEXT NOT NULL REFERENCES client(client_id),
|
|
user_id TEXT NOT NULL REFERENCES app_user(user_id),
|
|
role TEXT NOT NULL DEFAULT 'organiser', -- 'organiser' | 'colleague'
|
|
PRIMARY KEY (client_id, user_id)
|
|
);
|
|
|
|
-- ─────────────────────────────────────────────────────────────────────
|
|
-- Physical inventory
|
|
|
|
CREATE TABLE IF NOT EXISTS bathroom (
|
|
bathroom_id TEXT PRIMARY KEY,
|
|
venue_id TEXT NOT NULL REFERENCES venue(venue_id),
|
|
label TEXT NOT NULL
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS room (
|
|
room_id TEXT PRIMARY KEY,
|
|
venue_id TEXT NOT NULL REFERENCES venue(venue_id),
|
|
number INTEGER NOT NULL,
|
|
beds INTEGER NOT NULL,
|
|
room_type TEXT NOT NULL, -- 'MBZ' | 'DZ' | 'EZ_only'
|
|
building TEXT NOT NULL, -- 'gaestehaus' | 'haupthaus'
|
|
floor TEXT NOT NULL, -- 'eg' | 'og'
|
|
bathroom_id TEXT REFERENCES bathroom(bathroom_id),
|
|
wheelchair INTEGER NOT NULL DEFAULT 0,
|
|
ground_floor INTEGER NOT NULL DEFAULT 0,
|
|
quiet INTEGER NOT NULL DEFAULT 0,
|
|
shared_bath INTEGER NOT NULL DEFAULT 0,
|
|
dogs_allowed INTEGER NOT NULL DEFAULT 0,
|
|
double_bed_140 INTEGER NOT NULL DEFAULT 0,
|
|
allergy_friendly INTEGER NOT NULL DEFAULT 0,
|
|
surcharge_eur_cents INTEGER NOT NULL DEFAULT 0,
|
|
UNIQUE (venue_id, number)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS seminar_room (
|
|
seminar_room_id TEXT PRIMARY KEY,
|
|
venue_id TEXT NOT NULL REFERENCES venue(venue_id),
|
|
name TEXT NOT NULL
|
|
);
|
|
|
|
-- ─────────────────────────────────────────────────────────────────────
|
|
-- Bookings
|
|
|
|
CREATE TABLE IF NOT EXISTS booking (
|
|
booking_id TEXT PRIMARY KEY,
|
|
venue_id TEXT NOT NULL REFERENCES venue(venue_id),
|
|
client_id TEXT NOT NULL REFERENCES client(client_id),
|
|
event_name TEXT NOT NULL,
|
|
start_date TEXT,
|
|
end_date TEXT,
|
|
status TEXT NOT NULL, -- enquiry | form_received | reserved | deposit_paid | confirmed | ended | cancelled
|
|
half_house INTEGER NOT NULL DEFAULT 0,
|
|
online_ad INTEGER NOT NULL DEFAULT 0,
|
|
cover_image_url TEXT,
|
|
short_description TEXT,
|
|
organiser_website TEXT,
|
|
expected_persons INTEGER,
|
|
meal_time_breakfast TEXT,
|
|
meal_time_lunch TEXT,
|
|
meal_time_dinner TEXT,
|
|
daily_plan TEXT,
|
|
arrival_time TEXT,
|
|
departure_time TEXT,
|
|
payment_method TEXT NOT NULL DEFAULT 'transfer', -- 'cash' | 'transfer'
|
|
agb_year INTEGER,
|
|
agb_accepted_at TEXT,
|
|
privacy_accepted_at TEXT,
|
|
notes TEXT,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_booking_venue_dates
|
|
ON booking (venue_id, start_date, end_date);
|
|
CREATE INDEX IF NOT EXISTS idx_booking_client
|
|
ON booking (client_id);
|
|
CREATE INDEX IF NOT EXISTS idx_booking_status
|
|
ON booking (venue_id, status);
|
|
|
|
CREATE TABLE IF NOT EXISTS booking_extra (
|
|
booking_extra_id TEXT PRIMARY KEY,
|
|
booking_id TEXT NOT NULL REFERENCES booking(booking_id),
|
|
kind TEXT NOT NULL, -- 'cake' | 'second_seminar_room' | 'early_arrival' | 'bedlinen' | 'massage_bench' | 'sauna'
|
|
qty INTEGER NOT NULL DEFAULT 1,
|
|
on_dates TEXT, -- JSON array of dates for cake-day picker
|
|
unit_price_cents INTEGER NOT NULL DEFAULT 0,
|
|
note TEXT
|
|
);
|
|
|
|
-- ─────────────────────────────────────────────────────────────────────
|
|
-- Participants
|
|
|
|
CREATE TABLE IF NOT EXISTS participant (
|
|
participant_id TEXT PRIMARY KEY,
|
|
booking_id TEXT NOT NULL REFERENCES booking(booking_id),
|
|
name TEXT NOT NULL,
|
|
email TEXT,
|
|
age INTEGER,
|
|
kind TEXT NOT NULL DEFAULT 'overnight', -- 'overnight' | 'day_guest'
|
|
dietary_tag TEXT, -- 'omnivore' | 'vegetarian' | 'vegan' | 'gluten_free' | 'lactose_free' | 'pescatarian' | 'unknown'
|
|
free_text TEXT,
|
|
self_form_token TEXT UNIQUE,
|
|
self_form_submitted_at TEXT,
|
|
notes TEXT,
|
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_participant_booking
|
|
ON participant (booking_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS participant_allergy (
|
|
participant_id TEXT NOT NULL REFERENCES participant(participant_id),
|
|
allergen TEXT NOT NULL, -- 'nuts' | 'soy' | 'gluten_strict' | 'dairy' | 'egg' | 'fish' | 'other'
|
|
severity TEXT NOT NULL DEFAULT 'standard', -- 'standard' | 'separate_prep'
|
|
note TEXT,
|
|
PRIMARY KEY (participant_id, allergen)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS room_assignment (
|
|
booking_id TEXT NOT NULL REFERENCES booking(booking_id),
|
|
participant_id TEXT NOT NULL REFERENCES participant(participant_id),
|
|
room_id TEXT NOT NULL REFERENCES room(room_id),
|
|
PRIMARY KEY (booking_id, participant_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_room_assignment_room
|
|
ON room_assignment (room_id);
|
|
|
|
-- ─────────────────────────────────────────────────────────────────────
|
|
-- Invoicing
|
|
|
|
CREATE TABLE IF NOT EXISTS invoice (
|
|
invoice_id TEXT PRIMARY KEY,
|
|
booking_id TEXT NOT NULL REFERENCES booking(booking_id),
|
|
kind TEXT NOT NULL, -- 'deposit' | 'final'
|
|
invoice_number TEXT NOT NULL UNIQUE,
|
|
issued_on TEXT NOT NULL,
|
|
due_on TEXT,
|
|
paid_on TEXT,
|
|
amount_cents INTEGER NOT NULL,
|
|
status TEXT NOT NULL DEFAULT 'outstanding', -- 'outstanding' | 'paid' | 'cancelled'
|
|
pdf_url TEXT,
|
|
datev_ref TEXT
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_invoice_booking
|
|
ON invoice (booking_id);
|
|
|
|
-- ─────────────────────────────────────────────────────────────────────
|
|
-- Audit
|
|
|
|
CREATE TABLE IF NOT EXISTS audit_log (
|
|
audit_id TEXT PRIMARY KEY,
|
|
venue_id TEXT NOT NULL REFERENCES venue(venue_id),
|
|
user_id TEXT REFERENCES app_user(user_id),
|
|
entity TEXT NOT NULL,
|
|
entity_id TEXT NOT NULL,
|
|
field TEXT,
|
|
before_value TEXT,
|
|
after_value TEXT,
|
|
action TEXT NOT NULL, -- 'create' | 'update' | 'delete'
|
|
at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_audit_entity
|
|
ON audit_log (entity, entity_id);
|