32 KiB
MVP-1 «Загрузка сотрудников» — Design Document
| Дата | 2026-05-13 |
| Статус | Draft на ревью пользователя |
| Владелец | Чесноков Роман (Руководитель проектного отдела) |
| Срок MVP | 3-4 недели |
| Контекст-проект | Workload & Project Control System (см. memory project_workload_control) |
1. Контекст и проблема
В компании используются 4 учётных системы, ни одна из которых не даёт ответа на главные вопросы руководителя проектного отдела:
- BIT.RA (1С) — ежедневные отчёты сотрудников о выполненной работе, проектная финансовая аналитика.
- EVA Desk — задачи разработчиков/PM и Service Desk.
- Битрикс24 — CRM, сделки, прогноз продаж.
- Самописная 1С (финрез) — ручной агрегатор финреза по подразделениям.
Чтобы понять «загрузку сотрудника» сейчас, руководитель должен открыть 3 системы параллельно и склеить данные в голове или в Excel. Это не масштабируется и не даёт прогноза.
2. Цели MVP-1
Построить первую вертикальную автоматизацию — единый дашборд «Загрузка сотрудников» с 4 слоями (факт / текущая / плановая / прогнозная) для команды ~20 сотрудников за 3-4 недели работы.
Не-цели MVP-1
- Контроль сроков проектов поэтапно (подсистема C).
- Расчёт маржи, НЗП, актирования (подсистема C/F).
- Компетенции сотрудников (подсистема D).
- Расчёт финреза по подразделениям (подсистема F — отдельный мозговой штурм).
- BI-дашборды для всех руководителей (подсистема G).
- Multi-user интерфейс с правами по сотрудникам (зафиксировано MVP single-user).
- Двусторонняя интеграция (мы только читаем, источники остаются мастерами).
- Подключение CmfTimeTrackerHistory (под ACL deny, не используется).
- Подключение CmfTaskResAssign (не используется в команде).
- Все 16 воронок Битрикса (только CAT=16 «Проектные продажи (нов.)»).
- ИНН-маппинг клиентов BIT.RA ↔ Битрикс (поле в BIT.RA не заполняется).
- Прямая связь сделок Битрикса с проектами BIT.RA (
UF_CRM_PROJECTIDмёртвое поле).
3. Бизнес-вопросы и их витрины
| Вопрос | Витрина (mart) | Слой | Покрытие |
|---|---|---|---|
| Кто из сотрудников и сколько часов проработал коммерчески за месяц | mart.workload_actual |
Факт | 100% от BIT.RA-отчётности |
| Кто сейчас в работе на каких задачах и сколько часов на них уйдёт | mart.workload_current |
Текущая | ~43% задач EVA (по sample на 2026-05-13 — только задачи с responsible_id) |
| Сколько часов осталось доделать у каждого сотрудника (открытые задачи) | mart.workload_planned |
Плановая (как «осталось») | То же ~43% |
| Сколько часов может прилететь из сделок Битрикса в стадиях после Защиты КП | mart.workload_forecast |
Прогноз | Зависит от заполнения проектной команды |
| Сколько «безхозных» задач (без исполнителя или без проекта) — намёк команде | mart.tasks_orphan |
Метрика качества данных | — |
Дашборд в Metabase собирает всё в один экран.
4. Архитектура верхнего уровня
Источники Транспорт Оркестратор + Хранилище
───────────── ───────── ────────────────────────
BIT.RA (1C) ──pull──> HTTP-services ─┐
EVA Desk ──pull──> JSON-RPC + admin ─┤
Bitrix24 ──pull──> REST ─┼──> N8N orchestrator
Bitrix24 ──push──> Webhooks (tunnel)─┤ (cron + webhook triggers)
│ │
│ ▼
│ ┌──────────────────────┐
│ │ PostgreSQL │
│ │ raw_bitra (JSONB) │
│ │ raw_eva (JSONB) │
│ │ raw_bitrix (JSONB) │
│ │ ↓ SQL views/procs │
│ │ stg_* │
│ │ ↓ │
│ │ core.* │
│ │ ↓ │
│ │ mart.* │
│ └─────┬────────────────┘
│ │
│ ┌─────┴─────┐
│ ▼ ▼
│ Metabase NocoDB
│ (dashboards)(admin UI:
│ identity_map,
│ deal_team_weights)
│
└──> Telegram (alerts, optional)
Компоненты
Используем существующую инфраструктуру на хосте (Ubuntu в WSL), репозиторий ~/infrastructure/:
| Компонент | Статус | Назначение | Как используем |
|---|---|---|---|
| pipeline_postgres (postgres:15-alpine) | ✅ уже стоит | Хранилище | Создаём новую БД workload + пользователя workload_user |
| n8n | ✅ уже стоит | Оркестратор | Создаём наши workflows в существующем контейнере |
| pipeline_litellm | ✅ уже стоит (87+ моделей через OpenRouter) | LLM для опц. fuzzy-match ФИО | HTTP-нода в N8N → http://pipeline_litellm:4000 |
| pipeline_gitea | ✅ уже стоит | Версионирование | Новый репозиторий bit-flight-deck |
| Cloudflare tunnel (host-systemd) | ✅ уже стоит | Публичный endpoint для Bitrix webhooks | Добавляем поддомен n8n.bigmadnekenny.ru → localhost:5678 (N8N webhook-trigger) |
Ставим новое в ~/projects/bit-flight-deck/docker-compose.yml (подключение к external network pipeline_net):
| Компонент | Назначение |
|---|---|
| Metabase | Дашборды поверх mart-таблиц |
| NocoDB | UI для ручного управления core.identity_map, core.deal_team_weights |
Источники данных (внешние):
| Компонент | Назначение | Где |
|---|---|---|
| BIT.RA HTTP-сервисы | Серверный модуль IntegrationAPI с REST-эндпоинтами под нужные core-сущности |
Внутри BIT.RA (одноразовая 1С-разработка) |
| EVA Desk JSON-RPC | Стандартный API EVA с глобальным админ-токеном | Внешний firstbit.evateam.ru |
| Bitrix24 REST + webhooks | Pull через REST + push-приёмник через CF Tunnel | Внешний vdst421.1cbit.ru |
5. Транспорт по источникам
5.1. BIT.RA — HTTP-сервисы 1С (pull)
В BIT.RA пишется серверный модуль IntegrationAPI с эндпоинтами:
| Метод | Эндпоинт | Содержимое |
|---|---|---|
| GET | /api/works?modified_since=<ts>&limit=N |
Document.Работы + ТЧ за период с инкрементом |
| GET | /api/employees?modified_since=<ts> |
Catalog.Пользователи + ContactInfo (email) |
| GET | /api/projects?modified_since=<ts> |
Catalog.Проекты с EVA_ID |
| GET | /api/dictionaries |
Подразделения, Офисы, Менеджеры, СценарииПланирования и т.д. (редкий полный) |
| GET | /api/work_types |
Enum.ВидыРабот (статичный, тянем раз в сутки) |
| GET | /api/dept_history?modified_since=<ts> |
InformationRegister.ПодразделениеСотрудников |
Расписание: works/employees/projects — каждые 30 минут. Dictionaries/work_types — раз в сутки.
Аутентификация — выделенный 1С-пользователь с правами только на чтение релевантных объектов.
5.2. EVA Desk — Pull-гибрид + глобальный админ-токен
- Nightly full sync (раз в сутки):
.listна CmfPerson, CmfProject, CmfTask, CmfStatus — полный снимок вraw_eva.*. - Incremental sync (каждые 30 минут):
CmfAudit.list?filter=cmf_created_at>=<last_sync>→ список изменённых объектов →.getза деталями.
Глобальный админ-токен в env-переменной N8N. После разработки — пересоздаётся.
5.3. Bitrix24 — Webhooks + nightly reconcile
- Outbound webhooks (push): на события
ONCRMDEALADD,ONCRMDEALUPDATE,ONCRMDEALDELETE,ONUSERADD,ONUSERUPDATE,ONUSERDELETE. Битрикс POST'ит на наш endpoint через существующий Cloudflare Tunnel → новый поддомен → N8N webhook-trigger принимает →crm.deal.getза деталями → запись в raw. - Nightly reconcile pull (раз в сутки):
crm.deal.list?filter[CATEGORY_ID]=16со всеми UF-полями для сверки.
Поддомен для webhook'а: добавляется к существующему cloudflared (host-systemd сервис). Конфигурация — в cloudflared.env (route на localhost:5678). Webhook-URL — https://n8n.bigmadnekenny.ru/webhook/bitrix/<secret-token>.
Только воронка CAT=16. Только сделки в стадиях от «Защита КП» (FINAL_INVOICE) для прогноза + стадии реализации (UC_XPZ8Z5, UC_QYTFP3) как текущая загрузка.
5.4. finrez_1c — НЕ в MVP-1
Откладываем до подсистемы F. Доработка Catalog.Сотрудники (добавление email) — также вне MVP-1.
6. Data Model
6.1. Слои PostgreSQL
raw_bitra.* — JSONB-снимки ответов BIT.RA HTTP-сервисов
raw_eva.* — JSONB-снимки ответов EVA JSON-RPC
raw_bitrix.* — JSONB-снимки сделок и пользователей Битрикса
stg_bitra.* — нормализованные сущности BIT.RA (по одной таблице на сущность)
stg_eva.* — нормализованные сущности EVA
stg_bitrix.* — нормализованные сущности Битрикса
core.* — унифицированная модель (см. ниже)
mart.* — витрины для дашборда
6.2. core-таблицы (MVP-1 минимум)
core.employee (
id bigserial PRIMARY KEY,
email text UNIQUE NOT NULL,
full_name text,
is_active boolean,
is_target_for_mvp1 boolean, -- флаг «в фокусе MVP-1»
bitra_user_id text, -- guid из BIT.RA
eva_person_id text, -- CmfPerson:UUID
bitrix_user_id bigint, -- ID Битрикса
rate decimal(10,2), -- ставка
department_id bigint REFERENCES core.department,
office_id bigint REFERENCES core.office,
last_synced timestamptz
)
core.department (
id bigserial PRIMARY KEY,
name text,
bitra_id text,
bitrix_id bigint,
parent_id bigint REFERENCES core.department
)
core.office (
id bigserial PRIMARY KEY,
name text,
bitra_id text
)
core.work_type (
code text PRIMARY KEY, -- ЛУРВ, ЛТ, Демо, ИТС, ...
label text,
category text, -- commercial | presale | internal | free | ignored
is_billable boolean
)
core.project (
id bigserial PRIMARY KEY,
name text,
bitra_id text,
eva_id text,
is_sd boolean DEFAULT false, -- SD-проект (из явного списка 3 ID)
status text,
deadline date,
budget decimal(15,2)
)
core.work_log (
id bigserial PRIMARY KEY,
employee_id bigint REFERENCES core.employee,
work_date date NOT NULL,
work_type_code text REFERENCES core.work_type,
project_id bigint REFERENCES core.project,
stage_id bigint,
client_id bigint,
hours decimal(10,2),
description text,
bitra_doc_id text, -- ссылка на Document.Работы
bitra_row_index int
)
core.task (
id bigserial PRIMARY KEY,
code text, -- PBSD-12582
name text,
eva_id text UNIQUE, -- CmfTask:UUID
cache_status_type text, -- OPEN | IN_PROGRESS | IN_REVIEW | CLOSED
project_id bigint REFERENCES core.project,
responsible_id bigint REFERENCES core.employee,
cmf_created_at timestamptz,
cmf_modified_at timestamptz,
status_in_progress_start timestamptz
)
core.deal (
id bigserial PRIMARY KEY,
bitrix_id bigint UNIQUE,
title text,
category_id int, -- 16
stage_id text, -- C16:FINAL_INVOICE и т.д.
stage_semantic_id char(1), -- P | S | F
opportunity decimal(15,2),
begindate date,
closedate date,
assigned_to_id bigint REFERENCES core.employee,
company_id bigint -- ID Битрикс-компании (без маппинга на BIT.RA)
)
core.deal_team_member (
deal_id bigint REFERENCES core.deal,
employee_id bigint REFERENCES core.employee,
weight decimal(5,2) DEFAULT 1.0, -- вес сотрудника в команде (для распределения часов). По умолчанию 1.0 = поровну
is_manual boolean DEFAULT false, -- проставлен вручную через NocoDB
PRIMARY KEY (deal_id, employee_id)
)
core.identity_map (
entity_type text, -- employee | client | project
core_id bigint,
bitra_id text,
eva_id text,
bitrix_id bigint,
confidence text, -- auto | confirmed | manual
confirmed_by text,
confirmed_at timestamptz
)
6.3. core.work_type — справочник видов работ
Загружается из BIT.RA Enum.ВидыРабот (14 значений), плюс правило категоризации:
| Code (1С) | Label | Category | is_billable |
|---|---|---|---|
ЛУРВ |
ЛУРВ | commercial | true |
ЛТ |
ЛТ | commercial | true |
Демо |
Пресейл | presale | false |
ИТС |
ИТС (договор) | commercial | true |
ИТСПлатныеРаботы |
ИТС (доп. услуги) | commercial | true |
Сертификация |
Сертификация | internal | false |
Внутреннее |
Обучение | internal | false |
Управленка |
Работа руководителя | internal | false |
ВнутренниеРаботы |
Внутренние работы | internal | false |
НеОпл |
Бесплатные часы в счёт ПП | free | false |
Установка |
Установка в счёт ПП | free | false |
Гарантия |
Гарантия | free | false |
Коробка, Отложено |
(рудимент) | ignored | false |
6.4. mart-таблицы (дашборд MVP-1)
mart.workload_actual_monthly -- сотрудник × месяц → часы по категориям
mart.workload_current -- сотрудник × текущие задачи EVA (статус IN_PROGRESS) → часы (если есть оценка) или штуки
mart.workload_planned -- сотрудник × открытые задачи EVA (OPEN + IN_PROGRESS с responsible_id) → штуки и/или оценочные часы
mart.workload_forecast -- сотрудник × сделки Битрикс (от защиты КП до создания EVA-проекта) × proекторное распределение по проектной команде
mart.tasks_orphan -- задачи без responsible_id или без project_id (для team awareness)
mart.workload_summary -- composite: сотрудник × недели → факт/текущая/план/прогноз
7. Identity-resolution
7.1. Сотрудники — через email
Главный ключ. lower(email) сравнивается между:
- BIT.RA
Catalog.Пользователи.КонтактнаяИнформация(нужно дозаполнить если где-то пусто) - EVA
CmfPerson.login(= email на firstbit, домен@1cbit.ru) - Bitrix24
User.EMAIL(домен@1cbit.ruу 117 из 133 активных)
Fallback: ФИО → ручное разрешение через core.identity_map в NocoDB.
7.2. Проекты — через регистры BIT.RA + EVA_ID
Catalog.Проекты.EVA_ID— частично заполнен.InformationRegister.СоответствиеПроектовEVA_РА— есть данные, обработка синхронизации сломана. В рамках MVP-1 НЕ восстанавливаем (это отдельная 1С-задача). Используем то, что есть в регистре + EVA_ID.- Что не сматчилось — отмечаем
confidence='manual'и ждём ручного разрешения в NocoDB.
7.3. Клиенты — не маппим
В MVP-1 связь BIT.RA-клиент ↔ Битрикс-компания не строим (ИНН в BIT.RA не заполняется, согласовано). Сделки Битрикса висят с bitrix_company_id без связки на BIT.RA.
7.4. Identity-map — таблица
core.identity_map (
entity_type, -- employee | project
core_id, -- наш id
bitra_id,
eva_id,
bitrix_id,
confidence, -- auto (по точному email) | confirmed (через UI) | manual (без авто-сматчинга, ждёт человека)
confirmed_by,
confirmed_at
)
В NocoDB представление — отдельная страница «Identity issues» — все записи с confidence='manual' сортированные по дате создания. Пользователь пробегает раз в неделю и подтверждает.
8. Стратегия SQL-трансформаций
8.1. raw → stg
Stored procedure на каждую сущность каждого источника. Логика: INSERT INTO stg_X SELECT FROM raw_X WHERE NOT EXISTS (...) ON CONFLICT UPDATE. Идемпотентно.
8.2. stg → core
Stored procedure core.merge_employee(), core.merge_project(), core.merge_task(), core.merge_work_log(), core.merge_deal().
Логика merge:
- Найти
core_idчерезcore.identity_map. - Если найден — UPDATE.
- Если нет — попытаться сматчить (email, EVA_ID и т.п.). Если успех — UPDATE + добавить запись в identity_map.
- Если не сматчилось — INSERT новый core_id + identity_map с
confidence='manual'.
8.3. core → mart
Materialized views, обновляемые после каждой пачки sync'а. Триггер: N8N после sync'а делает SELECT mart.refresh_all().
8.4. Версионирование SQL
Структура проекта ~/projects/bit-flight-deck/ (имя финальное обсуждаем) — Gitea репозиторий:
~/projects/bit-flight-deck/
├── docker-compose.yml -- Metabase + NocoDB (подключение к pipeline_net)
├── .env / .env.example
├── infra/
│ ├── init-workload-db.sql -- создание БД workload + workload_user в pipeline_postgres
│ └── cloudflared-routes.md-- документация по поддоменам tunnel
├── sql/
│ ├── migrations/ -- одноразовые DDL миграции (CREATE TABLE и т.п.)
│ ├── views/ -- view-определения
│ ├── procedures/ -- stored procedures
│ └── seed/ -- начальные данные (work_type категории, SD-projects whitelist)
├── n8n/
│ └── workflows/ -- JSON-экспорты workflows N8N
├── docs/superpowers/specs/ -- эта спека и будущие
└── README.md
9. Дашборд Metabase
9.1. Главный экран «Загрузка сотрудников MVP-1»
| Раздел | Содержимое |
|---|---|
| Заголовок | Дата последней синхронизации (timestamp) с каждым источником |
| Plate 1 | Средний % коммерческой загрузки команды за 30 дней (большая цифра, цвет) |
| Plate 2 | Количество «безхозных» задач (без responsible_id или project_id) — намёк команде |
| Таблица | По каждому из ~20 сотрудников: ФИО / Подразделение / Факт 30д часы / Факт 30д % коммерч. / Текущая (часы IN_PROGRESS задач) / Осталось (часы OPEN+IN_PROGRESS) / Прогноз 4 недели (Б24) / Итого 4 недели |
| Линейный график | Динамика % коммерческой загрузки команды по неделям за 90 дней |
| Барчарт | Свободные ресурсы — топ-N сотрудников с факт+план ниже 50% |
| Таблица | Перегруженные — топ-N сотрудников с факт+план выше 90% |
9.2. Принципы визуализации
- Светофор: красный <50%, жёлтый 50-70%, зелёный 70-100%, серый >100% (перегруз).
- Все таблицы — с сортировкой и фильтрами по подразделению, виду работ.
- Цифры — округлены до часов, не до минут.
10. Operational concerns
10.1. Мониторинг
- N8N-flow «health check» каждый час: проверяет последние sync-таймстампы. Если sync с любым источником > 2 часа — алёрт в Telegram (или просто logging).
- Метрики на дашборде: количество записей в каждой raw_*, last_sync timestamp по каждому источнику.
10.2. Бэкап
- PostgreSQL — автоматический pg_dumpall ещё не настроен в инфре (TODO в
~/infrastructure/ROADMAP.md). Для MVP-1 — ручнойpg_dump workload > workload-YYYY-MM-DD.sql.gzраз в сутки (cron в WSL). Когда инфра-уровневый backup поднимется (sidecarpipeline_pg_backup) — наш проект пользуется им автоматом. - Schema-only бэкап перед каждой миграцией (
pg_dump --schema-only). - Gitea-репозиторий проекта — резервируется автоматически с остальным Gitea (в рамках инфры).
10.3. Безопасность
- EVA админ-токен в env N8N, не в git.
- Bitrix webhook URL — с секретным токеном в URL (защита от случайных POST'ов).
- PostgreSQL — отдельные роли:
etl_writer(N8N) с правами на raw_/stg_,analyst(Metabase, NocoDB) с правами read-only на core/mart. - HTTPS на туннеле для Bitrix-webhooks (Битрикс требует валидный SSL).
10.4. Производительность
Объёмы маленькие (десятки сотрудников, тысячи задач, тысячи строк работ в год). PostgreSQL без напряга справится. Индексы — по timestamps (modified_at, work_date) + по FK.
11. Acceptance criteria MVP-1
- ✅ В Metabase открыт дашборд «Загрузка сотрудников MVP-1», виден список ~20 сотрудников с 4 слоями загрузки.
- ✅ Факт за вчера в дашборде совпадает с тем что в BIT.RA
Document.Работыза вчера (выборочная проверка 3 сотрудников). - ✅ Текущая загрузка показывает задачи EVA в статусе
IN_PROGRESSдля сотрудников сresponsible_id. Сверка с EVA-UI (выборочно). - ✅ Прогнозная загрузка показывает сотрудников из проектных команд сделок Битрикса CAT=16 от стадии
FINAL_INVOICE(«Защита сделки»). - ✅ NocoDB-страница «Identity issues» показывает несматчившиеся сущности (с
confidence='manual'). - ✅ Свежесть данных: BIT.RA — не старше 1 часа, EVA — не старше 1 часа, Bitrix — не старше 5 минут (webhook).
- ✅ Один полный цикл E2E: меняешь данные в источниках → через указанные временные окна они отражаются в дашборде.
- ✅ Дашборд отвечает на 5 бизнес-вопросов из секции 3 без ручной фильтрации.
12. Параллельные организационные задачи
Не блокеры запуска MVP-1, но запускаются параллельно:
- Дисциплина EVA: внедрить в команде заполнение
plan_start_date/plan_end_date/deadline/responsible_idдля всех новых задач. Через 2-3 месяца — пересмотр MVP-1 с честной «плановой» через plan_start_date. - Email во всех системах: дозаполнить email сотрудников в BIT.RA
Catalog.Пользователигде пусто. Аналогично в Битриксе для новых юзеров.
13. Open questions / TODO — закрыто (2026-05-13)
- ✅ Имя проекта —
bit-flight-deck. Gitea-репозиторийbit-flight-deck. Локальная папка~/projects/bit-flight-deck/. - ✅ Поддомен для Bitrix-webhooks —
n8n.bigmadnekenny.ru. Добавить ingress-роут в cloudflaredhost-systemd. - ✅ Список сотрудников MVP-1 — 15 email подтверждены пользователем + 1 TBA. Полный список в mvp1-config.md. Применяется через
sql/seed/mvp1_target_employees.sql. - ✅ 3 SD-проекта EVA —
pbsd,sd-perm,sd-czentralnyj. Применяется черезsql/seed/sd_projects_whitelist.sql. - ✅ Стадии Битрикса CAT=16 для прогноза —
C16:UC_A2446J(Оценка и подготовка КП),C16:FINAL_INVOICE(Защита сделки),C16:UC_U68WK1(Подготовка рамочного договора). Применяется черезsql/seed/bitrix_forecast_stages.sql.UC_A02TUT(Отложено) и стадии Реализации НЕ включены (двойной счёт с EVA). - ✅ Заполняемость email в BIT.RA — пользователь подтверждает «все заполнены или будут заполнены к запуску MVP-1». Через MCP не проверяемо, но это организационная гарантия. ETL пишем в предположении что email есть.
Остающиеся внутренние:
- Распределение часов сделки по проектной команде. Базовая логика — поровну между членами команды. Веса можно править в NocoDB. Более умная логика (по компетенциям) — backlog для Подсистемы D.
14. Backlog после MVP-1
Не в MVP-1, но зафиксировано для последующих итераций:
- MVP-2: Подвисшие задачи и контроль сроков — EVA
CmfStatusHistory+ детектор простоев + алёрты в Telegram. - MVP-3: Маржа, НЗП, актирование — BIT.RA
ОборотыПроектныхПоказателей_v2+ расчёты маржинальности и НЗП. - MVP-4: Финрез по подразделениям — finrez_1c + отдельный мозговой штурм по схеме расчёта + доработка финрезной 1С.
- Подсистема D: Компетенции (производная из core.work_log) — расчёт «что сотрудник реально умеет» из истории работ.
- Восстановление обработки
СинхронизацияДанныхEVA_РАв BIT.RA — если потребуется для подсистемы C/D. - Автоматическое распределение SD-задач по компетенциям сотрудников — подсистема D.
- EVA TimeTracker — если получится получить токен с правами на TimeTracker.
- DataLens вместо Metabase — если потребуются более сложные визуализации.
- Полная Bitrix-интеграция — все воронки, лиды, контакты.