# 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 внутри основной кнопки вкладки | Непредсказуемая семантика клавиатуры/скринридера, сложные маленькие цели | Делать соседние `