# Features

This page walks through each module. What an officer sees depends on the permissions of their rank, see [Departments and permissions](/new/mdt/departments-and-permissions). Pages without permission are hidden from the sidebar.

## Shell and search

The MDT opens as a tablet. It has browser-style tabs (back, forward, reload, middle-click to close), collapsible sidebar groups and a notification center. Press Ctrl+F to search across people, plates, reports and pages. Moving the mouse outside the tablet makes it semi-transparent (`Config.Ui.fadeOutside`).

## Dashboard

The dashboard has a welcome bar with the duty toggle, KPI cards with 7-day bars, online employees with a division filter, the mail inbox, the notification center, bulletins and record counters. EMS departments see EMS cards (patients today, open EMS calls, beds, unpaid bills, units on duty, latest reports) and a panel with downed patients when koja-ambulance is linked.

Bulletins are department announcements. Creating them needs `bulletins.manage`.

## Dispatch and voice

Players call with `/911`, `/311` or the anonymous `/911a`. Officers press F9 for the panic button (10-99). Calls show up with a blip and sound for priority calls.

In the MDT, dispatchers and officers can:

- respond to a call, leave it, close it, add notes;
- create calls manually (with a GPS position) and assign units;
- set their unit status from the unit board (10-8, 10-6, 10-97, 10-23, 10-38, 10-7 and the EMS, fire and DOJ variants);
- set a GPS waypoint to the call.

Field departments (`leo`, `ems`, `fire` by default) receive calls that target them. A call with no target goes to law enforcement only. Extra call codes, including fire codes, come from `Config.Dispatch.callCodes`.

**Dispatcher voice.** A radio dispatcher reads new calls, panic alerts and responding units aloud while the officer is on duty, even with the MDT closed. Voice clips ship for English and Polish. If a clip is missing the interface falls back to speech synthesis. Each officer can switch the voice off and set the volume in Settings. Server options are in `Config.DispatchVoice`.

### Gunshot alerts

Gunfire creates a "Shots fired" call (`10-71`, priority 1) for law enforcement on its own, with a witness as the caller. The call appears 3 to 8 seconds after the shot, and its location is offset by up to 35 meters. Shots near a recent alert are merged into it, and one player can raise at most one alert every 30 seconds. Police on duty, silenced weapons, non-lethal weapons and shooting ranges are ignored. Everything is set in `Config.Dispatch.gunshots`.

## Quick dispatch

A compact overlay on screen for new calls while the MDT is closed. Keys: `Y` respond, `Delete` dismiss, `Page Up` and `Page Down` to move between calls, `Home` to show or hide. All keys can be rebound in the FiveM keybind settings. See `Config.QuickDispatch`.

## People

Search by name, phone or ID. A person's file has a photo, flags (armed, gang, parole and the others from `Config.ProfileTags`), licenses (revoke and reinstate with `licenses.revoke`), a criminal record summary, vehicles, firearms, warrants, BOLOs, court cases, a photo gallery, fingerprint and DNA data. New citation is available from the file. Medical summary appears for allowed police ranks only when `Config.Ems.policeSummary.enabled` is on.

## Vehicles and ANPR

Plate search with owner link, flags (stolen, wanted, impounded and others), strike points with a limit warning, BOLO and warrant alerts and history. The scan vehicle ahead function reads the vehicle in front of the officer.

**ANPR.** Plate readers work in two places:

- CCTV cameras read plates in range (`Config.Cameras.anpr`).
- In-vehicle ALPR on police models (`Config.Anpr.vehicle`). A panel shows the front and rear plate with hit history. Keys: toggle `F10`, lock front `Up`, lock rear `Down`, open in the MDT `Right`.

A hit (stolen, BOLO, warrant, or a flag from `Config.Anpr.hitFlags`) can create a dispatch call with code `10-ALPR`. Hits are logged to the ANPR log.

## Firearms

A serial registry with owner, model and status (stolen, seized, evidence). Other scripts can register weapons with the `RegisterWeapon` export, see [Server exports](/new/mdt/api/server-exports).

## Reports and sentencing

