Arquitetura do sistema jurídico
Um tribunal e um sistema jurídico elevam um servidor de roleplay FiveM de um jogo básico de policiais e ladrões para uma sociedade estruturada onde as leis têm peso e as consequências seguem o devido processo. O sistema abrange mandados que a polícia utiliza para autorizar buscas e detenções, um fluxo de trabalho de audiências judiciais onde os casos são apresentados a um juiz, funções de defesa e acusação para advogados, um sistema de gestão de provas que rastreia provas físicas e digitais, e um quadro de sentenças para multas, penas de prisão e punições alternativas. A arquitetura centra-se em um banco de dados de gerenciamento de casos que rastreia todos os procedimentos legais, desde a acusação inicial até a acusação, julgamento e veredicto. Cada caso está vinculado às partes envolvidas, suas funções, evidências apresentadas e o resultado final. Esses dados persistem permanentemente, construindo um histórico legal para o servidor que jogadores e árbitros podem consultar em processos futuros.
Esquema de banco de dados para registros legais
Seu banco de dados precisa lidar com mandados, processos judiciais, itens de provas e registros legais. O esquema liga as investigações policiais aos processos judiciais através de um sistema de provas partilhadas onde os itens recolhidos durante uma investigação se tornam provas apresentadas no julgamento. Projete as tabelas para manter uma trilha de auditoria completa de cada ação tomada em um processo legal:
CREATE TABLE IF NOT EXISTS warrants (
id INT AUTO_INCREMENT PRIMARY KEY,
type ENUM('arrest', 'search', 'bench') NOT NULL,
target_citizenid VARCHAR(50) NOT NULL,
target_name VARCHAR(100) NOT NULL,
reason TEXT NOT NULL,
issued_by VARCHAR(50) NOT NULL,
approved_by VARCHAR(50) DEFAULT NULL,
status ENUM('pending', 'active', 'executed', 'expired', 'revoked') DEFAULT 'pending',
issued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NULL,
executed_at TIMESTAMP NULL,
INDEX idx_target (target_citizenid),
INDEX idx_status (status)
);
CREATE TABLE IF NOT EXISTS court_cases (
id INT AUTO_INCREMENT PRIMARY KEY,
case_number VARCHAR(20) UNIQUE NOT NULL,
defendant_citizenid VARCHAR(50) NOT NULL,
defendant_name VARCHAR(100) NOT NULL,
prosecutor_citizenid VARCHAR(50) DEFAULT NULL,
defense_citizenid VARCHAR(50) DEFAULT NULL,
judge_citizenid VARCHAR(50) DEFAULT NULL,
charges TEXT NOT NULL,
status ENUM('filed', 'arraignment', 'pretrial', 'trial', 'verdict', 'closed', 'dismissed') DEFAULT 'filed',
plea ENUM('not_guilty', 'guilty', 'no_contest') DEFAULT NULL,
verdict ENUM('guilty', 'not_guilty', 'mistrial', 'dismissed') DEFAULT NULL,
sentence TEXT DEFAULT NULL,
fine_amount INT DEFAULT 0,
jail_minutes INT DEFAULT 0,
filed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
hearing_scheduled TIMESTAMP NULL,
closed_at TIMESTAMP NULL,
INDEX idx_defendant (defendant_citizenid),
INDEX idx_status (status)
);
CREATE TABLE IF NOT EXISTS evidence (
id INT AUTO_INCREMENT PRIMARY KEY,
case_id INT DEFAULT NULL,
type ENUM('physical', 'digital', 'testimony', 'document', 'photo') NOT NULL,
label VARCHAR(200) NOT NULL,
description TEXT DEFAULT NULL,
collected_by VARCHAR(50) NOT NULL,
collected_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
chain_of_custody TEXT DEFAULT NULL,
is_admitted BOOLEAN DEFAULT FALSE,
FOREIGN KEY (case_id) REFERENCES court_cases(id)
);
CREATE TABLE IF NOT EXISTS legal_records (
id INT AUTO_INCREMENT PRIMARY KEY,
citizenid VARCHAR(50) NOT NULL,
record_type ENUM('conviction', 'acquittal', 'fine', 'warning', 'restraining_order') NOT NULL,
description TEXT NOT NULL,
case_id INT DEFAULT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expunged BOOLEAN DEFAULT FALSE,
INDEX idx_citizen (citizenid),
FOREIGN KEY (case_id) REFERENCES court_cases(id)
);Sistema de Garantia
Os mandados são a porta de entrada legal entre a investigação e a ação policial. Um mandado de prisão autoriza os policiais a deter uma pessoa específica, um mandado de busca permite a busca em uma propriedade ou veículo e um mandado de prisão é emitido por um juiz quando alguém não comparece ao tribunal. Os policiais criam solicitações de mandados por meio do MDT que ficam em uma fila pendente para análise judicial. Um juiz ou funcionário autorizado analisa a solicitação, examina a descrição da causa provável e aprova ou nega. Os mandados aprovados tornam-se ativos e aparecem no MDT da polícia quando os policiais interagem com o indivíduo visado, alertando-o de que existe um mandado. Implemente a expiração do mandado para que os mandados não durem para sempre, com mandados de prisão com duração de 7 dias em tempo real e mandados de busca e apreensão com duração de 48 horas após a aprovação:
-- Warrant request by police
RegisterNetEvent('legal:server:requestWarrant', function(data)
local src = source
local Officer = QBCore.Functions.GetPlayer(src)
if not Officer or Officer.PlayerData.job.name ~= 'police' then return end
local warrant = {
type = data.type,
target_citizenid = data.targetCitizenid,
target_name = data.targetName,
reason = data.reason,
issued_by = Officer.PlayerData.citizenid,
}
local id = MySQL.insert.await(
'INSERT INTO warrants (type, target_citizenid, target_name, reason, issued_by) VALUES (?, ?, ?, ?, ?)',
{ warrant.type, warrant.target_citizenid, warrant.target_name, warrant.reason, warrant.issued_by }
)
-- Notify judges
local players = QBCore.Functions.GetQBPlayers()
for _, player in pairs(players) do
if player.PlayerData.job.name == 'judge' then
TriggerClientEvent('legal:client:warrantPending', player.PlayerData.source, {
id = id,
type = warrant.type,
targetName = warrant.target_name,
reason = warrant.reason,
officerName = Officer.PlayerData.charinfo.firstname .. ' ' .. Officer.PlayerData.charinfo.lastname,
})
end
end
TriggerClientEvent('QBCore:Notify', src, 'Warrant request submitted for judicial review', 'success')
end)
-- Judge approval
RegisterNetEvent('legal:server:approveWarrant', function(warrantId)
local src = source
local Judge = QBCore.Functions.GetPlayer(src)
if not Judge or Judge.PlayerData.job.name ~= 'judge' then return end
local warrant = MySQL.single.await('SELECT * FROM warrants WHERE id = ? AND status = "pending"', { warrantId })
if not warrant then return end
local expiryHours = warrant.type == 'search' and 48 or 168
local expiresAt = os.date('!%Y-%m-%d %H:%M:%S', os.time() + (expiryHours * 3600))
MySQL.update('UPDATE warrants SET status = "active", approved_by = ?, expires_at = ? WHERE id = ?',
{ Judge.PlayerData.citizenid, expiresAt, warrantId })
-- Notify requesting officer if online
TriggerClientEvent('QBCore:Notify', src, 'Warrant #' .. warrantId .. ' approved', 'success')
end)Fluxo de trabalho de audiência judicial
As audiências judiciais seguem um fluxo de trabalho estruturado que conduz os casos através de acusação, moções pré-julgamento, julgamento e sentença. Quando um caso é arquivado, o sistema gera um número de caso exclusivo e atribui a ele o status de arquivado. Um juiz analisa o caso e agenda uma audiência de acusação onde o réu apresenta uma contestação. Se o arguido se declarar inocente, o caso segue para o pré-julgamento, onde os advogados podem apresentar petições e provas, e depois para o julgamento, onde ambas as partes apresentam os seus argumentos. O juiz controla o fluxo da audiência por meio de comandos que avançam o status do caso e acionam atualizações da IU para todos os participantes. Implemente uma NUI de tribunal que exiba as informações do caso, a fase atual e forneça controles específicos da função para o juiz, promotor e advogado de defesa. O juiz recebe botões de veredicto e informações sobre a sentença, enquanto os advogados recebem botões de objeção e controles de apresentação de evidências.
Função do advogado e sistema de defesa
O trabalho de advogado cria uma carreira completa no servidor com mecânicas de jogo distintas. Os advogados de defesa podem ser contratados pelos réus por meio de um diretório de advogados acessível na prisão ou pelo aplicativo de telefone. Quando um advogado aceita um cliente, ele obtém acesso ao processo no sistema jurídico, incluindo todas as provas apresentadas pela acusação. Os advogados podem apresentar moções para suprimir provas, solicitar adiamento de audiências, negociar acordos de confissão com o procurador e apresentar as suas próprias provas e depoimentos de testemunhas durante o julgamento. Implemente um sistema de exame da ordem onde os novos personagens advogados devem passar por um teste de conhecimento antes de receberem o cargo de advogado, garantindo um nível mínimo de qualidade de interpretação jurídica. Acompanhe as estatísticas dos advogados, como casos vencidos, casos perdidos e redução média de penas para seus clientes, criando um mercado competitivo onde advogados estabelecidos podem cobrar honorários mais elevados:
Config.LawyerSystem = {
barExamQuestions = 15,
passingScore = 11, -- 73% to pass
examCooldown = 86400, -- 24 hours between attempts
maxActiveClients = 5,
consultationFee = 500, -- base fee for initial consultation
trialFeeRange = { min = 2000, max = 25000 },
motionTypes = {
{ id = 'suppress_evidence', label = 'Motion to Suppress Evidence', description = 'Request exclusion of illegally obtained evidence' },
{ id = 'dismiss_charges', label = 'Motion to Dismiss', description = 'Request dismissal due to insufficient evidence' },
{ id = 'continuance', label = 'Motion for Continuance', description = 'Request to postpone the hearing' },
{ id = 'change_venue', label = 'Motion for Change of Venue', description = 'Request trial at different location' },
{ id = 'bail_reduction', label = 'Motion for Bail Reduction', description = 'Request lower bail amount' },
{ id = 'expungement', label = 'Motion for Expungement', description = 'Request to clear prior conviction' },
},
}
-- Hire a lawyer from jail
RegisterNetEvent('legal:server:hireLawyer', function(lawyerCitizenid)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local citizenid = Player.PlayerData.citizenid
-- Find active case for this player
local activeCase = MySQL.single.await(
'SELECT * FROM court_cases WHERE defendant_citizenid = ? AND status NOT IN ("closed", "dismissed") ORDER BY filed_at DESC LIMIT 1',
{ citizenid }
)
if not activeCase then
TriggerClientEvent('QBCore:Notify', src, 'No active case found', 'error')
return
end
-- Assign lawyer to case
MySQL.update('UPDATE court_cases SET defense_citizenid = ? WHERE id = ?',
{ lawyerCitizenid, activeCase.id })
-- Notify lawyer
local lawyerPlayer = QBCore.Functions.GetPlayerByCitizenId(lawyerCitizenid)
if lawyerPlayer then
TriggerClientEvent('QBCore:Notify', lawyerPlayer.PlayerData.source,
'New client: ' .. Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname ..
' | Case #' .. activeCase.case_number, 'success')
end
TriggerClientEvent('QBCore:Notify', src, 'Attorney assigned to your case', 'success')
end)Sistema de gerenciamento de evidências
O sistema de evidências fornece uma cadeia de custódia que conecta a investigação da cena do crime à apresentação no tribunal. Quando a polícia coleta evidências em um local usando um comando de coleta de evidências, o sistema cria um registro de evidências com a identidade, data e hora e localização do policial que fez a coleta. Cada evidência recebe um identificador exclusivo que persiste durante todo o processo legal. Os tipos de evidências incluem itens físicos como armas, drogas e roupas, evidências digitais como registros telefônicos e imagens de CFTV, depoimentos de testemunhas registrados como entradas de texto e documentos como registros financeiros ou identidades falsas. Os advogados podem contestar a admissibilidade das provas por meio de moções que questionem o método de coleta ou a cadeia de custódia. O juiz analisa esses pedidos e pode marcar as provas como inadmissíveis, retirando-as dos autos. Implemente um armário de evidências na delegacia onde as evidências físicas são armazenadas, usando a integração do sistema de inventário para rastrear os itens reais coletados durante as investigações.
Mecânica de multa e fiança
Multas e fiança criam consequências económicas no sistema jurídico. Quando um réu é indiciado, o juiz define o valor da fiança com base na gravidade das acusações e no histórico criminal do réu. O réu pode pagar fiança através do sistema judicial para ser libertado da custódia enquanto aguarda julgamento, ou permanecer na prisão até a audiência. O pagamento da fiança é descontado da conta bancária do jogador e é reembolsado após a conclusão do caso, se o réu compareceu a todas as audiências. Se o réu não comparecer, a fiança será executada e um mandado de prisão será emitido. As multas são impostas como parte da sentença e devem ser pagas dentro de um prazo definido. Multas não pagas acumulam juros e podem desencadear consequências legais adicionais, como suspensão da carteira de motorista ou gravames de propriedade. Implementar um sistema de plano de pagamento de multas pesadas onde o réu possa fazer parcelas semanais em vez de pagar o valor total de uma só vez, acrescentando uma obrigação financeira persistente que mantém o sistema jurídico relevante para a experiência diária do jogador no servidor.
Comandos e sentenças do juiz
Os juízes precisam de um conjunto de comandos abrangente para gerir os processos judiciais e fazer cumprir o sistema jurídico. Os comandos principais incluem /case para visualizar e gerenciar casos, /warrant para aprovar ou negar solicitações de mandado, /sentence para emitir penas de prisão e multas, /bail para definir valores de fiança, /gag para silenciar jogadores perturbadores durante as audiências e /contempt para prender jogadores que desrespeitam o tribunal. O comando de sentença deve fazer referência a uma configuração de código penal que defina sentenças mínimas e máximas para cada acusação, garantindo consistência entre diferentes juízes. Implementar um sistema de diretrizes de sentença que sugira punições apropriadas com base nas acusações e no histórico criminal do réu, ao mesmo tempo em que permite aos juízes a discricionariedade para se desviarem com justificativa. Armazene todas as decisões judiciais na tabela de registros legais para que o servidor construa um conjunto de precedentes que jogadores experientes possam consultar em processos futuros. Adicione um processo de revisão judicial onde as sentenças podem ser apeladas a um juiz ou painel de alto escalão, criando camadas adicionais de dramatização jurídica para jogadores dedicados.
Integração com Polícia, Prisão e MDT
O sistema jurídico deve integrar-se perfeitamente com os recursos existentes da polícia, das prisões e da MDT para formar um canal de justiça coeso. Quando a polícia apresenta acusações através do MDT, o sistema deve criar automaticamente um processo judicial com o número de processo apropriado e ligar quaisquer provas já recolhidas durante a investigação. Quando um juiz condena um réu à prisão, o sistema deve chamar diretamente a função de exportação de prisão do recurso prisional para que a sentença flua automaticamente sem exigir que um policial execute manualmente um comando de prisão. Os mandados activos devem aparecer no MDT da polícia quando os agentes procuram um cidadão, com indicadores claros que mostram o tipo de mandado, a autoridade emissora e a data de validade. Os registos criminais gerados por sentenças judiciais devem estar acessíveis no MDT sob o perfil do cidadão, mostrando o seu historial jurídico completo, incluindo condenações, absolvições, casos activos e multas pendentes. Exporte todas as funções do sistema jurídico para que outros recursos possam verificar o status do mandado, verificar as credenciais dos advogados, consultar registros criminais e interagir com o sistema judicial de maneira programática.

