Документация

LLM Wiki проекта

LLM Wiki: Whiteout Survival Analytics

Последнее обновление: 2026-05-15

Этот файл хранит устойчивый контекст проекта для будущей разработки с LLM. Перед значимой доработкой нужно читать этот файл. Если в ходе работы фиксируется новая функция, бизнес-правило, техническое решение или изменение модели данных, этот файл нужно обновить в той же итерации.

Как Использовать Эту Wiki

  • Использовать docs/LLM_WIKI.md как основной источник проектного контекста.
  • Не хранить здесь временные debug-логи и одноразовые наблюдения.
  • Фиксировать только то, что важно для следующих итераций разработки.
  • Если решение устарело, обновлять существующий раздел, а не оставлять противоречивые записи.
  • В описаниях использовать точные имена файлов, API, таблиц, views и полей.

Бизнес-Контекст

Назначение Проекта

Whiteout Survival Analytics — локальный веб-сервис для анализа платных паков в игре Whiteout Survival.

Проект нужен, чтобы игрок мог понять, какие внутриигровые предложения дают лучшую ценность за реальные деньги. Основная метрика — сколько полезности, выраженной в алмазах, игрок получает за один рубль.

Целевая Польза

Сервис должен помогать:

  • сравнивать платные паки между собой;
  • видеть лучшие предложения по алм/₽;
  • понимать, из каких предметов складывается ценность пака;
  • замечать паки с неполным расчетом;
  • видеть, какие предметы пока не имеют подтвержденной ценности;
  • принимать решение о покупке на основе расчетов, а не баннерных процентов игры.

Основные Пользовательские Сценарии

  1. Игрок открывает дашборд и быстро видит лучшие паки.
  2. Игрок переходит в рейтинг и фильтрует паки по цене, типу или приоритету.
  3. Игрок открывает карточку пака и проверяет состав наград.
  4. Игрок смотрит, какие категории предметов дают основной вклад в value.
  5. Игрок открывает раздел проблем данных и видит, какие предметы требуют оценки.
  6. Игрок добавляет новые данные в базу/definitions, после чего сервис пересчитывает рейтинг.

Бизнес-Метрика

Главная метрика:

  • diamonds_per_rub / алм/₽

Смысл метрики:

  • все предметы переводятся в условную полезность в алмазах;
  • общая полезность пака делится на цену в рублях;
  • чем выше значение, тем выгоднее пак.

Шкала Приоритетов

Паки распределяются по приоритетам:

  • S+: diamonds_per_rub >= 200
  • S: diamonds_per_rub >= 120
  • A: diamonds_per_rub >= 100
  • B: diamonds_per_rub >= 80
  • C: diamonds_per_rub >= 50
  • D: ниже 50

Эта шкала используется как пользовательская подсказка для быстрого принятия решения. Она не заменяет детальный просмотр состава пака.

Неполные Расчеты

Если в паке есть предметы без подтвержденной ценности:

  • has_missing становится true;
  • total_value считается как нижняя оценка;
  • реальная ценность пака может быть выше;
  • такой пак должен быть явно помечен в интерфейсе.

Текущая бизнес-логика: лучше показать нижнюю оценку и флаг проблемы, чем скрыть пак полностью.

Источники Доверия

Для расчетов важны источники и доказательства:

  • скриншоты паков;
  • скриншоты магазинов/цен;
  • каталог предметов Whiteout Survival Wiki для расширения справочника items;
  • SQL-миграции с основаниями value;
  • JSON-описания паков;
  • комментарии к расчетам.

Скриншоты и заметки считаются частью доказательной базы. Если добавляются write-функции, нужно сохранять аудит изменения value.

Текущее Состояние Данных

Проверенное состояние API на 2026-05-15:

  • паков: 29
  • неизвестных value-ключей: 13
  • предметов в items: 431
  • предметов, импортированных только из Wiki с временным английским названием: 396
  • активный источник: postgres

Текущие неизвестные предметы показываются в разделе Проблемы данных.

Продуктовые Принципы

  • Интерфейс должен быть аналитическим, плотным и табличным.
  • Главный экран должен быть рабочим приложением, а не лендингом.
  • Баннерные проценты игры не являются главным источником истины.
  • Нужно явно показывать, когда расчет неполный.
  • Пользователь должен быстро понять, почему один пак лучше другого.
  • История value-предположений должна быть проверяемой.

Разработческий Контекст

