Skip to main content
Эта страница доводит клон репозитория до работающей установки с учётной записью оператора, под которой можно войти. Она пока ничего не продаёт — это Ваша первая продажа, которая начинается там, где заканчивается эта страница. Всё описанное ниже — локальный стек Compose, поставляемый в репозитории. Он публикует порты на localhost, использует учётные данные из compose.yaml и не терминирует TLS. Для сервера, смотрящего в интернет, прочитайте Развёртывание и Обратный прокси, прежде чем что-либо выставлять наружу.

Перед началом

Что делает каждый сервис

compose.yaml описывает семь сервисов. Порт на хост публикуют только api и web; PostgreSQL и Valkey остаются во внутренней сети Compose.
У сервиса migrate DSN для разработки postgres://omniflow:omniflow@postgres:5432/omniflow?sslmode=disable жёстко зашит в команду, и .env он не читает. Если вы меняете учётные данные базы данных, меняйте их и в compose.yaml, иначе миграции будут применены не туда, куда смотрит приложение.

Настройте установку

Вся конфигурация, принадлежащая проекту, — это переменные окружения с префиксом APP_, читаемые один раз при старте. Конфигурационного файла нет, горячей перезагрузки нет: изменение значения означает перезапуск процесса, который его читает.
1

Скопируйте файл-пример

Пример — это полный файл с комментариями. Каждое значение в нём либо рабочее значение по умолчанию, либо пустая строка, которую вы должны заполнить.
2

Сгенерируйте два секрета

APP_DATA_ENCRYPTION_KEY должен декодироваться ровно в 32 байта, иначе запуск падает с APP_DATA_ENCRYPTION_KEY must be base64-encoded 32 bytes. Им запечатываются контактные данные, TOTP-секреты, клиентские секреты OIDC, учётные данные провайдеров и короткоживущая cookie процесса входа — потеря ключа означает потерю доступа ко всему этому.APP_OPERATOR_TOKEN — предъявительские учётные данные для всего префикса /v1/admin, сравниваемые за постоянное время. Подойдёт любая случайная строка с высокой энтропией.
3

Заполните значения, которые нужны процессам

Отказы намеренны и происходят при старте, а не на первом запросе:Другие значения валидируются так же: APP_DEFAULT_CURRENCY после приведения к верхнему регистру должен совпадать с ^[A-Z]{3}$, APP_TELEGRAM_WEBHOOK_URL должен быть HTTPS, а APP_TELEMETRY_ENDPOINT должен быть HTTPS-URL, пока телеметрия включена.
4

Разрешите cookie по обычному HTTP для локального стека

Обе по умолчанию равны true, и это правильно для всего, перед чем стоит TLS. При отключении API пишет admin session cookie is not marked Secure; use this only for local development, и это предупреждение точное: без Secure cookie сессии можно перехватить из любого незашифрованного запроса к тому же хосту. Верните обе в true, прежде чем установка покинет вашу машину.

Поднимите стек

migrate запускается первым и завершается; api, bot и worker стартуют после его успешного завершения и после того, как Valkey отчитается о здоровье. Затем запустите веб-приложение, которое обслуживает и клиентский кабинет, и операторское рабочее место:
После этого:
  • API — http://localhost:8080
  • Клиентский кабинет — http://localhost:3000
  • Рабочее место оператора — http://localhost:3000/admin
make dev — это первая команда без migrate в списке аргументов, make up — всё вместе с профилем web, а make down останавливает всё. Полный перечень целей выдаёт make help.

Создайте первого владельца

В свежей установке нет ни одной учётной записи оператора, поэтому страница входа была бы тупиком. При старте, пока ни одного оператора не существует, API выпускает одноразовый токен настройки и пишет его в собственный лог на уровне предупреждения. Токен идёт в лог, а не в HTTP-ответ, потому что в этот момент никто не может аутентифицироваться, и эндпоинт, выдающий токен, выдал бы его любому спросившему.
1

Прочитайте токен из лога API

Токен действует 30 минут и может быть использован один раз. Перезапуск API, пока владельца нет, выпускает новый; как только владелец есть, перезапуск не печатает ничего, а POST /v1/panel/bootstrap навсегда отвечает 409 bootstrap_closed.
2

