The AI-Native IDP -- Parte 1
Por qué tu IDP no te ayuda
El Problema
Tu empresa apostó por platform engineering. Alguien montó Backstage. Hay un service catalog. Hay templates. Incluso hay una sección de TechDocs con architecture decision records.
Nadie lo usa.
El catálogo lleva seis meses sin actualizar. La mitad de los servicios no tienen owner asignado. Los templates generan proyectos con dependencias que no se han tocado desde que el equipo que los escribió se fue a otro proyecto. Los TechDocs son un cementerio de buenas intenciones — correctos cuando se escribieron, obsoletos ahora.
Esto no es un problema de Backstage. Es un problema de personas. Las developer platforms mueren porque necesitan mantenimiento constante, y nadie tiene tiempo para mantenimiento constante. El catálogo necesita a alguien que lo actualice cuando los servicios cambian. Los templates necesitan a alguien que mantenga las dependencias al día. La documentación necesita a alguien que la reescriba cuando la arquitectura evoluciona.
He visto este patrón en cada empresa en la que he trabajado. La plataforma se lanza con energía. Seis meses después es un enlace que nadie pulsa. Doce meses después el equipo debate si cerrarla.
La solución habitual es asignar a alguien para mantenerla. Un “platform team.” Pero los platform teams son caros, y su trabajo es invisible — mantener un catálogo preciso no aparece en los sprint demos. El equipo acaba absorbido por feature work. La plataforma se degrada. El ciclo se repite.

Hay otro enfoque. ¿Y si la plataforma pudiera mantenerse sola?
La Solución
Un AI-native IDP es una developer platform donde la IA no es una funcionalidad que añades después — es el motor que mantiene todo vivo.
El catálogo se actualiza solo porque la IA lee tus repositorios, detecta cambios y actualiza los metadatos de los servicios automáticamente. Los templates se mantienen al día porque la IA monitoriza las versiones de dependencias y propone actualizaciones. La documentación responde a tus preguntas porque está respaldada por RAG sobre tu codebase real, no por ficheros markdown estáticos.
El cambio clave: en vez de una plataforma que los desarrolladores tienen que mantener, construyes una plataforma que se mantiene sola y ayuda a los desarrolladores a trabajar más rápido.
Esta serie construye esa plataforma sobre Backstage — el framework open-source para IDPs más adoptado. Lo extenderemos con plugins con IA, uno por artículo, hasta tener una developer platform AI-native completa.
Qué hay en esta serie
- Por qué tu IDP no te ayuda — Lo estás leyendo. El problema con los IDPs tradicionales y qué cambia con la IA.
- Enseñando a tu catálogo a pensar — IA que auto-documenta servicios desde su código: descripciones, dependencias, owners.
- Software Templates con IA — Un scaffolder donde los desarrolladores describen lo que necesitan en lenguaje natural y obtienen un proyecto con prompts ATLAS+GOTCHA incluidos.
- El plugin de AI Code Review — Reviews de PRs con contexto arquitectónico del catálogo. La IA sabe qué servicio es, quién lo mantiene y qué patrones debe seguir.
- TechDocs que responden — RAG sobre tu documentación interna y ADRs. Una interfaz de chat dentro de Backstage que responde preguntas sobre tu arquitectura.
- El Governance Dashboard — Métricas sobre código generado por IA en tu organización: cuánto, qué calidad, qué coste y dónde están los gaps.
- AI-Assisted Incident Response — Correlacionar alertas con el catálogo y cambios recientes. Runbooks auto-generados. Contexto antes de que el ingeniero abra la terminal.
- El AI-Native IDP completo — Arquitectura de referencia, deployment a Kubernetes y el repositorio completo de plugins.
Tech Stack
| Capa | Tecnología |
|---|---|
| IDP Framework | Backstage (React + TypeScript) |
| AI Backend | ASP.NET Minimal API (.NET 10) |
| AI Models | OpenAI-compatible API (Mistral Large, Claude Sonnet, GPT-5, o cualquier proveedor) |
| Embeddings | mistral-embed (o text-embedding-3-small) |
| Vector Store | PostgreSQL + pgvector |
| Auth | QuantumID (o cualquier OIDC provider: Entra ID, Keycloak, Auth0) |
| Database | PostgreSQL (catalog metadata, metrics, audit) |
| Infrastructure | Kubernetes (Scaleway Kapsule, AKS, EKS, o cualquier cluster K8s) |
| CI/CD | Azure DevOps (o GitHub Actions, GitLab CI) |
El AI backend es un servicio .NET separado al que los plugins de Backstage llaman. Esto mantiene la lógica de IA en un stack que tú controlas — no enterrada dentro del runtime Node.js de Backstage. El frontend de Backstage habla con su propio backend-for-frontend, que hace proxy al servicio .NET de IA.
El servicio de IA usa la OpenAI-compatible API — la misma interfaz que exponen Scaleway Generative APIs, Mistral AI, Azure AI Foundry y OpenAI. Tú eliges el proveedor. El código no cambia. En esta serie usamos Scaleway con Mistral Large — pero puedes cambiar a Claude Sonnet o GPT-5 modificando dos variables de entorno.
Cada tecnología en esta serie se puede sustituir — esa es la gracia de usar protocolos estándar (OIDC, OpenAI-compatible API, Kubernetes). Pero los ejemplos de código y el repositorio forge en GitHub usan un stack concreto: QuantumID para auth, Scaleway Kapsule para K8s, Mistral Large para IA, y Azure DevOps para CI/CD. Cada artículo corresponde a un tag para que puedas seguir paso a paso.

