Full stack per GOAL.md / TODO.md:
- checker (Go): fetch sources, canonicalize/dedup (whitelist+sort, & fixes),
validity check (connect+latency+speed gates), geoip by exit IP, session model
("only working / last completed session"), global lock, manual run/stop,
Telegram start/finish notifications. Reuses tessero-checker dialers
(vless/vmess/trojan/ss), upstream parser, geoip, fetcher.
- api (Go): admin auth (single operator), dashboard stats, proxies
list/filter/export/bulk, subscriptions CRUD, sources CRUD, settings, checker
control, and dynamic public /sub endpoints with unique_ips + plain/base64/
clash/singbox rendering.
- frontend (React+Vite+TS+Tailwind): telemetry-console SPA — Dashboard, Proxies,
Subscriptions, Settings.
- postgres schema, docker-compose (postgres/checker/api/web-nginx), Dockerfiles,
Gitea Actions CI.
Verified end-to-end via Docker: pipeline, all sub formats, unique_ips collapse,
and all four panel tabs (Playwright).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014TtR4PP2JM9KadaBkhPGAE
18 KiB
zhguchiy_perchik — список желаний (wishlist)
Это НЕ архитектура и НЕ ТЗ. Это список того, что панель должна уметь, — «хотелки» по функционалу. Стек, схему БД, API и деплой обсуждаем отдельно позже.
Статус:
[~]— под вопросом (обсуждаем),[x]— согласовано, делаем.
О проекте
Панель-чекер прокси со своей sub-системой.
Суть: постоянно тянем конфиги прокси (vless / vmess / trojan / ss) из списков-источников,
проверяем каждый на валидность (по его исходящему IP), храним только рабочие,
и отдаём клиентам как подписки (sub-ссылки, конфиги через \n для Happ / v2rayN и подобных).
Критерий «валидности» (что проходит чек):
- Успешный коннект (handshake по протоколу) + удалось узнать exit IP в пределах таймаута.
- Латенси не хуже порога (порог в настройках).
- Скорость не хуже порога (порог в настройках) — спидтест ЯВЛЯЕТСЯ гейтом валидности, гоняется для каждого кандидата, прошедшего коннект+латенси.
Модель данных «только рабочие / только последняя сессия» (ключевой принцип)
- В базе (для отображения и выдачи) — только рабочие прокси, и только они.
- Работаем сессиями чека:
check_session_Nотчекала всё → по ней показываются прокси и вся статистика. Покаcheck_session_(N+1)в работе (или крашнулась — неважно), панель и подписки всегда показывают результат последней завершённой сессии. - Незавершённая / упавшая сессия не должна портить текущую выдачу — переключение на её результат происходит только когда она успешно завершилась.
- Нет автоудаления по N провалам и нет «мёртвого пула» в выдаче — невалид просто не попадает в актуальную сессию и не отдаётся клиентам. (см. «Автоудаление — нет».)
- Счётчики валид/невалид для статистики берём из результатов сессий (сколько кандидатов проверено, сколько прошло/не прошло), а не из выдаваемого списка.
- Персистентная история по canonical URL: на каждый уникальный прокси помним first_seen, last_alive, аптайм, провалы подряд, последние метрики — даже когда он сейчас невалиден. Это внутренняя история; в панели/подписках показываем и отдаём только рабочие из последней завершённой сессии. (нужно для аптайма и «провалов подряд»)
- Историю сессий храним ВСЮ, без чистки/ретеншена (для трендов по дням/неделям/месяцам).
- Атрибуция source: закрепляем за прокси ПЕРВЫЙ увиденный источник (first-seen), один source на прокси.
Уникализация прокси (грамотная) — с фактами из реальных источников
Проверил живьём ~577k строк из источников (__init__.py). Что реально прилетает и как чистим:
Что нашли (реальная «грязь»):
- Почти у КАЖДОЙ строки есть
#-метка — это реклама/лейбл, не часть конфига. Примеры:🔥Join+Telegram:@Farah_VPN🟣(×6939),EPODONIOS,@oneclickvpnkeys::US,@meliproxyy,کانال تلگرام, флаги-эмодзи стран,t.me/…. - Рекламные query-параметры:
Telegram(×25908 у vless),note(×1887),brand,@NebulaVPNx, и даже целый URL как имя ключа:https://t.me/WangCai2🇨🇳. - Баг HTML-экранирования: ~3.5% строк содержат
&вместо&→ параметры превращаются в битыеamp;type,amp;security(amp;type×15251 у vless), встречается и вариант с ведущим;(;type) и двойнойamp;;security. - Битые строки: два конфига слиты без переноса (
…type=tcptrojan://…), недекодируемые base64-блобы, текст ошибок вида订阅内容解析错误(«ошибка парсинга подписки»).
Правила чистки (желания):
- Разэкранировать
&→&(и разобрать варианты с;/двойнымamp;) ДО парсинга. - Выкинуть фрагмент
#…целиком (метки/реклама) — до сохранения и до чека. - Вайтлист query-параметров по протоколу: оставляем только реально влияющие на коннект,
остальное режем (реклама отваливается сама). Черновой вайтлист:
- vless:
type, security, encryption, sni, fp, path, host, pbk, sid, flow, headerType, alpn, mode, spx, serviceName, allowInsecure/insecure, packetEncoding, authority, extra, ech, quicSecurity; новые xhttp:x_padding_bytes, pcs, pqv, fm; ws early-data:ed, eh. - trojan:
sni, type, security, path, host, allowInsecure, fp, alpn, headerType, mode, serviceName, sid, pbk, spx, peer. - ss: userinfo = base64(
method:password); из query по сути толькоplugin. - vmess: это base64(json) — декодируем, оставляем
add, port, id, aid, net, type, host, path, tls, sni, alpn, fp, scy, v; выкидываемps(лейбл) и мусор (name, test_name, nation, pcs, vcn, deviceID). - Точный вайтлист финализируем при реализации (сверяемся с v2ray URL-спекой).
- vless:
- Сортировать query-параметры по алфавиту → одинаковый прокси в разном порядке параметров даёт один и тот же канонический URL.
- Нормализация формы: единый регистр схемы, обрезка хвостового
/в host:port, нормализация percent-encoding; для vmess — переупаковать json канонично. - Дедуп по каноническому URL (после всей чистки). В базе/выдаче — уже чистый URL.
- Битые/непарсящиеся строки — отклонять (не считать за прокси).
- Показывать в панели, сколько дублей/мусора схлопнулось при импорте (сырых строк → уникальных после канонизации).
Известное ограничение:
- [~] hysteria2 / hy2 / ssr / tuic встречаются (hysteria2 ×594 и т.д.), но Go-диалеры их не умеют — будут отсеиваться. Возможно добавим поддержку позже.
Уникализация по out_ip (кнопка unique_ips)
Две РАЗНЫЕ прокси (разный протокол/настройки/конфиг-строка) могут после подключения выходить в интернет с ОДНОГО и того же out_ip — это дубли «по точке выхода» (по конфигу они уникальны, по выходу — нет). Это отдельная от canonical-URL уникализация.
- Кнопка/тумблер
unique_ipsв табах Proxies и Subscriptions. Когда включена — группа прокси с одинаковым out_ip схлопывается до ОДНОГО прокси-победителя. На выходе — список / сабка, уникальные по out_ip. - Рядом с кнопкой — переключатель МЕТРИКИ схлопки: по
speed_test(берём с макс. Mbps) или поlatency(берём с мин. мс). Победитель на каждый out_ip выбирается по ней. - Дефолт: метрика
speed_test; тай-брейк при равной скорости — меньшая латенси. Самunique_ipsпо умолчанию выключен (opt-in). - Это фильтр отображения/выдачи — базу не меняет. В Proxies — тумблер над таблицей; в Subscriptions — опция подписки (хранится в её настройках, влияет на sub-ссылку).
Вкладки панели
1. Dashboard (статистика по сети — максимально подробно)
- Кол-во валид / невалид (по последней сессии), числом и в %.
- Разбивка валид/невалид по дням / неделям / месяцам (графики-тренды).
- Общее кол-во рабочих прокси в базе (актуальная сессия).
- Динамика: сколько добавилось нового / сколько отвалилось за день/неделю/месяц.
- Разбивка по протоколам (vless / vmess / trojan / ss) — кол-во и % валида.
- Разбивка по странам (гео по exit IP) — топ стран.
- Разбивка по источникам — какой source даёт валид, какой мусор.
- Статистика по латенси (средняя / медиана / распределение по бакетам мс).
- Статистика по скорости (спидтест включаем, ссылка в настройках).
- Аптайм конкретных прокси (как долго прокси держится живым между сессиями).
- Время последнего чека, длительность.
- Живой прогресс текущего цикла (проверено X из Y) + статус активной сессии.
2. Proxies
- Список прокси с фильтрами: протокол, страна, источник, латенси, скорость.
- Поиск по прокси.
- Выгрузка отфильтрованного списка в
.txt(по\n). - Скопировать конкретную проксю одной кнопкой.
- Массовые действия: удалить выбранные, пере-проверить выбранные.
- Метаданные прокси: пинг, страна, exit IP, кол-во провалов подряд, откуда взят.
- Кнопка
unique_ips+ переключатель метрики (speed_test / latency) — схлопка списка до уникальных по out_ip (см. раздел «Уникализация по out_ip»).
3. Subscriptions (подписки для клиентов)
- Создание подписки → уникальная sub-ссылка.
- Отдача прокси через
\n(формат для Happ / v2ray и прочих). - Sub отдаётся ДИНАМИЧЕСКИ: каждый запрос — актуальные рабочие по фильтрам из последней завершённой сессии (без кэша/снапшота).
- Фильтры подписки:
- по протоколу(ам);
- по стране(ам);
- по статусу (только живые);
- по латенси / скорости (не хуже порога);
- по источнику;
- лимит количества (топ-N).
- Опция
unique_ips+ метрика (speed_test / latency) — сабка отдаёт уникальные по out_ip (см. раздел «Уникализация по out_ip»). - Сортировка выдачи по одному или нескольким параметрам (выбираемым) — напр. по скорости, латенси, стране.
- Порядок формирования выдачи подписки: фильтры → (опц.) схлопка
unique_ips→ сортировка по выбранным параметрам → лимит топ-N. Т.е. лимит N считает УЖЕ уникальные по out_ip прокси. - Форматы выдачи (выбираются на подписке): plain text (
\n), base64 (v2ray/Happ), Clash / Clash.Meta YAML, sing-box JSON. - Вкл/выкл подписки, срок действия. Если подписка выключена или истёк срок — sub-ссылка отвечает 404 / ошибкой.
- Статистика по подписке: сколько раз дёргали, когда последний раз.
4. Settings
- Интервал проверки прокси (как часто гоняем цикл; каждый цикл сам перефетчивает источники — отдельного интервала импорта НЕ надо).
- Список source'ов — откуда брать прокси (добавить / удалить / вкл-выкл). Это ссылки на листы (txt / подписки).
- Параметры чека: таймаут, кол-во воркеров, порог латенси, порог мин. скорости, интервал чека, вкл/выкл спидтест. Черновые дефолты (тюнятся в UI): интервал 12 ч, воркеры 10, таймаут 5 сек, порог латенси 1000 мс, мин. скорость 3 Mbps.
- Ссылка для спидтеста (для замера скорости) — настраивается.
- URL для проверки коннекта / получения exit IP — НЕ в настройках, зашит дефолтом (надёжный IP-echo сервис, желательно с фолбэком на несколько).
- Гео-база: выбирается в настройках; дефолт —
geolite2-geo-whois-asn-country(mmdb) из https://github.com/sapics/ip-location-db. Страна прокси определяется по его exit IP. - Ручной запуск чека / импорта кнопкой + кнопка СТОП. Активна может быть только ОДНА операция чека зараз (глобальный лок): полный цикл и ручной «пере-проверить выбранные» не идут параллельно — второй блокируется, пока первый не завершится.
- Telegram-уведомления: в настройках задаётся ОДИН bot token + ОДИН chat_id, с чекбоксами когда слать — на НАЧАЛО чека и на КОНЕЦ (в конце — со статистикой сессии).
Явные «нет» (чтобы не делать лишнего)
- Отдельный интервал импорта — НЕ надо (каждый перечек перефетчит источники).
- Автоудаление прокси после N провалов — НЕ надо (храним только рабочие, см. модель выше).
- Экспорт всей базы / бэкап — НЕ надо.
- Уведомления «валида стало меньше обычного» — НЕ надо (телега шлёт только старт/финиш чека).
Идеи на потом (не для первой версии)
- История циклов проверки (когда, сколько проверено, сколько прошло) — нужна.
- [~] Поддержка hysteria2 / tuic / ssr — НЕ в первой версии (в источниках ~0.1%), возможно позже.
Что осознанно обсуждаем ОТДЕЛЬНО (не сейчас)
- Стек (бэкенд / чекер / фронт), язык, библиотеки.
- Схема БД, API-эндпоинты.
- Как именно реализуем модель «последняя завершённая сессия» на уровне БД.
- Точный финальный вайтлист параметров по протоколам.
- Аутентификация в панель.
- Деплой.