записи

04

Записи — вторая причина носить его с собой

Всё подтверждается автоматически, если кто-то не наложит вето до дедлайна. Это единственное место в продукте, где отсутствие за столом имеет цену — и где телефон её снимает. Вкладки переименованы: Ожидают и Утверждены.

9:41
Записи
АГ
Ожидают 2
Утверждены
Клиенты
Всё подтверждается автоматически.
12:30
27.09
Анна Ковалёва
Стрижка · 60 мин
через 3 ч
10:00
01.10
+7 ··· ·· 08
Окрашивание · 180 мин
через 26 ч
15:00
01.10
Дмитрий Соловьёв
Мужская стрижка · 30 мин
через 31 ч
Одна очередь на все календари. Здесь нет «моих» записей.
26-163 · перерисован /calendar/waiting · вкладка «В ожидании» → «Ожидают»

Тот же язык строк, что у «Утверждены»: время и дата в ведущей колонке, имя клиента жирным, услуга и длительность подписью. Справа — сколько осталось до автоподтверждения, потому что очередь отсортирована именно по этому и это единственное, что здесь читают бегло. Тап по строке открывает детальную запись (следующий экран). Показывается при calendar:configure или любом из booking:reject/cancel — тот же расширенный гейт, что и в консоли.

Имена — настоящие, и пробел закрыт. Первая версия этого экрана рисовала Услуга 01a08a02 и Мастер 01a084ec, хотя PendingBookingResponse несёт workerDisplayName и serviceName с 26-50, а имя клиента приезжает из реестра персон чата по personId — тем же display-merge, что и на «Утверждены». Когда имени нет — маскированный телефон, потом «Без имени», но никогда не шестнадцатеричный код. Идентификатор календаря на экране не показывается вовсе: это адрес для записи на сервер, а не факт для человека.

9:41
Записи
АГ
Ожидают 3
Утверждены
Клиенты
Всё подтверждается автоматически.
12:30
27.09
Анна Ковалёва
Стрижка · 60 мин
через 3 ч
10:00
01.10
+7 ··· ·· 08
Окрашивание · 180 мин
через 26 ч
Анна Ковалёва
Воскресенье, 27 сентября 2026 12:30–13:30
Подтвердится через 3 ч
УслугаСтрижка
МастерИрина Соколова
Телефон+7 ··· ·· 47
Отклонить
Отменить
Закрыть
26-163 · новый экран строка «Ожидают» → детальная запись → вето

Тот же нижний лист, что у детальной записи «Утверждены»: имя заголовком, дата слева и время справа одной строкой, «Услуга»/«Мастер»/«Телефон» строками с тонкими разделителями. «Телефон» рисуется только когда сервер его прислал — null здесь значит «нет права customer:read», а не «телефона нет», и прочерк на этом месте лгал бы.

Почему нет кнопки «Принять». Проверено по коду календаря, а не по ощущению: ConsoleEndpoints публикует для записи ровно три действия — reject, cancel, no-show. Операторского confirm нет: Event.Confirm вызывает только сборщик по дедлайну (право booking:confirm объявлено, но ни один эндпоинт его не проверяет). Очередь — список вето, а не список одобрений: «принять» — это ничего не нажимать, и лист говорит это прямо строкой «Подтвердится через 3 ч» вместо кнопки, на которую сервер не ответит. Ручное подтверждение — продуктовое решение и новый эндпоинт календаря, отдельной задачей.

Ровно два вето, и оба настоящие. Event.Reject принимает только PendingConfirmation; Event.Cancel — и PendingConfirmation, и Booked, под отдельным правом (booking:cancel против booking:reject) — поэтому оба на месте, равным весом. «Не пришёл» убран: Event.MarkNoShow принимает только Booked — неявка утверждает что-то о визите, который был подтверждён и не состоялся, и для ожидающей записи сервер отказывал на каждом нажатии. Тап по вето сначала закрывает лист, потом шлёт запрос: строка гаснет в списке, отказ сервера ложится в баннер над списком, успех перечитывает очередь — и всё это было бы скрыто за открытым листом.

