This commit is contained in:
ik
2026-09-03 08:18:35 +07:00
parent a7bfc7ee8d
commit d407e8fcfd
103 changed files with 24544 additions and 13 deletions
+23 -8
View File
@@ -1,6 +1,16 @@
# RF4 Spotter
RF4 Spotter — неофициальный сервис свежих точек и статистики клёва для Russian Fishing 4. Этап 1 содержит контейнерный каркас, демоданные, read-only API, главную страницу и страницу точки. Реальный импорт официальных рекордов пока остаётся отдельным исследовательским адаптером этапа 0.
RF4 Spotter — неофициальный сервис свежих точек и статистики клёва для Russian Fishing 4. Он объединяет публичные рекорды и подтверждённые пользовательские уловы, показывает свежесть источников и рассчитывает объяснимые индексы активности и уверенности. Проект не взаимодействует с игровым клиентом и не является официальным продуктом RF4.
## Статус разработки
- этапы 0 и 1 завершены;
- этап 2, официальный импорт, завершён технически; автоматический профиль остаётся выключенным до явного разрешения владельца источника;
- этап 3 выполнен частично: форма, MinIO, модерация, удаление с аудитом и постоянный rate limit готовы;
- ближайшие задачи — сквозной тест полного пользовательского сценария и раздельные состояния ошибок формы;
- затем начинается этап 4: формализация и расширенное тестирование индекса клёва.
Подробный план и актуальные чекбоксы находятся в [`docs/ROADMAP.md`](docs/ROADMAP.md).
## Запуск через Docker
@@ -37,7 +47,7 @@ docker compose up --build
## Что реализовано
- FastAPI и SQLAlchemy 2;
- PostgreSQL 17 и начальная миграция Alembic;
- PostgreSQL 17 и миграции Alembic до `0007`;
- идемпотентный seed с двумя точками и свежими демо-уловами;
- `GET /api/v1/activity` с фильтрами периода, водоёма, рыбы, способа и сортировки;
- `GET /api/v1/spots/{id}` и `/catches`;
@@ -48,8 +58,9 @@ docker compose up --build
- идемпотентный импорт официальных записей с журналом запусков;
- публичная страница `/records` с источником и временем последнего импорта;
- форма `/report`, защищённые admin API и журнал модерации;
- honeypot и базовый лимит отправок;
- скриншоты уловов в MinIO/S3 с декодированием изображения, ограничением размера и очисткой метаданных.
- honeypot и постоянный rate limit в PostgreSQL с HMAC-отпечатками вместо исходных IP;
- скриншоты уловов в MinIO/S3 с проверкой MIME, расширения, размера и фактического содержимого, повторным кодированием и очисткой метаданных;
- административная очередь `/admin/moderation` с одобрением, отклонением и обезличенным удалением записи с аудитом.
Все пользовательские ники и уловы в seed демонстрационные.
@@ -61,9 +72,11 @@ Backend и исследовательский парсер:
python3 -m venv .venv
.venv/bin/pip install -r apps/api/requirements.txt
.venv/bin/pip install -e .
.venv/bin/pytest apps/api/tests tests -q
.venv/bin/pytest -q
```
На текущем этапе набор содержит 21 backend/parser-тест.
Frontend:
```bash
@@ -89,7 +102,7 @@ npm run test:e2e
docker compose --profile tools run --rm importer
```
Импорт делает до трёх ограниченных попыток, проверяет DOM-контракт и не удаляет ранее сохранённые данные при сбое. Повторный запуск обновляет совпавшие записи по SHA-256 ключу и не создаёт дубликаты. Автоматическое расписание намеренно ещё не включено: сначала требуется согласовать допустимость регулярного опроса официального сайта.
Импорт делает до трёх ограниченных попыток, проверяет DOM-контракт и не удаляет ранее сохранённые данные при сбое. Повторный запуск обновляет совпавшие записи по SHA-256 ключу и не создаёт дубликаты. Расписание реализовано, но намеренно не включается обычным запуском: сначала требуется согласовать допустимость регулярного опроса официального сайта.
Ручной административный запуск также доступен через `POST /api/v1/admin/imports/official-records`, журнал — через `GET /api/v1/admin/imports`. Импорт сохраняет HTTP-метаданные и использует `ETag`/`Last-Modified`, когда источник их предоставляет.
@@ -110,10 +123,12 @@ curl -H "Authorization: Bearer change-me-in-production" \
"http://localhost:8000/api/v1/admin/catch-reports?status=pending"
```
Перед внешним развёртыванием обязательно замените демонстрационный `ADMIN_TOKEN`, а также значения `S3_ACCESS_KEY` и `S3_SECRET_KEY`. Форма принимает JPEG, PNG и WebP до 8 МБ; API повторно кодирует изображение и удаляет EXIF перед сохранением в MinIO. Модератор получает временную подписанную ссылку через admin API.
Перед внешним развёртыванием обязательно замените демонстрационные `ADMIN_TOKEN`, `RATE_LIMIT_SECRET`, `S3_ACCESS_KEY` и `S3_SECRET_KEY`. Форма принимает JPEG, PNG и WebP до 8 МБ; API сверяет MIME и расширение с фактическим форматом, повторно кодирует изображение и удаляет EXIF перед сохранением в MinIO. Модератор получает временную подписанную ссылку через admin API.
Очередь модерации доступна по адресу <http://localhost:4321/admin/moderation>. Администратор вводит `ADMIN_TOKEN`; интерфейс держит его только в памяти открытой страницы и не сохраняет в URL или браузерном хранилище.
Администратор может одобрить, отклонить или удалить сообщение. Удаление очищает ник, комментарий, исходную ссылку и объект скриншота, исключает запись из статистики, но сохраняет обезличенный факт действия в журнале аудита.
## Исследовательский парсер официальных рекордов
```bash
@@ -123,4 +138,4 @@ python -m rf4_research.records \
--category records
```
Команда делает один HTTP-запрос и печатает типизированные записи в JSON. Это ещё не продуктивный импортёр: в нём нет повторов, кэша, транзакций и дедупликации. Подтверждённая структура источника и риски описаны в [docs/data-sources.md](docs/data-sources.md).
Команда делает один HTTP-запрос и печатает типизированные записи в JSON. Это исследовательский инструмент этапа 0; продуктивный адаптер находится в `apps/api/app/importer.py` и добавляет ограниченные повторы, условные HTTP-запросы, транзакции, дедупликацию и журнал запусков. Подтверждённая структура источника и риски описаны в [docs/data-sources.md](docs/data-sources.md).