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

56 lines
3.2 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.

-- 0006_ticket_events — журнал событий заявки.
--
-- Каждый переход статусной машины оставляет запись: кто сделал, что было,
-- что стало, причина (для rejected/canceled) и когда. Запись создаётся
-- **в той же SQL-операции**, что и сам переход (CTE: UPDATE … RETURNING
-- → INSERT в журнал), поэтому «заявка перешла, а истории нет» невозможно:
-- либо обе части, либо ни одной.
--
-- from_status NULL — только у события «создана»: заявка появилась
-- из ничего. to_status всегда заполнен. actor_id может стать NULL
-- при удалении аккаунта — история не пропадает, остаётся «кто-то».
--
-- Действия: created, assigned, started, done, confirmed, rejected, canceled.
-- Названия действий отделены от статусов: одинаковый to_status='closed'
-- дают и принятие клиента (confirmed), и отмена (canceled) — журналу
-- важно именно «что сделали», а не только «куда ушло».
--
-- Старые заявки (до этой миграции) журнала не имеют — история начинается
-- с момента наката.
--
-- Применённый файл не редактировать (checksum в schema_migrations).
CREATE TABLE ticket_events (
id bigserial PRIMARY KEY,
ticket_id bigint NOT NULL REFERENCES tickets(id) ON DELETE CASCADE,
-- NULL — аккаунт автора удалён (ON DELETE SET NULL)
actor_id uuid REFERENCES profiles(id) ON DELETE SET NULL,
action text NOT NULL,
from_status text,
to_status text NOT NULL,
-- причина отклонения/отмены, для остальных действий пусто
comment text,
created_at timestamptz NOT NULL DEFAULT now(),
CONSTRAINT ticket_events_action_check
CHECK (action IN ('created', 'assigned', 'started', 'done',
'confirmed', 'rejected', 'canceled')),
CONSTRAINT ticket_events_from_status_check
CHECK (from_status IS NULL OR from_status IN
('new', 'assigned', 'in_progress', 'done', 'confirmed',
'rejected', 'closed')),
CONSTRAINT ticket_events_to_status_check
CHECK (to_status IN
('new', 'assigned', 'in_progress', 'done', 'confirmed',
'rejected', 'closed')),
-- причина нужна ровно там, где её требует машина статусов
CONSTRAINT ticket_events_comment_shape
CHECK (action NOT IN ('rejected', 'canceled')
OR comment IS NOT NULL)
);
-- Журнал читается по заявке в хронологии: (ticket_id, id) покрывает
-- и выборку страницы, и сортировку по умолчанию.
CREATE INDEX IF NOT EXISTS idx_ticket_events_ticket
ON ticket_events (ticket_id, id);