Skip to content

Управление интеграциями

Интеграции — это основная сущность приложения. Каждая интеграция представляет собой отдельную конфигурацию со своими credentials, secrets и handlers.

Обзор

Функциональность управления интеграциями включает:

  • ✅ Просмотр списка всех интеграций
  • ✅ Создание новых интеграций
  • ✅ Редактирование интеграций
  • ✅ Удаление интеграций
  • ✅ Управление credentials
  • ✅ Управление secrets
  • ✅ Управление handlers
  • ✅ Просмотр audit logs

Структура интеграции

typescript
interface IIntegration {
	id: string; // UUID
	name: string; // Название
	createdAt: string; // Дата создания
	updatedAt: string; // Дата обновления
}

Страницы

Список интеграций

URL: /admin/integrations

Отображает таблицу всех интеграций с возможностью:

  • Поиска по названию
  • Сортировки
  • Перехода к детальной странице
  • Удаления интеграции

Компонент: IntegrationsListComponent

typescript
@Component({
	selector: "app-integrations-list",
	standalone: true,
	imports: [MatTableModule, MatButtonModule, MatIconModule],
	templateUrl: "./integrations-list.component.html"
})
export class IntegrationsListComponent implements OnInit {
	private readonly integrationsService = inject(IntegrationsService);

	integrations: IIntegration[] = [];
	displayedColumns = ["name", "createdAt", "actions"];

	ngOnInit() {
		this.loadIntegrations();
	}

	loadIntegrations() {
		this.integrationsService.getAll().subscribe((integrations) => {
			this.integrations = integrations;
		});
	}

	deleteIntegration(id: string) {
		this.integrationsService.delete(id).subscribe(() => {
			this.loadIntegrations();
		});
	}
}

Создание интеграции

URL: /admin/integrations/new

Форма для создания новой интеграции.

Поля:

  • name — название интеграции (required)

Пример:

typescript
createIntegration() {
  const data: ICreateIntegrationRequest = {
    name: 'My New Integration'
  };

  this.integrationsService.create(data).subscribe(integration => {
    this.router.navigate(['/admin/integrations', integration.id]);
  });
}

Детальная страница

URL: /admin/integrations/:id

Детальная информация об интеграции с вкладками:

  1. Handlers — обработчики событий (webhooks)
  2. Secrets — секреты и конфиденциальные данные
  3. D1 — управление таблицами базы данных
  4. KV — управление key-value хранилищем
  5. Agent — настройки AI агента (промпт, ElevenLabs, голосовой ассистент)
  6. Tests — тестовые сценарии для интеграции
  7. Chats — история чатов с AI агентом

