feat: default locale Russian, geo determines language for other countries

- localization-svc: defaultLocale ru, resolveLocale only by geo
- web-svc: DEFAULT_LOCALE ru, layout lang=ru, embeddedTranslations fallback ru
- countryToLocale: default ru when no country or unknown country

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
home
2026-02-23 15:10:38 +03:00
parent 8fc82a3b90
commit cd6b7857ba
606 changed files with 26148 additions and 14297 deletions

View File

@@ -1,190 +0,0 @@
# GooSeek Search API Documentation
## Overview
GooSeeks Search API makes it easy to use our AI-powered search engine. You can run different types of searches, pick the models you want to use, and get the most recent info. Follow the following headings to learn more about GooSeek's search API.
## Endpoints
### Get Available Providers and Models
Before making search requests, you'll need to get the available providers and their models.
#### **GET** `/api/providers`
**Full URL**: `http://localhost:3000/api/providers`
Returns a list of all active providers with their available chat and embedding models.
**Response Example:**
```json
{
"providers": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "OpenAI",
"chatModels": [
{
"name": "GPT 4 Omni Mini",
"key": "gpt-4o-mini"
},
{
"name": "GPT 4 Omni",
"key": "gpt-4o"
}
],
"embeddingModels": [
{
"name": "Text Embedding 3 Large",
"key": "text-embedding-3-large"
}
]
}
]
}
```
Use the `id` field as the `providerId` and the `key` field from the models arrays when making search requests.
### Search Query
#### **POST** `/api/search`
**Full URL**: `http://localhost:3000/api/search`
**Note**: Replace `localhost:3000` with your GooSeek instance URL if running on a different host or port
### Request
The API accepts a JSON object in the request body, where you define the enabled search `sources`, chat models, embedding models, and your query.
#### Request Body Structure
```json
{
"chatModel": {
"providerId": "550e8400-e29b-41d4-a716-446655440000",
"key": "gpt-4o-mini"
},
"embeddingModel": {
"providerId": "550e8400-e29b-41d4-a716-446655440000",
"key": "text-embedding-3-large"
},
"optimizationMode": "speed",
"sources": ["web"],
"query": "What is GooSeek",
"history": [
["human", "Hi, how are you?"],
["assistant", "I am doing well, how can I help you today?"]
],
"systemInstructions": "Focus on providing technical details about GooSeek's architecture.",
"stream": false
}
```
**Note**: The `providerId` must be a valid UUID obtained from the `/api/providers` endpoint. The example above uses a sample UUID for demonstration.
### Request Parameters
- **`chatModel`** (object, required): Defines the chat model to be used for the query. To get available providers and models, send a GET request to `http://localhost:3000/api/providers`.
- `providerId` (string): The UUID of the provider. You can get this from the `/api/providers` endpoint response.
- `key` (string): The model key/identifier (e.g., `gpt-4o-mini`, `llama3.1:latest`). Use the `key` value from the provider's `chatModels` array, not the display name.
- **`embeddingModel`** (object, required): Defines the embedding model for similarity-based searching. To get available providers and models, send a GET request to `http://localhost:3000/api/providers`.
- `providerId` (string): The UUID of the embedding provider. You can get this from the `/api/providers` endpoint response.
- `key` (string): The embedding model key (e.g., `text-embedding-3-large`, `nomic-embed-text`). Use the `key` value from the provider's `embeddingModels` array, not the display name.
- **`sources`** (array, required): Which search sources to enable. Available values:
- `web`, `academic`, `discussions`.
- **`optimizationMode`** (string, optional): Specifies the optimization mode to control the balance between performance and quality. Available modes:
- `speed`: Prioritize speed and return the fastest answer.
- `balanced`: Provide a balanced answer with good speed and reasonable quality.
- `quality`: Prioritize answer quality (may be slower).
- **`query`** (string, required): The search query or question.
- **`systemInstructions`** (string, optional): Custom instructions provided by the user to guide the AI's response. These instructions are treated as user preferences and have lower priority than the system's core instructions. For example, you can specify a particular writing style, format, or focus area.
- **`history`** (array, optional): An array of message pairs representing the conversation history. Each pair consists of a role (either 'human' or 'assistant') and the message content. This allows the system to use the context of the conversation to refine results. Example:
```json
[
["human", "What is GooSeek?"],
["assistant", "GooSeek is an AI-powered search engine..."]
]
```
- **`stream`** (boolean, optional): When set to `true`, enables streaming responses. Default is `false`.
### Response
The response from the API includes both the final message and the sources used to generate that message.
#### Standard Response (stream: false)
```json
{
"message": "GooSeek is an innovative, open-source AI-powered search engine designed to enhance the way users search for information online. Here are some key features and characteristics of GooSeek:\n\n- **AI-Powered Technology**: It utilizes advanced machine learning algorithms to not only retrieve information but also to understand the context and intent behind user queries, providing more relevant results [1][5].\n\n- **Open-Source**: Being open-source, GooSeek offers flexibility and transparency, allowing users to explore its functionalities without the constraints of proprietary software [3][10].",
"sources": [
{
"content": "GooSeek is an innovative, open-source AI-powered search engine designed to enhance the way users search for information online.",
"metadata": {
"title": "What is GooSeek, and how does it function as an AI-powered search ...",
"url": "https://askai.glarity.app/search/What-is-GooSeek--and-how-does-it-function-as-an-AI-powered-search-engine"
}
},
{
"content": "GooSeek is an open-source AI-powered search tool that dives deep into the internet to find precise answers.",
"metadata": {
"title": "Sahar Mor's Post",
"url": "https://www.linkedin.com/posts/sahar-mor_a-new-open-source-project-called-gooseek-activity-7204489745668694016-ncja"
}
}
....
]
}
```
#### Streaming Response (stream: true)
When streaming is enabled, the API returns a stream of newline-delimited JSON objects using Server-Sent Events (SSE). Each line contains a complete, valid JSON object. The response has `Content-Type: text/event-stream`.
Example of streamed response objects:
```
{"type":"init","data":"Stream connected"}
{"type":"sources","data":[{"content":"...","metadata":{"title":"...","url":"..."}},...]}
{"type":"response","data":"GooSeek is an "}
{"type":"response","data":"innovative, open-source "}
{"type":"response","data":"AI-powered search engine..."}
{"type":"done"}
```
Clients should process each line as a separate JSON object. The different message types include:
- **`init`**: Initial connection message
- **`sources`**: All sources used for the response
- **`response`**: Chunks of the generated answer text
- **`done`**: Indicates the stream is complete
### Fields in the Response
- **`message`** (string): The search result, generated based on the query and enabled `sources`.
- **`sources`** (array): A list of sources that were used to generate the search result. Each source includes:
- `content`: A snippet of the relevant content from the source.
- `metadata`: Metadata about the source, including:
- `title`: The title of the webpage.
- `url`: The URL of the webpage.
### Error Handling
If an error occurs during the search process, the API will return an appropriate error message with an HTTP status code.
- **400**: If the request is malformed or missing required fields (e.g., no `sources` or `query`).
- **500**: If an internal server error occurs during the search.

95
docs/RUNBOOK.md Normal file
View File

@@ -0,0 +1,95 @@
# Runbook оператора GooSeek
**docs/architecture: 05-gaps-and-best-practices.md §9**
---
## 1. Проверка здоровья (K8s)
```bash
# Поды
kubectl get pods -n gooseek
# Health через port-forward (пример для chat-svc)
kubectl port-forward svc/chat-svc 3005:3005 -n gooseek &
curl -s http://localhost:3005/health
```
Или через Ingress: `curl -s https://gooseek.ru/api/health` (если web-svc проксирует).
Readiness: заменить `/health` на `/ready`.
---
## 2. Redis
```bash
redis-cli ping # PONG
redis-cli KEYS "discover:*" # ключи discover
redis-cli KEYS "finance:*" # ключи finance
```
---
## 3. Cache-worker (pre-compute)
В K3s: CronJob выполняются по расписанию. Логи Jobs:
```bash
kubectl get cronjobs -n gooseek
kubectl get jobs -n gooseek
kubectl logs job/<job-name> -n gooseek
```
---
## 4. Типичные сбои
| Симптом | Причина | Действие |
|---------|---------|----------|
| Discover пусто | Redis нет discover:*, Ghost/GHOST_CONTENT_API_KEY | Проверить cache-worker CronJob, .env в ConfigMap |
| Finance stub | FMP_API_KEY отсутствует или 429 | Добавить ключ, проверить лимиты FMP |
| Search 429 | Лимит SearXNG | Настроить свой инстанс, SEARXNG_URL |
| Chat зависает | LLM недоступен (Ollama/OpenAI) | Проверить OLLAMA_BASE_URL / OPENAI_API_KEY |
---
## 5. Масштабирование (K3s)
```bash
kubectl scale deployment chat-svc -n gooseek --replicas=4
```
HPA настроен в `deploy/k3s/hpa.yaml`. Требуется metrics-server.
---
## 6. Метрики Prometheus
Сервисы отдают `/metrics`. Аннотации на Pod: `prometheus.io/scrape`, `prometheus.io/port`, `prometheus.io/path`.
---
## 7. SSL (HTTPS для gooseek.ru)
См. **deploy/k3s/ssl/README.md** — получение сертификата, бэкап в `deploy/k3s/ssl/backup/`, создание Secret, применение ingress-production.yaml.
---
## 8. Порты
| Сервис | Порт |
|--------|------|
| web-svc | 3000 |
| search-svc | 3001 |
| discover-svc | 3002 |
| finance-svc | 3003 |
| travel-svc | 3004 |
| chat-svc | 3005 |
| projects-svc | 3006 |
| billing-svc | 3008 |
| library-svc | 3009 |
| memory-svc | 3010 |
| create-svc | 3011 |
| notifications-svc | 3013 |
| auth-svc | 3014 |

29
docs/TELEMETRY.md Normal file
View File

@@ -0,0 +1,29 @@
# Телеметрия и метрики в GooSeek
## Отправка данных третьим лицам (отключена)
| Источник | Сервис | Статус | Как отключено |
|----------|--------|--------|---------------|
| **Next.js** | web-svc | Отключено | `NEXT_TELEMETRY_DISABLED=1` в Dockerfile |
| **better-auth** | auth-svc | Отключено | `telemetry: { enabled: false }` в auth.ts + `BETTER_AUTH_TELEMETRY=0` в env |
| **workbox-google-analytics** | — | Не используется | Транзитивная зависимость next-pwa; GA не подключается в sw.js |
| **OpenTelemetry** | — | Не настроено | Optional peer dep (Prisma); без провайдеров ничего не отправляет |
## Локальные метрики Prometheus (observability)
Эндпоинты `/metrics` **не отправляют** данные наружу. Prometheus скрейпит их внутри кластера.
| Сервис | Endpoint |
|--------|----------|
| chat-svc | `GET /metrics` |
| search-svc | `GET /metrics` |
| discover-svc | `GET /metrics` |
| finance-svc | `GET /metrics` |
| travel-svc | `GET /metrics` |
| library-svc | `GET /metrics` |
| memory-svc | `GET /metrics` |
| create-svc | `GET /metrics` |
| audit-svc | `GET /metrics` |
| web-svc | `GET /api/metrics` |
Для полного отключения метрик удалите эти эндпоинты и аннотации `prometheus.io/*` в `deploy/k3s/*.yaml`.

View File

