> 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/installation.md).

# Installation

## Steps

{% stepper %}
{% step %}

## Drop the folder

Drop the folder into your resources directory, for example `resources/[addons]/tyrix_multijob`. Keep the folder name `tyrix_multijob` so the paths and ensure lines in these docs match what you actually have.
{% endstep %}

{% step %}

## Add the ensure lines

Add the ensure lines to your `server.cfg`, in this order:

```cfg
ensure oxmysql
ensure ox_lib
ensure es_extended
ensure esx_addonaccount
ensure tyrix_multijob
```

Order matters. `oxmysql` and `ox_lib` must be up before anything queries the database or registers a callback. Every deposit, withdrawal and bonus is applied through `esx_addonaccount`'s shared-account API rather than by writing the balance row itself, so that resource has to be started before tyrix\_multijob asks it for `society_<jobname>`.

If you run QBCore or QBox, replace `es_extended` with `qb-core` or `qbx_core` — but keep `esx_addonaccount`, because society funds are resolved through it on every framework.
{% endstep %}

{% step %}

## Configure `shared/config.lua`

Two things are worth doing before the first restart:

* Add your **boss menu locations**. Each entry pairs a coordinate with the job name it belongs to:

  ```lua
  Config.bossMenus.locations = {
      { coords = vec3(-803.64, 168.12, 72.82), job = 'police', label = 'POLICE' },
      { coords = vec3(-799.48, 169.90, 72.82), job = 'ambulance', label = 'EMS' },
  }
  ```