9:41
Записи
АГ
Ожидают 2
Утверждены
Клиенты
Пн28
Вт29
Ср30
Чт1
Пт2
Сб3
Сентябрь 2026 Октябрь 2026
Ирина Соколова · 4 записи
10:00
Анна Ковалёва
Стрижка · 60 мин
11:15
Мария Орлова
Окрашивание · 120 мин
13:30
+7 ··· ·· 67
Без имени · Стрижка · 45 мин
15:00
Ольга Титова
Укладка · 40 мин
Пётр Ким · 1 запись
12:00
Дмитрий Соловьёв
Мужская стрижка · 30 мин
/calendar/bookings · вкладка «Утверждённые» → «Утверждены»

Консоль показывает сетку неделя × мастер — единственный layout в продукте, который принципиально широкий. Android меняет оси местами: лента дат, затем этот день, сгруппированный по мастеру. Вопрос, на который он отвечает («что на четверг»), не меняется.

Строка клиента — это имя. Оно на первом плане, услуга и длительность — подписью под ним. Имя всегда берётся как есть и не проверяется (никаких «недействительно»). Когда имени нет — маскированный телефон и пометка «Без имени», но никогда не шестнадцатеричный код (сбор имени при записи — отдельная задача; телефон обязателен всегда).

Месяц и год — липкий, сжимающийся заголовок. Текущий месяц закреплён у левого края, пока его дни в ленте, тем же приглушённым шрифтом, что и подписи строк, год у каждого месяца. Когда следующий месяц выезжает справа и начинает наезжать на закреплённую подпись, та сжимается (обрезается многоточием), пока следующий не перехватит место и сам не станет закреплённым — и так в обе стороны прокрутки. Кадр справа ловит момент передачи: «Сентябрь» ужат почти в ничто, «Октябрь» вот-вот встанет к краю.

Два значка на строке — чат и телефон (слева направо), Material-глифы, оба всегда. Чат ведёт в диалог-источник записи (один на запись), телефон — к контакту. Тап по всей строке открывает детальную запись (следующий экран).

9:41
Записи
АГ
Ожидают 2
Утверждены
Клиенты
Вт30
Ср1
Чт2
Пт3
Сб4
Вс5
Пн6
Сентябрь 2026 Октябрь 2026
Ирина Соколова · 2 записи
09:30
Елена Волкова
Стрижка · 60 мин
11:00
Наталья Зайцева
Окрашивание · 120 мин
/calendar/bookings · лента прокручена к границе месяца

Момент передачи. Тот же экран «Утверждены», прокрученный так, что дни сентября почти ушли за левый край. «Сентябрь 2026» всё ещё закреплён у края — но подъехавший справа «Октябрь 2026» сжал его до «Се…». Ещё чуть — и «Октябрь» встанет к краю и сам станет закреплённым; прокрутка назад повторит всё в обратную сторону. Поведение чисто геометрическое (первый видимый чип + его смещение), поэтому одинаково воспроизводится в обе стороны.

9:41
Запись
Анна Ковалёва
Вторник, 29 сентября 2026 10:00–11:00
УслугаСтрижка · 60 мин
МастерИрина Соколова
Телефон+7 ··· ·· 67Показать
Подтверждён по SMSда
ИсточникВиджет на сайте
Перейти к диалогу
Закрыть
строка записи → детальная запись → диалог

Тап по строке открывает запись. Дата слева, время справа — двумя выключками в одну строку, без точки между ними. «Мастер» — отдельной строкой, как «Услуга». «Источник» — простым текстом (Виджет на сайте / Telegram / Макс), без стилизованных плашек.

Телефон — за «Показать» (аудируемое раскрытие, как в треде диалога). «Перейти к диалогу» ведёт в тот самый диалог, где создана запись — связь бронь↔диалог в обе стороны: из чипа записи в диалоге — сюда, отсюда — в диалог (новые поля origin_conversation_id на брони и result_booking_id на задаче чата).

9:41
Записи
АГ
Услуги
Часы
Ожидают 2
Утверждены
Клиенты
Всё подтверждается автоматически.
Записи · сегменты → сегменты + ⋮

Сегментов не может быть больше трёх. Услуги и Часы сначала легли четвёртым и пятым сегментом — на реальном телефоне подписи стали переноситься и обрезаться, ряд физически не резиновый. Правило на будущее: операционное остаётся в сегментах, настроечное уходит за ⋮.

Разделитель простой — спроси не «часто ли этим пользуются», а «есть ли что-то срочное прямо сейчас». Ожидают/Утверждены/Клиенты — живые люди и решения с дедлайном. Услуги и Часы — словари: их читают чаще, чем правят, и ничего не «горит», если зайти туда на день позже.