@@ -0,0 +1,695 @@
# Архитектура аналога Perplexity.ai — полная спецификация
Документ описывает полную архитектуру системы на базе микросервисов K3s с акцентом на:
- **ВСЕ сервисы в `services/`.** Папка `apps/` удаляется. Микросервисная архитектура: chat, search, discover, finance, travel, auth, library, memory, create, notifications, projects, web (UI), cache-worker.
- **~10 000 DAU** (ежедневных пользователей)
- **Клиентская логика** — максимум на клиенте; персональные данные — только для аккаунтов
- **Предварительная обработка и кэш** — новости, finance, travel, повторяющиеся запросы
- **Полное совпадение** с Perplexity.ai по страницам и логике
---
## 1. Карта страниц (URL-структура, 1:1 Perplexity)
| URL | Страница | Описание |
|-----|----------|----------|
| `/` | Home | Поисковая строка + виджеты discover/новости |
| `/search`, `/search/new?q=` | Search | Поисковый чат (Quick/Pro/Deep) |
| `/c/[threadId]` | Chat/Thread | Окно конкретного чата/треда |
| `/finance` | Finance | Рынок, heatmap, вкладки |
| `/finance/[ticker]` | Ticker Detail | Детальная страница акции/индекса |
| `/finance/predictions/[id]` | Predictions | Polymarket prediction markets |
| `/travel` | Travel | Trending, Inspiration Cards, отели, маршруты |
| `/discover` | Discover | Новости по темам (или часть Home) |
| `/library` | Library | История поисков, сохранённые треды |
| `/spaces` | Spaces | Список проектов/пространств |
| `/spaces/templates` | Space Templates | Шаблоны Spaces |
| `/collections/[id]` | Collections | Публичные коллекции (read-only Space) |
| `/patents` | Patents | Поиск и анализ патентов |
| Profile/Settings | Account | Профиль, Preferences, Personalize, Billing, My Connectors |
| — | Desktop app | Electron/Tauri (pplx.ai-аналог) |
| — | iOS / Android | Нативные приложения, voice search |
| — | Chrome extension | Расширение для браузера |
---
## 2. Карта функциональностей
### 2.1 Сводная матрица
| Категория | Функционал | Клиент | Сервер (обязательно) | Кэш/Фоново |
|-----------|------------|--------|----------------------|------------|
| **Поиск** | Quick Search | ✅ UI, локальное состояние | LLM, Researcher | ✅ Кэш по query_hash |
| **Поиск** | Pro Search | ✅ UI, стриминг | LLM, Mastra workflow | ✅ Кэш по query_hash |
| **Поиск** | Deep Research | ✅ UI, прогресс | LLM, Mastra | ✅ Кэш по query_hash |
| **Discover** | Новости по темам | ✅ Рендер | Агрегация | ✅ **Pre-compute + Redis** |
| **Finance** | Рынок, heatmap, watchlist | ✅ Рендер, watchlist в LS | Агрегация данных | ✅ **Pre-compute + Redis** |
| **Travel** | Маршруты, отели | ✅ UI stepper | Агрегация, LLM | ✅ **Pre-compute популярных** |
| **Проекты** | Spaces, файлы | ✅ CRUD UI | Хранение файлов, эмбеддинги | — |
| **Чат** | Сообщения, история | ✅ localStorage / IndexedDB | Только LLM, без хранения | Опционально: user preference |
| **Медиа** | Images, Videos | ✅ Рендер | SearXNG proxy | ✅ Кэш по query |
| **Виджеты** | Погода, акции, калькулятор | ✅ Калькулятор на клиенте | API-прокси | ✅ Погода/акции по ключу |
| **Профиль** | Account, prefs | ✅ Preferences в LS | Auth только (SSO) | — |
| **Биллинг** | Тарифы, оплата | ✅ UI | ЮKassa, лимиты | — |
| **Collections** | Публичные шаблоны | ✅ Рендер | projects-svc | Redis/PostgreSQL |
| **Library** | История, сохранённое | ✅ UI | library-svc (аккаунты) | PostgreSQL |
| **Memory** | Персональная память AI | ✅ UI | memory-svc | PostgreSQL + Redis |
| **Create/Labs** | Дашборды, отчёты, экспорт | ✅ UI | chat-svc + create-svc | — |
| **Patents** | Поиск патентов | ✅ Рендер | search-svc + patents API | Redis |
| **Export thread** | Экспорт тредов в PDF/MD | ✅ UI | create-svc / library-svc | — |
| **Notifications** | Push, email, напоминания | ✅ Клиент + SW | notifications-svc | — |
| **PWA/Офлайн** | Service worker, установка | ✅ SPA | Static + SW | — |
| **Model Council** | 3 модели параллельно, синтез | ✅ UI (Max) | chat-svc | — |
| **Background Assistant** | Фоновые задачи (Max) | ✅ Desktop/Mobile | chat-svc + queue | — |
### 2.2 Детальное описание функциональностей
#### A. Поисковый чат (Core)
| Функция | Описание |
|---------|----------|
| Quick Search | 1 запрос, базовые модели, без хранения истории |
| Pro Search | Многошаговый поиск, Mastra workflow, параллельные actions |
| Deep Research | Расширенный анализ, отчёт, визуализация этапов |
| **Answer Modes** | Standard, Focus, Academic, Writing + вертикали (Travel, Finance) |
| **Travel Mode** | Отдельный системный промпт, фокус на отели/маршруты/бронирование |
| Классификация | Classifier → skipSearch, sources, widgets |
| Actions | webSearch, academicSearch, socialSearch, scrapeURL, uploadsSearch (параллельно) |
| Writer | Финальный ответ с цитированием источников |
| **Step-by-step Learning** | Режим обучения: подсказки, guided questions, уровень сложности |
| **Response preferences** | Настройки формата/стиля ответов (Preferences) |
| **Input bar «+»** | Меню: файлы, источники, режимы (Quick/Pro/Deep/Create/Learn) |
| **Model Council** | Запуск 3 моделей параллельно → сравнение → синтез ответа (Max) |
#### B. Discover (Новости)
| Функция | Описание |
|---------|----------|
| Агрегация новостей | По темам: tech, finance, travel, world, science |
| Суммаризация | LLM-сводка каждой новости/блока |
| Обновление | Фоновая задача каждые 1530 мин |
| Кэш | Redis: `discover:{topic}:{date}` TTL 30 мин |
#### C. Finance
| Функция | Описание |
|---------|----------|
| Market Summary | Индексы, futures, VIX |
| Heatmap S&P 500 | Сектора, gainers/losers |
| **Вкладки** | Crypto, Earnings, Predictions, Screener, Politicians Watchlist, Watchlist |
| Recent Developments | Новости с суммаризацией и таймстампами |
| **Popular Spaces for Finance Research** | Блок коллекций по категории finance (SEC, Buffett, S&P Transcripts) |
| Standouts | Выделенные акции с кратким LLM-анализом |
| Watchlist | Клиент: localStorage; сервер: агрегация данных по тикерам |
| **Analyst ratings** | Рейтинги аналитиков по акциям (FMP, Benzinga и т.п.) |
| **Auditable financials** | Ссылки на SEC filings в ответах и на странице тикера |
| **ETF Holdings** | Детали холдингов ETF на странице тикера |
| **Heatmap hover** | Live-синтез причины движения цены при наведении (LLM on demand) |
| **Stock graphs** | Графики в ответах чата (мобильный/desktop) |
| Кэш | Redis: `finance:summary`, `finance:heatmap`, `finance:news:{ticker}` TTL 25 мин |
#### D. Travel
| Функция | Описание |
|---------|----------|
| Trending Destinations | Карточки с изображениями (pre-compute) |
| **Inspiration Cards** | Курируемые статьи («Лучшие тропы в Словении», «Лесные отели в Швеции») |
| Поиск мест, маршруты | Генерация itineraries (LLM) |
| Отели | Tripadvisor (рейтинги, отзывы, ссылки) |
| **Партнёрское бронирование** | Tripadvisor, Selfbook (прямое бронирование) |
| Stepper UI | Поиск → Места → Маршрут → Отели → Билеты |
| Answer Mode: Travel | Вертикаль чата с фокусом на путешествия |
| Кэш | Redis: `travel:trending`, `travel:inspiration`, `travel:itinerary:{hash}` TTL 124 ч |
#### E. Collections (публичные)
| Функция | Описание |
|---------|----------|
| Collections | Публичные read-only Spaces с предзагруженным контекстом |
| Категории | finance, travel, product, research — для Popular Spaces |
| Примеры | SEC Findings, Buffett letters, S&P 500 Transcripts |
| API | `GET /collections?category=finance`, `GET /collections/:id` |
#### F. Проекты (Spaces)
| Функция | Описание |
|---------|----------|
| CRUD проектов | Создание, переименование, архивация |
| Файлы в проекте | Загрузка, парсинг, эмбеддинги |
| Чаты в проекте | Контекст проекта во всех чатах |
| Internal Knowledge Search | Поиск по файлам + веб |
| Space Templates | Шаблоны под финансы, маркетинг, продукт, travel |
#### G. Library
| Функция | Описание |
|---------|----------|
| История поисков | Список тредов для авторизованного пользователя |
| Сохранённое | Saved threads, закладки |
| **Гости** | Только localStorage/IndexedDB, при закрытии — потеря |
| **Аккаунты** | Синхронизация на сервере (library-svc, PostgreSQL) |
#### H. Медиа
| Функция | Описание |
|---------|----------|
| Search Images | SearXNG, LLM формирует query |
| Search Videos | SearXNG, LLM формирует query |
| Кэш | Redis: `media:images:{query_hash}`, `media:videos:{query_hash}` TTL 1 ч |
#### I. Виджеты
| Функция | Описание |
|---------|----------|
| Weather | API (Open-Meteo и т.п.) |
| Stock | Yahoo Finance / Financial Modeling Prep |
| Calculation | **Полностью на клиенте** (mathjs и т.п.) |
| Кэш | Погода/акции: Redis по location/ticker TTL 515 мин |
#### J. Профиль и Connectors
| Функция | Описание |
|---------|----------|
| Account | Аватар, имя, email (только просмотр) |
| Preferences | Appearance, Language, Autosuggest, Homepage widgets, **Response preferences** |
| Personalize | Watchlists, настройки персонализации |
| Billing | Подписка, история платежей |
| **My Connectors** | Интеграции (Google Drive, Dropbox и т.п.) — Pro/общие пользователи |
| **App Connectors** | Enterprise: SharePoint, OneDrive, Box — автосинхронизация файлов в Space |
#### K. Memory (персональная память AI)
| Функция | Описание |
|---------|----------|
| Хранение | memory-svc, PostgreSQL (user_id, key, value, embedding) |
| Извлечение | Семантический поиск по памяти при каждом запросе (если Pro/Max) |
| Формат | Факты, предпочтения, контекст из прошлых тредов |
| UI | Просмотр/удаление памяти в Profile → Personalize |
| Enterprise Memory | Организационная память (org_id), доступна всем участникам |
#### L. Create / Labs
| Функция | Описание |
|---------|----------|
| Генерация | Таблицы, отчёты, дашборды по запросу (Pro) |
| Экспорт | .xlsx, .csv, .md, .pdf из ответов |
| Image generation | Генерация изображений (Pro, DALL·E/Stable Diffusion) |
| API | `POST /api/v1/create` — тип (table/dashboard/image), prompt |
#### M. Patents
| Функция | Описание |
|---------|----------|
| Страница | `/patents` — поиск по USPTO, EPO, патентам РФ |
| Интеграция | patents API или Google Patents; LLM-суммаризация |
| Кэш | Redis `patents:{query_hash}` TTL 1 ч |
#### N. Enterprise
| Функция | Описание |
|---------|----------|
| **Audit logs** | Логи: query, answer, model, sources, user_id, timestamp (compliance) |
| **Granular feature access** | Доступ к API, список Spaces, модели по ролям админа |
| **Domain-based sign-up** | Ограничение регистрации по верифицированным доменам email |
| **Usage guidelines** | Guidelines организации на homepage для членов |
| **Enterprise Memory** | Общая память на уровень org |
#### O. Клиентские приложения
| Платформа | Описание |
|----------|----------|
| **Desktop** | Electron или Tauri, единый код с web |
| **iOS / Android** | React Native или Capacitor; **voice search** (Web Speech API / native) |
| **Chrome extension** | Всплывающее окно, быстрый поиск со страницы |
| **PWA / Офлайн** | Service worker кэширует статику (JS, CSS, assets); workbox; установка на домашний экран; офлайн-fallback |
#### O.1 Export thread
| Функция | Описание |
|---------|----------|
| API | `POST /api/v1/library/threads/:id/export` или `POST /api/v1/export` с `contentType: 'thread'` |
| Форматы | PDF, Markdown |
| Реализация | create-svc или library-svc; рендер треда → PDF (puppeteer/jsPDF) или MD (template) |
| UI | Кнопка Export в окне чата/треда |
#### O.2 Notifications
| Функция | Описание |
|---------|----------|
| **Push** | Web Push API (VAPID); уведомление при готовности ответа (Pro/Deep); настройки в Preferences |
| **Email** | Опция «уведомить по email при завершении» для долгих запросов (Deep Research) |
| **Напоминания** | «Напомнить через N» — отложенная задача, push/email по расписанию |
| **Сервис** | notifications-svc; очереди (Redis/Bull) или вызов от chat-svc по событию |
#### O.3 Model Council (Max)
| Функция | Описание |
|---------|----------|
| Логика | Запрос → параллельный запуск 3 выбранных моделей (GPT-4, Claude, и др.) |
| Синтез | Отдельный LLM-вызов для сравнения и сведения в единый ответ |
| UI | Выбор моделей в input bar; side-by-side или сводный вид |
| API | `POST /api/v1/chat` с `modelCouncil: true`, `models: ['gpt-4','claude','...']` |
#### O.4 Background Assistant (Max)
| Функция | Описание |
|---------|----------|
| Назначение | Выполнение задач в фоне (Desktop/Mobile app), когда приложение свёрнуто |
| Архитектура | Queue (Redis/Bull); worker подхватывает задачи; push при готовности |
| Сценарии | «Найди отели в Париже» → фон → уведомление с результатом |
| API | `POST /api/v1/tasks` (создать фоновую задачу); polling или WebSocket/SSE для статуса |
#### P. Образование
| Функция | Описание |
|---------|----------|
| **Step-by-step Learning** | Режим в input bar «+»; ответы с подсказками, guided questions |
| **Quizzes / Flashcards** | Генерация тестов и карточек по теме (Pro/Education) |
| **Education Pro** | Тариф со скидкой для студентов/преподавателей (верификация) |
---
## 3. Микросервисы K3s
### 3.1 Карта сервисов
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ CLIENT (SPA / PWA) │
│ Next.js (SSR для статики) / React SPA — максимум логики, localStorage, IndexedDB │
└─────────────────────────────────────────────────────────────────────────────────┘
┌───────────────────┼───────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────────────┐ ┌───────────────────────┐ ┌───────────────────────┐
│ API Gateway │ │ Auth Service │ │ Web (CDN/Static) │
│ (Kong / Traefik) │ │ (Keycloak/Supabase) │ │ S3/MinIO + CDN │
└───────────────────────┘ └───────────────────────┘ └───────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────┐
│ BACKEND MICROSERVICES (K3s) │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ chat-svc │ │ search-svc │ │ discover-svc│ │ finance-svc │ │
│ │ LLM, Mastra │ │ SearXNG, │ │ News feed │ │ Market data │ │
│ │ Writer │ │ Scraper │ │ Summari-zer│ │ Heatmap │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ travel-svc │ │ media-svc │ │ projects-svc│ │ cache-worker│ │
│ │ Itineraries │ │ Images/Videos│ │ Files, │ │ Pre-compute │ │
│ │ Tripadvisor │ │ SearXNG │ │ Embeddings │ │ Background │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ billing-svc │ │ upload-svc │ │ library-svc │ │ memory-svc │ │
│ │ ЮKassa │ │ File parse │ │ Threads, │ │ AI Memory, │ │
│ │ Subscriptions│ │ Embeddings │ │ History │ │ Enterprise │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ # Create, Audit, Notifications │
│ │ create-svc │ │ audit-svc │ │notifications│ │
│ │ Tables, │ │ Query+Answer│ │ Push, Email │ │
│ │ Dashboards │ │ logging │ │ Reminders │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────┐
│ ИНФРАСТРУКТУРА │
│ Redis (кэш + сессии) │ PostgreSQL (billing, projects) │ MinIO (файлы) │
│ SearXNG (self-hosted) │ LLM Provider (OpenAI/Ollama) │ Vector DB (optional) │
└─────────────────────────────────────────────────────────────────────────────────┘
```
### 3.2 Описание микросервисов
| Сервис | Язык | Replicas (10k DAU) | Назначение |
|--------|------|--------------------|------------|
| **api-gateway** | — (Kong/Traefik) | 2 | Роутинг, rate limit, JWT validation |
| **auth-svc** | Node/Go | 2 | SSO (Google, Apple, Email magic link), JWT |
| **chat-svc** | Node.js | 35 | LLM, Mastra workflow, Writer, streaming |
| **search-svc** | Node.js | 3 | SearXNG, scrape, Researcher actions |
| **discover-svc** | Node.js | 2 | Агрегация новостей, суммаризация (фоново) |
| **finance-svc** | Node.js | 2 | Market data, heatmap, news по тикерам |
| **travel-svc** | Node.js | 2 | Itineraries, Tripadvisor, trending |
| **media-svc** | Node.js | 2 | Images/Videos через SearXNG |
| **projects-svc** | Node.js | 2 | CRUD проектов, файлы, эмбеддинги, **Collections** |
| **billing-svc** | Node.js | 1 | ЮKassa, subscriptions, лимиты |
| **upload-svc** | Node.js | 2 | Парсинг PDF/DOCX, embedding, chunking |
| **library-svc** | Node.js | 2 | История тредов, сохранённое для аккаунтов |
| **memory-svc** | Node.js | 2 | Персональная память AI, Enterprise Memory, векторный поиск |
| **create-svc** | Node.js | 12 | Create (таблицы, дашборды), экспорт, image generation |
| **audit-svc** | Node.js | 1 | Audit logs для Enterprise (query, answer, model, user) |
| **notifications-svc** | Node.js | 12 | Web Push, Email, напоминания; очереди задач |
| **cache-worker** | Node.js | 12 | Cron: pre-compute discover, finance, travel inspiration |
### 3.3 K3s манифесты (базовая структура)
```yaml
# namespaces
perplexica-prod
perplexica-cache
# Deployments с HPA
chat-svc: min 2, max 8, CPU 70%
search-svc: min 2, max 6
discover-svc: min 1, max 4
finance-svc: min 1, max 4
travel-svc: min 1, max 3
media-svc: min 1, max 4
projects-svc: min 1, max 4 (включая Collections)
upload-svc: min 1, max 4
library-svc: min 1, max 3
memory-svc: min 1, max 3
create-svc: min 1, max 2
audit-svc: min 1, max 1
notifications-svc: min 1, max 2
billing-svc: min 1, max 2
cache-worker: min 1, max 1 (CronJob)
auth-svc: min 2, max 4
```
---
## 3. Стратегия кэширования и предобработки
### 3.1 Ключевой принцип
> **Не суммировать и не обрабатывать по запросу то, что можно сделать заранее и переиспользовать.**
### 3.2 Кэш-слои
| Слой | Что кэширует | Ключ | TTL | Источник |
|------|--------------|------|-----|----------|
| **Discover** | Новости по теме + суммаризация | `discover:{topic}` | 30 мин | cache-worker каждые 15 мин |
| **Finance** | Market summary, heatmap | `finance:summary`, `finance:heatmap` | 5 мин | cache-worker каждые 2 мин |
| **Finance** | News по тикеру | `finance:news:{ticker}` | 15 мин | cache-worker при обновлении |
| **Travel** | Trending destinations | `travel:trending` | 6 ч | cache-worker каждые 4 ч |
| **Travel** | Inspiration Cards | `travel:inspiration` | 6 ч | cache-worker каждые 4 ч |
| **Travel** | Популярные маршруты | `travel:itinerary:{hash}` | 24 ч | On first request, reuse |
| **Search** | Идентичные запросы | `search:{query_hash}:{mode}` | 124 ч | On first request |
| **Media** | Images/Videos query | `media:{type}:{query_hash}` | 1 ч | On first request |
| **Widgets** | Погода, акции | `widget:{type}:{key}` | 515 мин | On first request |
### 3.4 Cache-worker (фоновые задачи)
```
Cron расписание:
├── */2 * * * * finance:summary, finance:heatmap
├── */15 * * * * discover:{topic} для всех тем
├── 0 */4 * * * travel:trending, travel:inspiration (Inspiration Cards)
└── 0 * * * * Инвалидация устаревших search cache
```
### 3.5 Логика поискового кэша
1. Входящий запрос → `query_hash = sha256(normalize(query) + mode + sources)`
2. Проверка Redis: `GET search:{query_hash}`
3. Если есть → отдать из кэша (без LLM)
4. Если нет → выполнить полноценный flow, сохранить в кэш
5. Популярные запросы (частота > N/день) → приоритет в cache-worker для pre-warm
---
## 4. Клиентская архитектура (без хранения данных)
### 4.1 Что на клиенте (включая My Connectors UI)
| Компонент | Реализация |
|-----------|------------|
| UI/UX | React, Next.js (SSR только для статики) |
| Состояние чата | Zustand/Context — в памяти, при refresh теряется (или опционально IndexedDB) |
| Preferences | localStorage: theme, language, units |
| Watchlist (finance) | localStorage |
| Калькулятор | Полностью локально (mathjs) |
| Роутинг | Client-side |
| **PWA / Офлайн** | Service worker (Workbox): кэш static (JS, CSS, assets); offline fallback; manifest для установки |
### 4.2 Что храним / не храним
**Не храним на сервере (гости):**
- История чатов — только в памяти/IndexedDB клиента
- Preferences — только в localStorage
**Храним для аккаунтов:**
- История тредов, сохранённое — library-svc (PostgreSQL)
- Projects, файлы, подписка — projects-svc, billing-svc
- Кэш поиска — обезличенный по query_hash, без user_id
### 4.3 Режимы пользователя
| Режим | Данные | Описание |
|-------|--------|----------|
| **Гость** | Всё на клиенте | Чат в памяти, при закрытии — потеря |
| **Аккаунт** | Auth + billing | Проекты, подписка — в БД; чаты опционально |
### 4.4 UI/UX требования
| Область | Требование |
|---------|------------|
| **Discover, Finance, Travel** | Skeleton/placeholder при cold start; timeout с сообщением; кнопка повтора при ошибке |
| **Поиск (Pro/Deep)** | Отображение этапов (Classifier → Researcher → Writer); оценка времени ожидания |
| **Загрузка файлов** | Прогресс по этапам: парсинг → chunking → эмбеддинги; индикация; кнопка Cancel; timeout 300 с |
| **Гости** | Предупреждение при закрытии: история теряется без аккаунта; CTA «Сохранить в аккаунт» |
| **Rate limit** | Сообщение при 429; предупреждение при 80% лимита; предложение апгрейда при достижении |
| **Ошибки** | Сообщение + Retry/Cancel; fallback при частичном сбое (например, виджет не загрузился) |
| **Travel Stepper** | Сохранение состояния шагов при уходе; скелетон между шагами |
| **Мобильный** | Адаптивность heatmap, Discover; жесты; SettingsButtonMobile |
---
## 5. API контракты (основные)
### 5.1 Chat/Search
```
POST /api/v1/chat
Body: { query, mode?, sources?, fileIds?, answerMode?, learningMode?, responsePrefs? }
answerMode: 'standard' | 'focus' | 'academic' | 'writing' | 'travel' | 'finance'
learningMode: boolean # Step-by-step Learning
responsePrefs: { format?, length?, tone? } # из Preferences
Response: SSE stream
Cache: Проверка query_hash до вызова LLM
POST /api/v1/search/cached
Query: ?q=...&mode=...
Response: JSON (если есть в кэше) или 404 → fallback на /chat
```
### 5.2 Discover
```
GET /api/v1/discover?topic=tech|finance|travel|...
Response: { items: [{ title, summary, source, url }] }
Source: Redis, refresh от cache-worker
```
### 5.3 Finance
```
GET /api/v1/finance/summary
GET /api/v1/finance/heatmap
GET /api/v1/finance/news/:ticker
GET /api/v1/finance/watchlist?tickers=AAPL,GOOG
GET /api/v1/finance/analyst-ratings/:ticker # Analyst ratings
GET /api/v1/finance/sec-filings/:ticker # Ссылки на SEC filings
GET /api/v1/finance/etf-holdings/:symbol # ETF Holdings
GET /api/v1/finance/price-context/:ticker # Heatmap hover: LLM-синтез причины движения
Response: JSON из Redis / live
```
### 5.4 Travel
```
GET /api/v1/travel/trending
GET /api/v1/travel/inspiration # Inspiration Cards (pre-compute)
POST /api/v1/travel/itinerary
Body: { destination, days, preferences }
Cache: По hash параметров
```
### 5.5 Collections
```
GET /api/v1/collections?category=finance|travel|product|research
GET /api/v1/collections/:id
Response: Публичный Space с контекстом (read-only)
```
### 5.6 Library
```
GET /api/v1/library/threads # Для авторизованных
POST /api/v1/library/threads # Сохранить тред
DELETE /api/v1/library/threads/:id
```
### 5.7 Auth
```
POST /auth/login/email
GET /auth/oauth/{provider}
POST /auth/refresh
GET /auth/me
```
### 5.8 Connectors
```
GET /api/v1/connectors # Список доступных (Pro)
POST /api/v1/connectors/:type # Подключить (Google Drive, Dropbox)
DELETE /api/v1/connectors/:id # Отключить
```
### 5.9 Memory
```
GET /api/v1/memory # Список записей памяти (Pro/Max)
POST /api/v1/memory # Добавить запись (внутренний вызов от chat-svc)
DELETE /api/v1/memory/:id # Удалить запись
```
### 5.10 Create / Labs
```
POST /api/v1/create
Body: { type: 'table' | 'dashboard' | 'image', prompt, context? }
Response: { url?, data?, imageUrl? }
POST /api/v1/export
Body: { format: 'xlsx' | 'csv' | 'md' | 'pdf', contentId?, contentType?: 'create' | 'thread' }
Body (thread): { format: 'pdf' | 'md', threadId }
Response: blob / download URL
```
### 5.10.1 Export thread
```
POST /api/v1/library/threads/:id/export
Query: ?format=pdf|md
Response: blob (application/pdf или text/markdown)
Реализация: create-svc или library-svc + puppeteer/jsPDF для PDF
```
### 5.11 Patents
```
GET /api/v1/patents?q=...
Response: { patents: [{ title, abstract, filingDate, url, summary }] }
Source: Google Patents / USPTO API; LLM-суммаризация; Redis кэш
```
### 5.12 Enterprise Audit
```
GET /api/v1/admin/audit-logs?from=&to=&userId=
Response: [{ query, answerSnippet, model, sources, userId, timestamp }]
Только для org admin
```
### 5.13 Notifications
```
POST /api/v1/notifications/subscribe # Web Push подписка (VAPID)
Body: { endpoint, keys: { p256dh, auth } }
POST /api/v1/notifications/preferences # Настройки: push при ответе, email, напоминания
Body: { pushOnAnswer?, emailOnDeepResearch?, reminders?: [...] }
POST /api/v1/notifications/remind # «Напомнить через N»
Body: { threadId?, query?, remindAt: ISO8601 }
```
### 5.14 Model Council (Max)
```
POST /api/v1/chat
Body: { ..., modelCouncil: true, models: ['gpt-4o','claude-sonnet','...'] }
Response: SSE с этапами: 3 ответа → синтез
```
### 5.15 Background Assistant (Max)
```
POST /api/v1/tasks # Создать фоновую задачу
Body: { query, mode?, callback?: 'push' | 'poll' }
Response: { taskId }
GET /api/v1/tasks/:id # Статус задачи
Response: { status, result?, error? }
```
---
## 6. Порядок реализации (best practices)
### Фаза 0 — Инфраструктура
1. K3s кластер, PostgreSQL, Redis, MinIO
2. API Gateway (Traefik/Kong)
3. Auth-svc (Keycloak или Supabase Auth)
### Фаза 1 — Ядро
4. chat-svc с Mastra (Classifier → parallel actions → Writer)
5. search-svc (SearXNG, actions)
6. cache-worker + Redis стратегия
7. Кэш для search по query_hash
### Фаза 2 — Discover + Finance
8. discover-svc + cache-worker pre-compute
9. finance-svc + cache-worker
10. Клиент: Discover, Finance страницы
### Фаза 3 — Travel
11. travel-svc, Tripadvisor, Selfbook
12. Inspiration Cards (cache-worker), Stepper UI
13. Answer Mode: Travel
### Фаза 4 — Проекты, Collections, Library, биллинг
14. projects-svc, upload-svc, **Collections** (Popular Spaces по категориям)
15. library-svc (история для аккаунтов)
16. billing-svc, ЮKassa
17. Клиент: Spaces UI, Library, Profile, Billing, My Connectors
### Фаза 5 — Memory, Create, Finance+, Patents, Enterprise
18. memory-svc (персональная память, Enterprise Memory)
19. create-svc (таблицы, дашборды, экспорт, image generation)
20. finance-svc: Analyst ratings, SEC links, ETF Holdings, heatmap hover, stock graphs
21. Patents page: search-svc + patents API, `/patents`
22. audit-svc (Enterprise audit logs)
23. Enterprise: domain sign-up, usage guidelines, granular feature access
24. Step-by-step Learning, Response preferences, Input bar «+»
### Фаза 6 — Клиенты и образование
25. Desktop app (Electron/Tauri)
26. iOS / Android (React Native/Capacitor), voice search
27. Chrome extension
28. Step-by-step Learning UI, Quizzes/Flashcards
29. Education Pro тариф
### Фаза 7 — Export, Notifications, PWA, Model Council, Background
30. Export thread: POST /library/threads/:id/export (PDF, MD)
31. PWA: Service worker (Workbox), manifest, offline fallback
32. notifications-svc: Web Push (VAPID), email, напоминания
33. Model Council (Max): параллельный запуск 3 моделей, синтез
34. Background Assistant (Max): POST /tasks, queue, push при готовности
### Фаза 8 — Оптимизация
35. Pre-warm популярных запросов в cache-worker
36. CDN для статики
37. Мониторинг, алерты, SLO
---
## 7. Латенси по сценариям (пользователь)
| Сценарий | Ожидаемое время | Cold / промах кэша |
|----------|-----------------|--------------------|
| Discover / Finance (кэш) | &lt;500 ms | 530 с |
| Finance редкий тикер | 1020 с (cold fill) | — |
| Travel itinerary | 1560 с | — |
| Pro/Deep Search | 30120 с | — |
| Загрузка файла (эмбеддинги) | 30300 с | — |
| Медиа (Images/Videos) | 310 с | — |
## 8. Оценка нагрузки (10k DAU)
| Метрика | Оценка | Решение |
|---------|--------|---------|
| RPS пиковый | ~50100 | HPA, 35 реплик chat-svc |
| LLM вызовов/день | ~30k (3 на юзера) | Кэш снижает до ~10k |
| Redis memory | ~48 GB | Кэш discover/finance/search |
| Storage | ~100 GB | Файлы проектов, логи |
---
## 9. Безопасность и compliance
- HTTPS везде
- JWT с коротким TTL (15 мин), refresh token
- Rate limiting: 100 req/min на IP, 300 Pro Search/день (Free)
- Не логировать персональные запросы в plaintext
- Кэш — только по hash, без привязки к user_id

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,282 @@
# Стратегия кэширования и предварительной обработки
## Принципы
1. **Не делать по запросу то, что можно сделать заранее**
2. **Кэшировать по обезличенному ключу** (query hash, topic, ticker)
3. **Фоновые воркеры** обновляют кэш по расписанию
4. **Первый запрос** — холодный, заполняет кэш для последующих
---
## 1. Discover (Новости)
### Архитектура
```
┌─────────────────────────────────────────────────────────────────────────┐
│ cache-worker (CronJob каждые 15 мин) │
│ │
│ 1. Агрегировать новости по темам (tech, finance, travel, world, ...) │
│ 2. Для каждой новости: суммаризация через LLM (batch) │
│ 3. Сохранить в Redis: discover:{topic} = JSON │
│ TTL = 30 мин │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ discover-svc (HTTP GET /discover?topic=tech) │
│ │
│ 1. Redis GET discover:tech │
│ 2. Если есть → отдать сразу │
│ 3. Если нет (cold) → синхронно выполнить агрегацию + суммаризацию, │
│ сохранить в Redis, отдать │
└─────────────────────────────────────────────────────────────────────────┘
```
### Redis схема
| Ключ | Значение | TTL |
|------|----------|-----|
| `discover:tech` | `{ items: [{ title, summary, source, url, fetched_at }] }` | 30 min |
| `discover:finance` | аналогично | 30 min |
| `discover:travel` | аналогично | 30 min |
### UX при cold start
- Skeleton карточек новостей; timeout 30 с; Retry при ошибке; предупреждение о задержке при cold
### Cron расписание
```
*/15 * * * * cache-worker --task=discover
```
---
## 2. Finance (Рынок, новости по тикерам)
### Архитектура
```
┌─────────────────────────────────────────────────────────────────────────┐
│ cache-worker (CronJob каждые 2 мин) │
│ │
│ 1. Market summary: индексы, futures, VIX │
│ 2. Heatmap S&P 500 │
│ 3. News для топ-20 тикеров (по популярности) → суммаризация │
│ 4. Redis: finance:summary, finance:heatmap, finance:news:AAPL, ... │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ finance-svc │
│ │
│ GET /finance/summary → Redis finance:summary │
│ GET /finance/heatmap → Redis finance:heatmap │
│ GET /finance/news/AAPL → Redis finance:news:AAPL (или cold fill) │
└─────────────────────────────────────────────────────────────────────────┘
```
### Redis схема
| Ключ | Значение | TTL |
|------|----------|-----|
| `finance:summary` | Market data JSON | 5 min |
| `finance:heatmap` | Heatmap JSON | 5 min |
| `finance:news:AAPL` | News + summary | 15 min |
| `finance:news:TSLA` | News + summary | 15 min |
### Cold fill для редких тикеров
Skeleton heatmap/карточки; timeout 20 с.
Если запрос на `finance:news:XOM` — в кэше нет:
1. Выполнить запрос к API + суммаризацию
2. Сохранить в Redis
3. Отдать пользователю
---
## 3. Travel (Маршруты, тренды, Inspiration Cards)
### Архитектура
```
┌─────────────────────────────────────────────────────────────────────────┐
│ cache-worker (CronJob каждые 46 ч) — task=travel │
│ │
│ 1. Trending destinations → Redis travel:trending │
│ 2. Inspiration Cards (курируемые статьи) → Redis travel:inspiration │
│ Примеры: «Лучшие тропы в Словении», «Лесные отели в Швеции», │
│ «Скрытые пляжи Португалии» — LLM генерация/суммаризация batch │
│ 3. (Опционально) Pre-warm популярных маршрутов: Paris 5d, Tokyo 7d │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ travel-svc │
│ │
│ GET /travel/inspiration → Redis travel:inspiration (отдать сразу) │
│ GET /travel/trending → Redis travel:trending │
│ POST /travel/itinerary → hash → Redis или LLM │
└─────────────────────────────────────────────────────────────────────────┘
```
### Redis схема
| Ключ | Значение | TTL |
|------|----------|-----|
| `travel:trending` | Список направлений с картинками | 6 h |
| `travel:inspiration` | `[{ title, summary, image, url }]` — Inspiration Cards | 6 h |
| `travel:itinerary:{hash}` | Сгенерированный маршрут | 24 h |
### UX при cold start
- Skeleton trending/inspiration; itinerary: прогресс по этапам, 60 с timeout
### Реализация Inspiration Cards в cache-worker
```typescript
// cache-worker/src/tasks/travel.ts
export async function runTravelPrecompute(redis: Redis) {
const trending = await fetchTrendingDestinations();
await redis.setex('travel:trending', 6 * 60 * 60, JSON.stringify(trending));
const inspirationTopics = [
'best hiking trails Slovenia',
'forest hotels Sweden solitude',
'hidden beaches Portugal',
'weekend getaways Europe',
// ... курированный список тем
];
const inspiration = await Promise.all(
inspirationTopics.map(async (topic) => {
const article = await generateOrFetchArticle(topic); // LLM или партнёрский API
return { title: article.title, summary: article.summary, image: article.image, url: article.url };
})
);
await redis.setex('travel:inspiration', 6 * 60 * 60, JSON.stringify(inspiration));
}
---
## 4. Поиск (Search / Chat)
### Архитектура
```
┌─────────────────────────────────────────────────────────────────────────┐
│ chat-svc POST /api/v1/chat │
│ │
│ 1. query_normalized = normalize(query) // lowercase, trim, etc. │
│ 2. query_hash = sha256(query_normalized + mode + sources) │
│ 3. Redis GET search:result:{query_hash} │
│ 4. Если есть и не expired → отдать (stream из сохранённого или JSON) │
│ 5. Если нет → полный pipeline → сохранить в Redis → отдать │
└─────────────────────────────────────────────────────────────────────────┘
```
### Redis схема
| Ключ | Значение | TTL |
|------|----------|-----|
| `search:result:{query_hash}` | `{ text, sources, widgets }` | 1 h (Quick) / 24 h (Pro, если low churn) |
### UX при Pro/Deep
- AssistantSteps: отображение этапов (Classifier → Researcher → Writer); оценка времени
### Pre-warm популярных запросов
cache-worker раз в час:
1. Анализ логов/метрик: топ-50 запросов за последние 24ч (без user_id, только query)
2. Для каждого: проверка кэша, если нет — выполнить pipeline, сохранить
---
## 5. Медиа (Images, Videos)
```
query_hash = sha256(search_query)
Redis: media:images:{query_hash}, media:videos:{query_hash}
TTL: 1 h
```
Одинаковые запросы на картинки/видео отдаются из кэша.
### UX
- Skeleton grid; timeout 15 с; Retry при ошибке
---
## 6. Виджеты
| Виджет | Ключ кэша | TTL |
|--------|-----------|-----|
| Погода | `widget:weather:{location}` | 15 min |
| Акции | `widget:stock:{ticker}` | 5 min |
| Калькулятор | **Не кэшируем** — на клиенте |
---
## 7. Реализация cache-worker
### Задачи (tasks)
```typescript
// cache-worker/src/tasks/discover.ts
export async function runDiscoverPrecompute(redis: Redis) {
const topics = ['tech', 'finance', 'travel', 'world', 'science'];
for (const topic of topics) {
const items = await aggregateNews(topic);
const summarized = await summarizeBatch(items); // batch LLM call
await redis.setex(
`discover:${topic}`,
30 * 60, // 30 min
JSON.stringify({ items: summarized, updated_at: Date.now() })
);
}
}
// cache-worker/src/tasks/finance.ts
export async function runFinancePrecompute(redis: Redis) {
const summary = await fetchMarketSummary();
await redis.setex('finance:summary', 5 * 60, JSON.stringify(summary));
const heatmap = await fetchHeatmap();
await redis.setex('finance:heatmap', 5 * 60, JSON.stringify(heatmap));
const topTickers = ['AAPL', 'TSLA', 'GOOGL', 'MSFT', ...];
for (const ticker of topTickers) {
const news = await fetchNewsForTicker(ticker);
const summarized = await summarizeNews(news);
await redis.setex(
`finance:news:${ticker}`,
15 * 60,
JSON.stringify(summarized)
);
}
}
// cache-worker/src/tasks/travel.ts
export async function runTravelPrecompute(redis: Redis) {
const trending = await fetchTrendingDestinations();
await redis.setex('travel:trending', 6 * 60 * 60, JSON.stringify(trending));
}
```
### CLI
```bash
cache-worker --task=discover # только discover
cache-worker --task=finance # только finance
cache-worker --task=travel # trending + Inspiration Cards
cache-worker --task=all # все задачи
```
---
## 8. Метрики кэширования
| Область | Снижение LLM вызовов |
|---------|----------------------|
| Discover | ~6080% |
| Finance | ~6080% |
| Search | ~3050% |

