Files
houseplan-card/docs/PRODUCT-IMPROVEMENT-PLAN.ru.md
T

48 KiB
Raw Blame History

House Plan — продуктовый аудит и план улучшений

Срез: v1.60.0, 7 августа 2026. Документ основан на чтении исходников, локальном проходе главных пользовательских сценариев и проверке фактических состояний интерфейса. Для принятых задач в нём также фиксируется актуальный статус реализации.

1. Краткая оценка

House Plan уже вышел за рамки «карточки с картинкой»: это полноценный визуальный редактор с собственной моделью геометрии, живыми состояниями, светом, солнцем, файлами и совместным хранением. Сильная сторона продукта — редкая глубина моделирования дома внутри Home Assistant. Основной риск теперь не недостаток функций, а их накопление без достаточно явной информационной архитектуры.

Текущая картина:

Область Оценка Почему
Пользовательская ценность Высокая План объединяет контроль, визуализацию, геометрию и контекст дома
Целостность визуальной модели Выше средней Единые статусы устройств, толстые стены, проёмы, Glow и солнце уже согласованы
Осваиваемость Средняя/низкая Скрытые жесты, длинные диалоги, контекстные действия и отсутствие встроенной легенды
Предсказуемость редактирования Выше средней Delete разделён на однозначные действия, геометрия получила общий Undo/Redo и обязательную сетку; незамкнутый контур пока теряется
Доступность Ниже средней Hover-зависимые данные, icon-only действия, нет полноценной семантики/фокус-менеджмента диалогов
Поддерживаемость кода Низкая houseplan-card.ts — 10 932 строки, styles.ts — 2 457 строк, в TypeScript около 429 употреблений any
Документационная целостность Низкая до этого аудита Старый README содержит поведение, уже не соответствующее коду; инженерные документы фрагментированы

Главная рекомендация: на ближайшем цикле не расширять поверхность настроек. Сначала сделать существующую систему объяснимой, обратимой и модульной.

2. Принципы целевой системы

Принцип Практическое правило
Один термин — одно действие «Стены» не должно означать только создание комнаты; «Удалить» не должно одновременно закрывать виртуальную стену, объединять комнаты и удалять комнату
Опасное действие видно заранее До потери геометрии показывать конкретный результат, а не только общий confirm
Настройка живёт на правильном уровне Глобальное, пространство, комната и устройство должны иметь одинаковую, явно показанную иерархию наследования
Состояние объяснимо Любой цвет, кольцо и смена иконки имеют встроенную легенду/предпросмотр
Touch не хуже desktop Всё, что доступно по hover/right click, имеет тап-эквивалент
Единый сеточный инвариант Все позиционные координаты создаются на сетке; legacy/import между узлами явно исправляет «Оптимизировать планы»
Изменение обратимо Редакторы используют общую историю команд, а не разрозненные локальные Undo
Модель и UI типизированы одной схемой Опция не может существовать только в форме, только в типе или только в backend validation

3. Нелогичные и рискованные функции

Приоритеты:

  • P0 — риск потери данных, опасного управления или блокировки основного сценария;
  • P1 — заметная логическая ошибка или регулярная пользовательская ловушка;
  • P2 — перегрузка, непоследовательность и трудная осваиваемость;
  • P3 — косметика, долг совместимости и внутренняя чистота.

3.1 Редактирование и геометрия

