-- 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);