Skip to content

Ваш первый модуль

Мы соберём минимальный модуль, который монтирует страницу в оболочке Building OS и читает данные через контекст платформы. Бюджет: 30 минут.

1. Создание каркаса

Начните с эталонного модуля — это канонический, заведомо рабочий образец:

bash
# Клонируйте репозиторий платформы (или только каталог эталонного модуля)
git clone git@github.com:tangovision/tv-platform.git
cp -r tv-platform/modules/tv-module-example my-module
cd my-module

2. Напишите манифест

module-manifest.json:

json
{
  "$schema": "https://npm.k8s.tangovision.dev/@tv/extension-sdk/1.0.0/manifest.schema.json",
  "id": "@acme/module-hello",
  "name": "Hello Module",
  "version": "1.0.0",
  "minCoreVersion": ">=2.0.0",
  "category": "operations",
  "permissions": [
    { "subject": "building.spaces", "actions": ["read"] }
  ],
  "events": {
    "publishes": [],
    "subscribes": []
  },
  "ui": {
    "routes": [{ "path": "/hello" }],
    "navigation": [
      { "label": "Hello", "path": "/hello", "section": "operations" }
    ]
  }
}

3. Проверьте его

bash
npx tv-sdk validate module-manifest.json
✓ Manifest is valid (version 1.0.0)

Если он неверен, валидатор укажет точное поле:

✗ permissions[0].subject: must be one of [building.spaces, building.elements, ...]

Встройте это в свой CI, чтобы сломанный манифест никогда не покидал вашу машину:

yaml
# .github/workflows/manifest.yml
- run: npx @tv/extension-sdk validate module-manifest.json

4. Соберите фронтенд

Ваш модуль экспортирует федеративный Shell. Внутри него используйте контекст платформы:

tsx
// frontend/src/App.tsx
import { usePlatformContext, useBuilding } from '@tv/extension-sdk/react';
import { useQuery } from '@tanstack/react-query';

export default function App() {
  const { api } = usePlatformContext();
  const building = useBuilding();

  const { data: spaces } = useQuery({
    queryKey: ['spaces', building.id],
    queryFn: () => api.get(`/api/v1/buildings/${building.id}/spaces`),
  });

  return (
    <div>
      <h1>Hello from {building.name}</h1>
      <p>{spaces?.length ?? 0} spaces</p>
    </div>
  );
}

Никаких токенов, никаких URL, которые нужно собирать вручную. Клиент api предварительно аутентифицирован и ограничен областью активного арендатора.

5. (Опционально) Объявите возможность бэкенда

Если у вашего модуля есть бэкенд на NestJS:

ts
import { ModuleCapability, RequiresLicense } from '@tv/extension-sdk/nestjs';

@ModuleCapability({ id: 'hello.greeting', version: '1.0.0' })
@Controller('api/v1/buildings/:buildingId/hello')
export class HelloController {
  @RequiresLicense('@acme/module-hello')
  @Get()
  greet() {
    return { message: 'hello' };
  }
}

6. Протестируйте на мок-контексте

ts
import { createMockPlatformContext } from '@tv/extension-sdk/testing';
import { PlatformProvider } from '@tv/extension-sdk/react';
import { render } from '@testing-library/react';
import App from './App';

const ctx = createMockPlatformContext({
  user: { ...defaultUser, roles: ['manager'] },
});

render(
  <PlatformProvider value={ctx}>
    <App />
  </PlatformProvider>,
);

Вы тестируете на точно той же форме контекста, что используется в продакшене — просто заполненной фейковыми данными. Никаких сюрпризов «работает у меня, ломается в проде».

7. Запустите его в песочнице

Перед публикацией прогоните модуль на настоящем (изолированном) здании:

Создать песочницу

Что вы только что узнали

  • Манифест — это ваш контракт; проверяйте его в CI.
  • PlatformContext — ваша единственная дверь к состоянию платформы.
  • Мок-контекст делает тесты соответствующими продакшену.
  • Эталонный модуль — это образец для копирования.

Далее: разберитесь с PlatformContext и событиями.

Создано на платформе Tango Vision. Вопросы? developers@tango.vision