axe/internal/db/migrations/0014_recurring_rules.sql
2026-10-18 22:07:25 +03:00

82 lines
4.6 KiB
SQL
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- 0014_recurring_rules — повторяющиеся заявки по расписанию.
--
-- Зачем: периодические работы («осмотр вентиляции раз в 3 месяца»)
-- заводятся один раз правилом, а фоновый планировщик сам создаёт
-- заявку, когда истекает интервал. Правило — шаблон будущей заявки
-- (объект, категория, описание, приоритет) плюс интервал в месяцах.
--
-- Кто владеет: client_id — клиент-владелец (заявка создаётся от его
-- имени, как ручная); created_by — кто завёл правило (админ или сам
-- клиент). Правило живёт в проекте и объекте: каскады унесут его
-- вместе с ними (удаление проекта админом из 0013).
--
-- Повторный запуск: правило созрело, но прошлая заявка ещё не
-- закрыта — новую не создаём (ждём закрытия, без дублей). Состояние
-- хранится в last_run_at (когда последний раз срабатывали) и в
-- recurring_runs (история: какая заявка создана по какому правилу).
--
-- Применённый файл не редактировать (checksum в schema_migrations).
-- ============ recurring_rules ============
CREATE TABLE IF NOT EXISTS recurring_rules (
id bigserial PRIMARY KEY,
-- Владелец будущих заявок: client_id проекта продублирован, чтобы
-- заявка создавалась без JOIN и составной FK projects был соблюдён.
client_id uuid NOT NULL REFERENCES profiles (id),
project_id bigint NOT NULL REFERENCES projects (id) ON DELETE CASCADE,
object_id bigint NOT NULL REFERENCES project_objects (id) ON DELETE CASCADE,
-- Шаблон заявки (те же колонки, что в tickets).
category text NOT NULL,
description text NOT NULL,
priority text NOT NULL DEFAULT 'normal',
floor text,
-- Расписание: 3 — квартальный осмотр, 12 — годовой.
interval_months int NOT NULL,
is_active boolean NOT NULL DEFAULT true,
-- Когда последний раз срабатывали; NULL — ещё ни разу.
last_run_at timestamptz,
created_by uuid REFERENCES profiles (id),
created_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT recurring_rules_category_check
CHECK (category IN ('electric', 'plumbing', 'climate', 'elevator', 'other')),
CONSTRAINT recurring_rules_priority_check
CHECK (priority IN ('low', 'normal', 'high')),
CONSTRAINT recurring_rules_interval_check
CHECK (interval_months >= 1),
-- Правило обязано жить в объекте своего проекта (то же ядро, что
-- у заявки): составной FK держит объект и проект согласованными.
CONSTRAINT recurring_rules_object_project_fk
FOREIGN KEY (object_id, project_id)
REFERENCES project_objects (id, project_id),
CONSTRAINT recurring_rules_project_client_fk
FOREIGN KEY (project_id, client_id)
REFERENCES projects (id, client_id)
);
-- Лента правил: клиент — свои, админ — все проекты.
CREATE INDEX IF NOT EXISTS recurring_rules_client_idx ON recurring_rules (client_id);
CREATE INDEX IF NOT EXISTS recurring_rules_project_idx ON recurring_rules (project_id);
-- Отбор созревших правил поллером.
CREATE INDEX IF NOT EXISTS recurring_rules_due_idx
ON recurring_rules (last_run_at) WHERE is_active;
-- ============ recurring_runs ============
-- История срабатываний: аудит «кто и когда создал авто-заявку».
CREATE TABLE IF NOT EXISTS recurring_runs (
id bigserial PRIMARY KEY,
rule_id bigint NOT NULL REFERENCES recurring_rules (id) ON DELETE CASCADE,
-- NULL, если созданную заявку потом удалили каскадом (проект).
ticket_id bigint REFERENCES tickets (id) ON DELETE SET NULL,
run_at timestamptz NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS recurring_runs_rule_idx ON recurring_runs (rule_id, run_at DESC);