PRAGMA foreign_keys = ON; CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, openid TEXT NOT NULL UNIQUE, unionid TEXT, phone TEXT, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, last_login_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE UNIQUE INDEX IF NOT EXISTS users_phone_unique_idx ON users(phone) WHERE phone IS NOT NULL AND phone <> ''; CREATE TABLE IF NOT EXISTS project_categories ( id TEXT PRIMARY KEY, name TEXT NOT NULL, sort INTEGER NOT NULL DEFAULT 0, status TEXT NOT NULL DEFAULT 'active', created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS projects ( id TEXT PRIMARY KEY, category_id TEXT NOT NULL REFERENCES project_categories(id), name TEXT NOT NULL, subtitle TEXT NOT NULL DEFAULT '', price_text TEXT NOT NULL, image TEXT NOT NULL DEFAULT '', status TEXT NOT NULL DEFAULT 'active', sort INTEGER NOT NULL DEFAULT 0, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS app_config ( config_key TEXT PRIMARY KEY, config_value TEXT NOT NULL DEFAULT '', updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS schedule_days ( id TEXT PRIMARY KEY, project_id TEXT NOT NULL REFERENCES projects(id), date TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'available', note TEXT NOT NULL DEFAULT '', created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE(project_id, date) ); CREATE TABLE IF NOT EXISTS time_slots ( id TEXT PRIMARY KEY, schedule_day_id TEXT NOT NULL REFERENCES schedule_days(id), start_time TEXT NOT NULL, end_time TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'available', created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE(schedule_day_id, start_time) ); CREATE TABLE IF NOT EXISTS bookings ( id TEXT PRIMARY KEY, user_id TEXT REFERENCES users(id), project_id TEXT NOT NULL REFERENCES projects(id), slot_id TEXT NOT NULL REFERENCES time_slots(id), phone TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', remark TEXT NOT NULL DEFAULT '', confirm_token TEXT NOT NULL, created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE IF NOT EXISTS price_inquiries ( id TEXT PRIMARY KEY, user_id TEXT REFERENCES users(id), phone TEXT NOT NULL, province TEXT NOT NULL, city TEXT NOT NULL, district TEXT NOT NULL, project_name TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', remark TEXT NOT NULL DEFAULT '', last_submitted_at TEXT NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'now', '+8 hours')), created_at TEXT NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'now', '+8 hours')), updated_at TEXT NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'now', '+8 hours')) ); CREATE UNIQUE INDEX IF NOT EXISTS price_inquiries_phone_unique_idx ON price_inquiries(phone); CREATE UNIQUE INDEX IF NOT EXISTS bookings_effective_unique_idx ON bookings(phone, project_id, slot_id) WHERE status IN ('pending', 'confirmed'); CREATE TABLE IF NOT EXISTS config_audit_logs ( id TEXT PRIMARY KEY, admin_id TEXT NOT NULL, target_type TEXT NOT NULL, target_id TEXT NOT NULL, action TEXT NOT NULL, before_json TEXT NOT NULL DEFAULT '{}', after_json TEXT NOT NULL DEFAULT '{}', created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP ); CREATE INDEX IF NOT EXISTS projects_category_idx ON projects(category_id, sort); CREATE INDEX IF NOT EXISTS schedule_days_project_date_idx ON schedule_days(project_id, date); CREATE INDEX IF NOT EXISTS time_slots_day_idx ON time_slots(schedule_day_id, start_time); CREATE INDEX IF NOT EXISTS bookings_phone_idx ON bookings(phone, created_at DESC); CREATE INDEX IF NOT EXISTS bookings_status_idx ON bookings(status, created_at DESC); CREATE INDEX IF NOT EXISTS price_inquiries_region_idx ON price_inquiries(province, city, district, created_at DESC);