# Бизнес-требования: Портал приложений (apps.mva154.duckdns.org) ## 1. Проблема Сейчас веб-приложения разбросаны по разным адресам: • `openclaw.mva154.duckdns.org/noisemap/` • `openclaw.mva154.duckdns.org/snowbike-rag/` • и т.д. Нет единой точки входа. При добавлении нового приложения нужно править конфиг nginx. --- ## 2. Что хотим получить Страницу-портал по адресу `apps.mva154.duckdns.org`, на которой отображаются кнопки/карточки наших приложений. Нажал — перешёл на нужное приложение. **Главное требование:** добавление нового приложения — это только добавление строки в конфиг-файл приложения, без правки nginx. --- ## 3. Функциональные требования ### 3.1 Главная страница • Адрес: `apps.mva154.duckdns.org` • Сетка карточек приложений (grid, 2–4 колонки на десктопе, 1 колонка на мобильном) • Каждая карточка: - Иконка (emoji или SVG) - Название приложения - Краткое описание (1 строка) - Клик → переход на приложение ### 3.2 Карточки приложений • Приложения загружаются из JSON-конфига (не из кода) • Новые приложения добавляются в конфиг — портал обновляется автоматически • Порядок: из конфига (поле `order`) • Активные/неактивные: поле `enabled: true/false` — скрыть если false ### 3.3 Навигация • Клик по карточке → переход на URL приложения • Открывается в той же вкладке (или в новой — настройка в конфиге) • URL приложений — относительные пути на `openclaw.mva154.duckdns.org` --- ## 4. Архитектура ### 4.1 Схема ``` apps.mva154.duckdns.org │ ▼ Nginx (location /) │ ▼ Flask (порт 5560) ← читает config.json │ ▼ HTML (карточки приложений) │ ▼ Клик → переход на openclaw.mva154.duckdns.org/{путь} ``` ### 4.2 Конфиг приложений Файл: `config/apps.json` ```json [ { "id": "noisemap", "name": "Карта шума", "description": "Карта шумового загрязнения от авиации", "icon": "🛩️", "url": "https://openclaw.mva154.duckdns.org/noisemap/", "enabled": true, "order": 1 }, { "id": "snowbike-rag", "name": "Snowbike Поиск", "description": "Семантический поиск по базе знаний сноубайков", "icon": "🏔️", "url": "https://openclaw.mva154.duckdns.org/snowbike-rag/", "enabled": true, "order": 2 } ] ``` **Поля:** • `id` — уникальный ID (используется для имени файла аватарки) • `name` — название • `description` — описание • `icon` — emoji для аватарки (используется при генерации) • `url` — ссылка на приложение • `enabled` — показывать на портале • `order` — порядок сортировки • `avatar` — (опционально) путь к кастомной аватарке; если отсутствует — генерируется автоматически ### 4.3 Добавление нового приложения 1. Добавить строку в `config/apps.json` 2. При первом запуске Flask автоматически сгенерирует аватарку в `static/avatars/{id}.png` 3. Готово — портал показывает новое приложение **НЕ нужно:** • Править nginx • Перезапускать Flask (конфиг перечитывается при старте) • Создавать аватарку вручную --- ## 5. Требования к дизайну ### 5.1 Стиль • Светлая тема (по мотивам snowbike-rag, но светлее) • Фон: #F8FAFC (светло-серый) • Карточки: белые (#FFFFFF), скруглённые углы (16px), лёгкая тень • Шрифт: Inter • Акцентный цвет: #3B82F6 (синий) • Текст: #0F172A (тёмный) ### 5.2 Карточка приложения ``` ┌────────────────────────┐ │ │ │ ┌──────────┐ │ │ │ аватарка │ │ │ │ 80×80 │ │ │ └──────────┘ │ │ │ │ Название приложения │ │ Краткое описание │ │ │ └────────────────────────┘ ``` • Аватарка: квадратная, скруглённая (12px), 80×80px, по центру карточки • Название: жирный шрифт, 18px, тёмный • Описание: обычный шрифт, 14px, серый (#64748B) • Hover: подсветка рамки синим, lift-эффект (тень), масштаб 1.02 • Аватарка — первое что бросается в глаза ### 5.3 Аватарки приложений **Автоматическая генерация при добавлении нового приложения:** При добавлении строки в `config/apps.json` Flask автоматически генерирует аватарку, если файл не существует. **Способ генерации:** • Градиентный фон (по хэшу названия приложения → уникальный цвет) • По центру — первая буква названия или emoji иконка (крупно, белым цветом) • Сохраняется в `static/avatars/{app_id}.png` • Генерация: Python PIL/Pillow (без внешних API) • Размер: 200×200px (масштабируется в CSS) **Примеры:** ``` 🛩️ на синем градиенте → «Карта шума» 🏔️ на зелёном градиенте → «Snowbike Поиск» 🔍 на оранжевом градиенте → «Портал поиска» ``` **Правила:** • Если в конфиге указано поле `avatar` — используется указанное изображение • Если `avatar` отсутствует — генерируется автоматически • Цвет градиента определяется по хэшу `name` (детерминированно — всегда одинаковый для одного названия) • Формат: PNG, 200×200px ### 5.4 Заголовок • Название портала: «Мои приложения» • Подзаголовок: «N активных приложений» • Светлый фон, тёмный текст ### 5.5 Адаптивность • Десктоп: 3–4 колонки • Планшет: 2 колонки • Мобильный: 1 колонка --- ## 6. Технические требования ### 6.1 Стек • Flask (порт 5560) • HTML + CSS + JS (один файл, inline) • Tailwind CSS через CDN • Google Fonts (Inter) через CDN ### 6.2 Nginx • Домен `apps.mva154.duckdns.org` → location `/` → proxy_pass `http://172.19.0.2:5560/` • Один location block, без правок при добавлении приложений • SSL через Certbot (как у основного домена) ### 6.3 Flask • `GET /` — главная страница (рендерит HTML из конфига) • `GET /api/apps` — JSON-список приложений (для отладки) • Конфиг: `config/apps.json` --- ## 7. Что НЕ входит • Авторизация • Админка для добавления приложений (через JSON-файл) • Мониторинг статуса приложений (online/offline) • Уведомления о новых приложениях --- ## 8. Критерии приёмки ✅ Открывается `apps.mva154.duckdns.org` — видно карточки приложений ✅ Клик по карточке — переход на нужное приложение ✅ Добавил строку в `apps.json` — портал показывает новое приложение с аватаркой ✅ Аватарка генерируется автоматически (градиент + emoji) ✅ НЕ нужно править nginx для нового приложения ✅ Хорошо выглядит на телефоне ✅ Светлая тема, похожая на snowbike-rag --- ## 9. Приоритет **Сейчас:** Главная страница + карточки + автогенерация аватарок **Позже:** Анимации, кастомные аватарки, мониторинг статуса