Skip to content

Repository files navigation

SAFe Organization Blueprint Designer

Diseña una organización SAFe entera, valídala contra los guardrails del marco y expórtala como JSON versionable — en un único archivo HTML, sin build, sin backend y sin dependencias.

Demo en vivo Licencia MIT Sin dependencias Sin build SAFe 6.0 PRs bienvenidos

▶ Probar la aplicación · Página del proyecto · English · Contribuir · Seguridad


Montar un Agile Release Train en una pizarra es fácil. Descubrir tres meses después que tenía catorce equipos, ningún System Architect asignado y que el 80% de las transiciones de su value stream cambian de responsable, ya no lo es.

Esta herramienta invierte el orden: modelas el diseño y el diseño te responde. Cada nodo que colocas, cada paso que encadenas y cada celda que marcas en la matriz se evalúa en tiempo real contra los rangos de referencia de SAFe —tamaño de equipo, número de trenes, cobertura de roles obligatorios, presupuesto Lean, densidad de handoffs— y el resultado se condensa en un Health Score y una lista de hallazgos accionables, cada uno enlazado al elemento que lo provoca.

El flujo y la organización son dos modelos independientes que puedes diseñar en cualquier orden. Los handoffs, que son donde se va el tiempo, solo aparecen al cruzarlos.

Todo ocurre en tu navegador. No hay servidor, no hay cuenta, no hay telemetría.


Tabla de contenidos


Qué hace

SAFe sostiene organize around value, y su taller de identificación de value streams sigue un orden concreto: value streams operativos → sistemas → personas → development value streams → diseño de ARTs. La organización es la variable dependiente, no el punto de partida.

Esta herramienta respeta ese orden. Por eso el flujo y la organización son dos modelos con identidad propia: puedes diseñar un value stream entero —pasos, sistemas, retrabajos— sin haber creado un solo equipo, y puedes montar la organización sin describir ningún flujo. Las tres vistas de la aplicación son esos dos modelos y su cruce.

Vista Atajo Qué contiene
Organización 1 Quién está en qué equipo, en qué tren y con qué roles
Flujo 2 Cómo se mueve el valor, de disparador a valor recibido
Alineación 3 Quién ejecuta cada paso. Los handoffs solo existen aquí

1 · El flujo

Dos tipos de value stream, cada uno con sus sistemas y su secuencia de pasos:

Tipo Qué describe Campos propios
Operational Value Stream (ovs) Cómo la empresa entrega valor a un cliente, de disparador a valor recibido trigger, value
Development Value Stream (dvs) Las personas y sistemas que construyen las soluciones que usa el flujo operativo supports (qué OVS sostiene), pareja con un nodo organizativo

Cada paso puede marcarse como retrabajo: la vuelta atrás en el flujo. Los sistemas se declaran una vez y se comparten entre streams, porque en la realidad también se comparten.

El asistente parte de dos plantillas editables —siete pasos cada una— que son el esqueleto habitual de cada tipo:

OVS   Solicitud · Cualificación · Preparación · Ejecución · Entrega · Seguimiento · Cierre
DVS   Análisis y refinamiento · Diseño de solución · Construcción · Integración ·
      Validación · Despliegue · Medición y aprendizaje

2 · La organización

Las cuatro configuraciones de SAFe

Cambia entre configuraciones y el lienzo, la paleta y el diagnóstico se adaptan a los niveles disponibles en cada una:

Configuración Niveles incluidos Clave interna
Essential SAFe ART + Agile Teams essential
Large Solution SAFe Solution Train + ARTs + Teams + Suppliers largeSolution
Portfolio SAFe Portfolio + Development Value Streams + ARTs + Teams portfolio
Full SAFe Todos los niveles full

Los seis tipos de nodo

Cada uno con su catálogo de roles obligatorios y opcionales, sus artefactos de referencia y sus reglas de anidamiento:

Nodo Nivel SAFe Acepta como hijo Roles obligatorios
Portfolio Portfolio Level Development Value Stream LPM, Epic Owners, Enterprise Architect
Development Value Stream Portfolio Level Solution Train, ART Value Stream Coordination
Solution Train Large Solution Level ART, Supplier STE, Solution Management, Solution Architect
Agile Release Train Essential Level Agile Team RTE, Product Management, System Architect, Business Owners
Agile Team Team Level — Product Owner, Scrum Master / Team Coach
Supplier Large Solution Level — Responsable de relación

La jerarquía se valida en tiempo real: cada nodo solo acepta los hijos que el marco permite, tanto al añadir desde la paleta como al arrastrar y soltar en el lienzo.

Los Agile Teams se tipifican además según Team Topologies (Stream-aligned, Complicated Subsystem, Platform, Enabling, System Team, Shared Services) y su método de ejecución (SAFe Scrum, SAFe Team Kanban o híbrido).

3 · La alineación

