37 KiB
RF4 Spotter — идеи и техническое задание для MVP
Рабочий документ для передачи в Codex. Его задача — дать Codex достаточно контекста, чтобы начать проектирование и разработку без пересказа всей переписки.
1. Идея продукта
RF4 Spotter — неофициальный информационный сайт для игроков «Русской Рыбалки 4» (Russian Fishing 4), который отвечает на практический вопрос:
Куда мне пойти ловить прямо сейчас, какую снасть или приманку взять и насколько свежа эта информация?
Сайт должен объединять:
- официальные рекорды RF4;
- пользовательские сообщения об уловах;
- координаты точек;
- приманки, наживки, оснастки и способы проводки;
- время поимки;
- историю активности;
- простой и понятный индекс клёва.
Главная ценность — не вечный справочник старых точек, а оценка текущей активности с указанием свежести и надёжности данных.
2. Что известно об источниках данных
Официальные данные
У RF4, по предварительным данным, нет документированного публичного API со всеми уловами и координатами. Однако официальный сайт публикует таблицы рекордов и рейтингов, которые можно разбирать автоматически.
Предположительно из таблиц рекордов можно получать:
- регион;
- категорию рекорда;
- игрока;
- вид рыбы;
- вес;
- водоём;
- приманку или наживку;
- дату.
Исходные точки для исследования:
- официальный раздел рекордов: https://rf4game.de/records/region/RU/;
- пример открытого парсера: https://github.com/hurfy/rf4-api;
- существующий статистический сервис: https://rf4-stat.ru/help/;
- пример пользовательской базы: https://download.rf4db.com/ru/catches.
Перед реализацией парсера нужно проверить актуальную 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 считается полезным, если пользователь может:
- открыть главную страницу;
- выбрать водоём, рыбу или способ ловли;
- увидеть активные комбинации «водоём + рыба + точка»;
- понять, на чём основана оценка;
- открыть карточку точки с приманками и динамикой;
- отправить свой улов через простую форму.
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 | 0–100 |
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]: ...
Этапы:
- загрузить страницу или JSON/XHR, если он существует;
- сохранить диагностические метаданные ответа;
- разобрать строки в
RawRecord; - нормализовать значения;
- вычислить ключ дедупликации;
- добавить или обновить записи транзакционно;
- записать результат запуска в
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 не должен молча принимать решения по этим пунктам, если они становятся блокирующими:
- Как будет называться проект и какой домен использовать?
- Нужна ли авторизация обычных пользователей в первом релизе?
- Где размещать приложение и объектное хранилище?
- Можно ли использовать реальные ники игроков в публичной выдаче?
- Какие именно официальные категории рекордов импортировать первыми?
- Какие водоёмы и рыбы нужны в пилотной базе?
- Какая лицензия будет у кода и данных?
- Разрешают ли правила и
robots.txtвыбранную частоту автоматического сбора?
Для начала разработки допустимы безопасные значения по умолчанию:
- рабочее название
RF4 Spotter; - без регистрации обычных пользователей;
- один регион RU;
- одна или две основные категории рекордов;
- локальное S3-совместимое хранилище MinIO;
- демонстрационные ники и данные в seed;
- импорт раз в 60 минут.
20. Как работать над проектом в Codex
- Создать пустой репозиторий и положить этот файл в
docs/RF4_MVP_SPEC.md. - Открыть корень репозитория в Codex.
- Дать Codex сначала исследовательскую задачу из блока ниже.
- Попросить фиксировать решения в
docs/и обновлять README. - Делить работу на небольшие проверяемые этапы, а не просить сразу «сделать весь сайт».
- После каждого этапа просить запускать тесты и показывать, что именно готово.
- Не передавать 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. Главное продуктовое правило
Если данных недостаточно или они устарели, сайт должен честно сказать об этом. «Не знаем» полезнее, чем красивая, но выдуманная рекомендация.