Что болело до нас

Собственнику среднего бизнеса нужна схема компании с зонами ответственности. Инструментов под эту узкую задачу в РФ почти нет. Люди идут в Miro и Visio.

Это универсальные рисовалки. Оргструктуру в них собирают с нуля прямоугольниками. Уходит час и больше. Результат остаётся картинкой без смысла: кто за что отвечает, из схемы не видно.

  • Платная подписка ради одной разовой задачи
  • Интерфейс на английском
  • Водяной знак на экспорте в бесплатных тарифах
  • Проблемы с доступом из России без VPN
  • Пустой холст вместо готовой заготовки под нишу

Что получилось

Конструктор на React Flow. Карточки сотрудников перетаскиваются мышью. Связи подчинения тянутся между четырьмя точками на карточке: сверху, справа, снизу, слева.

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

Шесть шаблонов под нишу лежат прямо в коде. Применение шаблона сразу расставляет сотрудников по координатам и строит связи подчинения. В шаблонах от 6 до 8 сотрудников, дальше вы дописываете своих.

Смысл схемы держится на поле ЦКП в карточке: ценный конечный продукт человека, за что он отвечает. Рядом должность, подотдел, цвет и фото. Встроенная модель на 28 подразделений (7 главных отделов и 21 подотдел) идёт с готовыми формулировками ЦКП, их можно взять как основу.

  • Экспорт в PNG и PDF, рендер в двойном масштабе для читаемости при печати
  • Регистрация по email, восстановление пароля письмом со ссылкой на час
  • Данные каждой компании лежат в отдельной папке под своим orgId
  • Через 15 дней без активности папка удаляется, баннер предупреждает за 7 и за 3 дня
!
Числа проверяются по файлу, память тут не помощник

Маркетинг писали отдельно от кода, и витрина обогнала продукт: восемь шаблонов в плитках против шести в репозитории, живой счётчик компаний против скрипта со случайной прибавкой. Теперь любое число на странице подтверждается ссылкой на конкретный файл. Если подтверждения нет, число со страницы уходит.

Как устроено внутри

Два раздельных приложения в одном репозитории. Клиент: React 18 и TypeScript на Vite, холст на React Flow 12. Сервер: Express на TypeScript, запускается через tsx без предварительной компиляции. Он же раздаёт собранный клиент, лендинг и политику.

Экспорт делается целиком в браузере. html2canvas снимает нужный DOM-узел с масштабом 2. Дальше картинка либо уходит в PNG через canvas.toDataURL, либо кладётся в jsPDF. Ориентация листа выбирается автоматически по соотношению сторон.

Базы данных здесь нет вообще. Всё хранится в JSON-файлах на диске. Решение осознанное, ради скорости запуска продукта. Изоляция компаний держится на двух вещах: requireAuth висит на всём префиксе /api и отрабатывает раньше остальных роутов, а orgId берётся строго из JWT и прогоняется через sanitizeOrgId, который оставляет латиницу, цифры и дефис и обрезает строку до 36 символов.

Деплой контейнерный. Push в main запускает GitHub Actions, тот собирает двухстадийный Docker-образ и публикует его в ghcr.io. Сервер забирает образ сам. Внутри контейнера процесс работает под непривилегированным пользователем, данные и загрузки подключены томами.

Грабли

Кейс писался по коду, и разбор вскрыл расхождения. Часть из них ушла в работу сразу.

Главный урок: лендинг написали раньше продукта, и за месяц они разъехались. В витрине лендинга восемь плиток шаблонов, включая «Производство», которого в коде нет вообще. Числа отделов и ролей в плитках тоже придуманы.

  • Счётчик «компаний создали структуру» на лендинге нарисованный: число зашито в HTML, скрипт каждые несколько секунд подкручивает его вверх. В кейс мы его не берём, реальное число видно только в админ-панели
  • Формы лид-магнита на живом лендинге показывали alert с заглушкой и никуда ничего не отправляли. Заявки терялись. Это первое в очереди на починку
  • Счётчиков аналитики на лендинге нет ни одного. Продукт делается ради трафика, а измерять результат нечем
  • Отказ от базы дал издержки: каждая правка перечитывает и переписывает файл целиком, id нового сотрудника считается максимумом по существующим. Две открытые вкладки затрут друг друга, блокировок нет
  • В middleware осталась запасная ветка: если пользователь не определён, orgId берётся из заголовка. Сейчас это мёртвый код, до него не доходит выполнение. Подстраховку убираем совсем, чтобы перестановка строк однажды не открыла чужую компанию
  • Первую версию Docker-образа собирали как Next.js, хотя проект это Vite плюс Express на tsx. Шаблон сборки от соседнего проекта не подошёл, образ переделали
  • Экспорт в режиме «Холст» снимает узел рендерера, поэтому отскролленное за пределы видимой области может не попасть в картинку. В «Иерархии» и «Функциональной» контейнеры снимаются целиком

Что продукт пока не делает

Честный список ограничений, чтобы вы не ждали от инструмента лишнего.

PDF собирается как растровая картинка внутри листа. Для печати плаката А1 он не годится. Публичной ссылки на просмотр нет: кнопка «Поделиться» копирует адрес, коллега без аккаунта увидит форму входа. Отдельного поля KPI в карточке нет, есть одно текстовое поле ЦКП. Данные удаляются через 15 дней бездействия, любая правка обнуляет таймер.

Частые вопросы

Сколько времени занимает сборка оргструктуры?

Вы открываете конструктор и применяете шаблон под свою нишу. Он сразу расставляет от 6 до 8 сотрудников по координатам и строит связи подчинения. Дальше вы меняете имена и дописываете своих людей. Отсюда и пять минут в заголовке.

Какие шаблоны уже есть внутри?

Шесть готовых шаблонов: агентство, IT, ритейл, ресторан, школа, стартап. Отдельно идёт встроенная модель на 28 подразделений: 7 главных отделов и 21 подотдел, у каждого прописан ЦКП. Формулировки из модели можно взять как основу и переписать под себя.

В каком виде можно скачать готовую схему?

Одной кнопкой в PNG или PDF, рендер идёт в двойном масштабе для читаемости при печати. Водяных знаков на экспорте нет, подписка не нужна. У PDF есть ограничение: лист собирается как растровая картинка, для печати плаката А1 он не подойдёт.

Кто увидит структуру моей компании?

Только вы и те, кому вы дадите доступ. Данные каждой компании лежат в отдельной папке под своим orgId, а orgId берётся строго из JWT, не из запроса. Проверка авторизации висит на всём префиксе /api и срабатывает раньше остальных роутов. Через 15 дней без активности папка удаляется, баннер предупреждает за 7 и за 3 дня.

Чем это лучше Miro или Visio?

Miro и Visio это универсальные рисовалки: оргструктуру там собирают прямоугольниками с пустого холста, уходит час и больше. Здесь вы стартуете с готового шаблона под нишу, а в каждой карточке есть поле ЦКП, то есть за что человек отвечает. Интерфейс русский, доступ из России без VPN, бесплатно.