Una matriz que cruza los pasos de cada value stream con los componentes de la organización. Pulsar una celda cicla entre cuatro roles y el vacío:

Rol Sigla Qué significa
Responsable R Ejecuta el paso y responde de él. Define la frontera para contar handoffs
Contribuye C Aporta trabajo al paso sin responder de su resultado
Aprueba A Puerta de decisión. Estructuralmente es una cola: el trabajo espera
Espera a E El paso queda bloqueado esperando a este componente. Cola pura

Qué componentes pueden ejecutar qué es data, no código: un OVS admite cualquier nivel, incluido Portfolio; un DVS admite de Development Value Stream para abajo.

Los handoffs solo existen aquí. Un handoff es un cambio de responsable entre dos pasos consecutivos: no está en el modelo de flujo ni en el organigrama por separado, aparece únicamente al cruzarlos. Si además uno de los dos pasos es retrabajo, el handoff cuenta como grave y pesa doble en la puntuación — volver atrás dentro del mismo equipo es fricción; volver atrás cambiando de responsable es cola con renegociación.

4 · Las métricas de Flow

Las seis métricas de Flow de SAFe en cada nodo con capacidad de flujo, cada una con su rango saludable y su semáforo:

Métrica Unidad Rango saludable Valor por defecto
Flow Distribution % 50–80 60
Flow Velocity ítems / PI > 0 24
Flow Time días ≤ 45 28
Flow Load WIP ≤ 30 18
Flow Efficiency % ≥ 15 22
Flow Predictability % 80–110 85

Son declaradas, y no puntúan. Estas cifras las escribe quien diseña, no las mide la herramienta: viajan en el export marcadas como provenance: "declared" y scored: false. Generan hallazgos cuando salen de rango, pero el Health Score solo pondera lo que el diseño sostiene por sí mismo. El bloque observed del export queda reservado para datos de ejecución reales.

5 · El diagnóstico

Un motor de reglas recorre los dos modelos y su cruce, y devuelve hallazgos con severidad (warn / err) enlazados al elemento que los origina. Cada regla lleva identificador estable, de modo que el export se puede filtrar y volcar a un tracker sin transformación previa.

Organización — org.*

  • Roles obligatorios sin asignar en cualquier nivel
  • Equipos fuera del rango de 5–11 personas
  • ARTs fuera de 5–12 equipos o de 50–125 personas (número de Dunbar)
  • Solution Trains con un solo ART; Value Streams sin ningún ART
  • Lean Budget sobreasignado o sin distribuir entre Value Streams
  • Horizontes de inversión o Capacity Allocation que no suman 100%

Flujo — flow.*

  • Value streams declarados pero sin ningún paso
  • Flow Efficiency < 15%, Flow Predictability < 80%, o Flow Load por encima del doble del tamaño del equipo

Alineación — align.*

  • Pasos sin nadie asignado, pasos con contribuidores pero sin responsable, y pasos con varios responsables a la vez
  • Densidad de handoffs: qué porcentaje de las transiciones cambia de responsable
  • Retrabajo que cruza frontera de responsable
  • Value streams fragmentados entre varios ARTs, y ARTs que aparecen en demasiados flujos
  • Puertas de decisión, que son colas contadas como tales
  • Componentes de la organización sin ningún trabajo asignado
  • Development Value Streams sin pareja organizativa, parejas que apuntan a un nodo ya borrado, Value Streams presupuestados sin flujo descrito y OVS que ningún DVS declara soportar

El Health Score

Todo se condensa en un número con esta ponderación:

healthScore = coberturaDeRoles       × 0.30
            + integridadEstructural  × 0.35
            + alineación             × 0.35

Donde:

integridadEstructural = 100 − (errores × 22 + avisos × 9) / max(1, nodos / 3)

alineación = coberturaDePasos        × 40   // pasos con un responsable claro
           + (1 − densidadHandoffs)  × 30   // el handoff grave cuenta doble
           + (1 − fragmentación)     × 20   // streams repartidos entre varios ARTs
           + (1 − ociosidad)         × 10   // ARTs y equipos sin trabajo asignado

Si no hay modelo de flujo, la alineación no se puede calcular y su peso se reparte proporcionalmente entre los otros dos factores en lugar de puntuar cero. Un organigrama sin flujo no queda penalizado por algo que no ha declarado; simplemente se le puntúa lo que sí tiene.

Productividad

  • Bienvenida con cuatro puertas: empezar por el flujo, empezar por la organización, cargar un blueprint existente o ver un tour
  • Dos tours guiados independientes de nueve pasos cada uno, uno para la organización y otro para el flujo
  • Asistente de diseño bifurcado: la rama de flujo pregunta por los value streams operativos, los de desarrollo y los sistemas, y ofrece derivar la organización a partir de ellos. Su previsualización usa el mismo plan que la generación, así que lo que anuncia es lo que crea, handoffs incluidos
  • Deshacer / rehacer con historial completo
  • Importar y exportar el blueprint en JSON
  • Exportar como SVG vectorial o PNG a 2×, siguiendo la vista activa
  • Tema claro y oscuro, y modo presentación que pliega los paneles laterales
  • Ejemplo precargado con organización y flujo: un Portfolio con su ART y tres equipos, un OVS de alta de cliente y un DVS que lo sostiene, ya alineados

