>
Guide 2026-04-14

Système judiciaire et tribunal pour FiveM

OntelMonke

OntelMonke

Administrateur et développeur chez Agency Scripts

Architecture du système juridique

Un système judiciaire et judiciaire élève un serveur de jeu de rôle FiveM du jeu de base de flics et de voleurs à une société structurée où les lois ont du poids et où les conséquences suivent une procédure régulière. Le système comprend des mandats que la police utilise pour autoriser les perquisitions et les arrestations, un déroulement des audiences judiciaires où les affaires sont présentées devant un juge, des rôles de défense et de poursuite pour les avocats, un système de gestion des preuves qui suit les preuves physiques et numériques et un cadre de détermination des amendes, des peines de prison et des peines alternatives. L'architecture est centrée sur une base de données de gestion de cas qui suit chaque procédure judiciaire depuis l'accusation initiale jusqu'à la mise en accusation, le procès et le verdict. Chaque cas est lié aux parties impliquées, à leurs rôles, aux preuves soumises et au résultat final. Ces données persistent de manière permanente, créant ainsi un historique juridique pour le serveur auquel les joueurs et les officiels pourront se référer lors de procédures futures.

Schéma de base de données pour les documents juridiques

Ton base de données doit gérer les mandats, les affaires judiciaires, les éléments de preuve et les dossiers juridiques. Le schéma relie les enquêtes policières aux procédures judiciaires grâce à un système de preuves partagées dans lequel les éléments collectés au cours d'une enquête deviennent des pièces à conviction présentées au procès. Concevez les tableaux pour conserver une piste d'audit complète de chaque action entreprise dans le cadre d'une procédure judiciaire :

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)
);

Système de garantie

Les mandats d’arrêt constituent la passerelle juridique entre l’enquête policière et l’action. Un mandat d'arrêt autorise les agents à détenir une personne spécifique, un mandat de perquisition permet de fouiller une propriété ou un véhicule et un mandat d'arrêt est délivré par un juge lorsqu'une personne ne se présente pas au tribunal. Les agents de police créent des demandes de mandat via le MDT qui sont placées dans une file d'attente en attente de contrôle judiciaire. Un juge ou un fonctionnaire autorisé examine la demande, examine la description de la cause probable et l'approuve ou la refuse. Les mandats approuvés deviennent actifs et apparaissent sur le MDT de la police lorsque les agents interagissent avec la personne ciblée, l'avertissant de l'existence d'un mandat. Mettez en œuvre l'expiration des mandats afin que les mandats ne persistent pas éternellement, avec des mandats d'arrêt d'une durée de 7 jours en temps réel et des mandats de perquisition d'une durée de 48 heures après l'approbation :

-- 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)

Flux de travail des audiences du tribunal

Les audiences judiciaires suivent un flux de travail structuré qui fait avancer les affaires jusqu'à la mise en accusation, les requêtes préalables au procès, le procès et la détermination de la peine. Lorsqu'un dossier est déposé, le système génère un numéro de dossier unique et lui attribue le statut déposé. Un juge examine l'affaire et planifie une audience de mise en accusation au cours de laquelle le défendeur plaide. Si l'accusé plaide non coupable, l'affaire passe à la phase préliminaire où les avocats peuvent présenter des requêtes et des preuves, puis au procès où les deux parties présentent leurs arguments. Le juge contrôle le déroulement de l'audience grâce à des commandes qui font progresser l'état du dossier et déclenchent des mises à jour de l'interface utilisateur pour tous les participants. Implémentez une salle d'audience NUI qui affiche les informations sur l'affaire, la phase en cours et fournit des contrôles spécifiques au rôle du juge, du procureur et de l'avocat de la défense. Le juge obtient des boutons de verdict et des informations sur la détermination de la peine, tandis que les avocats disposent de boutons d'objection et de contrôles de présentation des preuves.

Rôle de l'avocat et système de défense

Le métier d’avocat crée tout un parcours de carrière sur le serveur avec des mécanismes de jeu distincts. Les avocats de la défense peuvent être engagés par les accusés via un répertoire d'avocats accessible depuis la prison ou via l'application téléphonique. Lorsqu’un avocat accepte un client, il a accès au dossier du système judiciaire, y compris à toutes les preuves soumises par l’accusation. Les avocats peuvent déposer des requêtes pour supprimer des preuves, demander des prolongations pour retarder les audiences, négocier des accords de plaidoyer avec le procureur et présenter leurs propres preuves et témoignages pendant le procès. Mettre en œuvre un système d'examen du barreau dans lequel les nouveaux personnages avocats doivent passer un test de connaissances avant de se voir attribuer le poste d'avocat, garantissant ainsi un niveau minimum de qualité de jeu de rôle juridique. Suivez les statistiques des avocats telles que les affaires gagnées, les affaires perdues et la réduction moyenne de la peine de leurs clients, créant ainsi un marché concurrentiel où les avocats établis peuvent facturer des honoraires plus élevés :

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)

Système de gestion des preuves

