Skip to content

Pins are the bookmark set

Forms and configurationDashboardHTTPdefault_pinsbadgePATCH /api/me/preferenceshiddenRolePins

A role ships the exact queries its members need as pinned views with live counts, in their nav from the first login.

The situation

A new packer starts Monday. They live in three queries: cartons waiting, cartons in jeopardy, everything for one order. Every filter is already a URL. They should not have to build any of them.

The recipe

start.ts
roles: [{
role: 'packing',
title: 'Packing',
default_pins: [
{ label: 'Waiting', url: '/escalations/available?role=packing&view=table', badge: true },
{ label: 'In jeopardy', url: '/escalations/available?role=packing&jeopardy=1', badge: true },
],
}],

Members see the pins under the role’s display title. They can promote one into their own pins, hide one (recorded in hiddenRolePins), and reorder their own. Pin this view on any list captures the live filters as a new personal pin. Personal pins live in PATCH /api/me/preferences, a shallow merge where null deletes a key.

badge: true renders a live count beside the pin. The pin’s URL is parsed back into its query and counted server-side, so the badge and the list always agree.

The guarantee

Preferences carry presentation state only: URLs and UI choices, never data and never authorization. A pin to a query the user cannot read renders that query’s normal empty state. The preference merge is a single guarded statement, size-capped at about 32 KB. Membership is the persona’s bookmark set, so there is no per-user setup. See Dashboard.