# ТЗ: Веб-интерфейс для Snowbike RAG

## Общее описание

Одностраничное веб-приложение для семантического поиска по базе знаний сноубайков. Тёмная тема, адаптивный дизайн, минималистичный интерфейс.

**URL:** `https://openclaw.mva154.duckdns.org/snowbike-rag/`
**Стек:** Flask (порт 5557) + HTML/CSS/JS (без сборщиков)
**Бизнес-требования:** `docs/BRD-UI.md`

---

## Архитектура

```
Браузер
  ↓
Flask server.py (порт 5557)
  ↓
GET /snowbike-rag/ → index.html
GET /snowbike-rag/api/search?q=... → JSON ответ
GET /snowbike-rag/api/stats → статистика
```

**Nginx:** `location /snowbike-rag/ → proxy_pass http://172.19.0.2:5557/` (уже настроен)

---

## Файлы

```
tasks/snowbike-rag/
├── templates/
│   └── index.html — единственная страница (HTML + CSS + JS)
├── static/
│   └── style.css — кастомные стили (если нужно, иначе inline)
├── server.py — обновить: добавить роуты / и /api/search, /api/stats
└── docs/
    ├── BRD.md — бизнес-требования (API)
    ├── BRD-UI.md — бизнес-требования (UI)
    └── TZ-UI.md — это документ
```

---

## Страница: index.html

### 1. Заголовок
• Иконка снежинки или снегохода (emoji: 🏔️)
• Название: **Snowbike Поиск**
• Подзаголовок: «База знаний по 155 000 сообщений»

### 2. Поле ввода
• `<textarea>` по центру экрана, ширина 80% (max 700px)
• Placeholder: «Спросите про сноубайки... Например: какое масло для Polaris 850?»
• Высота: 2 строки (auto-resize до 5 строк при вводе)
• Кнопка отправки: иконка 🔍 справа внизу поля
• Отправка по Ctrl+Enter

### 3. Результаты
• Появляются ниже поля ввода
• Анимация: fadeIn 0.3s

**Блок ответа:**
• Заголовок: «Ответ»
• Текст: Markdown → HTML (через marked.js)
• Максимальная ширина: 700px, выравнивание по левому краю

**Блок источников:**
• Заголовок: «Источники (N)»
• Список карточек (max 10, с прокруткой если больше)
• Каждая карточка:
  - Дата: DD.MM.YYYY
  - Топик: цветная метка (badge)
  - Превью: 2 строки текста
  - Ссылка: «Открыть в Telegram» (если message_id доступен)

**Мета-информация:**
• Время ответа: X.X секунд
• Найдено источников: N

### 4. Состояние загрузки
• Спиннер (три пульсирующие точки) вместо кнопки
• Skeleton-анимация для блока ответа (серые полосы)

### 5. Ошибки
• API недоступен: тост-уведомление «Сервис временно недоступен»
• Пустой запрос: подсветка поля красным + текст «Введите запрос»

---

## Страница: статистика (footer)

Внизу страницы, маленькая ссылка «О базе данных»:
• Модальное окно при клике
• Показывает:
  - Всего сообщений в индексе
  - Количество топиков
  - Статус ChromaDB (генерация / готов)
  - Последнее обновление

---

## API (новые роуты в server.py)

### GET /
Возвращает `templates/index.html`

### GET /api/search?q={query}&topics={ids}&limit={N}
Аналогично текущему `/search`, но:
• Добавить CORS-заголовки
• Возвращать JSON с полями: answer, sources, count, time_ms

### GET /api/stats
Аналогично текущему `/stats`

---

## Стилизация

### Тема: тёмная
```css
--bg-primary: #0F172A;      /* фон страницы */
--bg-card: #1E293B;         /* карточки */
--bg-input: #334155;        /* поле ввода */
--text-primary: #F1F5F9;    /* основной текст */
--text-secondary: #94A3B8;  /* вторичный текст */
--accent: #3B82F6;          /* акцент (синий) */
--accent-hover: #2563EB;    /* акцент при наведении */
--error: #EF4444;           /* ошибки */
--border: #334155;          /* границы */
```

### Шрифты
• Основной: Inter (Google Fonts, через CDN)
• Моноширинный (код): JetBrains Mono (CDN)

### Адаптивность
• Мобильные (< 768px): поле ввода 95% ширины, источники в столбик
• Планшеты (768–1024px): поле ввода 80% ширины
• Десктоп (> 1024px): поле ввода max 700px, по центру

---

## Зависимости (CDN)

```html
<!-- Tailwind CSS -->
<script src="https://cdn.tailwindcss.com"></script>

<!-- Marked.js (Markdown → HTML) -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>

<!-- Google Fonts -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
```

---

## Обновление server.py

Добавить:
```python
from flask import render_template

@app.route('/')
def index():
    return render_template('index.html')
```

Переименовать `/search` → `/api/search` (или оставить оба для обратной совместимости)

---

## Критерии приёмки

- [ ] `https://openclaw.mva154.duckdns.org/snowbike-rag/` — открывается страница поиска
- [ ] Ввод «какое масло для Polaris» → ответ с источниками
- [ ] Тёмная тема, красивый интерфейс
- [ ] Хорошо выглядит на телефоне
- [ ] Markdown ответ рендерится в HTML
- [ ] Источники — карточки с датой и топиком
- [ ] Спиннер при загрузке
- [ ] Ошибка при недоступности API

---

## Важно

• Всё в одном HTML-файле (inline CSS + JS)
• Tailwind через CDN (без сборки)
• Не ломать существующие API-роуты
• Работает в контейнере (Flask :5557)
