Core Components

Dashboards

Dashboard data model, mapping, persistence, and execution in Cortex.

Overview

Dashboards group multiple metric visualizations into structured views. Each dashboard belongs to a specific environment (environment_id) and contains views, sections, and widgets with visualization configurations and field mappings.

Key pieces:

  • Pydantic data models for dashboards, views, sections, widgets, and visualization configs
  • A single-table ORM with a JSON config column that stores nested dashboard configuration
  • CRUD services that read/write dashboards using CortexStorage().get_session()
  • An execution service that loads a dashboard and produces standardized chart data
  • A mapping layer that validates and transforms metric results for different visualization types

Core Pydantic models

Dashboard:

cortex/core/dashboards/dashboard.py
class Dashboard(TSModel):
    """
    Core dashboard definition that combines semantic metrics into a cohesive view.
    Each dashboard is tied to a specific environment and contains multiple views.
    Frontend handles all layout, theming, and visual presentation.
    """
    id: UUID = Field(default_factory=uuid4)
    alias: Optional[str] = None
    environment_id: UUID
    name: str
    description: Optional[str] = None
    type: DashboardType

    views: List["DashboardView"]
    default_view: str

    tags: Optional[List[str]] = None
    created_by: UUID
    created_at: datetime = Field(default_factory=lambda: datetime.now(pytz.UTC))
    updated_at: datetime = Field(default_factory=lambda: datetime.now(pytz.UTC))
    last_viewed_at: Optional[datetime] = None

View and Section:

cortex/core/dashboards/dashboard.py
class DashboardView(TSModel):
    """A specific view within a dashboard."""
    alias: str
    title: str
    description: Optional[str] = None
    sections: List["DashboardSection"]
    context_id: Optional[str] = None
    layout: Optional[DashboardLayout] = None
    created_at: datetime = Field(default_factory=lambda: datetime.now(pytz.UTC))
    updated_at: datetime = Field(default_factory=lambda: datetime.now(pytz.UTC))
cortex/core/dashboards/dashboard.py
class DashboardSection(TSModel):
    """Logical grouping of related widgets within a view."""
    alias: str
    title: Optional[str] = None
    description: Optional[str] = None
    position: int
    widgets: List["DashboardWidget"]

Widgets and visualization configuration:

cortex/core/dashboards/dashboard.py
class VisualizationConfig(TSModel):
    type: VisualizationType
    data_mapping: DataMapping
    chart_config: Optional[ChartConfig] = None
    table_config: Optional[TableConfig] = None
    single_value_config: Optional[SingleValueConfig] = None
    gauge_config: Optional[GaugeConfig] = None
    show_legend: bool = True
    show_grid: bool = True
    show_axes_labels: bool = True
    color_scheme: Optional[ColorScheme] = None
    custom_colors: Optional[List[str]] = None
cortex/core/dashboards/dashboard.py
class DashboardWidget(TSModel):
    """Individual metric widget with visualization."""
    alias: str
    section_alias: str
    metric_id: UUID
    position: int
    grid_config: WidgetGridConfig
    title: str
    description: Optional[str] = None
    visualization: VisualizationConfig
    metric_overrides: Optional[MetricExecutionOverrides] = None

Common visualization configs and helpers:

cortex/core/dashboards/dashboard.py
class WidgetGridConfig(TSModel):
    columns: int = 1
    rows: int = 1
    min_columns: Optional[int] = None
    min_rows: Optional[int] = None
cortex/core/dashboards/dashboard.py
class MetricExecutionOverrides(TSModel):
    context_id: Optional[str] = None
    filters: Optional[Dict[str, Any]] = None
    parameters: Optional[Dict[str, Any]] = None
    limit: Optional[int] = None
cortex/core/dashboards/dashboard.py
class ChartConfig(TSModel):
    show_points: bool = True
    line_width: int = 2
    bar_width: Optional[float] = None
    stack_bars: bool = False
    smooth_lines: bool = False
    area_stacking_type: Optional[Literal['normal', 'gradient']] = None
cortex/core/dashboards/dashboard.py
class TableConfig(TSModel):
    show_header: bool = True
    sortable: bool = True
    pagination: bool = True
    page_size: int = 10
    searchable: bool = False
cortex/core/dashboards/dashboard.py
class SingleValueConfig(TSModel):
    number_format: NumberFormat
    prefix: Optional[str] = None
    suffix: Optional[str] = None
    show_comparison: bool = True
    comparison_config: Optional[ComparisonConfig] = None
    show_trend: bool = True
    trend_period: Optional[str] = "previous_period"
    show_sparkline: bool = False
    show_title: bool = True
    show_description: bool = False
    compact_mode: bool = False
    selection_mode: ValueSelectionMode = ValueSelectionMode.FIRST
    selection_config: Optional[ValueSelectionConfig] = None