Arquitectura

La aplicación entera vive en app/index.html: ~5 900 líneas, ~313 KB, tres bloques (sprite SVG + CSS + JS) y ninguna dependencia de terceros más allá de dos familias tipográficas servidas por Google Fonts.

Estructura del repositorio

index.html          Página de presentación del proyecto (bilingüe ES/EN)
app/index.html      La aplicación. Es el entregable

Ambos archivos son autónomos: cada uno abre con doble clic y funciona desde file://.

flowchart TD
    subgraph CAT["1 · Catálogo del framework"]
        C1["CONFIGS<br/>4 configuraciones"]
        C2["KINDS<br/>6 tipos de nodo:<br/>roles, artefactos, accepts/parent"]
        C3["FLOW<br/>6 métricas + predicado good()"]
    end

    subgraph CORE["3-4 · Estado y operaciones"]
        S["state<br/>config · root · selectedId<br/>doc · history · future"]
        OPS["addNode · deleteNode<br/>duplicateNode · moveNode<br/>patch · ensureHost"]
        H["snapshot / restore<br/>undo / redo"]
    end

    subgraph RULES["5 · Métricas y diagnóstico"]
        R1["rollup()"]
        R2["roleCoverage()"]
        R3["diagnose() → findings[]"]
        R4["healthScore()"]
    end

    subgraph VIEW["6-10 · Render"]
        V["render()"]
        V1["renderTree · renderPalette"]
        V2["renderInspector · renderOverview"]
        V3["renderStatus · renderLegend"]
    end

    subgraph IO["11 · Entrada / salida"]
        E1["buildExport() → JSON"]
        E2["buildSVG() → SVG / PNG"]
        E3["importJSON() → rehydrate()"]
    end

    CAT --> CORE
    CAT --> RULES
    OPS --> S
    S --> H
    S --> RULES
    RULES --> VIEW
    S --> VIEW
    V --> V1 & V2 & V3
    S --> IO
    E3 --> S
Loading

Mapa de módulos

El JavaScript está seccionado y numerado dentro del propio archivo, lo que hace que cualquier diff sea fácil de situar:

§ Sección Responsabilidad
1 Catálogo del framework CONFIGS, FLOW, KINDS, STREAMS, ASSIGN_ROLES, EXECUTORS, VIEWS, TEAM_TYPES, TEAM_METHODS, ORDER — todo el conocimiento de SAFe es data, no código
2 Utilidades $, $$, esc, uid, clamp, formateadores Intl
3 Fábricas y estado makeNode, makeStream, makeStep, makeSystem y el singleton state, con root (organización), flow y assignments como ramas independientes
4 Operaciones del modelo Alta, baja, duplicado, movimiento y parcheo, tanto de nodos como de streams y pasos; recorrido del árbol
5 Métricas y diagnóstico rollup, roleCoverage, analyzeStream, alignment, diagnose, healthParts / healthScore
6–10 Render Cabecera, paleta, lienzo de organización, lienzo de flujo, matriz de alineación, inspector, barra de estado y el render() maestro
11 Exportación buildExport (esquema 2.0), buildSVG para organigrama y flujo, exportJSON/SVG/PNG, importJSON, rehydrate
12–13 UI auxiliar y eventos Toasts, modales, menús contextuales, bind()
14 Configuración precargada seed() — el ejemplo de Essential SAFe con su flujo y sus asignaciones
16–18 Onboarding Los dos tours (TOURS), el asistente bifurcado (WIZ) y su cableado
19 Arranque seed(); bind(); render(); initOnboarding();

Decisiones de diseño

  • El catálogo de SAFe es data. Añadir un rol o un artefacto es editar un objeto literal en la sección 1, no tocar la lógica. El render, el diagnóstico, el export y el asistente lo derivan todo de ahí. Lo mismo vale para qué componentes pueden ejecutar qué pasos: es la tabla EXECUTORS, no una cadena de condicionales.
  • Flujo y organización no se contienen. state.root y state.flow son ramas hermanas, y state.assignments es la única que las relaciona. Cualquiera de las tres puede estar vacía sin romper a las otras dos, y por eso el Health Score sabe degradarse en lugar de puntuar cero.
  • Render completo, sin diffing. render() regenera el árbol y el inspector en cada cambio. Con blueprints de tamaño realista (decenas de nodos) el coste es despreciable y elimina toda una clase de bugs de sincronización. scrollMemo preserva la posición del lienzo entre renders.
  • Historial por serialización. snapshot() guarda un JSON.stringify del estado y restore() lo revierte. Simple y correcto por construcción.
  • Interpolación escapada. Todo el HTML se construye con plantillas de cadena y cualquier valor introducido por el usuario pasa por esc().
  • Estado en memoria. Lo único que se persiste en localStorage es una bandera (safe-blueprint-designer:onboarded) para no repetir el tour. El blueprint se guarda y recupera vía export/import JSON.

