How to Build an MDT / Police Computer Script for a GTA Roleplay Server With AI
An MDT (Mobile Data Terminal) is the in-game police computer the tool officers open to look up a citizen, run a plate, write a report, file charges, issue a warrant, or post a BOLO. It's the backbone of serious police roleplay, and because it touches criminal records, evidence, and warrants, it's also where permissions and server-side validation matter most. A leaky MDT lets a non-cop read or edit the whole justice database.
This guide covers building an MDT as a permission-gated NUI app backed by oxmysql, integrating with your framework's player and vehicle data, for ESX and QBCore (and QBox). PlayDeck teaches you to build this with AI: you describe the screens and the rank permissions, steer the AI as it designs the database schema, the NUI, and the server callbacks, and verify that every lookup and write is gated to actual police before you ship it on Tebex.
Design the database schema first
An MDT is mostly a database app, so start with the schema. You'll typically need tables for profiles/records (linking a citizen id to mugshot notes, flags, and a criminal history), reports/incidents, charges, warrants, BOLOs, evidence, and bulletins/announcements. Run these as SQL against your database via oxmysql. Reference existing citizen data (names, IDs) from your framework's players table rather than duplicating it.
Think about relationships up front: a report links to citizens and charges; a warrant links to a citizen and an issuing officer; evidence links to a case. Getting the schema right means lookups and case management work cleanly later. When you steer an AI to build this, describe the entities and how they relate; the AI proposes the tables and SQL, and you review the keys and relationships before generating them. This is exactly where planning with the AI beats diving into UI first.
Build lookups: citizens, vehicles, and weapons
The core officer action is a search. A citizen lookup queries your players/characters table by name or ID and returns their profile, flags, warrants, and record. A vehicle lookup queries your owned-vehicles table by plate and returns the registered owner, plus any flags or BOLOs on that plate. A weapon/serial lookup resolves a weapon's serial (stored as item metadata in ox_inventory see the inventory guide) back to its registered owner.
Every one of these runs as a server callback: the NUI requests a search, the server first confirms the requester is on-duty police with permission, runs the parameterized query through oxmysql, and returns only the allowed fields. Use parameterized queries never string-concatenate user input into SQL, or you open the door to injection. Describe each lookup and its inputs to your AI; it writes the callback and query, and you verify both the permission gate and that queries are parameterized.
Add reports, charges, warrants, and BOLOs
Writing data is where roleplay happens. Officers file incident reports (title, narrative, involved citizens, attached charges), add charges from a configured penal code (each with a fine and jail time), issue warrants (which then surface on that citizen's profile and ideally flag them on lookups), and post BOLOs that other officers see on relevant profiles. Each write is a server callback that validates permission and the input, then inserts through oxmysql.
Surface active warrants and BOLOs prominently: when any officer looks up a flagged citizen or plate, the MDT should immediately show the warrant. Connect charges to your jail/sentencing system so filing them has consequences. Log who created or edited each record for accountability. When you build this with AI, give it the penal code structure and which ranks can do what; it scaffolds the forms and inserts, and you confirm that, for example, only a sergeant or above can clear a warrant server-side.
Lock it down with permissions and integration
Permissions are the whole ballgame. Gate the MDT itself behind the police/sheriff job server-side opening it, every lookup, and every write must re-check the caller's job and rank, never trust an open NUI. Make actions rank-based: a cadet can view, an officer can file reports, a sergeant can clear warrants, command can manage the department. Store these as a permission map and check it on every callback.
Integrate with the rest of your server: dispatch (incoming calls and units), the jail system (charges to sentences), and your phone or laptop item to open the MDT. Open it with F11 or /mdt, or as an app on a tablet/phone. Because the MDT holds the justice system's data, it's a script you build carefully, sell on Tebex with a Cfx.re license and escrow, and never distribute as a leak. PlayDeck's approach is to have you build it with AI while learning exactly these permission and SQL-safety habits.
Frequently asked questions
What database tables does an MDT need?
Typically profiles/records, reports/incidents, charges, warrants, BOLOs, evidence, and bulletins, created via SQL through oxmysql. Reference existing citizen and vehicle data from your framework's tables rather than duplicating it.
How do I stop non-police from accessing the MDT?
Gate everything server-side on the police job and rank opening the app and every lookup and write must re-check the caller's job. Never trust the client just because the NUI is open.
How does a plate lookup find the owner?
Query your owned-vehicles table by plate on the server and return the registered owner plus any flags or BOLOs. Run it as a permission-checked, parameterized server callback to avoid SQL injection.
How do warrants show up on a suspect?
Store warrants linked to a citizen id; when any officer looks that citizen (or their plate) up, the MDT queries active warrants and BOLOs and displays them prominently, alerting the officer immediately.
Can AI build a full MDT?
Yes, when steered. You define the schema, screens, and rank permissions; the AI proposes the SQL, NUI, and server callbacks. You verify permission gates and parameterized queries the build-and-review workflow PlayDeck teaches.