mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 04:09:17 +00:00
docs: specify decor default style persistence (#377)
User-Visible: no Issue: #377
This commit is contained in:
@@ -0,0 +1,137 @@
|
||||
# ТЗ #377 — Персист цвета декора по умолчанию в серверный конфиг
|
||||
|
||||
- Issue: https://github.com/Matysh/houseplan-card/issues/377
|
||||
- Приоритет: P3, polish; полный трек (компатибилити-поле `settings.decor_default_style`,
|
||||
кросс-модульный путь записи — критерий §5 «без новых персистентных полей» не проходит;
|
||||
выделено из #376в по SPEC-REVIEW-376-r1 H1)
|
||||
- Ревизия: 1 (2026-08-29)
|
||||
- Продуктовое решение владельца (29.08): цвет декора по умолчанию персистится
|
||||
в серверный конфиг.
|
||||
|
||||
## Сценарий
|
||||
|
||||
Хозяин плана (персона «владелец дома», Background-редактор) подбирает под свой
|
||||
план фирменный цвет разметки — например, тёмно-красный для линий мебели-обводки —
|
||||
через пикер основного цвета в главном тулбаре (#360). Назавтра он открывает
|
||||
редактор снова, рисует новую линию — и она рисуется его тёмно-красным, а не
|
||||
заводским серо-синим. Тот же цвет видит второй редактор этого плана на другом
|
||||
устройстве.
|
||||
|
||||
## Что человек увидит до и после
|
||||
|
||||
**До**: выбранный «цвет по умолчанию» живёт до перезагрузки страницы; после неё
|
||||
новые элементы снова заводского цвета. **После**: выбранный стиль по умолчанию
|
||||
переживает перезагрузку и общий для всех, кто редактирует этот план. Ничего
|
||||
нового в UI не появляется.
|
||||
|
||||
## Проблема
|
||||
|
||||
`_decorStyle` — приватное in-memory поле карты (`houseplan-card.ts:984`,
|
||||
`{ ...DEFAULT_DECOR_STYLE }`). Ни конфиг, ни браузерное хранилище не задействованы:
|
||||
перезагрузка страницы молча выбрасывает выбор пользователя. Название #360
|
||||
(«цвет по умолчанию») обещает большее.
|
||||
|
||||
## Скоуп
|
||||
|
||||
- Новый опциональный ключ `settings.decor_default_style` в серверном конфиге.
|
||||
- Чтение при инициализации; запись при изменении стиля из UI.
|
||||
- Валидация на бэкенде; юниты обеих сторон; смок; доки; ченджлоги.
|
||||
|
||||
## Не-скоуп
|
||||
|
||||
- Новые элементы UI (пикеры уже существуют, #360).
|
||||
- Per-space или per-user стиль (ключ один, глобальный, как `settings.bg_color`).
|
||||
- Персист прочих сессионных предпочтений редактора (инструмент, зум и т.п.).
|
||||
- Экспорт/импорт: ключ едет внутри `settings` штатно, отдельной обработки нет.
|
||||
|
||||
## Контракт поведения
|
||||
|
||||
1. Ключ отсутствует → поведение сегодняшнее: `_decorStyle = DEFAULT_DECOR_STYLE`.
|
||||
2. Ключ присутствует → `_decorStyle` = мердж ключа поверх `DEFAULT_DECOR_STYLE`
|
||||
(неизвестные/отсутствующие поля берутся из дефолта; лишние поля игнорируются).
|
||||
3. Изменение любого поля стиля из UI (пикер тулбара или контекстный трей —
|
||||
оба уже пишут в один `_decorStyle`) планирует запись settings с дебаунсом
|
||||
**1000 мс** от последнего изменения: драг по палитре даёт одну запись.
|
||||
4. Запись идёт существующим сериализованным путём `_writeConfig`
|
||||
(`houseplan-editor-runtime.ts:1764`): expected_rev (#340), очередь записей,
|
||||
штатный conflict при гонке вкладок. Новый канал не создаётся.
|
||||
5. Если текущий стиль равен `DEFAULT_DECOR_STYLE` по значению — ключ из settings
|
||||
удаляется (паттерн `bg_color`/`fill_colors` в `_saveSettingsDialog`:
|
||||
дефолт хранится отсутствием ключа).
|
||||
6. Запись возможна только из editor-runtime; холодный View ключ читает, но
|
||||
никогда не пишет (класс #357 не задевается).
|
||||
7. Формат ключа — snake_case, поля фронтового `DecorStyle`
|
||||
(`src/editors/decor/types.ts:78`): `color`, `opacity`, `width_cm`, `fill`,
|
||||
`fill_color`, `fill_opacity`. Все опциональны.
|
||||
|
||||
## UX
|
||||
|
||||
Видимых изменений нет. Единственная новая наблюдаемая вещь — сохранённый цвет
|
||||
после перезагрузки. Ошибка записи показывается существующим тостом конфликта
|
||||
ревизий (#340), нового текста нет.
|
||||
|
||||
## Модель данных и миграция
|
||||
|
||||
- `custom_components/houseplan/validation.py`, settings-схема (~:1883):
|
||||
`vol.Optional("decor_default_style"): vol.Schema({vol.Optional("color"): _COLOR,
|
||||
vol.Optional("opacity"): 0..1, vol.Optional("width_cm"): vol.All(vol.Coerce(float),
|
||||
vol.Range(min=0.1, max=100)), vol.Optional("fill"): bool,
|
||||
vol.Optional("fill_color"): _COLOR, vol.Optional("fill_opacity"): 0..1})`.
|
||||
- Миграции нет: ключ опционален, старые конфиги валидны без него, старый
|
||||
бэкенд при откате терпит лишний ключ (settings-схема — `ALLOW_EXTRA`,
|
||||
проверено SPEC-REVIEW-376-r1).
|
||||
- `import_export.py`: settings переносится целиком — отдельной правки нет,
|
||||
но юнит это доказывает (AC6).
|
||||
|
||||
## i18n
|
||||
|
||||
Новых строк нет. Проверка — существующий паритет-гейт словарей.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- **AC1** (юнит бэкенда, pytest): settings с валидным `decor_default_style`
|
||||
проходит; каждое поле с мусором (цвет не-цвет, opacity 2, width_cm 0) режется
|
||||
ошибкой валидации.
|
||||
- **AC2** (юнит фронта): конфиг с ключом → `_decorStyle` = мердж поверх
|
||||
`DEFAULT_DECOR_STYLE`; частичный ключ (только `color`) наследует остальные
|
||||
поля дефолта.
|
||||
- **AC3** (юнит фронта): конфиг без ключа → `DEFAULT_DECOR_STYLE` (легаси).
|
||||
- **AC4** (смок): смена цвета в тулбаре → ровно одна запись config/set после
|
||||
дебаунса, несущая `decor_default_style`; серия быстрых изменений (драг) →
|
||||
по-прежнему одна запись; выставление стиля обратно в дефолт → запись БЕЗ ключа.
|
||||
- **AC5** (смок, продолжение AC4): пересоздание карты на конфиге из AC4 →
|
||||
новый нарисованный объект несёт сохранённый цвет.
|
||||
- **AC6** (юнит): экспорт→импорт конфига с ключом сохраняет ключ байт-в-байт.
|
||||
- **AC7** (гейт): полный гейт зелёный; бюджет ≈ без изменений; в холодном View
|
||||
(launchColdView) изменение недостижимо — записи нет (доказательство: смок
|
||||
AC4 работает только после входа в редактор).
|
||||
|
||||
## План автотестов
|
||||
|
||||
- pytest: AC1 (валидация), AC6 (import/export) — в существующих файлах тестов
|
||||
валидации/импорта.
|
||||
- node --test: AC2, AC3 (инициализация; файл тестов карты/декора).
|
||||
- смок `demo/smoke_decor_default_persist.mjs` (новый): AC4+AC5 на моковом
|
||||
config/set; плюс негативная ветка AC7.
|
||||
- Мутанты (mutation-gate): м1 — вырезать чтение ключа при инициализации →
|
||||
красный AC2/AC5; м2 — вырезать дебаунс (запись на каждый ввод) → красный AC4.
|
||||
|
||||
## Риски
|
||||
|
||||
- Гонка двух вкладок: штатный conflict #340; дебаунс сужает окно. Риск низкий.
|
||||
- Захламление settings при частой смене: дебаунс + удаление ключа при дефолте.
|
||||
- Обратная совместимость: ключ опционален в обе стороны (см. «Модель данных»).
|
||||
|
||||
## Откат
|
||||
|
||||
`git revert` реализационных коммитов. Уже записанный `decor_default_style`
|
||||
остаётся в конфиге и игнорируется старым фронтом; бэкенд после отката схемной
|
||||
правки терпит ключ через `ALLOW_EXTRA` (пока владелец не решит вычистить его
|
||||
следующим сохранением настроек — паттерн `weather_entity`). Потери данных нет.
|
||||
|
||||
## Release-артефакты
|
||||
|
||||
- CHANGELOG.md + CHANGELOG.ru.md: user-visible запись со ссылкой #377.
|
||||
- USER-GUIDE(.ru): одно предложение в разделе Background про сохранение
|
||||
выбранного стиля.
|
||||
- docs/STYLING-HOOKS.md / ARCHITECTURE.md: не задеты (ключ не влияет на хуки).
|
||||
Reference in New Issue
Block a user