* Set **`interactionType`** to match the target resource you actually run. It accepts exactly three values:

  ```lua
  Config.bossMenus.interactionType = 'target' -- 'zones' | 'target' | 'qb-target'
  ```

  `'zones'` uses ox\_lib zones with a TextUI prompt and a keypress, and needs no target resource at all. `'target'` calls `exports.ox_target`. `'qb-target'` calls `exports['qb-target']`.

  <div data-gb-custom-block data-tag="hint" data-style="warning" class="hint hint-warning"><p>Anything other than those three values fails silently in a confusing way: no interaction point is created, so standing on the spot does nothing and no error is printed.</p></div>

  Every setting in this block is documented in [Configuration → Boss menu](/docs/script-resources/tyrix-multi-job/configuration.md#boss-menu).
  {% endstep %}

{% step %}

## Restart the server

Restart the server, or run `ensure tyrix_multijob` from the console. The schema installs itself on start.
{% endstep %}
{% endstepper %}

## Database

There is nothing to import. On start, the server reads `SQL.sql` from the resource root and executes each statement, so the tables exist before the first player connects.

Every statement in that file is a `CREATE TABLE IF NOT EXISTS`, which makes the whole step idempotent — it runs on every boot and does nothing when the tables are already there. That is deliberate: it means a fresh install, a server that has been running for months and a database restored from a backup all reach the same state without you tracking which migration you are on.

On success the console prints a confirmation line with the number of statements applied:

```
[tyrix_multijob] ready | framework esx | locale en | 24 jobs | 6 tables | hours on | discord off
```

`SQL.sql` still ships in the resource root, and it is a normal SQL file you can import by hand. That is useful if you want to pre-provision the schema before the resource ever starts, or hand the DDL to a DBA for review — but it is optional, and importing it changes nothing about how the resource behaves.

{% hint style="warning" %}
If you see `SQL.sql not found - skipping schema auto-install`, the file was removed from the resource root. The resource will still start, but every query against a table that does not already exist will fail. Restore the file or import it manually.
{% endhint %}

The full table and column list is on the [Database](/docs/script-resources/tyrix-multi-job/database.md) page.

## Dependencies

| Dependency         | Required         | Purpose                                          |
| ------------------ | ---------------- | ------------------------------------------------ |
| `ox_lib`           | Yes              | Zones, TextUI, server callbacks, notifications.  |
| `oxmysql`          | Yes              | Database driver.                                 |
| `es_extended`      | One of the three | Framework — ESX.                                 |
| `qb-core`          | One of the three | Framework — QBCore.                              |
| `qbx_core`         | One of the three | Framework — QBox.                                |
| `esx_addonaccount` | Yes              | Society fund accounts — used on every framework. |
| `ox_target`        | Optional         | Only when `interactionType` is `'target'`.       |
| `qb-target`        | Optional         | Only when `interactionType` is `'qb-target'`.    |

`ox_lib` and `oxmysql` are declared as hard dependencies in the manifest, so the resource refuses to start without them. The rest are checked at runtime.

Society funds live in `esx_addonaccount` under account names of the form `society_<jobname>` — `society_police`, `society_mechanic`, and so on. You do not have to create those accounts. The first time a boss menu touches a society that has no account, tyrix\_multijob inserts the `addon_account` row and asks `esx_addonaccount` to refresh its registry, so the account exists from that point on with a zero balance. If you already have society accounts from other scripts, their existing balances are used untouched.

Neither target resource is needed if you run `interactionType = 'zones'`.

## Framework support

| Framework | Status |
| --------- | ------ |
| ESX       | ✅      |
| QBCore    | ✅      |
| QBox      | ✅      |

Detection is automatic. `Config.Framework = 'auto'` checks which framework resource is started — `qbx_core` first, then `qb-core`, then `es_extended` — and loads the matching bridge. The result is printed on boot:

```
[tyrix_multijob] ready | framework esx | locale en | 23 jobs | 6 tables | hours on | discord off
```

Leave it on `'auto'` unless you run more than one framework resource side by side. A QBox server still has `qb-core` started, for instance, which is why the check is ordered most-specific first.

If you need to force it, set the value explicitly:

```lua
Config.Framework = 'esx' -- 'auto' | 'esx' | 'qbcore' | 'qbox'
```

## Jobs come from your framework

tyrix\_multijob does not create jobs. It tracks **which of your framework's jobs each player holds**, and gives bosses a menu for the society behind them. On start it reads your `jobs` and `job_grades` tables to build its internal job list, then prints how many it found. Anything you reference in `Config.bossMenus.locations` must already exist there, or the job will not resolve and the boss menu for it will never open.

The same applies to ranks. Promotions, demotions and salary edits operate on rows that already exist in `job_grades` — a rank that is not in that table cannot be assigned. The resource never inserts grades of its own.

There is no "add job" button anywhere in the UI. A job is saved to a player's list **automatically**, the moment your framework assigns it to them — from a whitelist script, an admin command, a job-centre resource, anything. Nothing else in your server needs to be aware tyrix\_multijob exists.

The two exceptions are the off-duty job in `Config.offDutyJob` and any job listed in `Config.blacklist`, which are ignored on purpose so temporary states like `prisoner` never end up as a career.

{% hint style="warning" %}
`Config.bossMenus.bossGrades` is matched against the grade's **`name`** column in `job_grades`, not its `label` and not its numeric grade. The shipped default is `['boss'] = true`, which matches any grade whose `name` is `boss` — a rank whose label reads `Chief of Police` very often has exactly that name. Getting this wrong is the single most common reason a boss stands on their own boss menu and nothing happens.
{% endhint %}

## Verifying the install

A clean boot prints exactly one line, and it tells you everything at once:

```
[tyrix_multijob] ready | framework esx | locale en | 23 jobs | 6 tables | hours on | discord off
```

Read across it: the framework was detected, your locale file loaded, the jobs cache was built, the schema installed, and hour tracking and Discord logging report their state. If that line never appears, boot did not finish and whatever is printed above it explains why.

If the job count is `0`, the resource connected to the database but found nothing in `jobs` — usually the wrong database in your connection string, or a QBCore install whose jobs were never written to the table. The resource says so explicitly with a yellow warning right after the ready line.

Then smoke test in-game:

{% stepper %}
{% step %}

## Open the jobs menu

Run the jobs command (`/jobs` by default, or press the configured key) as any player. The menu should open and list whatever jobs that character already holds. An empty list on a brand-new character is correct — jobs appear as the framework assigns them.
{% endstep %}

{% step %}

## Test the boss menu

Set yourself to a job and grade whose `job_grades.name` is in `bossGrades`, then stand at one of your configured `locations`. In `'zones'` mode you get the TextUI prompt; in target mode the option appears in the third eye.
{% endstep %}

{% step %}

## Check society funds

Open the boss menu and check the balance reads correctly. If deposits and withdrawals show as locked, that is expected within the last ten minutes before a txAdmin scheduled restart — fund transfers are frozen in that window so money in flight cannot be lost to the restart, and they unlock by themselves once the server is back.
{% endstep %}
{% endstepper %}

If any of that misbehaves, [Troubleshooting](/docs/script-resources/tyrix-multi-job/troubleshooting.md) covers the usual causes.

One thing worth knowing before you go looking for it: setting a rank's salary from the boss menu writes to `job_grades.salary`. This resource does not run a paycheck loop of its own — your framework pays that value out on its normal schedule. Salary editing is also off by default (`Config.bossMenus.salaryManagement = false`); turn it on only if you want bosses controlling their own payroll.

## Next steps

* Every setting explained → [Configuration](/docs/script-resources/tyrix-multi-job/configuration.md)
* The command and keybind → [Commands](/docs/script-resources/tyrix-multi-job/commands.md)
* What your bosses can do → [Boss Menu](/docs/script-resources/tyrix-multi-job/boss-menu.md)
