Files
2026-09-02 19:52:32 +07:00

37 KiB
Raw Permalink Blame History

RF4 Spotter — идеи и техническое задание для MVP

Рабочий документ для передачи в Codex. Его задача — дать Codex достаточно контекста, чтобы начать проектирование и разработку без пересказа всей переписки.

1. Идея продукта

RF4 Spotter — неофициальный информационный сайт для игроков «Русской Рыбалки 4» (Russian Fishing 4), который отвечает на практический вопрос:

Куда мне пойти ловить прямо сейчас, какую снасть или приманку взять и насколько свежа эта информация?

Сайт должен объединять:

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

Главная ценность — не вечный справочник старых точек, а оценка текущей активности с указанием свежести и надёжности данных.

2. Что известно об источниках данных

Официальные данные

У RF4, по предварительным данным, нет документированного публичного API со всеми уловами и координатами. Однако официальный сайт публикует таблицы рекордов и рейтингов, которые можно разбирать автоматически.

Предположительно из таблиц рекордов можно получать:

  • регион;
  • категорию рекорда;
  • игрока;
  • вид рыбы;
  • вес;
  • водоём;
  • приманку или наживку;
  • дату.

Исходные точки для исследования:

Перед реализацией парсера нужно проверить актуальную HTML-структуру, сетевые запросы страницы и условия использования сайта. Нельзя считать приведённые URL и структуру полей неизменными.

Пользовательские данные

Официальные таблицы, вероятно, не содержат точных координат, проводки и всех обычных уловов. Их нужно собирать отдельно:

  • через собственную форму на сайте;
  • позднее — из разрешённых Telegram-, Discord- или VK-источников;
  • позднее — из скриншотов с подтверждением распознанных полей пользователем.

Важное ограничение

В MVP нельзя перехватывать трафик игрового клиента, внедряться в процесс игры, обходить античит или заниматься reverse engineering закрытого протокола. Проект должен работать только с публичными веб-данными и добровольно переданной пользователями информацией.

3. Для кого делаем

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

Типичный запрос:

Уровень: 19
Способ ловли: спиннинг
Доступные водоёмы: до Куори включительно
Цель: серебро

Ожидаемый ответ:

Сейчас активна щука на Вьюнке
Точка: 110:103
Приманка: Spiker #2 01-015
Последнее подтверждение: 34 минуты назад
Уловов за 12 часов: 27 от 11 игроков
Активность: высокая
Уверенность: 87 из 100

4. Главная гипотеза MVP

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

MVP считается полезным, если пользователь может:

  1. открыть главную страницу;
  2. выбрать водоём, рыбу или способ ловли;
  3. увидеть активные комбинации «водоём + рыба + точка»;
  4. понять, на чём основана оценка;
  5. открыть карточку точки с приманками и динамикой;
  6. отправить свой улов через простую форму.

5. Состав MVP

5.1. Главная страница «Что клюёт сейчас»

На странице должны быть:

  • фильтр по водоёму;
  • фильтр по рыбе;
  • фильтр по способу ловли;
  • фильтр по периоду: 6, 12, 24, 72 часа;
  • сортировка по активности, уверенности и свежести;
  • карточки активных точек;
  • явное время последнего обновления данных.

Карточка содержит:

  • водоём;
  • рыбу;
  • координаты;
  • лучшую приманку или наживку;
  • количество уловов за выбранный период;
  • количество разных авторов;
  • средний и максимальный вес;
  • время последнего подтверждения;
  • activity_score от 0 до 100;
  • confidence_score от 0 до 100;
  • короткое текстовое объяснение оценки.

5.2. Страница точки

URL вида:

/spots/vyunok/110-103/pike

Содержимое:

  • координаты и описание места;
  • статистика уловов за 24 часа, 3 дня и 7 дней;
  • список наиболее результативных приманок или наживок;
  • способы проводки и скорость, если указаны;
  • распределение уловов по игровому времени;
  • последние подтверждённые уловы;
  • источник и свежесть каждой записи;
  • предупреждение, если данных мало или они устарели.

5.3. Страница официальных рекордов

  • таблица импортированных рекордов;
  • фильтры по рыбе, водоёму, категории и периоду;
  • дата последнего успешного импорта;
  • отметка, что это данные официального сайта RF4;
  • ссылка на исходную страницу.

