170 lines
6.6 KiB
SQL
170 lines
6.6 KiB
SQL
-- Voting Plugin Database Schema
|
|
-- Plugin naming convention: pg_vt_tableName
|
|
-- pg_ = plugin, vt_ = voting plugin
|
|
|
|
-- Campaign Types: 'board_election', 'decision', 'survey'
|
|
-- Campaign Status: 'draft', 'scheduled', 'active', 'completed', 'cancelled'
|
|
-- Result Sharing: 'detailed', 'anonymous', 'none'
|
|
|
|
-- Voting Campaigns table
|
|
CREATE TABLE IF NOT EXISTS pg_vt_campaigns (
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
|
site_id UUID REFERENCES sites(id) ON DELETE CASCADE,
|
|
title VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
campaign_type VARCHAR(50) NOT NULL, -- board_election, decision, survey
|
|
form_id UUID, -- Foreign key to pg_vt_forms table
|
|
status VARCHAR(50) DEFAULT 'draft', -- draft, scheduled, active, completed, cancelled
|
|
overall_sharing_results VARCHAR(50) DEFAULT 'detailed', -- detailed, anonymous, none
|
|
public_access VARCHAR(50) DEFAULT 'restrict', -- restrict, allow
|
|
|
|
-- Campaign dates
|
|
start_date TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
end_date TIMESTAMP WITH TIME ZONE NOT NULL,
|
|
|
|
-- Recipients
|
|
recipient_group_id UUID, -- Reference to a group or null for all owners
|
|
recipient_type VARCHAR(50) DEFAULT 'all_owners', -- all_owners, board_members, authorized_voters, custom_group
|
|
|
|
-- Delivery methods
|
|
send_email BOOLEAN DEFAULT false,
|
|
send_text BOOLEAN DEFAULT false,
|
|
send_owner_app BOOLEAN DEFAULT false,
|
|
|
|
-- Metadata
|
|
created_by UUID REFERENCES users(id),
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
);
|
|
|
|
-- Create indexes for campaigns
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_campaigns_site_id ON pg_vt_campaigns(site_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_campaigns_type ON pg_vt_campaigns(campaign_type);
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_campaigns_status ON pg_vt_campaigns(status);
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_campaigns_dates ON pg_vt_campaigns(start_date, end_date);
|
|
|
|
-- Voting Forms table
|
|
-- Placeholder for form builder - will store form structure as JSON
|
|
CREATE TABLE IF NOT EXISTS pg_vt_forms (
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
|
site_id UUID REFERENCES sites(id) ON DELETE CASCADE,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
form_type VARCHAR(50) NOT NULL, -- board_election, decision, survey
|
|
|
|
-- Form structure stored as JSON
|
|
-- This is a placeholder until we build/embed a form builder
|
|
-- Example structure:
|
|
-- {
|
|
-- "questions": [
|
|
-- {
|
|
-- "id": "q1",
|
|
-- "type": "multiple_choice",
|
|
-- "label": "Choose 4 Board Members *",
|
|
-- "required": true,
|
|
-- "multiple": true,
|
|
-- "max_selections": 4,
|
|
-- "options": [
|
|
-- {"id": "opt1", "value": "bod 1"},
|
|
-- {"id": "opt2", "value": "bod 2"}
|
|
-- ]
|
|
-- }
|
|
-- ]
|
|
-- }
|
|
form_structure JSONB DEFAULT '{"questions": []}',
|
|
|
|
-- Metadata
|
|
created_by UUID REFERENCES users(id),
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
is_active BOOLEAN DEFAULT true
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_forms_site_id ON pg_vt_forms(site_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_forms_type ON pg_vt_forms(form_type);
|
|
|
|
-- Campaign Responses table (main response tracking)
|
|
CREATE TABLE IF NOT EXISTS pg_vt_responses (
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
|
campaign_id UUID REFERENCES pg_vt_campaigns(id) ON DELETE CASCADE,
|
|
person_id UUID REFERENCES people(id),
|
|
user_id UUID REFERENCES users(id),
|
|
|
|
-- Participation tracking
|
|
answered BOOLEAN DEFAULT false,
|
|
answered_date TIMESTAMP WITH TIME ZONE,
|
|
last_modified_date TIMESTAMP WITH TIME ZONE,
|
|
|
|
-- Communication tracking
|
|
email_sent BOOLEAN DEFAULT false,
|
|
text_sent BOOLEAN DEFAULT false,
|
|
|
|
-- Metadata
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
|
|
UNIQUE(campaign_id, person_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_responses_campaign_id ON pg_vt_responses(campaign_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_responses_person_id ON pg_vt_responses(person_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_responses_answered ON pg_vt_responses(answered);
|
|
|
|
-- Response Answers table (detailed answer data)
|
|
CREATE TABLE IF NOT EXISTS pg_vt_response_answers (
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
|
response_id UUID REFERENCES pg_vt_responses(id) ON DELETE CASCADE,
|
|
question_id VARCHAR(255) NOT NULL, -- Reference to question in form_structure
|
|
answer_value TEXT, -- For text, numeric, date answers
|
|
answer_options JSONB, -- For multiple choice answers: ["bod 1", "bod 3", "bod 5", "bod 4"]
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_response_answers_response_id ON pg_vt_response_answers(response_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_response_answers_question_id ON pg_vt_response_answers(question_id);
|
|
|
|
-- Change Logs table (audit trail for response changes)
|
|
CREATE TABLE IF NOT EXISTS pg_vt_response_change_logs (
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
|
response_id UUID REFERENCES pg_vt_responses(id) ON DELETE CASCADE,
|
|
campaign_id UUID REFERENCES pg_vt_campaigns(id) ON DELETE CASCADE,
|
|
person_id UUID REFERENCES people(id),
|
|
person_name VARCHAR(255),
|
|
unit VARCHAR(255),
|
|
email VARCHAR(255),
|
|
phone VARCHAR(50),
|
|
answered_date TIMESTAMP WITH TIME ZONE,
|
|
answered_change_date TIMESTAMP WITH TIME ZONE,
|
|
who_changed VARCHAR(255), -- Person who made the change
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_change_logs_campaign_id ON pg_vt_response_change_logs(campaign_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_change_logs_response_id ON pg_vt_response_change_logs(response_id);
|
|
|
|
-- Groups table (for custom recipient groups)
|
|
CREATE TABLE IF NOT EXISTS pg_vt_groups (
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
|
site_id UUID REFERENCES sites(id) ON DELETE CASCADE,
|
|
name VARCHAR(255) NOT NULL,
|
|
description TEXT,
|
|
created_by UUID REFERENCES users(id),
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_groups_site_id ON pg_vt_groups(site_id);
|
|
|
|
-- Group Members junction table
|
|
CREATE TABLE IF NOT EXISTS pg_vt_group_members (
|
|
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
|
|
group_id UUID REFERENCES pg_vt_groups(id) ON DELETE CASCADE,
|
|
person_id UUID REFERENCES people(id) ON DELETE CASCADE,
|
|
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
|
|
UNIQUE(group_id, person_id)
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_group_members_group_id ON pg_vt_group_members(group_id);
|
|
CREATE INDEX IF NOT EXISTS idx_pg_vt_group_members_person_id ON pg_vt_group_members(person_id);
|
|
|