Cohesive Systems logoCOHESIVE SYSTEMS

Building Blocks

Cohesive.Presentation

Cohesive.Presentation declares user-facing surfaces from backend-owned semantics: pages, workspaces, views, forms, actions, flows, bindings, and generated frontend contracts.

Core Idea

Presentation turns semantic system definitions into inspectable product surfaces. It is not a replacement for a frontend framework; it is the layer that preserves meaning while projecting into one.

Backend-Owned UI Semantics

Many systems duplicate the same facts across backend handlers, generated clients, frontend routes, form schemas, table columns, action enablement checks, and tests.

Cohesive.Presentation keeps those facts attached to the semantic model. A form can know which shape it edits, an action can know which API operation it calls, and a view can know which relation or repository query supplies its data.

Surface Model

Presentation definitions can describe:

  • Applications, workspaces, pages, routes, and panels.
  • Data sources, views, tables, cards, forms, fields, and metrics.
  • Actions, navigation, command surfaces, and task flows.
  • Visibility, enablement, labels, and derived state through expressions.
  • Target bindings for React, design systems, generated tests, and API clients.

Actions And Forms

Forms and actions are strongest when they remain connected to backend semantics. A create action can bind to an API command, a transition action can expose preconditions and expected results, and a query form can lower into a Cohesive.Relations query.

This lets presentation surfaces participate in the same identity, validation, API, storage, and process model as the backend.

Ari Admin UI Example

The Ari admin UI uses backend-authored presentation definitions as the source of truth, then projects them through a React runtime that supplies route state, data bindings, renderer choices, and design-system interpretation.

public static class AdminPresentationModule
{
    public const string ModuleId = "ari-admin-ui";
    public const string ModuleVersion = "0.1.0";
 
    public static PresentationModuleDefinition Create() =>
        PresentationModuleComposer.Compose(
            id: ModuleId,
            name: "Ari Admin UI",
            version: ModuleVersion,
            contributions:
            [
                AdminShellArea.CreateContribution(),
                ShapeGraphAuthoringArea.CreateContribution(),
                RelationsArea.CreateContribution(),
                ProcessesArea.CreateContribution()
            ]);
}
 
public static class AdminShellArea
{
    public static PresentationModuleContribution CreateContribution() => new()
    {
        Navigation = [AdminNavigation.Create()],
        Views = CreateViews(),
        DataSources = CreateDataSources(),
        Actions = CreateActions()
    };
 
    static ViewDefinition[] CreateViews() =>
    [
        AdminPresentationModule.Page(
            id: AdminPresentationViewIds.RelationsWorkspacePage,
            name: "Relations Workspace",
            routeId: AdminNavigationRouteIds.RelationsWorkspace,
            regions:
            [
                AdminPresentationModule.Region(
                    id: "body",
                    name: "Relations",
                    kind: ViewRegionKind.Surface,
                    viewIds: [AdminPresentationViewIds.RelationsWorkspaceBody])
            ],
            actions:
            [
                AdminPresentationModule.ActionPlacement(
                    actionId: AdminPresentationActionIds.RefreshRelations,
                    region: "toolbar",
                    label: "Refresh",
                    icon: AdminPresentationIconIds.RefreshCw)
            ]),
 
        AdminPresentationModule.SurfaceView(
            id: AdminPresentationViewIds.RelationsWorkspaceBody,
            name: "Relations",
            regions:
            [
                AdminPresentationModule.Region(
                    id: "definitions",
                    name: "Relation Definitions",
                    kind: ViewRegionKind.Collection,
                    viewIds: [AdminPresentationViewIds.RelationDefinitionTable])
            ]),
 
        AdminPresentationModule.Collection(
            id: AdminPresentationViewIds.RelationDefinitionTable,
            name: "Relation Definitions",
            dataSourceId: AdminPresentationDataSourceIds.RelationDefinitions,
            fieldIds:
            [
                AdminPresentationFieldIds.RelationSummaryName,
                AdminPresentationFieldIds.RelationSummarySource,
                AdminPresentationFieldIds.RelationSummaryTarget,
                AdminPresentationFieldIds.RelationSummaryLifecycle
            ],
            rowActions:
            [
                AdminPresentationModule.CollectionRowAction(
                    actionId: AdminPresentationActionIds.OpenRelationDefinition,
                    label: "Open",
                    icon: AdminPresentationIconIds.ExternalLink,
                    parameters:
                    [
                        AdminPresentationModule.CollectionRowActionParameter(
                            name: "id",
                            valuePath: nameof(RelationDefinitionSummary.Id))
                    ])
            ],
            rowIdentityPath: nameof(RelationDefinitionSummary.Id),
            rowLabelPath: nameof(RelationDefinitionSummary.Name)),
 
        AdminPresentationModule.Dashboard(
            id: AdminPresentationViewIds.RelationDefinitionHeader,
            name: "Relation Summary",
            dataSourceIds: [AdminPresentationDataSourceIds.RelationDefinition],
            fieldIds:
            [
                AdminPresentationFieldIds.RelationDefinitionName,
                AdminPresentationFieldIds.RelationDefinitionVersion,
                AdminPresentationFieldIds.RelationDefinitionLifecycle
            ],
            chrome: AdminPresentationModule.DocumentHeaderChrome(
                titleField: "RelationDefinition.Name",
                subtitleField: "RelationDefinition.Id",
                metadataFieldIds:
                [
                    AdminPresentationFieldIds.RelationDefinitionVersion,
                    AdminPresentationFieldIds.RelationDefinitionLifecycle
                ]))
    ];
 
