115 lines
6.0 KiB
Markdown
115 lines
6.0 KiB
Markdown
# 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).
|