# Веб-UI Конвенция: *как* мы пишем код приложения. Это правила оформления кода (How), а не спецификация поведения — что именно приложение показывает и какие действия обязано поддерживать, живёт в спеке OpenSpec. Фреймворк выбран 2026-08-11 разведкой `spa-framework-choice`: [ADR](../adr/ADR-2026-08-11-spa-on-vue.md), сравнение кандидатов в [research/spa-framework.md](../research/spa-framework.md). Прежняя редакция описывала htmx с прямым запретом на шаг сборки и реактивные фреймворки; она снята целиком вместе со сменой решения на SPA 2026-08-10. **Кода приложения ещё нет.** Правила ниже выведены из выбора и из замера на пробном экране, а не из написанного кода: первым их применяет и проверяет `spa-skeleton`. Место, где правило разойдётся с тем, что окажется удобным, — повод править эту запись, а не обходить её молча. Логирование запросов — [logging.md](logging.md). Трансляция доменных ошибок наружу — [errors.md](errors.md). **Механизировано:** типы разметки и кода проверяет `vue-tsc`, и он входит в команду сборки, а не стоит отдельным шагом. Правил линтера для кода приложения пока нет. ## Что решено про само приложение - **Приложение — SPA**, а не страницы, отрисованные сервером. Сервер отдаёт контракт данных, разметку собирает клиент. - **Приложение ставится на телефон** и запускается с ярлыка: манифест, иконки, service worker. - **Статика вшивается в бинарник** через `go:embed` и раздаётся им же. Внешнего веб-сервера под статику не заводим, бинарник остаётся самодостаточным. - **Шрифты и скрипты — со своего хоста**, без внешних. Внешних ресурсов времени выполнения нет. - **Офлайн-чтения расшифровок и очереди отправки без сети не делаем** — граница цели [web-access](../../tasks/items/web-access.md). Без сети приложение показывает состояние, а не пустой экран. - **Web Push не делаем**: уведомления идут через apprise и ntfy, цель [ready-notification](../../tasks/items/ready-notification.md). - **Записи звука в приложении не делаем** — файл выбирают системным диалогом. ## Фреймворк и сборка - **Vue 3, TypeScript, сборка Vite.** Серверной отрисовки нет, надстройки над фреймворком (Nuxt) нет: она ждёт рядом процесс Node, а у нас статика в бинарнике. - **Компонент — однофайловый, `