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

61 lines
3.8 KiB
SQL
Raw 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.

-- 0005_project_invitations — приглашения мастеров в проект.
--
-- Раньше POST /projects/:id/workers сразу давало членство. Теперь это
-- ровно два шага и без обходных путей:
-- 1) клиент/админ отправляет приглашение — строка получает 'invited'
-- и срок жизни expires_at (7 дней);
-- 2) мастер сам решает: accept → 'active' (и только тогда получает
-- заявки проекта) или decline → 'declined' (повторное приглашение
-- перезапускает ту же строку).
-- Принудительного членства (force) нет: активным мастер становится
-- только своим решением.
--
-- Статусы строки project_workers:
-- invited — ждём решения мастера (expires_at обязателен, см. CHECK);
-- active — мастер принял: назначение заявок разрешено;
-- declined — мастер отказал; строка остаётся как история отказа
-- и допускает повторное приглашение.
--
-- Строки, созданные до этой миграции, получают DEFAULT 'active' —
-- членство существующих мастеров не ломается.
--
-- Принцип прежний: переходы проверяются в самом SQL:
-- * назначение заявки требует членства status='active' — приглашённый
-- не получает заявки, пока не принял (см. Assign в repository/ticket.go);
-- * accept/decline двигают только строку в статусе 'invited';
-- * уход мастера (DELETE) снимает строку любого статуса — так же
-- отзывается и не принятое приглашение.
--
-- Применённый файл не редактировать (checksum в schema_migrations).
ALTER TABLE project_workers
ADD COLUMN status text NOT NULL DEFAULT 'active',
ADD COLUMN invited_by uuid REFERENCES profiles(id) ON DELETE SET NULL,
ADD COLUMN invited_at timestamptz,
ADD COLUMN responded_at timestamptz,
ADD COLUMN expires_at timestamptz;
ALTER TABLE project_workers
ADD CONSTRAINT project_workers_status_check
CHECK (status IN ('invited', 'active', 'declined'));
-- У приглашения всегда есть пригласивший и срок; у обычного членства
-- (включая строки до миграции) этих полей может не быть.
ALTER TABLE project_workers
ADD CONSTRAINT project_workers_invited_shape
CHECK (status <> 'invited'
OR (invited_at IS NOT NULL AND invited_by IS NOT NULL
AND expires_at IS NOT NULL AND responded_at IS NULL));
-- Принятое/отклонённое приглашение фиксирует момент ответа.
ALTER TABLE project_workers
ADD CONSTRAINT project_workers_responded_shape
CHECK (status = 'invited' OR responded_at IS NOT NULL
OR invited_at IS NULL); -- строки до миграции без ответа
-- Списки: мастера проекта (по статусу) и приглашения мастера (worker_id + срок).
CREATE INDEX IF NOT EXISTS idx_project_workers_project_status
ON project_workers (project_id, status);
CREATE INDEX IF NOT EXISTS idx_project_workers_worker_status
ON project_workers (worker_id, status, expires_at);