baton/docs/adr/ADR-005-frontend-stack.md

153 lines
6.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
Пользователи из разных стран (300400 человек) → вопрос о локализации.
---
## Варианты фронтенд-стека
### Вариант A: Vanilla JS (zero dependencies)
**Плюсы:**
- Нет build step: файлы деплоятся как есть
- Минимальный размер: app.js ~23 KB, style.css ~12 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 строка |
**Итого: 45 строк текста**, из которых главная (SOS) универсальна.
**Целевая аудитория:** 300400 пользователей из разных стран, но это не массовый 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).