Skip to content

Golden Path โ€” Helpers (helpers/*) โ€‹

Helpers group cross-cutting registration for a datatype โ€” most importantly payload handlers so list/detail views and $data stay coherent across users and widgets.

Payload registration โ€‹

Payload handlers tell raclette how to turn stored items into payload items for the UI and orchestrator. Registering a payload per datatype is what connects service return values, routes, and frontend store behavior.

typescript
fastify.registerPayloadHandler<example>("example", {
  type: "example",
  displayName: (item) => item.name || "",
  completion: (item) => item.name || "",
})

The plugin index.ts usually calls a small registerPayload(fastify) that internally performs fastify.registerPayloadHandler(...). See Plugin index.ts for wiring order.

For how services expose data that maps into payloads, see Service.

What ends up on each payload item โ€‹

The payload pipeline turns your stored documents into normalized frontend rows (_displayName, _completion, _tags, timestamps, โ€ฆ). The handler you register must supply displayName and completion callables; other required fields are merged from your document and/or the optional fields callback (see @raclettejs/core/services/backend/src/core/payload/payloadRegistrar.ts in the monorepo).

displayName โ€” short human-facing label for lists, breadcrumbs, and pickers (what a search or โ€œinsert referenceโ€ UI will show first). Keep it stable and specific enough to disambiguate items of the same type.

completion โ€” secondary line of context (subtitle, status, path). It can read like a title in small UIs, but it should carry extra information when possible so displayName + completion do not duplicate each other.

owner โ€” the user the row belongs to when your domain has ownership. The merge logic can leave owner-derived fields unset when your model does not carry one; use fields when you need to spell โ€œno ownerโ€ explicitly for your domain.

project โ€” legacy tenant / scope field on stored documents and request context. It will be superseded by space for mandant-style separation in a future release; new plugins should still set project today where the stack expects it, and plan to adopt space when the migration lands.

createdAt / updatedAt โ€” should exist on every persisted model you care about in the portal (see Model). The payload layer maps them to _createdAt / _updatedAt. Until automatic backfilling ships with the new database layer, define them on the model and return them from services so payload rows stay consistent.

tags โ€” should be a string[] on each model you publish broadly. Tags are a lightweight cross-cutting dimension (feature flags, collections, user-defined grouping) that other plugins or workbench features can lean on without knowing your schema in detail.

Guessable datatypes (especially for published plugins) โ€‹

The type string you register for payload is part of your pluginโ€™s public surface. Generic workbench features (for example a frontend search plugin that discovers payload types) work best when type keys and field shapes are consistent with the rest of the ecosystem. The same idea applies to plugin contracts โ€” see Service โ€” Cross-plugin communication.

See also โ€‹