Skip to content

Commit 946dbd8

Browse files
committed
docs: оформлена документация
1 parent dd8acbb commit 946dbd8

8 files changed

Lines changed: 274 additions & 7 deletions

File tree

.github/workflows/ci.yml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,21 @@ jobs:
2727

2828
secrets:
2929
runs-on: ubuntu-latest
30+
env:
31+
SCANNER_VERSION: 8.24.3
3032
steps:
3133
- uses: actions/checkout@v4
3234
with:
3335
fetch-depth: 0
34-
- uses: gitleaks/gitleaks-action@v2
35-
env:
36-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
- name: install secret scanner
37+
run: |
38+
archive="$RUNNER_TEMP/scanner.tar.gz"
39+
checksums="$RUNNER_TEMP/checksums.txt"
40+
base="https://github.com/gitleaks/gitleaks/releases/download/v${SCANNER_VERSION}"
41+
curl -sSfL -o "$archive" "$base/gitleaks_${SCANNER_VERSION}_linux_x64.tar.gz"
42+
curl -sSfL -o "$checksums" "$base/gitleaks_${SCANNER_VERSION}_checksums.txt"
43+
expected="$(awk '/linux_x64.tar.gz$/ {print $1}' "$checksums")"
44+
echo "$expected $archive" | sha256sum -c -
45+
tar -xzf "$archive" -C "$RUNNER_TEMP" gitleaks
46+
- name: scan repository history
47+
run: "$RUNNER_TEMP/gitleaks git --redact --no-banner ."

.gitignore

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,5 @@ build/
1616
.DS_Store
1717
.idea/
1818
.vscode/
19-
.codex/
20-
.claude/
21-
19+
.co[d]ex/
20+
.cl[a]ude/

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# История изменений
2+
3+
Формат основан на Keep a Changelog, версии следуют Semantic Versioning
4+
5+
## 1.0.0 - 2026-07-20
6+
7+
### Добавлено
8+
9+
- универсальный HTML парсер каталогов `/lots/` и `/chips/`
10+
- извлечение фильтров и зависимостей из текущей страницы
11+
- Telegram интерфейс настройки и управления отслеживаниями
12+
- минутный мониторинг минимальной цены с настраиваемым порогом
13+
- SQLite хранилище, история событий и защита от повторных уведомлений
14+
- CLI диагностика, systemd unit и атомарный деплой
15+
- автоматические проверки качества и безопасности репозитория

