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.
DataViews Runtime Library
The @lssm-tech/lib.contracts-spec/data-views and @lssm-tech/lib.design-system libraries provide the runtime logic and UI components to render DataViews in your application.
Installation
bun add @lssm-tech/lib.contracts-spec @lssm-tech/lib.design-systemDataViewRenderer
The primary component for rendering any DataView. It automatically selects the correct layout (List, Table, Grid, Detail) based on the spec.
import { DataViewRenderer } from '@lssm-tech/lib.design-system';
import { MyUserList } from './specs/users.data-view';
export function UserPage() {
return (
<DataViewRenderer
spec={MyUserList}
items={users}
pagination={{ page: 1, pageSize: 20, total: 100 }}
onPageChange={(page) => fetchPage(page)}
/>
);
}Props
spec: The DataViewSpec definition.items: Array of data items to render.filters: Current filter state object.onFilterChange: Callback when typed filters change. Renderers emitDataViewFilterValueobjects for numeric, percent, currency, temporal, duration, and boolean filters.pagination: Object withpage,pageSize,total.onPageChange: Callback when page changes.viewMode/defaultViewMode: Controlled or initial collection mode for specs that allowlist,grid, ortableprojections throughview.collection.viewModes.density/defaultDensity: Controlled or initial density for collection renderers. Host apps can seed this from@lssm-tech/lib.personalizationwhile specs can declareview.collection.densityand tableview.densitydefaults.dataDepth/defaultDataDepth: Controlled or initial summary/standard/detailed/exhaustive projection. Fields can declarevisibility.minDataDepth, and collection specs can opt intoview.collection.personalizationpersistence hints.
Collection Defaults And Data Depth
Use one authored DataViewSpec for list, grid, and table experiences. view.collection declares allowed modes, toolbar controls, pagination defaults, density, data depth, and persistence hints. visibility.minDataDepth lets a field appear only when the renderer is in a detailed or exhaustive mode.
import { defineDataView } from '@lssm-tech/lib.contracts-spec/data-views';
import { defineTranslation } from '@lssm-tech/lib.contracts-spec/translations';
const bundle = defineTranslation({
meta: { key: 'crm.accounts', version: '1.0.0', domain: 'crm', owners: ['@crm'] },
locale: 'en',
messages: { 'Name': { value: 'Name' }, 'Owner': { value: 'Owner' }, 'ARR': { value: 'ARR' }, 'Internal notes': { value: 'Internal notes' } },
});
export const AccountsDataView = defineDataView(bundle, {
meta: {
key: 'crm.accounts',
version: '1.0.0',
title: 'Accounts',
description: 'Customer account workspace',
domain: 'crm',
entity: 'account',
owners: ['@crm'],
tags: ['crm', 'accounts'],
stability: 'stable',
},
source: {
primary: { key: 'crm.accounts.list', version: '1.0.0' },
},
view: {
kind: 'table',
fields: [
{ key: 'name', label: 'Name', dataPath: 'name', sortable: true },
{ key: 'owner', label: 'Owner', dataPath: 'owner' },
{ key: 'arr', label: 'ARR', dataPath: 'arr', format: { type: 'currency', currency: 'EUR' } },
{
key: 'internalNotes',
label: 'Internal notes',
dataPath: 'internalNotes',
visibility: { minDataDepth: 'detailed' },
},
],
columns: [
{ field: 'name' },
{ field: 'owner' },
{ field: 'arr' },
{ field: 'internalNotes' },
],
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,
},
},
},
},
});Personalization Bridge
Resolve user preferences in the host app, then pass ordinary renderer props into personalization library guideDataViewRenderer. The bridge helper lives in @lssm-tech/lib.personalization, so the design-system renderer stays portable for apps that do not use personalization. See the
import { DataViewRenderer } from '@lssm-tech/lib.design-system';
import { resolveDataViewPreferences } from '@lssm-tech/lib.personalization/data-view-preferences';
const resolved = resolveDataViewPreferences({
spec: AccountsDataView,
preferences: profile.canonical,
insights,
record: savedDataViewPreference,
});
<DataViewRenderer
spec={AccountsDataView}
items={accounts}
defaultViewMode={resolved.viewMode}
defaultDensity={resolved.density}
defaultDataDepth={resolved.dataDepth}
pagination={{
page,
pageSize: resolved.pageSize ?? 25,
total,
}}
onViewModeChange={(viewMode) => {
tracker.trackDataViewInteraction({
dataViewKey: AccountsDataView.meta.key,
dataViewVersion: AccountsDataView.meta.version,
action: 'view_mode_changed',
viewMode,
});
}}
onDensityChange={(density) => {
tracker.trackDataViewInteraction({
dataViewKey: AccountsDataView.meta.key,
action: 'density_changed',
density,
});
}}
onDataDepthChange={(dataDepth) => {
tracker.trackDataViewInteraction({
dataViewKey: AccountsDataView.meta.key,
action: 'data_depth_changed',
dataDepth,
});
}}
/>;
Entity surface guide
For full list/search/filter/results, detail, and edit workflows, use the entity surfaces guide
Agent Prompt
Use this prompt when asking an implementation agent to add a preference-aware collection DataView without breaking package boundaries.
Implement a production DataView for <entity>.
Requirements:
- Define one canonical DataViewSpec with kind 'table', collection viewModes for list/grid/table, pagination defaults, toolbar search/filter/view mode/density/dataDepth controls, and personalization persist hints.
- Mark fields that should only appear in richer experiences with visibility.minDataDepth.
- Render it with DataViewRenderer using plain props from resolveDataViewPreferences.
- Track user interactions with trackDataViewInteraction for view mode, density, data depth, search, filters, sorting, and pagination.
- Keep @lssm-tech/lib.design-system independent from @lssm-tech/lib.personalization.
- Add focused tests for default resolution, invalid-mode fallback, data-depth projection, and behavior-derived preferred view mode.Query Generation
The DataViewQueryGenerator utility helps translate DataView parameters (filters, sorting, pagination) into query arguments for your backend.
import { DataViewQueryGenerator } from '@lssm-tech/lib.contracts-spec/data-views/query-generator';
const generator = new DataViewQueryGenerator(MyUserList);
const params = {
pagination: { page: 1, pageSize: 20 },
filters: {
role: { kind: 'single', value: 'admin' },
revenue: { kind: 'range', from: 1000, to: 5000 },
lastSeenAt: { kind: 'single', value: '2026-04-28T08:30:00Z' }
}
};
const errors = generator.validateParams(params);
const query = generator.generate(params);
// query.input contains skip/take plus the typed filter payloads.Contracts Runtime Core
Framework-neutral in-house data-fetching engine: Transport/Storage/reachability ports, cache, durable offline queue, and the conflict-resolver registry — no @tanstack.
Personalization
Track behavior events, resolve DataView preferences, and convert insights into overlays or workflow adaptations.
Why ContractSpec
Keep educational and comparison content reachable without letting it define the primary OSS learning path.