5.4. Форма добавления улова

Обязательные поля:

  • рыба;
  • вес;
  • водоём;
  • координаты x:y;
  • дата и время отправки.

Необязательные поля:

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

Для первой версии скриншот хранится как подтверждение, но не распознаётся автоматически.

5.5. Простая модерация

Минимальная закрытая страница администратора:

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

До одобрения пользовательский улов не влияет на публичный индекс клёва.

6. Что не входит в MVP

  • перехват данных из запущенной игры;
  • reverse engineering протокола RF4;
  • OCR и компьютерное зрение для скриншотов;
  • автоматический сбор всех публикаций Telegram, Discord и VK;
  • мобильное приложение;
  • сложная персонализация по снастям и бюджету;
  • прогнозирование клёва с помощью ML;
  • комментарии и социальная сеть;
  • полноценная интерактивная карта каждого водоёма;
  • автоматическое определение игровых обновлений и миграций рыбы.

Эти возможности допустимы после проверки основного сценария.

7. Предлагаемый стек

Вариант для первого релиза

  • Frontend: Astro + TypeScript;
  • интерактивные компоненты: React или Svelte islands только там, где они нужны;
  • стили: Tailwind CSS либо обычный CSS с дизайн-токенами;
  • Backend API: Python 3.12 + FastAPI;
  • ORM и миграции: SQLAlchemy 2 + Alembic;
  • БД: PostgreSQL;
  • фоновые задания: APScheduler или отдельный CLI, запускаемый cron;
  • парсер: сначала httpx + BeautifulSoup; Playwright только если обычного HTTP недостаточно;
  • хранение скриншотов: S3-совместимое объектное хранилище;
  • локальный запуск: Docker Compose;
  • тесты: pytest для backend, Vitest для frontend, Playwright для ключевого end-to-end сценария.

На старте Celery и Redis не нужны: периодический импорт можно сделать отдельной идемпотентной CLI-командой.

8. Архитектура

Официальный сайт RF4 ──> импортёр рекордов ──┐
                                             │
Форма пользователя ──> модерация ───────────┼──> PostgreSQL
                                             │         │
Ручной импорт CSV/JSON ──────────────────────┘         │
                                                       v
                                              расчёт активности
                                                       │
                                                       v
                                                FastAPI JSON API
                                                       │
                                                       v
                                                  Astro-сайт

Предлагаемая структура репозитория:

rf4-spotter/
├── README.md
├── .env.example
├── compose.yaml
├── apps/
│   ├── web/                  # Astro
│   └── api/                  # FastAPI
├── packages/
│   └── contracts/            # OpenAPI/types, если понадобится
├── data/
│   └── fixtures/             # обезличенные тестовые HTML/JSON
├── docs/
│   ├── RF4_MVP_SPEC.md
│   └── data-sources.md
└── scripts/
    └── seed_demo_data.*

9. Модель данных

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

fish

Поле Тип Назначение
id UUID идентификатор
slug text unique значение для URL
name_ru text unique название рыбы
trophy_weight_g integer nullable порог трофея, если известен

waterbody

Поле Тип Назначение
id UUID идентификатор
slug text unique значение для URL
name_ru text unique название водоёма
unlock_level integer nullable уровень открытия

bait

Объединённый справочник наживок и искусственных приманок для MVP.

Поле Тип Назначение
id UUID идентификатор
name text отображаемое название
normalized_name text unique ключ для сопоставления
kind enum bait, lure, unknown

spot

Поле Тип Назначение
id UUID идентификатор
waterbody_id UUID FK водоём
x integer координата X
y integer координата Y
description text nullable заметка о месте

Уникальный ключ MVP: (waterbody_id, x, y).

catch_report

