Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
-- ============================================================================
-- Nyxframework: nyx_parliament, nyx_treasury, nyx_ui
-- Migration: 067_campaign_finance_and_citizen_os_polling.sql
-- Description: Political Action Committees (PACs), statutory campaign finance donation
-- caps, independent PAC compliance auditing & statutory fines, and
-- Citizen OS mobile opinion surveys & voter sentiment polling.
-- Engine: InnoDB | Charset: utf8mb4 | Collation: utf8mb4_unicode_ci
-- ============================================================================

SET FOREIGN_KEY_CHECKS = 0;

-- 1. Political Action Committees (PACs) Registry
CREATE TABLE IF NOT EXISTS `nyx_parliament_pacs` (
`pac_id` VARCHAR(64) PRIMARY KEY,
`candidate_id` VARCHAR(64) NULL,
`office_id` VARCHAR(32) NULL,
`title` VARCHAR(128) NOT NULL,
`treasurer_citizen_id` VARCHAR(16) NOT NULL,
`balance` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
`total_donations_collected` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
`status` ENUM('active', 'audited', 'suspended', 'dissolved') NOT NULL DEFAULT 'active',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_pac_candidate` (`candidate_id`),
INDEX `idx_pac_office` (`office_id`),
INDEX `idx_pac_treasurer` (`treasurer_citizen_id`),
INDEX `idx_pac_status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 2. Campaign Finance Donations Ledger
CREATE TABLE IF NOT EXISTS `nyx_parliament_donations` (
`donation_id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`donation_uuid` VARCHAR(36) NOT NULL UNIQUE,
`pac_id` VARCHAR(64) NOT NULL,
`donor_citizen_id` VARCHAR(16) NOT NULL,
`donor_faction_id` VARCHAR(64) NULL,
`amount` DECIMAL(15, 2) NOT NULL,
`cap_limit_applied` DECIMAL(15, 2) NOT NULL DEFAULT 5000.00,
`compliance_status` ENUM('compliant', 'flagged_over_cap', 'refunded', 'audited') NOT NULL DEFAULT 'compliant',
`treasury_tx_uuid` VARCHAR(36) NULL,
`donated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_donation_pac` (`pac_id`),
INDEX `idx_donation_donor` (`donor_citizen_id`),
INDEX `idx_donation_compliance` (`compliance_status`),
INDEX `idx_donation_created` (`donated_at` DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 3. PAC Statutory Compliance Audits Ledger
CREATE TABLE IF NOT EXISTS `nyx_parliament_pac_audits` (
`audit_id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`audit_uuid` VARCHAR(36) NOT NULL UNIQUE,
`pac_id` VARCHAR(64) NOT NULL,
`auditor_citizen_id` VARCHAR(16) NOT NULL DEFAULT 'SYSTEM_PAC_AUDITOR',
`total_audited_contributions` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
`flagged_excess_amount` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
`fine_assessed` DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
`audit_status` ENUM('passed', 'violations_found', 'fines_assessed', 'cleared') NOT NULL DEFAULT 'passed',
`notes` VARCHAR(255) NULL,
`audited_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_pac_audit_pac` (`pac_id`),
INDEX `idx_pac_audit_status` (`audit_status`),
INDEX `idx_pac_audit_created` (`audited_at` DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 4. Citizen OS Mobile Opinion Surveys & Sentiment Polls
CREATE TABLE IF NOT EXISTS `nyx_parliament_polls` (
`poll_id` VARCHAR(64) PRIMARY KEY,
`title` VARCHAR(128) NOT NULL,
`description` TEXT NOT NULL,
`creator_citizen_id` VARCHAR(16) NOT NULL DEFAULT 'SYSTEM_GOV',
`poll_type` ENUM('approval_rating', 'policy_survey', 'civic_referendum') NOT NULL DEFAULT 'policy_survey',
`office_id` VARCHAR(32) NULL,
`options_json` JSON NOT NULL,
`total_responses` INT UNSIGNED NOT NULL DEFAULT 0,
`starts_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ends_at` TIMESTAMP NOT NULL,
`status` ENUM('active', 'concluded', 'archived') NOT NULL DEFAULT 'active',
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
INDEX `idx_poll_status` (`status`),
INDEX `idx_poll_office` (`office_id`),
INDEX `idx_poll_ends` (`ends_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 5. Citizen OS Mobile Poll Responses Registry
CREATE TABLE IF NOT EXISTS `nyx_parliament_poll_responses` (
`response_id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`poll_id` VARCHAR(64) NOT NULL,
`citizen_id` VARCHAR(16) NOT NULL,
`voter_hash` VARCHAR(64) NOT NULL,
`selected_option` VARCHAR(64) NOT NULL,
`device_os` VARCHAR(32) NOT NULL DEFAULT 'CitizenOS_Mobile',
`submitted_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY `uk_poll_citizen` (`poll_id`, `citizen_id`),
UNIQUE KEY `uk_poll_hash` (`poll_id`, `voter_hash`),
INDEX `idx_poll_resp_poll` (`poll_id`),
INDEX `idx_poll_resp_citizen` (`citizen_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 6. Seed Campaign Finance PAC Escrow Account in nyx_treasury_accounts
INSERT INTO `nyx_treasury_accounts`
(`account_id`, `label`, `balance`, `type`, `signatories_required`)
VALUES
('gov:escrow:pac', 'Municipal Campaign Finance PAC Reserve Account', 0.00, 'reserve', 1)
ON DUPLICATE KEY UPDATE `label` = VALUES(`label`);

SET FOREIGN_KEY_CHECKS = 1;
2 changes: 1 addition & 1 deletion FiveM/nyx_core/sql/migrations/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@
"064_industrial_refining_and_functional_parts_manufacturing.sql",
"065_judicial_bail_bonds_surety_escrow_and_fugitive_recovery.sql",
"066_municipal_toll_booths_and_commercial_weigh_stations.sql",
"067_municipal_water_utility_and_hydrant_pressure.sql"
"067_campaign_finance_and_citizen_os_polling.sql"
]
37 changes: 37 additions & 0 deletions FiveM/nyx_parliament/client/pacs.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
--[[
Nyxframework: nyx_parliament
File: client/pacs.lua
Description: Client-side Political Action Committee (PAC) interactions & campaign finance bridge.
]]

Nyx = Nyx or {}
Nyx.Parliament = Nyx.Parliament or {}

-- Donate to PAC Client Method
function Nyx.Parliament.DonateToPAC(pacId, amount, donorFactionId)
local res = Nyx.RPC.Call("parliament:donateToPAC", {
pacId = pacId,
amount = amount,
donorFactionId = donorFactionId
})
return res
end

-- Register PAC Client Method
function Nyx.Parliament.RegisterPAC(candidateId, officeId, title)
local res = Nyx.RPC.Call("parliament:registerPAC", {
candidateId = candidateId,
officeId = officeId,
title = title
})
return res
end

-- Exports
exports('DonateToPAC', function(pacId, amount, donorFactionId)
return Nyx.Parliament.DonateToPAC(pacId, amount, donorFactionId)
end)

exports('RegisterPAC', function(candidateId, officeId, title)
return Nyx.Parliament.RegisterPAC(candidateId, officeId, title)
end)
34 changes: 34 additions & 0 deletions FiveM/nyx_parliament/client/polling.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--[[
Nyxframework: nyx_parliament
File: client/polling.lua
Description: Client-side Citizen OS mobile opinion survey notification handlers & NUI bridge.
]]

Nyx = Nyx or {}
Nyx.Parliament = Nyx.Parliament or {}

-- New Mobile Poll Broadcast Handler
RegisterNetEvent("nyx:parliament:client:newMobilePoll", function(pollData)
if type(pollData) == "table" then
TriggerEvent("nyx:core:client:notify",
string.format("CITIZEN OS POLL: New mobile opinion survey: '%s'. Open Smartphone to respond.", pollData.title or "Public Poll"),
"info"
)
end
end)

-- Submit Mobile Poll Response via RPC
function Nyx.Parliament.SubmitMobilePollResponse(pollId, selectedOption)
local voterHash = string.format("hw_%d_%s", GetGameTimer(), tostring(GetPlayerServerId(PlayerId())))
local res = Nyx.RPC.Call("parliament:submitPollResponse", {
pollId = pollId,
selectedOption = selectedOption,
voterHash = voterHash
})
return res
end

-- Export for Citizen OS Smartphone UI
exports('SubmitMobilePollResponse', function(pollId, selectedOption)
return Nyx.Parliament.SubmitMobilePollResponse(pollId, selectedOption)
end)
6 changes: 6 additions & 0 deletions FiveM/nyx_parliament/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ Config.VotingWindowHours = 72 -- Hours allowed for active voting
Config.MaxCandidatesPerSession = 10 -- Max candidate ceiling per election session
Config.EnforceBoothProximity = false -- When true, requires physical presence at a booth to cast ballot

-- Statutory Campaign Finance & Citizen OS Polling
Config.StatutoryDonationCap = 5000.00 -- Max statutory donation cap per donor per election cycle ($)
Config.PACRegistrationFee = 1000.00 -- Collateral fee to register a Political Action Committee ($)
Config.PACAuditFineMultiplier = 1.5 -- Statutory fine multiplier for over-cap PAC contributions (150%)
Config.MobilePollDurationHours = 72 -- Default duration for Citizen OS mobile opinion surveys (hours)

-- Elective Municipal Offices
Config.Offices = {
['mayor'] = {
Expand Down
5 changes: 5 additions & 0 deletions FiveM/nyx_parliament/fxmanifest.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ shared_scripts {
'shared/irv.lua',
'shared/legislation_ui.lua',
'shared/elections.lua',
'shared/campaign_finance.lua',
'shared/statutory_enforcement.lua'
}

Expand All @@ -26,6 +27,8 @@ server_scripts {
'server/statutes.lua',
'server/enactment.lua',
'server/elections.lua',
'server/campaign_finance.lua',
'server/polling.lua',
'server/tabulation.lua',
'server/voting.lua',
'server/main.lua',
Expand All @@ -35,6 +38,8 @@ server_scripts {
client_scripts {
'client/booths.lua',
'client/legislation_ui.lua',
'client/polling.lua',
'client/pacs.lua',
'client/main.lua',
'client/exports.lua'
}
Expand Down
Loading
Loading