import pg from 'pg' const { Pool } = pg export const pool = new Pool({ connectionString: process.env.DATABASE_URL }) export async function initDb() { await pool.query(` -- Instance-level config: task display, twin detection, note visibility, etc. CREATE TABLE IF NOT EXISTS config ( key TEXT PRIMARY KEY, value JSONB NOT NULL, updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Rolling activity log. Pruned to 48h on each write. CREATE TABLE IF NOT EXISTS activity_log ( id SERIAL PRIMARY KEY, room_id TEXT NOT NULL, event_type TEXT NOT NULL, event_data JSONB, user_name TEXT, occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), service_date DATE NOT NULL, booking_ref TEXT ); CREATE INDEX IF NOT EXISTS activity_log_date_idx ON activity_log (service_date, occurred_at DESC); -- Lightweight NewBook change signals from the poller. No booking data stored. CREATE TABLE IF NOT EXISTS newbook_pings ( id SERIAL PRIMARY KEY, booking_ids TEXT[] NOT NULL, event_types TEXT[] NOT NULL, detected_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), expires_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + INTERVAL '5 minutes' ); CREATE INDEX IF NOT EXISTS newbook_pings_expires_idx ON newbook_pings (expires_at); `) await seedDefaultConfig() } async function seedDefaultConfig() { const defaults = { task_display: {}, twin_detection: { enabled: true, custom_field_ids: [], keywords: ['twin', 'two single', '2 single', 'single beds', 'sofabed', 'sofa bed'], exclude_keywords: ['twin room', 'twin suite'], }, extra_bed_detection: { enabled: true, keywords: ['extra bed', 'extra cot', 'rollaway', 'roll away', 'fold out'], }, excluded_categories: [], hide_excluded_categories: false, visible_note_types: [], checkout_notification_timeout: 30, default_checkout_time: process.env.DEFAULT_CHECKOUT_TIME || '11:00', } for (const [key, value] of Object.entries(defaults)) { await pool.query( `INSERT INTO config (key, value) VALUES ($1, $2) ON CONFLICT (key) DO NOTHING`, [key, JSON.stringify(value)] ) } }