реклама
Бургер менюБургер меню

Юрий Белк – Full stack Developer (страница 36)

18

– уникальность имени метки в workspace: unique (workspace_id, lower(name))

(обычно “Bug” и “bug” – одна и та же метка для людей)

9.4.8. task_labels

many-to-many связь:

– task_id (FK → tasks.id)

– label_id (FK → labels.id)

– created_at

Ключи:

– составной PK (task_id, label_id)

Индексы:

– индекс на label_id (чтобы быстро находить задачи по метке)

9.4.9. audit_events

– id

– workspace_id (nullable, FK → workspaces.id)

– actor_user_id (nullable, FK → users.id) – иногда события системные

– action (not null) – строка типа task.created

– entity_type (nullable) – task, project, …

– entity_id (nullable)

– ip (nullable)

– user_agent (nullable)

– metadata (jsonb, nullable)

– created_at

Индексы:

– (workspace_id, created_at desc)

– (actor_user_id, created_at desc)

– возможно (entity_type, entity_id)

9.4.10. idempotency_keys

Чтобы POST можно было безопасно повторять:

– id (uuid)

– user_id (FK → users.id)

– key (not null) – значение Idempotency-Key

– method (not null) – POST

– path (not null) – например /api/v1/projects/{id}/tasks

– request_hash (nullable) – чтобы ловить конфликт payload’ов

– response_code (not null)

– response_body (jsonb или text, not null)

– created_at

– expires_at

Индексы:

– unique (user_id, key, method, path)

– индекс на expires_at (чтобы чистить)

9.5. Индексы: как думать, чтобы не сделать “индекс на всё”

Индекс – это ускорение чтения ценой:

– места на диске,

– замедления записи,

– более сложного планирования.

9.5.1. Практическое правило: “индексируем то, чем фильтруем и сортируем”

Если ваш endpoint “список задач” почти всегда делает:

– WHERE workspace_id = ?

– AND status = ?

– ORDER BY created_at desc

То индекс должен соответствовать этой форме. Обычно порядок полей в индексе:

1) равенства (workspace_id, status)

2) сортировка (created_at, id)

9.5.2. “id в конце” для стабильной сортировки

Если вы делаете cursor pagination, вам нужна уникальная сортировка.

То есть сортируем по (created_at, id), а не только по created_at.

9.5.3. Partial indexes для soft delete

Если в таблице много удалённых записей, но вы почти всегда выбираете живые:

– делайте индекс с условием WHERE deleted_at IS NULL.

Это дешевле и эффективнее, чем индексировать всё подряд.

9.6. Constraints и foreign keys: когда база “воспитывает” приложение

Constraints – это ваша страховка от “случайно сохранили мусор”.

Что стоит делать всегда:

– NOT NULL там, где без значения сущность теряет смысл