ID Приоритет Наблюдение Пользовательский эффект Рекомендация
UX-01 P0 Незамкнутый контур существует только в памяти текущего инструмента и исчезает при переключении Потеря длинной ручной работы без явного предупреждения Сохранять черновик пространства на сервере или показывать диалог «Сохранить черновик / отбросить / остаться»; в перспективе реализовать уже спроектированные свободные стены
UX-02 P1 Выполнено 2026-08-06: контекстный Delete разделён на «Закрыть проём в границе», «Объединить комнаты» и «Удалить комнату» Каждое действие имеет один заранее понятный результат Delete удаляет только явно выбранную комнату; слияние и закрытие границы не запускаются из него
UX-03 P1 Выполнено 2026-08-06: инструмент замкнутой комнаты называется «Контур комнаты» Название соответствует доступной геометрии После реализации свободных стен добавить отдельный инструмент «Стена», не возвращая неоднозначное название
UX-04 P1 Расширено 2026-08-07: Plan и Background используют общий именованный Undo/Redo Комнаты, проёмы, декор и трансформация картинки отменяются одинаково Сессионный command stack хранит 50 команд; новая операция очищает redo-ветку; Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y и кнопки работают в обеих панелях
UX-05 P1 Решение владельца 2026-08-06: координаты объектов всегда привязаны к сетке; намеренный off-grid не поддерживается Оптимизация и редакторы больше не противоречат друг другу Позиционный обход через Shift удалён. Свободные точки округляются к узлам, wall-bound объекты проецируются на стену и квантуются вдоль неё; «Оптимизировать планы» исправляет старые и импортированные данные
UX-06 P2 После UX-05 Shift не отключает сетку, но меняет геометрию жеста: квадрат/круг при рисовании, независимые оси при resize, свободный угол и шаг компаса Позиционный инвариант не нарушается; контекстные исключения требуют явной подсказки Показывать подсказку рядом с соответствующим инструментом; не использовать Shift для off-grid
UX-07 P2 Ручки комнатной карточки, локальные масштабы шрифтов и общий масштаб пространства образуют несколько перемножающихся уровней Трудно понять, почему подпись слишком большая/маленькая Оставить: общий масштаб пространства + размер названия/метрик комнаты; визуальный drag-scale либо заменить теми же числовыми полями, либо показывать итоговый коэффициент и Reset
UX-08 P2 Проём кликабелен в редакторе, но полностью инертен в просмотре; только badge замка активен Неочевидно, где увидеть контакт и параметры двери/окна, особенно без замка Одиночный клик в View открывает карточку статуса проёма; редактирование остаётся только в Plan
UX-09 P2 Выполнено вместе с UX-02: открытие участка и закрытие пунктирного участка — разные инструменты У кнопки открытия больше нет обратного скрытого действия Сохранять разные подписи, курсоры и hover-подсказки
UX-26 P1 · выполнено Background имел разные рамки/жесты для текста, мебели и картинки; линии/фигуры нельзя было трансформировать одинаково Выбор объекта давал разный набор возможностей Единый selection/transform controller: все объекты получают рамку; линия — две конечные ручки; пропорции по умолчанию, Shift — независимые оси
UX-27 P1 · выполнено Толщина, размер текста и заливка декора были в SVG-единицах/коэффициентах, прозрачность отсутствовала, заливка использовала цвет контура и фиксированные 25% Масштаб пространства менял физический смысл стиля Канонические width_cm, size_cm, opacity, fill_color, fill_opacity; cm/in для малых стилей, m/ft для геометрии; legacy читается без скачка и мигрируется оптимизатором
UX-28 P1 · выполнено Картинка была активна в Select и непрозрачна под всеми инструментами Рамка перехватывала работу с декором, изображение визуально спорило с ним Отдельный инструмент картинки; под другими инструментами opacity 0.5 и нет interaction; View/прочие редакторы 1.0; resize/rotate/numeric properties и Undo
UX-29 P2 Типы, физическая геометрия и hp-color-opacity вынесены, но orchestration Background пока остаётся в houseplan-card.ts Корневой компонент всё ещё слишком велик и связан с pointer/render жизненным циклом Следующий рефакторинг без изменения поведения: decor-editor.ts, live-text-form.ts, furniture-palette.ts; root оставляет только wiring
UX-30 P2 · отложено Пользовательские картинки декора требуют не только нового SVG-kind, но и безопасного файлового жизненного цикла Наивное добавление создаст сироты, конфликт удаления и квот Сначала спроектировать upload/reference/copy-on-write/delete/quota; DecorImageTransform уже фиксирует совместимый transform-контракт, UI не реализован

3.2 Устройства и состояния