cortex/core/dashboards/dashboard.py
class GaugeConfig(TSModel):
    min_value: float = 0
    max_value: float = 100
    target_value: Optional[float] = None
    color_ranges: Optional[List[Dict[str, Any]]] = None
    show_value: bool = True
    show_target: bool = True
    gauge_type: str = "arc"
    thickness: int = 10
    selection_mode: ValueSelectionMode = ValueSelectionMode.FIRST
    selection_config: Optional[ValueSelectionConfig] = None

Data mapping layer

Widgets use VisualizationConfig.data_mapping to validate the fields expected by each visualization and to assist with transforming raw metric rows into chart-friendly shapes. The shared base mapping class:

cortex/core/dashboards/mapping/base.py
class DataMapping(TSModel):
    x_axis: Optional[FieldMapping] = None
    y_axes: Optional[List[FieldMapping]] = None
    value_field: Optional[FieldMapping] = None
    category_field: Optional[FieldMapping] = None
    series_field: Optional[FieldMapping] = None
    columns: Optional[List[ColumnMapping]] = None

    def get_all_fields(self) -> List[str]:
        ...

    def validate_against_result(self, result_columns: List[str]) -> None:
        ...

Supported visualizations are wired through a factory registry:

cortex/core/dashboards/mapping/factory.py
class MappingFactory:
    MAPPING_REGISTRY: Dict[VisualizationType, Type[VisualizationMapping]] = {
        VisualizationType.SINGLE_VALUE: SingleValueMapping,
        VisualizationType.BAR_CHART: ChartMapping,
        VisualizationType.LINE_CHART: ChartMapping,
        VisualizationType.AREA_CHART: ChartMapping,
        VisualizationType.PIE_CHART: ChartMapping,
        VisualizationType.DONUT_CHART: ChartMapping,
        VisualizationType.SCATTER_PLOT: ChartMapping,
        VisualizationType.TABLE: TableMapping,
        VisualizationType.GAUGE: GaugeMapping,
    }

Validation rules and transformations per type are implemented in mapping modules:

  • modules/single_value.py: uses x_axis as the value; supports selection and formatting
  • modules/chart.py: supports x/y series or category/value shapes; multiple series and stacking hints
  • modules/table.py: requires explicit column mappings and outputs table payloads
  • modules/gauge.py: uses x_axis as value; supports selection strategies and percentage within range

Persistence model (ORM)

Dashboards are stored in a single table with JSON configuration for nested structures:

cortex/core/dashboards/db/dashboard.py
class DashboardORM(BaseDBModel):
    __tablename__ = "dashboards"
    id = mapped_column(UUID, primary_key=True, index=True)
    environment_id = mapped_column(UUID, nullable=False, index=True)
    name = mapped_column(String(255), nullable=False, index=True)
    description = mapped_column(Text, nullable=True)
    type = mapped_column(String(50), nullable=False)
    default_view = mapped_column(String(255), nullable=False)
    tags = mapped_column(JSON, nullable=True)
    created_by = mapped_column(UUID, nullable=False)
    created_at = mapped_column(DateTime, default=datetime.now(pytz.UTC))
    updated_at = mapped_column(DateTime, default=datetime.now(pytz.UTC), onupdate=datetime.now(pytz.UTC))
    last_viewed_at = mapped_column(DateTime, nullable=True)
    config = mapped_column(JSON, nullable=False, default=dict)

CRUD utilities load/store dashboards and materialize the Pydantic model by merging config back into flat fields as needed:

cortex/core/dashboards/db/dashboard_service.py
class DashboardCRUD(TSModel):
    @staticmethod
    def get_dashboard_by_id(dashboard_id: UUID) -> Optional[Dashboard]:
        db_session = CortexStorage().get_session()
        try:
            db_dashboard = db_session.query(DashboardORM).filter(
                DashboardORM.id == dashboard_id
            ).first()
            if db_dashboard is None:
                return None
            dashboard_dict = db_dashboard.__dict__.copy()
            config = dashboard_dict.get('config') or {}
            for key in ('views',):
                if key in config:
                    dashboard_dict[key] = config[key]
            return Dashboard.model_validate(dashboard_dict, from_attributes=True)
        finally:
            db_session.close()

Execution and output format

The execution service loads a dashboard, resolves the target view by alias, executes each widget’s metric, and returns a standardized chart payload:

