← Библиотека ЭКВИЛИБРИУМ

КРИСТАЛЛ СТРОИТЕЛЬСТВА

КРИСТАЛЛ СТРОИТЕЛЬСТВА

Ниже — разбор строительства как системы Узлов, Рёбер и Кристалла. Это удобная модель, если мы хотим превратить отрасль не просто в набор процессов, а в управляемую смысловую, цифровую и организационную архитектуру.

Базовая логика модели

Узлы — это точки концентрации функций, ресурсов, решений, данных и ответственности.

Рёбра — это связи между узлами: потоки материалов, денег, документов, команд, технологий, людей и контроля.

Кристалл — это целостная структура, в которой все узлы и рёбра собраны не хаотично, а по законам симметрии, иерархии, прозрачности и развития.

Иначе говоря:

Строительство как граф

Строительная отрасль — это не одна цепочка, а многослойный граф.

В нём есть:

А рёбра между ними образуют:

Узлы строительства

Узлы замысла. Это начало любого объекта.

Ключевые узлы:

Их функция:

сформировать ответ на вопрос: что строим, зачем строим, для кого строим, на какие средства и в какой логике территории.

Узлы регулирования. Без них система не легитимна.

Сюда входят:

Их функция:

обеспечить допустимость, безопасность, соответствие и правовой каркас.

Узлы проектирования

Это узлы рождения формы.

Сюда входят:

Их функция:

перевести замысел в точную систему решений, чертежей, параметров, объёмов и ограничений.

Узлы ресурсов и снабжения

Без них объект не материализуется.

Сюда входят:

Их функция:

обеспечить стройку всем необходимым по объёму, сроку, качеству и цене.

Узлы производства работ

Это центр физического воплощения.

Сюда входят

Их функция: собрать объект в реальности.

Узлы финансов

Строительство без финансового каркаса быстро превращается в хаос.

Узлы:

Их функция:

обеспечить устойчивость денежного потока и предсказуемость исполнения.

Узлы эксплуатации

На самом деле объект строится не ради стройки, а ради жизни после стройки.

Узлы:

Их функция:

превратить построенное в работающую среду.

Узлы цифровой среды. Это уже ядро будущей отрасли.

Узлы:

Их функция: сделать систему прозрачной, управляемой и предиктивной.

Рёбра строительства

Теперь главное: узлы без рёбер — просто мёртвые точки.

Смысловые рёбра

Связывают:

Это отвечает на вопрос: почему именно это строительство имеет право быть.

Правовые рёбра

Связывают:

Это рёбра легитимности.

Информационные рёбра

Связывают:

Это рёбра данных.

Финансовые рёбра

Связывают:

Это рёбра стоимости и доверия.

Материальные рёбра

Связывают:

Это рёбра физического воплощения.

Управленческие рёбра

Связывают:

Это рёбра координации.

Рёбра качества. Связывают:

Это рёбра надёжности.

Рёбра обратной связи

Связывают:

  • пользователь ↔ эксплуатант;
  • эксплуатант ↔ проектировщик;
  • авария ↔ пересмотр нормы;
  • эксплуатация ↔ новое поколение проектов.

Это рёбра эволюции.

Кристалл строительства

Теперь главное: что такое кристалл?

Кристалл — это не просто сеть. Это гармонически организованная многослойная система, где каждый узел имеет место, функцию, степень связи и меру ответственности.

В строительстве кристалл — это:

единая пространственно-цифровая модель отрасли, где:

  • каждый объект имеет цифровой паспорт;
  • каждый участник имеет цифровой профиль;
  • каждый процесс имеет маршрут и контроль;
  • каждый ресурс имеет происхождение и состояние;
  • каждое решение имеет автора, дату и последствия;
  • каждый рубль имеет трассировку;
  • каждый риск виден заранее;
  • каждый результат входит в общую архитектуру страны.

Геометрия кристалла строительства

Разложим кристалл минимум на 7 граней.

Грань 1. Смысл

Что и зачем строится.

Грань 2. Пространство

Где, в какой территории, в каком контексте.

Грань 3. Право

На каком основании и по каким правилам.

Грань 4. Ресурсы

Из чего, кем и на чём строится.

Грань 5. Производство

Как именно объект собирается по этапам.

Грань 6. Финансы.На какие деньги и с какой устойчивостью.

Грань 7. Жизненный цикл

Как объект живёт после ввода. Если добавить цифровое ядро, получится уже кристалл 8-го уровня, где цифровая среда связывает все остальные грани.

Ядро кристалла

У любой кристаллической системы должно быть ядро.

Для строительства таким ядром должен стать:

Единый цифровой оператор строительных услуг

Он не заменяет всех участников, а становится:

  • координатором данных,
  • интегратором процессов,
  • цифровым арбитром,
  • навигатором жизненного цикла объекта,
  • оператором прозрачности,
  • средой взаимодействия государства, бизнеса и граждан.

Именно он превращает отрасль из разрозненного набора участников в единый кристалл строительства.

Формула кристалла строительства

Кристалл строительства = Узлы × Рёбра × Правила × Данные × Время

Где:

  • узлы дают структуру,
  • рёбра дают взаимодействие,
  • правила дают устойчивость,
  • данные дают прозрачность,
  • время даёт динамику жизненного цикла.

Практическая архитектура узлов

Контур А. Государство

Узлы:

  • стратегия,
  • нацпроекты,
  • нормы,
  • контроль,
  • реестры,
  • инфраструктурные программы.

Контур B. Девелопмент и заказ

Узлы:

  • заказчик,
  • инвестор,
  • девелопер,
  • земельный банк,
  • финансовая модель.

Контур C. Проектирование

Узлы:

  • архитектура,
  • инженерия,
  • BIM,
  • экспертиза,
  • смета.

Контур D. Производство

Узлы:

  • подрядчики,
  • поставщики,
  • техника,
  • стройконтроль,
  • календарный план.

Контур E. Эксплуатация

Узлы:

  • собственник,
  • управляющая компания,
  • сервис,
  • мониторинг,
  • ремонты.

Контур F. Цифровая платформа

Узлы:

  • цифровой паспорт,
  • идентификатор объекта,
  • цифровой маркетплейс,
  • аналитика,
  • ИИ,
  • мониторинг,
  • рейтинги участников.

Какие рёбра самые критические

Если говорить жёстко, отрасль чаще всего рушится не из-за отсутствия узлов, а из-за плохих рёбер.

Самые проблемные рёбра обычно такие:

  • проект ↔ стройка;
  • смета ↔ реальная стоимость;
  • подряд ↔ ответственность;
  • сроки ↔ фактическое исполнение;
  • разрешения ↔ цифровая прозрачность;
  • эксплуатация ↔ обратная связь в новое проектирование;
  • государственные данные ↔ частные данные;
  • поставщик ↔ качество ↔ происхождение материала.

То есть главная задача реформы — не просто создать новые узлы, а пересобрать рёбра.

Кристалл по жизненному циклу объекта

Можно представить один объект как малый кристалл:

Инициирование. Идея, потребность, участок, модель.

Проектирование Концепция, расчёты, BIM, смета.

Согласование. Экспертиза, разрешения, подключения.

Строительство. Поставки, работы, контроль, акты.

Ввод. Проверки, документация, запуск.

Эксплуатация Мониторинг, обслуживание, обратная связь.

Трансформация

Реконструкция, модернизация, повторное использование данных. Вот это и есть кристалл жизненного цикла.

Если говорить языком метаархитектуры

Тогда можно сформулировать так:

Узлы — это органы строительного организма. Рёбра — это его сосуды, нервы и каналы. Кристалл — это его скелет, форма, геном и закон внутренней гармонии. Без узлов нет функции. Без рёбер нет координации. Без кристалла нет целостности.