ID Приоритет Наблюдение Пользовательский эффект Рекомендация
UX-10 P1 Карточечная настройка show_temperature управляет и температурой, и влажностью Название не соответствует результату Переименовать в «Показывать значения датчиков (° / %)»; миграция ключа не обязательна, достаточно label
UX-11 P1 «Значение вместо иконки» показывает только число и молча возвращает иконку для текстовых состояний Пользователь выбирает value, но не видит значение open/playing/home В форме показывать live preview и ограничение; в будущем поддержать локализованный текст состояния с ограничением длины
UX-12 P1 Выполнено: controls, «Это источник света» и автоматические light.* сведены в resolvedLightSources(room) Glow, заливка «Свет», карточка комнаты, маркер и групповой toggle используют один набор Сохранить единый resolver при добавлении новых световых представлений
UX-13 P1 Вероятная несогласованность: Glow clip строится по всем комнатам открытой зоны, не фильтруя локальный fill_mode: none Комната, явно исключённая из тёмной заливки, может всё равно получить световое пятно Добавить сценарный тест и фильтровать Glow-зону по эффективному roomFillModeOf; отдельно решить, должен ли свет физически заходить в opt-out комнату
UX-14 P2 Жёлтая подложка и кольцо running одновременно сообщают работу В «Иконка + активность» один смысл дублируется двумя эффектами Сохранить подложку как статус, а кольцо работы сделать более спокойным или показывать только переходы/события; дать предпросмотр
UX-15 P2 Система красный/жёлтый/оранжевый/бледный/кольцо не имеет доступной легенды в самой карточке Поведение стройное в коде, но невидимо для пользователя Кнопка «Легенда состояний» в Device editor и компактная справка в диалоге display с примерами текущего устройства
UX-16 P2 Автофильтрация скрывает устройства по эвристикам, а причина скрытия не хранится/не показывается Пользователь не понимает, почему устройство пропало «Входящие устройства»: Новые / Скрытые автоматически / Скрытые вручную, с причиной и массовыми действиями
UX-17 P2 Правила иконок — длинный список regex в no-code интерфейсе Мощно, но сложно и легко сломать приоритетом первой строки Визуальный rule builder: содержит слова / домен / device class / модель; regex оставить как «Расширенный режим»
UX-18 P2 Диалог виртуального устройства показывает настройки состояния/света, которые могут не иметь источника Лишние решения и ложные ожидания Условно скрывать неработающие секции; для виртуального маркера оставить имя, комнату, иконку, ссылку/описание/файлы и запуск сценария
UX-19 P3 Секция называется «Manuals (PDF etc.)», но принимает изображения и TXT Нечёткая модель Назвать «Файлы и инструкции», показывать разрешённые форматы и лимит 50 МБ

3.3 Комнаты, подсказки и настройки

ID Приоритет Наблюдение Пользовательский эффект Рекомендация
UX-20 P1 Площадь комнаты и часть контекста доступны по hover; touch-first код намеренно отключает hover-подсказки На планшете новая площадь фактически недоступна в View Тап по комнате открывает компактную карточку комнаты с площадью/климатом/светом; отдельная маленькая ссылка ведёт в HA-зону
UX-21 P2 Ссылка на HA-зону спрятана в маленькой иконке рядом с названием комнаты Низкая обнаруживаемость и маленькая touch-цель В карточке комнаты сделать явное действие «Открыть зону в HA»
UX-22 P2 «Скрыть двери и окна» прячет символы, но сохраняет свет, солнце и контактную анимацию Полезная, но неожиданная семантика Назвать «Скрыть только символы проёмов» и оставить текущую поясняющую строку
UX-23 P2 Пространство смешивает источник файла, масштаб, видимость, карточки комнат, цвет, фон, солнце и заливку в одном длинном диалоге Прокрутка, ошибки уровня настроек, тяжёлое повторное редактирование Разделить на вкладки «Основа», «Комнаты», «Внешний вид», «Солнце»; опасное удаление вынести в отдельную зону
UX-24 P2 Общие настройки смешивают палитру, фон/солнце, обслуживание и About Обслуживание теряется внутри визуальных настроек Три диалога/страницы: «Внешний вид», «Солнце и окружение», «Обслуживание»; About — отдельная строка/диалог
UX-25 P2 Комната не может явно выбрать Glow, только наследовать его от пространства При последующей смене режима пространства нельзя зафиксировать Glow для одной комнаты Добавить явное «Glow» или заменить radio на «Наследовать / … / Glow» с объяснением поведения