There are eight report types (arrest, citation, traffic collision, vehicle pursuit, investigation, use of force, death investigation, general), each with a template. Reports hold a narrative, officers, suspects, victims and witnesses, vehicles, tags, photos and links to evidence, warrants and cases. A report can be marked restricted so only ranks with `incidents.restricted` see it.

**Sentencing.** For each suspect the officer picks charges from the penal code with counts and modifiers (attempted, accessory and similar), sets a reduction percentage and the plea, then processes the suspect. Processing:

- takes the fine from the bank and falls back to cash, and pays the society account;
- sends the player to jail through your jail script;
- adds license points and revokes the license at the limit;
- serves matching arrest warrants automatically.

Rules are in `Config.Processing`. The suspect must be online and near the officer by default.

## Penal code

The 57 charges from `shared/penalcode.lua` are seeded into the database on first start. After that they are edited in the MDT by ranks with `charges.manage` (judges and command by default). Each charge has a code, label, category, class (infraction, misdemeanor, felony), fine, months and points.

## Citations

Officers write tickets from the Citations page or the New citation button on a person. In game this opens the ticket book (`/citation`):

1. The book opens with the number, date, unit, location and the nearest player and vehicle filled in.
2. The officer adds violations (quick chips or search), checks the fields and signs.
3. The officer picks who takes the ticket among players in range and tears it off. The server re-checks permission, distance, cooldown and recalculates the fine from the penal code.
4. The other player sees the ticket and chooses Sign or Refuse to sign. After the answer, or after the timeout, they get the `citation` item.
5. File without handing over files the ticket without giving anyone the paper (parking, absent drivers).

Using the item shows the paper, where the violator can pay or contest. Tickets also appear on the person's record and in the citizen web portal under My tickets. Overdue tickets get a late fee. A contest can file a court case. Options are in `Config.Citations`.

## Warrants

Arrest, search, vehicle and bench warrants with an expiry. With `Config.Records.warrantsNeedApproval` they go through a judge: approve or deny with a note. Warrants can be marked served or cancelled. Expired warrants are closed automatically.

## BOLOs

Person, vehicle or general BOLOs with priority and photo. Creating one broadcasts a toast to every unit.

## Evidence

An evidence locker with a chain of custody log, status changes, photos and a link to the report. Types come from `Config.EvidenceTypes`.

## Custody (jail and impound)

The Custody page has two parts. Jail lists people serving a sentence with the time left and a history. Impound lists vehicles held in a lot with the fee and hold period. Records also appear on the person and vehicle pages.

- Jail records are created when a suspect is processed in the MDT or a sentence is applied in court. Jail and prison scripts can report their own sentences and releases, see [Integrations](/new/mdt/integrations) and the [API overview](/new/mdt/api/overview).
- Supervisors can release early, change the term and transfer.
- Impound runs the impound adapter, records the fee and hold and sets the vehicle's impounded flag. Release clears it.
- With `Config.Custody.autoRelease` records close when the time is up.

Options: `Config.Custody`.

## Court and DOJ

The docket lists cases with defendant, judge, prosecutor, defense, courtroom, hearing date, status, verdict and sentence. Features:

- case management with charges and linked records (reports, evidence, bodycams, warrants, citations, documents);
- hearing scheduling (arraignment, preliminary, motion, trial, sentencing, appeal);
- docket filings and rulings, also from parties assigned to the case;
- carrying out a sentence (fine and jail) for online defendants;
- expungement requests with review, also through the citizen portal;
- a bar registry of attorneys, public defenders, prosecutors and judges;
- warrant approval for judges.

On first start the DOJ departments get four form templates (subpoena, search warrant order, court order, expungement order). Options: `Config.Doj`.

## EMS

Departments with `type = 'ems'` get a Medical section:

- patient records (medical profile, history, bills, admissions);
- ePCR treatment reports with vitals, body diagram injuries, treatments from a catalog, transport, outcome and crew;
- medical bills charged to bank, then cash, paid to the society;
- a hospital bed board with admissions and discharges.