В заголовке страницы также есть быстрые ссылки на внешние сервисы:

  • Documentation — текстовая документация (https://integ.docs.happ.tools/integrations/{name})
  • API Docs — OpenAPI/Scalar документация ({baseUrl}/{name}/docs)
  • SaaS Platform, ElevenLabs, Inngest, Cloudflare Worker/Logs/Settings, D1, KV, GitHub Actions

Credentials

Credentials — это публичные учетные данные (например, API keys, usernames).

Операции

Просмотр

typescript
this.credentialsService.getByIntegration(integrationId).subscribe((credentials) => {
	console.log(credentials);
});

Создание

typescript
const data: ICreateCredentialRequest = {
	key: "API_KEY",
	value: "your-api-key-here"
};

this.credentialsService.create(integrationId, data).subscribe((credential) => {
	console.log("Created:", credential.id);
});

Обновление

typescript
const data: IUpdateCredentialRequest = {
	value: "new-api-key-value"
};

this.credentialsService.update(integrationId, credentialId, data).subscribe();

Удаление

typescript
this.credentialsService.delete(integrationId, credentialId).subscribe();

Пример использования

Credential для Telegram Bot:

typescript
{
  key: 'BOT_TOKEN',
  value: '123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11'
}

Secrets

Secrets — это конфиденциальные данные (например, webhook secrets, private keys).

Операции

API идентичен Credentials:

typescript
// Получить все секреты
this.secretsService.getByIntegration(integrationId);

// Создать секрет
this.secretsService.create(integrationId, {
	key: "WEBHOOK_SECRET",
	value: "secret-value"
});

// Обновить
this.secretsService.update(integrationId, secretId, {
	value: "new-secret-value"
});

// Удалить
this.secretsService.delete(integrationId, secretId);

Безопасность

Важно

Secrets хранятся в зашифрованном виде на backend'е. Frontend получает только зашифрованную версию.

Handlers

Handlers — это обработчики событий (webhooks).

Структура

typescript
interface IHandler {
	id: string;
	integrationId: string;
	name: string; // Используется в URL
	defaultArgs: Record<string, any>; // Дефолтные аргументы
	createdAt: string;
	updatedAt: string;
}

Синхронизация Handlers из OpenAPI

Handlers можно автоматически синхронизировать из OpenAPI спецификации integ-core. В UI рядом с кнопкой создания handler'а есть кнопка синхронизации (иконка sync).

typescript
this.integrationsService.syncHandlers(integrationId, { integrationName: "sofa" }).subscribe((result) => {
	console.log(`Created: ${result.created}, Updated: ${result.updated}`);
});

Синхронизация:

  • Делает запрос к {baseUrl}/{integrationName}/openapi.json
  • Парсит OpenAPI spec и извлекает handlers из paths
  • Создаёт новые или обновляет существующие handlers

Создание Handler

typescript
const data: ICreateHandlerRequest = {
	name: "order-created",
	defaultArgs: {
		timeout: 5000,
		retries: 3
	}
};

this.handlersService.create(integrationId, data).subscribe((handler) => {
	console.log("Handler URL:", `/webhook/${handler.name}`);
});

Выполнение Handler

Тестирование handler'а напрямую из UI:

typescript
this.handlersService
	.execute("order-created", "POST", {
		body: {
			orderId: "12345",
			amount: 100
		}
	})
	.subscribe((response) => {
		console.log("Status:", response.statusCode);
		console.log("Body:", response.body);
		console.log("Timestamp:", response.timestamp);
	});

Webhook URL

Handler доступен по URL:

POST https://your-domain.com/webhook/{handler-name}

Пример:

bash
curl -X POST https://api.example.com/webhook/order-created \
  -H "Content-Type: application/json" \
  -d '{"orderId": "12345", "amount": 100}'

Диалоги

Приложение использует Material Dialog для создания/редактирования:

Пример диалога создания Credential

typescript
@Component({
	selector: "app-credential-create-dialog",
	standalone: true,
	imports: [MatDialogModule, ReactiveFormsModule],
	template: `...`
})
export class CredentialCreateDialogComponent {
	private readonly dialogRef = inject(MatDialogRef);
	private readonly data = inject(MAT_DIALOG_DATA);

	form = new FormGroup({
		key: new FormControl("", Validators.required),
		value: new FormControl("", Validators.required)
	});

	onSubmit() {
		if (this.form.valid) {
			this.dialogRef.close(this.form.value);
		}
	}
}

Открытие диалога:

typescript
const dialogRef = this.dialog.open(CredentialCreateDialogComponent, {
	width: "500px",
	data: { integrationId }
});

dialogRef.afterClosed().subscribe((result) => {
	if (result) {
		this.credentialsService.create(integrationId, result).subscribe(() => {
			this.loadCredentials();
		});
	}
});

Audit Logs

Просмотр истории изменений интеграции.

typescript
this.auditService.getByIntegration(integrationId).subscribe((logs) => {
	console.log(logs);
});

API Endpoints

МетодEndpointОписание
GET/integrationsСписок интеграций
GET/integrations/:idДетали интеграции
POST/integrationsСоздать интеграцию
PUT/integrations/:idОбновить интеграцию
DELETE/integrations/:idУдалить интеграцию
POST/integrations/:id/sync-handlersСинхронизация handlers
GET/integrations/:id/credentialsСписок credentials
POST/integrations/:id/credentialsСоздать credential
PUT/integrations/:id/credentials/:credIdОбновить credential
DELETE/integrations/:id/credentials/:credIdУдалить credential
GET/integrations/:id/secretsСписок secrets
POST/integrations/:id/secretsСоздать secret
PUT/integrations/:id/secrets/:secIdОбновить secret
DELETE/integrations/:id/secrets/:secIdУдалить secret
GET/integrations/:id/handlersСписок handlers
POST/integrations/:id/handlersСоздать handler
PUT/integrations/:id/handlers/:handlerIdОбновить handler
DELETE/integrations/:id/handlers/:handlerIdУдалить handler

Типичные сценарии

Создание полной интеграции

typescript
// 1. Создать интеграцию
const integration = await firstValueFrom(this.integrationsService.create({ name: "Telegram Bot" }));

// 2. Добавить credential
await firstValueFrom(
	this.credentialsService.create(integration.id, {
		key: "BOT_TOKEN",
		value: "token-here"
	})
);

// 3. Добавить secret
await firstValueFrom(
	this.secretsService.create(integration.id, {
		key: "WEBHOOK_SECRET",
		value: "secret-here"
	})
);

// 4. Создать handler
await firstValueFrom(
	this.handlersService.create(integration.id, {
		name: "message-received",
		defaultArgs: { timeout: 5000 }
	})
);

Следующие шаги

SaaS Admin Documentation