cortex/core/dashboards/execution.py
class DashboardExecutionService(TSModel):
    @staticmethod
    def execute_dashboard(dashboard_id: UUID, view_alias: Optional[str] = None) -> DashboardExecutionResult:
        start_time = time.time()
        try:
            dashboard = DashboardCRUD.get_dashboard_by_id(dashboard_id)
            if dashboard is None:
                raise DashboardDoesNotExistError(dashboard_id)
            target_view_alias = view_alias or dashboard.default_view
            target_view = None
            for view in dashboard.views:
                if view.alias == target_view_alias:
                    target_view = view
                    break
            if target_view is None:
                raise DashboardViewDoesNotExistError(target_view_alias)
            view_result = DashboardExecutionService.execute_view(dashboard_id, target_view_alias)
            total_time = (time.time() - start_time) * 1000
            return DashboardExecutionResult(
                dashboard_id=dashboard_id,
                view_id=target_view_alias,
                view_execution=view_result,
                total_execution_time_ms=total_time
            )
        except Exception as e:
            raise DashboardExecutionError(dashboard_id, str(e))

Standardized chart data structures are used as the canonical output for all visualizations:

cortex/core/dashboards/transformers.py
class ChartDataPoint(TSModel):
    x: Union[str, int, float]
    y: Union[int, float]
    label: Optional[str] = None
    category: Optional[str] = None
    metadata: Optional[Dict[str, Any]] = None

class ChartSeries(TSModel):
    name: str
    data: List[ChartDataPoint]
    type: Optional[str] = None
    color: Optional[str] = None
    metadata: Optional[Dict[str, Any]] = None
cortex/core/dashboards/transformers.py
class ProcessedChartData(TSModel):
    series: Optional[List[ChartSeries]] = None
    categories: Optional[List[CategoryData]] = None
    table: Optional[TableData] = None
    value: Optional[Union[int, float, str]] = None
    totals: Optional[Dict[str, float]] = None
    averages: Optional[Dict[str, float]] = None
    trends: Optional[List[TrendData]] = None
cortex/core/dashboards/transformers.py
class StandardChartData(TSModel):
    raw: Dict[str, Any]
    processed: ProcessedChartData
    metadata: ChartMetadata

Supported Visualization Types

Cortex supports 9 visualization types, each optimized for different data patterns and use cases.

Quick Reference

VisualizationBest ForData Structure
Single ValueKPIs, summary statsSingle number
GaugeProgress, performanceSingle number with range
Bar ChartComparisons, rankingsCategory + value
Line ChartTrends over timeTime + value
Area ChartCumulative trendsTime + value
Pie / DonutProportions, partsCategory + value
Scatter PlotCorrelations, patternsTwo numbers (x, y)
Box PlotDistributions, outliersCategory + numerical values
TableDetailed recordsMultiple columns

Single Value (KPI Card)

When to use:

  • Displaying a single key metric
  • Executive dashboards showing critical KPIs
  • Summary statistics that need immediate visibility

Data requirements:

  • Single numeric value from metric result
  • Works best with aggregations (SUM, COUNT, AVG, etc.)

Field mappings:

  • x_axis: The value field to display

Example:

{
    "visualization": {
        "type": "single_value",
        "data_mapping": {
            "x_axis": {
                "field": "total_revenue",
                "label": "Total Revenue",
                "format": {
                    "number_format": "currency",
                    "prefix": "$"
                }
            }
        },
        "single_value_config": {
            "show_comparison": true,
            "show_sparkline": true
        }
    }
}

Gauge

When to use:

  • Showing progress toward a goal
  • Displaying percentage completion
  • Performance indicators with targets

Data requirements:

  • Single numeric value within a min/max range
  • Optional target value

Field mappings:

  • x_axis: The value field
  • Configure min_value, max_value, and optional target_value

Example:

{
    "visualization": {
        "type": "gauge",
        "data_mapping": {
            "x_axis": {
                "field": "completion_rate",
                "label": "Project Completion"
            }
        },
        "gauge_config": {
            "min_value": 0,
            "max_value": 100,
            "target_value": 75
        }
    }
}

Bar Chart

When to use:

  • Comparing values across categories
  • Ranking items (top customers, products, etc.)
  • Showing categorical distributions

Data requirements:

  • Categorical x-axis (category)
  • Numeric y-axis (value)

Field mappings:

  • x_axis: Category field
  • y_axes: Value field(s) - can have multiple series

Example:

{
    "visualization": {
        "type": "bar_chart",
        "data_mapping": {
            "x_axis": {
                "field": "product_category",
                "label": "Product Category"
            },
            "y_axes": [{
                "field": "revenue",
                "label": "Revenue"
            }]
        },
        "chart_config": {
            "stack_bars": false,
            "bar_width": 0.6
        }
    }
}

Line Chart

When to use:

  • Showing trends over time
  • Tracking metrics over continuous periods
  • Comparing multiple series over time