Используйте его на /admin/setup

Откройте http://localhost:3000/admin/setup. Форма запрашивает токен настройки, отображаемое имя длиной 1–80 символов, адрес электронной почты и пароль длиной 12–256 символов. Требований к составу пароля нет; единственное требование — длина, и форма в браузере в точности повторяет то, что проверяет API.Открытие /admin/login на установке, которой всё ещё нужен первый владелец, автоматически перенаправляет сюда, а эта страница перенаправляет обратно на экран входа в тот момент, когда учётная запись появляется, — так что забытая вкладка не может остаться на форме, которую больше нельзя отправить.Отказ конкретен: 422 weak_password для слишком короткого пароля, 409 email_in_use для уже зарегистрированного адреса, 409 bootstrap_closed после того, как первичная настройка завершена.
3

Войдите

Вас перенаправляет на /admin/login. Введите адрес и пароль. У учётной записи ещё нет второго фактора, поэтому вы попадаете на дашборд по адресу /admin.Вход отвечает одинаково на неверный пароль, неизвестный адрес и отключённую учётную запись — все три случая дают 401 invalid_credentials, — поэтому эндпоинт нельзя использовать, чтобы выяснить, за какими адресами закреплены учётные записи операторов. Частота ограничена десятью попытками в минуту на адрес и тридцатью в минуту на IP клиента, а если Valkey недоступен, проверка отказывает в доступе.

Включите двухфакторную аутентификацию

Первый владелец обладает всеми правами доступа в установке, включая единственную роль, которая может создавать других операторов. Дайте этой учётной записи второй фактор, прежде чем делать ею что-либо ещё.
1

Начните настройку

Откройте /admin/security и нажмите Настроить двухфакторную. В ответе приходят TOTP-секрет и URI otpauth://. Секрет показывается и текстом, и в QR-коде, потому что аутентификатор, работающий на том же устройстве, не может отсканировать экран, на котором он сам находится.Подпись, которую покажет ваш аутентификатор, берётся из APP_ADMIN_TOTP_ISSUER, по умолчанию равного Omniflow.
2

Подтвердите первый код

Введите шестизначный код и отправьте его. Пока код не подтверждён, секрет хранится неподтверждённым и не удовлетворяет ни одной проверке при входе, поэтому недоделанная настройка никогда не может заблокировать вам доступ. Неверный код отвечает 422 invalid_code; подтверждение без начала настройки отвечает 409 totp_not_started.
3

Сохраните резервные коды

Подтверждение возвращает десять одноразовых резервных кодов. Они показываются один раз и больше никогда — перевыпуск заменяет весь набор и обесценивает каждый неиспользованный код. Поле кода при входе принимает 6–24 символа и является текстовым, а не числовым, потому что резервный код содержит буквы.
Отключение второго фактора требует пароля от учётной записи, потому что снятие фактора — это ровно то, что попробует сделать атакующий с угнанной сессией. Смена пароля завершает все остальные сессии, а Завершить все остальные намеренно щадит ту сессию, из которой вы защищаете учётную запись. Сессиями управляют три числа: 30-минутный таймаут бездействия, который сдвигается, 12-часовой абсолютный таймаут, который не сдвигается никогда, и ротация токена каждые 15 минут.

Убедитесь, что всё работает

Живость и готовность отвечают на разные вопросы и намеренно вынесены в отдельные эндпоинты: процесс, который работает, но не может достучаться до PostgreSQL, следует убрать из балансировщика, а не перезапускать. /healthz — тот же обработчик, что и /livez, оставленный для развёртываний, которые уже его опрашивают.
Здоровый API отвечает 200:
Нездоровая зависимость превращает ответ в 503 с "status": "degraded", а отказавшая проверка несёт "error": "timeout" или "error": "unavailable" плюс счётчик consecutiveFailures. Эти два слова — единственные существующие значения ошибки: ошибка pgx или HTTP регулярно содержит DSN, имя хоста или учётные данные, поэтому проба сообщает классификацию вместо неё. Проба remnawave — это аутентифицированный вызов, а значит, отозванный токен API проявится здесь как нездоровая зависимость, а не как загадочный сбой выдачи доступа позже. Какие пробы регистрирует каждый процесс, различается, и это важно:
API, запущенный без APP_DATABASE_URL, сообщает о своей готовности, обслуживая почти ничего. Если /readyz зелёный, а /v1/catalog/plans не существует, проверьте, дошёл ли URL базы данных до контейнера.
Под учётной записью оператора та же информация доступна на /admin в разделе Система → Состояние (GET /v1/panel/overview/health, право доступа system.read) — вместе со здоровьем платёжных провайдеров и провайдеров цифровых товаров, которое HTTP-проба не покрывает.

