Files
rf4-spotter/README.md
T

115 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# RF4 Spotter
RF4 Spotter — неофициальный сервис свежих точек и статистики клёва для Russian Fishing 4. Этап 1 содержит контейнерный каркас, демоданные, read-only API, главную страницу и страницу точки. Реальный импорт официальных рекордов пока остаётся отдельным исследовательским адаптером этапа 0.
## Запуск через Docker
Требуются Docker Engine и Docker Compose. Это основной и рекомендуемый сценарий:
```bash
docker compose up --build
```
После успешного запуска:
- сайт: <http://localhost:4321>;
- OpenAPI: <http://localhost:8000/docs>;
- проверка API: <http://localhost:8000/health>;
- консоль MinIO: <http://localhost:9001>.
Контейнер API сам выполняет `alembic upgrade head`, затем идемпотентный seed. PostgreSQL хранит данные в именованном volume `postgres_data`, а MinIO — в `minio_data`.
Остановка:
```bash
docker compose down
```
Удаление volume и повторное создание чистой базы — только когда данные больше не нужны:
```bash
docker compose down --volumes
docker compose up --build
```
Переменные и локальные значения по умолчанию перечислены в [.env.example](.env.example). Секретов в репозитории нет.
## Что реализовано
- FastAPI и SQLAlchemy 2;
- PostgreSQL 17 и начальная миграция Alembic;
- идемпотентный seed с двумя точками и свежими демо-уловами;
- `GET /api/v1/activity` с фильтрами периода, водоёма, рыбы, способа и сортировки;
- `GET /api/v1/spots/{id}` и `/catches`;
- справочники рыб, водоёмов и приманок;
- Astro SSR-интерфейс с адаптивным дизайном из `design-reference` без переноса React/Vinext-стека;
- объяснимые индексы активности и уверенности по формуле спецификации;
- состояния «нет данных» и «источник недоступен»;
- идемпотентный импорт официальных записей с журналом запусков;
- публичная страница `/records` с источником и временем последнего импорта;
- форма `/report`, защищённые admin API и журнал модерации;
- honeypot и базовый лимит отправок;
- скриншоты уловов в MinIO/S3 с декодированием изображения, ограничением размера и очисткой метаданных.
Все пользовательские ники и уловы в seed демонстрационные.
## Проверка проекта
Backend и исследовательский парсер:
```bash
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
```
Frontend:
```bash
cd apps/web
npm install
npm run build
npm audit --omit=dev
```
E2E после запуска Compose:
```bash
cd apps/web
npx playwright install chromium
npm run test:e2e
```
## Импорт официальных рекордов
Однократный контейнерный запуск после старта базы:
```bash
docker compose --profile tools run --rm importer
```
Импорт делает до трёх ограниченных попыток, проверяет DOM-контракт и не удаляет ранее сохранённые данные при сбое. Повторный запуск обновляет совпавшие записи по SHA-256 ключу и не создаёт дубликаты. Автоматическое расписание намеренно ещё не включено: сначала требуется согласовать допустимость регулярного опроса официального сайта.
## Пользовательские уловы и модерация
Новая запись из `/report` получает статус `pending` и не участвует в активности до одобрения. Административные методы требуют заголовок `Authorization: Bearer $ADMIN_TOKEN`:
```bash
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.
## Исследовательский парсер официальных рекордов
```bash
python -m rf4_research.records \
--url https://rf4game.de/records/region/RU/ \
--region RU \
--category records
```
Команда делает один HTTP-запрос и печатает типизированные записи в JSON. Это ещё не продуктивный импортёр: в нём нет повторов, кэша, транзакций и дедупликации. Подтверждённая структура источника и риски описаны в [docs/data-sources.md](docs/data-sources.md).