# ADR-005: Выбор фронтенд-стека и i18n-стратегия **Дата:** 2026-03-20 **Статус:** Accepted **Автор:** Architect Agent (Kin pipeline, BATON-003) **Решения:** #1026 --- ## Контекст Фронтенд Baton — PWA с одной кнопкой SOS. Функционал: - Показать кнопку по центру экрана - При первом визите — форма ввода имени (регистрация) - При нажатии — вызов `/api/signal` с UUID, timestamp, geo (опционально) - Service Worker для cache-first - Адаптация под iOS/Android/Desktop Пользователи из разных стран (300–400 человек) → вопрос о локализации. --- ## Варианты фронтенд-стека ### Вариант A: Vanilla JS (zero dependencies) **Плюсы:** - Нет build step: файлы деплоятся как есть - Минимальный размер: app.js ~2–3 KB, style.css ~1–2 KB - Нет транспиляции, бандлинга, node_modules - Время загрузки: < 50ms на 3G - Полный контроль над SW lifecycle (нет абстракций) **Минусы:** - Нет компонентной модели (не нужна для 1 экрана) - Ручное управление DOM (getElementById, classList) - Нет HMR при разработке ### Вариант B: Preact (~3 KB gzip) **Плюсы:** - React-совместимый API в 3 KB - JSX + компоненты - Hooks для state management **Минусы:** - Требует build step (Vite/esbuild) - node_modules для 1 кнопки и 1 формы — overkill - Добавляет ~3 KB к bundle без пользы - Усложняет SW интеграцию (build output vs source) ### Вариант C: Vue 3 (используется в Kin) **Плюсы:** - Знакомость команды - Мощный template синтаксис - Экосистема (router, Pinia) **Минусы:** - ~33 KB gzip (runtime) - Обязателен build step - Vue Router, Pinia, SFC — всё это не нужно для 1 экрана - Кратный overkill: framework для 1 кнопки --- ## Решение (фронтенд) **Выбран Вариант A: Vanilla JS** --- ## Обоснование (фронтенд) 1. **Один экран, одна кнопка.** Компонентная модель не даёт преимуществ когда весь UI — это кнопка + форма имени + сообщение об ошибке. 2. **Zero build step = zero complexity.** Файлы `index.html`, `app.js`, `style.css`, `sw.js`, `manifest.json` деплоятся напрямую. Нет Vite, нет esbuild, нет `npm run build`. 3. **Минимальный bundle.** Для экстренного приложения скорость загрузки критична. Vanilla JS: ~5 KB total. Vue 3: ~40 KB минимум. На 3G разница: 50ms vs 400ms. 4. **SW интеграция проще.** Service Worker precache список — конечный и известный заранее. С build step нужно интегрировать hashed filenames в SW. 5. **Preact/Vue отклонены** — обоснованный overkill. Если в будущем UI усложнится (v2: история сигналов, настройки, чат) — миграция на Preact за 2 часа. --- ## i18n-стратегия (#1026) ### Решение: i18n НЕ НУЖНА в v1 ### Обоснование **Анализ текстового контента UI:** | Элемент | Текст | Универсальность | |---|---|---| | Кнопка | "SOS" или "HELP" | SOS — международный сигнал, не требует перевода | | Заголовок | "Baton" | Название продукта, не переводится | | Форма регистрации | "Your name" + placeholder | 1 строка, английский понятен целевой аудитории | | Ошибка сети | "No connection" | 1 строка | | Ошибка сервера | "Try again" | 1 строка | **Итого: 4–5 строк текста**, из которых главная (SOS) универсальна. **Целевая аудитория:** 300–400 пользователей из разных стран, но это не массовый consumer-продукт. Пользователи знают что это за приложение и как им пользоваться (установлено по прямой рекомендации). ### v2 (если потребуется) ```javascript // Минимальный i18n: JSON + navigator.language const LANG = navigator.language.slice(0, 2); const T = translations[LANG] || translations['en']; ``` Файл `translations.json`: ```json { "en": { "name_placeholder": "Your name", "no_connection": "No connection", "try_again": "Try again" }, "ru": { "name_placeholder": "Ваше имя", "no_connection": "Нет связи", "try_again": "Повторите" } } ``` **Триггер перехода к i18n:** явный запрос от пользователей или расширение аудитории на non-English speaking массовый рынок. --- ## Файловая структура фронтенда (v1) ``` frontend/ ├── index.html # App shell, meta tags, apple-touch-icon, manifest link ├── app.js # UUID auth, geolocation, fetch /api/signal, error handling ├── style.css # Центрированная кнопка, responsive, dark theme ├── sw.js # Cache-first precache, skipWaiting, clientsClaim ├── manifest.json # PWA metadata (name, icons, display:standalone) ├── icon-180.png # iOS apple-touch-icon ├── icon-192.png # Android manifest (required) └── icon-512.png # Android splash + maskable ``` --- ## Последствия 1. **Нет package.json в проекте.** Фронтенд не зависит от npm. Backend уже использует pip (requirements.txt). 2. **Деплой фронтенда = копирование файлов.** Nginx `root /path/to/frontend;` — готово. Нет CI/CD для сборки. 3. **Стили — один CSS файл.** Нет SCSS, нет PostCSS, нет CSS-in-JS. Для 1 экрана это достаточно. 4. **Тестирование фронтенда:** в v1 — ручное. Если потребуется автоматизация — Playwright (headless Chrome, без build step). 5. **i18n решение задокументировано явно (#1026).** При запросе локализации — план миграции готов (JSON файл + 3 строки JS).