Загрузка данных
## Обзор схемы базы данных
На основе предоставленного кода (класс `DatabaseManager`) база данных `bot.db` (SQLite) содержит следующие таблицы, разделённые по логическим группам.
### 1. Пользователи и роли
#### `users`
| Колонка | Тип | Ограничения | Описание |
|------------------|------------|---------------------------------------------|------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT | Внутренний ID |
| vk_id | INTEGER | UNIQUE NOT NULL | ID пользователя ВКонтакте |
| first_name | TEXT | NOT NULL | Имя |
| last_name | TEXT | NOT NULL | Фамилия |
| screen_name | TEXT | | Короткое имя ВК |
| phone | TEXT | | Телефон |
| is_active | INTEGER | DEFAULT 1 | 1 – активен, 0 – деактивирован |
| deactivated_at | DATETIME | | Дата деактивации |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | Дата регистрации |
#### `roles`
| Колонка | Тип | Ограничения | Описание |
|--------------|------------|---------------------------|--------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT | ID роли |
| name | TEXT | UNIQUE NOT NULL | Название роли |
| description | TEXT | | Описание |
| is_active | INTEGER | DEFAULT 1 | Активна/неактивна |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | Дата создания |
#### `permissions`
| Колонка | Тип | Ограничения | Описание |
|--------------|------------|---------------------------|--------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT | ID разрешения |
| name | TEXT | UNIQUE NOT NULL | Кодовое имя (`create_request` и т.д.) |
| description | TEXT | | Описание |
| address | TEXT | | Связанный эндпоинт (опционально) |
#### `role_permissions`
| Колонка | Тип | Ограничения |
|----------------|---------|------------------------------------------------------|
| role_id | INTEGER | PRIMARY KEY, FOREIGN KEY → roles(id) ON DELETE CASCADE |
| permission_id | INTEGER | PRIMARY KEY, FOREIGN KEY → permissions(id) ON DELETE CASCADE |
#### `users_roles`
| Колонка | Тип | Ограничения |
|--------------|---------|-------------------------------------------------------|
| user_id | INTEGER | PRIMARY KEY, FOREIGN KEY → users(id) ON DELETE CASCADE |
| role_id | INTEGER | PRIMARY KEY, FOREIGN KEY → roles(id) ON DELETE CASCADE |
| assigned_at | DATETIME| DEFAULT CURRENT_TIMESTAMP |
#### `role_subordination`
| Колонка | Тип | Ограничения |
|--------------------|---------|-------------------------------------------------------|
| superior_role_id | INTEGER | PRIMARY KEY, FOREIGN KEY → roles(id) ON DELETE CASCADE |
| subordinate_role_id| INTEGER | PRIMARY KEY, FOREIGN KEY → roles(id) ON DELETE CASCADE |
---
### 2. Заявки и связанные справочники
#### `request_statuses` (справочник статусов)
| Колонка | Тип | Ограничения | Описание |
|-------------|---------|----------------------|------------------------------|
| code | TEXT | PRIMARY KEY NOT NULL | Код (`NEW`, `IN_WORK`, …) |
| name | TEXT | NOT NULL | Отображаемое имя |
| sort_order | INTEGER | NOT NULL | Порядок сортировки |
**Значения после миграций:** NEW, IN_WORK, DEFERRED, ON_REVIEW, REVISION, DONE.
#### `urgencies` (срочность)
| Колонка | Тип | Ограничения | Описание |
|-----------------|---------|---------------------------|--------------------------------|
| code | TEXT | PRIMARY KEY NOT NULL | `NORMAL`, `URGENT` |
| name | TEXT | NOT NULL | Название |
| duration_hours | INTEGER | NOT NULL CHECK (>0) | Часов на выполнение |
| emoji | TEXT | | Эмодзи для визуализации |
#### `requests` (основная таблица заявок)
| Колонка | Тип | Ограничения |
|------------------------|----------|------------------------------------------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| description | TEXT | NOT NULL |
| location_id | INTEGER | NOT NULL (внешний ключ на `locations.id`) |
| nomer_id | INTEGER | (предположительно внешний ключ, но таблица `nomers` не объявлена) |
| urgency_code | TEXT | NOT NULL DEFAULT 'NORMAL', FOREIGN KEY → urgencies(code) |
| status_code | TEXT | NOT NULL DEFAULT 'NEW', FOREIGN KEY → request_statuses(code) |
| user_id | INTEGER | NOT NULL, FOREIGN KEY → users(id) ON DELETE RESTRICT |
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP |
| current_deadline_at | DATETIME | NOT NULL |
| assignee_user_id | INTEGER | FOREIGN KEY → users(id) ON DELETE SET NULL |
| assignee_role_id | INTEGER | FOREIGN KEY → roles(id) ON DELETE SET NULL |
| assigned_at | DATETIME | |
| started_at | DATETIME | |
| reviewed_at | DATETIME | |
| completed_at | DATETIME | |
| photo_count_initial | INTEGER | DEFAULT 0, CHECK (0–9) |
| is_draft | BOOLEAN | DEFAULT 0 |
| updated_by | INTEGER | FOREIGN KEY → users(id) ON DELETE SET NULL |
> **Примечание:** в триггере `set_request_deadline` используется столбец `initial_deadline_at`, но в определении таблицы он отсутствует – вероятно, добавлен миграцией (не показано). В финальной схеме этот столбец должен существовать.
#### `locations` (добавлено миграцией)
| Колонка | Тип | Ограничения |
|-----------|---------|-------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| name | TEXT | NOT NULL UNIQUE |
| address | TEXT | |
#### `rooms` (добавлено миграцией)
| Колонка | Тип | Ограничения |
|--------------|---------|--------------------------------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| location_id | INTEGER | NOT NULL, FOREIGN KEY → locations(id) ON DELETE CASCADE|
| name | TEXT | NOT NULL |
| UNIQUE | (location_id, name) |
---
### 3. Изображения
#### `imgs`
| Колонка | Тип | Ограничения |
|--------------|---------|-------------------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| url | TEXT | UNIQUE NOT NULL |
| uploader_id | INTEGER | NOT NULL, FOREIGN KEY → users(id) ON DELETE CASCADE |
| uploaded_at | DATETIME| DEFAULT CURRENT_TIMESTAMP |
| meta | TEXT | JSON-метаданные |
#### `request_imgs` (связь заявки и изображений)
| Колонка | Тип | Ограничения |
|-------------|---------|-------------------------------------------------------|
| request_id | INTEGER | PRIMARY KEY, FOREIGN KEY → requests(id) ON DELETE CASCADE |
| img_id | INTEGER | PRIMARY KEY, FOREIGN KEY → imgs(id) ON DELETE CASCADE |
> Триггер `limit_request_photos` ограничивает 9 фото на заявку.
#### `revisions` (доработки заявки)
| Колонка | Тип | Ограничения |
|--------------|---------|------------------------------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| request_id | INTEGER | NOT NULL, FOREIGN KEY → requests(id) ON DELETE CASCADE |
| reason | TEXT | NOT NULL |
| created_by | INTEGER | NOT NULL, FOREIGN KEY → users(id) ON DELETE CASCADE |
| created_at | DATETIME| DEFAULT CURRENT_TIMESTAMP |
| photo_count | INTEGER | DEFAULT 0, CHECK (0–9) |
#### `revision_imgs`
| Колонка | Тип | Ограничения |
|--------------|---------|--------------------------------------------------------|
| revision_id | INTEGER | PRIMARY KEY, FOREIGN KEY → revisions(id) ON DELETE CASCADE |
| img_id | INTEGER | PRIMARY KEY, FOREIGN KEY → imgs(id) ON DELETE CASCADE |
#### `done_work` (завершённая работа)
| Колонка | Тип | Ограничения |
|---------------|---------|------------------------------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| request_id | INTEGER | NOT NULL UNIQUE, FOREIGN KEY → requests(id) ON DELETE CASCADE |
| completed_at | DATETIME| NOT NULL |
| submitted_by | INTEGER | NOT NULL, FOREIGN KEY → users(id) ON DELETE CASCADE |
| photo_count | INTEGER | DEFAULT 0, CHECK (0–9) |
#### `completion_imgs`
| Колонка | Тип | Ограничения |
|----------------|---------|--------------------------------------------------------|
| completion_id | INTEGER | PRIMARY KEY, FOREIGN KEY → done_work(id) ON DELETE CASCADE |
| img_id | INTEGER | PRIMARY KEY, FOREIGN KEY → imgs(id) ON DELETE CASCADE |
---
### 4. История и аудит
#### `status_history`
| Колонка | Тип | Ограничения |
|-------------|---------|-----------------------------------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| request_id | INTEGER | NOT NULL, FOREIGN KEY → requests(id) ON DELETE CASCADE |
| from_code | TEXT | FOREIGN KEY → request_statuses(code) |
| to_code | TEXT | NOT NULL, FOREIGN KEY → request_statuses(code) |
| changed_by | INTEGER | NOT NULL, FOREIGN KEY → users(id) ON DELETE CASCADE |
| changed_at | DATETIME| DEFAULT CURRENT_TIMESTAMP |
| comment | TEXT | |
#### `assignment_history`
| Колонка | Тип | Ограничения |
|---------------|---------|-------------------------------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| request_id | INTEGER | NOT NULL, FOREIGN KEY → requests(id) ON DELETE CASCADE|
| to_user_id | INTEGER | FOREIGN KEY → users(id) ON DELETE SET NULL |
| to_role_id | INTEGER | FOREIGN KEY → roles(id) ON DELETE SET NULL |
| from_user_id | INTEGER | FOREIGN KEY → users(id) ON DELETE SET NULL |
| reason | TEXT | |
| assigned_by | INTEGER | NOT NULL, FOREIGN KEY → users(id) ON DELETE CASCADE |
| assigned_at | DATETIME| DEFAULT CURRENT_TIMESTAMP |
#### `deadline_extensions`
| Колонка | Тип | Ограничения |
|---------------|---------|-------------------------------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| request_id | INTEGER | NOT NULL, FOREIGN KEY → requests(id) ON DELETE CASCADE|
| reason | TEXT | NOT NULL |
| requested_by | INTEGER | NOT NULL, FOREIGN KEY → users(id) ON DELETE CASCADE |
| old_deadline | DATETIME| NOT NULL |
| new_deadline | DATETIME| NOT NULL |
| requested_at | DATETIME| DEFAULT CURRENT_TIMESTAMP |
---
### 5. Вспомогательные таблицы
#### `ratings` (добавлено миграцией)
| Колонка | Тип | Ограничения |
|--------------|---------|-------------------------------------------------------|
| id | INTEGER | PRIMARY KEY AUTOINCREMENT |
| request_id | INTEGER | NOT NULL, FOREIGN KEY → requests(id) ON DELETE CASCADE|
| assessor_id | INTEGER | NOT NULL, FOREIGN KEY → users(id) |
| executor_id | INTEGER | FOREIGN KEY → users(id) |
| rating | INTEGER | NOT NULL CHECK (1–5) |
| comment | TEXT | |
| created_at | DATETIME| DEFAULT CURRENT_TIMESTAMP |
#### `request_wizard_drafts` (черновики заявок)
| Колонка | Тип | Ограничения |
|-------------|---------|-------------------------------------------------|
| user_id | INTEGER | PRIMARY KEY, FOREIGN KEY → users(id) ON DELETE CASCADE |
| step | INTEGER | NOT NULL CHECK (1–7) |
| data_json | TEXT | NOT NULL |
| updated_at | DATETIME| DEFAULT CURRENT_TIMESTAMP |
---
### 6. Триггеры и индексы
**Триггеры** (кратко):
- `set_request_deadline` – устанавливает `initial_deadline_at` и `current_deadline_at` на основе `urgency_code` при вставке заявки.
- `log_status_change` – вставляет запись в `status_history` при изменении `status_code`.
- `log_assignment_change` – вставляет запись в `assignment_history` при изменении `assignee_user_id` или `assignee_role_id`.
- `apply_deadline_extension` – обновляет `current_deadline_at` при добавлении записи в `deadline_extensions`.
- Триггеры ограничения количества фото для `request_imgs`, `revision_imgs`, `completion_imgs` (максимум 9).
- Триггеры обновления счётчиков `photo_count_initial` (заявки), `photo_count` (revisions, done_work) при вставке/удалении фото.
**Индексы** (выборочно):
- `idx_requests_status_deadline` – для поиска по статусу и дедлайну.
- `idx_requests_assignee_user`, `idx_requests_assignee_role` – для фильтрации по исполнителям.
- `idx_requests_created_paginate` – для пагинации по дате создания.
- `idx_users_vk`, `idx_users_active` – ускорение поиска пользователей.
- Остальные индексы на внешние ключи и часто используемые поля.
---
## Визуальное представление (диаграмма ER)
Для лучшего понимания связей можно представить упрощённую ER-диаграмму в текстовом виде:
```
users ──┬── users_roles ──┬── roles
│ │
└── requests (user_id)
│
├── request_imgs ── imgs
├── revisions ── revision_imgs ──┤
├── done_work ── completion_imgs ─┘
├── status_history
├── assignment_history
├── deadline_extensions
├── ratings
├── locations ── rooms
└── request_wizard_drafts
```
*Примечание:* `locations` и `rooms` связаны с `requests` через `location_id` (внешний ключ явно не показан в коде, но `location_id` в таблице `requests` присутствует).
Такая структура обеспечивает полный жизненный цикл заявки: создание → назначение → выполнение → доработки → завершение, с аудитом всех значимых действий.