Что не работает на свежем клоне

Это текущие факты о main, а не ошибки конфигурации. Прочитайте их, прежде чем заключить, что ваша установка сломана.
  • У долговечной очереди заданий нет схемы. Omniflow ставит фоновую работу в очередь через River, но ни одна закоммиченная миграция не создаёт собственных таблиц River, и ничто в стеке не запускает мигратор River. Поэтому на базе, мигрированной только через docker compose up migrate, worker завершается при старте с записью start River, а любой расчёт — который вставляет задание исполнения в той же транзакции, что и деньги, — откатывается. Покупка не может завершиться, пока не появится эта миграция. О том, где именно останавливается тестовая покупка, см. Ваша первая продажа, а о том, что очередь должна делать, — Задания и очереди.
  • Транзакционный outbox пишется и никогда не публикуется. Вставляются три темы, published_at никто никогда не проставляет, и диспетчера не существует. Поэтому счётчики outbox на дашборде и в GET /v1/admin/outbox растут навсегда, APP_RETENTION_OUTBOX_DAYS не удаляет ничего, а пункт внимания «отставание outbox» на /admin ожидаем, а не диагностичен.
  • Провайдера трассировки нет. Код открывает спаны в HTTP, обновлениях Telegram, заданиях и SQL, но ни один экспортёр не установлен и ни одна переменная OTEL_* нигде в репозитории не читается. Установка стандартных переменных OpenTelemetry ничего не меняет; глобальный провайдер остаётся пустышкой. То, что установка на самом деле отдаёт, — это метрики и логи, см. Наблюдаемость.
  • Каждый бинарник сообщает "version":"dev". Версия не проставляется при сборке нигде, включая выпущенные образы, поэтому /livez, диагностический пакет и heartbeat телеметрии одинаково говорят dev.
  • Разделы настроек в панели не конфигурируют рантайм. Сохранение раздела складывает документ; подключение к Remnawave, бот, группа операторов, политика обслуживания, телеметрия, резервные копии и платёжные адаптеры берутся из переменных окружения, прочитанных при старте. См. Настройки установки.
  • Упавший процесс никто не перезапускает. Ни один основной сервис Compose не объявляет политику restart:, поэтому завершившийся процесс остаётся лежать, пока кто-нибудь не заметит. Добавьте её всему, что должно работать долго.
  • У вложения к обращению, загруженного из браузера, нет тома. APP_SUPPORT_ATTACHMENT_DIR по умолчанию равен /var/lib/omniflow/support-attachments и читается и api, и worker, но compose.yaml не монтирует туда том ни для одного из них. Файлы живут в записываемом слое контейнера, пока его не пересоберут, а воркер не может освободить место от файлов, которых не видит.

Дальнейшие шаги

Ваша первая продажа

Создайте тариф, назначьте цену версии, настройте провайдера, подключите бота и проведите тестовую покупку.

Справочник по конфигурации

Каждая переменная, её значение по умолчанию, какой процесс её читает и что она меняет.

Развёртывание

Тома, теги образов, миграции, обновления и поддерживаемая топология.

Обратный прокси

TLS, ограничения на размер тела и то, как держать /metrics и /readyz вне публичного хоста.

Резервное копирование и восстановление

Включите шифрованные резервные копии до того, как появится что терять.

Анонимная телеметрия

Точный состав данных и единственная переменная, которая останавливает все запросы телеметрии.