Управленческий вывод

Для концепции Единого цифрового оператора строительных услуг это означает следующее: оператор должен строиться не как сайт, не как набор сервисов и не как маркетплейс в узком смысле, а как:

Кристаллическая платформа отрасли, где:

  • узлы отрасли оцифрованы,
  • рёбра отрасли стандартизированы,
  • кристалл отрасли визуализирован и управляем.

То есть портал должен уметь показывать:

  • кто с кем связан;
  • где разрыв связи;
  • где узкое место;
  • где коррупциогенный риск;
  • где дефицит материалов;
  • где отставание по срокам;
  • где перегрузка подрядчика;
  • где объект выпадает из нормативного контура;
  • где жизненный цикл теряет управляемость.

Готовая формулировка для включения в концепцию

Можно вставить так:

Строительная отрасль рассматривается как кристаллическая сетевая система, состоящая из узлов, рёбер и интегрального цифрового ядра. Узлы представляют участников, ресурсы, функции и стадии жизненного цикла объекта. Рёбра отражают материальные, финансовые, информационные, правовые и управленческие связи между ними. Кристалл отрасли формируется как целостная архитектура, в которой все элементы взаимосвязаны, стандартизированы, прозрачны и управляемы в режиме реального времени. На этой основе создаётся Единый цифровой оператор строительных услуг как системный интегратор, обеспечивающий координацию, прослеживаемость и эволюционное развитие строительного комплекса.

Самая сильная версия этой модели

Если довести идею до конца, то можно сделать 3 продукта:

  • Смысловая карта строительства по Узлам и Рёбрам
  • Кристалл строительной отрасли России — как визуальная модель
  • Техническая архитектура цифровой платформы — на основе этого кристалла

Это уже не просто описание, а фундамент для:

  • дорожной карты,
  • техзадания,
  • атласа строительства,
  • архитектуры маркетплейса,
  • государственной цифровой платформы.



Таблица: Узлы — Рёбра — Функции — Цифровые сервисы

1. Контур: Замысел и инициирование

Узел

Рёбра (связи)

Функция

Цифровые сервисы

Заказчик

↔ инвестор, ↔ проектировщик

Формирование задачи

ЛК заказчика, ТЗ-конструктор

Инвестор

↔ банк, ↔ девелопер

Финансирование

Финмодель, ROI-калькулятор

Земельный участок

↔ кадастр, ↔ градплан

Пространственная база

Геоаналитика, GIS

Концепция

↔ проектирование

Идея объекта

Конструктор концепций, AI-анализ спроса

Государство

↔ стратегия, ↔ регион

Приоритеты развития

Реестр программ, нацпроекты

2. Контур: Регулирование

Узел

Рёбра

Функция

Цифровые сервисы

Нормативная база

↔ проект

Правила

База норм (ГИС), авто-проверка

Экспертиза

↔ проектировщик

Проверка

Цифровая экспертиза

Разрешения

↔ объект

Легализация

ЕРС (единая разрешительная система)

Контрольные органы

↔ стройка

Надзор

Онлайн-контроль, чек-листы

Кадастр

↔ участок

Учёт

Интеграция с Росреестром

3. Контур: Проектирование

Узел

Рёбра

Функция

Цифровые сервисы

Архитектор

↔ заказчик

Образ

BIM/ТИМ

Генпроектировщик

↔ подрядчик

Координация

CDE (единая среда данных)

Инженерия

↔ сети

Технические решения

Расчётные модули

Смета

↔ финансы

Стоимость

Автосмета

BIM-модель

↔ стройка

Цифровой двойник

Хранилище BIM

4. Контур: Ресурсы и снабжение

Узел

Рёбра

Функция

Цифровые сервисы

Поставщики

↔ стройка

Материалы

Маркетплейс

Производители

↔ логистика

Производство

Каталог продукции

Склады

↔ площадка

Хранение

WMS

Логистика

↔ объект

Доставка

Трекинг

Техника

↔ подрядчик

Механизация

Учет техники

5. Контур: Строительство

Узел

Рёбра

Функция

Цифровые сервисы

Генподрядчик

↔ заказчик

Управление

ERP стройки

Субподрядчики

↔ генподряд

Работы

Реестр подрядчиков

Площадка

↔ ресурсы

Исполнение

Диспетчер стройки

Контроль

↔ качество

Проверка

Мобильный технадзор

План-график

↔ факт

Сроки

План-факт аналитика

6. Контур: Финансы

Узел

Рёбра

Функция

Цифровые сервисы

Банк

↔ проект

Финансирование

Проектное финансирование

Казначейство

↔ подряд

Платежи

Казначейский модуль

Эскроу

↔ объект

Безопасность

Эскроу-счета

Контракты

↔ участники

Обязательства

Смарт-контракты

Страхование

↔ риски

Защита

Risk management

7. Контур: Эксплуатация

Узел

Рёбра

Функция

Цифровые сервисы

УК

↔ объект

Управление

Система эксплуатации

Пользователь

↔ УК

Обратная связь

Мобильное приложение

Ресурсоснабжение

↔ объект

Коммунальные услуги

IoT учет

Мониторинг

↔ система

Контроль

Датчики, IoT

Ремонт

↔ износ

Поддержка

План ремонтов

8. Контур: Цифровое ядро (Кристалл)

Узел

Рёбра

Функция

Цифровые сервисы

Единая платформа

↔ все узлы

Интеграция

Портал

Реестр объектов

↔ жизненный цикл

Учёт

ID объекта

Реестр участников

↔ рынок

Прозрачность

Рейтинг

Цифровой паспорт

↔ объект

Данные

Паспорт объекта

AI-аналитика

↔ данные

Прогноз

Предиктивная аналитика

Маркетплейс

↔ ресурсы

Сделки

Торговая платформа

Как это превращается в КРИСТАЛЛ

Теперь самое важное — не просто таблица, а логика:

Каждый узел — оцифрован → есть профиль, данные, история

Каждое ребро — прозрачно → видно:

Вся система — наблюдаема в реальном времени

→ это уже операционная система строительства

Ключевой управленческий вывод

Сейчас отрасль:

  • узлы есть ✔
  • рёбра хаотичны ❌
  • кристалл отсутствует ❌

Наша модель делает:

  • узлы → структурированными
  • рёбра → контролируемыми
  • кристалл → управляемым

💡 Что это даёт на практике

Пропадает “чёрный ящик” → видно, где деньги, где материалы, где задержка

Резко падает коррупция → потому что рёбра прозрачны

Ускоряется стройка → нет разрывов между узлами

Появляется прогнозирование → система видит проблемы ДО того, как они произошли

Следующий шаг (рекомендую)

Схему (визуальный кристалл) — как реально выглядит система

Архитектуру платформы — модули, API, роли

MVP портала — хотя бы:

💎 КРИСТАЛЛ СТРОИТЕЛЬСТВА

(метаархитектура отрасли)

Суть кристалла. Кристалл — это не схема. Это живая, самосогласованная система, где:

  • каждый элемент имеет место,
  • каждая связь имеет смысл,
  • каждая операция оставляет цифровой след,
  • вся система развивается через обратную связь.

👉 В строительстве это означает: отрасль становится управляемой как единый организм, а не разрозненный рынок.

Геометрия кристалла

Представь кристалл как многогранник с ядром и слоями.

ЯДРО. Единый цифровой оператор строительства. Функции:

  • интеграция всех узлов,
  • хранение данных,
  • координация процессов,
  • аналитика и прогноз,
  • контроль прозрачности.

ВНУТРЕННИЙ СЛОЙ (7 граней). Это структурные поля кристалла:

Смысл

  • зачем строим
  • кому это нужно

Пространство

  • где строим
  • контекст территории

Право

  • правила и нормы

Ресурсы

  • материалы, техника, люди

Производство

  • процессы стройки

Финансы

  • деньги и расчёты

Жизненный цикл

  • эксплуатация и развитие

ВНЕШНИЙ СЛОЙ (среда)

  • государство
  • рынок
  • общество
  • экология
  • технологии

Это то, с чем кристалл постоянно взаимодействует.

Кристаллическая решётка (ключевая идея)

Кристалл держится не узлами, а решёткой связей.

Основные типы рёбер:

  • 🔗 информационные
  • 💰 финансовые
  • 🧱 материальные
  • ⚖️ правовые
  • 📊 управленческие
  • 🔄 обратной связи

👉 Если хотя бы один тип связи слабый — кристалл начинает разрушаться.

Оси кристалла (управление)

У кристалла есть 3 главные оси:

Ось ВРЕМЕНИ

Идея → проект → стройка → эксплуатация → трансформация

Ось ДАННЫХ

Каждое действие фиксируется и доступно

Ось ОТВЕТСТВЕННОСТИ

Каждое решение имеет автора. 👉 Это три столпа прозрачности.

Фрактальная структура

Самое сильное: 👉 каждый объект — это маленький кристалл

И он полностью повторяет структуру всей отрасли. То есть:

  • дом = кристалл
  • район = кристалл
  • город = кристалл
  • страна = кристалл

Это даёт масштабируемость без потери управляемости.

Цифровой двойник кристалла. В платформе это выглядит так:  У каждого объекта есть:

  • ID
  • цифровой паспорт
  • BIM-модель
  • история решений
  • финансовый след
  • статус в реальном времени

👉 Это превращает стройку из процесса в наблюдаемую систему.

Поведение кристалла. Кристалл должен уметь:

1. Самодиагностика

  • где задержки
  • где риски
  • где разрывы

2. Самоадаптация

  • перераспределение ресурсов
  • изменение графиков

3. Самообучение

  • анализ прошлых проектов
  • улучшение будущих

Главные дефекты текущей отрасли

❌ Нет кристалла — есть хаос

  • узлы не связаны
  • данные разрознены
  • решения непрозрачны
  • ответственность размыта
  • деньги теряются
  • сроки “плывут”

👉 Это не проблема людей — это проблема отсутствия структуры.

Что делает кристалл

✔ Соединяет всё в систему

  • проект ↔ стройка
  • деньги ↔ работы
  • нормы ↔ факты
  • эксплуатация ↔ проектирование

✔ Делает отрасль управляемой

Ты видишь:

  • где проблема
  • кто отвечает
  • что делать

✔ Даёт прогноз. Система начинает говорить: “этот объект сорвётся через 3 месяца”

Архитектура платформы (скелет кристалла)

Модуль 1. Реестр

  • объекты
  • участники
  • ресурсы

Модуль 2. Маркетплейс

  • материалы
  • подрядчики
  • техника

Модуль 3. Управление проекто

  • сроки
  • задачи
  • контроль

Модуль 4. Финансы

  • платежи
  • сметы
  • контроль

Модуль 5. BIM/Цифровой двойник

  • модель объекта

Модуль 6. Аналитика и AI

  • прогноз
  • риски
  • оптимизация

Формула кристалла

Можно зафиксировать как базовый принцип: Кристалл строительства  (Узлы × Рёбра) + Данные + Время + Ответственность

Самое важное (без иллюзий)

Если ты хочешь реально изменить отрасль, нужно

❌ не делать ещё один портал

❌ не делать просто маркетплейс

✔ делать операционную систему строительства.Вот формулировка уровня стратегии:

Кристалл строительства представляет собой интегрированную цифровую и организационную архитектуру отрасли, основанную на структурировании узлов, стандартизации связей и формировании единого цифрового ядра. Такая модель обеспечивает прозрачность, управляемость и эволюционное развитие строительного комплекса на всех стадиях жизненного цикла объектов.



💎 ВИЗУАЛЬНАЯ СХЕМА

КРИСТАЛЛ СТРОИТЕЛЬСТВА

Центральная структура (ядро)

В центре кристалла:

ЕДИНЫЙ ЦИФРОВОЙ ОПЕРАТОР

Он — не участник рынка, а среда координации. Внутри ядра:

  • реестр объектов
  • реестр участников
  • цифровые паспорта
  • BIM/двойники
  • AI-аналитика

👉 Это “мозг” системы.

Первый круг — 7 граней кристалла

Вокруг ядра — 7 ключевых модулей (как лепестки/грани):

1. СМЫСЛ

  • потребности
  • стратегия
  • сценарии развития

2. ПРОСТРАНСТВО

  • земля
  • геоаналитика
  • мастер-план

3. ПРАВО

  • нормы
  • разрешения
  • экспертиза

4. РЕСУРСЫ

  • материалы
  • техника
  • кадры

5. ПРОИЗВОДСТВО

  • стройка
  • подрядчики
  • процессы

6. ФИНАНСЫ

  • инвестиции
  • платежи
  • контроль

7. ЖИЗНЕННЫЙ ЦИКЛ

  • эксплуатация
  • обслуживание
  • обратная связь

Второй круг — узлы

Каждая грань разбивается на узлы: Пример:

Грань “Производство”

  • генподрядчик
  • субподрядчики
  • площадка
  • контроль
  • график

Грань “Финансы”

  • банк
  • казначейство
  • контракты
  • страхование

👉 Визуально это — кластер внутри каждой грани

Рёбра (самое важное)

Теперь ключевая часть схемы:

🔗 ВСЕ УЗЛЫ СОЕДИНЕНЫ МЕЖДУ СОБОЙ

Типы линий (можно визуально различать):

  • сплошные → материальные потоки
  • пунктир → данные
  • двойные → финансы
  • красные → риски
  • зелёные → обратная связь

👉 Это превращает схему в живую сеть, а не в иерархию.

Оси кристалла 

Через центр проходят 3 оси:

Ось времени Идея → Проект → Стройка → Эксплуатация

Ось данных. Все узлы подключены к цифровому ядру

Ось ответственностию Каждый узел имеет владельца

Внешняя оболочка

Снаружи кристалла — контекст:

  • государство
  • рынок
  • общество
  • экология
  • технологии

👉 Это можно изобразить как сферу вокруг кристалла

Как это выглядит в идеале (словами)

Представь:

  • в центре — светящееся ядро
  • вокруг — симметричные сегменты
  • внутри сегментов — узлы
  • между ними — плотная сеть связей
  • всё это пульсирует данными

👉 Это уже не схема — это операционная модель отрасли

Упрощённая схема (для документа)

Можно вставить так:

                [ЭКСПЛУАТАЦИЯ]

                      ▲

                      |

[РЕСУРСЫ] ◄──► [ЯДРО / ЦИФРОВОЙ ОПЕРАТОР] ◄──► [ФИНАНСЫ]

      ▲                ▲                 ▲

      |                |                 |

[ПРОСТРАНСТВО]   [ДАННЫЕ / AI]     [ПРОИЗВОДСТВО]

      ▲                                  ▲

      |                                  |

      └──────────► [ПРАВО] ◄─────────────┘


Как использовать эту схему

Для государства — модель управления отраслью

Для инвесторов — прозрачность системы

Для IT — архитектура платформы

Для презентаций — сильный визуальный образ

ИНТЕРАКТИВНАЯ КАРТА КРИСТАЛЛА

(интерфейс платформы)

Главный экран (Core View). Это не список и не таблица. Это живая карта кристалла.