Requisitos del sistema

Ninguno más allá del navegador: no hay Node, ni gestor de paquetes, ni paso de compilación. Sí conviene saber qué APIs se dan por supuestas:

API / característica Uso Degradación
ES2020+ (??, ?., spread, Object.fromEntries) Todo el código Requiere navegador moderno
CSS Custom Properties, backdrop-filter, :focus-visible Sistema de temas y superficies Estética degradada, funcionalidad intacta
localStorage Bandera de onboarding Capturado en try/catch: funciona en modo privado
FileReader Importar JSON Sin alternativa
Blob + URL.createObjectURL Todas las descargas Sin alternativa
canvas.toBlob Export PNG Si falla, descarga el SVG automáticamente
Intl.NumberFormat (es-ES) Cifras y divisas Sin alternativa

Verificado en versiones recientes de Chrome, Edge, Firefox y Safari. Los paneles laterales se pliegan por debajo de 1180 px de ancho.


Instalación rápida

Opción 1 — no instalar nada

Abre la demo publicada. Nada sale de tu navegador.

Opción 2 — descargar el archivo

curl -O https://raw.githubusercontent.com/PacoCacheda/safe-org-blueprint-designer/main/app/index.html

Doble clic en index.html. Funciona desde file:// y sin conexión; sin red, las tipografías caen a las del sistema y nada más cambia.

Opción 3 — clonar el repositorio

git clone https://github.com/PacoCacheda/safe-org-blueprint-designer.git
cd safe-org-blueprint-designer

Ábrelo directamente, o levanta un servidor estático si prefieres trabajar sobre http:// (recomendado para contribuir, ver CONTRIBUTING.md):

# Cualquiera de estas sirve; ninguna instala nada permanente
python3 -m http.server 8080
npx --yes serve .          # npm
pnpm dlx serve .           # pnpm
bunx serve .               # bun

Nota deliberada: este proyecto no tiene package.json, ni node_modules, ni lockfile. Los comandos anteriores solo sirven ficheros estáticos; el proyecto sigue teniendo cero dependencias.


Uso

Por dónde empezar

La bienvenida ofrece cuatro puertas, y la primera no es casual:

Puerta Cuándo
Empezar por el flujo No sabes aún cómo debería organizarse. Describes los value streams y derivas los trenes de ahí
Empezar por la organización Ya tienes una estructura y quieres validarla, o contrastarla contra el flujo después
Cargar un blueprint Retomas un diseño existente desde su .json
Ver un tour Nueve pasos guiados. Hay uno para cada modelo, y el de organización termina ofreciendo el de flujo

Flujo típico, empezando por el valor

  1. Describe los value streams operativos: disparador, pasos, valor recibido. Marca los pasos que son retrabajo.
  2. Declara los sistemas que intervienen y los development value streams que los construyen.
  3. Deriva la organización, o móntala a mano desde la paleta. La configuración de SAFe (Essential, Large Solution, Portfolio o Full) decide qué niveles tienes disponibles.
  4. Ve a Alineación y marca quién ejecuta cada paso. Los handoffs aparecen solos.
  5. Rellena el detalle de cada nodo en el inspector: roles, tamaño, artefactos adoptados, presupuesto, métricas de Flow declaradas.
  6. Vigila el panel de diagnóstico: cada hallazgo enlaza al elemento que lo provoca.
  7. Exporta el blueprint en JSON para versionarlo, o como imagen para una presentación. El export vectorial sigue la vista activa: en Organización sale el organigrama, en Flujo y Alineación sale el diagrama de flujo.

Si prefieres el orden contrario, funciona igual: la rama de organización del asistente no destruye el modelo de flujo. Solo retira las asignaciones a nodos que dejan de existir, reintenta emparejar por nombre y te informa de ambas cosas.

Ejemplo: recorrer un blueprint exportado

El JSON es autodescriptivo y anidado, así que se procesa con cualquier lenguaje sin librería:

import { readFileSync } from 'node:fs';

const bp = JSON.parse(readFileSync('./banca-digital.json', 'utf8'));

// El resumen ya viene calculado por la aplicación
console.log(bp.summary.healthScore);            // 71
console.log(bp.summary.requiredRoleCoverage);   // "14/14 (100%)"
console.log(bp.summary.alignment.handoffs);     // 6

// Recorrido genérico del árbol
function* walk(node) {
  yield node;
  for (const child of node.children ?? []) yield* walk(child);
}

