{
  "version": "xarts.graph-relations/1",
  "family": "graph-relations",
  "operation": "architecture-boundaries",
  "provenance": {
    "legacyId": "concept-c4"
  },
  "data": {
    "elements": [
      {
        "id": "e1",
        "label": "Viajero",
        "kind": "person",
        "row": 0,
        "column": 0,
        "technology": "",
        "description": "Reserva sin estar registrado",
        "boundary": null,
        "role": "neutral"
      },
      {
        "id": "e2",
        "label": "Socio del programa",
        "kind": "person",
        "row": 3,
        "column": 0,
        "technology": "",
        "description": "Reserva y canjea puntos desde el móvil",
        "boundary": null,
        "role": "neutral"
      },
      {
        "id": "e3",
        "label": "Web de reserva",
        "kind": "container",
        "row": 0,
        "column": 1,
        "technology": "Next.js 14 · SSR",
        "description": "Buscador, ficha de hotel y pago",
        "boundary": "b1",
        "role": "neutral"
      },
      {
        "id": "e4",
        "label": "API de disponibilidad",
        "kind": "container",
        "row": 1,
        "column": 1,
        "technology": "Node 20 · Fastify",
        "description": "La puerta declarada al cupo y a la tarifa",
        "boundary": "b1",
        "role": "focus"
      },
      {
        "id": "e5",
        "label": "Caché de tarifas",
        "kind": "store",
        "row": 2,
        "column": 1,
        "technology": "Redis 7",
        "description": "Tarifa por hotel y noche, 90 s de vida",
        "boundary": "b1",
        "role": "neutral"
      },
      {
        "id": "e6",
        "label": "App de fidelización",
        "kind": "container",
        "row": 3,
        "column": 1,
        "technology": "React Native",
        "description": "Reserva y canje de puntos de los socios",
        "boundary": "b1",
        "role": "neutral"
      },
      {
        "id": "e7",
        "label": "Pasarela de pago",
        "kind": "system",
        "row": 0,
        "column": 2,
        "technology": "Redsys",
        "description": "Cobro con tarjeta y devoluciones",
        "boundary": null,
        "role": "neutral"
      },
      {
        "id": "e8",
        "label": "PMS del hotel",
        "kind": "system",
        "row": 2,
        "column": 2,
        "technology": "Oracle OPERA",
        "description": "Cupo, tarifa y estado de cada reserva",
        "boundary": null,
        "role": "neutral"
      }
    ],
    "boundaries": [
      {
        "id": "b1",
        "label": "Motor de reserva",
        "kind": "system"
      }
    ],
    "relationships": [
      {
        "id": "r1",
        "label": "Busca y reserva",
        "source": "e1",
        "target": "e3",
        "technology": "HTTPS",
        "offset": 0,
        "role": "neutral"
      },
      {
        "id": "r2",
        "label": "Cobra la reserva",
        "source": "e3",
        "target": "e7",
        "technology": "HTTPS",
        "offset": 0,
        "role": "neutral"
      },
      {
        "id": "r3",
        "label": "Pide cupo y tarifa",
        "source": "e3",
        "target": "e4",
        "technology": "JSON/HTTPS",
        "offset": 0,
        "role": "neutral"
      },
      {
        "id": "r4",
        "label": "Lee y refresca",
        "source": "e4",
        "target": "e5",
        "technology": "RESP",
        "offset": 0,
        "role": "neutral"
      },
      {
        "id": "r5",
        "label": "Consulta cupo",
        "source": "e4",
        "target": "e8",
        "technology": "SOAP",
        "offset": 0,
        "role": "neutral"
      },
      {
        "id": "r6",
        "label": "Consulta cupo sin API",
        "source": "e6",
        "target": "e8",
        "technology": "SOAP",
        "offset": 0,
        "role": "warning"
      },
      {
        "id": "r7",
        "label": "Canjea puntos",
        "source": "e2",
        "target": "e6",
        "technology": "HTTPS",
        "offset": 0,
        "role": "neutral"
      }
    ]
  },
  "relationship": {
    "kind": "software-architecture-dependencies",
    "level": "container",
    "assertionStatus": "authored-unverified",
    "boundaries": "explicit-flat-membership",
    "direction": "declared-source-to-target",
    "timeEncoding": "none",
    "trafficEncoding": "none",
    "deploymentStatus": "not-inferred"
  },
  "typography": {
    "body": {
      "size": 19,
      "weight": 700,
      "lineHeight": 27
    },
    "note": {
      "size": 16,
      "weight": 400,
      "lineHeight": 24
    },
    "stamp": {
      "size": 14,
      "weight": 700,
      "lineHeight": 22
    },
    "title": {
      "size": 22,
      "weight": 700,
      "lineHeight": 32
    }
  },
  "fontFamily": "'Inter', system-ui, -apple-system, sans-serif",
  "measurement": {
    "exportText": "glyph-advances"
  },
  "paints": {
    "neutral": {
      "fill": "surface",
      "stroke": "textSecondary",
      "text": "textPrimary",
      "dash": ""
    },
    "focus": {
      "fill": "series.blue",
      "stroke": "series.blue",
      "text": "surface",
      "dash": ""
    },
    "warning": {
      "fill": "surface",
      "stroke": "negative",
      "text": "negative",
      "dash": ""
    },
    "absent": {
      "fill": "none",
      "stroke": "textMuted",
      "text": "textMuted",
      "dash": "6 4"
    },
    "favorable": {
      "fill": "surfaceAlt",
      "stroke": "series.teal",
      "text": "textPrimary",
      "dash": ""
    }
  },
  "layout": {
    "margin": {
      "top": 24,
      "right": 24,
      "bottom": 24,
      "left": 24
    },
    "grid": 8,
    "rowGap": 56,
    "columnGap": 56,
    "maximumColumnGap": 152,
    "minimumElementWidth": 120,
    "boundaryPadding": 14,
    "boundaryLabelHeight": 26,
    "padding": {
      "x": 14,
      "y": 12
    },
    "maximumNameLines": 2,
    "maximumDescriptionLines": 2,
    "anchorGap": 20,
    "minimumRotatedSegment": 96,
    "longSegmentThreshold": 240,
    "longSegmentFraction": 0.34,
    "textOverflow": "whole-words",
    "placement": "boundary-records"
  },
  "marks": {
    "drawBoundaries": true,
    "boxRadius": 4,
    "personHeadHeight": 24,
    "storeCapRadius": 10,
    "containerBandWidth": 8,
    "codeFold": 16,
    "componentTab": {
      "width": 16,
      "height": 12
    },
    "systemRadius": 16,
    "silhouetteOpacity": 0.14,
    "thin": 1.25,
    "medium": 2,
    "thick": 4,
    "connector": "textSecondary",
    "boundaryBorder": "textSecondary",
    "boundaryText": "textMuted",
    "arrowLength": 9,
    "arrowHeight": 8
  },
  "labels": {
    "modelNotice": "Arquitectura declarada, sin despliegue ni tráfico acreditados. El nivel deriva de los tipos; los límites expresan pertenencia al sistema o contenedor indicado. La posición, tamaño y longitud de las relaciones no codifican tiempo ni volumen. Las relaciones conservan su origen, destino, propósito y tecnología; no se infiere una secuencia de ejecución.",
    "showModelNotice": true
  },
  "annotations": {
    "band": {
      "text": "ninguna flecha dice cuánto tráfico lleva: este mapa es de estructura",
      "role": "absent"
    },
    "verdict": "La app se salta la API: su cupo no pasa por la caché.",
    "bandHeight": 48,
    "verdictHeight": 48,
    "noteColor": "textMuted",
    "verdictColor": "accent",
    "separatorOpacity": 0.5
  },
  "document": {
    "textOverflow": "preserve",
    "header": {
      "title": "La app pide cupo al PMS por fuera de la única API que lo cachea",
      "subtitle": "Mapa de contenedores del motor de reserva directa de un grupo hotelero: seis de las siete llamadas pasan por la API de disponibilidad y la séptima, la del móvil, va directa al PMS y se salta la caché de 90 segundos"
    },
    "footer": {
      "source": "xarts · ejemplo de demostración",
      "notes": "Esquema ilustrativo para explorar la forma y sustituirlo por el propio."
    },
    "spacing": {
      "horizontalPadding": 24,
      "topPadding": 22,
      "bottomPadding": 16,
      "minimumTextGap": 4
    }
  },
  "presentation": {
    "theme": "anlak",
    "dimensions": {
      "width": 940,
      "height": 2746
    },
    "locale": "es-ES",
    "fonts": "reference",
    "surface": "theme",
    "framePadding": 24
  },
  "output": {
    "filename": "concept-c4",
    "embedSpec": true,
    "geometryDecimals": 2
  }
}
