Разберем, как спроектировать веб-приложение для бронирования переговорных: роли, правила, буферы и как попросить AI находить конфликты.

Офисная переговорная кажется простой вещью, пока несколько команд не начинают жить в разных календарях, переносить встречи в последний момент и считать, что «мы уже заняли». В итоге теряются 10 минут на поиск свободной комнаты, срываются созвоны, а администратор превращается в диспетчера.
Даже если у вас есть общий календарь, конфликты все равно появляются. Кто-то ставит встречу поверх другой, кто-то забывает отменить бронь, кто-то бронирует на 15 минут раньше «для надежности», а кто-то приходит раньше и занимает комнату без записи. Часто проблема еще и в ожиданиях: для одних «планерка на 30 минут», для других - «нам нужно время подготовиться и собрать людей».
Сервис бронирования решает две вещи: делает статус комнаты понятным всем и заставляет систему принимать решения одинаково для всех. Эти решения и есть «правила»: кто может бронировать, насколько заранее, на какой срок, можно ли переносить чужие встречи и что делать, если заявка пересекается с другой.
До разработки важно договориться об ограничениях. Если их не зафиксировать, они всплывут в виде исключений и ручных согласований.
С самого начала стоит определить рабочие часы и допустимую длительность встреч, буферы до и после брони (например, 5-10 минут на подготовку), правила по ролям (сотрудник, руководитель, администратор), приоритеты в спорных случаях (можно ли «вытеснять» бронь) и что считается подтверждением: запись в системе или фактическое занятие комнаты.
Если вы делаете такой сервис в TakProsto, удобно описать правила простым текстом и попросить AI реализовать их как единые проверки перед сохранением брони. Тогда одинаковая логика будет работать и в интерфейсе, и на сервере.
Начните с простой модели данных. Она должна отвечать на три вопроса: кто бронирует, что именно бронируют и на какое время.
Базовых сущностей обычно достаточно четыре: переговорная, пользователь, роль и бронь. Переговорная описывает ресурс (комната), пользователь - человека, роль - уровень прав, а бронь - конкретный интервал времени.
Для переговорной чаще всего хватает названия, локации (офис, этаж), вместимости и пары признаков вроде «есть телевизор» или «подходит для звонков». Эти поля помогают фильтровать комнаты, но не усложняют логику.
Бронь - главный объект, и у нее должны быть поля, которые однозначно задают интервал и ответственность: переговорная_id, начало, конец, статус, автор_id. Полезно сразу добавить время создания и обновления, а также короткое описание, чтобы люди понимали, почему комната занята.
Статусы лучше держать простыми: «черновик» (еще не заняли слот окончательно), «подтверждено» (участвует в проверке конфликтов) и «отменено» (для истории и разборов). Если нужна модерация, позже можно добавить «на согласовании».
Функции вроде повторов, приглашенных, тегов и расширенного описания часто хотят «сразу», но они быстро усложняют конфликты и права. Практичнее сделать их необязательными полями или отдельными таблицами, а в MVP оставить только то, что влияет на правила. Например, приглашенных сначала можно хранить как список без влияния на доступ.
Роли стоит хранить явно (role_id у пользователя или связь многие-ко-многим, если у человека несколько ролей). Тогда правила по ролям проще реализовать и тестировать.
Роли лучше определить до первой строки кода. Иначе правила начнут появляться «по ходу», а это почти всегда ломает логику конфликтов и уведомлений.
Базовый набор обычно выглядит так: сотрудник, руководитель, офис-менеджер и админ. Разница между ними не в «статусе», а в разрешенных действиях и в том, как система ведет себя в спорных случаях.
Обычно ограничения нужны вокруг пяти действий: создание брони (например, только в рабочие часы и в пределах длительности), перенос (например, запрет за 15 минут до начала), отмена (например, запрет отмены чужих встреч), бронирование «особых» комнат (только руководителям) и приоритетные брони (только офис-менеджеру или админу).
Кроме прав пользователя, полезны правила на уровне комнаты. Одна переговорная может быть «общей», другая - только для встреч с клиентами, третья - для руководства. Если это не заложить сразу, люди начнут обходить ограничения, бронируя «хоть что-то».
Исключения тоже нужны, но в ограниченном виде: приоритетная бронь, ручное подтверждение, экстренная блокировка комнаты на обслуживание. Важно, чтобы каждое исключение оставляло след: кто сделал, когда и почему. Если вы собираете это в TakProsto, попросите заранее заложить журнал действий и понятные причины для ручных решений.
Пример: сотрудник бронирует «Клиентскую» на 60 минут, но у комнаты стоит правило «только по подтверждению». Система создает заявку, удерживает слот на время, и снимает бронь, если офис-менеджер не подтвердил вовремя.
Если не зафиксировать базовые ограничения, споры начнутся уже на первой неделе: кто-то забронирует переговорку на ночь, кто-то поставит встречу на 5 минут, а кто-то займет комнату «навсегда» серией броней. Правила времени лучше решить до интерфейса и до кода.
Начните с расписания. У каждой комнаты может быть свой режим: например, 09:00-19:00 по будням, а по выходным брони запрещены. Если нужны исключения (праздники, корпоратив), их лучше хранить отдельными датами, а не менять расписание задним числом.
Дальше задайте длительности. Минимум защищает от «микроброней», максимум - от захвата ресурса на полдня. Сразу договоритесь о минимальной длительности (например, 15 или 30 минут), максимальной (например, 2 часа, или 4 по правилам офиса) и шаге времени (например, 15 минут), чтобы календарь был понятным.
Буфер до и после встречи снижает конфликты «на стыке»: людям нужно время на подготовку, уборку, проветривание. Буфер должен участвовать в проверке конфликтов так же, как и сама встреча. Пример: встреча 10:00-11:00 с буфером 10 минут означает занятость комнаты 09:50-11:10.
Окно планирования отвечает на вопрос, на сколько дней вперед можно бронировать. Типичный вариант - 14 или 30 дней. Это не дает «забронировать все лето».
Еще одно ограничение, которое быстро окупается: лимит активных броней на человека. Например, не больше 3 будущих бронирований одновременно. Так вы защищаете календарь от ситуации, когда один сотрудник держит запасные слоты «на всякий случай».
Конфликт - это ситуация, когда новая бронь делает невозможной уже существующую или нарушает правила комнаты. Важно считать конфликтом не только «чистое» пересечение встреч, но и пересечение с учетом буферов.
У каждой брони есть интервал [start, end) и буфер до и после, например 10 минут. Для проверки берите «расширенный» интервал: start - buffer_before и end + buffer_after. Конфликт есть, если расширенный интервал пересекается с расширенным интервалом другой брони в той же переговорной.
Проверка сводится к простой логике: пересечение есть, если new_start < existing_end и new_end > existing_start (после учета буферов). Встречи «ровно встык» не конфликтуют, если new_start == existing_end, и буферы не превращают это в пересечение. Переход через полночь не должен быть «особым случаем»: храните время как точные даты-время.
Черновики и отмены отделяйте по статусам. Обычно в конфликтных проверках участвуют только подтвержденные брони. Черновики можно игнорировать или учитывать мягко (например, предупреждать, но не блокировать). Отмененные и завершенные встречи исключайте из проверок.
Если по ролям кто-то может перебить бронь (например, администратор), это не отменяет конфликт, а меняет исход. Система фиксирует пересечение, но разрешает действие и оставляет след.
Пользователю полезно отвечать конкретно: причина отказа («занято с 14:00 до 15:30 плюс буфер 10 минут»), ближайшие доступные слоты и, если бронь перебили, кто и когда изменил запись, что произошло с исходной встречей.
Отдельно решите вопрос часовых поясов: храните время в базе в UTC, а показывайте в локальном часовом поясе офиса. Иначе «призрачные конфликты» появятся при смене зоны или переходах времени.
Сервис живет не в красивом календаре, а в трех действиях: создать бронь, перенести, отменить. Если эти сценарии продуманы заранее, споров становится меньше, а правила проверяются автоматически.
Пользователь выбирает комнату, дату и время, добавляет тему и участников. До сохранения система обязана прогнать проверку: доступна ли комната, не нарушены ли ограничения по длительности, рабочим часам и буферам. Если есть конфликт, покажите понятную причину (например, «занято с 14:00 до 14:30» или «нужен буфер 10 минут после предыдущей встречи»), а не просто «ошибка».
Перенос почти всегда сложнее создания. Пользователь ожидает, что встреча «съедет» как в календаре, но система должна повторно проверить все правила, как будто это новая бронь. Важно заранее решить, что можно менять без новых согласований: только время или еще комнату и участников. Если бронь уже началась, обычно разрешают менять описание, а не время.
Отмена должна учитывать роли. Автор встречи отменяет свою бронь, а администратор помещения может отменять любые, если комната закрыта. Для техперерывов и уборки удобнее отдельный тип события: «блокировка слота». Она перекрывает обычные брони и видна всем.
Уведомления лучше держать минимальными, чтобы не шуметь: автору - создание, перенос, отмена (с причиной); участникам - перенос и отмена; администратору - конфликты, массовые отмены, блокировки; всем - только если закрыта комната или изменены правила.
Если вы собираете это в TakProsto, опишите сценарии в одном месте и попросите AI реализовать проверки одинаково для создания, переноса и отмены.
Чтобы AI реально помог, ему нужны четкие рамки. Сначала выпишите требования простыми словами: какие есть роли, что каждой роли можно делать, какие лимиты по времени действуют и какие буферы нужны до и после встречи.
Полезный прием - сразу зафиксировать решение при конфликте. Например: «показывать ошибку и ближайшие свободные слоты» или «ставить в лист ожидания, если роль = admin». Без этого легко получить расплывчатую логику.
Вот пример промпта, который удобно вставить в TakProsto и уточнить под свой офис:
Ты аналитик и разработчик. Спроектируй правила бронирования переговорных.
1) Роли:
- employee: может бронировать только в рабочее время, максимум 2 часа, не раньше чем за 14 дней.
- assistant: может бронировать для других, максимум 4 часа.
- admin: может создавать исключения и обходить лимиты.
2) Ограничения времени:
- рабочие часы: 09:00-19:00
- минимальная длительность: 15 минут
- шаг времени: 5 минут
- буфер: 10 минут до и 10 минут после каждой встречи
3) Конфликты:
- запрети пересечения по одной переговорной с учетом буферов
- учти перенос и отмену
- опиши алгоритм проверки конфликтов простыми шагами
4) Реализация:
- предложи структуру таблиц PostgreSQL
- опиши серверные проверки (валидации) при create/update
5) Тест-кейсы:
- пересечение в середине, касание границ, буферы, перенос на занятое время
- разные роли и исключения админа
6) Поведение при конфликте:
- возвращай ошибку с причиной
- предложи 3 ближайших альтернативных слота
Если есть особые случаи (например, «большая переговорная доступна только руководителям» или «в пятницу сокращенный день»), добавьте их отдельным блоком «Исключения». Чем конкретнее вход, тем меньше сюрпризов в логике и в UI.
Собирайте приложение от того, что видит человек, к тому, что гарантирует система. Так проще не потерять правила и быстрее заметить места, где появятся накладки.
Начните с базового потока и добавляйте защиту слоями. Сначала экран списка переговорных и календарь на день и неделю: в ячейках показывайте занятость и тему встречи, а по клику - кто забронировал и на сколько. Затем форма бронирования с подсказками: допустимая длительность, рабочие часы, шаг времени, буфер до и после.
Дальше - серверная проверка конфликтов до сохранения. Клиентские проверки полезны, но только сервер может честно решить спор, если два человека нажали «Забронировать» почти одновременно.
Храните данные в PostgreSQL и обеспечьте быстрый поиск пересечений. Держите время начала и конца, комнату, автора и статус. Индекс по комнате и времени резко ускорит проверку.
И обязательно защититесь от параллельных запросов, чтобы не было двойных броней. Используйте транзакцию: сначала проверка, затем запись. Если в момент записи кто-то успел занять слот, возвращайте понятную ошибку и предлагайте ближайшие варианты.
Отдельно добавьте простую админку: роли, лимиты (например, максимум длительности и число активных броней), буферы и рабочие часы для каждой комнаты.
Если делаете это в TakProsto, удобно разнести работу по слоям: интерфейс на React, сервер на Go и базу на PostgreSQL, а правила хранить так, чтобы админ мог менять их без релиза.
Самая частая причина споров вокруг календаря переговорных - не «плохие пользователи», а мелкие недоговоренности в правилах. Они всплывают в первый же день, когда два человека пытаются занять одну комнату, а система дает разный результат в разных местах.
Если пересечения проверяются только в браузере, достаточно открыть две вкладки или поймать задержку сети, чтобы получить двойную бронь. Правило простое: окончательное решение всегда принимает сервер, а интерфейс лишь подсказывает заранее.
Еще одна ловушка - забыть про параллельные действия. Две заявки могут прилететь «в одну секунду». Нужны атомарные операции на сервере: либо бронь создалась, либо вернулась понятная ошибка о конфликте.
Буферы времени между встречами часто считают «приятным дополнением» и не включают в проверку пересечений. В итоге встреча в 10:00-11:00 и следующая в 11:00 формально не конфликтуют, но реально люди не успевают выйти и зайти. Буфер должен участвовать в расчетах так же, как и само время встречи.
Еще одна ошибка - размазать правила по ролям по разным кускам кода. Сегодня администратор может бронировать на 4 часа, завтра - на 6, и правки превращаются в «найди и замени». Лучше держать роли и ограничения в понятных настройках (пусть даже в базе), а код сделать проверяющим эти правила.
Наконец, не экономьте на тексте ошибок. Вместо «Ошибка 409» человеку нужны причина и подсказка: «Комната занята с 10:30 до 11:30. Попробуйте 11:45 или выберите другую переговорную».
Перед тем как писать код, договоритесь о правилах на уровне офиса. Это занимает час, но экономит недели споров и переделок.
У вас должны быть ответы на базовые вопросы: кто может бронировать, когда переговорная считается доступной и что происходит при пересечениях.
Проверьте по пунктам: роли и права утверждены; время задано явно (рабочие часы, минимальная и максимальная длительность, шаг времени и окно планирования); буферы согласованы; правила конфликтов описаны словами (пересечение, буфер, блокировка, приоритеты); есть набор тестов из 10-15 коротких сценариев с датами и ролями (перенос, отмена, пересечение на 5 минут, буфер нарушен, админ правит чужую бронь).
Отдельно решите, как вы будете менять правила без переписывания логики. Хороший минимум: хранить настройки (рабочие часы, буфер, лимиты, окно планирования) в базе и версионировать их, чтобы старые брони не «сломались».
Если вы используете TakProsto, удобно сначала описать правила простым текстом, затем попросить AI реализовать проверку конфликтов и покрыть ее вашими сценариями.
В офисе есть 3 переговорные: «Север», «Юг» и «Стекло». Две команды живут в календаре: продуктовая проводит синки по 60 минут, а продажники любят разборы на 2-3 часа.
Чтобы сервис бронирования не превращался в чат с криками, заранее вводят простые правила. Обычный сотрудник может бронировать от 30 минут до 2 часов. Менеджер может ставить встречу до 3 часов, но только в «Север» или «Юг», потому что «Стекло» часто нужно для звонков с клиентами.
Дальше добавляют буферы: 10 минут до и 10 минут после каждой встречи. Это не роскошь, а время на смену людей, проветривание и подготовку. Плюс у «Стекла» есть техперерыв 30 минут раз в день, например в 12:00, чтобы подключить оборудование и проверить звук.
Проблема возникает в среду: менеджер переносит встречу с 15:00 на 14:00. Раньше слот был свободен, но после буферов и техперерыва «Стекло» недоступно, а в «Севере» уже стоит синк другой команды.
Система должна отказать не молча, а по-человечески объяснить причину и предложить варианты. Например: конфликт с буфером после встречи в «Севере» до 14:10; «Стекло» закрыто на техперерыв с 12:00 до 12:30 и занято позже; по вашей роли доступно 3 часа, но только в «Север» или «Юг». И сразу показать альтернативы: «Юг» в 14:30 на 2 часа, «Север» в 15:10 на 3 часа, или разделить встречу на 2 слота.
Сначала соберите требования в одном месте. Достаточно короткого документа на 1-2 страницы: роли, правила, буферы, исключения и что делать при конфликте.
Дальше важный принцип: правила должны настраиваться, а не быть «зашитыми» в одном куске кода. Даже в MVP заложите место, где можно поменять буфер, разрешенную длительность встречи или права ролей без переписывания логики. Обычно это отдельная таблица настроек или простой конфиг с понятными параметрами.
Чтобы быстро проверить идею, начните с узкого MVP: одна локация и 3-5 переговорных, базовые роли (сотрудник, ассистент, админ), 2-3 ограничения (рабочие часы, буфер между встречами, максимум длительности) и один главный сценарий - создать бронь и увидеть понятное предупреждение о конфликте.
Если хочется ускориться без ручной сборки каркаса, TakProsto (takprosto.ai) помогает собрать веб, сервер и базу в формате «чата с задачей», а затем спокойно докрутить правила и UX. Это особенно удобно, когда нужно быстро показать рабочий прототип офису и проверить реальные сценарии за неделю.
План запуска простой: выделите тестовую неделю, заранее назначьте «хозяина правил» (кто принимает решения), соберите 10-15 реальных кейсов и в конце недели внесите правки. Часто выясняется, что 10 минут буфера мало для переговорной на другом этаже, а роль ассистента должна уметь переносить бронь без отмены.
Начните с фиксированных правил: рабочие часы, минимальная и максимальная длительность, шаг времени, буферы до/после и окно планирования. Если это не согласовать заранее, почти каждую неделю будут «исключения», которые потом сложно автоматизировать.
Буфер должен участвовать в конфликте так же, как время встречи. Практичное правило: при проверке расширяйте интервал до start - buffer_before и end + buffer_after, иначе получите «встык» встречи, где люди физически не успевают смениться.
Держите базу простой: переговорная, пользователь (с ролью) и бронь. Для брони достаточно room_id, author_id, start_at, end_at, status, created_at, updated_at и короткой темы, чтобы было понятно, почему комната занята.
Минимум ролей обычно закрывает 90% споров: сотрудник создает и отменяет свои брони, руководитель получает расширенные лимиты, офис-менеджер подтверждает или управляет «особыми» комнатами, админ может делать исключения. Важно заранее решить, кто имеет право переносить чужую бронь и за сколько минут до начала это запрещено.
Используйте правило пересечения интервалов: конфликт есть, если new_start < existing_end и new_end > existing_start в рамках одной переговорной, при этом берите времена уже с учетом буферов. Встык без пересечения считается нормой только если буферы не превращают стык в overlap.
Проверки в интерфейсе полезны только как подсказка, но окончательное решение должен принимать сервер. Иначе два человека могут нажать «Забронировать» одновременно в разных вкладках, и вы получите двойную бронь.
Делайте проверку и запись в одной транзакции: сначала ищете пересечения по комнате и времени, затем создаете бронь, и если в процессе кто-то занял слот, возвращаете понятную ошибку. На практике это резко снижает редкие, но самые болезненные «двойные» брони.
Храните время в базе в UTC, а показывайте в часовом поясе офиса. Тогда вы избегаете ситуаций, когда встреча визуально «съехала» и начала конфликтовать с другой из‑за разного отображения времени.
Разрешайте «перебивание» только тем ролям, которым это действительно нужно, и фиксируйте это как отдельное действие с причиной. Пользователь должен видеть, кто и когда изменил или отменил бронь, иначе конфликты перейдут из системы в личные чаты.
Сделайте настройки отдельными данными: рабочие часы, буфер, лимиты длительности, окно планирования и ограничения по ролям. Практичный подход — версионировать изменения правил или хотя бы хранить, когда правило изменилось, чтобы не было ощущения, что «вчера можно было, а сегодня система сломалась».