{
  "schema_version": 1,
  "diagram_type": "architecture",
  "meta": {
    "title": "Aplicación web de ejemplo",
    "output": "web-app-rendered.html",
    "quality_profile": "showcase",
    "views": [
      {
        "id": "request-path",
        "label": "Ruta principal de solicitud",
        "focus": [
          "users",
          "cdn",
          "lb",
          "api",
          "db"
        ],
        "note": "Sigue la solicitud principal del cliente desde el perímetro hasta los datos persistentes."
      },
      {
        "id": "identity-and-cache",
        "label": "Identidad y caché",
        "focus": [
          "auth",
          "api",
          "cache"
        ],
        "note": "Explora la autenticación y la caché de lectura junto a la ruta de solicitud."
      },
      {
        "id": "async-work",
        "label": "Contenido estático y trabajo asíncrono",
        "focus": [
          "cdn",
          "s3",
          "api",
          "queue",
          "worker"
        ],
        "note": "Consulta las dos rutas secundarias sin recargar la solicitud principal."
      }
    ],
    "locale": "es"
  },
  "components": [
    {
      "id": "users",
      "type": "external",
      "label": "Usuarios",
      "sublabel": "Navegador / móvil",
      "pos": [
        40,
        300
      ],
      "size": [
        120,
        60
      ]
    },
    {
      "id": "auth",
      "type": "security",
      "label": "Autenticación",
      "sublabel": "OAuth 2.0",
      "pos": [
        40,
        110
      ],
      "size": [
        120,
        64
      ],
      "tag": "JWT + PKCE"
    },
    {
      "id": "cdn",
      "type": "cloud",
      "label": "CloudFront",
      "sublabel": "CDN",
      "pos": [
        250,
        300
      ],
      "size": [
        130,
        60
      ]
    },
    {
      "id": "lb",
      "type": "cloud",
      "label": "Balanceador",
      "sublabel": "HTTPS :443",
      "pos": [
        460,
        300
      ],
      "size": [
        130,
        60
      ]
    },
    {
      "id": "api",
      "type": "backend",
      "label": "Servidor de API",
      "sublabel": "FastAPI :8000",
      "pos": [
        670,
        300
      ],
      "size": [
        130,
        60
      ]
    },
    {
      "id": "cache",
      "type": "database",
      "label": "Redis",
      "sublabel": "caché :6379",
      "pos": [
        670,
        150
      ],
      "size": [
        130,
        60
      ]
    },
    {
      "id": "db",
      "type": "database",
      "label": "PostgreSQL",
      "sublabel": "principal :5432",
      "pos": [
        880,
        300
      ],
      "size": [
        130,
        60
      ]
    },
    {
      "id": "s3",
      "type": "cloud",
      "label": "S3",
      "sublabel": "archivos estáticos",
      "pos": [
        250,
        440
      ],
      "size": [
        130,
        60
      ],
      "tag": "protegido con OAI"
    },
    {
      "id": "queue",
      "type": "messagebus",
      "label": "SQS",
      "sublabel": "cola de tareas",
      "pos": [
        670,
        440
      ],
      "size": [
        130,
        60
      ]
    },
    {
      "id": "worker",
      "type": "backend",
      "label": "Procesador",
      "sublabel": "tareas asíncronas",
      "pos": [
        880,
        440
      ],
      "size": [
        130,
        60
      ]
    }
  ],
  "boundaries": [
    {
      "kind": "region",
      "label": "Región AWS: us-west-2",
      "wraps": [
        "cdn",
        "lb",
        "api",
        "cache",
        "db",
        "s3",
        "queue",
        "worker"
      ]
    },
    {
      "kind": "security-group",
      "label": "sg-api :443/:8000",
      "wraps": [
        "lb",
        "api"
      ]
    }
  ],
  "connections": [
    {
      "id": "users-to-cdn",
      "from": "users",
      "to": "cdn",
      "label": "HTTPS",
      "variant": "emphasis"
    },
    {
      "id": "jwt-verification",
      "from": "auth",
      "to": "api",
      "label": "validar JWT",
      "variant": "security",
      "fromSide": "right",
      "toSide": "top",
      "via": [
        [
          620,
          142
        ],
        [
          620,
          246
        ],
        [
          735,
          246
        ]
      ]
    },
    {
      "id": "cdn-to-lb",
      "from": "cdn",
      "to": "lb"
    },
    {
      "id": "static-assets",
      "from": "cdn",
      "to": "s3",
      "label": "estático",
      "variant": "dashed",
      "fromSide": "bottom",
      "toSide": "top",
      "labelDy": 58
    },
    {
      "id": "lb-to-api",
      "from": "lb",
      "to": "api"
    },
    {
      "id": "cache-read-through",
      "from": "api",
      "to": "cache",
      "label": "lectura con caché",
      "fromSide": "top",
      "toSide": "bottom",
      "labelDy": -68
    },
    {
      "id": "api-sql",
      "from": "api",
      "to": "db",
      "label": "SQL"
    },
    {
      "id": "enqueue-job",
      "from": "api",
      "to": "queue",
      "label": "encolar",
      "variant": "dashed",
      "fromSide": "bottom",
      "toSide": "top",
      "labelDy": 58
    },
    {
      "id": "queue-to-worker",
      "from": "queue",
      "to": "worker"
    }
  ],
  "cards": [
    {
      "dot": "cyan",
      "title": "Perímetro",
      "items": [
        "La CDN CloudFront recibe todo el tráfico",
        "S3 sirve los archivos estáticos mediante OAI"
      ]
    },
    {
      "dot": "emerald",
      "title": "Aplicación",
      "items": [
        "FastAPI detrás de un balanceador HTTPS",
        "Caché Redis de lectura",
        "Un procesador ejecuta las tareas asíncronas de SQS"
      ]
    },
    {
      "dot": "rose",
      "title": "Seguridad",
      "items": [
        "OAuth 2.0 con JWT + PKCE",
        "API y balanceador aislados en un grupo de seguridad"
      ]
    }
  ]
}
