from django.db import migrations CREATE_CLIENT_FOLLOW_LOGS = """ CREATE TABLE client_follow_logs ( id UUID NOT NULL DEFAULT gen_random_uuid(), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), client_id UUID NOT NULL REFERENCES clients(id) ON DELETE CASCADE, log_type VARCHAR(30) NOT NULL CHECK (log_type IN ('written','modified','sensitive_view', 'other','system')), purpose VARCHAR(50), content TEXT, log_tag VARCHAR(50), change_detail JSONB, is_public BOOLEAN NOT NULL DEFAULT TRUE, is_deletable BOOLEAN NOT NULL DEFAULT TRUE, operator_id UUID REFERENCES staff(id) ON DELETE SET NULL, operator_snapshot JSONB, deleted_at TIMESTAMPTZ, PRIMARY KEY (id, created_at) ) PARTITION BY RANGE (created_at); CREATE TABLE client_follow_logs_2026_04 PARTITION OF client_follow_logs FOR VALUES FROM ('2026-04-01') TO ('2026-05-01'); CREATE TABLE client_follow_logs_2026_05 PARTITION OF client_follow_logs FOR VALUES FROM ('2026-05-01') TO ('2026-06-01'); CREATE TABLE client_follow_logs_default PARTITION OF client_follow_logs DEFAULT; CREATE INDEX idx_cfl_client_time ON client_follow_logs(client_id, created_at DESC) WHERE deleted_at IS NULL; CREATE INDEX idx_cfl_type ON client_follow_logs(client_id, log_type, created_at DESC) WHERE deleted_at IS NULL; CREATE INDEX idx_cfl_operator ON client_follow_logs(operator_id, created_at DESC) WHERE deleted_at IS NULL; CREATE INDEX idx_cfl_sensitive ON client_follow_logs(client_id, created_at DESC) WHERE log_type = 'sensitive_view'; """ DROP_CLIENT_FOLLOW_LOGS = "DROP TABLE IF EXISTS client_follow_logs CASCADE;" CREATE_TRIGGERS = """ CREATE OR REPLACE FUNCTION update_client_last_follow() RETURNS TRIGGER AS $$ BEGIN IF NEW.log_type = 'written' THEN UPDATE clients SET last_follow_at = NEW.created_at, last_active_at = NEW.created_at, updated_at = NOW() WHERE id = NEW.client_id; END IF; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_client_last_follow AFTER INSERT ON client_follow_logs FOR EACH ROW EXECUTE FUNCTION update_client_last_follow(); CREATE OR REPLACE FUNCTION update_client_viewing_progress() RETURNS TRIGGER AS $$ BEGIN UPDATE clients SET updated_at = NOW() WHERE id = NEW.client_id; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER trg_client_viewing_progress AFTER INSERT ON client_viewings FOR EACH ROW EXECUTE FUNCTION update_client_viewing_progress(); """ DROP_TRIGGERS = """ DROP TRIGGER IF EXISTS trg_client_viewing_progress ON client_viewings; DROP FUNCTION IF EXISTS update_client_viewing_progress(); DROP TRIGGER IF EXISTS trg_client_last_follow ON client_follow_logs; DROP FUNCTION IF EXISTS update_client_last_follow(); """ CREATE_UNIQUE_CLIENT_NO = """ CREATE UNIQUE INDEX idx_clients_client_no_active ON clients(client_no) WHERE deleted_at IS NULL; """ DROP_UNIQUE_CLIENT_NO = "DROP INDEX IF EXISTS idx_clients_client_no_active;" class Migration(migrations.Migration): dependencies = [ ("fonrey_client", "0001_initial"), ] operations = [ migrations.RunSQL(CREATE_CLIENT_FOLLOW_LOGS, reverse_sql=DROP_CLIENT_FOLLOW_LOGS), migrations.RunSQL(CREATE_TRIGGERS, reverse_sql=DROP_TRIGGERS), migrations.RunSQL(CREATE_UNIQUE_CLIENT_NO, reverse_sql=DROP_UNIQUE_CLIENT_NO), ]