With koja-ambulance started, the EMS MDT can import live vitals and injuries into an ePCR, show live patient status and ambulance records, follow its duty, mirror its calls and beds, and send bills as koja-ambulance invoices. Configure it in `Config.Ems.ambulance`.

## Fire

Departments with `type = 'fire'` use dispatch with the fire call codes (structure fire, vehicle fire, brush fire, alarm, rescue, hazmat) and fire unit statuses (including staging). They share the staff modules: roster, mail, calendar, divisions, certifications and forms.

## Roster

The employee list shows every member, online and offline, with status, rank, divisions, certificates, weekly hours and duty status. With `roster.manage` you can promote, demote, fire and hire a nearby player. Hiring uses `Config.Roster.hireGrade`, firing sets the job to `Config.Roster.fireJob`. `roster.discipline` gives rewards and strikes and `roster.suspend` suspends or reinstates.

A member's profile has a banner and photo, rank, phone, join date, last duty, badge, rewards and strikes, a 7 by 24 duty heatmap, divisions, certificates, permissions and suspension state.

## Divisions

Divisions such as Firearms, K-9, SWAT or Traffic exist per department. Each has a head, members, on-duty avatars and import and export templates. My divisions shows in the sidebar. Defaults come from `Config.Divisions`.

## Certifications

Qualifications per division with a status (active, disabled, on hold) and what they unlock. Assign and revoke from a member. Other scripts can check them with the `HasCertification` export, see [Server exports](/new/mdt/api/server-exports). Defaults come from `Config.Certifications`.

## Forms

A form builder with 8 field types (short text, long text, number, select, checkbox, date, person, image) and up to 50 fields per form. Forms are internal or public. Submissions go to a review queue where reviewers approve or reject with a note. After filing, the filer gets the `mdt_document` item that shows the signed document. Public forms can be filled by citizens in the web portal.

## Mail

Internal department email. Compose to officers or whole departments (whole departments need `mail.broadcast`), with inbox, unread, starred and sent folders, search, reply, reply all, forward, a signature and an important flag. A rich text editor is shared with reports, warrants, BOLOs and bulletins.

## Calendar

Department events with attendees, RSVP, reactions and comments, reminders before the start, and court hearings if `Config.Calendar.court` is on. Creating and editing needs `calendar.manage`.

## CCTV

Security cameras in the world, viewed from the MDT in a separate camera window. Switch between cameras with Q and E, zoom with the scroll wheel, and lock onto a vehicle to read its plate. Cameras are placed in game with a free camera by players holding the `koja-mdt.cameras` ace. Default cameras are seeded on first start (`Config.Cameras.seedDefaults`).

## Bodycams

Officers start and stop recording with F7 or `/bodycam` (`on`, `off`, `rec`, `stop`). Auto start triggers are configurable: sirens, drawn weapon, dispatch attach, panic or going on duty. Supervisors watch live (`bodycams.watch`) or review sessions with the route, shots and notes (`bodycams.view`). Sessions are kept for `Config.Bodycams.keepDays`. With `requireItem` the officer needs the `bodycam` item.

Recording uses `Config.Bodycams.recording`, 8 frames per second by default. See [Configuration](/new/mdt/configuration) for the frame rate options and their disk cost.

## Live map

A live map showing on-duty field units with their position and heading, for ranks with `dispatch.view`. Units from departments the viewer may not see are hidden.

## Admin panel

Open to holders of the `koja-mdt.admin` ace (and `command`, by default) and to ranks with `admin.view` or `admin.manage`. It offers:

- departments: edit label, short, colors, logo, jobs, ranks and permission lists; create, remove and reset departments (`Config.Admin.departmentOverrides`);
- jobs: edit jobs and grades on ESX (`Config.Admin.jobEditing`);
- officers: change a callsign, force off duty, reset web access;
- system: status of detected integrations, table row counts, online and on-duty counts, web portal state, purge old logs and expired web sessions.

## Audit log

Every action is logged to the database (auto purge after `Config.Logs.keepDays`) and optionally sent to Discord webhooks per category (`incidents`, `warrants`, `processing`, `roster`, `dispatch`). Viewing needs `logs.view`.

## Web portal