На экране:

  • центр → ядро (оператор)
  • вокруг → 7 граней
  • внутри → узлы
  • между → рёбра (связи)

👉 Пользователь видит всю систему сразу

Режимы отображения (ключевая фишка)

Один и тот же кристалл переключается:

 Режим 1 — Объект

Показывает:

  • один строительный проект
  • все связи вокруг него

Режим 2 — Территория

  • город / регион
  • все стройки

Режим 3 — Отрасль

  • вся система страны

Взаимодействие (UX)

Клик по узлу:

  • кто это
  • рейтинг
  • проекты
  • связи

Клик по ребру:

  • контракт
  • сумма
  • сроки
  • статус

Клик по объекту:

  • BIM
  • финансы
  • график
  • риски

Цветовая логика

Чтобы интерфейс “говорил”:

  • 🟢 норма
  • 🟡 риск
  • 🔴 проблема
  • 🔵 данные
  • 🟣 финансы

Панель справа (Control Panel)

  • фильтры (регион, тип объекта)
  • переключение режимов
  • аналитика
  • предупреждения

Панель снизу (Timeline)

Ползунок времени: 👉 можно “прокручивать стройку”

  • как было
  • как есть
  • прогноз

Главная ценность интерфейса

Это не UI.

Это: 👉 операционная карта отрасли в реальном времени

ТЕХНИЧЕСКАЯ АРХИТЕКТУРА (ТЗ)

Общая архитектура

Тип: Microservices + Data Platform + Digital Twin

Основные модули

Core Platform

  • авторизация
  • роли
  • API-шлюз

Реестры

Реестр объектов

  • ID
  • статус
  • гео
  • стадия

Реестр участников

  • компании
  • рейтинги
  • история

 Digital Twin (BIM)

  • хранение моделей
  • версии
  • привязка к этапам

Graph Engine (КЛЮЧЕВОЙ МОДУЛЬ)

Это сердце системы. Хранит:

  • узлы
  • рёбра
  • связи

👉 Технологии:

  • Neo4j / TigerGraph

Project Management

  • задачи
  • сроки
  • зависимости

Финансовый модуль

  • контракты
  • платежи
  • контроль

Маркетплейс

  • материалы
  • подрядчики
  • техника

AI / Аналитика

  • прогноз сроков
  • выявление рисков
  • оптимизация

Monitoring (IoT)

  • датчики
  • стройка
  • эксплуатация

Типы данных

Узлы:

  • объект
  • участник
  • ресурс
  • документ

Рёбра:

  • контракт
  • поставка
  • задача
  • платёж

API (пример)

Получить граф объекта

GET /api/object/{id}/graph

Получить связи участника: GET /api/company/{id}/relations

Получить риски: GET /api/object/{id}/risks

Роли пользователей

  • государство
  • инвестор
  • заказчик
  • подрядчик
  • контроль
  • гражданин

Потоки данных

1. BIM → Graph

2. Финансы → Graph

3. IoT → Monitoring

4. Пользователь → UI 👉 Всё сходится в Graph Engine

🔷 2.7. Без чего система не заработает

❌ если нет Graph Engine — нет кристалла

❌ если нет ID объектов — хаос

❌ если нет цифрового паспорта — нет прозрачности


КЛЮЧЕВАЯ ИДЕЯ 

Мы сейчас строим не:

  • сайт
  • маркетплейс
  • CRM

👉 Ты строишь:

Graph-based Operating System для строительства


MVP КРИСТАЛЛА СТРОИТЕЛЬСТВА

(первая работающая версия системы)

Цель MVP . Не надо пытаться сразу построить весь кристалл. Цель MVP: 👉 показать, что система “видит стройку как граф”. То есть MVP должен уметь:

  • создать объект
  • связать участников
  • показать связи
  • отобразить статус
  • выявить проблему

Если этого нет — всё остальное бессмысленно.

Что входит в MVP (минимум)

Реестр объектов

  • ID объекта
  • адрес / гео
  • стадия (проект / стройка / эксплуатация)
  • базовые параметры

Реестр участников

  • компании
  • роли (заказчик, подрядчик и т.д.)
  • рейтинг (пока простой)

Graph Engine (ядро) 👉 Самое важное. Хранит:

Визуальная карта (UI)

  • узлы = кружки
  • связи = линии
  • клик → информация

Простейший статус объекта

  • 🟢 нормально
  • 🟡 риск
  • 🔴 проблема


Базовая аналитика

  • просрочки
  • перегруз подрядчика
  • отсутствие связи

Архитектура MVP

Упрощённо:

[Frontend]

     ↓

[API Gateway]

     ↓

-------------------------

|   Core Backend        |

|-----------------------|

| Objects Service       |

| Companies Service     |

| Graph Service         |

| Auth Service          |

-------------------------

     ↓

[Databases]

- PostgreSQL

- Graph DB (Neo4j)

Стек технологий (оптимальный)

Backend 👉 Node.js (NestJS) или 👉 Python (FastAPI). Почему:

Frontend 👉 React + Next.js. Плюс:

Визуализация графа (КЛЮЧ)

👉 Cytoscape.js Или 👉 D3.js. Если хочешь проще старт: 👉 React Flow

Graph Database 👉 Neo4j (обязательно). Это сердце кристалла.

Основная БД 👉 PostgreSQL

API

  • REST (на MVP достаточно)
  • позже → GraphQL

Хостинг 👉 Быстрый старт:

  • Vercel (frontend)
  • Railway / Render (backend)
  • Neo4j Aura (graph)

Авторизация 👉 Auth0 / Firebase Auth или простой JWT на старте

Модель данных (упрощённая)

Узлы:

Object

  • id
  • name
  • status
  • location

Company

  • id
  • name
  • role

Рёбра: RELATION

  • type (contract / supplier / control)
  • start_date
  • status

Пример логики Graph

[Объект]

   |

   |---(контракт)---> [Генподрядчик]

   |

   |---(финансирование)---> [Банк]

   |

   |---(контроль)---> [Надзор]

👉 Это и есть минимальный кристалл.

MVP интерфейс (что должно быть)

Главный экран:

  • граф (центр)
  • панель справа:
    • список узлов
    • фильтр

При клике:

Объект:

  • статус
  • участники
  • риски

Компания:

  • проекты
  • связи

План разработки (реальный)

Неделя 1–2

  • архитектура
  • базы
  • API

Неделя 3–4

  • Graph Engine
  • связи

Неделя 5–6

  • UI + визуализация

Неделя 7–8

  • тест
  • запуск

👉 Через 2 месяца у тебя уже есть система

Минимальная команда

  • 1 backend
  • 1 frontend
  • 1 fullstack (или CTO)
  • 1 дизайнер (по желанию)

Где обычно ломаются

❌ Ошибка 1

делают CRM вместо графа

❌ Ошибка 2

нет нормальной модели данных

❌ Ошибка 3

перегружают MVP

❌ Ошибка 4

пытаются сразу “госуровень”

Ключ к успеху 👉 Сначала граф — потом всё остальное. Если у тебя:

  • есть узлы
  • есть связи
  • есть визуал

👉 у тебя уже есть кристалл

Что ты получишь на выходе MVP

  • живая карта стройки
  • прозрачные связи
  • первый уровень контроля
  • демонстрацию для инвесторов / государства

После MVP: 👉 добавить: финансы, BIM, маркетплейс

Если мы: 👉 сейчас запустим MVP за 6–8 недель — мы обгоним всех, кто пишет стратегии.

Структура базы данных

Логика простая: PostgreSQL хранит справочники, карточки объектов, пользователей, документы, события. Neo4j хранит сам граф связей: кто с кем связан, по какому типу связи, в каком статусе.

PostgreSQL: основные таблицы

