Backstage vs Port vs Compass vs Cortex: guía de compra

Objetivos del capítulo
  • Comparar Backstage con las tres alternativas comerciales dominantes.

  • Construir un scoring honesto por criterio.

  • Argumentar la inversión ante una CTO con métricas de adopción.

  • Tomar una decisión buy vs build informada.

No hay un "mejor", hay un "para quién"

La pregunta correcta no es "¿cuál IDP es mejor?" sino "¿qué IDP encaja con el tamaño, la cultura y el presupuesto de mi equipo?". Aquí comparamos cuatro opciones dominantes en 2026 con honestidad: ninguna es perfecta.

Tabla comparativa (5 ejes)

Criterio Backstage Port Compass Cortex

Modelo de despliegue

Self-hosted OSS (CNCF)

SaaS (cloud-hosted, también on-prem)

SaaS (Atlassian)

SaaS (multi-cloud)

Curva de aprendizaje

Alta (TS/React/Node/K8s)

Media (UI low-code, sin tocar infra)

Media (si ya usas Atlassian)

Baja (UI muy guiada)

Coste inicial

Bajo (mano de obra)

Medio (licencias por developer)

Medio (bundle con Jira/Confluence)

Medio (premium por integraciones)

Personalización

Total (es OSS, todo el código)

Media (extensiones JS/TS)

Baja-media (UI constraints)

Baja (dashboards templados)

Riesgo de lock-in

Bajo (forkeable, sin licencia)

Medio-alto (data export, API)

Alto (Atlassian ecosystem)

Alto (integraciones propietarias)

Ecosistema

+800 plugins comunitarios

~200 integrations oficiales

Integración fuerte con Atlassian

~150 integraciones

Compliance / SOC2

Tú lo certificas

Sí (SOC2 Type II)

Sí (SOC2 Type II)

Sí (SOC2 Type II)

Backstage en detalle

  • Fortalezas: OSS, CNCF, sin vendor lock-in, máxima personalización, comunidad grande, plugins para casi todo.

  • Debilidades: requiere equipo dedicado (1-3 FTE), self-hosted implica actualizar y securizar tú mismo, documentación dispersa.

Cuándo elegir Backstage
  • Empresa con equipo de platform engineering.

  • Más de 50 services en producción.

  • Necesidad de personalización profunda (dominios propios, workflows no estándar).

  • Disposición a invertir 12-18 meses en adopción.

Port en detalle

  • Fortalezas: SaaS listo para usar, UI low-code, integraciones nativas con Jira/GitHub/K8s, self-service sin código.

  • Debilidades: menos flexible que Backstage, costes crecientes con el tamaño, integraciones proprietarias en algunos casos.

Cuándo elegir Port
  • Quieres una IDP en producción en menos de 3 meses.

  • Equipo de platform pequeño (1-2 personas) que prefiere low-code.

  • Budget de SaaS aprobado y buscas time-to-value rápido.

Compass en detalle

  • Fortalezas: integración nativa con Jira/Confluence/Bitbucket, UI consistente con Atlassian, scorecards out-of-the-box.

  • Debilidades: lock-in fuerte con Atlassian, menos flexible fuera del ecosistema, precios bundle.

Cuándo elegir Compass
  • Empresa ya invertida en Atlassian (Jira, Confluence, Bitbucket).

  • Quieres scorecards y métricas listas.

  • No necesitas extensibilidad fuera del ecosistema.

Cortex en detalle

  • Fortalezas: UI muy cuidada, integrations curadas, enfoque en service catalog + scorecards + incidents.

  • Debilidades: personalización limitada, coste elevado en planes premium, comunidad más pequeña.

Cuándo elegir Cortex
  • Quieres una experiencia "product" fuerte (UI cuidada, soporte premium).

  • Tu organización valora dashboards templados sobre customización.

Radar comparativo

Ranking por criterio (1=bajo, 5=alto)