3.4 Навигация и доступность

ID Приоритет Наблюдение Пользовательский эффект Рекомендация
A11Y-01 P1 Настройка пространства и закрытие редактора — отдельные click-target внутри основной кнопки вкладки Непредсказуемая семантика клавиатуры/скринридера, сложные маленькие цели Делать соседние <button> с собственным aria-label, не click-handler на вложенном ha-icon
A11Y-02 P1 · выполнено Все модальные окна переведены на общий hp-dialog Клавиатура и скринридер получают настоящую модальную границу и заголовок HA ha-dialog + нативный fallback; реализованы trap, initial focus, Esc и restore focus, в том числе для вложенных и сменяющих друг друга окон
A11Y-03 P1 Цвет — основной канал для working/open/alarm/LQI Пользователи с нарушением цветоощущения теряют смысл Добавить формы/мини-бейджи: !, play, open; текстовые статусы в карточке и доступные aria-label
A11Y-04 P2 Часть toolbar-текста исчезает на узкой ширине, остаются title-tooltip и иконка Title недоступен на touch и плохо работает с клавиатурой aria-label, долгое нажатие/Help overlay, адаптивное overflow-меню вместо безымянных иконок
A11Y-05 P2 Киоск-настройка открывается скрытым удержанием 3 секунды Функция почти не обнаруживается Однократный onboarding/индикатор в углу и документируемая кнопка в конфигурации карточки
A11Y-06 P2 Native confirm() смешан с кастомными диалогами Разная визуальная модель и слабый контекст результата Один компонент подтверждения с названием операции, объектом, необратимостью и безопасным default focus

4. Ненужные и устаревшие функции

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

Кандидат Факт в v1.59.0-rc.1 Решение
houseplan-space-card.aspect_ratio Поле есть в GUI и типе, но render его не читает; холст квадратный Удалить из GUI сейчас; один цикл принимать в YAML без эффекта, затем убрать из публичного типа
Карточечный tap_action Помечен deprecated/ignored с v1.38.1, но остаётся в CardConfig Показывать однократное предупреждение в editor/YAML diagnostics; затем удалить тип и совместимый код
Старый display ripple («только пульсация») Уже не предлагается, читается как icon_ripple и мигрируется оптимизатором Правильное решение уже принято; после достаточного окна убрать backend-значение ripple
vacuum.room_highlight Есть только в типе и backend schema, фактического потребителя не найдено Подтвердить поиском тестов/реальных конфигов; удалить или реализовать как отдельную принятую фичу, не хранить «на всякий случай»
vacuum.segment_map Есть в типе/schema, фактического потребителя не найдено Аналогично: миграционная заметка и удаление, если телеметрия не использует
settings.show_all Legacy shared-toggle; текущая версия удаляет его после materialization Завершить миграцию и убрать write/fallback после установленного окна совместимости
settings.exclude_integrations Внутренний ключ влияет на фильтр, но публичного UI/документации нет Либо сделать поддерживаемой advanced-настройкой с причинами, либо заменить версионированными filter rules
settings.group_lights Влияет на группировку, но не виден пользователю Добавить явную настройку в Device discovery либо зафиксировать always-on и удалить ключ
Старые decor.text.entity/attr/unit/size/scale Схема принимает для миграции, новый UI их не создаёт Оставить только мигратор; после гарантированного преобразования вынести из основной модели совместимости
Старые decor.width и space.plan_scale Читаются без визуального изменения; новый UI пишет width_cm и plan_scale_x/y Мигрировать только явной операцией «Оптимизировать планы»; не менять молча при загрузке
Старый space.segments Backend уже удаляет ключ, стены выводятся из комнат Удалить остаточные ссылки из публичной архитектурной документации и тестовых фикстур после окна совместимости
Старые README-сценарии Описывают карточечный tap и исторические display-режимы Новый user guide сделать источником истины; README сократить до презентации, установки и ссылки на руководство

Что не следует убирать