// Equipos fuera del rango de SAFe
for (const n of walk(bp.organization)) {
  if (n.type === 'team' && (n.size < 5 || n.size > 11)) {
    console.warn(`${n.name}: ${n.size} personas`);
  }
}

// Artefactos pendientes por ART, para alimentar un plan de adopción
for (const n of walk(bp.organization)) {
  if (n.type === 'art' && n.artifacts.pending.length) {
    console.log(`${n.name} → pendiente: ${n.artifacts.pending.join(', ')}`);
  }
}

Y los hallazgos del diagnóstico se convierten en incidencias de tu tracker sin transformación previa. Como cada uno lleva un rule estable, se pueden encaminar por familia:

const familia = f => f.rule.split('.')[0];   // 'org' | 'flow' | 'align'

bp.summary.findings
  .filter(f => f.severity === 'err')
  .forEach(f => console.error(`[${familia(f).toUpperCase()}] ${f.subject} — ${f.detail}`));

Ejemplo: encontrar dónde se pierde el tiempo

Los value streams traen su analítica calculada, así que localizar los peores es un sort:

const streams = [...bp.flow.operationalValueStreams,
                 ...bp.flow.developmentValueStreams];

streams
  .filter(s => s.analysis.handoffDensity > 0.5)
  .sort((a, b) => b.analysis.handoffDensity - a.analysis.handoffDensity)
  .forEach(s => console.log(
    `${s.name}: ${Math.round(s.analysis.handoffDensity * 100)}% de transiciones ` +
    `cambian de responsable (${s.analysis.handoffs} handoffs, ` +
    `${s.analysis.severeHandoffs} sobre retrabajo)`
  ));

// Pasos sin nadie que responda de ellos
streams.flatMap(s => s.steps.map(st => ({ stream: s.name, ...st })))
  .filter(st => !st.executors.some(e => e.role === 'owns'))
  .forEach(st => console.warn(`${st.stream} → «${st.name}» sin responsable`));

Ejemplo: comparar dos trimestres

Como el export es determinista salvo la marca de tiempo, dos blueprints se comparan directamente:

jq 'del(.blueprint.generated)' q1.json > /tmp/q1.norm.json
jq 'del(.blueprint.generated)' q2.json > /tmp/q2.norm.json
diff -u /tmp/q1.norm.json /tmp/q2.norm.json

O solo la evolución de los indicadores:

jq -r '"\(.blueprint.name): health=\(.summary.healthScore) equipos=\(.summary.agileTeams) hallazgos=\(.summary.findings | length)"' *.json

Ejemplo: extender el catálogo

Todo el conocimiento del marco vive en objetos literales. Para añadir un rol al ART basta una línea en la sección 1:

art: {
  label: 'Agile Release Train', level: 'Essential Level', /* … */
  accepts: ['team'], parent: 'valueStream', flowLabel: 'ART Flow',
  roles: [
    { key: 'rte',       label: 'Release Train Engineer (RTE)',   short: 'RTE',  req: true },
    { key: 'pm',        label: 'Product Management',             short: 'PM',   req: true },
    { key: 'sysArch',   label: 'System Architect / Engineering', short: 'SArq', req: true },
    { key: 'bizOwners', label: 'Business Owners',                short: 'BO',   req: true },
    { key: 'sysTeam',   label: 'System Team Lead',               short: 'ST',   req: false }  // ← nuevo
  ],
  artifacts: [ /* … */ ]
}

El inspector, el diagnóstico, el cálculo de cobertura, el asistente y el export lo recogen automáticamente. Si el rol se marca req: true, diagnose() empezará a exigirlo y el Health Score bajará hasta que se asigne.


Formato del blueprint

El export produce un documento versionado bajo $schema: "safe-org-blueprint/2.0" con ocho bloques de primer nivel:

Bloque Contenido
framework Procedencia: marco, versión, configuración activa y referencia
blueprint Metadatos: nombre, organización, divisa y marca de tiempo
summary Todo lo calculado: Health Score y su composición, recuentos, analítica de alineación y hallazgos
organization El árbol organizativo, desde el Portfolio hasta los equipos
flow Los value streams operativos y de desarrollo, con sus sistemas y sus pasos
assignments La matriz de alineación aplanada: qué componente ejecuta qué paso y con qué rol
observed Reservado para datos de ejecución reales. Hoy siempre available: false

Los tres modelos —organización, flujo y asignaciones— viajan separados, igual que en memoria. Un blueprint sin organización, o sin flujo, es un documento válido.

El resumen