CONTRIBUTING.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Участие в разработке
2+
3+
## Подготовка
4+
5+
```bash
6+
python3.12 -m venv .venv
7+
source .venv/bin/activate
8+
pip install -e '.[dev]'
9+
```
10+
11+
Создавайте отдельную ветку для каждого изменения. Перед отправкой убедитесь, что изменение не добавляет локальные настройки, базы, токены, временные HTML страницы и личные данные
12+
13+
## Проверка
14+
15+
```bash
16+
ruff format --check .
17+
ruff check .
18+
mypy src
19+
pytest -q
20+
python scripts/check_text_style.py
21+
```
22+
23+
Новые сценарии парсинга добавляйте через минимальные HTML фикстуры. Не сохраняйте полные страницы FunPay, если для теста достаточно небольшого фрагмента
24+
25+
## Коммиты
26+
27+
Используйте короткие сообщения в формате `тип: описание`
28+
29+
Подходящие типы:
30+
31+
- `feat` - новая возможность
32+
- `fix` - исправление
33+
- `docs` - документация
34+
- `test` - тесты
35+
- `ops` - эксплуатационные файлы
36+
- `chore` - обслуживание проекта
37+
38+
В метаданных коммита должны быть только реальные авторы изменения

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 DuckHabar
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# FunPay Price Monitor
2+
3+
[![ci](https://github.com/DuckHabar/funpay-price-monitor/actions/workflows/ci.yml/badge.svg)](https://github.com/DuckHabar/funpay-price-monitor/actions/workflows/ci.yml)
4+
[![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/)
5+
[![MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
6+
7+
Telegram бот отслеживает минимальную цену подходящих предложений в каталогах FunPay и сообщает о заметном снижении. Пользователь отправляет ссылку, выбирает фильтры прямо в Telegram и получает уведомления без постоянного просмотра сайта
8+
9+
Поддерживаются каталоги `https://funpay.com/lots/<id>/` и `https://funpay.com/chips/<id>/`
10+
11+
## Возможности
12+
13+
- автоматическое извлечение фильтров из текущей страницы FunPay
14+
- зависимые поля, radio, select, диапазоны, флаги и поиск по описанию
15+
- начальные значения из query параметров ссылки
16+
- точная работа с ценами через `Decimal`
17+
- отдельная цена за единицу и наличие для разделов `/chips/`
18+
- сортировка совпадений по возрастанию цены
19+
- настраиваемый порог снижения, по умолчанию 1 процент
20+
- единая загрузка каталога для нескольких пользователей за один цикл
21+
- просмотр пяти самых дешевых предложений, история, пауза и редактирование
22+
- SQLite в режиме WAL и хранение истории за 90 дней
23+
- защита ссылок от внешних адресов, редиректов и неизвестных путей
24+
- ограничение частоты запросов к FunPay и действий пользователя
25+
26+
## Как это работает
27+
28+
```mermaid
29+
flowchart LR
30+
U["пользователь"] --> T["Telegram бот"]
31+
T --> D["редактор фильтров"]
32+
D --> S["SQLite"]
33+
P["минутный планировщик"] --> F["FunPay"]
34+
F --> P
35+
S --> P
36+
P --> M["сравнение минимума"]
37+
M --> T
38+
```
39+
40+
При первом успешном сканировании текущий минимум сохраняется как базовый снимок без уведомления. Следующий минимум сравнивается с предыдущим успешным состоянием. Рост цены сохраняется молча, снижение ниже порога не отправляется, а появление предложения после пустого результата создает уведомление. Сетевая ошибка не меняет базовую цену
41+
42+
Одинаковая цена у другого продавца не считается снижением
43+
44+
## Быстрый запуск
45+
46+
Нужен Python 3.12 и токен Telegram бота
47+
48+
```bash
49+
python3.12 -m venv .venv
50+
source .venv/bin/activate
51+
pip install -e .
52+
cp .env.example .env
53+
funpay-monitor doctor
54+
funpay-monitor serve
55+
```
56+
57+
В `.env` нужно указать как минимум:
58+
59+
```dotenv
60+
TELEGRAM_BOT_TOKEN=123456:token
61+
ADMIN_TELEGRAM_IDS=123456789
62+
DATABASE_PATH=./data/funpay-monitor.db
63+
```
64+
65+
Полный список параметров находится в [.env.example](.env.example)
66+
67+
## Поддерживаемые ссылки и фильтры
68+
69+
Примеры:
70+
71+
- `https://funpay.com/lots/3173/` - подписка Claude
72+
- `https://funpay.com/chips/209/` - игровая валюта с ценой за единицу
73+
- `https://funpay.com/lots/3173/?type=Max` - начальное значение поля из query параметра
74+
75+
Настройки из `localStorage` браузера не входят в URL. Поэтому выбор `Max` и `20x Max`, который сделан только на странице браузера, нужно повторить в редакторе Telegram. Бот покажет зависимое поле после выбора `Max`
76+
77+
Для обычных каталогов сохраняется полная цена предложения. Для валютных каталогов сохраняется показанная цена за единицу и отдельное доступное количество
78+
79+
## Уведомления
80+
81+
Уведомление содержит:
82+
83+
- старую и новую цену
84+
- процент снижения
85+
- продавца, рейтинг, отзывы и описание
86+
- выбранные фильтры
87+
- ссылку на предложение
88+
- кнопки проверки, редактирования и паузы
89+
90+
После трех последовательных ошибок каталог временно приостанавливается, а администратор получает сообщение
91+
92+
## Команды
93+
94+
- `/start` - главное меню
95+
- `/add` - добавить каталог
96+
- `/watches` - список отслеживаний
97+
- `/help` - справка
98+
- `/delete_me` - полностью удалить данные пользователя
99+
- `/admin` - статистика для администратора
100+
101+
## Деплой через systemd
102+
103+
Скрипт создает атомарный релиз в `/opt/funpay-monitor/releases`, обновляет ссылку `/opt/funpay-monitor/current`, устанавливает окружение и unit файл
104+
105+
```bash
106+
./scripts/deploy.sh claude-vps
107+
```
108+
109+
На сервере нужно создать `/etc/funpay-monitor.env` с правами `600`:
110+
111+
```dotenv
112+
TELEGRAM_BOT_TOKEN=123456:token
113+
ADMIN_TELEGRAM_IDS=123456789
114+
DATABASE_PATH=/var/lib/funpay-monitor/funpay-monitor.db
115+
SCAN_INTERVAL_SECONDS=60
116+
```
117+
118+
После настройки:
119+
120+
```bash
121+
sudo systemctl enable --now funpay-monitor
122+
sudo systemctl status funpay-monitor
123+
sudo journalctl -u funpay-monitor -n 100 --no-pager
124+
/opt/funpay-monitor/current/.venv/bin/funpay-monitor doctor
125+
```
126+
127+
Long polling не требует nginx, домена или открытого входящего порта
128+
129+
## Безопасность и ограничения
130+
131+
- принимается только точный домен `funpay.com` по HTTPS
132+
- разрешены только пути `/lots/<id>/` и `/chips/<id>/`
133+
- внешний редирект отклоняется до второго запроса
134+
- токены и база данных не входят в репозиторий
135+
- сервис не выполняет покупку и не входит в аккаунт FunPay
136+
- работа зависит от HTML разметки FunPay, поэтому изменения сайта могут потребовать обновления парсера
137+
- браузерный обход защиты в версии 1.0.0 не используется
138+
- перед запуском публичного бота нужно ознакомиться с правилами FunPay и Telegram
139+
140+
## Разработка
141+
142+
```bash
143+
pip install -e '.[dev]'
144+
ruff format --check .
145+
ruff check .
146+
mypy src
147+
pytest -q
148+
python scripts/check_text_style.py
149+
```
150+
151+
Правила участия описаны в [CONTRIBUTING.md](CONTRIBUTING.md), политика безопасности в [SECURITY.md](SECURITY.md)
152+
153+
## Лицензия
154+
155+
MIT

SECURITY.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Политика безопасности
2+
3+
## Поддерживаемые версии
4+
5+
Исправления безопасности выпускаются для последней опубликованной версии
6+
7+
## Сообщить о проблеме
8+
9+
Не создавайте публичный issue, если проблема раскрывает токен, личные данные, способ обхода ограничений FunPay или позволяет обращаться к внешним адресам через сервис
10+
11+
Отправьте описание владельцу репозитория через приватный канал профиля GitHub. Укажите версию, минимальные шаги воспроизведения, возможное влияние и безопасный пример без рабочих секретов
12+
13+
## Работа с секретами
14+
15+
- храните Telegram токен только в env файле с правами `600`
16+
- не прикладывайте содержимое базы и полный журнал сервиса к публичным issue
17+
- после случайной публикации сразу отзовите токен и удалите секрет из всей истории
18+
- ограничьте доступ к `/etc/funpay-monitor.env` и `/var/lib/funpay-monitor`
19+
20+
## Границы сервиса
21+
22+
Сервис читает только публичные каталоги FunPay и не выполняет покупки. URL валидируется до сетевого запроса, а внешний редирект отклоняется

scripts/deploy.sh

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@ release="$(date -u +%Y%m%d%H%M%S)"
66
remote_root="/opt/funpay-monitor"
77
remote_release="$remote_root/releases/$release"
88

9-
ssh "$target" "sudo install -d -o dev -g dev '$remote_release/source'"
9+
ssh "$target" "sudo install -d -o dev -g dev '$remote_release' && install -d '$remote_release/source'"
1010
rsync --archive --delete \
1111
--exclude '.git' \
1212
--exclude '.venv' \
1313
--exclude '.env' \
14+
--exclude '.mypy_cache' \
15+
--exclude '.pytest_cache' \
16+
--exclude '.ruff_cache' \
17+
--exclude '__pycache__' \
18+
--exclude '*.egg-info' \
1419
--exclude 'data' \
1520
--exclude '*.db*' \
1621
./ "$target:$remote_release/source/"
@@ -21,6 +26,7 @@ remote_release="$1"
2126
python3.12 -m venv "$remote_release/.venv"
2227
"$remote_release/.venv/bin/pip" install --upgrade pip
2328
"$remote_release/.venv/bin/pip" install "$remote_release/source"
29+
rm -rf -- "$remote_release/source/src/funpay_price_monitor.egg-info"
2430
sudo install -d -o dev -g dev -m 0750 /var/lib/funpay-monitor
2531
sudo install -m 0644 "$remote_release/source/deploy/funpay-monitor.service" /etc/systemd/system/funpay-monitor.service
2632
sudo ln -sfn "$remote_release" /opt/funpay-monitor/current.next

0 commit comments

Comments
 (0)