> For the complete documentation index, see [llms.txt](https://tyrix.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tyrix.gitbook.io/docs/script-resources/tyrix-multi-job/boss-menu.md).

# Boss Menu

The **boss menu** is the management panel your job leaders use to run their society: society funds, a full money history, the employee roster, weekly hour goals, optional rank salaries, and optional money washing. It is a single NUI panel with a left sidebar; Overview loads when the menu opens, and every other tab fetches its data from the server as you switch to it.

Everything in this panel is authorised server-side on each individual action. A boss who gets demoted or loses the job mid-session stops being able to act immediately — the UI staying open does not keep any permission alive.

## Opening the menu

Boss menus are defined per job in `Config.bossMenus.locations`. Each entry pairs a job name with a set of coordinates, and `Config.bossMenus.interactionType` decides how players interact with that point.

| `interactionType` | How it opens                                                         | Relevant settings                             |
| ----------------- | -------------------------------------------------------------------- | --------------------------------------------- |
| `'zones'`         | An ox\_lib sphere zone shows a text prompt; the player presses a key | `label`, `key`, `distance`                    |
| `'target'`        | ox\_target third-eye option on the point                             | `targetIcon`, `targetLabel`, `targetDistance` |
| `'qb-target'`     | qb-target third-eye option on the point                              | `targetIcon`, `targetLabel`, `targetDistance` |

The value is read once at resource start, so it applies to every location — you cannot mix modes. Note that `Config.bossMenus.label` is the text-UI prompt used in `'zones'` mode, while the `label` inside a location entry is the name the job is registered under with `esx_society:registerSociety` on ESX. The name the panel itself displays comes from the job's own `label` in the `jobs` table, not from the location entry.

```lua
Config.bossMenus = {
    enabled = true,
    interactionType = 'target',

    label = '[E] - Access Boss Menu',
    key = 38,
    distance = 2.0,

    targetIcon = 'fas fa-briefcase',
    targetLabel = 'Access Boss Menu',
    targetDistance = 2.5,

    locations = {
        { coords = vec3(-803.64, 168.12, 72.82), job = 'police', label = 'POLICE', moneywash = true, percent = 0.90 },
    },

    bossGrades = {
        ['boss'] = true,
    },
}
```

Two conditions must both be true before the prompt or third-eye option even appears: the player's **current** job has to match the location's `job`, and their grade's *name* has to be a key set to `true` in `Config.bossMenus.bossGrades`. Because multijob players are only ever clocked into one job at a time, a police boss who is currently clocked into their EMS job will not see the police boss menu — they clock back into police first.

{% hint style="warning" %}
`bossGrades` keys match the `name` column of the framework's `job_grades` table, not the label and not the numeric grade. If your top rank's row is `name = 'chief'` with `label = 'Chief of Police'`, the key is `['chief']`. This is the single most common reason a boss menu "does not open".
{% endhint %}

Locations without `coords` are configuration-only entries — they register money wash settings for a job without creating any in-world interaction point, which is how you feed those values to an external boss menu. See [Configuration → Boss menu](/docs/script-resources/tyrix-multi-job/configuration.md#boss-menu) for the full key list and [Integration](broken://spaces/nbepUC6poQxMqxuJkcj7/pages/d64454a88bf46d671c15b40643e268259ea7243b) for opening the menu from another resource.

## Overview

Overview is the landing tab. It opens with the society's current balance and **Deposit** / **Withdraw** buttons beneath it.

Both movements use the accounts named in `Config.bossMenus.depositAccount` and `Config.bossMenus.withdrawalAccount`, so you decide whether bosses handle society money as cash or through their bank balance. Deposits check the boss actually holds the money first; withdrawals check the society holds it. On ESX the balance lives in an `esx_addonaccount` shared account named `society_<jobname>`, which is registered automatically the first time funds move through it — you do not need to pre-create accounts for the jobs you list.

The panel enforces a five second cooldown between fund movements, on both the client and the server, and the buttons show `Pending…` while a transfer is in flight. The server returns its own post-transaction balance and the panel displays that figure once the transfer completes, so the card does not sit on a stale number.

**Balance over time** sits next to the funds card as a line chart with `3 Days`, `7 Days` and `14 Days` ranges (it opens on 3 days). Each point is an end-of-day balance. Those balances are reconstructed by taking the account's current balance and walking backwards through the recorded transaction history, which has one consequence worth knowing: money moved into or out of the society account by *another* resource is never recorded here, so it shifts the entire line instead of appearing as a step on the day it happened. Money wash entries are also excluded from the chart, because washing does not change the society's balance.

Inside the funds card, under the buttons, **Quick actions** covers hiring and jumping to the other tabs. A row of stat tiles sits below both cards:

| Tile          | Shows                                                    | Notes                                               |
| ------------- | -------------------------------------------------------- | --------------------------------------------------- |
| Employees     | Head count for the job                                   | Clicks through to the Employees tab                 |
| Goal Progress | Percentage of employees meeting their rank's weekly goal | Reads `—` when hour tracking is off                 |
| Wash Fee      | Current fee percentage for this society                  | Money wash enabled only                             |
| Money Washed  | Dirty money put through the wash this week               | Money wash enabled only                             |
| Society Funds | Current balance                                          | Shown instead of the wash tiles when washing is off |
| Net Change    | Balance movement across the selected chart range         | Shown instead of the wash tiles when washing is off |

Goal Progress counts every employee in the society, not just the page a boss happens to be looking at, and compares each one's weekly hours against the goal for *their* rank — so a society where the junior ranks are pulling their weight and the senior ranks are not reads correctly.

The bottom row pairs **Top employees - this week** (the three highest weekly-hour employees, with their rank and hours) against **Recent activity** (the five most recent money movements, with a `View All` link into Transactions). Both refresh automatically — along with the balance chart — after the boss performs a fund movement, hire, fire, rank change or goal change, so the panel updates without being reopened. The push goes to the acting boss, so a colleague's withdrawal elsewhere in the city is not mirrored live. Dashboard results are cached per society for a few seconds and cleared on every money movement, which keeps a busy society from hammering the database while bosses click between tabs.

## Transactions

Transactions is the society's full money ledger. Every deposit, withdrawal, bonus and money wash is written to it with the acting player's name, the target's name where one applies, and a timestamp.

Filter chips across the top narrow the list to `All`, `Deposits`, `Withdrawals`, `Bonuses` or `Money Wash` — the wash chip only appears for societies that have washing enabled. Under the chips, three tiles show **In**, **Out** and **Net** for the current filter. Those totals cover every matching row in the society's history, not only the page on screen, so switching to `Bonuses` gives a boss the real all-time bonus spend rather than a page total.

The list itself is paginated ten rows at a time, newest first. Deposits are recorded as positive amounts and everything else as negative, which is why the list renders them green and red without any extra bookkeeping. Bonus rows are labelled with the employee who received the money; the rest are labelled with the boss who performed the action.

History is stored in `tyrix_multijob_funds_history` and starts accumulating the moment the resource is installed. Nothing is reconstructed retroactively, so an established server's first few days will look sparse and the balance chart will be flat until there is real history behind it. See [Database](/docs/script-resources/tyrix-multi-job/database.md) for the column layout.

## Employees

The Employees tab is the roster. It lists everyone holding this job, ordered by rank descending and then surname, fifty per page — large organisations page through with the arrows at the bottom of the list.

Above the list, rank chips and a name search narrow what is displayed, and three tiles summarise the result: **Total**, **On Track** (employees at or above their rank's weekly goal) and **Avg Hours**. The On Track and Avg Hours tiles only appear when hour tracking is enabled. Bear in mind that the chips and the search box filter the *loaded page*, so in a society large enough to paginate, the summary tiles describe the current page rather than the whole organisation.

Clicking a row expands it. The expanded panel shows all-time hours, weekly hours against that rank's goal with a progress bar, and the salary attached to the rank, then offers three actions.

| Action        | What happens                                                                                                                      |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| Edit Rank     | Replaces the action bar with an inline picker listing every rank; the employee's current rank is marked and cannot be re-selected |
| Give Bonus    | Prompts for an amount and pays it to the employee out of society funds                                                            |
| Fire Employee | Asks for confirmation, then removes the employee from the job                                                                     |

Rank changes apply to the framework job and to this resource's own record at the same time, and the employee gets a notification naming their new rank. Offline employees are handled too on ESX. The row updates immediately and quietly re-syncs from the server if the change was rejected — which is what happens if the boss stepped away from the menu between opening the picker and choosing a rank. Remember that promoting someone into a grade whose `name` is listed in `bossGrades` hands them boss menu access for that job.

Bonuses are debited from the society account before the employee is credited, and the payment is refused outright if the society cannot cover it. The employee is notified of the amount and the job it came from, and the transaction lands in the Transactions ledger with their name on it.

{% hint style="info" %}
On ESX, an offline employee's bonus is credited straight to their stored cash. On QB-Core and QBox, offline balances are not written — pay bonuses to employees who are online.
{% endhint %}

Firing deletes the employee's row for that job, so the job disappears from their [jobs menu](/docs/script-resources/tyrix-multi-job/jobs-menu.md), and if they are currently clocked into it they are moved to `Config.offDutyJob`. A boss cannot fire themselves. Their recorded hours are deliberately left in place, so re-hiring someone restores their history rather than resetting it — see [Hours Tracking](/docs/script-resources/tyrix-multi-job/hours-tracking.md).

### Hiring

**Hire Employee** sits in the tab header and in the Overview quick actions. It scans for players within `Config.bossMenus.hireRadius` metres (5.0 by default) and presents them in a picker; if nobody is close enough, the boss is told so instead of being handed an empty list. Choosing a player assigns them the job at grade 0 — the lowest rank — and the head count updates straight away.

Hiring respects the *target's* job limit, not the boss's, and that limit honours any per-player allowance you granted through `Config.maxJobsOverrides`. If the player is already at their maximum number of jobs the hire is refused and the boss gets a generic failure notification. Re-hiring somebody who already has a record for this job skips the limit check, because it does not consume a new slot.

## Weekly goals

The Goals tab lists every rank in the job with its current weekly hour requirement. Clicking a rank swaps the row for a picker offering `5h`, `10h`, `15h`, `20h`, `40h` and `Custom…` for anything else.

Goals are stored per job and per rank in `tyrix_multijob_goals`. Ranks without a stored goal fall back to `Config.hoursTracking.defaultWeeklyGoal`, so you can ship a sensible baseline and let bosses adjust from there. Values are validated server-side, rejected outside 0–168, and rounded down to whole hours: goal comparisons are cleaner against integers, and the same `weekly hours >= weekly goal` test drives every on-track count in the resource.

That one number feeds several places at once — the progress bar an employee sees for the job in their own jobs menu, the bar on their row in the Employees tab, the On Track tile, and the Goal Progress tile on Overview. Raising a goal will visibly knock people off track, so it is worth telling bosses that before they experiment. [Hours Tracking](/docs/script-resources/tyrix-multi-job/hours-tracking.md) covers how the hours themselves are accumulated and reset.

## Salaries

Salary management is off by default. Set it on to add a **Salaries** tab to the sidebar (when it is off the tab is not shown at all, and the server refuses salary edits regardless of what a client sends):

```lua
Config.bossMenus.salaryManagement = true
```

The tab lists each rank with its current per-paycheck figure and lets a boss set a new one. The value is validated server-side to a whole number between 0 and 1,000,000, so a modded client cannot write an arbitrary figure, and the new amount is pushed to every connected client so salary figures elsewhere in the UI stay correct.

This writes the `salary` column of the framework's `job_grades` table. That is worth being explicit about for two reasons. First, tyrix\_multijob does not run a payroll loop of its own and never pays a recurring wage — your framework's existing paycheck system reads that column and pays it out on its own schedule, so if paychecks are broken or disabled on your server, changing a number here will not fix them. Second, the change applies to the rank, not to a person: every employee at that grade, in that job, is now on the new salary.

Leave `salaryManagement = false` if your server treats wages as an administrative decision. Every change can be logged either way — see [Discord logging](/docs/script-resources/tyrix-multi-job/discord-logging.md).

## Money wash

Money wash converts a boss's dirty money into clean cash at a configured rate. It is the boss's own `black_money` being washed, credited back as cash to the same player, and the society balance is not involved at any point.

The tab shows the current rate, the amount the society has washed this week, a numeric input with a live estimate of the payout, and a short list of recent washes pulled from the society's latest fund activity. Enable it for every society at once, or per location:

```lua
Config.bossMenus = {
    moneywashDefault = true,   -- enable on every boss menu
    moneywashPercent = 0.90,   -- global rate

    locations = {
        -- Per-location overrides beat the globals above
        { coords = vec3(-803.64, 168.12, 72.82), job = 'police', label = 'POLICE', moneywash = true, percent = 0.90 },
        { coords = vec3(-799.48, 169.90, 72.82), job = 'ambulance', label = 'EMS', moneywash = false },
    },
}
```

A location's `moneywash` decides whether the tab appears at all for that job, and its `percent` overrides `moneywashPercent` for that job. When a society has washing disabled the Money Wash entry is removed from the sidebar entirely.

The rate is the fraction the player *keeps*. At `0.90` a player who submits $10,000 in dirty money has all $10,000 removed and receives $9,000 in clean cash; the remaining 10% is the fee. That fee is not paid into the society account and not paid to anyone else — it leaves the economy, which makes washing a money sink rather than a transfer. The Money Washed figures on Overview and in this tab count dirty money submitted, not clean cash paid out, and reset with the weekly boundary.

Payouts are rounded down. A wash that would round down to nothing is refused outright rather than consuming the dirty money for a zero payout, so very small amounts against a very low rate fail. Single washes are capped at 10,000,000.

See [Configuration → Money wash](/docs/script-resources/tyrix-multi-job/configuration.md#money-wash) for the full set of keys.

## Restart protection

Society deposits and withdrawals are locked for the final ten minutes before a txAdmin scheduled restart. Money moving between a player and a society account touches two separate stores, and a restart landing between them is how servers lose money — the lock removes that window entirely.

While the lock is on, the Deposit and Withdraw buttons are disabled and the funds card reads `Funds locked during server restart`. The state is global, so it flips live in any boss menu that happens to be open rather than only being read when the menu is opened. Bonuses and money washing are not gated by the lock. The lock clears automatically when the resource next starts, so nothing needs to be reset by hand after the restart.

This relies on txAdmin's scheduled restart events. Servers restarted by other means get no warning window and therefore no lock.

## Security

Nothing in this panel trusts the UI. Every action is re-authorised on the server at the moment it is performed:

* **Boss permission is re-checked server-side** for every action that changes something, and for reading the dashboard, the chart, the transaction history and the roster. Being a boss when the menu opened does not authorise anything afterwards.
* **Employee data is only ever returned to a verified boss of that society**, so the roster and hours cannot be scraped by a modded client pointed at another job.
* **Proximity can be verified server-side** for every action that changes something, comparing the player's position against the configured location coordinates. `Config.bossMenus.serverSideDistanceCheck` ships as `false` so external boss menus keep working; set it to `true` to enforce the check.
* **Fund movements are rate limited to one every five seconds** per player on the server, with a shared bucket for deposits and withdrawals; other boss actions are throttled at two seconds on the client.
* **Amounts are type-checked, required to be positive, capped at 10,000,000, and floored before deposits, withdrawals and bonuses are written**, which closes off decimal-rounding exploits.
* **Targets are validated before anything is written** — identifier format is checked, the target must genuinely be an employee of that society, ranks must exist in the job, and a boss cannot fire themselves.
* **Every database query is parameterized.** No player-supplied value is ever concatenated into SQL.

Money leaving a society is always debited before the recipient is credited, and a deposit that cannot reach the society account refunds the player rather than silently consuming their cash. If something still looks wrong, [Troubleshooting](/docs/script-resources/tyrix-multi-job/troubleshooting.md) lists the usual causes, and every boss action can be recorded through [Discord logging](/docs/script-resources/tyrix-multi-job/discord-logging.md).
