tenants/<slug>.json: tema, assets, cursos, aulas).
Cada etapa é pulável (--skip-*) para retomar após falha parcial sem repetir trabalho.
Cria o tenant do zero nos dois mundos, reaproveitando o Artisan do vtp-webservices — nada é reimplementado em JS.
php artisan tenant:provision-local → banco vtp_{slug}, migrations, seed e domínio api-{slug}.vitrinepro.localmigrate + db:seed contra ele (env override)Monta o payload a partir do bloco theme do JSON e publica no tenant local.
colors, radius, flags + componentsbase_preset opcional (ex. clean-light) herda o semantic do catálogo — foi assim que a morgana virou o 1º tenant de tema clarobase_preset_version quando há preset (catálogo todo na v1)Gera capa por capa os slots do bloco assets (capas de curso, hero, avisos, logo…), sobe via POST /file/{type} e grava as keys no manifest {slug}.assets-manifest.json.
raw_prompt (logo) e no_stock nunca vêm de banco de imagem — nem do pool de inspiraçãoinspiration/; matching numa chamada só de visão (gemini-2.5-flash) + crop por saliência (sharp); falha no matching não derruba o runSe o JSON aponta theme.logo_asset (convenção: slot brand_emblem), o tema é republicado com a logo_key recém-gerada no manifest.
docker exec -e DB_DATABASE=vtp_{slug} … php artisan tenant:seed-content {slug}
video_host=youtube) — padrão Cozy Videos, sem passar pelo video-processordeploy-tenant-stack.sh {slug} — backend e frontend do tenant sobem num comando.
{slug}.pwa-icons/api-{slug}.aws ainda não resolve, builda com APP_URL = URL crua do API Gateway (evita links NXDOMAIN); volta ao host bonito no próximo deployPor último de propósito: o CNAME da API exige o custom domain na API Gateway, e o da PWA exige o CloudFront do deploy. Não existe API de zona no registro.br — o medusa invoca o vtp-dns-configurator (Puppeteer humanizado no painel web, idempotente, aborta em conflito).
api-{slug}.aws → alvo descoberto via aws apigatewayv2 get-domain-name (regionalDomainName)app-{slug}.aws → alvo descoberto pelo alias na distribuição CloudFront; pulado sem falhar se a PWA não foi deployada--tenant-url).loginTesta as credenciais admin (POST /api/v1/admin/login, guard custom, sem 2FA) e cacheia o token bearer em ~/.config/vtp-tenant-filler, com refresh automático.
auditDiagnóstico: mostra o que falta pro tenant ficar apresentável — cursos sem capa (heurística placeholder/robot), categorias vazias, hub ausente.
populateCria categoria + curso + módulo + aulas a partir de um --topic: busca vídeos reais no YouTube (embeddable + público), gera a capa via Imagen e opcionalmente associa um hub.
fill-imagesSó gera capas pros cursos que ainda estão com o placeholder ("robô"), sem mexer no resto. Faz round-trip completo no PUT pra não esbarrar nas validações.
attach-videosVídeo local em videos/{slug-da-aula}.mp4 sobe pro PandaVideo via TUS e vence até YouTube já aplicado — mas nunca re-sobe por cima de Panda (idempotente, sem custo duplicado).
dns / 🏗️ provisionAs etapas 6 e 1 do pipeline, avulsas: CNAME individual (--app pra PWA) e provisionamento local+Neon com runbook do restante.
src/*.js), injetável e mockável nos testes (vitest, 117+ testes).vtp-ios/apps/<Nome>/ — passo manual do Bruno).
O provision nunca cria recursos pagos sozinho: deploy e DNS são sempre opt-in explícito.