# Installation

:::::steps
### Install the dependencies

koja-mdt needs these resources started before it:

- `oxmysql`
- your framework (`es_extended`, `qb-core` or `qbx_core`)
- [`koja-lib`](https://github.com/Koja-Scripts/koja-lib)

Optional: `screenshot-basic` for photo upload and selfies, and an inventory if you want item based features.

### Add the resource

Use the release zip. It contains the built interface in `web/build`. Put the `koja-mdt` folder in your resources directory.

### Edit server.cfg

Ensure koja-mdt after its dependencies:

```cfg title="server.cfg"
ensure oxmysql
ensure es_extended   # or qb-core / qbx_core
ensure koja-lib
ensure screenshot-basic   # optional
ensure koja-mdt
```

The manifest declares `oxmysql` and `koja-lib` as dependencies, so the resource will not start without them.

To keep bodycam footage and images on Cloudflare R2, S3 or Fivemanage instead of the server disk, add the storage keys to `server.cfg` with `set` (never in `shared/config.lua`). See [Storage and CDN](/new/mdt/storage).

### Database

Nothing to import by hand in a normal install. On every start the resource reads `koja-mdt.sql` and runs it statement by statement. Every statement is `CREATE TABLE IF NOT EXISTS`, so restarts are safe. Columns added in later versions are added automatically with `ALTER TABLE` when missing.

| File | What it is |
|---|---|
| `koja-mdt.sql` | All tables. Run automatically at start. |
| `sql/custody.sql`, `sql/divisions.sql`, `sql/admin.sql`, `sql/web.sql` | The same module tables, run again by their own modules at start. Safe to ignore. |
| `sql/mail.sql`, `sql/forms.sql` | Copies of the mail and forms tables, also contained in `koja-mdt.sql`. Safe to ignore. |
| `sql/jobs_fire.sql` | Optional and not run automatically. ESX only: adds a `fire` job with grades to the `jobs` and `job_grades` tables if it does not exist yet. Import it yourself if you want a ready LSFD job. |

The penal code from `shared/penalcode.lua` is seeded into the database on first start. After that, charges are edited in game. See [Database](/new/mdt/database) for the table list.

### Add inventory items (optional)

Items are only needed for the features below. If you do not use them, skip this step.

| Item | Config | Used for |
|---|---|---|
| `mdt_tablet` | `Config.Open.item` | Opening the MDT by using the item. Set `Config.Open.requireItem = true` to make the item mandatory. |
| `citation` | `Config.Citations.item` | Printed traffic citations. Using it shows the paper. |
| `mdt_document` | `Config.Forms.item` | A signed form document. Using it shows the document. |
| `bodycam` | `Config.Bodycams.item` | Body camera. Only required when `Config.Bodycams.requireItem = true`. |

Item names come from the config. Use the same names in your inventory.

::::tabs
:::tab{title="ox_inventory"}
Add to `ox_inventory/data/items.lua`. Items are made usable through koja-lib:

```lua title="ox_inventory/data/items.lua"
['mdt_tablet'] = {
    label = 'MDT Tablet',
    weight = 500,
    stack = false,
    close = true,
    server = { export = 'koja-lib.useItem' },
},
['citation'] = {
    label = 'Citation',
    weight = 10,
    stack = false,
    close = true,
    consume = 0,
    description = 'A printed traffic citation.',
    server = { export = 'koja-lib.useItem' },
},
['mdt_document'] = {
    label = 'Document',
    weight = 10,
    stack = false,
    close = true,
    consume = 0,
    description = 'A signed MDT document.',
    server = { export = 'koja-lib.useItem' },
},
['bodycam'] = {
    label = 'Body camera',
    weight = 150,
    stack = false,
    close = true,
    consume = 0,
    server = { export = 'koja-lib.useItem' },
},
```

`stack = false` keeps each citation separate with its own metadata. `consume = 0` means using the item does not remove it. The `citation` entry is the one from the official citations guide; the other three follow the same pattern.

Copy `docs/citation.png` and `docs/mdt_document.png` into `ox_inventory/web/images/`.
:::
:::tab{title="QBCore"}
Add to `qb-core/shared/items.lua`:

```lua title="qb-core/shared/items.lua"
mdt_tablet = { name = 'mdt_tablet', label = 'MDT Tablet', weight = 500, type = 'item', image = 'mdt_tablet.png', unique = true, useable = true, shouldClose = true, description = 'Mobile data terminal.' },
citation = { name = 'citation', label = 'Citation', weight = 10, type = 'item', image = 'citation.png', unique = true, useable = true, shouldClose = true, description = 'A printed traffic citation.' },
mdt_document = { name = 'mdt_document', label = 'Document', weight = 10, type = 'item', image = 'mdt_document.png', unique = true, useable = true, shouldClose = true, description = 'A signed MDT document.' },
bodycam = { name = 'bodycam', label = 'Body camera', weight = 150, type = 'item', image = 'bodycam.png', unique = true, useable = true, shouldClose = true, description = 'Department-issued body camera.' },
```
:::
:::tab{title="ESX (items table)"}
```sql
INSERT IGNORE INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES
  ('mdt_tablet', 'MDT Tablet', 1, 0, 1),
  ('citation', 'Citation', 1, 0, 1),
  ('mdt_document', 'Document', 1, 0, 1),
  ('bodycam', 'Body camera', 1, 0, 1);
```

If your inventory does not store item metadata, using a `citation` opens the latest citation written to that player.
:::
:::tab{title="koja_grid_inventory"}
Nothing to do. When `koja_grid_inventory` is started and `Config.Inventory.system` is `'auto'`, koja-mdt registers `citation`, `mdt_document` and `bodycam` itself from `Config.Inventory.items` (size, weight, image). Set `Config.Inventory.registerItems = false` to register them yourself, or `Config.Inventory.system = 'framework'` to use the framework inventory instead.
:::
::::

### Set ace permissions

Two optional aces are used. Add them to `server.cfg` for your admins:

```cfg title="server.cfg"
add_ace group.admin koja-mdt.admin allow
add_ace group.admin koja-mdt.debug allow
add_ace group.admin koja-mdt.cameras allow
add_principal identifier.license:xxxxxxxxxxxxxxxx group.admin
```

| Ace | Config | Grants |
|---|---|---|
| `koja-mdt.admin` | `Config.Admin.ace` | Full access to the Admin panel, even without an MDT rank. By default the generic `command` ace also works (`Config.Admin.allowCommandAce`). |
| `koja-mdt.debug` | `Config.DebugTools.aces` | The `/mdtdebug` demo and test commands. See [Demo mode](/new/mdt/demo-mode). The generic `command` ace also works. |
| `koja-mdt.cameras` | `Config.Cameras.adminAce` | Placing and editing CCTV cameras. |

:::hint{type="warning" title="Production"}
`command` is the ace of the server console and of players with full command rights. If you do not want those players to use the demo tools or the Admin panel, set `Config.Admin.allowCommandAce = false` and remove `'command'` from `Config.DebugTools.aces`, or turn the demo tools off with `Config.DebugTools.enabled = false`.
:::

### Map your jobs to departments

Open `shared/departments.lua` and make sure the `jobs` of each department match the job names on your server. A framework job that is not listed in any department has no MDT access. See [Departments and permissions](/new/mdt/departments-and-permissions).

### Restart and check the console

Start the server. The console prints a startup banner with the detected framework, jail, inventory, radial and target integrations. If a line says `none` for something you use, check that the resource is started before `koja-mdt` or set the option explicitly. See [Integrations](/new/mdt/integrations).
:::::

## First-run checklist

- [ ] Server starts without SQL errors in the console.
- [ ] `koja-lib`, `oxmysql` and your framework are started before `koja-mdt`.
- [ ] Your job names are listed in `shared/departments.lua`.
- [ ] Set `Config.Locale` to your server language. See [Translations](/new/mdt/translations).
- [ ] Join with a police job and press F6 or type `/mdt`. The tablet opens.
- [ ] Go on duty from the dashboard or with `/mdtduty`.
- [ ] Search a citizen and a plate to check the framework bridge returns data.
- [ ] Write a test report and process a suspect to check fine and jail. See `Config.Processing` in [Configuration](/new/mdt/configuration).
- [ ] If you use the tablet item, `Config.Open.requireItem` matches your inventory setup.
- [ ] If you want photos, `Config.Camera.uploadUrl` is set and `screenshot-basic` is started.
- [ ] Type `/mdtweb` and open the address to check the web portal.
- [ ] Before going live: decide whether the demo tools stay on (`Config.DebugTools.enabled`) and who has the admin aces.