The resource serves its own web portal through the FXServer HTTP server, no extra hosting needed. It shows the same MDT in a browser or on a phone (responsive layout, can be added to the home screen).

**Sign in**

- One-time code: type `/mdtweb` in game. You get a 6-character code (valid `Config.Web.loginCodeMinutes` minutes, single use) and the address.
- Username and password: in the MDT open Settings, Web access, and set a username (3 to 24 characters: a-z, 0-9, `_`, `.`) and a password (8 or more characters). The same panel lists signed-in devices and lets you sign out one or all.

Officers see the MDT for their current job and rank even while offline. Actions that need a character in game (responding to a call, sentencing, hiring nearby, the duty toggle) are game-only.

**Citizen portal.** With `Config.Web.allowCitizens`, any player can sign in to the citizen portal: public forms (job applications, complaints), the status of their submissions, My tickets, expungement requests, and with `Config.Web.citizenRecord` their own record and licenses.

**Address**

| Case | Address |
|---|---|
| Default | The relay address `https://mdt.kojascripts.com/<server-id>/` when `Config.Web.relay.enabled` is on. |
| No relay | `https://<your-id>.users.cfx.re/<resource>/`, built from the `web_baseUrl` convar. |
| Your own domain | Set `Config.Web.publicUrl`, for example `https://mdt.example.com/`, and point a reverse proxy to `http://127.0.0.1:30120/koja-mdt/`. Set `Config.Web.trustProxyHeaders = true` so rate limits see real IPs. |
| Local test | `http://<server-ip>:30120/koja-mdt/`, plain HTTP. |

`Config.Web.publicUrl` wins over the relay. Sessions last `Config.Web.sessionDays` days and renew on use, with up to `Config.Web.maxSessionsPerAccount` devices. Turn the portal off with `Config.Web.enabled = false`.

## Interaction menu

A quick menu on the key `Left Alt` (command `mdtinteract`): Ask for ID, Write citation, Run plate, Parking citation, Open MDT. It plugs into a radial menu (koja-police, ox_lib, qb-radialmenu) or a target resource (ox_target, koja-interactions, qb-target) when one is started. Asking for ID prompts the other player, who can accept or refuse, and shows an ID card with licenses and status (warrant, BOLO, unpaid citations). Ranks that can only confirm identity see a limited card. See `Config.Interact`.

## Onboarding tour and tutorials

The first time an officer opens the MDT a short guided tour (the "MDT tour") starts by itself after a moment. It points at the real interface: navigation, search, the notification bell, dispatch, the profile, the tabs and Settings.

Longer hands-on walkthroughs live in Settings, in the Tutorials section. Each one highlights the real buttons and waits for the officer to click them. Only the tutorials the officer has access to through their permissions are shown. The section shows overall progress with a "Next up" suggestion, Start and Replay buttons and a Reset progress button.

| Group | Tutorials |
|---|---|
| Getting started | MDT tour |
| On patrol | Issue a citation, Look up a person, Check a vehicle and plate, Respond to dispatch calls |
| Investigations | Start a search: BOLO, Request a warrant, Write an arrest report, Evidence, jail and impound, Body cameras and recordings |
| Office | Mail and calendar |
| Your department | Court cases and warrant review, ePCR reports and billing, Running a department |

Progress is stored per officer in the `settings` column of `koja_mdt_officers`, under `settings.tutorials`: `tour` is the version of the intro tour the officer has seen and `done` is the list of finished tutorial ids. Reset progress clears `done` but keeps `tour`, so the first-open tour does not start again.

:::hint{type="info" title="For developers who build the UI"}
`TOUR_VERSION` in `web/src/components/tour/progress.ts` is the tour version. Raising it makes the tour start again for every officer who has seen an older version. It is part of the compiled UI, so the change needs a UI rebuild. Servers that use the released build cannot change it.
:::

## Settings and language

Settings holds the officer's own callsign, badge and photo (including a selfie and `/mdtphoto`), the personal accent color, dispatcher voice options, web access and the language. If `Config.Languages.playerChoice` is on, each player picks their own language and the choice applies to the MDT and to the game notifications they receive. See [Translations](/new/mdt/translations).
