{
  "schemaVersion": "1.0",
  "id": "api-dependency-map",
  "title": "API dependency map from OpenAPI specs",
  "slug": "api-dependency-map",
  "diagramFamily": "architecture",
  "goal": "Maintain a current diagram of which services expose, consume, and depend on which APIs by parsing OpenAPI specs and SDK imports across the repository, then patching the persisted Zindex scene each time a service ships.",
  "inputs": [
    "Glob of OpenAPI spec files in the monorepo (e.g. services/*/openapi.yaml)",
    "Glob of source files that import generated SDKs (used to derive consumer→provider edges)",
    "Existing Zindex scene id (stored as a repo secret)",
    "Zindex API key with scene-write scope"
  ],
  "outputs": [
    "Updated persisted scene with one node per service and one edge per cross-service call",
    "Rendered SVG showing the current API topology",
    "Revision diff highlighting newly added consumers / providers since the last run",
    "Optional: PR comment when the topology changes meaningfully (new service added, edge removed)"
  ],
  "mcpTools": [
    "dsp_create_scene",
    "dsp_apply_ops",
    "dsp_validate_scene",
    "dsp_render_scene"
  ],
  "httpEndpoints": [
    "POST /v1/scenes",
    "POST /v1/scenes/:id/applyOps",
    "POST /v1/scenes/:id/render"
  ],
  "steps": [
    {
      "id": "create_or_fetch_scene",
      "label": "Create or fetch the persisted scene",
      "description": "On first run, create a scene with hierarchical LR layoutStrategy. On subsequent runs, fetch the existing scene by id to read the current revision and elements.",
      "mcp": "dsp_create_scene",
      "http": {
        "method": "POST",
        "path": "/v1/scenes",
        "exampleResponse": "{ \"sceneId\": \"sc_api_topo\", \"revision\": 1 }"
      }
    },
    {
      "id": "parse_specs",
      "label": "Parse OpenAPI specs",
      "description": "Walk every services/*/openapi.yaml in the monorepo. Each spec becomes a service node; emit operationIds + paths so they can later become edge labels (e.g. 'POST /v1/login'). Do not parse free-text README links - the spec is the source of truth.",
      "mcp": null,
      "http": null
    },
    {
      "id": "derive_consumers",
      "label": "Derive consumer→provider edges",
      "description": "Scan source files for imports of generated SDKs (e.g. `import { usersClient } from '@acme/sdk-users'`). Each import is evidence that the importing service consumes the imported API. Map the SDK package name back to the spec → an edge from consumer to provider, labeled with the most-frequently-called operationId.",
      "mcp": null,
      "http": null
    },
    {
      "id": "diff_against_scene",
      "label": "Diff parsed topology against the persisted scene",
      "description": "Compare the parsed (services, edges) tuple to what's currently in the scene. New services become createNode ops; removed services become deleteElement ops; changed labels become updateEdge ops. Always reuse stable element ids (the service name) so a renamed label stays on the same edge.",
      "mcp": "dsp_get_scene",
      "http": {
        "method": "GET",
        "path": "/v1/scenes/${SCENE_ID}",
        "exampleResponse": "{ \"sceneId\": \"sc_api_topo\", \"revision\": 47, \"elements\": [\"...\"] }"
      }
    },
    {
      "id": "apply_ops",
      "label": "Apply the operation batch",
      "description": "Send the diff as one applyOps batch with errorPolicy=allOrNothing. Reuse stable element ids - `users_api`, `orders_api`, `e_orders_users` - so renames update the existing element rather than create a duplicate.",
      "mcp": "dsp_apply_ops",
      "http": {
        "method": "POST",
        "path": "/v1/scenes/${SCENE_ID}/ops",
        "exampleResponse": "{ \"sceneId\": \"sc_api_topo\", \"revision\": 48, \"applied\": 6 }"
      }
    },
    {
      "id": "validate",
      "label": "Validate the new revision",
      "description": "Confirm the topology is still valid: every edge endpoint resolves to a node, no duplicate edges between the same pair without distinct labels.",
      "mcp": "dsp_validate_scene",
      "http": {
        "method": "POST",
        "path": "/v1/scenes/validate"
      }
    },
    {
      "id": "render",
      "label": "Render the updated diagram",
      "description": "Render to SVG. The hierarchical LR layout naturally separates clients (left), gateway (centre), and provider APIs (right); cloud-icon services render icon-only and read cleanly inside the layout.",
      "mcp": "dsp_render_scene",
      "http": {
        "method": "POST",
        "path": "/v1/scenes/${SCENE_ID}/render",
        "exampleRequest": "{ \"format\": \"svg\", \"theme\": \"clean\" }"
      }
    },
    {
      "id": "publish",
      "label": "Publish the rendered SVG to the docs site",
      "description": "Upload the rendered SVG to the docs site (or commit to the repo's docs/ directory). Optionally, when the topology diff contains added or removed services, post a Slack message to the platform channel so the team is aware of the new dependency.",
      "mcp": null,
      "http": null
    }
  ]
}