    static DataSourceDefinition[] CreateDataSources() =>
    [
        AdminPresentationModule.RemoteDataSource(
            id: AdminPresentationDataSourceIds.PresentationNavigation,
            name: "Presentation Navigation",
            kind: DataSourceKind.Navigation,
            resultShape: "NavigationDefinition",
            endpointId: AdminApiDefinition.GetPresentationNavigation.Id.Value),
 
        AdminPresentationModule.RemoteDataSource(
            id: AdminPresentationDataSourceIds.PresentationModule,
            name: "Presentation Module",
            kind: DataSourceKind.Module,
            resultShape: "PresentationModuleDefinition",
            endpointId: AdminApiDefinition.GetPresentationModule.Id.Value),
 
        AdminPresentationModule.LocalDataSource(
            id: AdminPresentationDataSourceIds.AuthContext,
            name: "Authenticated User Context",
            kind: DataSourceKind.LocalState,
            resultShape: "AdminAuthContext")
    ];
 
    static ActionDefinition[] CreateActions() =>
    [
        AdminPresentationModule.NavigationAction(
            id: AdminPresentationActionIds.OpenRelationDefinition,
            name: "Open Relation Definition",
            routeId: AdminNavigationRouteIds.RelationDefinitionEditor,
            parameters: [new(Name: "id", Type: "string", IsRequired: true)]),
 
        AdminPresentationModule.LocalAction(
            id: AdminPresentationActionIds.RefreshRelations,
            name: "Refresh Relations",
            scope: ActionScopeKind.Page,
            resultInvalidateDataSourceIds:
            [
                AdminPresentationDataSourceIds.RelationDefinitions
            ])
    ];
}
 
public static class AdminNavigation
{
    public static NavigationDefinition Create() => new(
        Id: "ari-admin",
        Label: "Ari Admin",
        Nodes:
        [
            new(
                Id: AdminNavigationNodeIds.RelationsWorkspace,
                Label: "Relations",
                Kind: NavigationNodeKind.Page,
                RouteId: AdminNavigationRouteIds.RelationsWorkspace,
                IsPrimary: true,
                ActiveRouteIds: [AdminNavigationRouteIds.RelationDefinitionEditor],
                Icon: AdminPresentationIconIds.GitBranch,
                ActionId: AdminNavigationActionIds.OpenRelationsWorkspace),
 
            new(
                Id: AdminNavigationNodeIds.RelationDefinitionEditor,
                Label: "Relation Definition Editor",
                Kind: NavigationNodeKind.EntityDetail,
                RouteId: AdminNavigationRouteIds.RelationDefinitionEditor,
                IsPrimary: false,
                ActiveRouteIds: [],
                Icon: AdminPresentationIconIds.ExternalLink,
                ActionId: AdminPresentationActionIds.OpenRelationDefinition)
        ],
        Edges:
        [
            new(
                Id: "relations-to-relation-definition",
                FromNodeId: AdminNavigationNodeIds.RelationsWorkspace,
                ToNodeId: AdminNavigationNodeIds.RelationDefinitionEditor,
                Kind: NavigationEdgeKind.RelatedEntityRoute,
                Label: "Open relation definition")
        ]);
}
export function AdminRoutedSurfaceRouteHost({
  componentSystem = shadcnPresentationComponentSystem,
  designSystem = tailwindPresentationDesignSystem,
  navigationTarget,
  routeParameters,
}: AdminRoutedSurfaceRouteHostProps) {
  const { activeAccount, canLoadApiData, querySuffix } = useTrainingApiAuthState()
  const { tenants } = useTrainingApiTenantContext()
  const { activeTasks } = useProcessTasks()
 
  const dataSourceTargetInterpretation = useMemo(
    () => createTrainingDataSourceTargetInterpretation({
      isApiAuthorized: canLoadApiData,
    }),
    [canLoadApiData],
  )
 
  const createDataSourceBindingRegistry = useCallback(
    ({ paginationRequestsByDataSourceId }) =>
      createTrainingDataSourceBindingRegistry({
        activeProcessTasks: activeTasks,
        currentUserLabel: activeAccount?.name ?? activeAccount?.username ?? 'No account',
        isApiAuthorized: canLoadApiData,
        paginationRequestsByDataSourceId,
        querySuffix,
        tenants,
        targetInterpretation: dataSourceTargetInterpretation,
      }),
    [activeAccount, activeTasks, canLoadApiData, dataSourceTargetInterpretation, querySuffix, tenants],
  )
 
  return (
    <ProjectedRoutedSurfaceRuntime<AdminPresentationRouteContext>
      componentSet="ari-admin-ui"
      componentSystem={componentSystem}
      createDataSourceBindingRegistry={createDataSourceBindingRegistry}
      dataSourceTargetInterpretation={dataSourceTargetInterpretation}
      designSystem={designSystem}
      navigationTarget={navigationTarget}
      routeParameters={routeParameters}
    />
  )
}

Projection Targets

React UI

What it receives
Typed surfaces, actions, forms, views, and data bindings.
Why it helps
Frontend code starts from product semantics instead of duplicated route and field strings.

Generated clients

What it receives
API operation ids, scope metadata, route parameters, and response shapes.
Why it helps
Requests stay aligned with backend definitions.

Tests

What it receives
Stable semantic identifiers and generated mocks.
Why it helps
Tests can target meaning instead of incidental DOM details.

Design systems

What it receives
Component roles and interaction intent.
Why it helps
Different renderers can share the same underlying product model.

Why It Matters

Presentation becomes another interpretation of the semantic system model rather than a separate frontend reinvention. Product surfaces can evolve while preserving identifiers, contracts, actions, and state behavior across the stack.