Tabla comparativa extraída del radar original, mantenida como referencia cualitativa. Los valores son orientativos según análisis del autor; verifica con cada vendor antes de tomar decisiones.

| Criterio | Backstage | Port | Compass | Cortex | |----------------|-----------|------|---------|--------| | Flexibilidad | 5 | 3 | 2 | 2 | | Facilidad | 2 | 4 | 4 | 5 | | Coste bajo | 4 | 3 | 3 | 2 | | Ecosistema | 5 | 4 | 3 | 3 | | Soporte vendor | 2 | 4 | 5 | 5 |

  • Lectura del cuadro: Backstage gana en flexibilidad y ecosistema (cero lock-in, plugins ilimitados), pero pierde en facilidad y soporte vendor (lo operas tú). Port y Cortex son el opuesto: más fáciles pero menos personalizables. Compass encaja si ya vives en Atlassian.

Métricas de adopción

DAU/MAU como señal

Una IDP sana tiene:

  • DAU/MAU > 60% (developer vuelve casi todos los días).

  • Catálogo coverage > 80% (la mayoría de servicios están registrados).

  • Scaffolder usage > 5 templates/mes (la IDP se usa para crear, no solo consultar).

Si DAU/MAU < 30% tras 6 meses, hay un problema de UX o de comunicación.

ROI: el argumentario para la CTO

Frameworks de ROI
  1. Time-to-Dev (TTD): tiempo desde "necesito un servicio nuevo" hasta "está en producción". Antes 2-4 semanas; con scaffolder + IaC, 1-2 días.

  2. Cognitive load reduction: developers encuentran docs, owners y runbooks sin preguntar. Encuesta interna antes/después.

  3. Operational toil: tickets "dónde está X" caen > 50% tras 6 meses.

Calcula horas ahorradas × coste/hora × 12 meses. La cifra resultante es defendible.

Embudo de decisión buy vs build
Failed to generate image: Could not find the 'mmdc' executable in PATH; add it to the PATH or specify its location using the 'mmdc' document attribute
flowchart TB
  Start{Tienes equipo platform?} -->|Sí| Build[Build con Backstage]
  Start -->|No| Time{Necesitas < 3 meses?}
  Time -->|Sí| BuySaaS[Buy SaaS Port/Cortex]
  Time -->|No| Hire[Contrata 1 platform eng + Backstage]
  Build --> Score{Aceptas 12-18 meses?}
  Score -->|Sí| Backstage
  Score -->|No| Hire

Scoring honesto: cómo lo construirías para tu empresa

  1. Define tus 5 criterios con pesos (coste, tiempo, flexibilidad, vendor lock-in, soporte).

  2. Puntúa cada opción 1-5 en cada criterio.

  3. Calcula el score ponderado.

  4. Valida con un pilot de 30 días (Backstage local + Port trial + Compass trial + Cortex trial).

  5. Decide con datos, no con hype.

Marketing speak fuera

Ningún vendor te va a decir "somos malos en X". Lee críticas en Reddit, G2, Hacker News, no las páginas de marketing. Y mide tu pilot; no te fíes del deck del vendedor.

Cierre del libro

Has recorrido los 16 capítulos: de "¿qué es una IDP?" a "¿la compro o la construyo?". La respuesta razonable para una organización de 100-500 developers con equipo de platform engineering es Backstage. La respuesta razonable para una organización de 30 developers sin equipo de platform es Port o Cortex.

Lo que hagas con la IDP importa más que la IDP que compres.

Example 16. Receta del capítulo
  1. Construye la tabla comparativa con tus 5 criterios.

  2. Puntúa cada opción (Backstage, Port, Compass, Cortex) honestamente.

  3. Pilot de 30 días con la opción mejor puntuada.

  4. Mide TTD, DAU/MAU, cobertura del catalog.

  5. Decide con datos: build, buy o híbrido.

