# 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:

```ts
src/api/workqueue/workqueueConfig.ts
```

and wired into user permissions via:

```ts
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`**](https://github.com/opencrvs/opencrvs-core/blob/625cd2662a5101caac5a1f7b26a6c8ed77c27246/packages/commons/src/events/EventIndex.ts#L172) **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:

```ts
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`](https://roles.tshttps/github.com/opencrvs/opencrvs-countryconfig/blob/0fc50a9d21d2c7525e5b8e3b8f1cd7c0ca7a7328/src/data-seeding/roles/roles.ts#L30) 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](https://documentation.opencrvs.org/product-specifications/workflow-management?utm_source=chatgpt.com)

***

### 2. How roles use workqueue slugs

The seeded roles in:

```ts
src/data-seeding/roles/roles.ts
```

include a mapping from **role → allowed workqueue slugs**.

Roughly:

```ts
{
  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:

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