Поле Тип Назначение
id UUID идентификатор
fish_id UUID FK рыба
spot_id UUID FK nullable точка; у официального рекорда её может не быть
waterbody_id UUID FK водоём хранится явно
bait_id UUID FK nullable приманка или наживка
weight_g integer вес в граммах
rig_type text nullable тип оснастки
retrieve_method text nullable способ проводки
retrieve_speed integer nullable скорость проводки
game_time time nullable игровое время
caught_at timestamptz nullable время поимки, если известно
reported_at timestamptz время попадания в систему
player_name text nullable ник игрока
source_type enum official_record, user, manual_import
source_url text nullable ссылка на источник
source_external_id text nullable ключ для дедупликации
source_confidence smallint 0100
moderation_status enum pending, approved, rejected
screenshot_key text nullable ключ объекта в хранилище
raw_payload jsonb nullable исходные данные импортёра

official_record_import

Поле Тип Назначение
id UUID запуск импортёра
started_at timestamptz начало
finished_at timestamptz nullable завершение
status enum running, success, partial, failed
source_url text источник
rows_seen integer найдено строк
rows_created integer добавлено записей
rows_updated integer обновлено записей
error_summary text nullable краткая ошибка

moderation_event

Хранит историю решений по пользовательскому сообщению: кто, когда, какой статус установил и почему.

10. Нормализация и дедупликация

Это критическая часть проекта.

Нужно:

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

Для официальных рекордов ключ дедупликации можно сначала строить из нормализованной комбинации:

region + category + player + fish + weight_g + waterbody + bait + record_date

Этот ключ следует хешировать и хранить в source_external_id.

11. Индекс активности

Требование

Алгоритм MVP должен быть простым, детерминированным и объяснимым. Нельзя показывать псевдоточную оценку без расшифровки.

Расчёт производится для группы:

водоём + точка + рыба + выбранный временной интервал

Предлагаемый первый вариант:

freshness_i = exp(-age_hours_i / 18)

weighted_reports = sum(freshness_i * source_confidence_i / 100)
unique_players = количество уникальных непустых player_name
trophy_bonus = min(1, trophy_count / 3)

activity_raw =
    55 * min(1, weighted_reports / 12)
  + 25 * min(1, unique_players / 6)
  + 20 * trophy_bonus

activity_score = round(activity_raw)

Начальная оценка уверенности:

confidence_score = round(
    45 * min(1, approved_reports / 10)
  + 35 * min(1, unique_players / 5)
  + 20 * average_source_confidence / 100
)

Правила отображения:

  • меньше трёх одобренных пользовательских наблюдений — пометка «данных мало»;
  • нет уловов за 72 часа — пометка «данные устарели»;
  • один игрок не может создать высокую уверенность большим количеством сообщений;
  • официальный рекорд без координат нельзя автоматически приписывать конкретной точке;
  • значения 0–100 — сравнительные индексы сервиса, а не вероятность поймать рыбу.

Карточка должна объяснять результат, например:

Высокая активность: 18 свежих уловов от 7 игроков.
Последнее подтверждение 42 минуты назад.
Уверенность средняя: часть сообщений без скриншотов.

Формулу после накопления реальных данных нужно откалибровать.

12. API MVP

Публичные методы:

GET /api/v1/activity
GET /api/v1/spots/{spot_id}
GET /api/v1/spots/{spot_id}/catches
GET /api/v1/records
GET /api/v1/fishes
GET /api/v1/waterbodies
GET /api/v1/baits
POST /api/v1/catch-reports

Пример фильтров активности:

GET /api/v1/activity?waterbody=vyunok&fish=pike&hours=24&method=spinning

Административные методы:

GET   /api/v1/admin/catch-reports?status=pending
PATCH /api/v1/admin/catch-reports/{id}
POST  /api/v1/admin/imports/official-records
GET   /api/v1/admin/imports

Все списочные методы должны иметь пагинацию, предсказуемую сортировку и валидацию фильтров.

13. Импорт официальных рекордов

Импортёр должен быть отдельным адаптером, чтобы изменение вёрстки RF4 не затронуло остальное приложение.

Интерфейс адаптера:

class OfficialRecordsSource(Protocol):
    async def fetch(self, region: str, category: str) -> list[RawRecord]: ...

Этапы:

  1. загрузить страницу или JSON/XHR, если он существует;
  2. сохранить диагностические метаданные ответа;
  3. разобрать строки в RawRecord;
  4. нормализовать значения;
  5. вычислить ключ дедупликации;
  6. добавить или обновить записи транзакционно;
  7. записать результат запуска в official_record_import.