Функция Почему сохранить
Явная «Иконка + активность» Позволяет пользователю выбирать степень анимации; проблема не в функции, а в отсутствии предпросмотра/легенды
Отдельная жёлтая подложка Даёт единый устойчивый сигнал работы при любой заливке комнаты
Скрыть только символы проёмов Полезно для чистого плана, если название объясняет сохранение физической семантики
Виртуальные стены Важны для зонирования открытых пространств и распространения света
Оптимизация с предпросмотром Нужна для старых и импортированных моделей; обязательная сетка применяется вместе с миграцией и нормализацией
Статическая карточка Полезна для обзорных дашбордов; нужно только очистить её API

5. Информационная архитектура настроек

5.1 Предлагаемая структура верхнего уровня

Раздел Содержимое
План Пространства, контуры, стены, виртуальные границы, проёмы
Устройства Входящие, видимые, скрытые; привязки, действия, состояния и иконки
Подложка Изображение, декор, мебель и живой текст
Внешний вид Палитры, размеры по умолчанию, заливки, стены
Окружение Фон, день/ночь, север, солнце и погода
Обслуживание Проверка модели, оптимизация по категориям, отчёт, undo, экспорт диагностики
О продукте Версия, ссылки, журнал изменений

5.2 Диалог пространства

Вкладка Поля
Основа Название, источник/файл, клетка, замена/удаление файла
Комнаты Границы, названия, карточка комнаты и её общий масштаб
Внешний вид Цвет/прозрачность, заливка, LQI, декор, проёмы
Окружение Фон, север и солнечные лучи

5.3 Диалог устройства

Вкладка Поля Условность
Привязка Имя, HA device/entity/virtual, комната, скрытие Всегда
Управление Tap action, target, confirm, controls Только доступные действия домена
Состояние Display, live preview, climate value Только при HA-привязке
Свет Source flag, controls, radius Только при возможном on/off источнике
Внешний вид Иконка, размер, поворот, activity color/size Activity поля только в соответствующем display
Пылесос Live source, calibration, trail Только для vacuum/координатной сущности
Информация Модель, ссылка, описание, вложения Всегда

Форма должна показывать итог, а не внутренние поля: рядом с Display — живой пример текущего устройства; рядом с Tap action — «При клике сейчас будет…».

6. Целевая архитектура кода

6.1 Текущие узкие места

Узкое место Доказательство Риск
Монолит карточки src/houseplan-card.ts: более 11 тысяч строк Любая правка задевает жизненный цикл, диалоги, геометрию и render одновременно
Монолит стилей src/styles.ts: 2 457 строк Трудно ограничить CSS конкретным компонентом и состоянием
Слабая типизация Около 429 any в TS Schema/UI/backend расходятся незаметно
Состояние как набор mutable fields Сотни приватных полей диалогов и drag-сессий Трудные переходы, warm remount, отмена и параллельные изменения
Разрозненная логика настроек Resolver-ы в logic.ts, render и диалогах Один источник считается по-разному в разных режимах
Две серверные записи Config и layout сохраняются отдельно Сложность атомарных операций, ревизий и undo
HTML диалоги копируются вручную menuwrap/dialogwrap во многих render-методах Нет общего focus/a11y/confirm-контракта

6.2 Предлагаемое разбиение frontend

src/
  app/
    houseplan-card.ts          # только композиция и жизненный цикл
    houseplan-store.ts         # нормализованное состояние и серверные ревизии
    command-stack.ts           # undo/redo и транзакции
    navigation-controller.ts   # space/mode/viewport/kiosk
  editors/
    plan/
      plan-editor.ts
      plan-commands.ts
      plan-toolbar.ts
    devices/
      device-editor.ts
      device-form.ts
      discovery-inbox.ts
    decor/
      decor-editor.ts
      live-text-form.ts
      furniture-palette.ts
  render/
    room-layer.ts
    wall-layer.ts
    opening-layer.ts
    glow-layer.ts
    sun-layer.ts
    device-layer.ts
    vacuum-layer.ts
  settings/
    schema.ts                  # единая типизированная модель
    resolve.ts                 # global → space → room → device
    migrations.ts
  components/
    hp-dialog.ts
    hp-confirm.ts
    hp-color-opacity.ts
    hp-entity-picker.ts
    hp-status-preview.ts