Открывает то же самое: пункт меню ведёт на уже существующий экран (Услуги/Часы) без изменений внутри него — переезжает только точка входа. Тот же приём годится для любой вкладки, которая начинает разъезжаться: прежде чем резать текст или уменьшать шрифт, спроси, не пора ли часть сегментов сделать пунктами ⋮.

9:41
Запись
Мария Орлова
Вторник, 29 сентября 2026 11:15–13:15
Подтвердится через 3 ч
УслугаОкрашивание · 120 мин
МастерИрина Соколова
Телефон+7 9•• ••• •• 08Показать
Подтвердить
Отклонить
Закрыть
строка «Ожидают» → детальная запись

Ожидают: Подтвердить + Отклонить. «Отменить» убрана — на строке, которая сама подтвердится, если её не тронуть, осмысленное отрицание — это вето (Reject), а не отмена подтверждённого визита. «Подтвердить» — главное действие, «Отклонить» — вторичное.

«Подтвердить» — это ранний ручной коммит того же перехода, что делает автосвип (Event.Confirm: PendingConfirmation→Booked). Домен уже так умеет: Event.Confirm намеренно не проверяет дедлайн, потому что и свип, и оператор — законные вызывающие. Не хватает только эндпоинта POST /bookings/{id}/confirm и use case; право booking:confirm уже объявлено и уже выдано роли «Оператор», но пока никем не потребляется.

Строка «Подтвердится через N ч» остаётся — это правда об автоподтверждении: если никто не нажал, свип подтвердит запись на дедлайне. Ручное подтверждение просто делает это раньше и снимает дедлайн; автосвип остаётся резервом.

9:41
Запись
Анна Ковалёва
Четверг, 1 октября 2026 10:00–11:00
УслугаСтрижка · 60 мин
МастерИрина Соколова
Телефон+7 ··· ·· 67Показать
ИсточникВиджет на сайте
Открыть диалог
Перенести
Отменить
Закрыть
строка «Утверждены» → детальная запись (визит впереди)

Утверждены: добавлены «Перенести» и «Отменить». «Открыть диалог» и «Закрыть» остаются. «Отменить» — опасный тон (Booked→Cancelled, CancelledByOperator).

«Не пришёл» здесь не показана — визит ещё не состоялся. Event.MarkNoShow отказывает до конца слота, поэтому кнопка появляется только когда now ≥ EndsAt (следующий экран). Тот же урок, что 26-163 применил к очереди: не предлагать действие там, где сервер его отклонит.

Перенос — отдельное право (booking:reschedule, по аргументу гранулярности adr/0016) либо, как запасной вариант, по booking:cancel — решение автора. Новое право стоит парной строки в каталоге ago-chat и в сид-роли «Оператор» (adr/0093).

9:41
Запись
Дмитрий Соловьёв
Сегодня, 26 сентября 2026 12:00–12:30
Визит уже прошёл
УслугаМужская стрижка · 30 мин
МастерПётр Ким
Телефон+7 ··· ·· 31Показать
Не пришёл
Отменить
Закрыть
строка «Утверждены» → детальная запись (визит прошёл)

«Не пришёл» появляется только после конца слота. Тот же экран, но now ≥ EndsAt: кнопка «Не пришёл» (Booked→NoShow) теперь доступна. «Перенести» на прошедшем визите не показывается — двигать уже состоявшееся время бессмысленно; перенос — только для будущих записей.

Это — настоящее прибытие «Не пришёл» на Android: markNoShow есть в API-слое, но ни один экран его сегодня не вызывает (в WorkerSlotsScreen «Неявка» — только ярлык статуса). Консоль же предлагает «Не пришёл» на очереди «Ожидают», где сервер его отклоняет — это тоже чинится (перенести на подтверждённые).

9:41
Перенести записьАнна Ковалёва · Стрижка · 60 мин
Сейчас: Чт 1 окт, 10:00–11:00, мастер Ирина Соколова. Выберите новое время у того же мастера — услуга и длительность те же.
Чт1
Пт2
Сб3
Вс4
Пн5
Вт6
Пт 2 октября · свободно
09:00
09:30
14:00
14:30
16:00
16:30
Достаточно ли подряд идущих слотов, решает сервер в момент записи — свободность нового времени проверяется тем же compare-and-set внутри транзакции (правило 8), не предчтением.
«Перенести» → выбор нового времени