Le système de preuves fournit une chaîne de possession qui relie l'enquête sur les lieux du crime à la présentation en salle d'audience. Lorsque la police collecte des preuves sur une scène à l'aide d'une commande de collecte de preuves, le système crée un enregistrement de preuves avec l'identité, l'horodatage et l'emplacement de l'agent chargé de la collecte. Chaque élément de preuve reçoit un identifiant unique qui persiste tout au long du processus juridique. Les types de preuves comprennent des objets physiques tels que des armes, des drogues et des vêtements, des preuves numériques telles que des enregistrements téléphoniques et des images de vidéosurveillance, des témoignages enregistrés sous forme d'entrées de texte et des documents tels que des dossiers financiers ou de fausses pièces d'identité. Les avocats peuvent contester l’admissibilité des preuves en recourant à des requêtes qui remettent en question la méthode de collecte ou la chaîne de possession. Le juge examine ces requêtes et peut marquer les preuves comme irrecevables et les retirer du dossier. Mettez en place un casier à preuves au poste de police où les éléments de preuve physiques sont stockés, en utilisant l'intégration du système d'inventaire pour suivre les éléments réellement collectés au cours des enquêtes.

Mécanique des amendes et des cautions

Les amendes et les cautions ont des conséquences économiques au sein du système judiciaire. Lorsqu'un accusé est traduit en justice, le juge fixe le montant de la caution en fonction de la gravité des accusations et des antécédents criminels de l'accusé. L'accusé peut payer une caution par l'intermédiaire du système judiciaire pour être libéré en attendant son procès, ou rester en prison jusqu'à l'audience. Le paiement de la caution est déduit du compte bancaire du joueur et est remboursé une fois l'affaire terminée si l'accusé a assisté à toutes les audiences. Si le défendeur ne se présente pas, la caution est confisquée et un mandat d'arrêt est délivré. Les amendes sont imposées dans le cadre de la détermination de la peine et doivent être payées dans un délai déterminé. Les amendes impayées génèrent des intérêts et peuvent entraîner des conséquences juridiques supplémentaires telles que la suspension du permis de conduire ou des privilèges fonciers. Mettre en œuvre un système de plan de paiement des amendes pour les amendes importantes, dans lequel le défendeur peut effectuer des versements hebdomadaires plutôt que de payer le montant total en une seule fois, ajoutant ainsi une obligation financière persistante qui maintient le système juridique pertinent pour l'expérience quotidienne du joueur sur le serveur.

Ordres du juge et détermination de la peine

Les juges ont besoin d’un ensemble complet de commandes pour gérer les procédures judiciaires et faire respecter le système juridique. Les commandes principales incluent /case pour visualiser et gérer les dossiers, /warrant approuver ou refuser les demandes de mandat, /sentence d'imposer des peines de prison et des amendes, /bail fixer le montant de la caution, /gag pour couper le son aux acteurs perturbateurs pendant les audiences, et /contempt emprisonner les joueurs qui manquent de respect au terrain. Le commandement de détermination de la peine doit faire référence à une configuration du code pénal qui définit les peines minimales et maximales pour chaque accusation, garantissant ainsi la cohérence entre les différents juges. Mettre en œuvre un système de lignes directrices en matière de détermination de la peine qui suggère des sanctions appropriées en fonction des accusations et des antécédents criminels de l'accusé, tout en laissant aux juges le pouvoir discrétionnaire de s'écarter avec justification. Stockez toutes les décisions judiciaires dans le tableau des dossiers juridiques afin que le serveur crée un ensemble de précédents auquel les joueurs expérimentés pourront se référer lors de procédures futures. Ajoutez un processus de contrôle judiciaire dans lequel les peines peuvent faire l'objet d'un appel auprès d'un juge de rang supérieur ou d'un comité, créant ainsi des niveaux supplémentaires de jeu de rôle juridique pour les acteurs dévoués.

Intégration avec la police, la prison et MDT

Le système juridique doit s'intégrer de manière transparente aux ressources existantes de la police, des prisons et du MDT pour former un pipeline de justice cohérent. Lorsque la police dépose des accusations via le MDT, le système doit automatiquement créer un dossier judiciaire avec le numéro de dossier approprié et relier toutes les preuves déjà collectées au cours de l'enquête. Lorsqu'un juge condamne un accusé à une peine de prison, le système doit appeler directement la fonction d'exportation d'emprisonnement de la ressource pénitentiaire afin que la peine s'écoule automatiquement sans qu'il soit nécessaire qu'un policier exécute manuellement une commande d'emprisonnement. Les mandats actifs doivent apparaître sur le MDT de police lorsque les agents recherchent un citoyen, avec des indicateurs clairs indiquant le type de mandat, l'autorité d'émission et la date d'expiration. Les casiers judiciaires générés par les verdicts des tribunaux doivent être accessibles dans le MDT sous le profil du citoyen, montrant son historique juridique complet, y compris les condamnations, les acquittements, les affaires actives et les amendes impayées. Exportez toutes les fonctions du système juridique afin que d'autres ressources puissent vérifier l'état des mandats, vérifier les informations d'identification des avocats, rechercher des casiers judiciaires et interagir avec le système judiciaire par programmation.

Partager cet article

Prêt à améliorer votre serveur ?

Découvrez nos scripts FiveM premium dans la boutique Agency Scripts ou rejoignez notre communauté Discord pour le support et les mises à jour.