logic.ts, device-visual.ts, sun.ts, vacuum.ts, open-spans.ts и wall-thickness.ts уже показывают правильное направление: чистая доменная логика отдельно от Lit/DOM. Для Background первый этап выполнен: src/editors/decor/types.ts, geometry.ts и hp-color-opacity.ts отделяют модель, вычисления и общий контрол. Следующий этап — вынести orchestration и формы, не создавая второй набор жестов.

6.3 Command model

Каждое изменение должно описываться командой:

interface PlanCommand {
  label: string;
  apply(model: HousePlanModel): HousePlanModel;
  invert(before: HousePlanModel): PlanCommand;
  affectedSpaces: string[];
}

Примеры: AddRoom, MoveWall, SplitRoom, MergeRooms, SetWallThickness, SetOpenSpan, AddOpening, MoveDecor, MoveMarker, OptimizeModel.

Преимущества:

  • единый Undo/Redo;
  • одна транзакция config+layout;
  • точный журнал «что изменится»;
  • защита от случайного повторного применения;
  • проще синхронизировать несколько клиентов;
  • тесты проверяют команды без DOM.

6.4 Единая схема настроек

Нужно сократить тройное дублирование types.ts → форма → Voluptuous schema.

Целевой контракт:

  1. TypeScript-схема/описание поля задаёт тип, default, диапазон, видимость и миграцию.
  2. Форма строится из этой схемы либо использует экспортированный field registry.
  3. Backend validation генерируется/сверяется машинным тестом с registry.
  4. Любое compatibility-поле имеет introduced, deprecated, readUntil, migrate.
  5. Неизвестные поля сохраняются для forward compatibility, но не становятся публичными настройками автоматически.

7. Дорожная карта

Этап 0. Источник истины и очистка поверхности

Цель: перестать накапливать ложные настройки до следующего расширения.

Задача Результат
Сделать новый user guide основным README ведёт на руководство; исторические спецификации помечены как инженерные
Убрать aspect_ratio из static GUI UI больше не обещает неработающее поле
Инвентаризировать legacy/dead keys Таблица телеметрии конфигов/миграций для tap_action, ripple, room_highlight, segment_map, show_all
Добавить schema parity check Любая GUI-опция обязана читаться renderer-ом и приниматься backend-ом
Зафиксировать визуальную легенду Один behavior spec + сценарная матрица доменов

Критерий завершения: в визуальных редакторах нет поля, которое не влияет на результат; публичная документация не противоречит коду.

Этап 1. Безопасность редактирования

Задача Результат
Черновик незамкнутого контура Переключение режима не теряет работу
Разделить Delete Выполнено: результат каждого действия однозначен
Общий Undo/Redo MVP Выполнено: 50 именованных операций Plan editor обратимы
Единый сеточный инвариант Выполнено: редакторы не создают intentional off-grid; оптимизатор чинит legacy/import
Карточка комнаты по тапу Площадь и контекст доступны на touch

Критерий завершения: ни один обычный переход между инструментами не теряет данные без явного решения пользователя.

Этап 2. Информационная архитектура и доступность

Задача Результат
Новый hp-dialog Focus trap, Esc, aria, возврат фокуса и адаптивная высота едины
Разбить Space/Device/General dialogs Меньше решений на экране, условные поля
Встроить status preview/legend Display и live states понимаются до сохранения
Отдельные кнопки для cog/close Корректная клавиатурная и touch-семантика
Нецветовые признаки состояния Авария/работа/открыто читаются без цвета
Помощь по жестам Однократный overlay для углового Shift, long-press, swipe, right click alternatives

Критерий завершения: ключевые сценарии доступны клавиатурой и touch без hover/title; формы не требуют чтения внешней документации для понимания эффекта.

Этап 3. Модульный frontend