View File

@@ -0,0 +1,212 @@
# Сверка логики страниц с Perplexity.ai
Соответствие архитектуры структуре Perplexity.ai (фев 2026).
---
## 1. Карта страниц Perplexity.ai
| URL | Страница | Описание (фактическая логика) |
|-----|----------|-------------------------------|
| `/` | Home | Главная: поисковая строка + виджеты discover/новости |
| `/search` / `/search/new?q=` | Search | Поисковый чат, Quick/Pro/Deep modes |
| `/c/[threadId]` | Chat/Thread | Окно конкретного чата/треда |
| `/finance` | Finance | Финансы: рынок, heatmap, вкладки |
| `/finance/[ticker]` | Ticker Detail | Детальная страница акции/индекса |
| `/finance/predictions/[id]` | Predictions | Prediction markets (Polymarket) |
| `/travel` | Travel | Путешествия: trending, inspiration, отели |
| `/discover` | Discover | Новости по темам (может быть часть Home) |
| `/library` | Library | История поисков, сохранённое |
| `/spaces` | Spaces | Список проектов/пространств |
| `/spaces/templates` | Space Templates | Шаблоны Spaces |
| `/collections/[id]` | Collections | Публичные коллекции (SEC, Buffett и т.д.) |
| Profile/Settings | Account | Профиль, настройки, биллинг |
---
## 2. Finance (`/finance`) — детальная сверка
### Perplexity (фактически)
| Элемент | Есть в Perplexity | Есть в архитектуре |
|--------|-------------------|---------------------|
| Вкладки: Crypto, Earnings, Predictions, Screener, Politicians Watchlist, Watchlist | ✅ | ✅ (roadmap 2.1) |
| Index Movement (S&P Futures, NASDAQ Fut., Dow Futures, VIX) | ✅ | ✅ |
| Market Summary + новости (обновление ~4 мин) | ✅ | ✅ |
| S&P 500 Heatmap (секторы, акции) | ✅ | ✅ |
| Recent Developments (новости с таймстампами) | ✅ | ✅ |
| Popular Spaces for Finance Research (collections) | ✅ | ✅ **Collections** по категории, `GET /collections?category=finance` |
| Standouts (акция с анализом) | ✅ | ✅ (roadmap 2.1) |
| Create Watchlist | ✅ | ✅ |
| Prediction Markets (Polymarket) | ✅ | ✅ |
| Gainers / Losers / Active | ✅ | ✅ |
| Equity Sectors | ✅ | ✅ |
| Popular Cryptocurrencies | ✅ | ✅ |
| Fixed Income (TIPS, Treasuries, Municipals) | ✅ | ✅ |
| Источники: FMP, Unusual Whales, Quartr, Fiscal.ai, S&P Global | ✅ | ✅ (roadmap) |
| Детальная страница тикера `/finance/AAPL` | ✅ | ✅ |
---
## 3. Travel (`/travel`) — детальная сверка
### Perplexity (фактически, 2025)
| Элемент | Есть в Perplexity | Есть в архитектуре |
|--------|-------------------|---------------------|
| Trending Destinations (карточки с изображениями) | ✅ | ✅ |
| Inspiration Cards (курируемые статьи) | ✅ | ✅ **travel:inspiration**, cache-worker, `GET /travel/inspiration` |
| Поиск мест, генерация маршрутов | ✅ | ✅ |
| Отели (Tripadvisor) | ✅ | ✅ |
| Партнёрское бронирование (Selfbook) | ✅ | ✅ Tripadvisor, Selfbook в 01-perplexity-analogue-design |
| Answer Modes — Travel vertical | ✅ | ✅ **answerMode: 'travel'** в chat-svc, отдельный системный промпт |
| Stepper UI (Поиск → Места → Маршрут → Отели → Билеты) | ? | ✅ |
| Агентский ассистент (реал-тайм) | ✅ | ✅ |
---
## 4. Discover / Home
### Perplexity
- **Home** — поиск + виджеты (discover-лента новостей по темам).
- **Discover** может быть отдельной страницей или встроена в Home.
### Архитектура
- discover-svc, GET /discover?topic=
- Home: виджеты discover/news
- Pre-compute, Redis кэш
---
## 5. Spaces / Projects / Collections
### Perplexity
| Концепт | Описание |
|--------|----------|
| **Spaces** | Приватные/шарируемые проекты, файлы, чаты |
| **Collections** | Публичные шаблоны (SEC Findings, Buffett letters, S&P 500 Transcripts) |
| **Space Templates** | Готовые Spaces под финансы, маркетинг, продукт, travel |
### Архитектура
- Projects/Spaces
- Space Templates
- Collections: projects-svc, GET /collections?category=, GET /collections/:id
---
## 6. Library
### Perplexity
- История поисков
- Сохранённое (saved threads?)
### Архитектура
- Гости: localStorage/IndexedDB, при закрытии теряется
- Аккаунты: library-svc, PostgreSQL, синхронизация тредов
---
## 7. Profile / Account
### Perplexity
- Account, Preferences, Personalize, Billing, Connectors
- Appearance, Language, Autosuggest, Homepage widgets
- My Connectors (интеграции)
### Архитектура
- Профиль, биллинг
- Preferences: localStorage (гости) + сервер (аккаунты)
- My Connectors: GET/POST/DELETE /api/v1/connectors
---
## 8. Поиск (Search) и режимы
### Perplexity
- **Quick Search** — быстрый ответ
- **Pro Search** — многошаговый, прозрачные шаги
- **Deep Research** — углублённый отчёт
- **Focus** — режим без отвлечений
- **Answer Modes** — Standard, Academic, Writing, etc. + вертикали (Travel)
### Архитектура
- Quick, Pro, Deep Research
- Answer Modes: Standard, Focus, Academic, Writing, Travel, Finance (answerMode в body)
---
## 9. Покрытие фич Perplexity 20252026
По данным [Perplexity Changelog](https://www.perplexity.ai/changelog/). Все перечисленные фичи **добавлены в архитектуру** (01, 02, [06-roadmap-specification](./06-roadmap-specification.md)).
### 9.1 Поиск и ответы ✅
| Фича Perplexity | В архитектуре |
|-----------------|---------------|
| **Model Council** — запуск 3 моделей параллельно | ✅ §2.2.A, §5.14, фаза 7 (Max) |
| **Step-by-step Learning** | ✅ chat-svc, learningMode, §2.2.A, §2.2.P, input bar «+» |
| **Response preferences** | ✅ answerMode + responsePrefs в body, Preferences |
| **Memory** | ✅ memory-svc, §2.2.K, GET/POST/DELETE /api/v1/memory |
| **Input bar «+»** | ✅ UI: файлы, источники, режимы (Quick/Pro/Deep/Create/Learn) |
### 9.2 Генерация и Create ✅
| Фича Perplexity | В архитектуре |
|-----------------|---------------|
| **Labs / Create** | ✅ create-svc, §2.2.L, POST /api/v1/create |
| **Image generation** | ✅ create-svc, type: 'image' |
| **Экспорт** | ✅ POST /api/v1/export, форматы xlsx/csv/md/pdf |
### 9.3 Finance ✅
| Фича Perplexity | В архитектуре |
|-----------------|---------------|
| **Analyst ratings** | ✅ GET /api/v1/finance/analyst-ratings/:ticker |
| **Auditable financials / SEC** | ✅ GET /api/v1/finance/sec-filings/:ticker |
| **ETF Holdings** | ✅ GET /api/v1/finance/etf-holdings/:symbol |
| **Heatmap hover** | ✅ GET /api/v1/finance/price-context/:ticker |
| **Stock graphs** в ответах | ✅ finance-svc, §2.2.C |
### 9.4 Commerce и Shopping
| Фича Perplexity | В архитектуре |
|-----------------|---------------|
| **Instant Buy / PayPal** | Отложен (низкий приоритет) |
| **Virtual Try On** | Отложен |
| **Shopping** | Отложен |
### 9.5 Продукты и платформы ✅
| Фича Perplexity | В архитектуре |
|-----------------|---------------|
| **Comet AI Browser** | Отдельный продукт, вне scope |
| **Desktop app** | ✅ §1 карта страниц, фаза 6, Electron/Tauri |
| **iOS / Android** | ✅ фаза 6, voice search |
| **Chrome extension** | ✅ фаза 6 |
| **Voice search** | ✅ §2.2.O, Web Speech API / native |
| **Background Assistant** | ✅ §2.2.O.4, POST /api/v1/tasks, фаза 7 (Max) |
### 9.6 Образование ✅
| Фича Perplexity | В архитектуре |
|-----------------|---------------|
| **Quizzes / Flashcards** | ✅ §2.2.P, Pro/Education |
| **Education Pro** | ✅ roadmap 7.1 |
### 9.7 Прочие страницы ✅
| Фича Perplexity | В архитектуре |
|-----------------|---------------|
| **Patents page** `/patents` | ✅ §2.2.M, GET /api/v1/patents, search-svc |
| **Персональные хабы** | Коллекции по категории (расширяемо) |
| **Export thread** | ✅ POST /library/threads/:id/export (PDF, MD) |
| **Notifications** | ✅ notifications-svc, Web Push, Email, напоминания |
| **PWA / Офлайн** | ✅ Service worker (Workbox), manifest, offline fallback |
### 9.8 Enterprise ✅
| Фича Perplexity | В архитектуре |
|-----------------|---------------|
| **Audit logs** | ✅ audit-svc, GET /api/v1/admin/audit-logs |
| **Granular feature access** | ✅ §2.2.N |
| **Domain-based sign-up** | ✅ auth-svc, §2.2.N |
| **Usage guidelines** | ✅ §2.2.N |
| **Enterprise Memory** | ✅ memory-svc, org_id |

View File

@@ -0,0 +1,108 @@
# Production checklist и требования
## 0. Узкие места и митигации
| Область | Узкое место | Митигация (внедрено/требуется) |
|---------|-------------|---------------------------------|
| **Пользователь** | Холодный старт 530 с | Skeleton, timeout, Retry — см. §8 UI/UX |
| **Пользователь** | Загрузка файлов 30300 с | Прогресс по этапам + кнопка Cancel; pre-upload preview |
| **Пользователь** | Гости: история теряется | Предупреждение при закрытии; CTA «Сохранить в аккаунт» |
| **Пользователь** | Rate limit 300 Pro Search/день | 429 + предупреждение при 80%; предложение апгрейда |
| **Инфраструктура** | SearXNG — единый инстанс | Очередь запросов в search-svc; при росте — пул инстансов |
| **Инфраструктура** | cache-worker зависает | `activeDeadlineSeconds` во всех CronJob (520 мин) |
| **Инфраструктура** | Redis/PostgreSQL без HA | Sentinel/Cluster и Read replica при масштабировании |
| **Инфраструктура** | travel-svc без HPA | HPA 14 replicas добавлен в 02-k3s-microservices-spec |
| **Функции** | Внешние API (LLM, FMP, TA) | Retry + circuit breaker; fallback при частичном сбое |
## 1. Инфраструктура
| Компонент | Helm chart | Namespace |
|-----------|------------|-----------|
| Redis | bitnami/redis | perplexica-infra |
| PostgreSQL | bitnami/postgresql | perplexica-infra |
| MinIO | bitnami/minio | perplexica-infra |
| SearXNG | Deployment | perplexica-infra |
## 2. Secrets
- notifications-secrets (vapid_public, vapid_private, smtp_url)
- redis-credentials (url)
- db-credentials (url)
- auth-secrets (jwt_secret)
- llm-credentials (openai)
- finance-keys (fmp)
- travel-keys (tripadvisor)
- yookassa-credentials (shop_id, secret)
## 3. Сетевые политики (NetworkPolicy)
- Ingress: только из ingress-controller
- chat-svc → search-svc, Redis
- cache-worker → Redis, discover-svc, finance-svc, travel-svc
- Redis, PostgreSQL: без внешнего доступа
## 4. PodDisruptionBudget
Минимум 2 доступных пода для: chat-svc, search-svc.
## 5. Observability
- Prometheus: метрики `/metrics` из каждого сервиса
- Grafana: дашборды
- Structured JSON логи
- OpenTelemetry/Jaeger: распределённые трейсы
- Алерты: latency, error rate, availability
## 6. Резервирование и масштабирование
| Область | Решение |
|---------|---------|
| chat-svc | HPA, кэш по query_hash |
| Redis | Sentinel / Cluster при росте |
| PostgreSQL | Read replica, PgBouncer |
| SearXNG | Очередь запросов в search-svc/media-svc; кэш media; при росте — пул инстансов |
| cache-worker | Ограничение concurrency, batch size; `activeDeadlineSeconds` для защиты от зависаний |
## 7. Безопасность
- CORS: ограничить Access-Control-Allow-Origin
- Rate limiting: API Gateway / Ingress
- TLS (cert-manager / Let's Encrypt)
- Retry + circuit breaker для внешних API (FMP, Tripadvisor, LLM)
## 8. UI/UX
| Компонент | Требование |
|-----------|------------|
| Discover, Finance, Travel | Skeleton при cold start; timeout; Retry |
| Pro/Deep Search | Этапы (Classifier → Researcher → Writer); оценка времени |
| Загрузка файлов | Прогресс по этапам: парсинг → chunking → эмбеддинги; кнопка Cancel; timeout 300 с |
| Гости | Предупреждение при закрытии; CTA «Сохранить в аккаунт» для переноса истории |
| Rate limit | 429 + предупреждение при 80% лимита; предложение апгрейда при достижении лимита |
| Ошибки | Сообщение + Retry/Cancel |
| Travel Stepper | Сохранение состояния; skeleton между шагами |
| Медиа | Skeleton grid; 15 с timeout |
## 9. Чек-лист развёртывания
- [ ] Ingress path-based routing
- [ ] Probes /health, /ready во всех сервисах
- [ ] HPA: chat-svc, search-svc, discover-svc, finance-svc, travel-svc, upload-svc, memory-svc
- [ ] Redis, PostgreSQL, MinIO, SearXNG
- [ ] Secrets
- [ ] TLS
- [ ] Rate limiting
- [ ] Prometheus + алерты
- [ ] Backup PostgreSQL, MinIO
- [ ] PDB для chat-svc, search-svc
- [ ] Runbook оператора
- [ ] UI/UX: skeleton, timeout, rate limit feedback, guest warning, file upload progress+cancel
## 10. Ссылки (внутри architecture)
- [04-pages-logic-verification.md §9](./04-pages-logic-verification.md#9-покрытие-фич-perplexity-20252026) — покрытие vs Perplexity 2026
- [06-roadmap-specification.md](./06-roadmap-specification.md) — roadmap и спеки фич
- [01-perplexity-analogue-design.md](./01-perplexity-analogue-design.md)
- [02-k3s-microservices-spec.md](./02-k3s-microservices-spec.md)
- [03-cache-and-precompute-strategy.md](./03-cache-and-precompute-strategy.md)
- [04-pages-logic-verification.md](./04-pages-logic-verification.md)

View File

@@ -0,0 +1,63 @@
# Roadmap и спецификация фич
**docs/architecture — самодостаточный проект.** Все спеки фич находятся здесь. Порядок реализации — в [01-perplexity-analogue-design.md §6](./01-perplexity-analogue-design.md#6-порядок-реализации-best-practices).
---
## 1. Спецификация фич (детали)
Все пункты определены в [01-perplexity-analogue-design.md](./01-perplexity-analogue-design.md), [02-k3s-microservices-spec.md](./02-k3s-microservices-spec.md), [04-pages-logic-verification.md §9](./04-pages-logic-verification.md#9-покрытие-фич-perplexity-20252026).
### 1.1 Memory (memory-svc)
- **Сервис:** memory-svc, порт 3010
- **Хранение:** PostgreSQL (user_id, org_id, key, value, embedding)
- **API:** GET/POST/DELETE /api/v1/memory
- **Фаза:** 5
### 1.2 Create / Labs (create-svc)
- **API:** POST /api/v1/create, POST /api/v1/export
- **Фаза:** 5
### 1.3 Finance расширения
- analyst-ratings, sec-filings, etf-holdings, price-context
- **Фаза:** 5
### 1.4 Patents, Enterprise, Step-by-step Learning
- **Фаза:** 56
### 1.5 Export thread
- **API:** POST /api/v1/library/threads/:id/export?format=pdf|md
- **Фаза:** 7
### 1.6 Notifications (notifications-svc)
- **Сервис:** notifications-svc, порт 3013
- **Web Push, Email, напоминания**
- **Фаза:** 7
### 1.7 PWA / Офлайн
- Service worker (Workbox), manifest, offline fallback
- **Фаза:** 7
### 1.8 Model Council (Max)
- modelCouncil: true в POST /api/v1/chat
- **Фаза:** 7
### 1.9 Background Assistant (Max)
- POST /api/v1/tasks, GET /api/v1/tasks/:id
- **Фаза:** 7
---
## 2. Связь с functional-inventory
**docs/functional-inventory** — описание **текущего** кода Perplexica (инвентаризация).
**docs/architecture** — целевая архитектура (что строить).
При миграции можно сопоставлять 01-api-routes → новые сервисы, 05-agents → Mastra и т.д. Правки в architecture **не требуют** правок в functional-inventory.
---
## Ссылки
- [Perplexity Changelog](https://www.perplexity.ai/changelog/)
- [ЮKassa](https://yookassa.ru/developers/payments/recurring-payments)

View File

@@ -1,406 +0,0 @@
# Архитектура микросервисов GooSeek
Документ описывает план разбиения монолитного приложения GooSeek на микросервисы.
---
## 1. Текущая архитектура (монолит)
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Next.js Application (monolith) │
├─────────────────────────────────────────────────────────────────────────────┤
│ API Routes │ Agents/Search │ Models/Providers │ Data │
│ /api/chat │ classifier │ OpenAI, Anthropic │ SQLite│
│ /api/search │ researcher │ Ollama, Groq... │ config│
│ /api/images │ widgets │ registry │ uploads│
│ /api/videos │ writer │ │ │
│ /api/uploads │ media (image/video) │ │ │
│ /api/chats │ │ │ │
│ /api/providers │ │ │ │
│ /api/config │ │ │ │
│ /api/suggestions │ │ │ │
│ /api/weather │ │ │ │
│ /api/discover │ │ │ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ External: SearXNG │ Yahoo Finance │ Open-Meteo │ LLM APIs (OpenAI, etc.) │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## 2. Предлагаемые микросервисы
### 2.1 Общая схема
```
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Frontend │────▶│ Gateway │────▶│ Chat │────▶│ Research │
│ (Next.js) │ │ (BFF/API) │ │ Service │ │ Service │
└──────────────┘ └──────────────┘ └──────┬───────┘ └──────┬───────┘
│ │ │ │
│ │ │ │
│ ▼ ▼ ▼
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ │ Config/Chats │ │ LLM Proxy │ │ Search │
└────────────▶│ Service │ │ Service │ │ Service │
└──────────────┘ └──────────────┘ └──────┬───────┘
│ │ │
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Storage │ │ Providers │ │ Uploads │
│ Service │ │ (external) │ │ Service │
└──────────────┘ └──────────────┘ └──────────────┘
```
---
## 3. Описание сервисов
### 3.1 Frontend (Next.js UI)
**Назначение:** Только UI — страницы, компоненты, клиентский state.
**Содержимое:**
- `src/app/page.tsx`, `layout.tsx`, маршруты страниц
- `src/components/` — все UI компоненты
- `src/lib/hooks/` — клиентские хуки
- `src/lib/actions.ts` — вызовы к Gateway API
**Исключить:** Все API routes (`src/app/api/`), серверная логика агентов, прямые вызовы DB.
**API:** Вызывает только Gateway.
---
### 3.2 Gateway (Backend-for-Frontend / API Gateway)
**Назначение:** Единая точка входа для клиента, роутинг, валидация, агрегация.
**Реализация:** Отдельный Node.js сервис (Fastify/Express) или часть Next.js API routes, которая только проксирует.
**Маршруты:**
- `POST /api/chat` → Chat Service
- `POST /api/search` → Chat Service (API mode)
- `GET/POST /api/chats/*` → Storage Service
- `POST /api/uploads` → Uploads Service
- `GET/POST /api/providers/*` → Config + LLM Proxy
- `GET/POST /api/config/*` → Storage Service (config)
- `POST /api/suggestions` → Chat Service
- `POST /api/images` → Chat/Media Service
- `POST /api/videos` → Chat/Media Service
- `GET /api/weather` → Widgets Service (или inline)
- `POST /api/discover` → Search Service
**Зависимости:** Chat, Storage, Uploads, Search. Не содержит бизнес-логики.
---
### 3.3 Chat Service (Оркестратор)
**Назначение:** Главный оркестратор диалога: классификация, планирование, вызов research и writer.
**Исходники:**
- `src/lib/agents/search/index.ts` — SearchAgent
- `src/lib/agents/search/api.ts` — APISearchAgent
- `src/lib/agents/search/classifier.ts`
- `src/lib/agents/search/widgets/` — executor + виджеты (weather, stock, calc)
- `src/lib/prompts/search/` — classifier, writer, researcher prompts
- `src/lib/session.ts`
**API (внутренние):**
- `POST /classify` — классификация запроса
- `POST /search` — полный пайплайн (classify → research → widgets → write)
- `POST /suggestions` — генерация подсказок
**Вызывает:**
- Research Service — для поиска
- LLM Proxy — для LLM вызовов (classify, write, suggestions)
- Widgets (внешние API: Yahoo Finance, погода) — можно вынести в отдельный сервис
**Поток данных:**
1. Классификация (LLM)
2. Параллельно: Research Service + виджеты
3. Генерация ответа (LLM)
4. Сохранение в Storage (через Gateway или напрямую)
---
### 3.4 Research Service
**Назначение:** Выполнение исследовательского цикла — tools (web, academic, social, scrape, uploads).
**Исходники:**
- `src/lib/agents/search/researcher/` — Researcher, ActionRegistry
- `src/lib/agents/search/researcher/actions/` — webSearch, academicSearch, socialSearch, scrapeURL, uploadsSearch, plan, done
- `src/lib/prompts/search/researcher.ts`
**API:**
- `POST /research` — вход: classification, query, chatHistory, config → выход: searchFindings, findings
**Вызывает:**
- Search Service — SearXNG (web, academic, social)
- Uploads Service — семантический поиск по файлам
- LLM Proxy — для researcher agent (tool calls)
- Внешние URL — scrape
**Важно:** Researcher — это LLM-driven agent с tool calls. LLM решает, какой tool вызвать. Либо LLM живёт в Chat Service и вызывает tools по HTTP, либо Research Service сам держит копию researcher LLM — тогда нужно дублировать LLM-вызовы.
**Рекомендация:** Оставить researcher внутри Chat Service, а в Research Service вынести только **действия** (web search, scrape, uploads search) как отдельные HTTP endpoints. Chat Service вызывает Research Service по каждому tool call. Это уменьшает связанность, но увеличивает сетевые вызовы.
**Альтернатива:** Research как один сервис с LLM — получает query и classification, сам итерирует и возвращает готовые findings. Меньше round-trips, но дублирование LLM-инфраструктуры.
---
### 3.5 Search Service (SearXNG + обёртка)
**Назначение:** Обёртка над SearXNG для веб/академического/медиа поиска.
**Исходники:**
- `src/lib/searxng.ts`
- Вызовы: webSearch, academicSearch, socialSearch, image, video — все идут через `searchSearxng`
**API:**
- `GET /search?q=...&engines=...&categories=...`
- `GET /images?q=...`
- `GET /videos?q=...`
**Внешняя зависимость:** SearXNG (уже отдельный сервис/контейнер).
**Реализация:** Минимальный Node.js/Fastify сервис, который проксирует к SearXNG и добавляет логику (rate limiting, fallback, кэш).
---
### 3.6 Uploads Service
**Назначение:** Загрузка файлов, парсинг (PDF, DOCX, TXT), эмбеддинги, семантический поиск.
**Исходники:**
- `src/lib/uploads/manager.ts` — UploadManager
- `src/lib/uploads/store.ts` — UploadStore (поиск по эмбеддингам)
- `src/lib/utils/splitText.ts`, `computeSimilarity.ts`
- Зависимости: pdf-parse, officeparser
**API:**
- `POST /upload` — multipart, возвращает fileIds
- `POST /search` — query, fileIds → chunks (семантический поиск)
- `GET /files/:id` — метаданные файла
**Вызывает:** LLM Proxy — только для embedding модели (можно вынести в отдельный Embedding Service).
**Хранение:** Файлы на диске/volume, `uploaded_files.json`, `.content.json` с chunks.
---
### 3.7 Storage Service
**Назначение:** Централизованное хранилище: чаты, сообщения, конфигурация.
**Исходники:**
- `src/lib/db/` — schema, migrations, drizzle
- `src/lib/config/` — ConfigManager, modelProviders
**API:**
- `GET/POST/PUT/DELETE /chats`
- `GET/POST/PUT/DELETE /chats/:id`
- `GET/POST/PUT/DELETE /messages`
- `GET/POST /config`
- `GET/POST /config/providers`
**База:** SQLite (или PostgreSQL при масштабировании). config.json можно мигрировать в ту же БД или отдельную таблицу.
---
### 3.8 LLM Proxy Service (опционально)
**Назначение:** Единая точка для вызовов LLM и embedding — OpenAI, Anthropic, Ollama, Groq, Gemini и т.д.
**Исходники:**
- `src/lib/models/` — registry, providers, base LLM/Embedding
**API:**
- `POST /chat` — text generation (streaming)
- `POST /embed` — embedding
- `GET /providers` — список провайдеров и моделей
**Конфигурация:** Берёт из Storage Service (config/providers) или env.
**Альтернатива:** LLM Proxy можно не выделять в отдельный сервис — каждый сервис (Chat, Research, Uploads) сам подключается к провайдерам. Но тогда дублирование кода и конфигурации. Рекомендуется вынести в общую библиотеку или отдельный сервис.
---
### 3.9 Geo Device Service (реализован)
**Назначение:** Определение геопозиции пользователя, типа устройства, браузера и ОС.
**Расположение:** `apps/geo-device-service/`
**API:**
- `GET /api/context` — контекст по IP и заголовкам (User-Agent, Accept-Language)
- `POST /api/context` — контекст с дополнительными данными от клиента (screen, timezone, Geolocation API)
**Данные:**
- **geo** — latitude, longitude, city, country, timezone (geoip-lite по IP или из body)
- **device** — type (desktop/mobile/tablet), vendor, model
- **browser** — name, version (ua-parser-js)
- **os** — name, version
- **client** — screenWidth, viewportHeight, timezone, language, hardwareConcurrency, deviceMemory, doNotTrack (из POST body)
**Запуск:** `npm run dev:geo` или `PORT=4002 npm run start -w geo-device-service`
**Интеграция:** Frontend вызывает `/api/geo-context` (проксирует к сервису), клиент — `fetchContextWithClient()` из `@/lib/geoDevice`.
---
### 3.10 Localization Service (реализован)
**Назначение:** Локализация на основе геопозиции. Определяет locale (язык) пользователя по данным из Geo Device Service.
**Расположение:** `apps/localization-service/`
**Зависимость:** Geo Device Service (вызывает `/api/context` для получения countryCode, client.language, Accept-Language).
**API:**
- `GET /api/locale` — resolve locale по IP/заголовкам (гео через geo-device-service)
- `POST /api/locale` — resolve locale с client data (screen, language, geo)
- `GET /api/translations/:locale` — переводы для UI
- `GET /api/locales` — список поддерживаемых локалей
**Данные (LocalizationContext):**
- **locale** — BCP 47 language code (ru, en, de, ...)
- **source** — geo | accept-language | client | fallback
**Приоритет определения locale:**
1. client.language (браузер navigator.language)
2. Accept-Language заголовок
3. countryCode из геопозиции
4. fallback: en
**Запуск:** `npm run dev:locale` или `PORT=4003 npm run start -w localization-service`
**Конфигурация:** `GEO_DEVICE_SERVICE_URL` — URL geo-device-service (по умолчанию http://localhost:4002)
**Интеграция:** Frontend вызывает `/api/locale`, `/api/translations/[locale]` (проксирует к сервису), клиент — `fetchLocaleWithClient()`, `fetchTranslations()` из `@/lib/localization`.
---
## 4. Матрица зависимостей
| Сервис | От кого получает вызовы | Кого вызывает |
|----------------|----------------------------------|----------------------------------|
| Gateway | Frontend | Chat, Storage, Uploads, Search |
| Localization | Frontend | Geo Device Service |
| Geo Device | Frontend, Localization | — |
| Chat | Gateway | Research, LLM Proxy, Storage |
| Research | Chat | Search, Uploads, LLM Proxy |
| Search | Research, Chat (media) | SearXNG (внешний) |
| Uploads | Gateway, Research | LLM Proxy (embedding) |
| Storage | Gateway, Chat | — |
| LLM Proxy | Chat, Research, Uploads | OpenAI, Anthropic, Ollama... |
---
## 5. Разбиение по репозиториям/папкам
### Вариант A: Монорепо (рекомендуется для старта)
```
gooseek/
├── apps/
│ ├── frontend/ # Next.js UI
│ ├── gateway/ # BFF / API Gateway
│ ├── chat-service/ # SearchAgent, classifier, writer, widgets
│ ├── research-service/ # Researcher, actions
│ ├── search-service/ # SearXNG wrapper
│ ├── uploads-service/ # UploadManager, UploadStore
│ ├── storage-service/ # DB, config
│ ├── llm-proxy/ # Models registry, providers
│ ├── geo-device-service/ # Геопозиция, устройство, браузер
│ ├── localization-service/ # Локализация (зависит от geo-device)
│ ├── shared-types/ # Общие типы, DTO
│ └── shared-utils/ # formatHistory, splitText, computeSimilarity
├── docker-compose.yaml
└── package.json # Turborepo/nx workspace
```
### Вариант B: polyrepo
Отдельные репозитории для каждого сервиса. Больше гибкости в деплое, но сложнее координация изменений.
---
## 6. Порядок миграции (фазы)
### Фаза 1: Выделение Search Service
- Обернуть SearXNG в отдельный сервис
- Chat/Research вызывают его по HTTP вместо прямого импорта `searchSearxng`
- **Риск:** Низкий. SearXNG уже внешний.
### Фаза 2: Выделение Storage Service
- Вынести DB + config в отдельный сервис
- Gateway и Chat переходят на HTTP к Storage
- **Риск:** Средний. Много точек входа в DB.
### Фаза 3: Выделение Uploads Service
- Вынести UploadManager + UploadStore
- Research (uploadsSearch action) и Gateway вызывают Uploads по HTTP
- **Риск:** Средний. Embedding модель — зависимость.
### Фаза 4: Выделение LLM Proxy
- Общая обёртка над провайдерами
- Chat, Research, Uploads вызывают LLM Proxy
- **Риск:** Высокий. Много мест используют LLM напрямую.
### Фаза 5: Выделение Research Service
- Researcher + actions в отдельный сервис
- Chat вызывает Research по одному endpoint «проведи исследование»
- **Риск:** Высокий. Тесная связь с Session, streaming.
### Фаза 6: Gateway + развязка Frontend
- Frontend только UI, все вызовы через Gateway
- Gateway — тонкий роутер без бизнес-логики
- **Риск:** Средний. Рефакторинг API routes.
---
## 7. Ключевые вызовы и риски
1. **Streaming:** Текущий chat stream идёт от SearchAgent до клиента. При разбиении нужно решить: стримить через Gateway (proxy) или от Chat Service напрямую (WebSocket/SSE через Gateway как туннель).
2. **Session/state:** SessionManager — in-memory. При масштабировании Chat Service нужен Redis или аналог для shared state.
3. **Латентность:** Каждый HTTP hop добавляет ~1050ms. Research делает много итераций — если Research в отдельном сервисе, round-trips умножаются.
4. **Embedding в Uploads:** Uploads нужна embedding модель. Варианты: вызывать LLM Proxy, или держать тяжёлую модель (transformers) внутри Uploads.
5. **Конфигурация:** Сейчас config.json на диске. При микросервисах — централизованный config (env, vault, или Storage Service).
---
## 8. Минимальный MVP разбиения
Если цель — не полный microservices, а **модульность и возможность деплоить части отдельно**:
| Сервис | Код | Отдельный процесс |
|---------------|-----------------------------|-------------------|
| **search-api**| `searxng.ts` + route | Да (отдельный порт) |
| **uploads-api**| `uploads/` + route | Да |
| **chat** | Всё остальное (agents, LLM, DB) | Один процесс |
| **frontend** | Next.js UI | Отдельно (static/SSR) |
Так получается 34 контейнера вместо 1, но без глубокой декомпозиции логики.
---
## 9. Следующие шаги
1. Определить: полное разбиение или MVP.
2. Выбрать стек для каждого сервиса (Node.js/Fastify, Next.js API routes, Go и т.д.).
3. Описать контракты API (OpenAPI/JSON Schema) для межсервисного взаимодействия.
4. Настроить docker-compose для локальной разработки.
5. Внедрить общие пакеты (shared-types, shared-utils) в монорепо.
6. Начать с Фазы 1 (Search Service) как пилот.

View File

@@ -0,0 +1,129 @@
# Миграция GooSeek на микросервисную архитектуру
**Ссылки:** [01-perplexity-analogue-design.md](./01-perplexity-analogue-design.md), [02-k3s-microservices-spec.md](./02-k3s-microservices-spec.md)
---
## Текущий статус
### Реализовано (Фаза 02)
| Компонент | Описание | Статус |
|-----------|----------|--------|
| **services/discover-svc** | Агрегация новостей, Redis кэш | ✅ |
| **services/search-svc** | SearXNG proxy, кэш по query_hash | ✅ |
| **services/finance-svc** | Market summary, heatmap, news (базово) | ✅ |
| **services/travel-svc** | Trending, Inspiration (базово) | ✅ |
| **services/cache-worker** | Pre-compute: discover, finance, travel | ✅ |
| **Redis, PostgreSQL** | Локально или в K8s (см. deploy/k3s) | ✅ |
| **api/v1/discover** | Прокси к discover-svc | ✅ |
| **services/library-svc** | История тредов (PostgreSQL) | ✅ |
| **services/projects-svc** | Collections, Spaces (заглушка) | ✅ |
| **api/v1/library** | Прокси к library-svc | ✅ |
| **api/v1/collections** | Прокси к projects-svc | ✅ |
| **deploy/k3s/** | library-svc, projects-svc, chat-svc, ingress | ✅ |
| **services/chat-svc** | LLM, Mastra, Writer, Classifier, Researcher | ✅ |
| **api/chat** | При CHAT_SVC_URL проксирует на chat-svc | ✅ |
| **services/auth-svc** | SSO, JWT, Bearer, GET /api/auth/me (миграция из apps/auth-mcs) | ✅ |
| **services/memory-svc** | Персональная память AI, Enterprise Memory | ✅ |
| **api/v1/memory** | Прокси к memory-svc | ✅ |
| **services/create-svc** | Create (stub), Export PDF/MD | ✅ |
| **api/v1/create, api/v1/export** | Прокси к create-svc | ✅ |
| **finance-svc** | + analyst-ratings, sec-filings, etf-holdings (FMP) | ✅ |
| **search-svc** | + GET /api/v1/patents (SearXNG) | ✅ |
| **api/v1/patents** | Прокси к search-svc | ✅ |
| **services/notifications-svc** | Web Push, preferences, reminders | ✅ |
| **api/v1/notifications** | Прокси к notifications-svc | ✅ |
| **services/billing-svc** | Тарифы Free/Pro/Max, ЮKassa, подписки | ✅ |
| **api/v1/billing** | Прокси к billing-svc | ✅ |
| **services/audit-svc** | Enterprise audit logs (stub) | ✅ |
| **api/v1/admin/audit-logs** | Прокси к audit-svc | ✅ |
| **страница /profile** | Account, Preferences, Personalize, Billing, Connectors | ✅ |
| **services/auth-svc** | SSO, JWT, Bearer, GET /api/auth/me | ✅ |
| **services/web-svc** | UI + прокси (миграция из apps/frontend) | ✅ |
| **services/geo-device-svc** | Геопозиция, устройство | ✅ |
| **services/localization-svc** | Локализация | ✅ |
### В разработке / запланировано
- **Миграция apps → services завершена:** auth-svc, web-svc, geo-device-svc, localization-svc в services/
- **API Gateway** (Traefik/Kong) для production
### deploy/k3s — HPA и PDB
| Файл | Описание |
|------|----------|
| hpa.yaml | HPA для chat-svc, search-svc, discover-svc, finance-svc; PDB для chat, search |
---
## Запуск (только Kubernetes)
Развёртывание в Kubernetes (Docker Desktop → Settings → Kubernetes, не Docker-контейнеры):
```bash
./deploy/k3s/deploy.sh
```
Конфигурация сервисов: `deploy/k3s/deploy.config.yaml`. Миграции БД выполняются автоматически при деплое.
---
## Переменные окружения
| Переменная | Описание | По умолчанию |
|------------|----------|--------------|
| `REDIS_URL` | Redis connection string | `redis://localhost:6379` |
| `SEARXNG_URL` | SearXNG instance | `https://searx.tiekoetter.com` |
| `SEARXNG_FALLBACK_URL` | Доп. инстансы (через запятую) | — |
| `DISCOVER_SVC_URL` | discover-svc (для frontend proxy) | `http://localhost:3002` |
| `SEARCH_SVC_URL` | search-svc — при установке frontend вызывает его вместо прямого SearXNG | `http://localhost:3001` |
| `CHAT_SVC_URL` | chat-svc — при установке /api/chat проксирует сюда | `http://localhost:3005` |
| `MEMORY_SVC_URL` | memory-svc (персональная память AI) | `http://localhost:3010` |
| `CREATE_SVC_URL` | create-svc (Create, Export) | `http://localhost:3011` |
| `NOTIFICATIONS_SVC_URL` | notifications-svc (Web Push, reminders) | `http://localhost:3013` |
| `BILLING_SVC_URL` | billing-svc (тарифы, подписки, ЮKassa) | `http://localhost:3008` |
| `AUTH_SERVICE_URL` | auth-svc (Bearer validation) | `http://localhost:3014` |
| `GHOST_URL`, `GHOST_CONTENT_API_KEY` | Ghost для topic=gooseek (discover-svc) | — |
| `NEWS_REGION` | Регион новостей: america\|eu\|russia\|china\|auto | `auto` |
| `FMP_API_KEY` | Financial Modeling Prep (finance summary, analyst-ratings, sec-filings, etf-holdings) | — |
| `YOOKASSA_SHOP_ID`, `YOOKASSA_SECRET` | ЮKassa для billing-svc (оплата Pro/Max) | — |
| `BILLING_RETURN_URL` | URL возврата после оплаты | `http://localhost:3000/profile?tab=billing` |
| `POSTGRES_URL` | PostgreSQL (library-svc, memory-svc, notifications-svc, billing-svc) | `postgresql://gooseek:gooseek@localhost:5432/gooseek` |
---
## Сборка Docker-образов
```bash
# discover-svc, search-svc, notifications-svc, auth-svc
docker build -t gooseek/discover-svc:latest -f services/discover-svc/Dockerfile services/discover-svc
docker build -t gooseek/search-svc:latest -f services/search-svc/Dockerfile services/search-svc
docker build -t gooseek/notifications-svc:latest -f services/notifications-svc/Dockerfile services/notifications-svc
docker build -t gooseek/auth-svc:latest -f services/auth-svc/Dockerfile services/auth-svc
# chat-svc, create-svc, billing-svc
docker build -t gooseek/chat-svc:latest -f services/chat-svc/Dockerfile services/chat-svc
docker build -t gooseek/create-svc:latest -f services/create-svc/Dockerfile services/create-svc
docker build -t gooseek/billing-svc:latest -f services/billing-svc/Dockerfile services/billing-svc
docker build -t gooseek/audit-svc:latest -f services/audit-svc/Dockerfile services/audit-svc
```
## deploy/k3s — манифесты
| Файл | Описание |
|------|----------|
| search-svc.yaml | SearXNG proxy, Redis cache |
| notifications-svc.yaml | Web Push, PostgreSQL, VAPID |
| auth-svc.yaml | better-auth, namespace gooseek-auth, PVC |
| discover-svc.yaml | + GHOST_URL, GHOST_CONTENT_API_KEY (optional) |
| cache-worker.yaml | CronJob finance/discover/travel, activeDeadlineSeconds |
| hpa.yaml | HPA + PDB для chat, search, discover, finance, travel, memory |
| audit-svc.yaml | Enterprise audit logs |
| ingress.yaml | + /api/v1/search, /api/v1/notifications, /api/v1/admin |
---
## Порядок реализации (roadmap)
См. [01-perplexity-analogue-design.md §6](./01-perplexity-analogue-design.md#6-порядок-реализации-best-practices).

View File

@@ -1,38 +1,30 @@
# GooSeek Architecture
# Архитектура аналога Perplexity.ai
GooSeek is a Next.js application that combines an AI chat experience with search.
**Отдельный проект.** Документы самодостаточны; все спеки и roadmap — внутри этой папки.
For a high level flow, see [WORKING.md](WORKING.md). For deeper implementation details, see [CONTRIBUTING.md](../../CONTRIBUTING.md).
Целевая система для ~10 000 DAU с **полным совпадением** логики Perplexity.ai:
- **ВСЁ в `services/`.** Папка `apps/` удаляется. Никаких app — только микросервисы.
- Микросервисы в K3s (chat, search, discover, finance, travel, auth, library, memory, create, notifications, projects, cache-worker, web/frontend)
- Максимум логики на клиенте; персональные данные только для аккаунтов
- Предварительная обработка и кэширование (discover, finance, travel+inspiration, поиск)
## Key components
## Документы
1. **User Interface**
| Документ | Описание |
|----------|----------|
| [01-perplexity-analogue-design.md](./01-perplexity-analogue-design.md) | Карта функциональностей, микросервисы, стратегия кэша, порядок реализации |
| [02-k3s-microservices-spec.md](./02-k3s-microservices-spec.md) | K3s манифесты, Deployment, Service, CronJob для каждого сервиса |
| [03-cache-and-precompute-strategy.md](./03-cache-and-precompute-strategy.md) | Детальная стратегия кэширования: discover, finance, travel, search |
| [04-pages-logic-verification.md](./04-pages-logic-verification.md) | Сверка логики страниц с Perplexity.ai — полное совпадение |
| [05-gaps-and-best-practices.md](./05-gaps-and-best-practices.md) | Production checklist, требования инфраструктуры |
| [06-roadmap-specification.md](./06-roadmap-specification.md) | Roadmap и спецификация фич (Memory, Create, Notifications и др.) |
- A web based UI that lets users chat, search, and view citations.
## Быстрый старт
2. **API Routes**
1. Прочитать `01-perplexity-analogue-design.md` для общего понимания
2. Использовать `02-k3s-microservices-spec.md` для развёртывания
3. Реализовать `cache-worker` и Redis по `03-cache-and-precompute-strategy.md`
- `POST /api/chat` powers the chat UI.
- `POST /api/search` provides a programmatic search endpoint.
- `GET /api/providers` lists available providers and model keys.
## Отношение к functional-inventory
3. **Agents and Orchestration**
- The system classifies the question first.
- It can run research and widgets in parallel.
- It generates the final answer and includes citations.
4. **Search Backend**
- A meta search backend is used to fetch relevant web results when research is enabled.
5. **LLMs (Large Language Models)**
- Used for classification, writing answers, and producing citations.
6. **Embedding Models**
- Used for semantic search over user uploaded files.
7. **Storage**
- Chats and messages are stored so conversations can be reloaded.
**docs/functional-inventory** — описание **текущего** кода (инвентаризация). Используется только для справки при миграции. Правки в architecture **не требуют** правок в functional-inventory.

View File

@@ -1,6 +1,6 @@
# How GooSeek Works
This is a high level overview of how GooSeek answers a question.
This is a high level overview of how Perplexica answers a question.
If you want a component level overview, see [README.md](README.md).

View File

@@ -1,81 +0,0 @@
# Update GooSeek to the latest version
To update GooSeek to the latest version, follow these steps:
## For Docker users (Using pre-built images)
Simply pull the latest image and restart your container:
```bash
docker pull itzcrazykns1337/gooseek:latest
docker stop gooseek
docker rm gooseek
docker run -d -p 3000:3000 -v gooseek-data:/home/gooseek/data --name gooseek itzcrazykns1337/gooseek:latest
```
For slim version:
```bash
docker pull itzcrazykns1337/gooseek:slim-latest
docker stop gooseek
docker rm gooseek
docker run -d -p 3000:3000 -e SEARXNG_API_URL=http://your-searxng-url:8080 -v gooseek-data:/home/gooseek/data --name gooseek itzcrazykns1337/gooseek:slim-latest
```
Once updated, go to http://localhost:3000 and verify the latest changes. Your settings are preserved automatically.
## For Docker users (Building from source)
1. Navigate to your GooSeek directory and pull the latest changes:
```bash
cd GooSeek
git pull origin master
```
2. Rebuild the Docker image:
```bash
docker build -t gooseek .
```
3. Stop and remove the old container, then start the new one:
```bash
docker stop gooseek
docker rm gooseek
docker run -p 3000:3000 -p 8080:8080 --name gooseek gooseek
```
4. Once the command completes, go to http://localhost:3000 and verify the latest changes.
## For non-Docker users
1. Navigate to your GooSeek directory and pull the latest changes:
```bash
cd GooSeek
git pull origin master
```
2. Install any new dependencies:
```bash
npm i
```
3. Rebuild the application:
```bash
npm run build
```
4. Restart the application:
```bash
npm run start
```
5. Go to http://localhost:3000 and verify the latest changes. Your settings are preserved automatically.
---