OSS-first docs

These docs teach the open system first: contracts, generated surfaces, runtimes, governance, and incremental adoption. Studio shows up as the operating layer on top, not as the source of truth.

AI index

DataViews

A

DataViewSpec

describes how data should be queried, filtered, sorted, and presented to users. Runtime adapters execute optimized database queries and serve list views, detail views, and search interfaces while respecting policy constraints.

Core concepts

Data sources

A DataView connects to one or more data sources—databases, APIs, or other capabilities. You specify the source and the fields you want to expose.

Filtering

Define filters that users can apply to narrow down results. Filters are typed as search, enum, number, percent, currency, date, time, datetime, duration, or boolean so renderers and query helpers can validate values before execution.

Sorting

Specify which fields can be sorted and the default sort order. ContractSpec generates efficient database queries with proper indexes.

Pagination

DataViews automatically support pagination to handle large datasets. You can configure page size limits and cursor-based or offset-based pagination.

Collection modes and data depth

List, grid, and table views can share a single view.collection contract. It declares allowed view modes, toolbar controls, page-size defaults, density, data depth, and persistence hints. Fields can use visibility.minDataDepth so summary views stay light while detailed views expose richer context.

Personalization hints

The contract layer stays neutral: it can opt into persistence with view.collection.personalization, but it does not import the personalization runtime. Host apps resolve preferences and behavior insights into renderer props.

Example DataViewSpec

Here is the canonical table contract used by the live

Data Grid Showcase

:

import { defineDataView } from '@lssm-tech/lib.contracts-spec/data-views';
import { defineTranslation } from '@lssm-tech/lib.contracts-spec/translations';
import { ListDataGridShowcaseRowsQuery } from '@lssm-tech/example.data-grid-showcase/contracts/data-grid-showcase.operation';

const bundle = defineTranslation({
  meta: { key: 'examples.data-grid-showcase.table', version: '1.0.0', domain: 'examples', owners: ['@platform.core'] },
  locale: 'en',
  messages: {
    'Account': { value: 'Account' }, 'Owner': { value: 'Owner' }, 'Status': { value: 'Status' },
    'ARR': { value: 'ARR' }, 'Health score': { value: 'Health score' },
    'Last activity': { value: 'Last activity' }, 'Notes': { value: 'Notes' },
  },
});

export const DataGridShowcaseDataView = defineDataView(bundle, {
  meta: {
    key: 'examples.data-grid-showcase.table',
    version: '1.0.0',
    entity: 'account',
    title: 'Data Grid Showcase Table',
    description:
      'Declarative DataViewSpec for the ContractSpec table showcase.',
    domain: 'examples',
    owners: ['@platform.core'],
    tags: ['examples', 'table', 'data-grid'],
    stability: 'experimental',
  },
  source: {
    primary: {
      key: ListDataGridShowcaseRowsQuery.meta.key,
      version: ListDataGridShowcaseRowsQuery.meta.version,
    },
  },
  view: {
    kind: 'table',
    executionMode: 'client',
    selection: 'multiple',
    columnVisibility: true,
    columnResizing: true,
    columnPinning: true,
    rowExpansion: {
      fields: ['notes', 'renewalDate', 'lastActivityAt'],
    },
    initialState: {
      pageSize: 4,
      hiddenColumns: ['notes'],
      pinnedColumns: {
        left: ['account'],
      },
      sorting: [{ field: 'arr', desc: true }],
    },
    fields: [
      { key: 'account', label: 'Account', dataPath: 'account', sortable: true },
      { key: 'owner', label: 'Owner', dataPath: 'owner', sortable: true },
      { key: 'status', label: 'Status', dataPath: 'status', sortable: true },
      {
        key: 'arr',
        label: 'ARR',
        dataPath: 'arr',
        sortable: true,
        format: { type: 'currency', currency: 'USD', rounded: true },
      },
      {
        key: 'healthScore',
        label: 'Health score',
        dataPath: 'healthScore',
        format: { type: 'percent', valueScale: 'fraction', maximumFractionDigits: 1 },
      },
      {
        key: 'lastActivityAt',
        label: 'Last activity',
        dataPath: 'lastActivityAt',
        format: { type: 'datetime', dateStyle: 'medium', timeStyle: 'short' },
      },
      {
        key: 'notes',
        label: 'Notes',
        dataPath: 'notes',
        visibility: { minDataDepth: 'detailed' },
      },
    ],
    collection: {
      viewModes: {
        defaultMode: 'table',
        allowedModes: ['list', 'grid', 'table'],
      },
      pagination: {
        pageSize: 25,
        pageSizeOptions: [10, 25, 50],
      },
      toolbar: {
        search: true,
        viewMode: true,
        filters: true,
        density: true,
        dataDepth: true,
      },
      density: 'comfortable',
      dataDepth: 'standard',
      personalization: {
        enabled: true,
        persist: {
          viewMode: true,
          density: true,
          dataDepth: true,
          pageSize: true,
        },
      },
    },
    filters: [
      { key: 'status', label: 'Status', field: 'status', type: 'enum' },
      {
        key: 'arr',
        label: 'ARR',
        field: 'arr',
        type: 'currency',
        valueMode: 'range',
      },
      {
        key: 'lastActivityAt',
        label: 'Last activity',
        field: 'lastActivityAt',
        type: 'datetime',
        valueMode: 'range',
      },
    ],
  },
});

This one contract drives the DataView lane, while the same rows and controller also feed the raw web primitive, native-first primitive, and composed design-system demos.

Policy integration

DataViews automatically enforce

PolicySpecs

. If a user doesn't have permission to see certain fields, those fields are automatically filtered out or redacted. If a user can only see their own data, the query is automatically scoped.

This means you define the data view once, and it works correctly for all users based on their permissions—no need to write separate queries for different roles.

Personalized Rendering Pattern

To personalize a DataView, keep the spec declarative and resolve user-specific defaults at the app boundary. Use resolveDataViewPreferences from @lssm-tech/lib.personalization/data-view-preferencesto compute viewMode, density, dataDepth, and pageSize. Pass those values to DataViewRenderer as controlled or default props, then record UI changes with trackDataViewInteraction.

const resolved = resolveDataViewPreferences({
  spec: DataGridShowcaseDataView,
  preferences: profile.canonical,
  insights,
  record: savedPreference,
});

<DataViewRenderer
  spec={DataGridShowcaseDataView}
  items={rows}
  defaultViewMode={resolved.viewMode}
  defaultDensity={resolved.density}
  defaultDataDepth={resolved.dataDepth}
/>;

Served outputs

From a DataViewSpec, ContractSpec serves:

  • Database queries

    – Optimized SQL or NoSQL queries executed at runtime

  • API endpoints

    – RESTful or GraphQL endpoints for fetching data

  • UI components

    – List views, tables, cards, and detail views

  • Personalized defaults

    – Plain renderer props for preferred mode, density, data depth, and page size

  • Search interfaces

    – Full-text search with autocomplete

  • Export functions

    – CSV, JSON, or Excel exports

Best practices

  • Only expose fields that users actually need—this improves performance and security.

  • Use appropriate indexes for sortable and filterable fields.

  • Set reasonable pagination limits to prevent performance issues.

  • Use allowedModes to constrain mode switching to layouts that the fields and row actions can support.

  • Store preferences only for dimensions enabled by view.collection.personalization.persist.

  • Test DataViews with realistic data volumes to ensure they perform well.