Требования:

  • таймауты и повторы с ограничением;
  • понятный User-Agent с названием проекта и контактным URL, когда он появится;
  • умеренная частота запросов;
  • кэширование;
  • фикстуры реальных HTML-ответов для unit-тестов;
  • отказ с понятной ошибкой, если ожидаемые колонки исчезли;
  • никакого молчаливого импорта перепутанных полей;
  • возможность запустить командой вроде python -m app.cli import-records;
  • расписание не чаще необходимого; начать с одного раза в 30–60 минут.

Если официальный сайт отдаёт данные через внутренний JSON/XHR endpoint, нужно предпочесть его HTML-парсингу, но только если он доступен без обхода защиты.

14. Интерфейс и визуальный принцип

Сайт должен выглядеть как современный полезный инструмент, а не как форум или перегруженная игровая база.

Принципы:

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

Минимальные состояния каждой страницы:

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

15. Безопасность и приватность

  • не принимать исполняемые файлы;
  • проверять MIME-тип, расширение и размер скриншотов;
  • удалять EXIF из загруженных изображений;
  • генерировать серверные имена объектов;
  • ограничить частоту отправки формы;
  • добавить honeypot или CAPTCHA после появления спама;
  • экранировать пользовательский текст;
  • не публиковать IP и технические идентификаторы;
  • ник игрока сделать необязательным;
  • предусмотреть удаление пользовательского сообщения;
  • административную часть защитить аутентификацией;
  • секреты хранить только в переменных окружения;
  • не коммитить .env и реальные скриншоты пользователей.

16. Критерии готовности MVP

MVP готов, когда:

  • проект поднимается одной документированной командой через Docker Compose;
  • миграции создают чистую БД;
  • seed-команда добавляет демонстрационные водоёмы, рыб, приманки и уловы;
  • импортёр получает или разбирает официальные рекорды из актуального источника;
  • повторный импорт не создаёт дубликаты;
  • сбой источника не удаляет ранее загруженные данные;
  • главная страница показывает активные точки и фильтруется;
  • карточка точки объясняет активность и уверенность;
  • пользователь может отправить улов;
  • администратор может его одобрить или отклонить;
  • одобренный улов появляется в публичной статистике;
  • есть автоматические тесты главного сценария;
  • README описывает запуск, настройку, импорт, тесты и ограничения проекта.

17. Этапы разработки

Этап 0. Исследование источника

  • проверить официальный сайт RF4 и его сетевые запросы;
  • зафиксировать доступные регионы и категории;
  • проверить актуальность проекта hurfy/rf4-api;
  • сохранить небольшие HTML/JSON-фикстуры;
  • описать риски и ограничения в docs/data-sources.md;
  • не писать весь продукт, пока не доказано, что хотя бы один источник стабильно разбирается.

Результат: маленький исследовательский скрипт и документ с подтверждённой структурой данных.

Этап 1. Каркас и демонстрационные данные

  • создать монорепозиторий;
  • настроить Astro, FastAPI, PostgreSQL и миграции;
  • создать модель данных;
  • добавить seed;
  • реализовать read-only API;
  • сверстать главную и страницу точки на демоданных.

Этап 2. Официальные рекорды

  • реализовать адаптер источника;
  • добавить нормализацию и дедупликацию;
  • добавить журнал запусков;
  • сделать страницу рекордов;
  • добавить периодический запуск.

Этап 3. Пользовательские уловы

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

Этап 4. Индекс клёва

  • агрегаты;
  • активность и уверенность;
  • человекочитаемое объяснение;
  • тесты на свежесть, дубликаты и вклад разных игроков.

Этап 5. Пилот

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

18. Идеи после MVP

Приоритет определять по реальному использованию:

  • распознавание скриншота с обязательным подтверждением пользователем;
  • Telegram-бот для отправки улова;
  • импорт из разрешённых каналов и сообществ;
  • персональный профиль: уровень, открытые водоёмы, снасти, бюджет;
  • режим «куда пойти прямо сейчас»;
  • сравнение приманок;
  • динамика клёва по игровому времени;
  • обнаружение смены рабочих точек после обновлений;
  • уведомление, когда активизировалась выбранная рыба;
  • карта водоёма;
  • публичный API для сообщества;
  • репутация источников и авторов;
  • мультиязычность и поддержка разных регионов RF4.

