Песочницы по запросу
Песочница — это ваша отдельная организация в Tango Vision: собственная база данных PostgreSQL, наполненный граф здания и выделенный стек tv-api — на собственном поддомене. Вы разрабатываете в ней вместо продакшена.
Что изолировано, а что общее
«Изоляция» — слово, которое стоит расшифровать: важно понимать, до чего может дотянуться ошибка в вашей песочнице.
Изолировано:
- База данных. У каждой песочницы своя база и своя роль PostgreSQL для подключения к ней — на выделенном сервере Postgres, где нет продуктивных данных. Эта роль не может открыть базу другой песочницы, а также (tv-platform#822) базу
postgresна этом сервере и — если провижинер хранит своё состояние на том же сервере — эту базу состояния. - Под. tv-api песочницы — отдельный Deployment в изолированном пространстве имён (
dev), отличном от продуктивного, со своим Secret и своим токеном. - Сетевой путь до продакшена. Между этим пространством имён и продакшеном стоят NetworkPolicy. Кроме того, у пода песочницы выключены продуктивный брокер MQTT (
WIFI_SENSING_MQTT_ENABLED=false) и регистрация на платформе — заданы вenvконтейнера, поэтому унаследовать другое значение он не может. - Оболочка, которая загружает ваш модуль. Сторонний код модуля работает только в оболочке песочницы, привязанной к вашей песочнице, и никогда — в продуктивной оболочке; см. Ваш модуль в оболочке песочницы.
Общее:
- Кластер Kubernetes. Песочницы — это пространства имён в том же кластере, а не отдельный кластер. Именно поэтому существуют квоты ниже.
- Один реалм Keycloak. Все песочницы аутентифицируются в единственном реалме
sandboxes(никогда не в продуктивном). Разделение внутри него задумано по клеймуtenant_id, равномуorganizationIdвашей песочницы, а не по отдельному реалму на разработчика. - Сам провижинер и его база метаданных: в ней лежат записи песочниц и API-ключи всех разработчиков.
Вход в песочницы пока общий (на 26.09.2026)
Сейчас любая песочница пускает любого пользователя общего реалма sandboxes, для какой бы песочницы ни была заведена его учётная запись: описанная выше проверка tenant_id пока не применяется. Исправление, после которого каждая песочница будет пускать только пользователей своей организации, уже в работе; когда оно выйдет, это предупреждение уберём. До тех пор исходите из того, что в вашу песочницу может войти любой пользователь песочниц, и храните в ней только синтетические данные.
Итого: роль базы данных вашей песочницы не может прочитать базу другой песочницы, и ошибка в ней не достаёт до продакшена. Но это не приватный кластер и не граница безопасности, которую стоит проверять намеренно, — об этом же просят условия использования.
Только синтетические данные. Не загружайте в песочницу реальные данные компании (списки арендаторов, планы этажей, любые сведения о реальных людях), если это не согласовано с нами письменно. Песочницы — общая инфраструктура, у них ограниченный срок жизни, а сохранность данных не гарантируется.
Общего исходящего доступа в интернет нет. Поды песочницы не могут делать произвольные исходящие вызовы. Одно следствие всплывает сразу: Copilot песочницы не может достучаться до внешней LLM, поэтому ИИ-функции, которые ходят к провайдеру, в песочнице работать не будут. Разрабатывайте их на моках, см. Свой LLM-эндпоинт.
Зачем
- Реалистичность. Она наполнена параметризованным зданием —
mall,officeилиuniversity— с помещениями, элементами и телеметрией, чтобы ваш модуль отрисовывался на данных реальной формы. - Одноразовость. Сбросьте её, когда навели беспорядок; она истекает автоматически.
Создание — через CLI
SDK покрывает весь жизненный цикл, так что писать curl руками не нужно. Войдите один раз (вход через CLI) — и каждая команда sandbox аутентифицируется сама, из системного хранилища ключей:
npx @tv/extension-sdk login
npx @tv/extension-sdk sandbox create \
--name="acme-cafm-dev" \
--type=mall \
--storeys=3 \
--area-sqm=20000 \
--seed-telemetry-days=14 \
--ttl-days=30В CI и любой другой неинтерактивной среде вместо входа используйте API-ключ, выпущенный в портале — явные учётные данные всегда важнее сохранённой сессии:
export TV_API_TOKEN=$SANDBOX_API_KEY # tvk_-ключ из портала
npx @tv/extension-sdk sandbox listПо умолчанию CLI обращается к https://sandbox-api.k8s.tangovision.dev; перенаправить его можно флагом --api=<url> (или переменной TV_SANDBOX_API_URL).
| Подкоманда | Что делает |
|---|---|
create | Создаёт песочницу. --dry-run генерирует наполнение локально, не обращаясь к сервису. --type=university допустим начиная с 1.14.0 (требуется @tv/extension-sdk 1.14.0 или новее): сервис и шаблоны наполнения принимали его всегда, но собственный разбор аргументов в CLI отклонял его вплоть до 1.13.0 включительно. На более старом CLI создавайте университет через API ниже. |
list | Список ваших песочниц |
connect <id> | Печатает запись песочницы, а затем её собственный URL tv-api и токен администратора как настройки TV_API_URL=… / TV_API_TOKEN=… — только для серверного кода (скрипта, локального бэкенда; никогда для кода в браузере). Не экспортируйте их в терминале, где вы запускаете команды sandbox: list и create читают их как адрес сервиса песочниц и ваш ключ и начнут обращаться к вашей песочнице. SDK 1.15.0 печатал их строками export. |
extend <id> --days=N | Продлевает TTL. --days обязателен, целое число 1–7. |
reset <id> | Очищает и заново наполняет, не удаляя |
delete <id> | Удаляет немедленно |
install <manifest> | Регистрирует ваш модуль в вашей собственной песочнице, выдаёт лицензию и печатает URL, который нужно открыть. Начиная с 1.14.0 (требуется @tv/extension-sdk 1.14.0 или новее); см. Ваш модуль в оболочке песочницы. |
<id> (и install --sandbox=<id>) — это идентификатор песочницы вида sbx_…: его печатает create, а sandbox list показывает идентификаторы всех ваших песочниц. Это не slug из URL песочницы.
Дополнительные параметры наполнения: --spaces-min / --spaces-max (по умолчанию 10/30), --equipment-density=sparse|realistic|dense, --occupancy-profile=24x7|office-hours|peak-evenings, --ttl-days=N (1–30, по умолчанию 14) и --seed=<строка> для детерминированной генерации. Добавьте --format=json к любой подкоманде, чтобы использовать её в скриптах. create, list и connect показывают slug и organizationId каждой песочницы и в обычном выводе (SDK 1.15.1 и новее; 1.15.0 показывал их только с --format=json), а create заканчивает вывод строкой, которую нужно прислать нам для учётных записей в песочнице.
Поддомен — это slug, который сервис собирает как <ваша-организация>-<первые 16 символов имени>-<6 случайных символов>: он начинается с вашей организации и поэтому никогда не конфликтует с одноимённой песочницей другой организации:
https://dev-a1b2c3d4e5f6-acme-cafm-dev-k2x7p9.sandbox.k8s.tangovision.devSlug вашей организации — dev-<12 шестнадцатеричных символов>: каждая учётная запись разработчика — отдельная организация. Это же и граница «ваших» песочниц, и единица, в которой считаются квоты ниже. Если над одной песочницей работают двое, см. Два разработчика, одна песочница.
Создание — через API
curl -X POST https://sandbox-api.k8s.tangovision.dev/api/v1/sandboxes \
-H "Authorization: Bearer $SANDBOX_API_KEY" \
-H "content-type: application/json" \
-d '{
"name": "acme-cafm-dev",
"buildingType": "mall",
"storeys": 3,
"areaSqm": 20000,
"ttlDays": 14
}'Ответ — 202 Accepted. Развёртывание идёт в фоне (база данных, граф здания с данными и отдельный стек tv-api — на реалистичных параметрах это несколько минут), поэтому запись возвращается в статусе provisioning:
{
"sandboxId": "sbx_...",
"name": "acme-cafm-dev",
"slug": "dev-a1b2c3d4e5f6-acme-cafm-dev-k2x7p9",
"status": "provisioning",
"apiUrl": "https://dev-a1b2c3d4e5f6-acme-cafm-dev-k2x7p9.sandbox.k8s.tangovision.dev",
"consoleUrl": null,
"apiToken": "...",
"organizationId": null,
"buildingId": null,
"createdAt": "2026-05-30T...",
"expiresAt": "2026-06-13T...",
"extensionsUsed": 0,
"extensionsRemaining": 2,
"failureReason": null
}apiToken — собственные учётные данные песочницы, сохраните их: они дают права администратора в API этой песочницы — и больше нигде. organizationId и buildingId остаются пустыми, пока развёртывание не завершится.
consoleUrl — интерфейс, привязанный к этой песочнице. Он равен null, пока не развёрнута оболочка песочницы. Если она развёрнута, это тот же хост песочницы: оболочка отдаётся на /, а API остаётся на /api и /socket.io, поэтому интерфейс и бэкенд работают в одном origin. Оболочка песочницы — отдельный деплой, не продовый: код модуля полностью доверен в той оболочке, которая его загружает, поэтому ваш модуль запускается только в оболочке, привязанной к вашей песочнице.
organizationId — идентификатор организации песочницы. У всех песочниц один общий реалм Keycloak, и по замыслу пользователь входит именно в вашу песочницу только тогда, когда его клейм tenant_id равен этому значению (пока это не применяется, см. предупреждение в разделе Что изолировано, а что общее). Это значение нужно оператору, чтобы завести учётную запись в песочнице; оно уникально для каждой песочницы, а не для её имени.
Опрашивайте эндпоинт детализации, пока status не выйдет из provisioning:
curl -H "Authorization: Bearer $SANDBOX_API_KEY" \
https://sandbox-api.k8s.tangovision.dev/api/v1/sandboxes/sbx_...Всего статусов пять: provisioning, ready, failed, expired и deleted. ready — песочница готова (заполнены buildingId и итоговый apiUrl); failed — в failureReason записана причина, и это терминальный статус. CLI (sandbox create) опрашивает сервис сам каждые 5 секунд и завершается, когда песочница готова, — либо сдаётся через 15 минут, после чего развёртывание продолжается на сервере, а результат покажет sandbox list.
Жизненный цикл
| Действие | Эндпоинт | Ответ |
|---|---|---|
| Список | GET /api/v1/sandboxes | 200 { sandboxes: [...] } |
| Получить одну | GET /api/v1/sandboxes/:id | 200 — именно её вы опрашиваете |
| Создать | POST /api/v1/sandboxes | 202, статус provisioning |
| Продлить TTL | POST /api/v1/sandboxes/:id/extend, тело { "days": 7 } | 201 |
| Сбросить | POST /api/v1/sandboxes/:id/reset | 201 либо 409, если статус не ready |
| Удалить | DELETE /api/v1/sandboxes/:id | 204, идемпотентно |
Поле days при продлении обязательно и должно быть целым числом 1–7; без него — 400. Обратите внимание, что это другая граница, чем у --ttl-days при создании (1–30), поэтому --days=14 будет отклонён.
Что делает reset
Команда удаляет и заново создаёт базу данных песочницы, выполняет тот же шаг миграции и наполнения, что и create, с параметрами, с которыми песочница была создана, и перезапускает API песочницы на новой базе — вы получаете свежий граф здания с теми же id, URL и токеном. Идентификатор здания меняется, потому что граф генерируется заново. Пока API перезапускается, он около минуты недоступен.
Если наполнение не удалось, песочница переходит в статус failed, а не остаётся ready с пустой базой; удалите её и создайте новую.
Квоты
Чтобы общий кластер оставался здоровым:
- 3 одновременно активные песочницы на организацию (считаются
provisioningиready;expiredиdeleted— нет) - 2 продления TTL на песочницу, по 7 дней максимум каждое
- 30 дней — максимальный TTL при создании, то есть предельный срок жизни одной песочницы — 44 дня
Напоминаний перед истечением срока нет, а истёкшую песочницу продлить нельзя: её база и хост удаляются. Запишите дату expires при создании и продлевайте вовремя.
modules при создании не принимается: непустой массив — это 400 с кодом MODULES_NOT_SUPPORTED. Раньше поле принималось и молча отбрасывалось: песочница поднималась без запрошенных модулей, и ничто об этом не сообщало. Устанавливайте модуль в песочницу, когда она перешла в ready, командой sandbox install (SDK 1.14.0 или новее). Текст самой ошибки до сих пор утверждает, что эта команда не выпущена; он устарел.
Превышение квоты — это 403 с машиночитаемым кодом: QUOTA_CONCURRENCY при достижении лимита одновременных песочниц и QUOTA_EXTENSIONS, когда песочница израсходовала оба продления. Некорректное тело запроса — 400; неизвестные поля отклоняются, а не игнорируются.
Что внутри свежей песочницы
- Организация + площадка + здание, наполненные через
@tv/sandbox-seed(закрытый пакет; его перечислениеBuildingType— ровноmall | office | university) - Этажи, помещения, элементы и точки, размер которых задан вашими параметрами
- До 30 дней дозаполненной телеметрии (настраивается через
seedTelemetryDays) - Стандартная схема tv-api, так что работают все эндпоинты платформы
Ваш модуль обращается к tv-api песочницы так же, как к продуктивному: относительные пути /api/… и authorizationHeader() из @tv/extension-sdk/context в каждом запросе — см. Вызов API из модуля. Структурно песочница — это продакшен.
Для сотрудников Tango Vision: консоль
Сотрудники могут создавать песочницы и из служебной консоли, для входа в которую нужна учётная запись сотрудника; приглашённые разработчики пользуются CLI (см. выше). Её страница Sandboxes (в админ-навигации) принимает API-ключ, затем — New sandbox:
| Поле | Значение |
|---|---|
| Name | Отображаемое имя; поддомен выводится из него |
| Building type | mall, office или university |
| Storeys | 1–50 |
| Area (m²) | Общая площадь |
| TTL (days) | 1–30; автоочистка после |
Строка появляется в статусе provisioning и переходит в ready, когда база засеяна — от минуты на маленьком здании до нескольких минут на реалистичных параметрах.