RefLink: пример плагина
RefLink — открытый полнофункциональный плагин реферальных кампаний для Senler. В одном репозитории находятся frontend, backend, общие контракты, миграции, пользовательская документация и файлы самостоятельного запуска.
Этот раздел объясняет приложение в том порядке, в котором проходит реальная работа: как открывается встроенная страница, как backend получает доступ к проекту, как AI вызывает действия через MCP и как выполняется шаг автоматизации. После этого можно переходить к конкретным папкам и файлам.
Как пользоваться примером
RefLink полезен, если новому плагину нужны несколько возможностей сразу:
- встроенная страница внутри кабинета;
- OAuth-доступ к API Senler от имени проекта;
- собственный шаг автоматизации и форма его настройки;
- действия backend, доступные AI через MCP;
- webhook с проверкой подписи и защитой от повторной обработки;
- общие типы между frontend и backend;
- публичная документация на русском и английском языках.
Не копируйте приложение целиком. Сначала выберите нужный сценарий, затем возьмите соответствующий слой и адаптируйте права, данные и время жизни сессий под свой продукт.
RefLink не реализует конфигуратор инструмента агента. Для него используется тот же подход с Senler Bridge, но backend-операция размечается AgentToolConfigurator, а frontend обрабатывает запуск tool_configurator.
Технологии и их роль
| Часть | Технология | Для чего используется |
|---|---|---|
| Frontend | React и Senler UI | Интерфейс встроенной страницы, форма настройки шага и взаимодействие с кабинетом через Senler Bridge. |
| Backend | NestJS | HTTP-контроллеры, проверка DTO, модули приложения, OAuth, сессии и обработчики webhook. |
| API-контракт | OpenAPI и NestJS Swagger | Описание обычных endpoint и выбранных действий приложения для MCP. |
| API Senler | @senlerio/api | Типизированные вызовы каналов, лидов, переменных, агентов, сегментов и автоматизаций. |
| Хранилище | PostgreSQL и TypeORM | Кампании, OAuth-подключения, обработанные события и техническое состояние выдачи награды. |
| Локальный запуск | Docker Compose | Совместный запуск frontend, backend и PostgreSQL с воспроизводимой конфигурацией. |
Как проходит запрос
У RefLink есть три основных сценария. Они используют один backend, но разные способы входа и разные полномочия.
- Встроенная страница: запуск, сессия и доступ к API проекта.
- Действия через MCP: публикация методов и их вызов AI.
- Шаг автоматизации: конфигуратор и выполнение webhook.
В каком порядке читать исходный код
| Шаг | Раздел репозитория | Что станет понятно |
|---|---|---|
| 1 | README.md | Назначение приложения, режимы кампаний, запуск и публикация документации. |
| 2 | docs/architecture.md | Где хранятся данные и почему реферальная статистика не дублируется в Postgres. |
| 3 | docs/senler-app-setup.md | Какие URL, события, OAuth-права и поля результата указываются в настройках приложения. |
| 4 | contracts/src/index.ts | Общие типы, режимы кампаний и результаты шага, которыми пользуются обе части приложения. |
| 5 | frontend/src | Подключение Bridge, обмен кода на сессию и переключение между основной страницей и конфигуратором. |
| 6 | backend/src/core/session | Проверка одноразовых кодов, project-scoped сессии и защита endpoint. |
| 7 | backend/src/resources/oauth | OAuth callback, хранение подключения и обновление токенов. |
| 8 | backend/src/integrations/senler | Изолированный адаптер для вызовов API Senler. |
| 9 | backend/src/resources/campaigns | CRUD кампаний, статистика, создание автоматизации и OpenAPI-действия. |
| 10 | backend/src/resources/referrals | Подписи webhook, дедупликация, атрибуция и выдача наград. |
| 11 | docs/public и assets/catalog | Как хранить пользовательскую документацию и материалы карточки приложения рядом с кодом. |
| 12 | docker-compose.yml | Как связаны frontend, backend, база данных, health-check и переменные окружения. |
Ключевые архитектурные решения
Проект определяется доверенным контекстом
project_id из query-параметра, тела запроса или аргументов AI нельзя считать доказательством доступа. RefLink определяет проект только после проверки launch_code, сессии приложения, management token, OAuth subject или подписи webhook. Затем сервисы получают уже подтверждённый ID через @EmbeddedProject().
Это решение предотвращает ситуацию, когда пользователь или AI подставляет ID другого проекта в обычный параметр.
Авторизация разделена по назначению
| Значение | Кто выдаёт | Для чего оно нужно |
|---|---|---|
launch_code | Senler | Одноразово подтвердить запуск страницы или management session и передать подписанный контекст проекта. |
session_token | Backend RefLink | Разрешить открытому frontend обращаться к backend RefLink в рамках одного проекта. |
management_token | Backend RefLink | Разрешить Senler вызвать конкретное действие приложения через MCP. |
| OAuth access/refresh token | Senler OAuth | Разрешить backend RefLink обращаться к API Senler с подтверждёнными пользователем правами проекта. |
Ни один из этих токенов не следует использовать вместо другого. Секреты OAuth хранятся в зашифрованном виде через SecretVaultService, а новая пара access/refresh сохраняется вместе под блокировкой подключения в OAuthConnectionService.
SDK отделён от предметной логики
Контроллеры и сервисы кампаний не формируют HTTP-запросы к Senler напрямую. Все такие вызовы собраны в SenlerApiClient, который использует официальный SDK.
Так проще обновлять SDK, тестировать ответы и временно изолировать операции, которых ещё нет в опубликованной версии клиента.
Источник данных выбирается заранее
В PostgreSQL RefLink хранит настройки кампаний, OAuth-подключения и техническое состояние. Реферальные связи и счётчики остаются в переменных лидов Senler. Приложение не поддерживает вторую копию той же статистики и не синхронизирует два источника истины.
Это не универсальная схема данных, но универсальный принцип: до разработки нужно определить владельца каждого вида данных и хранить локально только то, что действительно принадлежит приложению.
Что переиспользовать в новом приложении
- Создайте отдельные пакеты или каталоги для общих контрактов, frontend, backend и интеграционного адаптера.
- Реализуйте проверку
launch_codeи project-scoped сессию до разработки бизнес-форм. - Добавьте OAuth только с необходимыми правами, храните токены зашифрованными и сохраняйте новую пару после refresh атомарно.
- Подключите Senler UI и Senler Bridge, затем явно обработайте каждый нужный
context.launch.type. - Оставьте бизнес-endpoint обычными контроллерами с DTO, а выбранные операции опубликуйте через
AppAction,AgentToolConfiguratorилиAutomationStepConfigurator. - Проверьте полученный OpenAPI командой
senler-app validate-openapiдо добавления URL в настройки приложения. - Для webhook сначала реализуйте проверку подписи, event ID, идемпотентность и восстановление зависшей обработки, затем добавляйте предметный сценарий.
- Храните пользовательскую документацию и материалы каталога рядом с исходным кодом и проверяйте русскую и английскую версии в CI.
Что не копировать без проверки
- OAuth-права RefLink: новому приложению может требоваться меньше или больше разрешений.
- Срок жизни сессии: его выбирают по риску, способу повторного запуска и требованиям продукта.
- Имена переменных лидов, webhook-события, поля результата и правила награды: это предметная модель реферального приложения.
- URL endpoint и имена переменных окружения: они должны принадлежать вашему домену и инфраструктуре.
- Все MCP-действия сразу: публикуйте только операции, которые AI действительно должен вызывать, и точно отмечайте
read_only,destructiveиidempotent.