Таблица users. Пользователи системы.

Поле

Тип

Назначение

id

UUID PK

Идентификатор

email

varchar unique

Логин

password_hash

varchar

Хэш пароля

full_name

varchar

ФИО

phone

varchar

Телефон

status

varchar

active / blocked / invited

created_at

timestamp

Дата создания

updated_at

timestamp

Дата обновления

Таблица rolesю Роли доступа.

Поле

Тип

id

UUID PK

code

varchar unique

name

varchar

Примеры:

Таблица user_roles. Связка пользователей и ролей.

Поле

Тип

id

UUID PK

user_id

UUID FK -> users.id

role_id

UUID FK -> roles.id

created_at

timestamp

Таблица companies. Участники рынка.

Поле

Тип

Назначение

id

UUID PK

ID компании

name

varchar

Наименование

short_name

varchar

Короткое имя

inn

varchar

ИНН

ogrn

varchar

ОГРН

company_type

varchar

customer / contractor / supplier / bank / regulator

rating

numeric(3,2)

Рейтинг

status

varchar

active / inactive

website

varchar

Сайт

created_at

timestamp

Дата создания

updated_at

timestamp

Дата обновления

Таблица company_users. Привязка пользователя к компании.

Поле

Тип

id

UUID PK

company_id

UUID FK -> companies.id

user_id

UUID FK -> users.id

position

varchar

is_primary

boolean

created_at

timestamp

Таблица regions. Справочник регионов.

Поле

Тип

id

UUID PK

code

varchar unique

name

varchar

Таблица locations. Адреса и координаты.

Поле

Тип

id

UUID PK

region_id

UUID FK -> regions.id

address

text

lat

numeric(10,7)

lon

numeric(10,7)

cadastral_number

varchar

created_at

timestamp

Таблица projects. Карточка объекта строительства.

Поле

Тип

Назначение

id

UUID PK

ID объекта

code

varchar unique

Внутренний номер

name

varchar

Название

description

text

Описание

project_type

varchar

residential / industrial / infrastructure

lifecycle_stage

varchar

concept / design / construction / operation

status

varchar

normal / risk / problem / archived

location_id

UUID FK -> locations.id

Локация

customer_company_id

UUID FK -> companies.id

Заказчик

start_date

date

Плановый старт

end_date

date

Плановое завершение

planned_budget

numeric(18,2)

Плановый бюджет

actual_budget

numeric(18,2)

Факт

created_at

timestamp

Дата создания

updated_at

timestamp

Дата обновления

Таблица project_stages. Этапы проекта.

Поле

Тип

id

UUID PK

project_id

UUID FK -> projects.id

stage_code

varchar

stage_name

varchar

planned_start

date

planned_end

date

actual_start

date

actual_end

date

status

varchar

created_at

timestamp

Таблица contracts. Контракты внутри системы.

Поле

Тип

id

UUID PK

project_id

UUID FK -> projects.id

contract_number

varchar

contract_type

varchar

customer_company_id

UUID FK -> companies.id

contractor_company_id

UUID FK -> companies.id

amount

numeric(18,2)

currency

varchar

date_start

date

date_end

date

status

varchar

created_at

timestamp

updated_at

timestamp

Таблица documents. Документы проекта.

Поле

Тип

id

UUID PK

project_id

UUID FK -> projects.id

company_id

UUID FK -> companies.id null

contract_id

UUID FK -> contracts.id null

doc_type

varchar

title

varchar

file_url

text

version

integer

issued_at

date

status

varchar

created_by

UUID FK -> users.id

created_at

timestamp

Таблица risks Риски по объекту.

Поле

Тип

id

UUID PK

project_id

UUID FK -> projects.id

related_company_id

UUID FK -> companies.id null

related_stage_id

UUID FK -> project_stages.id null

risk_type

varchar

severity

varchar

probability

varchar

description

text

status

varchar

detected_at

timestamp

resolved_at

timestamp null

Таблица events. Лента событий.

Поле

Тип

id

UUID PK

project_id

UUID FK -> projects.id null

company_id

UUID FK -> companies.id null

user_id

UUID FK -> users.id null

event_type

varchar

event_payload

jsonb

created_at

timestamp

Таблица project_metrics. Метрики по проекту.

Поле

Тип

id

UUID PK

project_id

UUID FK -> projects.id

metric_date

date

progress_percent

numeric(5,2)

cost_variance

numeric(18,2)

schedule_variance_days

integer

open_risks_count

integer

created_at

timestamp

Индексы PostgreSQL

Минимально нужны:

Neo4j: модель графа

В графе храним сущности как узлы и отношения как рёбра.

Узлы. Основные labels:

Обязательные свойства узла. Для единообразия:

Типы рёбер Neo4j. Основные отношения

  • [:LOCATED_AT]
    Project -> Location
  • [:OWNED_BY]
    Project -> Company
  • [:PARTICIPATES_IN]
    Company -> Project
  • [:HAS_STAGE]
    Project -> Stage
  • [:HAS_CONTRACT]
    Project -> Contract
  • [:CUSTOMER_IN]
    Company -> Contract
  • [:CONTRACTOR_IN]
    Company -> Contract
  • [:HAS_DOCUMENT]
    Project -> Document
  • [:ISSUED_BY]
    Document -> Company
  • [:HAS_RISK]
    Project -> Risk
  • [:RELATED_TO]
    Risk -> Company или Risk -> Stage
  • [:EMPLOYED_BY]
    User -> Company

Свойства рёбер

Например у PARTICIPATES_IN:

  • role
  • startDate
  • endDate
  • status

У HAS_CONTRACT:

  • contractNumber
  • amount
  • currency
  • status

У HAS_RISK:

  • severity
  • detectedAt

Пример графа

(Company: Customer) -[:PARTICIPATES_IN {role:"customer"}]-> (Project)

(Company: GeneralContractor) -[:PARTICIPATES_IN {role:"general_contractor"}]-> (Project)

(Project) -[:HAS_CONTRACT]-> (Contract)

(Company: Customer) -[:CUSTOMER_IN]-> (Contract)

(Company: GeneralContractor) -[:CONTRACTOR_IN]-> (Contract)

(Project) -[:HAS_STAGE]-> (Stage: Construction)

(Project) -[:HAS_RISK {severity:"high"}]-> (Risk)

(Project) -[:LOCATED_AT]-> (Location)


Архитектура API

Для MVP хватит REST API v1.Позже можно добавить GraphQL для сложных экранов графа.

Общие правила API

Базовый префикс

/api/v1

Формат

{

  "data": {},

  "meta": {},

  "error": null

}

Ошибка