Задача Результат
Вынести render layers Комнаты, стены, openings, devices, Glow, Sun, Vacuum независимы
Вынести editor controllers Режимы становятся явными state machines
Нормализованный store Меньше прямых мутаций _curSpaceCfg и JSON deep-copy
Типизированные dialog models Удаление основной массы any
Scoped styles/components Стили принадлежат компонентам, меньше глобальных пересечений
Page objects/scenario matrix UI-тесты описывают пользовательские действия, а не внутренние методы

Критерий завершения: корневой houseplan-card.ts отвечает за композицию и имеет ориентир менее 1500–2000 строк; новая функция не требует добавлять диалог, логику и CSS в один файл.

Этап 4. Единая семантика источников и состояний

Задача Результат
resolvedLightSources Room fill, Glow, room card и marker status считают свет одинаково
resolvedDeviceVisual как публичный pure contract UI, статусы и тесты используют одну матрицу
Текстовые value states Значение вместо иконки работает с локализованными нечисловыми состояниями
Device discovery inbox Автоскрытие объяснимо и управляемо
Rule builder Regex перестаёт быть обязательным знанием

Этап 5. Свободные стены и незамкнутые контуры

Этот этап следует начинать только после command model и общей истории Undo. Уже сохранённое ТЗ на свободные стены остаётся самостоятельной продуктовой инициативой.

Первая версия должна:

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

Не стоит в тот же релиз добавлять T-ветвления, преобразование существующих комнат в свободные стены и сложную смену типа контура: это отдельные уровни сложности.

8. План проверки качества после рефакторинга

Матрицы, которые должны стать исполняемыми спецификациями

Матрица Измерения
Устройство domain × device_class × state × display × live_states × controls
Свет source type × hidden × is_light × fill mode × virtual/door connection
Стена thickness A/B × real/virtual spans × T/corner × opening × resize
Проём door/window × thin/thick wall × contact/invert × lock × hide symbols
Комната with/without area × fill override × source override × island/shared wall
Ввод mouse/touch/keyboard × view/editor/kiosk × zoom level
Миграция every deprecated field × optimize × save × reload × older client

Продуктовые метрики

Метрика Цель
Потерянные незавершённые контуры 0
Необратимые действия редактора 0, кроме явного удаления файла/пространства с подтверждением
GUI-поля без runtime consumer 0
Ключевые действия, доступные только по hover/right click 0
Ключевые цвета без альтернативного признака 0
Расхождения frontend/backend enum 0 в CI
any в новых/переписанных модулях 0, кроме изолированного HA adapter boundary
Максимальный размер feature-компонента Ориентир <800 строк; исключения обосновываются

9. Рекомендуемый ближайший пакет изменений

Если выбирать один компактный релиз без большой архитектурной перестройки, оптимальный состав такой:

  1. Удалить aspect_ratio из редактора static card.
  2. Переименовать show_temperature в UI в «Температура и влажность»/«Значения датчиков».
  3. Переименовать Стены в Контур комнаты до реализации свободных стен.
  4. Разделить контекстный Delete хотя бы на явные подтверждения с названием фактической операции.
  5. Добавить карточку комнаты по тапу с площадью и ссылкой на HA-зону.
  6. Добавить live preview трёх display-режимов в диалог устройства.
  7. Исправить/подтвердить Glow-clip для room override и унифицировать световые источники.
  8. Вынести «Обслуживание» из общих цветов в отдельный диалог.
  9. Добавить сохранение черновика контура или хотя бы блокирующее предупреждение при выходе.
  10. Начать hp-dialog и заменить им один наиболее длинный диалог как эталон.

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

10. Решение по документации

Новая структура должна быть такой:

  • корневой README — короткое позиционирование, установка, два YAML-примера и ссылки;
  • docs/USER-GUIDE.ru.md — пользовательский источник истины;
  • отдельные docs/* — инженерные спецификации механизмов;
  • CHANGELOG — только изменения релизов;
  • ADR/decisions — почему принято архитектурное решение, без повторения пользовательской инструкции;
  • автопроверка внутренних ссылок и упоминаний удалённых опций.

При изменении поведения PR/релиз не считается завершённым, пока обновлены: пользовательская таблица поведения, enum/schema parity и сценарная матрица затронутого домена.