{
  "$schema": "safe-org-blueprint/2.0",
  "framework": {
    "name": "Scaled Agile Framework",
    "version": "6.0",
    "configuration": "Essential SAFe",
    "reference": "https://framework.scaledagile.com/"
  },
  "blueprint": {
    "name": "Blueprint Essential SAFe — Banca Digital",
    "organization": "Mi Empresa",
    "currency": "EUR",
    "generated": "2026-08-07T12:01:10.644Z"
  },
  "summary": {
    "healthScore": 71,
    "healthComposition": { "roleCoverage": "30%", "structure": "35%", "alignment": "35%" },
    "scoreBasis": "Sólo puntúa lo que el diseño sostiene. Las seis métricas de Flow son declaradas y no puntúan.",
    "valueStreams": 1,
    "solutionTrains": 0,
    "agileReleaseTrains": 1,
    "agileTeams": 3,
    "suppliers": 0,
    "peopleInTrains": 24,
    "requiredRoleCoverage": "14/14 (100%)",
    "alignment": {
      "score": 68,
      "operationalValueStreams": 1,
      "developmentValueStreams": 1,
      "steps": 10,
      "handoffs": 6,
      "severeHandoffs": 2,
      "decisionGates": 1,
      "stepsWithSingleOwner": 10,
      "orphanSteps": 0,
      "ambiguousSteps": 0,
      "fragmentedStreams": 0,
      "idleComponents": 1,
      "executableComponents": 4,
      "derivedFrom": "topology-only"
    },
    "findings": [
      {
        "rule": "org.art.people",
        "severity": "warn",
        "subject": "Digital Banking ART: 24 personas",
        "detail": "El rango de referencia de un ART es de 50 a 125 personas (número de Dunbar)."
      },
      {
        "rule": "align.stream.reworkCross",
        "severity": "err",
        "subject": "Banca Digital: 2 retrabajo(s) cruzando frontera",
        "detail": "Volver atrás dentro del mismo equipo es fricción; volver atrás cambiando de responsable es cola con renegociación. Es el handoff más caro del sistema."
      }
    ]
  }
}

Cada hallazgo lleva un rule estable —org.*, flow.*, align.*— así que se puede filtrar por familia sin parsear el texto.

La organización

Un nodo del árbol, con sus hijos en children:

{
  "id": "nzqdbg5t",
  "type": "team",
  "safeLevel": "Team Level",
  "name": "Onboarding Digital",
  "code": "T-01",
  "roles": {
    "Product Owner": "Ana Gil",
    "Scrum Master / Team Coach": "Luis Marín"
  },
  "artifacts": {
    "adopted": ["Team Backlog", "Team PI Objectives", "Iteration Goals",
                "Definition of Done", "Iteration Review y Retrospective"],
    "pending": ["Prácticas de Built-in Quality"]
  },
  "flowMetrics": {
    "scope": "Team Flow",
    "provenance": "declared",
    "scored": false,
    "distribution": 68, "velocity": 23, "time": 21,
    "load": 12, "efficiency": 27, "predictability": 95,
    "observed": null
  },
  "size": 8,
  "teamType": "Stream-aligned",
  "method": "SAFe Scrum"
}

Los niveles superiores añaden lo suyo: leanBudget, investmentHorizons y capacityAllocation en Portfolio; allocatedBudget y streamType en Value Stream; piIterations, iterationWeeks y piWeeks en ART y Solution Train; contract en Supplier.

El flujo

Cada value stream trae sus sistemas, sus pasos con los ejecutores ya resueltos, y su analítica calculada:

{
  "operationalValueStreams": [
    {
      "id": "nti7sl1x",
      "type": "operationalValueStream",
      "name": "Alta de cliente digital",
      "code": "OVS-01",
      "trigger": "Una persona solicita hacerse cliente desde la app",
      "value": "Cuenta operativa con tarjeta activa",
      "systems": [
        { "id": "ni6brq9y", "name": "App móvil" },
        { "id": "narohk7x", "name": "Core bancario" }
      ],
      "steps": [
        {
          "id": "nc45gudw",
          "sequence": 1,
          "name": "Solicitud del cliente",
          "rework": false,
          "executors": [
            { "node": "nzqdbg5t", "nodeName": "Onboarding Digital",
              "role": "owns", "roleLabel": "Responsable" }
          ],
          "notes": null
        }
      ],
      "analysis": {
        "steps": 4,
        "handoffs": 2,
        "severeHandoffs": 0,
        "handoffDensity": 0.667,
        "decisionGates": 0,
        "stepsWithSingleOwner": 4,
        "orphanSteps": 0,
        "ambiguousSteps": 0,
        "artsInvolved": 1
      }
    }
  ],
  "developmentValueStreams": [ /* … además: "supports": [ids de OVS], pareja organizativa */ ]
}

Y las asignaciones, aplanadas, para quien prefiera reconstruir la matriz por su cuenta:

"assignments": [
  { "step": "nc45gudw", "node": "nzqdbg5t", "role": "owns",        "roleLabel": "Responsable" },
  { "step": "ndfw8cet", "node": "nnvpxhuk", "role": "owns",        "roleLabel": "Responsable" },
  { "step": "ndfw8cet", "node": "nzqdbg5t", "role": "contributes", "roleLabel": "Contribuye" }
]

