Карта фич и известные пробелы¶
Снимок на 2026-08-02. Цель — дать честную картину "что реально работает" vs "что выглядит готовым, но не закончено", чтобы не предполагать наличие фичи по факту существования файла/таблицы.
Полностью реализовано¶
| Область | Состояние |
|---|---|
| Auth | email/password, SMS, Google/GitHub/VK/Facebook/Yandex/LinkedIn/Twitter/YouTube/Telegram OAuth, MetaMask/crypto-кошелёк |
| Верификация соцсетей | GitHub, Twitter, YouTube, Rutube — отдельные цепочки подтверждения владения |
| Профиль/визитка | dix.su/p/slug, аватар, соцссылки, OG-карточки |
| Короткие ссылки | сокращатель с авторством и счётчиком кликов |
| Туннель — HTTP | WebSocket-relay, стриминг без накопления тела в памяти на сервере |
| Туннель — TCP | 7 протоколов (SSH/RDP/VNC/Postgres/MySQL/Redis/MongoDB), TLS-терминация на прокси |
| Биллинг | Smart Billing Phase 2 — несколько тарифов, lazy-deduction, автопереключение, Тинькофф-эквайринг. См. BILLING.md |
| Анти-абуз (TCP) | rate-limit, детектор перебора slug'ов, лимит конкурентных соединений |
| Анти-абуз (HTTP) | анти-скрейпинг по объёму + узкий детектор перебора приватных slug'ов с исключением каталожных |
| Видимость инцидентов | журнал банов (файл + таблица tunnel_incidents), панель суперадмина, email-уведомление владельцу (VIP+), раздел «Безопасность» в кабинете (VIP+). См. SECURITY.md |
| Аналитика трафика | трафик/визиты/гео по туннелю, гейтится тарифом PRO/PERS |
| Заморозка туннелей | админ может заморозить туннель пользователя, отдельно от биллинга |
| Каталог туннелей | подача заявки, модерация, публичная страница dix.su/catalog с поиском и фильтром по категориям |
| Приватный режим (Фаза 1) | флаг private_mode с необратимым выбором при онбординге, верификация 1₽, 14-дневный SIMPLE-триал с автозаморозкой, ограничения визитки/каталога/коротких ссылок, access-gate для HTTP/HTTPS-туннеля (вход только владельцу через сессию dix.su). См. BILLING.md, SECURITY.md |
| Приватный режим (Фаза 2, E2E) | сквозное шифрование работает end-to-end: токены private_e2e_tokens/PrivateE2eController, DNS-01 helper через Cloudflare (AcmeDnsChallengeController), raw-relay без терминации TLS (DixuProxyWeb.Tcp.E2eRawListener, порт 9443), nginx stream{}-маршрутизация по SNI (подэтапы 2a/2b задеплоены и проверены на проде). device_client реализует ACME v2 (DNS-01) и локальный TLS-терминатор — приватный ключ никогда не уходит с устройства. Проверено на проде (Chrome, Firefox). См. SECURITY.md |
| Android — CIFS Documents Provider | Форк wa2c/cifs-documents-provider с нативной поддержкой dix.su-туннеля. DixsuTunnelForwarder.kt — loopback-прокси, отправляет preamble DIXSU:<slug>\n до SSH-хендшейка; JSch/SFTP-слой видит обычный локальный сервер. APK v2.4.0 раздаётся с dix.su/downloads/, раздел Android в ЛК. Исходники: gitlab.com/dixsu/applications/android/cifs-documents-provider |
| Контейнерные стеки (docker-compose) | Образ ramanzes/dixsu-tunnel:latest с elixir:1.19-slim + CA-сертификаты. Читает DIXSU_SLUG/DIXSU_TOKEN/LOCAL_PORT из env (без CLI-аргументов). TUNNEL_SOURCE=docker передаётся в WebSocket-URL, хранится в Registry, отображается в ЛК (📦 docker-стек). SSH/RDP/VNC заблокированы для docker-туннелей в UI. Настройки создания туннеля блокируются при активном туннеле (любого типа). Стеки: django_shop, dixsu-git, dixsu-test на GitLab. |
| Отзывы и репутация (профиль) | Полная система реакций + звёзд + комментариев на страницах профиля и каталога. Реакции like/complaint/abuse с весовой схемой по тарифу (1.0×SIMPLE, 1.5×VIP, 2.0×PRO, 3.0×PERS/GLAVA). Звёздный рейтинг (1–5) с агрегированным avg в реальном времени. Текстовые комментарии (до 1000 симв.). Поддержка анонимных отзывов (без входа) через hCaptcha + sessionStorage-дедупликация. Модерация-гейт: анонимные и низкодоверенные пользователи (email-only / только MetaMask) → pending до одобрения; высокодоверенные (есть верифицированная соцсеть кроме MetaMask) → сразу approved. Публичный вид одобренных анонимных отзывов с маркером «от анонимного пользователя». Владелец туннеля может одобрять неанонимные pending-отзывы (POST /api/reviews/{id}/approve-owner), суперадмин — одобрять и отклонять всё. Средний рейтинг (avg_rating) считается только по approved-отзывам и исключает анонимных (reviewer_id IS NOT NULL). Отображение в Otzovik-ленте — агрегированный feed с LEFT JOIN (анонимные отзывы видны после одобрения). Миграции V47–V52. |
| Платформа Otzovik | Независимые ресурсы (otzovik_resources) с отзывами (otzovik_reviews), не привязанные к туннелям. Оценки, голоса, агрегированная лента dix.su/otzovik. |
Известные пробелы¶
0. Lemon Squeezy — интеграция завершена, активация заблокирована¶
Код полностью готов и задеплоен (коммиты a3713a1…f4fa680):
- Кнопка «💳 Pay with card $X.XX» появляется у платных тарифов
- POST /api/billing/init-ls строит checkout URL напрямую (без server-side API
call — Cloudflare блокирует запросы с VPS к api.lemonsqueezy.com)
- POST /api/billing/notify-ls обрабатывает subscription_created /
subscription_payment_success, начисляет 30 дней
- Идемпотентность по payments.ls_order_id
Текущий блокер: магазин dixsu.lemonsqueezy.com не активирован —
Stripe Connect onboarding требует иностранный банковский счёт (IBAN/routing
number). Россия не поддерживается Stripe. Варианты разблокировки:
- Payoneer — принимает российский паспорт, даёт IBAN
- Wise — только если есть нероссийская резидентность
- Открыть счёт в Армении/Грузии/Казахстане лично
Текущее состояние на проде: LS_STORE_SLUG=dixsu задан, кнопка видна,
но при переходе на checkout — This store has not been activated (LS Dashboard).
После активации магазина через Stripe Connect: checkout заработает
без изменений в коде — всё уже готово.
1. Документация (исправлено в ревизии 2026-06-21)¶
До 2026-06-21 в репозитории было 8+ независимых .md-файлов в корне без
единого источника правды, с прямыми противоречиями (например, ветка
modulauth — prod или prod_update?). Консолидировано в docs/,
устаревшие документы архивированы в history/ с пометками
о текущем статусе описанных в них фич.
2. Device client — отдельный репозиторий¶
Клиент, который ставится на оборудование пользователя, физически не
находится в dixsu-infra — он в репозитории websocket-client/device_client_app
(рядом, но отдельно). Распространяется как готовый Burrito-бинарник (5
платформ) через личный кабинет. Документация — README.md в том репозитории;
архитектура — SECURITY.md "Фаза 2" (серверный взгляд на
протокол).
3. TEST/web-server и PATHTO/ — недокументированное содержимое в корне¶
TEST/web-server — тестовая фикстура (веб-сервер с загрузками для ручной
проверки туннеля), не имеет README, не часть прод-системы.
PATHTO/iroh_vs_dixsu_analysis.md — отдельная исследовательская заметка
(сравнение с проектом iroh), не связана с остальной документацией и не
отслеживается в git; оставлена нетронутой при этой ревизии, не являлась
частью консолидации.
4. Кнопка topbarReact на интерстициале — декоративная¶
Кнопка реакции на интерстициальной странице (interstitial_plug.ex) — декоративная,
ничего не сохраняет (это отдельный поверхностный виджет на интерстициале, не связанный
с полной системой отзывов на странице профиля dix.su/p/slug, которая полностью работает).
Вес голоса с аккаунтов private_mode=true должен быть принудительно нулевым, если
такая кнопка будет реализована (решение пользователя, см. docs/BILLING.md).
5. Явно неподдерживаемые протоколы (архитектурное ограничение)¶
UDP — не поддерживается в принципе. WebSocket-relay работает поверх TCP. Затронуто: Minecraft Bedrock Edition, большинство игровых серверов (UDP), DNS, VoIP/SIP, STUN/TURN.
Произвольные TCP-порты без TLS — маршрутизация требует TLS SNI от клиента. Протоколы, не поддерживающие TLS (Minecraft Java Edition/25565, большинство игровых движков, MQTT, и т.д.) не могут быть добавлены без изменения архитектуры маршрутизации.
Добавление нового TCP-протокола возможно только если клиентская библиотека поддерживает TLS. Это задокументированное ограничение, а не баг.
6. Интернационализация — частично реализована¶
Приоритет по сложности/отдаче:
| # | Задача | Сложность | Статус |
|---|---|---|---|
| 1 | Cookie consent banner (GDPR — EU) | S | ✅ (реализован) |
| 2 | Privacy Policy + T&C на английском | S | ✅ /en/privacy, /en/terms, /en/aup |
| 3 | Английская landing page + FAQ + контентные страницы | M | ✅ /en/, /en/faq, сервисные страницы через Accept-Language |
| 4 | Переключатель языка EN/RU (/set-lang) |
M | ✅ реализован |
| 5 | i18n публичных шаблонов (#{key}) |
M | ✅ landing, services, tunnel-landing и др. через messages_en.properties |
| 6 | Полный i18n защищённых страниц (protected-page.html и LK) |
L | ❌ не начато |
| 7 | Английская документация (dix.su/docs/) |
L | ❌ не начато |
Решение по домену: один домен dix.su, мультиязычный контент. Отдельный домен для международной версии не нужен — подробнее в guides/internationalization.md.
7. Android tunnel client — не реализован¶
Нативный клиент туннеля для Android (устройство само является хостом туннеля, а не потребителем).
Что нужно:
- WebSocket-клиент на Kotlin (OkHttp) — реализует протокол websocket-client/device_client_app
- Android Foreground Service с постоянной нотификацией («Туннель активен»)
- TCP-форвардинг: входящее соединение через WebSocket → локальный порт Android-устройства
- Wake Lock + исключение из battery optimization (Doze mode)
- UI: ввод токена, отображение статуса, список активных туннелей
Что уже есть как основа:
- DixsuTunnelForwarder.kt в cifs-documents-provider — реализует обратное направление (Android как клиент), логика splice потоков переиспользуется
- Протокол device_client в websocket-client/device_client_app (Elixir/Burrito) — эталон для переноса на Kotlin
- heartbeat/reconnect паттерн из device_client с pending_heartbeat
Сложности: агрессивный killер фона на MIUI/One UI, нужна watchdog-логика переподключения.
Оценка: 1–2 недели на ядро (WebSocket + форвардинг + Service + UI).
Статус: ❌ не начато
Не проверено / требует отдельного аудита¶
- Покрытие тестами (
dixu_proxy/test/существует, но глубина не оценивалась в рамках этого обзора — отдельная задача, если нужна). - Полный список переменных окружения в
.env.exampleне сверялся построчно с тем, что реально используется в коде (могут быть мёртвые/недокументированные переменные).