DashboardConfig

The JSON contract that drives a dashboard — fully serializable, validated with Zod. parseDashboardConfig() throws on an invalid shape; safeParseDashboardConfig() returns a result object instead.

Top level

ts
interface DashboardConfig {
  $schema?: string;
  version: string;
  settings: DashboardSettings;
  globalFilters: GlobalFilter[];
  calculatedFields: CalculatedField[];
  columnLabels: Record<string, string>;
  widgets: Widget[];
}

settings

ts
interface DashboardSettings {
  title: string;
  description?: string;
  layout: { columns: number; rowHeight: number; gutter: number; responsiveBreakpoints?: Record<string, number> };
  theme?: {
    mode?: 'light' | 'dark' | 'auto';
    primaryColor?: string;
    fontFamily?: string;
    borderRadius?: string;
    echartsTheme?: string | Record<string, unknown>;
  };
  numberFormat?: { locale?: string; currencySymbol?: string };
}

globalFilters

Date-range, multi/single-select, text, or number-range controls that any widget can bind to via dataQuery.filterRefIds.

ts
interface GlobalFilter {
  id: string;
  field: string;
  type: 'date_range' | 'multi_select' | 'single_select' | 'text' | 'number_range';
  label: string;
  defaultValue?: unknown;
}

calculatedFields

Derived columns computed per-row from a small, deliberately non-Turing-complete arithmetic grammar (+ - * / ( ), field references, numeric literals) — no eval.

ts
interface CalculatedField {
  id: string;
  label: string;
  formula: string; // e.g. "amount - previous_amount"
  format?: 'number' | 'currency' | 'percentage';
}

columnLabels

A dataset-wide display name per field (e.g. created_at → "Order Date"), used as the table header / chart axis / legend / tooltip label anywhere that field appears, across every widget. Set once in Settings instead of relabeling the same field everywhere.

dataQuery (on a widget)

ts
interface DataQuery {
  dimensions?: { field: string; granularity?: 'second'|'minute'|'hour'|'day'|'week'|'month'|'quarter'|'year' }[];
  metrics?: { field: string; aggregation: 'sum'|'avg'|'min'|'max'|'count'|'none'; alias?: string }[];
  sort?: { field: string; direction: 'asc' | 'desc' }[];
  pagination?: { pageSize: number };
  filterRefIds?: string[];
}

See Widgets & charts for each widget's renderConfig shape.