Introduction

Key Concepts

The main ideas behind the Laioutr frontend including Nuxt app, Studio-driven content, Orchestr data layer, apps and features, and how they fit together.

Key Concepts

This page builds on the Architecture and Data Model overview with frontend-specific detail. Read those first if you haven't.

Tokens

Tokens are the contract between the frontend and apps. The frontend uses canonical tokens to request data or run mutations; apps register handlers for those tokens. This keeps the frontend backend-agnostic.

A query token describes a data request:

import { z } from 'zod/v4';
import { defineQueryToken } from '@laioutr-core/core-types/orchestr';

export const ProductBySlugQuery = defineQueryToken('ecommerce/product/by-slug', {
  entity: 'Product',
  type: 'single',
  label: 'Product by slug',
  input: z.object({
    slug: z.string(),
  }),
});

An entity component token describes a piece of entity data with a typed schema:

import { z } from 'zod/v4';
import { defineEntityComponentToken } from '@laioutr-core/core-types/orchestr';

export const ProductBase = defineEntityComponentToken('base', {
  entityType: 'Product',
  schema: z.object({
    name: z.string(),
    slug: z.string(),
  }),
});

The same pattern applies to link tokens (relationships between entities), action tokens (mutations), and page type tokens. See Orchestr for how handlers are registered.

Page types and routing

A page type token binds a type of page to its URL shape, required data, and Studio metadata:

import { z } from 'zod/v4';
import { defineQueryToken } from '@laioutr-core/core-types/orchestr';
import { definePageTypeToken } from '@laioutr-core/core-types/frontend';
const CategoryBySlugQuery = defineQueryToken('ecommerce/category/by-slug', {
  entity: 'Category', type: 'single', label: 'Category by slug',
  input: z.object({ slug: z.string() }),
});
// ---cut---

export const ProductListingPage = definePageTypeToken('ecommerce/product-listing-page', {
  kind: 'dynamic',
  studio: { label: 'Product Listing', group: 'Shop', icon: 'tags' },
  requiredQueries: [
    {
      alias: 'category',
      entityType: 'Category',
      default: {
        label: 'Listing Category',
        token: CategoryBySlugQuery,
        inputRules: { slug: { join: ['/', { var: 'route.params.slug' }] } },
      },
    },
  ],
  pathConstraints: {
    requiredParams: ['slug'],
    default: '/categories/:slug+',
  },
  resolveFor: [{ referenceType: 'Category' }],
});

Routing is driven by the runtime config (RC): each page in the RC becomes a Nuxt route. The link resolver on the frontend turns references (e.g. "link to this product") into URLs by finding the page type that resolveFor that reference type. See Page Types for the full API.

Features and adapters

The frontend provides extension points for cross-cutting concerns. Each feature defines a store and an adapter interface; apps plug in implementations:

  • Consent (docs): useConsentStore() + consent adapters (e.g. Cookiebot)
  • Tracking (docs): useTrackingStore() + tracking adapters (e.g. GTM)
  • Media (docs): media library providers for asset browsing in Studio

These adapters are registered by apps at module install time. The frontend core does not ship with any default adapter implementations.