<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://docs.victor.onl/pt-BR/blog</id>
    <title>Platform Engineering Blog</title>
    <updated>2026-05-10T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://docs.victor.onl/pt-BR/blog"/>
    <subtitle>Platform Engineering Blog</subtitle>
    <icon>https://docs.victor.onl/pt-BR/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[Repositórios de Aplicação como Golden Paths: Dockerfile, CI e .k8s em Cada Repo]]></title>
        <id>https://docs.victor.onl/pt-BR/blog/application-repositories-golden-paths</id>
        <link href="https://docs.victor.onl/pt-BR/blog/application-repositories-golden-paths"/>
        <updated>2026-05-10T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Como repositórios de aplicação scaffoldados com Dockerfile, pipeline de CI e pasta .k8s dão autonomia aos desenvolvedores sobre a configuração de carga de trabalho mantendo o controle da plataforma.]]></summary>
        <content type="html"><![CDATA[<p>Nossa plataforma gerencia <em>onde</em> e <em>como</em> os serviços são implantados através de repositórios GitOps. Mas e a aplicação em si — o código, o build, o contêiner? Até agora, cada equipe configurava seu próprio Dockerfile, escrevia seu próprio pipeline de CI e elaborava sua própria estratégia de tagueamento de imagens. O resultado era previsível: 10 times, 10 workflows de CI diferentes, 10 abordagens diferentes de build de contêiner e zero consistência.</p>
<p>A convenção de Repositórios de Aplicação muda isso. Quando um novo serviço é scaffoldado via Backstage, ele entrega um repositório completo e opinativo com código fonte, Dockerfile, pipeline de CI e uma pasta <code>.k8s</code> — dando à equipe da aplicação autonomia sobre a configuração de sua carga de trabalho enquanto mantém a plataforma no controle do modelo de implantação.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-arquitetura-dois-repos-uma-implantação">A arquitetura: dois repos, uma implantação<a href="https://docs.victor.onl/pt-BR/blog/application-repositories-golden-paths#a-arquitetura-dois-repos-uma-implanta%C3%A7%C3%A3o" class="hash-link" aria-label="Link direto para A arquitetura: dois repos, uma implantação" title="Link direto para A arquitetura: dois repos, uma implantação" translate="no">​</a></h2>
<p>Nosso modelo GitOps usa uma separação clara entre <strong>configuração de implantação</strong> e <strong>configuração da aplicação</strong>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">{domain}-gitops/k8s/{env}/{service}/    ← Manifestos base gerenciados pela plataforma</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">{app}-repo/.k8s/values.yaml             ← Sobrescrições gerenciadas pelo desenvolvedor</span><br></div></code></pre></div></div>
<p>O repositório GitOps do domínio contém a configuração fundacional do Kubernetes — Deployments, Services, NetworkPolicies, HPA, PDB — gerada pelo template <code>create-service</code> e mantida pelas convenções de plataforma do time do domínio.</p>
<p>O repositório da aplicação contém uma pasta <code>.k8s</code> onde o time de desenvolvimento gerencia valores que mudam frequentemente com os releases da aplicação.</p>
<p>O padrão de <strong>Múltiplas Fontes (Multiple Sources)</strong> do ArgoCD mescla ambas as fontes no momento da sincronização. Os manifestos base do repo GitOps fornecem estrutura e segurança. As sobrescrições da aplicação fornecem flexibilidade e velocidade.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-os-desenvolvedores-podem-sobrescrever">O que os desenvolvedores podem sobrescrever<a href="https://docs.victor.onl/pt-BR/blog/application-repositories-golden-paths#o-que-os-desenvolvedores-podem-sobrescrever" class="hash-link" aria-label="Link direto para O que os desenvolvedores podem sobrescrever" title="Link direto para O que os desenvolvedores podem sobrescrever" translate="no">​</a></h2>
<p>O <code>.k8s/values.yaml</code> no repositório da aplicação dá aos desenvolvedores controle sobre:</p>
<ul>
<li class=""><strong>Tag da imagem</strong>: Atualizada automaticamente pelo CI em cada build bem-sucedido</li>
<li class=""><strong>Réplicas</strong>: Sobrescrever limites min/max do HPA para necessidades específicas da carga de trabalho</li>
<li class=""><strong>CPU e memória</strong>: Ajustar requests e limits conforme o perfil da aplicação evolui</li>
<li class=""><strong>Variáveis de ambiente</strong>: Configuração específica da aplicação que muda com os releases</li>
</ul>
<p>Esses são os valores que mudam com mais frequência e estão mais diretamente ligados ao código da aplicação. Mantendo-os no repo da app, desenvolvedores não precisam de um PR no repo GitOps toda vez que fazem push de um release.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-os-desenvolvedores-não-tocam">O que os desenvolvedores não tocam<a href="https://docs.victor.onl/pt-BR/blog/application-repositories-golden-paths#o-que-os-desenvolvedores-n%C3%A3o-tocam" class="hash-link" aria-label="Link direto para O que os desenvolvedores não tocam" title="Link direto para O que os desenvolvedores não tocam" translate="no">​</a></h2>
<p>Os manifestos base em <code>{domain}-gitops/k8s/</code> permanecem sob controle da convenção da plataforma:</p>
<ul>
<li class=""><strong>Definição do Namespace</strong> com todos os 9 labels obrigatórios</li>
<li class=""><strong>Contexto de segurança</strong>: <code>runAsNonRoot</code>, <code>readOnlyRootFilesystem</code>, <code>capabilities: drop: [ALL]</code></li>
<li class=""><strong>NetworkPolicy</strong>: isolamento por fronteira de projeto</li>
<li class=""><strong>PodDisruptionBudget</strong>: rede de segurança apenas para prod</li>
<li class=""><strong>ResourceQuota</strong>: limites dimensionados por ambiente</li>
</ul>
<p>Essa separação garante que as garantias de segurança e conformidade nunca sejam acidentalmente sobrescritas por um desenvolvedor que "só precisa mudar o limite de memória."</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-pipeline-de-ci-do-commit-ao-deploy">O pipeline de CI: do commit ao deploy<a href="https://docs.victor.onl/pt-BR/blog/application-repositories-golden-paths#o-pipeline-de-ci-do-commit-ao-deploy" class="hash-link" aria-label="Link direto para O pipeline de CI: do commit ao deploy" title="Link direto para O pipeline de CI: do commit ao deploy" translate="no">​</a></h2>
<p>Todo repositório de aplicação scaffoldado pelo <code>create-service</code> inclui um workflow pré-configurado do GitHub Actions. O pipeline não é algo que o time precisa escrever — ele chega pronto:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Desenvolvedor faz push do código</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ▼</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">┌─── Pipeline de CI ─────────────────────────────────┐</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│                                                     │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│  1. Test &amp; Lint      Executa testes, verificações  │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│  2. Build            Constrói contêiner do Dockerfile│</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│  3. Publish          Push da imagem para o registry │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│  4. Atualização de   Atualiza .k8s/values.yaml com │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│     Tag              nova tag, commit de volta      │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│                                                     │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└─────────────────────────────────────────────────────┘</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ▼</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ArgoCD detecta mudança no app repo (fonte secundária)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        │</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        ▼</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Implantação sincroniza com nova tag da imagem</span><br></div></code></pre></div></div>
<p>O passo chave é a <strong>Atualização de Tag</strong>. Após publicar a imagem do contêiner, o pipeline atualiza automaticamente <code>image.tag</code> em <code>.k8s/values.yaml</code> e faz commit da mudança de volta no repositório da aplicação. Esse commit é o que o ArgoCD observa.</p>
<p>Como o ArgoCD está configurado com Multiple Sources — uma apontando para o repo GitOps para manifestos base, outra apontando para o repo da app para sobrescrições — a nova tag aciona uma sincronização automática para o ambiente alvo.</p>
<p><strong>Sem atualizações manuais de tag de imagem. Sem passo separado de "deploy". Faça push do código, obtenha a implantação.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-dockerfile-seguro-por-padrão">O Dockerfile: seguro por padrão<a href="https://docs.victor.onl/pt-BR/blog/application-repositories-golden-paths#o-dockerfile-seguro-por-padr%C3%A3o" class="hash-link" aria-label="Link direto para O Dockerfile: seguro por padrão" title="Link direto para O Dockerfile: seguro por padrão" translate="no">​</a></h2>
<p>O Dockerfile scaffoldado segue os padrões de segurança da plataforma:</p>
<ul>
<li class=""><strong>Build multi-estágio</strong>: Estágios separados de build e runtime para minimizar o tamanho da imagem</li>
<li class=""><strong>Usuário não-root</strong>: <code>USER 1000</code> — combina com o contexto de segurança do pod (<code>runAsNonRoot: true</code>)</li>
<li class=""><strong>Compatível com filesystem somente leitura</strong>: Escritas da aplicação vão para <code>/tmp</code> (montado como <code>emptyDir</code>)</li>
<li class=""><strong>Otimização específica por linguagem</strong>: Node.js, .NET e Python recebem cada um um Dockerfile adaptado com imagens base e cache de dependências apropriados</li>
</ul>
<p>O desenvolvedor não precisa saber sobre contextos de segurança de pod ou filesystems somente leitura. O Dockerfile e os manifestos Kubernetes são projetados para funcionar juntos desde o primeiro dia.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-quadro-completo">O quadro completo<a href="https://docs.victor.onl/pt-BR/blog/application-repositories-golden-paths#o-quadro-completo" class="hash-link" aria-label="Link direto para O quadro completo" title="Link direto para O quadro completo" translate="no">​</a></h2>
<p>Quando o <code>create-service</code> é executado, o desenvolvedor recebe:</p>
<table><thead><tr><th>O quê</th><th>Onde</th><th>Quem mantém</th></tr></thead><tbody><tr><td>Código fonte boilerplate</td><td><code>{app}-repo/src/</code></td><td>Time da aplicação</td></tr><tr><td>Dockerfile</td><td><code>{app}-repo/Dockerfile</code></td><td>Time da aplicação</td></tr><tr><td>Pipeline de CI</td><td><code>{app}-repo/.github/workflows/ci.yaml</code></td><td>Time de plataforma (gerado), time da aplicação (estendido)</td></tr><tr><td>Sobrescrições da carga de trabalho</td><td><code>{app}-repo/.k8s/values.yaml</code></td><td>Time da aplicação</td></tr><tr><td>TechDocs</td><td><code>{app}-repo/docs/</code></td><td>Time da aplicação</td></tr><tr><td>Manifestos K8s base</td><td><code>{domain}-gitops/k8s/{env}/{service}/</code></td><td>Time do domínio</td></tr><tr><td>Roteamento ArgoCD</td><td><code>platform-gitops/argocd/applicationsets/</code></td><td>Time de plataforma</td></tr></tbody></table>
<p>Três repositórios, três fronteiras de propriedade, uma implantação que funciona sem coordenação manual.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="por-que-não-tudo-no-repo-da-app">Por que não tudo no repo da app?<a href="https://docs.victor.onl/pt-BR/blog/application-repositories-golden-paths#por-que-n%C3%A3o-tudo-no-repo-da-app" class="hash-link" aria-label="Link direto para Por que não tudo no repo da app?" title="Link direto para Por que não tudo no repo da app?" translate="no">​</a></h2>
<p>Uma pergunta comum: "Por que não colocar todos os manifestos Kubernetes no repositório da aplicação?"</p>
<p>Porque quebra o modelo de propriedade:</p>
<ol>
<li class=""><strong>Contexto de segurança e políticas de rede são preocupações da plataforma</strong>, não da aplicação. Desenvolvedores não deveriam precisar (nem poder) modificá-los.</li>
<li class=""><strong>Múltiplos serviços compartilham o mesmo ApplicationSet e estrutura de domínio.</strong> Centralizar isso no repo GitOps evita duplicação e garante consistência.</li>
<li class=""><strong>Validação de convenção roda no repo GitOps.</strong> Verificações de CI para nomenclatura, labels e padrões de segurança acontecem onde essas definições vivem.</li>
</ol>
<p>A pasta <code>.k8s</code> dá aos desenvolvedores a autonomia que precisam — tags de imagem, escalonamento, recursos — sem dar acesso às coisas que não deveriam mudar.</p>
<hr>
<p>A convenção de Repositórios de Aplicação está documentada na <a class="" href="https://docs.victor.onl/pt-BR/docs/platform-convention/application-repositories">Convenção da Plataforma — Repositórios de Aplicação</a>. O padrão de Múltiplas Fontes do ArgoCD está na <a class="" href="https://docs.victor.onl/pt-BR/docs/platform-convention/argocd">Convenção ArgoCD</a>.</p>]]></content>
        <author>
            <name>Platform Engineering</name>
        </author>
        <category label="GitOps" term="GitOps"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
        <category label="IDP" term="IDP"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Golden Paths: Como Templates Backstage Garantem Serviços Corretos por Padrão]]></title>
        <id>https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates</id>
        <link href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates"/>
        <updated>2026-05-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Mergulho profundo em como templates do Backstage Scaffolder aplicam convenções da plataforma por design, tornando serviços corretos por padrão a única opção para engenheiros de produto.]]></summary>
        <content type="html"><![CDATA[<p>Documentação é ignorada. Runbooks ficam desatualizados. Páginas de wiki acumulam instruções conflitantes de três autores diferentes. Quando o "jeito certo" de criar um serviço existe apenas em documentação, cada novo serviço é uma chance de desviar da convenção.</p>
<p>Os templates do Backstage Scaffolder mudam essa equação. Em vez de documentar o caminho correto e torcer para que os engenheiros sigam, codificamos o caminho correto em um formulário que produz saída correta todas as vezes. Este post é sobre como nossa cadeia de templates funciona, por que a ordem de dependência importa, e o que acontece quando você clica em <strong>Create</strong>.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-problema-com-padrões-baseados-em-documentação">O problema com padrões baseados em documentação<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#o-problema-com-padr%C3%B5es-baseados-em-documenta%C3%A7%C3%A3o" class="hash-link" aria-label="Link direto para O problema com padrões baseados em documentação" title="Link direto para O problema com padrões baseados em documentação" translate="no">​</a></h2>
<p>Nossa convenção de plataforma define um padrão preciso de nomenclatura, 9 labels obrigatórios, padrões de segurança e uma estrutura específica de repositório. Antes dos templates, aplicar esses padrões significava:</p>
<ol>
<li class="">Ler 3 páginas diferentes de wiki</li>
<li class="">Copiar e colar YAML de exemplos (frequentemente desatualizados)</li>
<li class="">Torcer para o revisor pegar o que você esqueceu</li>
<li class="">Esperar o time de plataforma corrigir o que o revisor não pegou</li>
</ol>
<p>O resultado: 80% dos novos serviços precisavam de pelo menos um PR de correção após a criação inicial. Conformidade com a convenção era aspiracional.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="templates-como-mecanismo-de-aplicação">Templates como mecanismo de aplicação<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#templates-como-mecanismo-de-aplica%C3%A7%C3%A3o" class="hash-link" aria-label="Link direto para Templates como mecanismo de aplicação" title="Link direto para Templates como mecanismo de aplicação" translate="no">​</a></h2>
<p>Um template do Backstage Scaffolder é uma definição YAML que combina um formulário voltado ao usuário com uma sequência de ações automatizadas. O desenvolvedor preenche o formulário. O template gera todos os arquivos, abre os PRs e registra a entidade no catálogo.</p>
<p>O template não documenta a convenção — ele <strong>implementa</strong> a convenção. Não existe como criar um serviço com labels faltando, nomenclatura errada ou contexto de segurança incorreto, porque o template gera tudo isso.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-cadeia-de-templates">A cadeia de templates<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#a-cadeia-de-templates" class="hash-link" aria-label="Link direto para A cadeia de templates" title="Link direto para A cadeia de templates" translate="no">​</a></h2>
<p>Templates têm dependências. Você não pode criar um serviço sem um system. Não pode criar um system sem um domain. A cadeia impõe esta ordem:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Camada de pessoas (execute a qualquer momento)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">──────────────────────────────────────────────────────</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> create-group → entidade Group + RBAC + papéis ArgoCD</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> create-user  → entidade User  + RBAC + acesso ArgoCD</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Camada de plataforma (execute em ordem)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">──────────────────────────────────────────────────────</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> create-domain</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      │  Entidade Domain, repositório {domain}-gitops, AppProject</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      ▼</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> create-system</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      │  Entidade System, ApplicationSet</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      ▼</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      ├─────────────────────────┬─────────────────────┐</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">      ▼                         ▼                     ▼</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> create-service          create-resource         create-secret</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> Entidade Component,     Entidade Resource,      SealedSecret</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> App Repo (CI/CD,        Claim Crossplane/env,   manifesto/env</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> TechDocs, .k8s),        namespace de infra</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> manifestos k8s/env</span><br></div></code></pre></div></div>
<p>Cada template usa <code>EntityPicker</code> para selecionar seu pai. Você escolhe o domain de um dropdown que mostra apenas domains existentes. Escolhe o system de um dropdown filtrado pelos systems daquele domain. <strong>A integridade referencial é aplicada pela própria interface.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-o-create-service-realmente-faz">O que o <code>create-service</code> realmente faz<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#o-que-o-create-service-realmente-faz" class="hash-link" aria-label="Link direto para o-que-o-create-service-realmente-faz" title="Link direto para o-que-o-create-service-realmente-faz" translate="no">​</a></h2>
<p>Quando um engenheiro de produto executa <code>create-service</code>, ele preenche:</p>
<ul>
<li class=""><strong>System</strong>: selecionado do catálogo (domain, repo e AppProject resolvem automaticamente)</li>
<li class=""><strong>Nome do serviço</strong>: ex., <code>api</code>, <code>worker</code>, <code>frontend</code></li>
<li class=""><strong>Tipo do serviço</strong>: api / worker / frontend / grpc / cronjob</li>
<li class=""><strong>Imagem do contêiner</strong>: caminho do registry</li>
<li class=""><strong>Perfil de recursos</strong>: qual tier de CPU/memória</li>
<li class=""><strong>Ambientes alvo</strong>: em quais envs fazer deploy</li>
</ul>
<p>Então o template executa:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="passo-1--gerar-o-repositório-da-aplicação">Passo 1 — Gerar o Repositório da Aplicação<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#passo-1--gerar-o-reposit%C3%B3rio-da-aplica%C3%A7%C3%A3o" class="hash-link" aria-label="Link direto para Passo 1 — Gerar o Repositório da Aplicação" title="Link direto para Passo 1 — Gerar o Repositório da Aplicação" translate="no">​</a></h3>
<p>Um novo repositório é criado com:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">{app}-repo/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── src/                    ← código fonte boilerplate</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── Dockerfile              ← otimizado, non-root, específico da linguagem</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── .github/workflows/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── ci.yaml             ← lint, test, build, publish, atualização de tag</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── .k8s/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── values.yaml         ← sobrescrições (tag da imagem, réplicas, recursos)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">├── docs/</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│   └── index.md            ← base do TechDocs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── catalog-info.yaml       ← entidade Component do Backstage</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="passo-2--gerar-manifestos-kubernetes-no-repositório-do-domínio">Passo 2 — Gerar manifestos Kubernetes no repositório do domínio<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#passo-2--gerar-manifestos-kubernetes-no-reposit%C3%B3rio-do-dom%C3%ADnio" class="hash-link" aria-label="Link direto para Passo 2 — Gerar manifestos Kubernetes no repositório do domínio" title="Link direto para Passo 2 — Gerar manifestos Kubernetes no repositório do domínio" translate="no">​</a></h3>
<p>Em <code>{domain}-gitops/k8s/{env}/{service}/</code>, o template cria:</p>
<ul>
<li class=""><strong>Namespace</strong> com todos os 9 labels obrigatórios</li>
<li class=""><strong>Deployment</strong> com contexto de segurança, limites de recursos, probes de readiness/liveness</li>
<li class=""><strong>Service</strong> expondo a porta correta</li>
<li class=""><strong>HPA</strong> com escalonamento apropriado por env (dev: 1→2, staging: 2→5, prod: 3→10)</li>
<li class=""><strong>PDB</strong> (apenas prod, <code>minAvailable: 1</code>)</li>
<li class=""><strong>NetworkPolicy</strong> isolando por fronteira de projeto</li>
</ul>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="passo-3--atualizar-o-applicationset">Passo 3 — Atualizar o ApplicationSet<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#passo-3--atualizar-o-applicationset" class="hash-link" aria-label="Link direto para Passo 3 — Atualizar o ApplicationSet" title="Link direto para Passo 3 — Atualizar o ApplicationSet" translate="no">​</a></h3>
<p>No <code>platform-gitops</code>, o template adiciona o novo serviço como elemento no ApplicationSet existente:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">elements</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">service</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> api      </span><span class="token comment" style="color:#999988;font-style:italic"># ← existente</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain"> </span><span class="token key atrule" style="color:#00a4db">service</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> worker   </span><span class="token comment" style="color:#999988;font-style:italic"># ← adicionado pelo template</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="passo-4--registrar-e-abrir-prs">Passo 4 — Registrar e abrir PRs<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#passo-4--registrar-e-abrir-prs" class="hash-link" aria-label="Link direto para Passo 4 — Registrar e abrir PRs" title="Link direto para Passo 4 — Registrar e abrir PRs" translate="no">​</a></h3>
<p>O template abre dois PRs:</p>
<ol>
<li class=""><strong>PR do repositório do domínio</strong>: manifestos k8s + entidade Component</li>
<li class=""><strong>PR do repositório da plataforma</strong>: elemento do ApplicationSet</li>
</ol>
<p>Ele também registra o novo <code>catalog-info.yaml</code> no catálogo do Backstage.</p>
<p><strong>A ordem de merge importa</strong>: PR da plataforma primeiro (o ApplicationSet deve existir antes que o ArgoCD possa sincronizar), depois o PR do domínio. Em minutos após ambos serem mergeados, o serviço está rodando no cluster dev.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-workflow-de-dois-prs">O workflow de dois PRs<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#o-workflow-de-dois-prs" class="hash-link" aria-label="Link direto para O workflow de dois PRs" title="Link direto para O workflow de dois PRs" translate="no">​</a></h2>
<p>Todo template segue o mesmo padrão: um PR no repositório do domínio/catálogo, um PR no <code>platform-gitops</code>. Essa separação existe porque:</p>
<ul>
<li class=""><strong>Times de domínio são donos de seus manifestos</strong> — eles revisam e mergeiam o que implantam</li>
<li class=""><strong>Time de plataforma é dono do roteamento</strong> — eles revisam mudanças na configuração do ArgoCD e RBAC</li>
<li class=""><strong>CODEOWNERS impõe isso</strong> — mudanças no repositório errado são bloqueadas automaticamente</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="resultados">Resultados<a href="https://docs.victor.onl/pt-BR/blog/golden-paths-backstage-templates#resultados" class="hash-link" aria-label="Link direto para Resultados" title="Link direto para Resultados" translate="no">​</a></h2>
<p>Desde a adoção dos templates:</p>
<ul>
<li class=""><strong>100% de conformidade de labels</strong> em todos os novos serviços (era &lt; 20%)</li>
<li class=""><strong>&lt; 3 minutos</strong> do clique em Create até os PRs abertos (eram horas de YAML manual)</li>
<li class=""><strong>Zero violações de convenção</strong> em serviços gerados por template</li>
<li class=""><strong>Serviço rodando em dev em &lt; 30 minutos</strong> (era 2–5 dias)</li>
</ul>
<p>Os templates não apenas tornaram a criação de serviços mais rápida — tornaram violações de convenção estruturalmente impossíveis para novos serviços. O "jeito correto" é o único jeito.</p>
<hr>
<p>A cadeia completa de templates e resumo de saída estão documentados na <a class="" href="https://docs.victor.onl/pt-BR/docs/platform-convention/templates">Convenção da Plataforma — Templates</a>. O modelo de entidades do Backstage e design do catálogo estão na <a class="" href="https://docs.victor.onl/pt-BR/docs/platform-convention/backstage">Convenção Backstage</a>.</p>]]></content>
        <author>
            <name>Platform Engineering</name>
        </author>
        <category label="Backstage" term="Backstage"/>
        <category label="IDP" term="IDP"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[O ROI de Nomear as Coisas: Como Uma Chave de 3 Segmentos Eliminou a Confusão Entre Times]]></title>
        <id>https://docs.victor.onl/pt-BR/blog/roi-of-naming-things</id>
        <link href="https://docs.victor.onl/pt-BR/blog/roi-of-naming-things"/>
        <updated>2026-05-08T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Como uma única convenção de nomenclatura de 3 segmentos no Kubernetes, ArgoCD, Backstage e Crossplane eliminou a confusão entre times e economizou horas de mapeamento manual toda semana.]]></summary>
        <content type="html"><![CDATA[<p>Nomear coisas é famosamente o problema mais difícil da ciência da computação. É também, silenciosamente, um dos mais caros. Quando quatro equipes diferentes nomeiam seus namespaces de quatro formas diferentes, o custo aparece em incidentes que demoram mais para diagnosticar, em onboardings que viram sessões de conhecimento tribal, e em um time de plataforma que gasta suas semanas traduzindo entre sistemas ao invés de construir.</p>
<p>Este post é sobre como uma única convenção de nomenclatura — três segmentos, uma chave — unificou Kubernetes, ArgoCD, Backstage e Crossplane. E por que o retorno sobre investimento foi medido em dias economizados por semana.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-custo-da-deriva-de-nomenclatura">O custo da deriva de nomenclatura<a href="https://docs.victor.onl/pt-BR/blog/roi-of-naming-things#o-custo-da-deriva-de-nomenclatura" class="hash-link" aria-label="Link direto para O custo da deriva de nomenclatura" title="Link direto para O custo da deriva de nomenclatura" translate="no">​</a></h2>
<p>Antes da convenção, cada equipe tinha seu próprio estilo:</p>
<ul>
<li class="">Time A nomeava namespaces <code>payments-api-prod</code></li>
<li class="">Time B usava <code>prod-orders-backend</code></li>
<li class="">Time C optava por <code>frontend_staging</code></li>
</ul>
<p>Nenhum desses está errado. Todos são incompatíveis. Quando um incidente atingia <code>payments-api-prod</code>, a primeira pergunta era sempre: <em>"Qual aplicação do ArgoCD gerencia isso?"</em> Ninguém sabia sem investigar. A resposta vivia na cabeça de alguém, ou em uma planilha atualizada pela última vez três meses atrás.</p>
<p>O custo real não era a nomenclatura em si — era o <strong>mapeamento manual</strong> necessário toda vez que um humano ou ferramenta precisava cruzar referências entre sistemas:</p>
<table><thead><tr><th>Pergunta</th><th>Sem convenção</th><th>Com convenção</th></tr></thead><tbody><tr><td>Qual app do ArgoCD gerencia este namespace?</td><td>Pergunte a alguém, consulte planilha</td><td>Leia o label <code>argocd/app</code></td></tr><tr><td>Qual time é responsável?</td><td>Verifique JIRA, Slack ou git blame</td><td>Leia o label <code>team</code></td></tr><tr><td>Quais pods pertencem a este serviço em todos os envs?</td><td>kubectl manual em cada cluster</td><td><code>kubectl get ns -l backstage.io/component=gateway-api</code></td></tr><tr><td>Este serviço está saudável em prod?</td><td>Abra Grafana, ArgoCD, kubectl separadamente</td><td>Abra uma página de Component no Backstage</td></tr></tbody></table>
<p>Cada uma dessas perguntas custava 5–15 minutos por ocorrência. Multiplique pelo número de engenheiros fazendo-as diariamente, e a deriva de nomenclatura consumia <strong>horas por semana</strong> em toda a organização.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-chave-semântica">A chave semântica<a href="https://docs.victor.onl/pt-BR/blog/roi-of-naming-things#a-chave-sem%C3%A2ntica" class="hash-link" aria-label="Link direto para A chave semântica" title="Link direto para A chave semântica" translate="no">​</a></h2>
<p>A convenção é simples. Todo recurso na plataforma é endereçado por três segmentos:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">{project}-{env}-{service}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">payments-prod-api</span><br></div></code></pre></div></div>
<table><thead><tr><th>Segmento</th><th>O que significa</th><th>Onde aparece</th></tr></thead><tbody><tr><td><code>project</code></td><td>Fronteira de propriedade (domínio)</td><td>Domain no Backstage, AppProject no ArgoCD, prefixo do namespace</td></tr><tr><td><code>env</code></td><td>Alvo de implantação</td><td>Label do cluster, segmento do meio do namespace</td></tr><tr><td><code>service</code></td><td>Carga de trabalho individual</td><td>Sufixo do namespace, sufixo do Component no Backstage</td></tr></tbody></table>
<p>O insight principal é que isso não é apenas um padrão de nomenclatura — é um <strong>contrato</strong>. Quando a nomenclatura é consistente, as ferramentas conversam entre si sem um humano no meio.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="como-uma-chave-conecta-quatro-sistemas">Como uma chave conecta quatro sistemas<a href="https://docs.victor.onl/pt-BR/blog/roi-of-naming-things#como-uma-chave-conecta-quatro-sistemas" class="hash-link" aria-label="Link direto para Como uma chave conecta quatro sistemas" title="Link direto para Como uma chave conecta quatro sistemas" translate="no">​</a></h2>
<p>Aqui está o mapeamento completo para um único serviço:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Backstage Domain:      payments          ← project</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ArgoCD AppProject:     payments          ← project</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Backstage System:      gateway           ← agrupamento lógico</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ArgoCD ApplicationSet: gateway           ← agrupamento lógico</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Backstage Component:   gateway-api       ← system + service</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">ArgoCD Application:    gateway-api-prod  ← system + service + env</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Kubernetes Namespace:  payments-prod-api ← project + env + service</span><br></div></code></pre></div></div>
<p>Quando um desenvolvedor abre a página do Component <code>gateway-api</code> no Backstage, o plugin de Kubernetes encontra pods em <strong>todos os clusters</strong> usando um único label selector: <code>project=payments,service=api</code>. Sem configuração por ambiente. Sem registro manual do namespace de cada cluster. O label faz o trabalho.</p>
<p>O plugin do ArgoCD mostra o status de sincronização por ambiente usando a mesma abordagem de labels. O grafo de dependências mostra quais bancos de dados e filas este serviço utiliza.</p>
<p><strong>Um nome, uma consulta, uma página, uma fonte de verdade.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="os-9-labels-que-fazem-funcionar">Os 9 labels que fazem funcionar<a href="https://docs.victor.onl/pt-BR/blog/roi-of-naming-things#os-9-labels-que-fazem-funcionar" class="hash-link" aria-label="Link direto para Os 9 labels que fazem funcionar" title="Link direto para Os 9 labels que fazem funcionar" translate="no">​</a></h2>
<p>Todo namespace na plataforma carrega 9 labels obrigatórios:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">labels</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">project</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> payments               </span><span class="token comment" style="color:#999988;font-style:italic"># domínio</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">env</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> prod                       </span><span class="token comment" style="color:#999988;font-style:italic"># ambiente</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">service</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> api                    </span><span class="token comment" style="color:#999988;font-style:italic"># carga de trabalho</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">team</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> team</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">payments             </span><span class="token comment" style="color:#999988;font-style:italic"># time responsável</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">backstage.io/domain</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> payments   </span><span class="token comment" style="color:#999988;font-style:italic"># → Backstage Domain</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">backstage.io/system</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> gateway    </span><span class="token comment" style="color:#999988;font-style:italic"># → Backstage System</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">backstage.io/component</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> gateway</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">api  </span><span class="token comment" style="color:#999988;font-style:italic"># → Backstage Component</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">argocd/app</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> gateway</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">api</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">prod    </span><span class="token comment" style="color:#999988;font-style:italic"># → ArgoCD Application</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">argocd/app-set</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> gateway         </span><span class="token comment" style="color:#999988;font-style:italic"># → ArgoCD ApplicationSet</span><br></div></code></pre></div></div>
<p>Qualquer label faltando reprova o PR no CI. Não existe caminho de exceção. Isso não é aplicado por documentação — é aplicado por código.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-impacto-no-negócio">O impacto no negócio<a href="https://docs.victor.onl/pt-BR/blog/roi-of-naming-things#o-impacto-no-neg%C3%B3cio" class="hash-link" aria-label="Link direto para O impacto no negócio" title="Link direto para O impacto no negócio" translate="no">​</a></h2>
<p>Após implantar a convenção na primeira equipe de domínio:</p>
<table><thead><tr><th>Métrica</th><th>Antes</th><th>Depois</th></tr></thead><tbody><tr><td>Tempo para responder "quem é dono deste namespace?"</td><td>5–15 min (pergunte por aí)</td><td>0 seg (leia o label)</td></tr><tr><td>Referência cruzada entre ferramentas em incidentes</td><td>Manual, propenso a erros</td><td>Automático via labels</td></tr><tr><td>Bootstrapping de novo serviço</td><td>8–15 passos manuais</td><td>1 template, 2 PRs</td></tr><tr><td>Namespaces com todos os labels obrigatórios</td><td>&lt; 20%</td><td>100% (novos serviços)</td></tr></tbody></table>
<p>A convenção é a coisa mais barata que construímos e o investimento de maior ROI em toda a plataforma. Toda integração de ferramenta, toda automação, todo dashboard depende dela. Sem nomenclatura consistente, a plataforma é apenas uma coleção de ferramentas. Com ela, a plataforma é um produto.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-lição">A lição<a href="https://docs.victor.onl/pt-BR/blog/roi-of-naming-things#a-li%C3%A7%C3%A3o" class="hash-link" aria-label="Link direto para A lição" title="Link direto para A lição" translate="no">​</a></h2>
<p><strong>Invista em nomenclatura antes de investir em ferramental.</strong> Um setup perfeito do ArgoCD com nomes de namespaces inconsistentes é pior do que um setup básico com nomes consistentes. A convenção de nomenclatura não é um documento para escrever depois que a arquitetura está pronta — é a fundação sobre a qual a arquitetura é construída.</p>
<p>Cada hora que investimos acertando a chave de três segmentos economizou dez horas de debugging de integrações de ferramentas depois.</p>
<hr>
<p>A convenção completa de nomenclatura e o mapeamento entre sistemas estão documentados na <a class="" href="https://docs.victor.onl/pt-BR/docs/platform-convention/naming-convention">Convenção da Plataforma</a>. Os objetivos de negócio e métricas de sucesso estão no <a class="" href="https://docs.victor.onl/pt-BR/docs/platform-prd/executive-summary">PRD da Plataforma</a>.</p>]]></content>
        <author>
            <name>Platform Engineering</name>
        </author>
        <category label="Platform Engineering" term="Platform Engineering"/>
        <category label="IDP" term="IDP"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Construindo uma Plataforma Interna para Desenvolvedores: Do Inferno de Tickets ao Self-Service em 30 Minutos]]></title>
        <id>https://docs.victor.onl/pt-BR/blog/building-an-idp</id>
        <link href="https://docs.victor.onl/pt-BR/blog/building-an-idp"/>
        <updated>2026-05-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Como construímos uma Internal Developer Platform com Backstage, ArgoCD, Kubernetes e Crossplane para substituir provisionamento via tickets por self-service em menos de 30 minutos.]]></summary>
        <content type="html"><![CDATA[<p>Todo time de plataforma chega ao mesmo ponto de inflexão. A fila de tickets cresce mais rápido do que o time. Engenheiros esperam dias por um namespace, um banco de dados ou uma aplicação ArgoCD — coisas que deveriam levar minutos. A equipe de plataforma se torna o gargalo de cada time que tenta entregar.</p>
<p>Chegamos nesse limite. Este post é sobre como saímos dele.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-problema">O problema<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#o-problema" class="hash-link" aria-label="Link direto para O problema" title="Link direto para O problema" translate="no">​</a></h2>
<p>Antes do IDP, onboardar um novo serviço tinha essa cara:</p>
<ol>
<li class="">Abrir um ticket no JIRA para criação de namespace</li>
<li class="">Esperar de 2 a 5 dias para a equipe de plataforma revisar</li>
<li class="">Receber o namespace — com as labels erradas ou sem limites de recursos</li>
<li class="">Abrir outro ticket para a aplicação ArgoCD</li>
<li class="">Abrir outro ticket para o banco de dados</li>
</ol>
<p>De oito a quinze etapas manuais em múltiplas ferramentas. Cada etapa exigia uma pessoa da equipe de plataforma. Cada erro exigia mais uma rodada de ida e volta.</p>
<p>A causa raiz não era falta de automação. Tínhamos Terraform, tínhamos Helm, tínhamos ArgoCD. O problema era que <strong>nada disso era self-service</strong>. A automação só rodava quando a equipe de plataforma a executava.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-construímos">O que construímos<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#o-que-constru%C3%ADmos" class="hash-link" aria-label="Link direto para O que construímos" title="Link direto para O que construímos" translate="no">​</a></h2>
<p>O IDP é quatro ferramentas trabalhando juntas:</p>
<table><thead><tr><th>Pilar</th><th>Ferramenta</th><th>Função</th></tr></thead><tbody><tr><td>Portal do desenvolvedor</td><td>Backstage</td><td>Templates, catálogo, observabilidade</td></tr><tr><td>Entrega GitOps</td><td>ArgoCD</td><td>Entrega contínua do Git para o Kubernetes</td></tr><tr><td>Runtime de containers</td><td>Kubernetes</td><td>Agendamento e isolamento de cargas de trabalho</td></tr><tr><td>IaC em nuvem</td><td>Crossplane</td><td>Recursos de nuvem como objetos Kubernetes</td></tr></tbody></table>
<p>O insight fundamental foi que <strong>as convenções são o produto</strong>. Uma convenção de nomenclatura não é documentação — é o contrato que permite que cada ferramenta fale com todas as outras sem um humano no meio.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-chave-semântica">A chave semântica<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#a-chave-sem%C3%A2ntica" class="hash-link" aria-label="Link direto para A chave semântica" title="Link direto para A chave semântica" translate="no">​</a></h2>
<p>Todo recurso da plataforma — namespace, aplicação ArgoCD, entidade Backstage, claim Crossplane — é endereçado pela mesma chave de três segmentos:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">{project}-{env}-{service}</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">payments-prod-api</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│         │     └── Namespace Kubernetes: payments-prod-api</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│         │         Component Backstage: gateway-api</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">│         └── Application ArgoCD: gateway-api-prod</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">└── AppProject ArgoCD: payments</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    Domain Backstage: payments</span><br></div></code></pre></div></div>
<p>Quando a nomenclatura é consistente, o plugin Kubernetes do Backstage consegue encontrar todos os pods de um serviço em cada cluster com um único label selector. O plugin ArgoCD consegue exibir o status de sync por ambiente. Sem mapeamento manual. Sem planilhas.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="templates-backstage-como-caminhos-dourados">Templates Backstage como caminhos dourados<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#templates-backstage-como-caminhos-dourados" class="hash-link" aria-label="Link direto para Templates Backstage como caminhos dourados" title="Link direto para Templates Backstage como caminhos dourados" translate="no">​</a></h2>
<p>A camada de self-service é um conjunto de templates do Backstage Scaffolder — um por operação da plataforma:</p>
<ul>
<li class=""><strong><code>create-domain</code></strong> — cria o limite de propriedade, o repositório GitOps e o AppProject ArgoCD</li>
<li class=""><strong><code>create-system</code></strong> — cria um agrupamento de produto, seu ApplicationSet e base para TechDocs</li>
<li class=""><strong><code>create-service</code></strong> — estrutura um Repositório de Aplicação (com Dockerfile, workflow de CI e base para TechDocs), gera manifestos Kubernetes por ambiente, registra a entrada no catálogo e abre os PRs</li>
<li class=""><strong><code>create-resource</code></strong> — cria Claims Crossplane para infraestrutura de nuvem (bancos de dados, filas, buckets)</li>
<li class=""><strong><code>create-secret</code></strong> — fornece criptografia segura de segredos via self-service usando Sealed Secrets</li>
<li class=""><strong><code>create-group</code></strong> / <strong><code>create-user</code></strong> — onboarda times e engenheiros com RBAC correto desde o primeiro dia</li>
</ul>
<p>Um engenheiro de produto executa <code>create-service</code>, seleciona seu sistema, nomeia o serviço, escolhe um perfil de recursos e clica em <strong>Create</strong>. Dois PRs são abertos automaticamente. Quando ambos são mesclados, o ArgoCD detecta o novo elemento do ApplicationSet e sincroniza o serviço com o cluster de dev. <strong>O serviço está rodando em menos de 30 minutos sem nenhuma intervenção da equipe de plataforma.</strong></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="validação-de-convenção-na-ci">Validação de convenção na CI<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#valida%C3%A7%C3%A3o-de-conven%C3%A7%C3%A3o-na-ci" class="hash-link" aria-label="Link direto para Validação de convenção na CI" title="Link direto para Validação de convenção na CI" translate="no">​</a></h2>
<p>Os templates garantem a saída correta no momento da criação. A validação da CI mantém os repositórios corretos ao longo do tempo.</p>
<p>Todo repositório GitOps de domínio inclui um workflow do GitHub Actions (<code>validate-conventions.yaml</code>) gerado pelo <code>create-domain</code>. Em cada PR ele roda o <code>validate-namespaces.sh</code> e verifica:</p>
<ul>
<li class="">Nomenclatura de namespace segue <code>{project}-{env}-{service}</code></li>
<li class="">Todas as 9 labels obrigatórias estão presentes</li>
<li class="">Todo container tem requests e limits de recursos</li>
<li class="">Manifestos Kubernetes passam na validação de schema (kubeconform)</li>
<li class="">Dry-run diff do ArgoCD contra o cluster de dev passa</li>
</ul>
<p>Violações de convenção bloqueam o merge do PR. Não existe caminho de exceção.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="infraestrutura-de-nuvem-como-código--sem-expertise-em-terraform">Infraestrutura de nuvem como código — sem expertise em Terraform<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#infraestrutura-de-nuvem-como-c%C3%B3digo--sem-expertise-em-terraform" class="hash-link" aria-label="Link direto para Infraestrutura de nuvem como código — sem expertise em Terraform" title="Link direto para Infraestrutura de nuvem como código — sem expertise em Terraform" translate="no">​</a></h2>
<p>Recursos de nuvem (bancos de dados, filas, armazenamento) são declarados como Claims do Crossplane commitados no Git. O ArgoCD os sincroniza com o cluster. O Crossplane provisiona o recurso real no GCP, AWS, Azure ou IBM.</p>
<p>Um desenvolvedor solicitando uma instância Cloud SQL não escreve Terraform. Ele executa <code>create-resource</code>, seleciona GCP → Cloud SQL, preenche um formulário e mescla o PR. O Claim cai em <code>crossplane/claims/prod/cloudsql-main.yaml</code>. O Crossplane reconcilia continuamente — o drift é corrigido automaticamente. <code>deletionPolicy: Orphan</code> nos Claims de produção significa que um <code>kubectl delete</code> acidental não pode destruir um banco de dados.</p>
<p>A página de Resource do Backstage para esse banco de dados exibe <code>READY: True</code> e <code>SYNCED: True</code> assim que o provisionamento é concluído. Sem cavar no console da nuvem.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="rbac-sem-o-fardo-de-manutenção">RBAC sem o fardo de manutenção<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#rbac-sem-o-fardo-de-manuten%C3%A7%C3%A3o" class="hash-link" aria-label="Link direto para RBAC sem o fardo de manutenção" title="Link direto para RBAC sem o fardo de manutenção" translate="no">​</a></h2>
<p>O acesso é concedido via grupos do provedor de identidade, nunca usuários individuais. Remover alguém do time GitHub ou do grupo Okta revoga imediatamente todo acesso ao Kubernetes — sem limpeza manual de RoleBinding.</p>
<p>O papel <code>developer</code> não tem RoleBinding criado para namespaces de produção. Não por convenção. Não por documentação. Pelo fato de que o binding simplesmente não existe. O acesso a produção exige elevação explícita de papel.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="gerenciamento-seguro-de-segredos">Gerenciamento seguro de segredos<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#gerenciamento-seguro-de-segredos" class="hash-link" aria-label="Link direto para Gerenciamento seguro de segredos" title="Link direto para Gerenciamento seguro de segredos" translate="no">​</a></h2>
<p>O acesso aos ambientes de produção é estritamente controlado, e a plataforma impõe uma regra rigorosa de "nenhum segredo em texto claro".
Em vez de abrir tickets para gerenciar segredos, os desenvolvedores usam o template <strong><code>create-secret</code></strong> do Backstage. Eles criptografam seus segredos localmente usando <code>kubeseal</code> e preenchem o template. A plataforma abre automaticamente um PR com o manifesto <code>SealedSecret</code> diretamente no repositório GitOps do seu domínio. O serviço de plataforma <code>sealed-secrets</code> roda no cluster e lida com a descriptografia, garantindo que o gerenciamento seguro de segredos permaneça totalmente self-service.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="resultados-até-agora">Resultados até agora<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#resultados-at%C3%A9-agora" class="hash-link" aria-label="Link direto para Resultados até agora" title="Link direto para Resultados até agora" translate="no">​</a></h2>
<p>Estamos na Fase 1 do rollout. O primeiro time de domínio é totalmente autossuficiente:</p>
<ul>
<li class="">Criação de serviço: <strong>&lt; 30 minutos</strong> (eram 2–5 dias)</li>
<li class="">Tickets para a equipe de plataforma: <strong>em queda</strong></li>
<li class="">Namespaces com todas as labels obrigatórias: <strong>100%</strong> (para novos serviços)</li>
<li class="">Tempo de onboarding do engenheiro: <strong>&lt; 2 horas</strong> (eram 1–3 dias)</li>
</ul>
<p>A Fase 2 estenderá o self-service para todos os times de produto e trará observabilidade full-stack do Backstage para cada serviço. A Fase 3 migrará serviços e recursos de nuvem existentes para o catálogo.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="o-que-aprendemos">O que aprendemos<a href="https://docs.victor.onl/pt-BR/blog/building-an-idp#o-que-aprendemos" class="hash-link" aria-label="Link direto para O que aprendemos" title="Link direto para O que aprendemos" translate="no">​</a></h2>
<p><strong>Convenções primeiro.</strong> Nenhuma integração de ferramenta funciona sem nomenclatura consistente. Investimos tempo na convenção antes de construir templates, e cada hora ali economizou dez horas de depuração de integrações de ferramentas.</p>
<p><strong>Templates como mecanismo de aplicação.</strong> Documentação é ignorada. Templates tornam o caminho correto o único caminho. Se você pode executar <code>create-service</code> e obter um serviço funcionando, você não tem razão para fazer manualmente.</p>
<p><strong>GitOps escala.</strong> Geradores de matriz ApplicationSet significam que adicionar um novo serviço a um novo cluster é uma linha em um arquivo YAML. O ArgoCD cuida do resto. Não criamos Applications manualmente.</p>
<p><strong>Crossplane para IaC de nuvem pertence ao Kubernetes.</strong> Manter recursos de nuvem no mesmo loop de reconciliação que as cargas de trabalho de aplicação significa um lugar para olhar drift, um lugar para olhar status, um modelo RBAC para acesso.</p>
<hr>
<p>Os requisitos completos, arquitetura e roadmap estão documentados no <a class="" href="https://docs.victor.onl/pt-BR/docs/platform-prd/executive-summary">PRD da Plataforma</a>. A convenção de nomenclatura e os padrões operacionais estão na <a class="" href="https://docs.victor.onl/pt-BR/docs/platform-convention/intro">Convenção da Plataforma</a>.</p>]]></content>
        <author>
            <name>Platform Engineering</name>
        </author>
        <category label="IDP" term="IDP"/>
        <category label="Platform Engineering" term="Platform Engineering"/>
        <category label="Backstage" term="Backstage"/>
        <category label="GitOps" term="GitOps"/>
        <category label="Kubernetes" term="Kubernetes"/>
    </entry>
</feed>