{

  "data": null,

  "meta": {},

  "error": {

    "code": "PROJECT_NOT_FOUND",

    "message": "Project not found"

  }


Авторизация Authorization: Bearer <token>


Auth API. POST /auth/login. Вход.

Request

{

  "email": "[email protected]",

  "password": "secret"

}

Response

{

  "data": {

    "accessToken": "jwt",

    "refreshToken": "jwt",

    "user": {

      "id": "uuid",

      "fullName": "Иван Петров",

      "email": "[email protected]",

      "roles": ["customer"]

    }

  },

  "meta": {},

  "error": null

}

POST /auth/refresh. Обновление токена.

GET /auth/me. Профиль текущего пользователя.

API компаний

GET /companies. Список компаний. Параметры:

  • search
  • companyType
  • status
  • page
  • limit

POST /companies. Создать компанию.

Request

{

  "name": "ООО СтройГрад",

  "shortName": "СтройГрад",

  "inn": "1234567890",

  "ogrn": "1234567890123",

  "companyType": "contractor",

  "website": "https://example.com"

}

GET /companies/{id}. Карточка компании.

PATCH /companies/{id}. Обновить компанию.


GET /companies/{id}/projects. Проекты компании.

GET /companies/{id}/relations. Связи компании в графе.

Response

{

  "data": {

    "nodes": [

      { "id": "c1", "type": "company", "name": "ООО СтройГрад" },

      { "id": "p1", "type": "project", "name": "ЖК Север" }

    ],

    "edges": [

      {

        "from": "c1",

        "to": "p1",

        "type": "PARTICIPATES_IN",

        "role": "contractor",

        "status": "active"

      }

    ]

  },

  "meta": {},

  "error": null

}

API проектов

GET /projects. Список проектов. Фильтры:

  • status
  • lifecycleStage
  • regionId
  • customerCompanyId
  • search
  • page
  • limit

POST /projects. Создать проект.

Request

{

  "name": "ЖК Север",

  "description": "Многофункциональный жилой комплекс",

  "projectType": "residential",

  "lifecycleStage": "design",

  "status": "normal",

  "location": {

    "regionId": "uuid",

    "address": "Санкт-Петербург, ...",

    "lat": 59.93,

    "lon": 30.31,

    "cadastralNumber": "78:00:0000000:1234"

  },

  "customerCompanyId": "uuid",

  "startDate": "2026-04-01",

  "endDate": "2028-10-31",

  "plannedBudget": 2500000000

}

GET /projects/{id}Карточка проекта.

PATCH /projects/{id}. Обновить проект.

GET /projects/{id}/graph. Главный endpoint MVP. Возвращает узлы и рёбра объекта.

Response

{

  "data": {

    "project": {

      "id": "uuid",

      "name": "ЖК Север",

      "status": "risk",

      "lifecycleStage": "construction"

    },

    "nodes": [

      { "id": "p1", "type": "project", "name": "ЖК Север", "status": "risk" },

      { "id": "c1", "type": "company", "name": "Заказчик Девелопмент", "status": "active" },

      { "id": "c2", "type": "company", "name": "ГенПодряд 1", "status": "active" },

      { "id": "r1", "type": "risk", "name": "Срыв сроков", "status": "open" }

    ],

    "edges": [

      { "from": "c1", "to": "p1", "type": "PARTICIPATES_IN", "role": "customer", "status": "active" },

      { "from": "c2", "to": "p1", "type": "PARTICIPATES_IN", "role": "general_contractor", "status": "active" },

      { "from": "p1", "to": "r1", "type": "HAS_RISK", "severity": "high" }

    ]

  },

  "meta": {},

  "error": null

}

GET /projects/{id}/timeline. Лента изменений и событий.

GET /projects/{id}/metrics. Метрики проекта.

GET /projects/{id}/risks. Список рисков.

POST /projects/{id}/risks. Создать риск.

GET /projects/{id}/documents. Документы проекта.

POST /projects/{id}/documents. Загрузить документ.

GET /projects/{id}/companies. Участники проекта.

POST /projects/{id}/companies. Добавить участника в проект.

Request

{

  "companyId": "uuid",

  "role": "supplier",

  "startDate": "2026-05-01",

  "status": "active"

}

API этапов проекта

GET  /projects/{id}/stages. Список этапов.

POST /projects/{id}/stages. Создать этап.

PATCH  /projects/{id}/stages/{stageId}. Обновить этап.

API контрактов

GET /contracts. Список контрактов. Фильтры:

  • projectId
  • customerCompanyId
  • contractorCompanyId
  • status

POST /contracts. Создать контракт.

Request

{

  "projectId": "uuid",

  "contractNumber": "C-2026-001",

  "contractType": "general_contract",

  "customerCompanyId": "uuid",

  "contractorCompanyId": "uuid",

  "amount": 1500000000,

  "currency": "RUB",

  "dateStart": "2026-04-10",

  "dateEnd": "2027-12-20",

  "status": "active"

}

GET /contracts/{id}. Карточка контракта.

PATCH /contracts/{id}. Обновить контракт.

API рисков

GET /risks. Общий список рисков. Фильтры:

POST /risks. Создать риск.

PATCH /risks/{id}. Изменить риск.

POST /risks/{id}/resolve. Закрыть риск.

API документов

GET /documents/{id}. Метаданные документа.

GET /documents/{id}/download Скачать файл.

API графа. Это отдельный сервис, потому что это сердце системы.

GET /graph/projects/{id}

Граф проекта.

GET /graph/companies/{id}

Граф компании.

POST /graph/query

Поисковый или аналитический запрос к графу. Для MVP лучше ограничить шаблонными запросами, а не давать произвольный Cypher.

Request

{

  "queryType": "project_neighbors",

  "entityId": "uuid",

  "depth": 2

}

GET /graph/search. Поиск сущностей в графе:

  • q
  • type

API аналитики

GET /analytics/dashboard

Сводные показатели:

  • число проектов
  • число проблемных проектов
  • число открытых рисков
  • число активных компаний

GET /analytics/projects/status-summary

Сводка по статусам проектов.

GET /analytics/companies/top-contractors

Топ подрядчиков по числу проектов.

GET /analytics/risks/hotspots

Где больше всего рисков.

API событий

GET /events

Журнал событий. Фильтры:

  • projectId
  • companyId
  • eventType
  • from
  • to

Разделение на сервисы. Для MVP достаточно 5 сервисов.

auth-service

  • login
  • refresh
  • me
  • users
  • roles

directory-service

  • companies
  • regions
  • locations

project-service

  • projects
  • stages
  • contracts
  • documents
  • risks
  • metrics
  • events

graph-service

  • graph endpoints
  • sync from PostgreSQL to Neo4j
  • graph queries

analytics-service

  • dashboards
  • summaries
  • alerts

Синхронизация PostgreSQL и Neo4j

Это важный момент. Источник истины для карточек — PostgreSQL. Источник истины для связей и обходов — Neo4j.

Подход. После создания/обновления сущности в PostgreSQL:

  • пишем запись в events
  • публикуем событие
  • graph-service обновляет граф

Примеры событий:

  • project.created
  • project.updated
  • company.added_to_project
  • contract.created
  • risk.created

Минимальные DTO

CreateProjectDto

{

  "name": "string",

  "description": "string",

  "projectType": "residential",

  "lifecycleStage": "design",

  "status": "normal",

  "customerCompanyId": "uuid",

  "startDate": "2026-04-01",

  "endDate": "2027-12-31",

  "plannedBudget": 1000000

}

AddCompanyToProjectDto

{

  "companyId": "uuid",

  "role": "contractor",

  "startDate": "2026-04-01",

  "endDate": null,

  "status": "active"

}

CreateRiskDto

{

  "projectId": "uuid",

  "relatedCompanyId": "uuid",

  "riskType": "deadline_delay",

  "severity": "high",

  "probability": "medium",

  "description": "Отставание от графика на 21 день"

}

Что обязательно сделать в первой версии

Без этого MVP будет пустым:

Обязательно

  • projects
  • companies
  • contracts
  • risks
  • events
  • GET /projects/{id}/graph
  • GET /companies/{id}/relations

Можно отложить

  • сложные документы
  • расширенную аналитику
  • IoT
  • BIM-хранилище
  • маркетплейс

Прямой рекомендуемый стек под эту схему

Backend

  • NestJS
  • PostgreSQL
  • Prisma или TypeORM
  • Neo4j
  • Redis для кэша и очередей
  • Swagger/OpenAPI для документации

Frontend

  • Next.js
  • React Query
  • Cytoscape.js для графа
  • Tailwind CSS или MUI

Infra

  • Docker
  • Docker Compose для MVP
  • Nginx
  • S3-совместимое хранилище для документов


Структура репозитория

/crystal-construction

  /apps

    /api-gateway

    /auth-service

    /directory-service

    /project-service

    /graph-service

    /analytics-service

    /web-client

  /packages

    /shared-types

    /shared-utils

    /ui

  /infra

    /docker

    /nginx

    /db

  /docs

    openapi.yaml

    database-schema.md

    graph-model.md

Самый правильный порядок сборки

  • Поднять auth-service
  • Поднять directory-service
  • Сделать project-service
  • Сделать graph-service
  • Подключить UI к GET /projects/{id}/graph
  • Добавить риски и события
  • Добавить dashboard

MVP должен отвечать на 4 вопроса:

  • Что это за объект?
  • Кто с ним связан?
  • Где риск?
  • Что происходит сейчас?

Если API и БД это дают — у тебя уже есть рабочее ядро Кристалла Строительства.





1. OpenAPI-черновик

Ниже укороченный, но рабочий каркас спецификации OpenAPI 3.1 для MVP.

openapi: 3.1.0

info:

  title: Crystal Construction API

  version: 1.0.0

  description: API MVP платформы "Кристалл Строительства"


servers:

  - url: https://api.crystal-construction.local/api/v1


tags:

  - name: Auth

  - name: Companies

  - name: Projects

  - name: Contracts

  - name: Risks

  - name: Graph

  - name: Analytics


paths:

  /auth/login:

    post:

      tags: [Auth]

      summary: Вход пользователя

      requestBody:

        required: true

        content:

          application/json:

            schema:

              $ref: '#/components/schemas/LoginRequest'

      responses:

        '200':

          description: Успешный вход

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/AuthResponse'


  /auth/me:

    get:

      tags: [Auth]

      summary: Профиль текущего пользователя

      security:

        - bearerAuth: []

      responses:

        '200':

          description: Профиль пользователя

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/UserProfileResponse'


  /companies:

    get:

      tags: [Companies]

      summary: Список компаний

      security:

        - bearerAuth: []

      parameters:

        - in: query

          name: search

          schema: { type: string }

        - in: query

          name: companyType

          schema: { type: string }

        - in: query

          name: status

          schema: { type: string }

        - in: query

          name: page

          schema: { type: integer, minimum: 1, default: 1 }

        - in: query

          name: limit

          schema: { type: integer, minimum: 1, maximum: 100, default: 20 }

      responses:

        '200':

          description: Список компаний

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/CompanyListResponse'


    post:

      tags: [Companies]

      summary: Создать компанию

      security:

        - bearerAuth: []

      requestBody:

        required: true

        content:

          application/json:

            schema:

              $ref: '#/components/schemas/CreateCompanyRequest'

      responses:

        '201':

          description: Компания создана

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/CompanyResponse'


  /companies/{id}:

    get:

      tags: [Companies]

      summary: Карточка компании

      security:

        - bearerAuth: []

      parameters:

        - $ref: '#/components/parameters/IdPath'

      responses:

        '200':

          description: Данные компании

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/CompanyResponse'


    patch:

      tags: [Companies]

      summary: Обновить компанию

      security:

        - bearerAuth: []

      parameters:

        - $ref: '#/components/parameters/IdPath'

      requestBody:

        required: true

        content:

          application/json:

            schema:

              $ref: '#/components/schemas/UpdateCompanyRequest'

      responses:

        '200':

          description: Компания обновлена

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/CompanyResponse'


  /companies/{id}/relations:

    get:

      tags: [Graph]

      summary: Граф связей компании

      security:

        - bearerAuth: []

      parameters:

        - $ref: '#/components/parameters/IdPath'

        - in: query

          name: depth

          schema: { type: integer, minimum: 1, maximum: 3, default: 1 }

      responses:

        '200':

          description: Граф компании

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/GraphResponse'


  /projects:

    get:

      tags: [Projects]

      summary: Список проектов

      security:

        - bearerAuth: []

      parameters:

        - in: query

          name: status

          schema: { type: string }

        - in: query

          name: lifecycleStage

          schema: { type: string }

        - in: query

          name: regionId

          schema: { type: string, format: uuid }

        - in: query

          name: customerCompanyId

          schema: { type: string, format: uuid }

        - in: query

          name: search

          schema: { type: string }

        - in: query

          name: page

          schema: { type: integer, default: 1 }

        - in: query

          name: limit

          schema: { type: integer, default: 20 }

      responses:

        '200':

          description: Список проектов

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/ProjectListResponse'


    post:

      tags: [Projects]

      summary: Создать проект

      security:

        - bearerAuth: []

      requestBody:

        required: true

        content:

          application/json:

            schema:

              $ref: '#/components/schemas/CreateProjectRequest'

      responses:

        '201':

          description: Проект создан

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/ProjectResponse'


  /projects/{id}:

    get:

      tags: [Projects]

      summary: Карточка проекта

      security:

        - bearerAuth: []

      parameters:

        - $ref: '#/components/parameters/IdPath'

      responses:

        '200':

          description: Данные проекта

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/ProjectResponse'


    patch:

      tags: [Projects]

      summary: Обновить проект

      security:

        - bearerAuth: []

      parameters:

        - $ref: '#/components/parameters/IdPath'

      requestBody:

        required: true

        content:

          application/json:

            schema:

              $ref: '#/components/schemas/UpdateProjectRequest'

      responses:

        '200':

          description: Проект обновлён

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/ProjectResponse'


  /projects/{id}/graph:

    get:

      tags: [Graph]

      summary: Граф проекта

      security:

        - bearerAuth: []

      parameters:

        - $ref: '#/components/parameters/IdPath'

        - in: query

          name: depth

          schema: { type: integer, minimum: 1, maximum: 3, default: 2 }

      responses:

        '200':

          description: Граф проекта

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/ProjectGraphResponse'


  /projects/{id}/companies:

    post:

      tags: [Projects]

      summary: Добавить участника в проект

      security:

        - bearerAuth: []

      parameters:

        - $ref: '#/components/parameters/IdPath'

      requestBody:

        required: true

        content:

          application/json:

            schema:

              $ref: '#/components/schemas/AddCompanyToProjectRequest'

      responses:

        '201':

          description: Участник добавлен

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/OperationResponse'


  /contracts:

    get:

      tags: [Contracts]

      summary: Список контрактов

      security:

        - bearerAuth: []

      parameters:

        - in: query

          name: projectId

          schema: { type: string, format: uuid }

        - in: query

          name: customerCompanyId

          schema: { type: string, format: uuid }

        - in: query

          name: contractorCompanyId

          schema: { type: string, format: uuid }

        - in: query

          name: status

          schema: { type: string }

      responses:

        '200':

          description: Список контрактов

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/ContractListResponse'


    post:

      tags: [Contracts]

      summary: Создать контракт

      security:

        - bearerAuth: []

      requestBody:

        required: true

        content:

          application/json:

            schema:

              $ref: '#/components/schemas/CreateContractRequest'

      responses:

        '201':

          description: Контракт создан

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/ContractResponse'


  /risks:

    get:

      tags: [Risks]

      summary: Список рисков

      security:

        - bearerAuth: []

      parameters:

        - in: query

          name: projectId

          schema: { type: string, format: uuid }

        - in: query

          name: severity

          schema: { type: string }

        - in: query

          name: status

          schema: { type: string }

      responses:

        '200':

          description: Список рисков

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/RiskListResponse'


    post:

      tags: [Risks]

      summary: Создать риск

      security:

        - bearerAuth: []

      requestBody:

        required: true

        content:

          application/json:

            schema:

              $ref: '#/components/schemas/CreateRiskRequest'

      responses:

        '201':

          description: Риск создан

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/RiskResponse'


  /risks/{id}/resolve:

    post:

      tags: [Risks]

      summary: Закрыть риск

      security:

        - bearerAuth: []

      parameters:

        - $ref: '#/components/parameters/IdPath'

      responses:

        '200':

          description: Риск закрыт

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/RiskResponse'


  /analytics/dashboard:

    get:

      tags: [Analytics]

      summary: Дашборд MVP

      security:

        - bearerAuth: []

      responses:

        '200':

          description: Сводная аналитика

          content:

            application/json:

              schema:

                $ref: '#/components/schemas/DashboardResponse'


components:

  securitySchemes:

    bearerAuth:

      type: http

      scheme: bearer

      bearerFormat: JWT


  parameters:

    IdPath:

      in: path

      name: id

      required: true

      schema:

        type: string

        format: uuid


  schemas:

    ApiError:

      type: object

      properties:

        code: { type: string }

        message: { type: string }

      required: [code, message]


    LoginRequest:

      type: object

      properties:

        email: { type: string, format: email }

        password: { type: string }

      required: [email, password]


    AuthUser:

      type: object

      properties:

        id: { type: string, format: uuid }

        fullName: { type: string }

        email: { type: string, format: email }

        roles:

          type: array

          items: { type: string }

      required: [id, fullName, email, roles]


    AuthResponse:

      type: object

      properties:

        data:

          type: object

          properties:

            accessToken: { type: string }

            refreshToken: { type: string }

            user:

              $ref: '#/components/schemas/AuthUser'

        meta: { type: object }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    UserProfileResponse:

      type: object

      properties:

        data:

          $ref: '#/components/schemas/AuthUser'

        meta: { type: object }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    Company:

      type: object

      properties:

        id: { type: string, format: uuid }

        name: { type: string }

        shortName: { type: string }

        inn: { type: string }

        ogrn: { type: string }

        companyType: { type: string }

        rating: { type: number }

        status: { type: string }

        website: { type: string, nullable: true }

      required: [id, name, companyType, status]


    CreateCompanyRequest:

      type: object

      properties:

        name: { type: string }

        shortName: { type: string }

        inn: { type: string }

        ogrn: { type: string }

        companyType: { type: string }

        website: { type: string }

      required: [name, inn, ogrn, companyType]


    UpdateCompanyRequest:

      type: object

      properties:

        name: { type: string }

        shortName: { type: string }

        companyType: { type: string }

        rating: { type: number }

        status: { type: string }

        website: { type: string }


    CompanyResponse:

      type: object

      properties:

        data:

          $ref: '#/components/schemas/Company'

        meta: { type: object }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    CompanyListResponse:

      type: object

      properties:

        data:

          type: array

          items:

            $ref: '#/components/schemas/Company'

        meta:

          type: object

          properties:

            page: { type: integer }

            limit: { type: integer }

            total: { type: integer }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    LocationInput:

      type: object

      properties:

        regionId: { type: string, format: uuid }

        address: { type: string }

        lat: { type: number }

        lon: { type: number }

        cadastralNumber: { type: string }

      required: [regionId, address]


    Project:

      type: object

      properties:

        id: { type: string, format: uuid }

        code: { type: string }

        name: { type: string }

        description: { type: string, nullable: true }

        projectType: { type: string }

        lifecycleStage: { type: string }

        status: { type: string }

        customerCompanyId: { type: string, format: uuid }

        startDate: { type: string, format: date, nullable: true }

        endDate: { type: string, format: date, nullable: true }

        plannedBudget: { type: number, nullable: true }

        actualBudget: { type: number, nullable: true }

      required: [id, name, projectType, lifecycleStage, status]


    CreateProjectRequest:

      type: object

      properties:

        name: { type: string }

        description: { type: string }

        projectType: { type: string }

        lifecycleStage: { type: string }

        status: { type: string }

        location:

          $ref: '#/components/schemas/LocationInput'

        customerCompanyId: { type: string, format: uuid }

        startDate: { type: string, format: date }

        endDate: { type: string, format: date }

        plannedBudget: { type: number }

      required:

        - name

        - projectType

        - lifecycleStage

        - status

        - location

        - customerCompanyId


    UpdateProjectRequest:

      type: object

      properties:

        name: { type: string }

        description: { type: string }

        lifecycleStage: { type: string }

        status: { type: string }

        actualBudget: { type: number }

        endDate: { type: string, format: date }


    ProjectResponse:

      type: object

      properties:

        data:

          $ref: '#/components/schemas/Project'

        meta: { type: object }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    ProjectListResponse:

      type: object

      properties:

        data:

          type: array

          items:

            $ref: '#/components/schemas/Project'

        meta:

          type: object

          properties:

            page: { type: integer }

            limit: { type: integer }

            total: { type: integer }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    GraphNode:

      type: object

      properties:

        id: { type: string }

        type: { type: string }

        name: { type: string }

        status: { type: string, nullable: true }

        metadata:

          type: object

          additionalProperties: true

      required: [id, type, name]


    GraphEdge:

      type: object

      properties:

        from: { type: string }

        to: { type: string }

        type: { type: string }

        role: { type: string, nullable: true }

        status: { type: string, nullable: true }

        metadata:

          type: object

          additionalProperties: true

      required: [from, to, type]


    GraphResponse:

      type: object

      properties:

        data:

          type: object

          properties:

            nodes:

              type: array

              items: { $ref: '#/components/schemas/GraphNode' }

            edges:

              type: array

              items: { $ref: '#/components/schemas/GraphEdge' }

        meta: { type: object }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    ProjectGraphResponse:

      type: object

      properties:

        data:

          type: object

          properties:

            project:

              $ref: '#/components/schemas/Project'

            nodes:

              type: array

              items: { $ref: '#/components/schemas/GraphNode' }

            edges:

              type: array

              items: { $ref: '#/components/schemas/GraphEdge' }

        meta: { type: object }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    CreateContractRequest:

      type: object

      properties:

        projectId: { type: string, format: uuid }

        contractNumber: { type: string }

        contractType: { type: string }

        customerCompanyId: { type: string, format: uuid }

        contractorCompanyId: { type: string, format: uuid }

        amount: { type: number }

        currency: { type: string }

        dateStart: { type: string, format: date }

        dateEnd: { type: string, format: date }

        status: { type: string }

      required:

        - projectId

        - contractNumber

        - contractType

        - customerCompanyId

        - contractorCompanyId

        - amount

        - currency

        - status


    Contract:

      type: object

      properties:

        id: { type: string, format: uuid }

        projectId: { type: string, format: uuid }

        contractNumber: { type: string }

        contractType: { type: string }

        customerCompanyId: { type: string, format: uuid }

        contractorCompanyId: { type: string, format: uuid }

        amount: { type: number }

        currency: { type: string }

        status: { type: string }

      required: [id, projectId, contractNumber, contractType, amount, currency, status]


    ContractResponse:

      type: object

      properties:

        data:

          $ref: '#/components/schemas/Contract'

        meta: { type: object }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    ContractListResponse:

      type: object

      properties:

        data:

          type: array

          items: { $ref: '#/components/schemas/Contract' }

        meta: { type: object }

        error:

          oneOf:

            - $ref: '#/components/schemas/ApiError'

            - { type: 'null' }


    CreateRiskRequest:

      type: object

      properties:

        projectId: { type: string, format: uuid }

        relatedCompanyId: { type: string, format: uuid, nullable: true }

        riskType: { type: string }

        severity: { type: string }

        probability: { type: string }

        description: { type: string }

      required: [projectId, riskType, severity, probability, description]


    Risk:

      type: object

      properties:

        id: { type: string, format: uuid }

        projectId: { type: string, format: uuid }

        relatedCompanyId: { type: string, format