Resumen

  • Backstage = OSS flexible; Port = SaaS rápido; Compass = bundle Atlassian; Cortex = UX cuidada.

  • El scoring honesto y el pilot de 30 días ganan al deck del vendedor.

  • ROI = TTD × cognitive load × toil.

  • La IDP que importa es la que tu equipo usa, no la que el marketing dice que es la mejor.

Glosario del capítulo

TTD

Time-to-Dev. Tiempo desde la idea hasta el servicio en producción.

DAU/MAU

Daily/Monthly Active Users. Métrica de adopción y stickiness.

SOC2

Estándar de auditoría de seguridad para SaaS.

vendor lock-in

Dependencia técnica que dificulta migrar a otro proveedor.

pilot

Prueba controlada (30 días) antes de comprar o desplegar a producción.

Próximo paso

Requisitos desde cero —si llegaste aquí sin prerrequisitos, vuelve al apéndice A y prepara tu mise-en-place.

Parte VII: Apéndices

Material de referencia. Lo que se asume como prerrequisito se enseña aquí desde cero. Léelos antes de la Parte 1 si vienes de fuera del mundo backend.

Apéndice A — Git desde cero

Objetivo del apéndice

Darte el mínimo de Git necesario para seguir el libro: clonar, branchear, commitear, pushear y abrir PR.

Instalación

# macOS
brew install git

# Ubuntu/Debian
sudo apt install git -y

# Windows (WSL)
wsl --install
# dentro de WSL: sudo apt install git -y

Configuración inicial

git config --global user.name "Tu nombre"
git config --global user.email "tu@email.com"
git config --global init.defaultBranch main
git config --global pull.rebase true

El flujo mínimo

# Clonar
git clone https://github.com/sazon-foods/backstage-sazon.git
cd backstage-sazon

# Crear rama
git checkout -b feat/sazon-status-plugin

# Editar archivos, luego:
git add .
git commit -m "feat(sazon-status): add /health endpoint"

# Sincronizar y pushear
git pull --rebase
git push origin feat/sazon-status-plugin

# Abrir PR desde la URL que imprime GitHub CLI:
gh pr create --fill

Conceptos clave

  • Working tree: tu carpeta de archivos.

  • Index / Staging: lo que va en el próximo commit (git add).

  • HEAD: el commit actual.

  • Branch: puntero a un commit (rama de trabajo).

  • Remote: el repo en el servidor (origin por convención).

Comandos de rescate

git status                # qué ha cambiado
git diff                  # diff sin stage
git diff --staged         # diff en stage
git log --oneline -10     # últimos 10 commits
git stash                 # guarda cambios sin commitear
git stash pop             # los restaura
git reset --hard HEAD~1   # descarta el último commit (cuidado)
git revert HEAD            # revierte el último commit (seguro)

Apéndice B — Línea de comandos Linux/macOS

Objetivo del apéndice

El mínimo de shell que necesitas para seguir el libro: navegación, ficheros, pipes, procesos y permisos.

Navegación

pwd                       # dónde estoy
ls                        # qué hay aquí
ls -la                    # con ocultos y detalles
cd /ruta                  # cambiar de directorio
cd -                      # volver al directorio anterior
cd ~                      # ir al home

Ficheros

mkdir -p dir/sub          # crear estructura
touch file.txt            # crear/actualizar archivo
cp a.txt b.txt            # copiar
mv a.txt dir/             # mover
rm file.txt               # borrar
rm -rf dir                # borrar recursivo (cuidado)
cat file.txt              # imprimir
less file.txt             # paginar
head -20 file.txt         # primeras 20 líneas
tail -f file.txt          # últimas líneas, sigue creciendo

Pipes y redirección

ls | grep .yaml           # filtrar
cat file | sort | uniq    # encadenar
echo "hola" > file.txt    # sobreescribir
echo "adicional" >> file.txt  # añadir
cmd 2>&1                  # stderr a stdout
cmd > out.log 2>&1        # todo a un archivo

Procesos

ps aux | grep node        # procesos de node
kill PID                  # terminar proceso (SIGTERM)
kill -9 PID               # forzar (SIGKILL)
nohup cmd &               # correr en background, inmune a hangup
jobs                      # trabajos del shell actual
fg %1                     # traer a foreground

Permisos

chmod +x script.sh        # hacer ejecutable
chmod 644 file            # rw-r--r--
chmod 600 key.pem         # rw------- (privado)
chown user:group file     # cambiar dueño

SSH y claves

ssh-keygen -t ed25519 -C "tu@email.com"   # crear clave
ssh-copy-id user@host                     # subir pública
ssh user@host                             # conectar
Atajos del shell
  • :code:`Ctrl+R` — buscar en el historial.

  • :code:`Ctrl+A/E` — inicio/fin de línea.

  • :code:`Ctrl+U/K` — borrar hasta inicio/fin de línea.

  • :code:`!!` — repetir último comando.

  • :code:`sudo !!` — repetir último comando con sudo.

Apéndice C — Docker y Docker Compose

Objetivo del apéndice

Imágenes, contenedores, redes, volúmenes y multi-servicio con Compose. Suficiente para correr Backstage localmente.

Conceptos

  • Imagen: snapshot de un FS + comando de arranque.

  • Contenedor: instancia corriendo de una imagen.

  • Volumen: almacenamiento persistente fuera del FS del contenedor.

  • Red: espacio de nombres donde los contenedores se ven por hostname.

  • Compose: declarativa multi-contenedor en YAML.

Comandos esenciales

docker pull postgres:16           # bajar imagen
docker images                     # listar imágenes
docker run -d --name db postgres:16
docker ps                         # contenedores corriendo
docker ps -a                      # todos
docker logs -f db                 # logs del contenedor
docker exec -it db bash           # shell interactivo
docker stop db                    # parar
docker rm db                      # borrar
docker rmi postgres:16            # borrar imagen

Compose mínimo

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
volumes:
  pgdata:
docker compose up -d      # arranca en background
docker compose down       # para y borra contenedores (no volúmenes)
docker compose logs -f    # logs agregados
docker compose exec db bash

Dockerfile mínimo (Node)

FROM node:20-bookworm-slim AS builder
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN corepack enable && pnpm install --frozen-lockfile
COPY . .
RUN pnpm build

FROM node:20-bookworm-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 7007
CMD ["node", "dist/index.js"]
Buenas prácticas
  • Imágenes slim (:code:`-slim`) cuando puedas.

  • :code:`HEALTHCHECK` para que Compose sepa si el contenedor está listo.

  • :code:`--init` para que las señales lleguen al proceso principal.

  • Variables de entorno en :code:`.env`, no en el YAML.

Apéndice D — Kubernetes básico

Objetivo del apéndice

Suficiente Kubernetes para desplegar Backstage: Pod, Deployment, Service, Ingress, kubectl. Sin entrar en Operators ni Helm charts avanzados.

Conceptos

  • Pod: 1+ contenedores corriendo juntos en el mismo nodo.

  • Deployment: controladora que mantiene N réplicas de un Pod.

  • Service: punto de acceso estable a un Deployment (ClusterIP, NodePort, LoadBalancer).

  • Ingress: reglas HTTP/S externas (host + path → service).

  • Namespace: aislamiento lógico.

  • ConfigMap / Secret: config y secretos inyectados como env o archivos.

kubectl esencial

kubectl get pods -A
kubectl get svc,ing -A
kubectl describe pod <name>
kubectl logs -f <pod>
kubectl exec -it <pod> -- bash
kubectl apply -f deployment.yaml
kubectl delete -f deployment.yaml
kubectl rollout status deployment/backstage
kubectl rollout undo deployment/backstage    # rollback
kubectl top pod                                # uso de recursos

Deployment mínimo

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backstage
  namespace: backstage
spec:
  replicas: 2
  selector:
    matchLabels: { app: backstage }
  template:
    metadata:
      labels: { app: backstage }
    spec:
      containers:
        - name: backstage
          image: ghcr.io/sazon-foods/backstage:1.31.0
          ports: [{ containerPort: 7007 }]
          envFrom:
            - secretRef: { name: backstage-secrets }

Service e Ingress

apiVersion: v1
kind: Service
metadata: { name: backstage, namespace: backstage }
spec:
  selector: { app: backstage }
  ports: [{ port: 80, targetPort: 7007 }]
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata: { name: backstage, namespace: backstage }
spec:
  rules:
    - host: backstage.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: backstage
                port: { number: 80 }
Debugging
  • :code:`kubectl describe` > :code:`kubectl get` para problemas (te dice Events).

  • :code:`kubectl logs --previous` para el contenedor que crasheó.

  • :code:`kubectl port-forward svc/backstage 7007:80 -n backstage` para acceso local sin Ingress.

Apéndice E — YAML y JSON

Objetivo del apéndice

YAML suficiente para escribir catalog-info.yaml, app-config.yaml, manifests de K8s y templates del Scaffolder.

Reglas de oro

  • Indentación: 2 espacios (nunca tabs).

  • Claves: :code:`clave: valor` con espacio después de los dos puntos.

  • Listas: :code:`- elemento` (guión + espacio).

  • Strings: comillas solo si hace falta (caracteres especiales, números como string).

  • Comentarios: :code:`# comentario` hasta fin de línea.

Tipos básicos

cadena: "hola"
numero: 42
boolean: true
nulo: null
fecha: 2026-07-23
lista:
  - uno
  - dos
  - tres
mapa:
  clave1: valor1
  clave2: valor2
multilinea: |
  Línea 1
  Línea 2

JSON equivalente

{
  "cadena": "hola",
  "numero": 42,
  "boolean": true,
  "lista": ["uno", "dos"],
  "mapa": { "clave1": "valor1" }
}

Multi-documento (---)

apiVersion: v1
kind: Service
metadata: { name: a }
spec: { selector: { app: a } }
---
apiVersion: v1
kind: Service
metadata: { name: b }
spec: { selector: { app: b } }

Anclas y referencias (& y *)

defaults: &defaults
  retries: 3
  timeout: 30
service-a:
  <<: *defaults
  name: a
service-b:
  <<: *defaults
  name: b
Validador online

Un YAML inválido rompe Backstage al arrancar: valida antes de commitear.

Apéndice F — JavaScript y TypeScript básico

Objetivo del apéndice

Lo mínimo de JS/TS que necesitas para escribir plugins de Backstage. Si vienes de otro lenguaje, este apéndice te da el vocabulario.

Variables y tipos básicos

const name: string = 'sazon';
const port: number = 7007;
const enabled: boolean = true;
const tags: string[] = ['api', 'restaurant'];
const map: Record<string, number> = { a: 1 };
const maybe: string | null = null;

Funciones

function add(a: number, b: number): number { return a + b; }
const greet = (name: string): string => `Hola, ${name}`;
const optional = (x?: number) => x ?? 0;     // nullish coalescing
async function load(): Promise<string> { return 'ok'; }

Objetos e interfaces

interface Service { name: string; port: number; tags?: string[]; }
const svc: Service = { name: 'api', port: 7007 };
const withDefaults: Service = { name: 'api', port: 7007, tags: [] };

Async/Await

async function getStatus(service: string) {
  const res = await fetch(`/api/sazon/status/${service}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json() as Promise<{ status: string }>;
}

Destructuring

const { name, port = 80 } = svc;
const [first, ...rest] = ['a', 'b', 'c']; // first='a', rest=['b','c']

Modules: import/export

import { z } from 'zod';
import type { LoggerService } from '@backstage/backend-plugin-api';

export const StatusSchema = z.object({ service: z.string() });
export type Status = z.infer<typeof StatusSchema>;

Node: package.json mínimo

{
  "name": "@sazon/plugin-x",
  "version": "0.1.0",
  "main": "src/index.ts",
  "scripts": {
    "start": "backstage-cli package start",
    "test": "backstage-cli package test"
  }
}
Tipado estricto

Backstage activa :code:`strict: true` por defecto. Si vienes de JS, prepárate para tipar todo al principio; a la larga, el compilador atrapa errores caros.

Apéndice G — OAuth2/OIDC conceptual

Objetivo del apéndice

OAuth2 y OIDC sin jerga. Lo justo para entender qué pasa cuando haces login en Backstage y qué decisiones tomar como admin.

Roles

  • Resource Owner: el developer (dueño de su identidad).

  • Client: la app que pide datos (Backstage).

  • Authorization Server / IdP: emite tokens (GitHub, Keycloak, Okta).

  • Resource Server: la API que valida el token.

Flujo Authorization Code (el que usa Backstage)

  1. Developer hace clic en "Login with GitHub".

  2. Backstage redirige al IdP.

  3. IdP muestra consentimiento; developer acepta.

  4. IdP redirige a :code:`https://backstage/auth/github/handler?code=XXX`.

  5. Backstage intercambia el code por un access_token (server-to-server).

  6. Backstage pide :code:`/userinfo` con el token.

  7. Backstage crea la sesión (cookie) y devuelve 200.

Tokens

  • Access token: corta duración (minutos). Para llamar a APIs.

  • Refresh token: larga duración. Para renovar el access token.

  • ID token (OIDC): JWT con claims de identidad (sub, email, name).

Claims típicas

{
  "sub": "user:default/tester",
  "email": "tester@sazon-foods.com",
  "preferred_username": "tester",
  "name": "Maite Tester",
  "groups": ["platform-sazon", "engineering"],
  "iss": "https://keycloak.sazon-foods.com/realms/sazon",
  "aud": "backstage",
  "exp": 1720003200
}

Scopes

Definen qué puede pedir el client:

  • :code:`openid` — mínimo OIDC.

  • :code:`profile` — nombre, username.

  • :code:`email` — email.

  • :code:`groups` — grupos (en Keycloak con mapper).

Mejores prácticas
  • Usa Authorization Code with PKCE (no Implicit).

  • Access tokens de corta vida (< 1 h).

  • Refresh tokens en storage seguro del client.

  • Claims de grupos para mapear a Group del catalog.

Apéndice H — Migración de legacy backend (referencia)

Objetivo del apéndice

Cómo pasar del legacy :code:`index.ts` a la New Backend System, con el mapeo uno-a-uno de patrones comunes.

Diferencias clave

Concepto Legacy New Backend System

Punto de entrada

:code:`createPlugin()` + router manual

:code:`createBackendPlugin()` o :code:`createBackendModule()`

Router

:code:`app.use('/api/foo', router)`

:code:`httpRouter.use(await createRouter(…​))`

Config

:code:`Config.getOptionalString(…​)` con lectura directa

:code:`ConfigService` inyectado

Identity

Request headers ad-hoc

:code:`HttpAuthService.credentials()`

DB

:code:`Knex(…​)` instanciado a mano

:code:`DatabaseService` con migraciones

Logging

:code:`winston` o consola

:code:`LoggerService` (pino)

Paso 1 — Reescribir index.ts

// Antes (legacy)
const backend = new Backend({ ... });
backend.add(...);
// muchas líneas de routers
backend.start();

// Después (New Backend System)
const backend = createBackend();
backend.add(import('@backstage/plugin-catalog-backend'));
backend.add(import('@sazon/plugin-sazon-status-backend'));
backend.start();

Paso 2 — Convertir plugins

// Antes (legacy)
export default async function createPlugin({ ... }: PluginEnvironment) {
  const router = Router();
  router.get('/foo', ...);
  return router;
}

// Después (New Backend System)
export const fooPlugin = createBackendPlugin({
  id: 'foo',
  register(env) {
    env.registerInit({
      deps: { httpRouter: coreServices.httpRouter },
      async init({ httpRouter }) {
        httpRouter.use(await createRouter({ ... }));
      },
    });
  },
});

Paso 3 — Servicios

Pasa de singletons globales a deps declarativos:

env.registerInit({
  deps: {
    database: coreServices.database,
    logger: coreServices.logger,
    httpAuth: coreServices.httpAuth,
  },
  async init({ database, logger, httpAuth }) { ... },
});

Paso 4 — Custom services

Si tenías un service factory custom, decláralo con :code:`createServiceFactory`:

export const myCustomService = createServiceFactory({
  service: createServiceRef<MyService>({ id: 'my-custom', scope: 'plugin' }),
  factory: async () => MyServiceImpl,
});

Y lo registras con :code:`backend.add(myCustomService)`.

Compatibilidad

  • La legacy backend system sigue operativa en Backstage 1.x.

  • No puedes mezclar: si arrancas con :code:`createBackend(), todos los plugins deben ser NBS o estar envueltos en un :code:`legacyPlugin() shim.

  • Planifica la migración antes de que tu :code:`index.ts` legacy supere 500 líneas.

Apéndice I — Glosario de términos

Objetivo del apéndice

Términos recurrentes del libro, en orden alfabético, con su definición corta y un enlace al capítulo donde se explican.

ApisRegistry

Bus de APIs del shell de Backstage (frontend). Ver :cap-09.

BackendFeature

Unidad que el backend monta: plugin, módulo o service factory. Ver :cap-05.

Bootstrap

Asistente :code:`@backstage/create-app` que genera un monorepo Backstage. Ver :cap-03.

Codemod

Script automatizado que migra código entre versiones de Backstage. Ver :cap-15.

coreServices

Bus de servicios del backend (Database, Cache, Auth, Logger, etc.). Ver :cap-05.

Component

Entidad del catalog que representa un servicio o sitio. Ver :cap-04.

Crossplane

Plataforma K8s que expone recursos cloud como CRDs. Ver :cap-15.

DAU/MAU

Daily/Monthly Active Users. Métrica de adopción. Ver :cap-16.

DiscoveryProcessor

Pieza que descubre entidades desde fuentes externas. Ver :cap-04.

Datasource

Backend que expone datos a la IDP (GitHub, GitLab, AWS). Ver :cap-15.

Entidad

Objeto JSON/YAML del catalog (Component, API, Resource, System, etc.). Ver :cap-04.

EventsService

Bus pub/sub interno del backend de Backstage. Ver :cap-07.

HttpAuthService

Servicio que convierte credenciales HTTP en Principal. Ver :cap-07.

HttpRouterService

Servicio que expone el router HTTP compartido del backend. Ver :cap-05.

IDP

Internal Developer Portal. Portal unificado para developers. Ver :cap-01.

Knex

SQL query builder usado por Backstage. Ver :cap-07.

Kind

Categoría de una entidad del catalog (Component, API, Resource, System, Domain, Group, User). Ver :cap-04.

makeStyles

API de Material UI v4 para crear hooks de estilos tipados. Ver :cap-10.

New Backend System

Arquitectura recomendada desde Backstage 1.20. Ver :cap-05.

OAuth

Protocolo de delegación de autorización. Ver :apéndice G.

OIDC

Capa de identidad sobre OAuth 2.0. Ver :apéndice G.

OpenTofu

Fork open source de Terraform, mantenido por la Linux Foundation. Ver :cap-15.

PermissionPolicy

Función TS que evalúa si una acción está permitida (RBAC). Ver :cap-14.

Principal

Objeto que representa al usuario autenticado (subject, type). Ver :cap-06.

RBAC

Role-Based Access Control. Modelo allow/deny sobre acciones y recursos. Ver :cap-14.

RouteRef

Identificador inmutable de una ruta frontend. Ver :cap-08.

Scaffolder

Plugin de Backstage para generar proyectos desde plantillas. Ver :cap-12.

ServiceMonitor

CRD de Prometheus Operator para descubrir métricas. Ver :cap-15.

signIn.resolver

Función que mapea el usuario autenticado a una entidad User del catalog. Ver :cap-14.

SLO

Service Level Objective. Objetivo medible (latencia, disponibilidad). Ver :cap-15.

System

Entidad que agrupa Components de un mismo dominio. Ver :cap-04.

Tags

Marcadores libres que clasifican entidades. Ver :cap-04.

Template

YAML del Scaffolder que define un flujo generador. Ver :cap-12.

themes.json

Archivo que define paletas light y dark de la IDP. Ver :cap-11.

TTD

Time-to-Dev. Tiempo desde la idea hasta el servicio en producción. Ver :cap-16.

useApi

Hook de Backstage que resuelve un ApiRef en su implementación inyectada. Ver :cap-09.

vendor lock-in

Dependencia técnica que dificulta migrar a otro proveedor. Ver :cap-16.

WCAG

Web Content Accessibility Guidelines. Estándar de accesibilidad web. Ver :cap-10.

Zod

Librería de validación de esquemas para TypeScript. Ver :cap-06.

Apéndice J — Métricas de éxito (resumen ejecutivo)

Objetivo del apéndice

El dashboard que entregas a la CTO al cierre de cada trimestre: 8 KPIs que cuentan si tu IDP está viva o moribunda.

Las 8 métricas que importan

KPI Qué mide Objetivo Cómo medirlo

Catalog coverage

% de servicios registrados

> 80%

:code:`catalogApi.getEntities({ filter: { kind: 'Component' } })` vs fuente de verdad externa

DAU/MAU

Frecuencia de uso

> 60%

Cookies de sesión o logs de acceso autenticado

Template usage

Templates ejecutados / mes

> 5

Contador del scaffolder

TTD medio

Días desde idea a producción

< 3

Scaffolder log + PR open-to-merge time

Owner coverage

Componentes con :code:`spec.owner`

> 95%

Validación del catalog

SLO availability

Uptime mensual

> 99.5%

Prometheus :code:`up{job="backstage"}`

Error rate

% respuestas 5xx

< 1%

Prometheus :code:`rate(http_requests_total{status=~"5.."}[5m])`

Plugin adoption

Plugins con > 1 usuario activo

> 5

Logs de acceso por plugin

Cómo presentar el dashboard

Cada métrica, una respuesta
  • ¿Estamos mejorando? → línea temporal.

  • ¿Dónde estamos hoy? → número + delta vs trimestre anterior.

  • ¿Qué hay que hacer? → acción concreta si la métrica está en rojo.

Un dashboard sin acciones es ruido. Si una métrica está mal, propón un plan para arreglarla en la misma reunión.

Ejemplo de reporte trimestral

Q3 2026 — Backstage Sazón Foods

  • Catalog coverage: 87% (+12 pp vs Q2) — se migraron 14 servicios legacy.

  • DAU/MAU: 64% (+8 pp) — adopción estable en equipos de producto.

  • Templates ejecutados: 23 (12 servicios nuevos, 11 features) — por encima del objetivo.

  • TTD medio: 4.2 días (-2.1 vs Q2) — el scaffolder recortó tiempo de setup.

  • SLO: 99.7% availability (objetivo cumplido).

  • Action item: RBAC queda al 30% de cobertura; objetivo Q4 es 70%.

Verde, amarillo, rojo. Una página. Sin slides.

Por qué importan las métricas

Lo que mides, lo que mejoras
  • Sin métricas, una IDP es "el juguete de platform".

  • Con métricas, es infraestructura: una pieza que falla si no se cuida.

  • Las métricas dan ownership y mejoran la moral del equipo.

El :cap-16 tiene el argumentario para defender estas métricas ante la dirección.