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.
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.