Набросок флоу переноса. Та же лента дат, что и на «Утверждены», но показывает свободные времена того же мастера. Выбор одного времени включает «Далее». В v1 — только время: тот же мастер, та же услуга (длина прогона не меняется). Другой мастер/услуга — это «отменить и записать заново», отдельная задача.

Перенос в этой модели данных — это отпустить старый прогон и заявить новый. Строка тут — это и слот, и запись; переезда «на месте» нет (целевое время — уже свои Available-строки; возврата в Available у старых строк нет намеренно). Поэтому перенос = отмена старого прогона + атомарный клейм нового, в одной транзакции. Это предмет предлагаемого ADR.

9:41
Перенести записьПодтверждение
Анна Ковалёва · Стрижка
БылоЧт 1 окт, 10:00–11:00
СтанетПт 2 окт, 14:00–15:00
МастерИрина Соколова
Старое время освобождается (перекрытие с него снимается) и по текущим правилам продукта заново клиентам не предлагается — как и при обычной отмене. Клиенту уйдёт уведомление, когда появится рассылка (20-05).
Если новое время займут за эту секунду — перенос не состоится, а старая запись останется как была. Ничего не «повиснет» между двумя временами.
выбор времени → подтверждение переноса

Было → станет, одной парой. Новый прогон приземляется сразу в Booked: оператор, переносящий запись, и есть подтверждающий — нового окна вето нет (как и у ручного «Подтвердить»).

Атомарность названа вслух. Если целевое время займут в гонке — вся транзакция откатывается, старая запись цела. Свободный старый слот заново не открывается (наследуется от текущей отмены); стоит ли открывать — отдельное стоячее решение, оно касается и обычной отмены.

05

Конфигурация записей — флоу, которого в консоли нет

Шесть фактов решают, может ли незнакомец записаться. Сервер считает все шесть одним запросом (GET /booking-readiness) — и это цепочка зависимостей: каждый следующий пункт бессмысленен, пока не выполнен предыдущий. Консоль разносит эти шесть по пяти маршрутам и показывает сам список как пассивную панель на двух из них. Здесь цепочка — это и есть навигация.

Что именно сломано в консоли, и это проверяемо

  • «Расписание» называет две разные вещи. Пункт меню «Расписание» — это /calendar/schedule, исключения: выходной и короткий день. Кнопка «Расписание» в карточке мастера — это генерирующий шаблон: недельный или цикл, длина слота, перерыв, горизонт. Одно слово, две несвязанные поверхности — и у второй, той самой, которая и производит слоты, вообще нет собственного адреса.
  • «Когда работает мастер» отвечается на двух экранах. Рабочие часы — форма на /calendar/setup. Шаблон графика — секция карточки на /calendar/masters. Оба обязательны (пункты 4 и 5 цепочки), и ни один не упоминает другой.
  • Причина и следствие в трёх экранах друг от друга. Шаблон правится в карточке, его результат виден только в /masters/:id/slots, а починка уже нарезанных дней — четвёртый экран, /recut. На экране, где правят, не видно, что получилось.
  • Услугу нельзя исправить. calendarApi.ts экспортирует createService и ничего больше для этого типа: услуга с неверной длительностью не правится нигде в продукте. Названо здесь, а не обойдено.
9:41
Конфигурация записей
Основной календарь Нельзя записаться
1Календарь опубликован
2На календаре есть активный мастерИрина Соколова, Пётр Ким
3Мастер оказывает услугу4 услуги у Ирины, 2 у Петра
4Заданы рабочие часы или циклУ Петра Кима не заданы — без этого график нечего материализоватьИсправить →
5График сохранёнЖдёт пункта 4
6Слоты сгенерированы в горизонтеЖдёт пункта 5
Справочники
Календари
1 · опубликован
Мастера
2 активных
Услуги
6 · правка пока не поддержана сервером
Остальное
Исключения: выходной и короткий день
Разрешённые источники страницы
GET /booking-readiness · собирает /calendar/setup, /masters, /services, /schedule

Заголовок экрана — это буквально вопрос, который задаёт себе тенант, и он уже есть в консоли как строка: «Может ли клиент записаться прямо сейчас?». Разница в том, что здесь это экран, а не панель на другом экране.

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

Справочники доступны и плоским списком ниже — для того, кто пришёл переименовать услугу, а не выяснять, почему никто не записывается. Цепочка — это ответ на вопрос «почему не работает», а не мастер-визард, через который надо проходить.

