4.2.9.1 Configurable workqueue API

Workqueue endpoint – configuring queues with slugs & Elasticsearch queries

Path (countryconfig repo) src/api/workqueue/

The workqueue endpoint in the countryconfig service is responsible for returning the list of workqueues that the client should show, including:

  • a slug (identifier),

  • label/description (for the UI),

  • and the Elasticsearch query that defines which records appear in that queue.

Everything is configured in:

src/api/workqueue/workqueueConfig.ts

and wired into user permissions via:

src/data-seeding/roles/roles.ts

At runtime, OpenCRVS Core uses these configs to:

  1. Decide which queues a user can see (based on their role→queue slugs), and

  2. Run the Elasticsearch query for each queue to fetch the records that should be listed there.

The queries themselves are built using the QueryExpressions DSL from EventIndex in opencrvs-core, which compiles down to Elasticsearch queries.


1. What lives in workqueueConfig.ts

workqueueConfig.ts defines all available workqueues for your country. Conceptually it’s a list (or map) of objects, one per queue, along the lines of:

export const workqueueConfig = [
  {
    slug: 'draft',
    label: { ... },
    description: { ... },
    // optional: icon, sort, etc.
    query: <QueryExpression>
  },
  {
    slug: 'ready-for-review',
    label: { ... },
    query: <QueryExpression>
  },
  ...
]

Each entry represents one queue in the UI, such as:

  • draft

  • in-progress

  • ready-for-review

  • requires-updates

  • sent-for-approval

  • ready-to-print

  • ready-to-issue

  • etc.

The slug is the key thing:

  • It’s how the client and roles refer to the queue.

  • It’s what you reference in roles.ts when granting access.

The query is a typed QueryExpression that describes which events should appear in that queue, using the same status semantics as the product docs (In progress, Ready for review, Requires updates, Ready to print, Ready to issue, etc.). documentation.opencrvs.org+1


2. How roles use workqueue slugs

The seeded roles in:

src/data-seeding/roles/roles.ts

include a mapping from role → allowed workqueue slugs.

Roughly:

{
  id: 'REGISTRATION_AGENT',
  // ...
  scopes: [
    // ...
    'workqueue[id=assigned-to-you|recent|requires-updates-self|sent-for-review]',
    // ...
  ]
}

This means:

  • When a user logs in, their roles determine which queue slugs they can see.

  • The client then asks the workqueue endpoint for definitions and filters them down to the ones the user is allowed to access.

  • That’s why a Field Agent, Registration Agent and Registrar see different queues (even if some share the same underlying statuses).

So the flow is:

  1. roles.ts says: “This role can see queues A, B, C …”

  2. workqueueConfig.ts says: “Queue A means this label + this ES query, B means …”

  3. The workqueue endpoint exposes that whole config to the UI & core.


3. The query: using QueryExpressions → Elasticsearch

The query field in each workqueue config is where the real power lives.

Instead of hand-writing Elasticsearch JSON, you use the QueryExpressions DSL from opencrvs-core (the same layer used for search & dedup queries).

Patterns you’ll typically see:

import { and, or, not, field, user } from '@opencrvs/events/EventIndex' // conceptually

export const draftQueue = {
  slug: 'draft',
  label: { ... },
  query: and(
    field('status').isEqualTo('IN_PROGRESS'),
    field('isDraft').isEqualTo(true),
    user('scope').has('record.declare.birth') // user-specific filtering
  )
}

The key ideas:

  • field('...') refers to an indexed property of the event (e.g. status, event type, office, assigned user, timestamps).

  • Logical combinators like and, or, not build complex boolean queries.

  • User-aware helpers like user('officeId') or user('primaryOfficeId') can scope records to the current user’s office or jurisdiction.

  • At runtime, these QueryExpressions are compiled into Elasticsearch queries against the event index (see EventIndex.ts in opencrvs-core).

This is how you implement things like:

  • “Draft” → events with status IN_PROGRESS created by the current user.

  • “Ready for review” → events with status IN_REVIEW or VALIDATED assigned to the user’s office.

  • “Requires updates” → events with status REQUIRES_UPDATES.

  • “Ready to print” → events with status REGISTERED with no certificates yet.

So each queue is literally “just” an ES query defined via this DSL.

4. Mental model

You can think of the workqueue endpoint as:

“A country-specific list of named Elasticsearch queries (slug + label + QueryExpression) that define which records appear in each queue, and which queues each role can access.”

  • workqueueConfig.ts → defines the queues and their queries.

  • roles.ts → decides who can see which queues (by slug).

  • EventIndex / QueryExpressions → turns those definitions into real ES queries over the event index.

Last updated