From 6010531114a0cd22f32213c09ebfae380c973e87 Mon Sep 17 00:00:00 2001 From: HotelSync Date: Thu, 12 Mar 2026 12:09:53 +0300 Subject: [PATCH] Add migration 002: missing updated_at columns + auto-update triggers + indexes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tables fixed: - rooms → added updated_at - housekeeping_tasks → added updated_at - channels → added created_at + updated_at Trigger function set_updated_at() attached to all 6 tables (hotels, users, rooms, bookings, housekeeping_tasks, channels) — updated_at now auto-sets on every UPDATE via BEFORE UPDATE trigger. Indexes added for archiving / range queries: - bookings(hotel_id, created_at), bookings(hotel_id, updated_at) - housekeeping_tasks(hotel_id, created_at) - rooms(hotel_id, updated_at) - channels(hotel_id, updated_at) Also patched 001_schema.sql so fresh installs start correct. Migration runner is idempotent — skips already applied files. Co-Authored-By: Claude Sonnet 4.6 --- backend/migrations/001_schema.sql | 6 ++- backend/migrations/002_timestamps.sql | 75 +++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 backend/migrations/002_timestamps.sql diff --git a/backend/migrations/001_schema.sql b/backend/migrations/001_schema.sql index 4f7a6af..bb8c98c 100644 --- a/backend/migrations/001_schema.sql +++ b/backend/migrations/001_schema.sql @@ -43,6 +43,7 @@ CREATE TABLE IF NOT EXISTS rooms ( amenities TEXT[] NOT NULL DEFAULT '{}', notes TEXT, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(hotel_id, number) ); @@ -84,7 +85,8 @@ CREATE TABLE IF NOT EXISTS housekeeping_tasks ( notes TEXT, due_date DATE, completed_at TIMESTAMPTZ, - created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- ── Channels ─────────────────────────────────────────────────────────────── @@ -97,6 +99,8 @@ CREATE TABLE IF NOT EXISTS channels ( api_key_encrypted TEXT, hotel_external_id VARCHAR(255), last_synced_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(hotel_id, name) ); diff --git a/backend/migrations/002_timestamps.sql b/backend/migrations/002_timestamps.sql new file mode 100644 index 0000000..37c1df2 --- /dev/null +++ b/backend/migrations/002_timestamps.sql @@ -0,0 +1,75 @@ +-- Migration 002 — Add missing updated_at columns and auto-update trigger +-- ───────────────────────────────────────────────────────────────────────────── +-- Tables audit: +-- hotels ✅ created_at ✅ updated_at +-- users ✅ created_at ✅ updated_at +-- rooms ✅ created_at ❌ updated_at ← add +-- bookings ✅ created_at ✅ updated_at +-- housekeeping_tasks ✅ created_at ❌ updated_at ← add +-- channels ❌ created_at ❌ updated_at ← add both +-- ───────────────────────────────────────────────────────────────────────────── + +-- ── 1. Add missing columns ────────────────────────────────────────────────── + +ALTER TABLE rooms + ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); + +ALTER TABLE housekeeping_tasks + ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); + +ALTER TABLE channels + ADD COLUMN IF NOT EXISTS created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + ADD COLUMN IF NOT EXISTS updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(); + +-- ── 2. Trigger function: auto-set updated_at = NOW() on every UPDATE ──────── + +CREATE OR REPLACE FUNCTION set_updated_at() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- ── 3. Attach trigger to every table that has updated_at ──────────────────── +-- Using DROP IF EXISTS + CREATE so the migration is idempotent. + +DROP TRIGGER IF EXISTS trg_hotels_updated_at ON hotels; +DROP TRIGGER IF EXISTS trg_users_updated_at ON users; +DROP TRIGGER IF EXISTS trg_rooms_updated_at ON rooms; +DROP TRIGGER IF EXISTS trg_bookings_updated_at ON bookings; +DROP TRIGGER IF EXISTS trg_housekeeping_tasks_updated_at ON housekeeping_tasks; +DROP TRIGGER IF EXISTS trg_channels_updated_at ON channels; + +CREATE TRIGGER trg_hotels_updated_at + BEFORE UPDATE ON hotels + FOR EACH ROW EXECUTE FUNCTION set_updated_at(); + +CREATE TRIGGER trg_users_updated_at + BEFORE UPDATE ON users + FOR EACH ROW EXECUTE FUNCTION set_updated_at(); + +CREATE TRIGGER trg_rooms_updated_at + BEFORE UPDATE ON rooms + FOR EACH ROW EXECUTE FUNCTION set_updated_at(); + +CREATE TRIGGER trg_bookings_updated_at + BEFORE UPDATE ON bookings + FOR EACH ROW EXECUTE FUNCTION set_updated_at(); + +CREATE TRIGGER trg_housekeeping_tasks_updated_at + BEFORE UPDATE ON housekeeping_tasks + FOR EACH ROW EXECUTE FUNCTION set_updated_at(); + +CREATE TRIGGER trg_channels_updated_at + BEFORE UPDATE ON channels + FOR EACH ROW EXECUTE FUNCTION set_updated_at(); + +-- ── 4. Indexes on created_at for archiving / range queries ────────────────── +-- Нужны чтобы запрос "дай все записи старше 6 месяцев" работал быстро. + +CREATE INDEX IF NOT EXISTS idx_bookings_created_at ON bookings(hotel_id, created_at); +CREATE INDEX IF NOT EXISTS idx_bookings_updated_at ON bookings(hotel_id, updated_at); +CREATE INDEX IF NOT EXISTS idx_housekeeping_tasks_created_at ON housekeeping_tasks(hotel_id, created_at); +CREATE INDEX IF NOT EXISTS idx_rooms_updated_at ON rooms(hotel_id, updated_at); +CREATE INDEX IF NOT EXISTS idx_channels_updated_at ON channels(hotel_id, updated_at);