9:41
Пётр Киммастер · 1e5b7d44
1 · Кто
Ким Пётр Андреевич
Отображается как «Пётр Ким» · активен
2 · Где
Основной календарь
Europe/Moscow · у мастера ровно один календарь
3 · Что делает
Мужская стрижка
Бритьё
+ услуга
4 · Когда работает
Рабочие часы не заданы
Пока их нет, графику нечего нарезать — и записаться к этому мастеру нельзя.
Задать часы
График мастера
Не сохранён · недельный или цикл, длина слота, горизонт
5 · Что получилось
Слотов нет: ни часов, ни графика. Появятся здесь сразу после сохранения.
/calendar/masters · + рабочие часы, переехавшие с /calendar/setup

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

Пятая секция отвечает на «а что получилось» прямо здесь, а не через два экрана.

9:41
График мастераИрина Соколова
Недельный (обычная неделя)
«2 через 2» и «сутки через трое» — это шаблон «Цикл», а не недельный.
30
10
Перерывы внутри длинной записи считаются рабочим временем
При таких числах: услуга 70 мин займёт 2 слота.
30
Ограничено 180 днями.
Что получится
Горизонт покрывает 30 дней, из них рабочих 22.
Около 16 слотов в рабочий день, всего ≈352.
Смотреть слоты
Дни, нарезанные по старому шаблону, сами не изменятся. Пересчитать расписание → — там видно, что будет удалено, прежде чем это произойдёт.
WorkerScheduleSection — секция карточки в консоли, без своего адреса

Консоль уже считает арифметическую фразу («услуга 70 мин займёт N слотов», зеркало серверного ComputeSlotsNeeded) — она сохранена дословно. Добавлены две цифры, которые тенант на самом деле хочет видеть: сколько дней покрывает горизонт и сколько слотов выходит в день. Читаются после сохранения, на этом же экране, со ссылкой прямо в нарезанные слоты.

Слово «Расписание» здесь не используется вообще: этот экран — График мастера, а экран выходных и коротких дней — Исключения. Двусмысленности, которую они заменяют, в консоли ровно столько, что её хватило, чтобы заполнять всё «как-то».

9:41
Пересчёт расписанияШаг 2 из 3 · решение по каждой записи
С 24 апреля будет перенарезано 18 дней. В них попали 7 записей — по каждой нужно решение.
Чт 24 апр, 10:00 · Стрижка
Сова · Клубника 7c4e18f0 · +7 9•• ••• •• 47 Показать
Отменить
Оставить
Чт 24 апр, 14:00 · Окрашивание
Анна К. · +7 9•• ••• •• 08 Показать
Отменить
Оставлена
Пт 25 апр, 11:00 · Укладка
Коала · Авокадо d6081bba · +7 9•• ••• •• 31 Показать
Отменить
Оставить
/calendar/masters/:workerId/recut · шаг 2

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

Карточка на запись, а не строка: смысл этого шага в том, что каждая запись — это чей-то визит. Кнопки «применить ко всем» здесь нет намеренно.

Шаг нельзя оставить наполовину. Счётчик «решено 4 из 7» закреплён внизу, и «Далее» не активна, пока хоть одна запись без решения. Консоль полагается на то, что оператор прокрутит таблицу и заметит; телефон так не может, поэтому счёт назван вслух.

9:41
Пересчёт расписанияШаг 3 из 3 · подтверждение
Это действие нельзя отменить
Слоты с 24 апреля будут удалены и нарезаны заново по текущему графику. Отменённые записи получат отмену; клиентам уйдут уведомления по обычным правилам.
Что произойдёт
Дней перенарезано18
Слотов удалено214
Слотов будет создано252
Записей отменено3
Записей сохранено4
Будут отменены
Чт 24 апр, 10:00 · Стрижка · Сова · Клубника 7c4e18f0
Пт 25 апр, 11:00 · Укладка · Коала · Авокадо d6081bba
Сб 26 апр, 09:30 · Бритьё · Сергей В.
/calendar/masters/:workerId/recut · шаг 3

Отменённые записи перечислены поимённо, а не сосчитаны — число «3» ничего не стоит, три конкретных визита стоят. Подтверждающая кнопка называет своё последствие в собственном тексте и остаётся единственной кнопкой опасного тона во всём флоу.

Диалога нет: подтверждение — вторая панель, а не модалка. Это собственная форма подтверждения, уже принятая в консоли (удаление мастера, стирание диалога), и она же здесь.