docs: add technical design doc 1 - data model
This commit is contained in:
1 parent
9cbae40aa4
commit
d15f320fb3
1 file changed
+572
@@ -0,0 +1,572 @@
|
|||||||
|
# Технический проект. Документ 1: Модель данных
|
||||||
|
|
||||||
|
**Проект:** АС «Платформа ОПОРА РОССИИ»
|
||||||
|
**СУБД:** PostgreSQL 16
|
||||||
|
**Дата:** 26.09.2026
|
||||||
|
**Статус:** черновик к согласованию
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Общие принципы
|
||||||
|
|
||||||
|
- **Единое хранилище** для бота и сайта (п. 4.1.1 ТЗ).
|
||||||
|
- Первичные ключи — `bigint` (identity) либо `uuid` для внешне адресуемых сущностей (токены, сессии).
|
||||||
|
- Все таблицы содержат `created_at` / `updated_at` (`timestamptz`).
|
||||||
|
- Мягкое удаление (`deleted_at`) — для сущностей, где нужна история (карточки, задачи, артефакты).
|
||||||
|
- Перечисления — через `enum`-типы PostgreSQL или `text` + `CHECK` (выбор на этапе реализации).
|
||||||
|
- Денормализованные агрегаты (прирост, рейтинг) — материализованные представления, пересчитываемые Celery-задачей.
|
||||||
|
- JSONB — для гибких полей (фильтры аудитории, payload аудита).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Перечисления (enum)
|
||||||
|
|
||||||
|
| Enum | Значения |
|
||||||
|
|---|---|
|
||||||
|
| `messenger_type` | `telegram`, `max` |
|
||||||
|
| `user_status` | `active`, `blocked`, `pending` |
|
||||||
|
| `role_code` | `admin`, `coordinator`, `region_head`, `member`, `deputy` |
|
||||||
|
| `login_token_status` | `active`, `used`, `expired`, `revoked` |
|
||||||
|
| `snapshot_kind` | `point0`, `current`, `history` |
|
||||||
|
| `member_type` | `member`, `resident` |
|
||||||
|
| `task_status` | `new`, `in_progress`, `review`, `done` |
|
||||||
|
| `task_priority` | `low`, `medium`, `high` |
|
||||||
|
| `request_type` | `join`, `access`, `event`, `support` |
|
||||||
|
| `request_status` | `new`, `in_progress`, `closed` |
|
||||||
|
| `broadcast_type` | `info`, `education`, `rating` |
|
||||||
|
| `broadcast_status` | `draft`, `scheduled`, `sending`, `sent`, `failed` |
|
||||||
|
| `recipient_status` | `pending`, `sent`, `failed` |
|
||||||
|
| `actor_type` | `user`, `assistant`, `system` |
|
||||||
|
| `link_type` | `community`, `chat` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Справочники
|
||||||
|
|
||||||
|
### 3.1. `federal_districts` — федеральные округа (8)
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения | Описание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | bigint | PK | |
|
||||||
|
| name | text | NOT NULL, UNIQUE | «ЮФО», «ЦФО»… |
|
||||||
|
| code | text | UNIQUE | краткий код |
|
||||||
|
| created_at | timestamptz | NOT NULL | |
|
||||||
|
|
||||||
|
### 3.2. `regions` — регионы (89)
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения | Описание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | bigint | PK | |
|
||||||
|
| name | text | NOT NULL, UNIQUE | «Донецкая Народная Республика» |
|
||||||
|
| federal_district_id | bigint | FK → federal_districts | округ |
|
||||||
|
| status | text | NOT NULL, default `active` | |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL | |
|
||||||
|
|
||||||
|
### 3.3. `roles` — роли
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| code | role_code | NOT NULL, UNIQUE |
|
||||||
|
| name | text | NOT NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Пользователи и доступ
|
||||||
|
|
||||||
|
### 4.1. `users` — аккаунты
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения | Описание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | bigint | PK | |
|
||||||
|
| full_name | text | | ФИО |
|
||||||
|
| messenger_type | messenger_type | NOT NULL | |
|
||||||
|
| messenger_id | text | NOT NULL | внешний id в мессенджере |
|
||||||
|
| phone | text | | опционально |
|
||||||
|
| region_id | bigint | FK → regions, NULL | привязка к региону |
|
||||||
|
| status | user_status | NOT NULL, default `active` | |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL | |
|
||||||
|
|
||||||
|
**Уникальность:** `UNIQUE (messenger_type, messenger_id)`.
|
||||||
|
|
||||||
|
### 4.2. `user_roles` — роли пользователей (с областью действия)
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| user_id | bigint | FK → users |
|
||||||
|
| role_id | bigint | FK → roles |
|
||||||
|
| region_id | bigint | FK → regions, NULL (область: своё отделение) |
|
||||||
|
| granted_by | bigint | FK → users, NULL |
|
||||||
|
| granted_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
**Уникальность:** `UNIQUE (user_id, role_id, region_id)`.
|
||||||
|
|
||||||
|
### 4.3. `login_tokens` — одноразовые ссылки входа
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения | Описание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | uuid | PK | |
|
||||||
|
| token | text | NOT NULL, UNIQUE | случайный, достаточной длины |
|
||||||
|
| user_id | bigint | FK → users, NULL | может быть выдан до регистрации |
|
||||||
|
| region_id | bigint | FK → regions, NULL | |
|
||||||
|
| issued_by | bigint | FK → users (координатор) | |
|
||||||
|
| status | login_token_status | NOT NULL, default `active` | |
|
||||||
|
| expires_at | timestamptz | NOT NULL | |
|
||||||
|
| used_at | timestamptz | NULL | |
|
||||||
|
| created_at | timestamptz | NOT NULL | |
|
||||||
|
|
||||||
|
**Правило:** повторное использование → `status = used`, ответ «Ссылка уже была использована…» (п. 4.1.5 ТЗ).
|
||||||
|
|
||||||
|
### 4.4. `sessions` — сессии
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | uuid | PK |
|
||||||
|
| user_id | bigint | FK → users |
|
||||||
|
| token_hash | text | NOT NULL, UNIQUE |
|
||||||
|
| messenger_type | messenger_type | NOT NULL |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
| expires_at | timestamptz | NOT NULL |
|
||||||
|
| revoked_at | timestamptz | NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Цели и метрики
|
||||||
|
|
||||||
|
### 5.1. `goals` — цели
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения | Описание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | bigint | PK | |
|
||||||
|
| name | text | NOT NULL | «Рост базы членов» |
|
||||||
|
| description | text | | |
|
||||||
|
| target_value | numeric | | «+1096» |
|
||||||
|
| unit | text | | «чел.» |
|
||||||
|
| is_active | boolean | NOT NULL, default true | |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL | |
|
||||||
|
|
||||||
|
### 5.2. `snapshots` — срезы
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения | Описание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | bigint | PK | |
|
||||||
|
| goal_id | bigint | FK → goals | |
|
||||||
|
| snapshot_date | date | NOT NULL | дата среза |
|
||||||
|
| kind | snapshot_kind | NOT NULL | `point0` / `current` / `history` |
|
||||||
|
| source | text | | `upload` / `manual` |
|
||||||
|
| created_at | timestamptz | NOT NULL | |
|
||||||
|
|
||||||
|
**Правило:** для цели ровно один `point0`; `current` — последний по дате.
|
||||||
|
|
||||||
|
### 5.3. `region_goal_values` — значения по регионам
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| snapshot_id | bigint | FK → snapshots |
|
||||||
|
| region_id | bigint | FK → regions |
|
||||||
|
| value | numeric | NOT NULL |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
**Уникальность:** `UNIQUE (snapshot_id, region_id)`.
|
||||||
|
|
||||||
|
### 5.4. `data_uploads` — загрузки выгрузок
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| goal_id | bigint | FK → goals |
|
||||||
|
| file_key | text | NOT NULL (MinIO) |
|
||||||
|
| uploaded_by | bigint | FK → users |
|
||||||
|
| status | text | `uploaded` / `processed` / `failed` |
|
||||||
|
| processed_at | timestamptz | NULL |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 5.5. Материализованное представление `mv_region_metrics`
|
||||||
|
|
||||||
|
Расчёт (п. 4.3.1 ТЗ):
|
||||||
|
|
||||||
|
- `point0_value` — значение среза `point0`;
|
||||||
|
- `current_value` — значение последнего `current`;
|
||||||
|
- `growth = current_value − point0_value`;
|
||||||
|
- `has_dynamics = growth > 0`;
|
||||||
|
- `freshness_days = now() − snapshot_date` (для правила «не старше 7 дней»).
|
||||||
|
|
||||||
|
Поля: `region_id`, `goal_id`, `point0_value`, `current_value`, `growth`, `has_dynamics`, `snapshot_date`, `freshness_days`, `updated_at`.
|
||||||
|
|
||||||
|
### 5.6. `mv_district_metrics`
|
||||||
|
|
||||||
|
Агрегат по округу: `district_id`, `goal_id`, `growth_sum`, `regions_with_dynamics`, `regions_total`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Карточка региона
|
||||||
|
|
||||||
|
### 6.1. `region_cards`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| region_id | bigint | PK, FK → regions |
|
||||||
|
| population | integer | численность |
|
||||||
|
| head_user_id | bigint | FK → users, NULL |
|
||||||
|
| updated_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 6.2. `region_links` — сообщества и чаты
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| region_id | bigint | FK → regions |
|
||||||
|
| type | link_type | NOT NULL |
|
||||||
|
| title | text | |
|
||||||
|
| url | text | NOT NULL |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 6.3. `region_card_history` — история изменений
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| region_id | bigint | FK → regions |
|
||||||
|
| field | text | NOT NULL |
|
||||||
|
| old_value | text | |
|
||||||
|
| new_value | text | |
|
||||||
|
| changed_by | bigint | FK → users |
|
||||||
|
| changed_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Члены организации
|
||||||
|
|
||||||
|
### 7.1. `members`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения | Описание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | bigint | PK | |
|
||||||
|
| user_id | bigint | FK → users, NULL | связь с аккаунтом |
|
||||||
|
| region_id | bigint | FK → regions | |
|
||||||
|
| full_name | text | NOT NULL | |
|
||||||
|
| type | member_type | NOT NULL, default `member` | член / резидент |
|
||||||
|
| status | text | NOT NULL, default `active` | |
|
||||||
|
| joined_at | date | | |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Артефакты
|
||||||
|
|
||||||
|
### 8.1. `artifacts`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения | Описание |
|
||||||
|
|---|---|---|---|
|
||||||
|
| id | bigint | PK | |
|
||||||
|
| title | text | | |
|
||||||
|
| file_key | text | NOT NULL | ключ в MinIO |
|
||||||
|
| file_name | text | NOT NULL | |
|
||||||
|
| mime_type | text | | |
|
||||||
|
| size_bytes | bigint | | до 50 МБ (п. 4.2.8.1) |
|
||||||
|
| region_id | bigint | FK → regions, NULL | привязка |
|
||||||
|
| goal_id | bigint | FK → goals, NULL | привязка |
|
||||||
|
| task_id | bigint | FK → tasks, NULL | привязка |
|
||||||
|
| uploaded_by | bigint | FK → users | |
|
||||||
|
| deleted_at | timestamptz | NULL | мягкое удаление |
|
||||||
|
| created_at | timestamptz | NOT NULL | |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Задачи (трекер)
|
||||||
|
|
||||||
|
### 9.1. `tasks`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| title | text | NOT NULL |
|
||||||
|
| description | text | |
|
||||||
|
| due_date | date | |
|
||||||
|
| priority | task_priority | NOT NULL, default `medium` |
|
||||||
|
| status | task_status | NOT NULL, default `new` |
|
||||||
|
| region_id | bigint | FK → regions, NULL |
|
||||||
|
| assignee_user_id | bigint | FK → users, NULL |
|
||||||
|
| assignee_role | role_code | NULL |
|
||||||
|
| created_by | bigint | FK → users |
|
||||||
|
| deleted_at | timestamptz | NULL |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 9.2. `task_comments`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| task_id | bigint | FK → tasks |
|
||||||
|
| author_id | bigint | FK → users |
|
||||||
|
| body | text | NOT NULL |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. База знаний
|
||||||
|
|
||||||
|
### 10.1. `knowledge_categories`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| name | text | NOT NULL, UNIQUE |
|
||||||
|
|
||||||
|
### 10.2. `knowledge_articles`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| title | text | NOT NULL |
|
||||||
|
| body | text | NOT NULL |
|
||||||
|
| category_id | bigint | FK → knowledge_categories, NULL |
|
||||||
|
| created_by | bigint | FK → users |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Календарь событий
|
||||||
|
|
||||||
|
### 11.1. `events`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| title | text | NOT NULL |
|
||||||
|
| description | text | |
|
||||||
|
| starts_at | timestamptz | NOT NULL |
|
||||||
|
| ends_at | timestamptz | |
|
||||||
|
| location | text | |
|
||||||
|
| created_by | bigint | FK → users |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 11.2. `event_reminders`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| event_id | bigint | FK → events |
|
||||||
|
| user_id | bigint | FK → users |
|
||||||
|
| remind_at | timestamptz | NOT NULL |
|
||||||
|
| sent_at | timestamptz | NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Запросы (заявки)
|
||||||
|
|
||||||
|
### 12.1. `requests`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| type | request_type | NOT NULL |
|
||||||
|
| user_id | bigint | FK → users |
|
||||||
|
| region_id | bigint | FK → regions, NULL |
|
||||||
|
| subject | text | |
|
||||||
|
| body | text | |
|
||||||
|
| status | request_status | NOT NULL, default `new` |
|
||||||
|
| assigned_to | bigint | FK → users, NULL |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 12.2. `request_comments`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| request_id | bigint | FK → requests |
|
||||||
|
| author_id | bigint | FK → users |
|
||||||
|
| body | text | NOT NULL |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Советы от регионов
|
||||||
|
|
||||||
|
### 13.1. `advices`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| region_id | bigint | FK → regions |
|
||||||
|
| goal_id | bigint | FK → goals, NULL |
|
||||||
|
| author_user_id | bigint | FK → users |
|
||||||
|
| body | text | NOT NULL |
|
||||||
|
| status | text | `published` / `hidden` |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Рассылки
|
||||||
|
|
||||||
|
### 14.1. `broadcast_templates`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| code | text | NOT NULL, UNIQUE |
|
||||||
|
| name | text | NOT NULL |
|
||||||
|
| type | broadcast_type | NOT NULL |
|
||||||
|
| body_template | text | NOT NULL (с плейсхолдерами) |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 14.2. `broadcasts`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| template_id | bigint | FK → broadcast_templates, NULL |
|
||||||
|
| type | broadcast_type | NOT NULL |
|
||||||
|
| subject | text | |
|
||||||
|
| body | text | |
|
||||||
|
| audience_filter | jsonb | регион/округ/роль/подписка |
|
||||||
|
| status | broadcast_status | NOT NULL, default `draft` |
|
||||||
|
| scheduled_at | timestamptz | NULL |
|
||||||
|
| started_at / finished_at | timestamptz | NULL |
|
||||||
|
| created_by | bigint | FK → users |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 14.3. `broadcast_recipients`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| broadcast_id | bigint | FK → broadcasts |
|
||||||
|
| user_id | bigint | FK → users |
|
||||||
|
| status | recipient_status | NOT NULL, default `pending` |
|
||||||
|
| sent_at | timestamptz | NULL |
|
||||||
|
| error | text | NULL |
|
||||||
|
|
||||||
|
**Уникальность:** `UNIQUE (broadcast_id, user_id)`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. История платформы
|
||||||
|
|
||||||
|
### 15.1. `platform_history`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| title | text | NOT NULL |
|
||||||
|
| body | text | |
|
||||||
|
| event_date | date | |
|
||||||
|
| is_public | boolean | NOT NULL, default true |
|
||||||
|
| created_by | bigint | FK → users |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. Аудит и ассистент
|
||||||
|
|
||||||
|
### 16.1. `audit_log`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| actor_user_id | bigint | FK → users, NULL |
|
||||||
|
| actor_type | actor_type | NOT NULL |
|
||||||
|
| action | text | NOT NULL |
|
||||||
|
| entity_type | text | |
|
||||||
|
| entity_id | text | |
|
||||||
|
| payload | jsonb | |
|
||||||
|
| ip | inet | |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 16.2. `assistant_configs`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| owner_user_id | bigint | FK → users, UNIQUE |
|
||||||
|
| enabled | boolean | NOT NULL, default false |
|
||||||
|
| permissions | jsonb | разрешённые действия |
|
||||||
|
| created_at / updated_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
### 16.3. `assistant_actions`
|
||||||
|
|
||||||
|
| Поле | Тип | Ограничения |
|
||||||
|
|---|---|---|
|
||||||
|
| id | bigint | PK |
|
||||||
|
| owner_user_id | bigint | FK → users |
|
||||||
|
| action | text | NOT NULL |
|
||||||
|
| entity_type | text | |
|
||||||
|
| entity_id | text | |
|
||||||
|
| payload | jsonb | |
|
||||||
|
| status | text | `ok` / `failed` |
|
||||||
|
| created_at | timestamptz | NOT NULL |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 17. ERD (основные связи)
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
erDiagram
|
||||||
|
FEDERAL_DISTRICTS ||--o{ REGIONS : contains
|
||||||
|
REGIONS ||--o{ USERS : "привязка"
|
||||||
|
REGIONS ||--|| REGION_CARDS : has
|
||||||
|
REGIONS ||--o{ REGION_LINKS : has
|
||||||
|
REGIONS ||--o{ MEMBERS : has
|
||||||
|
REGIONS ||--o{ REGION_GOAL_VALUES : has
|
||||||
|
REGIONS ||--o{ TASKS : has
|
||||||
|
REGIONS ||--o{ ARTIFACTS : has
|
||||||
|
REGIONS ||--o{ ADVICES : has
|
||||||
|
|
||||||
|
USERS ||--o{ USER_ROLES : has
|
||||||
|
ROLES ||--o{ USER_ROLES : grants
|
||||||
|
USERS ||--o{ LOGIN_TOKENS : receives
|
||||||
|
USERS ||--o{ SESSIONS : has
|
||||||
|
USERS ||--|| ASSISTANT_CONFIGS : owns
|
||||||
|
USERS ||--o{ ASSISTANT_ACTIONS : performs
|
||||||
|
|
||||||
|
GOALS ||--o{ SNAPSHOTS : has
|
||||||
|
SNAPSHOTS ||--o{ REGION_GOAL_VALUES : contains
|
||||||
|
GOALS ||--o{ DATA_UPLOADS : receives
|
||||||
|
|
||||||
|
TASKS ||--o{ TASK_COMMENTS : has
|
||||||
|
TASKS ||--o{ ARTIFACTS : links
|
||||||
|
|
||||||
|
KNOWLEDGE_CATEGORIES ||--o{ KNOWLEDGE_ARTICLES : groups
|
||||||
|
EVENTS ||--o{ EVENT_REMINDERS : triggers
|
||||||
|
REQUESTS ||--o{ REQUEST_COMMENTS : has
|
||||||
|
|
||||||
|
BROADCAST_TEMPLATES ||--o{ BROADCASTS : based_on
|
||||||
|
BROADCASTS ||--o{ BROADCAST_RECIPIENTS : sends
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 18. Индексы и производительность
|
||||||
|
|
||||||
|
| Таблица | Индекс | Назначение |
|
||||||
|
|---|---|---|
|
||||||
|
| users | `(messenger_type, messenger_id)` UNIQUE | поиск при входе |
|
||||||
|
| login_tokens | `(token)` UNIQUE, `(status, expires_at)` | проверка ссылки |
|
||||||
|
| region_goal_values | `(snapshot_id, region_id)` UNIQUE | целостность |
|
||||||
|
| region_goal_values | `(region_id)` | выборки по региону |
|
||||||
|
| tasks | `(region_id, status)`, `(assignee_user_id, status)` | фильтры трекера |
|
||||||
|
| artifacts | `(region_id)`, `(task_id)`, `(goal_id)` | привязки |
|
||||||
|
| broadcast_recipients | `(broadcast_id, status)` | прогресс рассылки |
|
||||||
|
| audit_log | `(actor_user_id, created_at)`, `(entity_type, entity_id)` | аудит |
|
||||||
|
| members | `(region_id, type)` | численность |
|
||||||
|
|
||||||
|
**Материализованные представления** `mv_region_metrics`, `mv_district_metrics` обновляются Celery-задачей после каждой загрузки выгрузки и по расписанию.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 19. Открытые вопросы
|
||||||
|
|
||||||
|
1. **Члены vs пользователи** — нужна ли отдельная сущность `members` или достаточно `users` со статусом? (влияет на учёт численности)
|
||||||
|
2. **История срезов** — хранить все срезы (`history`) или только `point0` + `current`?
|
||||||
|
3. **Резиденты** — отдельная таблица или `member_type`?
|
||||||
|
4. **Мультирегиональность пользователя** — может ли пользователь быть привязан к нескольким регионам?
|
||||||
|
5. **Хранение артефактов** — MinIO на том же диске (единый диск сервера).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 20. Следующие документы
|
||||||
|
|
||||||
|
- Документ 2: контракты API (REST).
|
||||||
|
- Документ 3: макеты экранов (mobile-first).
|
||||||
Reference in new issue
Block a user