Ejecución
Vamos a montar la base: una instancia de Backstage con autenticación QuantumID y un Software Catalog básico poblado desde tus repositorios.
Paso 1: Crear la app de Backstage
pnpm dlx @backstage/create-app@latest --skip-install
Cuando te pida un nombre, usa forge (o como tu equipo llame a la plataforma). Esto genera una app de Backstage 1.35+ con el nuevo backend system. Después instala las dependencias:
cd forge
pnpm install
Paso 2: Configurar autenticación OIDC
Backstage soporta OIDC providers de serie. Aquí usamos QuantumID (OIDC con firmas ML-DSA), pero la misma configuración funciona con Entra ID, Keycloak, Auth0, o cualquier proveedor OIDC. La configuración es estándar.
Necesitas una aplicación OIDC de tu proveedor. Para QuantumID, regístrate en la beta business y sigue la configuración del artículo 4 de la serie Quantum-Safe Cloud. Para otros proveedores, crea una app OIDC en tu dashboard. Necesitarás un client_id, client_secret y la discovery URL.
En app-config.yaml:
auth:
environment: development
session:
secret: ${BACKEND_SECRET}
providers:
guest:
dangerouslyAllowOutsideDevelopment: false
oidc:
development:
metadataUrl: ${OIDC_METADATA_URL} # e.g. https://auth.quantumapi.eu/.well-known/openid-configuration
clientId: ${OIDC_CLIENT_ID}
clientSecret: ${OIDC_CLIENT_SECRET}
prompt: consent
additionalScopes:
- profile
- email
El session.secret es obligatorio — sin él, la estrategia OIDC passport falla porque necesita soporte de sesión para gestionar el flujo OAuth. El provider guest está ahí para desarrollo local sin OIDC. En producción, elimínalo y cambia environment a production.
También necesitas activar la backend auth key para comunicación servicio-a-servicio. En la sección backend de app-config.yaml, descomenta el bloque auth:
backend:
auth:
keys:
- secret: ${BACKEND_SECRET}
Añade el módulo de auth del backend en packages/backend/src/modules/auth.ts:
import { createBackendModule } from '@backstage/backend-plugin-api';
import {
authProvidersExtensionPoint,
createOAuthProviderFactory,
} from '@backstage/plugin-auth-node';
import { oidcAuthenticator } from '@backstage/plugin-auth-backend-module-oidc-provider';
/**
* OIDC sign-in module for Backstage.
* Works with any OIDC provider: QuantumID, Entra ID, Keycloak, Auth0.
*/
export default createBackendModule({
pluginId: 'auth',
moduleId: 'oidc-sign-in',
register(reg) {
reg.registerInit({
deps: { providers: authProvidersExtensionPoint },
async init({ providers }) {
providers.registerProvider({
providerId: 'oidc',
factory: createOAuthProviderFactory({
authenticator: oidcAuthenticator,
signInResolver: async ({ profile }, ctx) => {
if (!profile.email) {
throw new Error('OIDC profile missing email');
}
const userEntityRef = `user:default/${profile.email!.split('@')[0]}`;
return ctx.signInWithCatalogUser({
filter: { 'spec.profile.email': profile.email },
}).catch(() => {
// Auto-provision user on first login
return ctx.issueToken({
claims: {
sub: userEntityRef,
ent: [userEntityRef],
},
});
});
},
}),
});
},
});
},
});
Después regístralo en packages/backend/src/index.ts:
backend.add(import('./modules/auth'));
Configura tus variables de entorno:
export OIDC_METADATA_URL=https://auth.quantumapi.eu/.well-known/openid-configuration
export OIDC_CLIENT_ID=your_client_id
export OIDC_CLIENT_SECRET=your_client_secret
export BACKEND_SECRET=change-this-to-a-real-secret
El frontend necesita un API ref personalizado para el OIDC provider y una página de sign-in que lo ofrezca. En packages/app/src/apis.ts, añade la factoría de la API OIDC:
import {
ScmIntegrationsApi,
scmIntegrationsApiRef,
ScmAuth,
} from '@backstage/integration-react';
import {
AnyApiFactory,
ApiRef,
BackstageIdentityApi,
configApiRef,
createApiFactory,
createApiRef,
discoveryApiRef,
OAuthApi,
oauthRequestApiRef,
OpenIdConnectApi,
ProfileInfoApi,
SessionApi,
} from '@backstage/core-plugin-api';
import { OAuth2 } from '@backstage/core-app-api';
export const oidcAuthApiRef: ApiRef<
OAuthApi &
OpenIdConnectApi &
ProfileInfoApi &
BackstageIdentityApi &
SessionApi
> = createApiRef({
id: 'auth.oidc',
});
export const apis: AnyApiFactory[] = [
createApiFactory({
api: scmIntegrationsApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) => ScmIntegrationsApi.fromConfig(configApi),
}),
ScmAuth.createDefaultApiFactory(),
createApiFactory({
api: oidcAuthApiRef,
deps: {
discoveryApi: discoveryApiRef,
oauthRequestApi: oauthRequestApiRef,
configApi: configApiRef,
},
factory: ({ discoveryApi, oauthRequestApi, configApi }) =>
OAuth2.create({
discoveryApi,
oauthRequestApi,
provider: {
id: 'oidc',
title: 'QuantumID',
icon: () => null,
},
defaultScopes: ['openid', 'profile', 'email'],
environment: configApi.getOptionalString('auth.environment'),
}),
}),
];
Después actualiza el SignInPage en packages/app/src/App.tsx para ofrecer login con QuantumID y guest:
import { apis, oidcAuthApiRef } from './apis';
// ... in createApp:
components: {
SignInPage: props => (
<SignInPage
{...props}
providers={[
{
id: 'oidc',
title: 'QuantumID',
message: 'Sign in with QuantumID (OIDC)',
apiRef: oidcAuthApiRef,
},
'guest',
]}
/>
),
},
El oidcAuthApiRef genérico se eliminó de Backstage en una versión anterior, así que necesitas crear el tuyo. La factoría OAuth2.create() gestiona el flujo completo OAuth2/OIDC — funciona con cualquier OIDC provider, no solo QuantumID.
También añade la integración con GitHub en app-config.yaml para que Backstage pueda leer repositorios y el scaffolder pueda publicar nuevos:
integrations:
github:
- host: github.com
token: ${GITHUB_TOKEN} # Personal access token with repo scope
Crea un GitHub Personal Access Token con scope repo y expórtalo:
export GITHUB_TOKEN=ghp_your_token_here
Paso 3: Poblar el Software Catalog
El catálogo es el núcleo de Backstage. Cada servicio, librería y componente de infraestructura tiene un catalog-info.yaml en la raíz de su repositorio.
Aquí tienes uno para la users API de la serie ATLAS+GOTCHA:
# catalog-info.yaml (in users-api repo)
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: users-api
description: REST API for user management with JWT authentication
annotations:
github.com/project-slug: victorZKov/users-api
backstage.io/techdocs-ref: dir:.
tags:
- dotnet
- postgresql
- kubernetes
links:
- url: https://users-api.victorz.cloud/healthz
title: Health Check
icon: dashboard
spec:
type: service
lifecycle: production
owner: team-platform
system: victorz-cloud
providesApis:
- users-api
---
apiVersion: backstage.io/v1alpha1
kind: API
metadata:
name: users-api
description: Users CRUD + JWT authentication
spec:
type: openapi
lifecycle: production
owner: team-platform
definition:
$text: ./openapi.yaml
Registra la ubicación en app-config.yaml:
catalog:
locations:
- type: url
target: https://github.com/victorZKov/users-api/blob/main/catalog-info.yaml
rules:
- allow: [Component, API]
- type: url
target: https://github.com/victorZKov/ScraperAgent/blob/main/catalog-info.yaml
rules:
- allow: [Component, API]
Esto funciona para un puñado de servicios. En una empresa real, usarías el GitHub Discovery provider para auto-detectar cada catalog-info.yaml en tu organización — sin registro manual. Lo mantenemos simple aquí porque automatizaremos el descubrimiento del catálogo con IA en el artículo 2.
Paso 4: Añadir un Software Template básico
Los templates son la forma en que Backstage ayuda a los desarrolladores a crear nuevos servicios. Aquí tienes uno simple para una API .NET:
# templates/dotnet-api/template.yaml
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: dotnet-api
title: .NET API Service
description: Create a new .NET 10 API with PostgreSQL, JWT auth, and K8s deployment
tags:
- dotnet
- api
- recommended
spec:
owner: team-platform
type: service
parameters:
- title: Service Details
required:
- name
- description
- owner
properties:
name:
title: Service Name
type: string
pattern: '^[a-z0-9-]+$'
ui:help: 'Lowercase, dashes only. Example: invoice-api'
description:
title: Description
type: string
owner:
title: Owner
type: string
ui:field: OwnerPicker
- title: Infrastructure
properties:
database:
title: Database
type: string
enum: ['postgresql', 'none']
default: postgresql
auth:
title: Authentication
type: string
enum: ['oidc-jwt', 'api-key', 'none']
default: oidc-jwt
kubernetes:
title: Deploy to Kubernetes
type: boolean
default: true
steps:
- id: fetch
name: Fetch Skeleton
action: fetch:template
input:
url: ./skeleton
values:
name: ${{ parameters.name }}
description: ${{ parameters.description }}
owner: ${{ parameters.owner }}
database: ${{ parameters.database }}
auth: ${{ parameters.auth }}
kubernetes: ${{ parameters.kubernetes }}
- id: publish
name: Publish to Git
action: publish:github # or publish:gitlab, publish:azure-devops
input:
repoUrl: github.com?owner=victorZKov&repo=${{ parameters.name }}
description: ${{ parameters.description }}
defaultBranch: main
repoVisibility: private
- id: register
name: Register in Catalog
action: catalog:register
input:
repoContentsUrl: ${{ steps.publish.output.repoContentsUrl }}
catalogInfoPath: /catalog-info.yaml
output:
links:
- title: Repository
url: ${{ steps.publish.output.remoteUrl }}
- title: Open in Catalog
icon: catalog
entityRef: ${{ steps.register.output.entityRef }}
Este template es estático — genera desde un skeleton fijo. En el artículo 3, lo reemplazaremos con un scaffolder con IA que recibe una descripción en lenguaje natural y genera un proyecto con prompts GOTCHA adaptados al servicio.
Paso 5: Ejecutar
pnpm dev
Abre http://localhost:3000. Verás la UI de Backstage con tu catálogo, tu template y login OIDC.
Esta es la base. Es un setup estándar de Backstage — nada de IA todavía. El catálogo es manual. El template es estático. La documentación son ficheros.
A partir del artículo 2, eso cambia. Cada artículo añade un plugin que hace inteligente una parte de la plataforma.
Checklist
- App de Backstage creada y funcionando en local
- Autenticación OIDC configurada (QuantumID, Entra ID, Keycloak, o tu proveedor)
- Al menos dos servicios registrados en el Software Catalog
- Un Software Template disponible (aunque sea estático)
- Todos los secrets en variables de entorno, no en ficheros de configuración
-
catalog-info.yamlcommiteado en cada repositorio de servicio
Antes del siguiente artículo
Mira tu Software Catalog. ¿Cuántos servicios aparecen? Ahora abre uno y revisa la descripción. ¿Es correcta? ¿El owner es el correcto? ¿Cuándo se actualizó por última vez?
Si eres como la mayoría de equipos, al menos un campo está mal. Ese es el problema que resolvemos en el artículo 2: un plugin de Backstage que lee tu código, entiende qué hace el servicio y mantiene el catálogo preciso — sin que nadie lo mantenga a mano.
Si esta serie te resulta útil, puedes invitarme a un café.
Este es el artículo 1 de la serie AI-Native IDP. Siguiente: Enseñando a tu catálogo a pensar — IA que auto-documenta tus servicios desde su código fuente.
Loading comments...