Add "Feed"

2026-04-12 20:46:38 +00:00
parent a8508ff587
commit 7197ae52e4

86
Feed.md Normal file

@@ -0,0 +1,86 @@
# Фид товаров
## Обзор
YML-фид каталога товаров загружается с URL из настроек (`feedUrl`). Данные используются для подстановки в Mindbox-теги при рендере превью.
## Загрузка фида
Функция `_fetchFeedProducts(feedUrl)`:
1. Проверка `isPublicUrl(feedUrl)` — блокирует localhost, private IP, IPv6, hex IP
2. HTTP GET с таймаутом 90 сек, User-Agent: `AspekterVA-FeedReader/1.0`
3. Автодетект кодировки windows-1251 из Content-Type или XML declaration
4. Парсинг regex-ом (не DOM) — извлекает `<offer>` элементы
## Кэширование
### В памяти
- `feedCache` — Map `{url: {ts, products: Map}}`
- TTL: 3 часа (`FEED_CACHE_TTL = 3 * 60 * 60 * 1000`)
### На диске
- `data/feed-cache.json``{url, ts, products: {id: {...}}}`
- Восстанавливается при старте сервера
### Дедупликация запросов
- `feedPending` — Map текущих in-flight запросов
- Если запрос уже выполняется, новый подключается к Promise
- Stale timeout: 2 минуты (если Promise завис)
## Поля товара из фида
```javascript
{
id, available, // идентификатор и наличие
name, price, oldPrice, // название, цены
image, url, // картинка и ссылка
description, // описание
categoryId, vendor, // категория и бренд
typePrefix, model, // тип товара и модель
gender, color, // гендер и цвет
discountPercent, // процент скидки
// Кастомные поля (из param):
denomination, year, dia, material, country,
condition, weight, assay, vendorCode,
reverseImage, salePercent, series
}
```
## API эндпоинты фида
### POST /api/project/:name/feed-refresh
Принудительная перезагрузка фида:
- Очищает кэш
- Загружает заново
- Возвращает diff: `{added, removed, total}`
### POST /api/project/:name/feed-lookup
Поиск товаров по ID:
- Body: `{ids: ["123", "456"]}`
- Возвращает: `{found: [{id, name, price, ...}], notFound: ["789"]}`
### POST /api/project/:name/feed-suggest
Замена недоступного товара:
- Body: `{productId: "123", limit: 10}`
- Алгоритм скоринга:
| Фактор | Баллы |
|--------|-------|
| Тот же бренд (vendor) | +25 |
| Тот же тип (typePrefix) | +20 |
| Та же категория (categoryId) | +15 |
| Тот же гендер | +10 |
| Близкая цена | 0-10 |
| Тот же цвет | +5 |
- Исключаются товары с ценой >3x от оригинала
- Возвращает топ-N по скору
## "Нет в наличии"
При рендере:
1. Mindbox-теги подставляются из фида
2. Если товар `available === false` → на картинку накладывается CSS-оверлей
3. Список `unavailableProducts[]` возвращается клиенту
4. В UI показывается warning: "⚠ Нет в наличии (N) · фид DD.MM HH:MM"
5. Клик раскрывает список с кнопками "Заменить" для каждого товара
6. "Заменить" → показывает модал с рекомендациями из `feed-suggest`