19. Открытые вопросы

Codex не должен молча принимать решения по этим пунктам, если они становятся блокирующими:

  1. Как будет называться проект и какой домен использовать?
  2. Нужна ли авторизация обычных пользователей в первом релизе?
  3. Где размещать приложение и объектное хранилище?
  4. Можно ли использовать реальные ники игроков в публичной выдаче?
  5. Какие именно официальные категории рекордов импортировать первыми?
  6. Какие водоёмы и рыбы нужны в пилотной базе?
  7. Какая лицензия будет у кода и данных?
  8. Разрешают ли правила и robots.txt выбранную частоту автоматического сбора?

Для начала разработки допустимы безопасные значения по умолчанию:

  • рабочее название RF4 Spotter;
  • без регистрации обычных пользователей;
  • один регион RU;
  • одна или две основные категории рекордов;
  • локальное S3-совместимое хранилище MinIO;
  • демонстрационные ники и данные в seed;
  • импорт раз в 60 минут.

20. Как работать над проектом в Codex

  1. Создать пустой репозиторий и положить этот файл в docs/RF4_MVP_SPEC.md.
  2. Открыть корень репозитория в Codex.
  3. Дать Codex сначала исследовательскую задачу из блока ниже.
  4. Попросить фиксировать решения в docs/ и обновлять README.
  5. Делить работу на небольшие проверяемые этапы, а не просить сразу «сделать весь сайт».
  6. После каждого этапа просить запускать тесты и показывать, что именно готово.
  7. Не передавать Codex пароли, токены и игровые учётные данные; использовать .env.example.

Первый промпт для Codex

Прочитай docs/RF4_MVP_SPEC.md целиком. Пока не создавай весь сайт.

Выполни только этап 0 — исследование источников официальных рекордов RF4.

Задачи:
1. Изучи текущую структуру официальной страницы рекордов и её сетевые запросы.
2. Проверь, существует ли доступный JSON/XHR endpoint, который можно использовать без обхода защиты.
3. Изучи архитектурные идеи проекта https://github.com/hurfy/rf4-api, но не копируй код вслепую и проверь его актуальность.
4. Создай минимальный исследовательский скрипт, который получает одну страницу/категорию и преобразует записи в типизированную внутреннюю структуру.
5. Добавь обезличенную небольшую фикстуру и unit-тест парсера.
6. Создай docs/data-sources.md: подтверждённые поля, URL, параметры, ограничения, рекомендуемую частоту опроса и риски поломки.
7. Не исследуй сетевой протокол игры, не запускай игровой клиент и не обходи защиту сайтов.

Перед изменениями изучи репозиторий и предложи краткий план. После работы запусти тесты и сообщи, что подтверждено фактически, а что осталось предположением.

Второй промпт после успешного исследования

Прочитай docs/RF4_MVP_SPEC.md и docs/data-sources.md. Реализуй этап 1: каркас приложения на Astro + TypeScript, FastAPI, PostgreSQL, SQLAlchemy 2 и Alembic.

Требования:
- локальный запуск через Docker Compose;
- модели и миграции для основных сущностей MVP;
- seed с демонстрационными данными;
- read-only API для активности, точек и справочников;
- главная страница и страница точки;
- адаптивная вёрстка;
- тесты backend и одного главного пользовательского сценария;
- README с точными командами запуска и проверки.

Используй данные только из seed: реальный импортёр будет отдельным этапом. Сначала предложи план и список файлов, затем реализуй и проверь результат.

21. Короткое описание проекта для README

RF4 Spotter — неофициальный сервис свежих точек и статистики клёва для Russian Fishing 4. Он объединяет публичные рекорды и подтверждённые пользовательские уловы, показывает свежесть источников и рассчитывает объяснимые индексы активности и уверенности. Проект не взаимодействует с игровым клиентом и не является официальным продуктом RF4.

22. Главное продуктовое правило

Если данных недостаточно или они устарели, сайт должен честно сказать об этом. «Не знаем» полезнее, чем красивая, но выдуманная рекомендация.