Data requirements:

  • Time series or continuous x-axis
  • Numeric y-axis values

Field mappings:

  • x_axis: Time or continuous field
  • y_axes: Value field(s)
  • Optional series_field: For multiple lines

Example:

{
    "visualization": {
        "type": "line_chart",
        "data_mapping": {
            "x_axis": {
                "field": "date",
                "label": "Date"
            },
            "y_axes": [{
                "field": "revenue",
                "label": "Revenue"
            }]
        },
        "chart_config": {
            "show_points": true,
            "line_width": 2
        }
    }
}

Area Chart

When to use:

  • Emphasizing the magnitude of change
  • Showing cumulative values
  • Volume and cumulative trends

Data requirements:

  • Time or continuous x-axis
  • Numeric y-axis values

Field mappings:

  • x_axis: Time field
  • y_axes: Value field(s)

Example:

{
    "visualization": {
        "type": "area_chart",
        "data_mapping": {
            "x_axis": {
                "field": "month",
                "label": "Month"
            },
            "y_axes": [{
                "field": "cumulative_revenue",
                "label": "Cumulative Revenue"
            }]
        },
        "chart_config": {
            "area_stacking_type": "normal"
        }
    }
}

Pie Chart / Donut Chart

When to use:

  • Showing part-to-whole relationships
  • Displaying proportions or percentages
  • Small categorical breakdowns (5-7 categories max)

Best practices:

  • Use when values represent parts of a whole
  • Limit to 5-7 categories for readability
  • Don't use for trends over time

Data requirements:

  • Category field
  • Value field (should sum meaningfully)

Field mappings:

  • category_field: Category names
  • value_field: Values

Example:

{
    "visualization": {
        "type": "pie_chart",
        "data_mapping": {
            "category_field": {
                "field": "product_category",
                "label": "Category"
            },
            "value_field": {
                "field": "revenue",
                "label": "Revenue"
            }
        }
    }
}

Scatter Plot

When to use:

  • Showing correlation between two variables
  • Detecting patterns in data
  • Analyzing relationships between metrics

Data requirements:

  • Two numerical variables

Field mappings:

  • x_axis: First numerical variable
  • y_axes: Second numerical variable

Example:

{
    "visualization": {
        "type": "scatter_plot",
        "data_mapping": {
            "x_axis": {
                "field": "price",
                "label": "Price"
            },
            "y_axes": [{
                "field": "quantity_sold",
                "label": "Quantity Sold"
            }]
        }
    }
}

Box Plot

When to use:

  • Displaying data distribution
  • Identifying outliers
  • Comparing statistical distributions across categories
  • Showing quartiles and medians

Data requirements:

  • Categorical x-axis (groups)
  • Numerical y-axis (values to analyze)

Field mappings:

  • x_axis: Category field
  • y_axes: Numerical value field

What it shows:

  • Min: Minimum value
  • Q1: First quartile (25th percentile)
  • Median: Middle value (50th percentile)
  • Q3: Third quartile (75th percentile)
  • Max: Maximum value
  • Outliers: Points beyond 1.5 * IQR

Example:

{
    "visualization": {
        "type": "box_plot",
        "data_mapping": {
            "x_axis": {
                "field": "region",
                "label": "Sales Region"
            },
            "y_axes": [{
                "field": "sales_amount",
                "label": "Sales Amount"
            }]
        }
    }
}

Table

When to use:

  • Showing detailed records
  • Displaying multiple attributes
  • Tabular data exploration
  • Export-ready data presentation

Data requirements:

  • Any structured data with columns
  • Multiple fields to display

Field mappings:

  • columns: Array of column definitions

Example:

{
    "visualization": {
        "type": "table",
        "data_mapping": {
            "columns": [
                {
                    "field": "customer_name",
                    "label": "Customer Name",
                    "width": 200,
                    "sortable": true
                },
                {
                    "field": "order_date",
                    "label": "Order Date",
                    "width": 150,
                    "format": {
                        "date_format": "YYYY-MM-DD"
                    }
                },
                {
                    "field": "order_total",
                    "label": "Order Total",
                    "width": 120,
                    "format": {
                        "number_format": "currency"
                    }
                }
            ]
        },
        "table_config": {
            "sortable": true,
            "pagination": true,
            "page_size": 25
        }
    }
}

Notes and best practices

  • Always set environment_id on dashboards to ensure the correct environment scoping.
  • Use alias on dashboards and views for stable referencing from the UI.
  • Visualization configs should include explicit field mappings; mappings validate against metric result columns.
  • For tables, provide explicit column mappings in VisualizationConfig.data_mapping.columns.
  • Persist and update the entire nested configuration through DashboardCRUD (JSON config field).