{# Schema-discovery ERD section: legend, toolbar, interactive Cytoscape canvas with a static-SVG fallback, and the JSON data island powering both. #} {# Card-internal styles. Emitted once for the fallback SVG on the page and inlined into every standalone card SVG (SVG-as-image cannot see page CSS). #} {% set erd_card_css %} .schema-node { fill: #fff; stroke: #b7c9c2; stroke-width: 1.4; } .schema-node-header { fill: #123d32; } .schema-node-header.is-hub { fill: #0d5f4a; } .schema-node-header-rule { fill: #0d7a5f; } .schema-node-icon { stroke: #9de0ca; stroke-width: 1.4; fill: none; } .schema-node-title { fill: #fff; font-size: 15px; font-weight: 800; letter-spacing: -.01em; } .schema-node-meta { fill: #b9d8ce; font-size: 10.5px; } .schema-role { fill: #cfeee2; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; } .schema-section-label { fill: #7a8984; font-size: 9.5px; font-weight: 800; letter-spacing: .09em; } .schema-row-rule { stroke: #e5ece9; stroke-width: 1; } .schema-row-label { fill: #23312c; font-size: 11.5px; font-weight: 700; } .schema-row-detail { fill: #71817b; font-size: 10px; } .schema-key-badge { stroke-width: 1; } .schema-key-badge.pk { fill: #dff4ed; stroke: #b9e3d5; } .schema-key-badge.fk { fill: #e8f0f6; stroke: #cbdce8; } .schema-key-badge-text { font-size: 9px; font-weight: 850; text-anchor: middle; } .schema-key-badge-text.pk { fill: #07624b; } .schema-key-badge-text.fk { fill: #345b74; } .schema-empty-state { fill: #7a8984; font-size: 10.5px; } .schema-more { fill: #0d5f4a; font-size: 10.5px; font-weight: 700; } {% endset %} {# One table card drawn at local (0,0). Reused by the fallback SVG (wrapped in a translate group) and by card_svg() below for the Cytoscape node image. #} {% macro table_card(node) %} {{ node.display_table }} {{ node.row_count | format_value }} rows · {{ node.column_count }} columns {{ node.role }}{% if node.role in ['hub', 'dimension'] and node.referenced_by %} · ref {{ node.referenced_by }}{% elif node.references %} · refs {{ node.references }}{% endif %} INFERRED KEY ROLES {% if node.rows %} {% for row in node.rows %} {{ row.kind }} · {{ row.full_label }} · {{ row.detail }} {% if not loop.first %}{% endif %} {{ row.kind }} {{ row.label }} {{ row.detail }} {% endfor %} {% else %} No candidate key roles met the evidence threshold {% endif %} {% if node.overflow_count %} + {{ node.overflow_count }} more — show all {% endif %} {% endmacro %} {# Standalone SVG document for one card, used as a Cytoscape node image. #} {% macro card_svg(node) -%} {{ table_card(node) }} {%- endmacro %}
{{ sections.number('erd') }}

{{ artifact.title }}

Evidence-backed candidates, not declared constraints. Scroll to zoom, drag the canvas to pan, drag a table to rearrange, click a table to focus its relationships; toggle tables to declutter.

Keys PK candidate primary key FK inferred foreign key Table roles hub dimension fact junction Confidence high medium low Cardinality 1 exactly one (parent side) N can match many (child side)
{% set nodes_by_importance = artifact.data.nodes | sort(attribute='referenced_by', reverse=true) %}
{% for node in nodes_by_importance[:12] %} {{ node.role }} {{ node.display_table }}{% if node.referenced_by %} · ref by {{ node.referenced_by }}{% endif %} {% endfor %}
Tables
{% for node in artifact.data.nodes %} {% endfor %}
{% for edge in artifact.data.edges %} {{ edge.child_table }}.{{ edge.child_columns | join(' + ') }} → {{ edge.parent_table }}.{{ edge.parent_columns | join(' + ') }} · {{ edge.cardinality | replace('_', '–') }} · {{ "%.0f%%" | format(edge.confidence * 100) }} confidence (inclusion {{ "%.0f%%" | format(edge.inclusion_rate * 100) }}, name match {{ "%.0f%%" | format(edge.name_similarity * 100) }}, type {{ "%.0f%%" | format(edge.type_compatibility * 100) }}) {% for mark in edge.source_marks %} {% endfor %} {% for mark in edge.target_marks %} {% endfor %} {% endfor %} {% for node in artifact.data.nodes %} {{ node.table }} · {{ node.row_count }} rows · {{ node.column_count }} columns · role: {{ node.role }}{% if node.referenced_by %} (referenced by {{ node.referenced_by }}){% endif %} {{ table_card(node) }} {% endfor %}
Drag tables to rearrange · click a table to focus · click empty space to reset
{% if cytoscape_js %} {% endif %} {% include "_erd_cytoscape.html" %} {% include "_erd_fallback.html" %}