> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Operating the Lerian SISBAJUD executor

> Set up and run the Lerian SISBAJUD executor: institutions and their Midaz connector, ledger routing, orders that need attention, credential key rotation, roles, listeners, and deploy constraints.

This page describes how to set up and run the **executor**. [Operating Lerian SISBAJUD](/en/rails/sisbajud/sisbajud-operations) describes the Mensageria. [How the Lerian SISBAJUD executor runs orders](/en/rails/sisbajud/sisbajud-executor) describes what the executor does with each order.

<h2 id="institution-setup">
  Institution setup
</h2>

***

Register each institution on the Mensageria and on the executor, with the same `institutionId`. [Operating Lerian SISBAJUD](/en/rails/sisbajud/sisbajud-operations#institutions) describes the Mensageria request.

`POST /v1/institutions` registers an institution on the executor. The body has these fields:

| Field | Meaning |
| - | - |
| `institutionId` | The UUID of the institution. Use the same value as on the Mensageria. |
| `connectorType` | The ledger connector. Set it to `midaz`. |
| `institutionCode` | The CNPJ root of the institution, 8 digits. |
| `enabled` | Whether the institution is active. Send `true`. |
| `connectorMetadata` | The Midaz configuration of the institution. The tables below describe it. |
| `retryPolicyConfig` | Optional. The retry policy, as JSON. |
| `branchFormat` | Optional. A Go RE2 regular expression, at most 64 characters, for the branch number that a court can name in a block restriction. |
| `accountFormat` | Optional. A Go RE2 regular expression, at most 64 characters, for the account number that a court can name in a block restriction. |

The request also creates the tokenization keyset and the audit keyset of the institution. A second request with the same `institutionId` returns `409`.

The executor records itself as the owner of the institution, from its own M2M identity (`EXECUTOR_M2M_SUBJECT`). No request field sets the owner, and a `PATCH` does not change it.

### Connector metadata

| Key | Required | Meaning |
| - | - | - |
| `organizations` | Yes | A list of `{organizationId, ledgers}` entries: the Midaz organizations that the executor searches for the accounts of a subject. Without `ledgers`, the executor searches every ledger of the organization. |
| `baseUrl` | Yes | The base URL of the Midaz ledger of the institution. |
| `authAddress` | When credentials are stored | The Access Manager address that issues the Midaz token of the institution. |
| `blockableBalances` | Yes | The Midaz balance keys that a block can use, for example `default`. These are balance keys, not the `available` or `onHold` amounts. |
| `blockableAccountTypes` | Yes | The account types that a block can use. |
| `salaryAccountTypes` | Yes | The account types that are salary accounts. Send `["NONE"]` when the institution has no salary account type. |
| `crmMode` | No | `legacy` or `embedded`. Without a value, the institution uses `MIDAZ_CRM_MODE`. |
| `crmBaseUrl` | No | The base URL of the standalone Midaz CRM, for `legacy`. With `embedded`, leave it empty: the executor reads the CRM through `baseUrl`. |
| `executorLedger` | To run orders | The ledger where the executor writes. The next table describes it. |

### Executor ledger

| Key | Meaning |
| - | - |
| `organizationId` | The Midaz organization of the writes. |
| `ledgerId` | The Midaz ledger of the writes. |
| `asset` | Set it to `BRL`, exactly. |
| `judicialDepositAccountAlias` | The alias of the judicial deposit account. It must follow the Midaz alias rule. |

The executor refuses an institution request whose `executorLedger` is present and not valid, with `400`. At startup, the executor leaves out of its ledger routing an institution that has no valid `executorLedger`.

### Connector credentials

`PUT /v1/institutions/{institutionId}/connector-credentials` writes the Midaz credentials of the institution:

* `ledger_client_id` and `ledger_client_secret` are always required.
* `crm_client_id` and `crm_client_secret` are required with `crmMode` `legacy`. With `embedded`, do not send them.

The executor encrypts the credentials before it stores them. `PATCH /v1/institutions/{institutionId}` refuses a body with credentials. A new credential does not revoke the previous one at the Access Manager, so revoke it there.

The executor gets the Midaz token of the institution from `{authAddress}/v1/login/oauth/access_token`. When the institution has no stored credentials, the executor sends no `Authorization` header to Midaz.

### Change the configuration

* `PATCH /v1/institutions/{institutionId}` changes the fields of the institution. A `connectorMetadata` in the body replaces the whole bag, except the stored credentials.
* `PUT /v1/institutions/{institutionId}/connector-config` replaces `connectorType` and `connectorMetadata`. It keeps the stored credentials, and it refuses a body with credentials.
* `GET /v1/institutions/{institutionId}` returns the configuration without the credentials.

The executor reads the configuration of its institutions at startup. After you create an institution or change its configuration, restart the executor.

<h2 id="ledger-routing">
  Ledger routing
</h2>

***

With `SYSTEMPLANE_ENABLED` on, the executor serves the tenant documents of its accounting routes under `/tenant-system`. The executor reads two of them: `routing.organizations` turns on accounting routes for each organization, and `routing.ledger_bindings` holds the routes. With `SYSTEMPLANE_ENABLED` off, the executor writes without routes.

`GET /v1/admin/ledger-routing/preflight` checks the routing configuration against the ledger of the institution. It writes nothing. A single-tenant executor needs the `institutionId` query parameter. The report covers these checks:

* The transaction routes and the operation routes exist, and they match the writes of the executor.
* A ledger that validates account types has `sisbajud_block` registered.
* The judicial deposit account in `executorLedger` exists in the ledger and is not blocked.

The `ready` field reports whether the configuration is ready. The report shows the stored `executorLedger`. The running executor uses the configuration that it read at startup.

<h2 id="orders-that-need-attention">
  Orders that need attention
</h2>

***

| Operation | What it returns |
| - | - |
| `GET /v1/institutions/{institutionId}/executor/failed-orders` | The order revisions that the executor failed or abandoned. Each item has the order ID, the revision, a reason token, and the ID of its journal entry. It does not list the revisions whose outcome is not known yet. |
| `GET /v1/institutions/{institutionId}/executor/human-decisions` | The order revisions that the executor stopped on a human decision. |

Each human decision has a `humanDisposition`:

* `GAVE_UP`: the executor attempted no ledger write and answered `EXECUTOR_GAVE_UP`.
* `HELD_MONEY_MOVED`: the executor attempted a write. Money can have moved, and the executor posted no answer.

The Mensageria also lists the orders that the executor gave up on. [Operating Lerian SISBAJUD](/en/rails/sisbajud/sisbajud-operations#orders-that-need-attention) describes that list.

<h2 id="credential-key-rotation">
  Credential key rotation
</h2>

***

`POST /v1/institutions/{institutionId}/security/credential-kek:rotate` rotates the key that wraps the stored Midaz credentials of the institution. This key is not the institution-data key that the Mensageria rotates.

* The rotation moves the stored credentials to the new key version. The credential values do not change. To replace a credential, use `PUT /v1/institutions/{institutionId}/connector-credentials`.
* The response shows the previous and the new key version.
* An institution with no stored credentials returns `404`.
* While another rotation of the same institution runs, a rotation returns `409`.
* With HashiCorp Vault as the key provider and `STREAMING_ENABLED` on, the rotation publishes a `kek.rotated` event with `keyPurpose` `CREDENTIALS`.

With `PLUGIN_AUTH_ENABLED` off, the executor does not serve this operation.

<h2 id="audit-verification">
  Audit verification
</h2>

***

`GET /v1/admin/audit/verify` checks a range of the audit log of the institution, from `fromIndex` to `toIndex`. It does not decrypt any payload. It reports tampering and deleted entries.

<h2 id="roles">
  Roles
</h2>

***

Each operation needs one permission:

| Operation | Permission |
| - | - |
| Create or update an institution, its connector configuration, or its credentials | `institution_config:write` |
| Read an institution, the failed orders, the human decisions, or the audit verification | `admin:read` |
| Credential key rotation | `credential_kek:rotate` |
| Ledger-routing preflight, and reads under `/tenant-system` | `tenant_policy:read` |
| Writes under `/tenant-system` | `tenant_policy:write` |

The `admin` role holds every permission in this table. The `operator`, `investigator`, and `compliance-officer` roles hold `admin:read`. The `systemplane` permissions of `/system` go to the M2M role `editor`, and to no business role.

### The executor on the Mensageria

The executor calls the execution API of the Mensageria with its own M2M client. Set the client in `MENSAGERIA_CLIENT_ID` and `MENSAGERIA_CLIENT_SECRET`. The executor gets its token from the Access Manager at `PLUGIN_AUTH_HOST`. On the Mensageria, the client holds the role `br-sisbajud-executor-role`. [Integrating with Lerian SISBAJUD](/en/rails/sisbajud/sisbajud-integration#execution-api) describes its permissions.

<h2 id="listeners">
  Listeners
</h2>

***

The executor has two listeners:

* **Main API**, at `SERVER_ADDRESS`. Set it to `:4029`, the port that the image exposes. It serves the operations of the API reference. It also serves `/health`, `/readyz`, and `/version`. With `SYSTEMPLANE_ENABLED` on, it serves `/system` and `/tenant-system`. With `SWAGGER_ENABLED` on, it serves `/swagger`.
* **Webhook listener**, at `EXECUTOR_HUB_WEBHOOK_ADDRESS`. The default is `:9082`. It has one route, `POST` at `EXECUTOR_HUB_WEBHOOK_PATH`, whose default is `/v1/webhooks/hub`. Expose this port to the Streaming Hub, and use your ingress address plus this path as the subscription URL.

The webhook listener has no application authentication. It accepts a delivery only when the HMAC signature verifies with the subscription secret or with the previous secret. Outside `DEPLOYMENT_MODE=local`, the listener needs its own TLS certificate. As an alternative, terminate TLS in front of it and set `EXECUTOR_HUB_WEBHOOK_UPSTREAM_TLS_VALIDATED=true`.

`/readyz` includes two executor checks:

* `hub_webhook`: the webhook listener.
* `executor_institutions`: the number of institutions that the executor owns, and how many of them have ledger routing. This check does not fail readiness.

<h2 id="deploy-constraints">
  Deploy constraints
</h2>

***

* **One tenant for each process.** The executor does not start when its tenant list holds more than one tenant.
* **Its own database.** The executor runs on its own empty PostgreSQL database. Its migrations refuse a database that already holds another migration history.
* **Restart after configuration changes.** The executor reads its institutions at startup.
* **Termination grace period.** Set the `terminationGracePeriodSeconds` of the pod to at least 90.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.