Текущий Стек

  • Frontend: React.
  • Full-stack framework: Next.js App Router.
  • Backend: Next.js route handlers.
  • Database: PostgreSQL 16 через Docker Compose.
  • Package manager: npm.

Текущие версии:

  • Next.js: ^16.2.0, установленная версия наблюдалась как 16.2.6.
  • React: ^19.2.0.
  • npm: 11.14.1, установлен локально в ~/.local/bin/npm.

Локальные URL

Development server:

  • http://127.0.0.1:3000

Основной API:

  • GET /api/analytics

API для изображений:

  • GET /api/media/[...path]

Страница wiki на сайте:

  • /wiki

Страница просмотра Postgres:

  • /database

Страница каталога предметов:

  • /items

Карта Репозитория

Ключевые файлы и директории:

  • app/ — Next.js App Router страницы и route handlers.
  • app/page.jsx — серверная страница, загружает initial data.
  • app/layout.jsx — корневой layout.
  • app/api/analytics/route.js — JSON API аналитики.
  • app/api/media/[...path]/route.js — безопасная отдача локальных изображений.
  • app/database/page.jsx — отдельная страница просмотра таблиц и views Postgres.
  • app/items/page.jsx — отдельная страница каталога предметов из Postgres.
  • app/wiki/page.jsx — отдельная страница сайта с LLM Wiki.
  • app/globals.css — стили приложения, адаптированные из макета.
  • components/AnalyticsApp.jsx — основной интерактивный React UI.
  • components/DatabaseBrowser.jsx — client-side вкладки и таблицы для просмотра Postgres.
  • components/ItemsCatalog.jsx — client-side фильтры и таблица каталога предметов.
  • components/WikiPage.jsx — server-rendered представление docs/LLM_WIKI.md.
  • lib/databaseBrowser.js — server-side чтение всех BASE TABLE и VIEW из public.
  • lib/data.js — серверная загрузка, нормализация и fallback данных.
  • lib/itemsCatalog.js — server-side чтение items с value и usage-контекстом для /items.
  • lib/postgres.js — общий Postgres pool factory и безопасное экранирование identifiers.
  • lib/wiki.js — чтение Markdown-файла wiki для страницы /wiki.
  • db/001_schema.sql — схема Postgres и основные views.
  • db/*.sql — seed/value migrations.
  • db/011_items_wiki_fields.sql — metadata-поля для предметов, импортированных или сопоставленных с Whiteout Survival Wiki.
  • db/012_items_local_icons.sql — локальные иконки предметов, вырезанные из пользовательских скриншотов и подключенные через items.local_icon_url.
  • db/013_essence_stones_value_from_vip_shop.sql — value для essence_stones по VIP-магазину: 1500 алмазов за 1 камень эссенции.
  • db/014_hero_items_ru_from_screenshots.sql — русские названия, описания, редкость и screenshot-source для Hero Items из пользовательских скриншотов IMG_6139IMG_6147.
  • db/015_speedup_atomic_durations.sql — нормализация ускорений в weekly speedup card до атомарной длительности предмета и регистрация IMG_6148 как справочника длительностей.
  • db/016_speedup_duration_items.sql — ввод duration-items для ускорений: отдельные предметы по типу и длительности (speedup_general_1h, speedup_general_5m и т.д.) и миграция pack_items на эти предметы.
  • db/018_personalized_hero_widget_chest_temporary_value.sql — добавляет item_values.value_quality и временную оценку для personalized_hero_widget_chest.
  • db/021_mark_zero_value_analytics_items_needs_review.sql — правило качества: предметы, которые используются в pack_items, но не имеют активного value или имеют value 0, получают items.recognition_status = needs_review.
  • scripts/import_wiki_items.mjs — импорт каталога предметов с https://www.whiteoutsurvival.wiki/items/ в Postgres.
  • public/item-icons/ — локальные изображения предметов, которые не имеют точного Wiki-сопоставления.
  • packs/definitions/*.json — JSON-описания состава паков.
  • packs/ — скриншоты паков.
  • screenshots/ — дополнительные скриншоты и доказательства value.
  • exports/pack_summary.csv — экспорт сводки и файловый fallback.
  • docker-compose.yml — локальный Postgres.
  • INSTALL.md — установка и эксплуатационные заметки.
  • docs/LLM_WIKI.md — этот файл.

Поток Данных

Frontend не является источником истины.

Порядок работы:

  1. app/page.jsx вызывает getAnalyticsData() из lib/data.js.
  2. lib/data.js сначала пытается прочитать Postgres.
  3. Если Postgres доступен, данные берутся из v_pack_summary, v_pack_item_values, packs, screenshots и v_active_item_values.
  4. Если Postgres недоступен, backend переключается на файловый fallback: exports/pack_summary.csv, packs/definitions/*.json и db/*.sql.
  5. Frontend получает нормализованный JSON и выполняет только операции отображения.

Что Считается На Backend/Postgres

Канонические расчеты должны оставаться на backend/Postgres:

  • общая ценность пака;
  • diamonds_per_rub;
  • признак неполного расчета;
  • активные item values;
  • total quantity предметов в паках;
  • каноническая metadata паков и предметов.

Что Допустимо Считать На Frontend

Frontend может считать только UI-агрегации:

  • фильтрация;
  • сортировка;
  • поиск;
  • top-5 для отображения;
  • среднее diamonds_per_rub для dashboard-контекста;
  • распределение по приоритетам;
  • bars вклада категорий в деталке пака.

Frontend не должен дублировать формулы value как источник истины.

Текущий API Shape

GET /api/analytics возвращает:

{
  packs: [
    {
      id,
      name,
      price,
      currency,
      date,
      limit,
      validity_days,
      status,
      priority,
      banner,
      total_value,
      dia_per_rub,
      has_missing,
      comment,
      tag,
      source,
      screenshot_path,
      purchase_count,
      instant,
      daily,
      lines
    }
  ],
  unknowns: [
    {
      key,
      name,
      category,
      occurrences,
      total_qty,
      visual,
      packs
    }
  ],
  lastImport,
  source: {
    kind,
    label,
    summaryPath,
    definitionsPath
  }
}

Модель Базы Данных

Канонические таблицы:

  • screenshots — источники и metadata скриншотов.
  • items — каталог предметов. Для интеграции с Whiteout Survival Wiki дополнительно используются поля name_en, wiki_slug, wiki_url, wiki_icon_url, wiki_category, wiki_imported_at. Для иконок из локальных скриншотов используется local_icon_url; UI берет local_icon_url первым, затем wiki_icon_url.
  • item_values — value единицы предмета в алмазах. Поле value_quality фиксирует качество оценки: unknown, temporary, derived, confirmed. Временные гипотезы не считать окончательными справочными ценами.
  • Для предметов из аналитики (pack_items) статус confirmed допустим только когда у предмета есть ненулевой активный value. Если value отсутствует, неизвестен или равен 0, ставить items.recognition_status = needs_review, даже если Wiki-сопоставление уже найдено.
  • price_observations — наблюдения цен в магазинах.
  • packs — metadata платных паков.
  • pack_items — состав паков.

Канонические views:

  • v_active_item_values — последнее активное value по каждому предмету.
  • v_pack_item_values — item-level contribution в рамках пака.
  • v_pack_summary — pack-level summary.

UI Views

Сейчас приложение использует client-side route state, а не URL routes.

Текущие views:

  • dashboard — KPI, топ паков, распределение приоритетов, preview проблем данных.
  • ranking — таблица рейтинга с сортировкой и фильтрами.
  • detail — деталка пака: состав, metadata, скриншот, вклад категорий.
  • missing — неизвестные предметы/value issues.
  • source — статус источника данных и refresh control.
  • /database — отдельная URL-страница с вкладками по таблицам и views Postgres.
  • /items — отдельная URL-страница каталога предметов из items с фильтрами, wiki-иконками, name_ru/name_en, статусом, активным value и использованием в паках.
  • /wiki — отдельная URL-страница с содержимым docs/LLM_WIKI.md.
  • В левом сайдбаре всех основных страниц показывается контактный блок: Telegram @FlashSW как ссылка на https://t.me/FlashSW; игровой контакт — сервер 43, ник Flashbang.
  • Главная страница / по умолчанию открывает Дашборд; рейтинг доступен через /?view=ranking. Сайдбары URL-страниц должны показывать оба пункта: Дашборд и Рейтинг паков; в dev-режиме также Проблемы данных (/?view=missing) и Источник (/?view=source). Wiki проекта находится в категории Документация, а не в Данные.
  • В production (NODE_ENV=production) скрываются внутренние QA/служебные элементы: пункты Проблемы данных, Источник, База данных, блок дашборда Требуют внимания; прямой route /database возвращает notFound().

Текущие Технические Решения

  • Next.js используется как full-stack framework.
  • Postgres — preferred source of truth.
  • Файловый fallback намеренно сохранен для локальной работы без базы.
  • Скриншоты отдаются через /api/media/..., а не прямыми абсолютными путями.
  • Макет из /Users/andrey/Downloads/whiteout survival.zip использован как визуальная и продуктовая основа.
  • components/AnalyticsApp.jsx пока является крупным компонентом; при росте UI его стоит разнести на модули.
  • Wiki проекта доступна на сайте по /wiki и server-side читает тот же файл docs/LLM_WIKI.md; не дублировать содержимое wiki вручную в React-компонентах.
  • Просмотр базы доступен по /database: страница читает все BASE TABLE и VIEW из схемы public, отображает каждый объект отдельной вкладкой и не выполняет write-действий.
  • Каталог предметов доступен по /items: страница читает Postgres на сервере, а на frontend выполняет только поиск и UI-фильтрацию по категории, статусу и срезу Все / Аналитика / Только Wiki.
  • В деталке пака строки состава используют icon_url из items.wiki_icon_url вместо текстовых сокращений категорий. Если иконки нет, UI оставляет прежний fallback с короткой подписью.
  • Раздел Проблемы данных также использует icon_url из неизвестных строк предметов. Если у предмета нет local_icon_url или wiki_icon_url, остается fallback ?.
  • Каталог предметов можно расширять из Whiteout Survival Wiki через scripts/import_wiki_items.mjs. Существующие предметы, которые уже участвуют в аналитике, не переименовываются: их русское name_ru сохраняется, а английское название и ссылка на Wiki пишутся в metadata-поля. Новые предметы, которых нет в текущей аналитике, добавляются с временным английским name_ru и статусом wiki_imported_en.
  • Сопоставление Wiki Gems закреплено за аналитическим предметом diamonds (Алмазы). Не создавать отдельный wiki_gems.
  • В категории Wiki Hero Items закреплены соответствия: Mythic General Hero Shardhero_shard_universal_mythic, Mythic Exploration Skill Manualskill_combat_manual_orange (Учебник боя оранжевый), Mythic Expedition Skill Manualskill_development_manual_orange (Учебник развития оранжевый). Не сопоставлять Epic/Rare manuals и shards с мифическими/оранжевыми предметами.
  • Для Hero Items русские игровые названия подтверждены скриншотами: Rare/Epic/Mythic Expedition Skill ManualРедкий/Великий/Мифический инструктаж экспедиции, Rare/Epic/Mythic Exploration Skill ManualРедкое/Великое/Мифическое руководство по освоению, Rare/Epic/Mythic General Hero ShardРедкий/Великий/Мифический общий фрагмент героя. Сохранять эти name_ru при повторных Wiki-импортах.
  • Сопоставление Wiki Chief Stamina закреплено за stamina_can_10 (Банка выносливости (10)). Не создавать отдельный wiki_chief_stamina.
  • Сопоставление Wiki Lv.2 Custom Ressource Chest закреплено за resource_box_personal_lv2 (Персональный ящик с ресурсами ур. 2). Не создавать отдельный wiki_lv_2_custom_ressource_chest.
  • Дополнительные сопоставления Wiki для предметов, используемых в паках: Gold keygolden_key, Enhancement XP Componentgear_exp_component_100, Lucky Hero Gear Chestweekly_gear_chest, Custom Mythic Hero Gear Chestpersonalized_hero_widget_chest, Hardened Alloygovernor_gear_alloy, Design Plansgovernor_gear_scroll, Charm Guidetalisman_manual, Charm Designgovernor_talisman_scroll, Mystery Badgesecret_token (Тайный жетон), Blacksmith Stoneessence_stones. Не создавать отдельный предмет blacksmith_stone: это ошибочное распознавание камней эссенции.
  • personalized_hero_widget_chest (Персонализированный ящик с подделкой героя, Wiki Custom Mythic Hero Gear Chest) имеет временный value 3000 алмазов за 1 шт. Формула: 5 таких ящиков стоят в 2 раза дороже 5 камней эссенции, значит 1 ящик = 2 × essence_stones = 3000. В item_values.value_quality это значение помечено как temporary; при появлении прямого магазина/скрина заменить подтвержденным value. В UI временные value показываются warning-цветом: в каталоге /items бейдж временно, в деталке пака подпись алм/ед. окрашена и имеет значок ? с tooltip-обоснованием расчета.
  • Для ускорений каноническая модель разделена на две сущности. Базовые speedup_general_min, speedup_construction_min, speedup_research_min, speedup_training_min хранят value одной минуты и не должны использоваться как строки состава новых паков. В pack_items используются duration-items: speedup_*_1m, speedup_*_5m, speedup_*_1h, а для общих ускорений также speedup_general_3h и speedup_general_8h. Их value_per_unit_diamonds уже равен стоимости одной карточки ускорения нужной длительности, например speedup_general_5m = 5 × speedup_general_min, speedup_general_1h = 60 × speedup_general_min.
  • После перехода на duration-items поле pack_items.quantity_per_claim для ускорений означает количество карточек ускорения, а не минуты. Длительность берется из item_id. Например строка speedup_general_1h с quantity_per_claim = 20 означает 20 предметов по 1 часу; строка speedup_general_5m с quantity_per_claim = 480 означает 480 предметов по 5 минут. Не сворачивать такие строки обратно в один минутный предмет, иначе UI снова будет показывать 13 алм/ед. вместо value одной карточки ускорения.
  • Для обобщенных speedup-предметов нет точного Wiki-сопоставления. Их иконки рисуются в UI как одна стрелка с фоном по длительности и маленьким маркером типа: общее, строительство, исследование, тренировка. Цвет фона: 1m — серый, 5m — зеленый, 1h — синий, 3h — фиолетовый, 8h — оранжевый. Компонент находится в components/SpeedupIcon.jsx и переиспользуется в деталке пака, каталоге /items и новых местах, где нужно показать предмет ускорения. Нижнее число на игровых иконках является количеством предметов и не должно попадать в иконку. После подключения speedup-иконок 228 из 250 строк состава паков имеют изображение. Без уверенного сопоставления остаются синие/рассветные supply chest; не склеивать их с похожими Wiki-предметами без визуального подтверждения.
  • essence_stones (Камни эссенции) имеет подтвержденный value 1500 алмазов за 1 шт. Источник: VIP-магазин, зафиксировано 2026-05-15.

Локальные Особенности Окружения

На машине был Node из Codex.app, но не было npm в PATH.

Установлено:

  • npm path: ~/.local/bin/npm
  • npx path: ~/.local/bin/npx
  • npm version: 11.14.1

В ~/.zshrc добавлен ~/.local/bin.

У Node из Codex.app есть проблема с загрузкой native SWC на macOS из-за code-signing. Поэтому локальные scripts используют Webpack + wasm SWC:

{
  "dev": "NEXT_TEST_WASM_DIR=./node_modules/@next/swc-wasm-nodejs next dev --webpack",
  "build": "NEXT_TEST_WASM_DIR=./node_modules/@next/swc-wasm-nodejs next build --webpack"
}

Не удалять этот workaround без проверки native SWC в текущем окружении.

Команды

Установка зависимостей:

npm install

Запуск dev-сервера:

npm run dev -- --hostname 127.0.0.1 --port 3000

Сборка:

npm run build

Проверка API:

curl -sS http://127.0.0.1:3000/api/analytics

Postgres helpers:

./scripts/db.sh start
./scripts/db.sh summary
./scripts/db.sh export-packs
./scripts/db.sh psql
./scripts/db.sh stop

Импорт предметов из Whiteout Survival Wiki:

node scripts/import_wiki_items.mjs

Правила Для Будущей Разработки

  1. Перед изменениями читать docs/LLM_WIKI.md.
  2. При добавлении новой фичи обновлять эту wiki.
  3. При изменении data flow, API или schema обновлять соответствующие разделы.
  4. Если добавляются write-действия, продумать audit trail.
  5. Не переносить канонические value-формулы на frontend.
  6. Для новых расчетов сначала определить, где источник истины: Postgres, backend или UI-only aggregation.

Ближайший Backlog

Потенциальные следующие задачи:

  • Перевести client-side route state на URL routes для shareable detail pages.
  • Добавить CSV export из таблицы рейтинга.
  • Добавить CRUD для pack definitions и item values.
  • Добавить admin action: отметить value предмета как 0 с audit note.
  • Добавить сравнение Postgres-данных и file fallback.
  • Добавить authentication перед write-действиями.
  • Добавить тесты для lib/data.js.
  • Добавить loading/error states для refresh API.
  • Разбить components/AnalyticsApp.jsx на более мелкие компоненты.

Принципы Реализации

  • Postgres остается каноническим источником расчетов.
  • Fallback-режим должен быть детерминированным и заметным пользователю.
  • UI должен быть плотным, аналитическим и удобным для сравнения.
  • Скриншоты и source notes являются доказательной базой.
  • Любое изменение value должно быть проверяемым.