PrimeBrickPrimeBrick
  • Docs
  • Contact
  • MIT License
  • Documentation
  • MCP Server
  • API Catalog
  • Services
  • Libraries
PrimeBrickPrimeBrick

© 2026 PrimeBrick. MIT License. v3.11.2

github
Backend
    Roles and PermissionsWorking Together on the Same RecordManaging ModulesSigning In and MFA
    Generated
    Manual
    Developer Guide
      OverviewArchitectureAPI ConventionsEntity metadata contractEntity CRUD PipelineEntities and CRUD conventionsModule Navigation MetadataService RegistryMCP GatewayThe Service ProxyRotating Secrets EngineTranslationsAuthenticationRBACEnvironment ConfigurationCollaboration & Visual Merge
Frontend
Microservices
powered by Zudoku
Developer Guide

Entity metadata contract

GET /api/v1/entities/{entity}/meta returns the entity metadata — a typed JSON document describing how the entity is displayed and which operations it supports. The canonical type is EntityMeta in src/http/entity-meta.types.ts: a closed interface (no index signature), so any property not declared in the schema is a compile-time error. Every static meta object (*.meta.ts) MUST be annotated EntityMeta.

Source and assembly

  • The static meta declares identity, display_field, columns, optional table options, and optional actions_overrides.
  • assembleMeta(meta, entityClass) injects runtime fragments: display_name (defaulted to "${display_field}" when omitted) and collaboration (from getEntityPersistenceMeta().isAuditable).
  • deriveEntityActions(router, entity, actions_overrides) scans the registered route table and emits the actions array.

Anatomy

Code
{ "entity": "user_profile", "translation_key": "user_profile", "title_key": "system.entities.user_profile.title", "uid": "uuid", "display_field": "display_name", "display_name": "${display_name}", "actions_overrides": { "duplicate.bulk": { "enabled": false } }, "columns": [ /* MetaColumn[] — see props sheet */ ], "table": { "default_view": "table", "default_sort": { "key": "created_at", "dir": "desc" }, "default_page_size": 25, "page_size_options": [10, 25, 50, 100], "row_custom_actions": [ { "action_name": "change_password", "translation_key": "system.settings.users.change_password", "icon": "key-round", "required_permission": "AUTHENTICATED_ADMIN" } ] }, "actions": [ { "op": "list", "enabled": true, "permissions": ["user_profile.read.all"] }, { "op": "duplicate.bulk", "enabled": false } ], "collaboration": { "enabled": true, "expose_editing_value": true } }

Root properties

FieldWhereRequiredPurpose
entitystaticyesEntity key, snake_case singular — route segment
translation_keystaticyessnake_case singular i18n prefix
title_keystaticyesi18n key for the entity title
uidstaticyesColumn key used as row identity
display_fieldstaticyesKey of the primary display column
display_nameresponseyesDisplay template (${field}). Optional in static meta — assembleMeta defaults it to "${display_field}"
actions_overridesstaticnoPer-op enabled toggles — may only affect existing ops
columnsstaticyesRoot-level field dictionary, transversal to all page types
tablestaticnoEntityListTable options — absent on form-only metas
actionsresponseyesDerived capability contract
collaborationresponseyes{ enabled, expose_editing_value }

display_name is the generic display representation — edit-page titles, comboboxes, related-object labels. It supports ${field} template syntax (interpolated client-side) so composed expressions like "${first_name} ${last_name}" are possible.

columns props sheet (MetaColumn)

PropRequiredPurpose
keyyesRow field key (snake_case)
label_keyyesi18n key for header/form label
typeyestext | badge | date | datetime | color | boolean | number | sparkline
orderyesExplicit position within its rendering group — array position in columns MUST NOT matter. Convention: uuid is order: -1 (canonical first sticky column, hidden but selectable), the display_field column is order: 0
stickyPinned left — uuid and the display_field column are the standard sticky pair
auditedSystem audit column — rendered last
sortable / searchable / filterable / hideableCapability flags (default true)
default_visiblefalse = selectable but hidden by default
badge{ values: Record<string, { label_key?, label_text?, color? }> }
datetime_iana_toggle{ record_iana_field }
sparklinetype:"sparkline" — { endpoint, request_field, row_key, response_field?, bucket_field?, bucket_unit_field?, series }; virtual column, the list engine batch-POSTs row keys after every load
tooltip, tooltip_priority, tooltip_titleTooltip keys/priority
show_form_tooltip, show_list_tooltipTooltip visibility per context

Rendering order derives from flags: sticky → normal → audited, each sorted by order (orderedColumns on the FE).

table options

PropPurpose
default_viewtable | cards | cards_list
default_sort{ key, dir }
default_page_sizeInitial rows per page
page_size_optionsDropdown values
row_custom_actionsCustom row CTA display config for non-standard ops
filter_presetsMutually-exclusive preset scope filters in the toolbar — display: "button_group" renders icon-only buttons (per-option icon required, meaning via title tooltip + aria-pressed; the label is never displayed); "combobox" for long lists. Exactly one option active; where:[] = "all" escape; conditions AND into every /list request

table is absent on form-only metas (e.g. GET /api/v1/auth/me/meta — meMeta in auth-session.router.ts is a plain EntityMeta without table).

actions — standard vocabulary

deriveEntityActions always emits every standard op; missing routes produce explicit enabled: false entries:

list, meta, get, create.single, update.single, delete.single, restore.single, read.audit, export, delete.bulk, restore.bulk, duplicate.single, duplicate.bulk

  • enabled: true → op exists; per-user gating via permissions/sentinel
  • enabled: false → route absent OR product-disabled via actions_overrides — CTA hidden everywhere
  • actions_overrides never invents ops — it can only toggle enabled
  • Non-standard routes surface as additional bare ops (change-password, check-availability)
  • Ops outside /api/v1/entities/:entity (e.g. /api/v1/auth/users) are included via the extraScans parameter

Search semantics

Default "all fields" search covers visible ∩ searchable ∩ text-physical columns. The BE derives fallback search keys per entity via src/lib/search-keys.ts — meta searchable flag ∩ DAL pgType (varchar/text/uuid; uuid uses the existing text cast). JSONB and other non-text columns MUST be searchable: false.

Specializations

  • ConfigEntryMeta extends EntityMeta adds required type_capabilities (from @primebrick/sdk) — used by config_entry only.
  • EntityMetaResponse is the served shape: EntityMeta plus required display_name, actions, collaboration.

Next steps

  • API conventions — endpoint taxonomy
  • Collaboration — the collaboration fragment
  • RBAC — permissions behind actions[].permissions
Last modified on October 28, 2026
API ConventionsEntity CRUD Pipeline
On this page
  • Source and assembly
  • Anatomy
  • Root properties
  • columns props sheet (MetaColumn)
  • table options
  • actions — standard vocabulary
  • Search semantics
  • Specializations
  • Next steps