La información está deliberadamente dos veces: dentro de cada paso como executors, para leer el documento sin cruzar índices, y aplanada en assignments, para procesarlo. Ambas se generan de la misma fuente.

Notas sobre el contrato

  • La raíz de organization es siempre un nodo portfolio, aunque la configuración activa sea Essential y el lienzo solo muestre el ART y sus equipos. El modelo mantiene la cadena jerárquica completa; la configuración controla qué se renderiza y qué se diagnostica, no qué se guarda.
  • El bloque summary describe el blueprint completo, no la parte visible: requiredRoleCoverage, alignment y findings recorren todo lo que hay.
  • Las métricas de Flow son declaradas. provenance: "declared" y scored: false lo dicen en el propio documento, y observed queda reservado para datos medidos. Ninguna herramienta que consuma este JSON debería tratarlas como medición.
  • Los roles se serializan por etiqueta legible, no por clave interna. rehydrate() acepta ambas formas al importar, así que un JSON escrito a mano con claves ("rte": "…") también funciona.
  • Los artefactos se parten en adopted / pending para que el documento sea legible sin consultar el catálogo. Al importar también se acepta un array plano o un objeto {artefacto: boolean}.
  • El presupuesto aparece como leanBudget en Portfolio y como allocatedBudget en Value Stream; el importador reconoce ambos y también un genérico budget.
  • La importación es tolerante por diseño: acepta la raíz en organization, en root o en el propio documento, completa con los valores por defecto de las fábricas todo lo que falte, y sigue leyendo documentos 1.0 — un blueprint de la versión anterior se abre sin flujo ni asignaciones, y el Health Score se degrada en consecuencia.

Esto permite versionar los diseños en Git, compararlos entre trimestres o generar informes con herramientas externas.


Personalización de marca

Todo el aspecto de la aplicación vive en custom properties. Un tema es un JSON externo que las redefine, junto con la marca y las tipografías, sin tocar el código ni mantener una copia bifurcada de la herramienta.

Cargar y quitar un tema

Se carga igual que un blueprint: desde Importar o arrastrando el .json a la ventana. El importador decide qué es cada fichero por su $schema, así que el mismo selector sirve para ambos. El tema aplicado se recuerda entre sesiones, y Ayuda → Restablecer tema devuelve el aspecto por defecto.

La carga es manual a propósito. La aplicación está pensada para abrirse con doble clic, y bajo el protocolo file:// los navegadores bloquean fetch, de modo que no puede leer un fichero suelto que esté junto a ella. Pedir el fichero al usuario es lo único que funciona en los dos escenarios, servida por HTTP y abierta en local.

Qué se acepta y qué se descarta

Un tema es un fichero de fuera, así que se sanea antes de aplicarlo:

Elemento Regla
Nombres de token Solo --nombre-valido; el resto se ignora
Valores de token Se descartan los que contengan <>{};@, javascript:, expression() o url() que no apunte a data:
Import de fuentes Solo una URL https://; cualquier otro esquema se descarta
Isotipo Únicamente datos de trazado SVG (paths), nunca markup
Textos de marca Se escapan e insertan como texto, con longitud limitada

Los descartes se anuncian en la consola, de forma que un tema mal escrito falla de manera visible y no en silencio.

Un matiz sobre las data: URI: aunque la regla de url() las permite, el punto y coma está en la lista de caracteres prohibidos, así que la forma habitual url(data:image/png;base64,…) también se descarta. En la práctica solo pasan las data: sin punto y coma, como url(data:image/svg+xml,…). Es una restricción conservadora: para incrustar un logotipo, la vía prevista es brand.mark con datos de trazado.

Auditoría de contraste

Al aplicar un tema se comprueban el texto, los acentos y los seis colores de nivel SAFe contra el fondo, en modo claro y oscuro. Si algún par no llega al 4,5:1 de WCAG 2.1 AA, la notificación lo indica y la consola detalla qué token y con qué ratio. Es informativa: nunca impide aplicar el tema.

Conviene leerla con criterio. El umbral de 4,5:1 corresponde a texto normal, y varios de los tokens auditados —los colores de nivel, los estados— se usan como acentos, bordes y distintivos, donde el criterio aplicable es el de 3:1 de elementos no textuales. La paleta por defecto ya arroja 12 avisos con esa vara de medir, así que un tema propio partirá de ese suelo: lo relevante no es el número absoluto sino si empeora los tokens que sí llevan texto encima.

Limitación conocida

El PNG exportado no hereda las webfonts remotas. Rasterizar un SVG sobre canvas no espera a que se descarguen las tipografías externas, así que la exportación usa la primera fuente local disponible de la pila. El SVG vectorial sí conserva la familia declarada. Si la marca es innegociable en el PNG, conviene incluir en --font-sans una alternativa local razonable.

