Backstage vs Port vs Compass vs Cortex: guía de compra
|
Objetivos del capítulo
|
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
|
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
|
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
|
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
|
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:
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
Calcula horas ahorradas × coste/hora × 12 meses. La cifra resultante es defendible. |
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
-
Define tus 5 criterios con pesos (coste, tiempo, flexibilidad, vendor lock-in, soporte).
-
Puntúa cada opción 1-5 en cada criterio.
-
Calcula el score ponderado.
-
Valida con un pilot de 30 días (Backstage local + Port trial + Compass trial + Cortex trial).
-
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.
-
Construye la tabla comparativa con tus 5 criterios.
-
Puntúa cada opción (Backstage, Port, Compass, Cortex) honestamente.
-
Pilot de 30 días con la opción mejor puntuada.
-
Mide TTD, DAU/MAU, cobertura del catalog.
-
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 (
originpor 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 |
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 |
-
yamllint(CLI) para CI. -
https://www.yamllint.com/para validación rápida.
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)
-
Developer hace clic en "Login with GitHub".
-
Backstage redirige al IdP.
-
IdP muestra consentimiento; developer acepta.
-
IdP redirige a :code:`https://backstage/auth/github/handler?code=XXX`.
-
Backstage intercambia el code por un access_token (server-to-server).
-
Backstage pide :code:`/userinfo` con el token.
-
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
Groupdel 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
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
El :cap-16 tiene el argumentario para defender estas métricas ante la dirección. |
Para más
-
Capítulo 15 — Backstage en producción (SLOs y alertas)