Esquema del fichero

{
  "$schema": "safe-blueprint-theme/1",
  "name": "Nombre del tema",
  "defaultMode": "light",           // "light" | "dark" | omitido
  "brand": {
    "name": "Marca",                // opcional; se antepone al producto
    "product": "Nombre del producto",
    "sub": "Subtítulo de cabecera",
    "claim": "Frase de marca",      // aparece en el pie de la exportación
    "mark": {                       // isotipo: SOLO datos de trazado
      "viewBox": "0 0 24 24",
      "stroke": true,
      "strokeWidth": 3.4,
      "paths": ["M…"]
    }
  },
  "fonts": { "import": "https://…" },   // hoja de estilos de fuentes; solo https
  "tokens": {
    "root":  { "--font-sans": "…", "--r-md": "16px" },
    "light": { "--bg": "#F4F1E9", "--text": "#14101B" },
    "dark":  { "--bg": "#121018", "--text": "#F4F1E9" }
  }
}

tokens.root se aplica siempre; tokens.light y tokens.dark solo en su modo, lo que permite que los colores de nivel SAFe cambien entre uno y otro. La lista completa de tokens disponibles está comentada en el bloque :root de app/index.html, agrupada por tipografía, escala, forma, marca y capa decorativa.


Atajos de teclado

Atajo Acción
1 2 3 Cambiar a Organización, Flujo o Alineación
P Modo presentación: pliega los dos paneles laterales
[ · ] Plegar el panel izquierdo o el derecho por separado
Ctrl/⌘ + Z Deshacer
Ctrl/⌘ + Shift + Z · Ctrl/⌘ + Y Rehacer
Ctrl/⌘ + S Exportar blueprint como JSON
Supr · Retroceso Eliminar el elemento seleccionado
Esc Cerrar modal, menú o asistente
← → Navegar por el tour guiado

Los atajos de una sola tecla se ignoran mientras escribes en un campo.


Roadmap 2026

Prioridades ordenadas por impacto para quien llega nuevo al repositorio. Las propuestas se discuten en el issue tracker.

Trimestre Hito Detalle
Q3 2026 Capturas y carpeta docs/ Un lienzo con Full SAFe montado en el README; es lo que más ayuda a quien evalúa la herramienta en diez segundos
Q3 2026 Carpeta ejemplos/ Dos o tres blueprints JSON exportados (un Essential, un Full) para probar la importación sin construir nada
Q3 2026 Release v2.0.0 Etiqueta estable, .zip descargable y CHANGELOG con formato Keep a Changelog. La primera versión que cierra ya incluye el modelo de flujo y la matriz de alineación
Q4 2026 Persistencia local opcional Autoguardado en localStorage con recuperación de sesión, desactivable desde la interfaz
Q4 2026 Tipografías autoalojadas Eliminar la última petición de red externa (Google Fonts) y quedar 100% offline y sin terceros
Q4 2026 Internacionalización La interfaz está hoy solo en español; extraer las cadenas a un diccionario y publicar es / en
Q1 2027 Comparador de blueprints Cargar dos JSON y ver el delta estructural y de métricas entre trimestres dentro de la propia aplicación
Q1 2027 Export a PDF y PowerPoint El SVG ya se genera desde el estado; falta el empaquetado para comité
Continuo Accesibilidad Auditoría WCAG 2.1 AA: navegación completa por teclado del lienzo, roles ARIA en el árbol y contraste verificado en ambos temas
Continuo Fidelidad al marco Seguir las revisiones de SAFe y ajustar catálogo y guardrails

Contribuir

Las incidencias y propuestas son bienvenidas. Al ser un único archivo, cualquier cambio es un diff legible sobre app/index.html.

Antes de abrir un PR, lee CONTRIBUTING.md: explica el flujo de ramas, los estándares de código y la lista de verificación manual que sustituye a la suite de tests. La participación se rige por el Código de Conducta.


Aviso legal

SAFe®, Scaled Agile Framework® y los nombres de sus roles y artefactos son marcas registradas de Scaled Agile, Inc.

Este proyecto es una herramienta independiente creada con fines educativos y de diseño organizativo. No está afiliado, patrocinado ni respaldado por Scaled Agile, Inc., y no sustituye a la formación oficial ni a la documentación normativa del marco, disponible en framework.scaledagile.com.

Los rangos y guardrails implementados en el motor de diagnóstico son una interpretación de la orientación pública del marco y deben tomarse como apoyo a la conversación, no como norma.


Licencia

Distribuido bajo licencia MIT. © 2026 Francisco López.

About

Diseñador visual de estructuras organizativas bajo Scaled Agile Framework (SAFe 6.0). La aplicación es un único archivo HTML, sin dependencias ni build. · Visual designer for organizational structures under SAFe 6.0. A single HTML file, no dependencies, no build.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages