-- Voting Methods as Plugins -- Each voting method is a configurable plugin with its own settings -- Voting method plugins (system plugins for voting) CREATE TABLE voting_method_plugins ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), name VARCHAR(50) NOT NULL UNIQUE, display_name VARCHAR(100) NOT NULL, description TEXT, icon VARCHAR(50), -- Icon identifier for UI is_active BOOLEAN NOT NULL DEFAULT TRUE, -- Platform-level activation is_default BOOLEAN NOT NULL DEFAULT FALSE, -- Default method for new proposals config_schema JSONB, -- JSON Schema for configuration options default_config JSONB DEFAULT '{}', min_options INT DEFAULT 2, max_options INT, supports_delegation BOOLEAN NOT NULL DEFAULT TRUE, complexity_level VARCHAR(20) DEFAULT 'simple', -- simple, moderate, advanced created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Community voting method configuration CREATE TABLE community_voting_methods ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), community_id UUID NOT NULL REFERENCES communities(id) ON DELETE CASCADE, voting_method_id UUID NOT NULL REFERENCES voting_method_plugins(id) ON DELETE CASCADE, is_enabled BOOLEAN NOT NULL DEFAULT TRUE, is_default BOOLEAN NOT NULL DEFAULT FALSE, config JSONB DEFAULT '{}', -- Community-specific configuration allowed_roles UUID[], -- Roles that can use this method (NULL = all) created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), UNIQUE(community_id, voting_method_id) ); -- Insert default voting method plugins INSERT INTO voting_method_plugins (name, display_name, description, icon, is_active, is_default, config_schema, default_config, complexity_level) VALUES ( 'approval', 'Approval Voting', 'Vote for one or more options. Simple and easy to understand.', 'check-circle', TRUE, TRUE, '{ "type": "object", "properties": { "max_selections": {"type": "integer", "minimum": 1, "description": "Maximum options a voter can select"}, "require_selection": {"type": "boolean", "description": "Require at least one selection"} } }', '{"max_selections": null, "require_selection": true}', 'simple' ), ( 'ranked_choice', 'Ranked Choice (IRV)', 'Rank options in order of preference. Eliminates spoiler effect.', 'list-ordered', TRUE, FALSE, '{ "type": "object", "properties": { "require_full_ranking": {"type": "boolean", "description": "Require ranking all options"}, "min_rankings": {"type": "integer", "minimum": 1, "description": "Minimum rankings required"} } }', '{"require_full_ranking": false, "min_rankings": 1}', 'moderate' ), ( 'schulze', 'Schulze Method', 'Condorcet-consistent pairwise comparison. Best for complex decisions.', 'git-compare', TRUE, FALSE, '{ "type": "object", "properties": { "show_pairwise_matrix": {"type": "boolean", "description": "Show detailed pairwise comparison results"}, "allow_ties": {"type": "boolean", "description": "Allow equal rankings"} } }', '{"show_pairwise_matrix": true, "allow_ties": true}', 'advanced' ), ( 'star', 'STAR Voting', 'Score Then Automatic Runoff. Rate options 0-5 stars.', 'star', TRUE, FALSE, '{ "type": "object", "properties": { "max_score": {"type": "integer", "minimum": 3, "maximum": 10, "description": "Maximum score (default 5)"}, "show_runoff": {"type": "boolean", "description": "Show automatic runoff details"} } }', '{"max_score": 5, "show_runoff": true}', 'moderate' ), ( 'quadratic', 'Quadratic Voting', 'Express intensity of preference. Cost = votes². Good for resource allocation.', 'trending-up', TRUE, FALSE, '{ "type": "object", "properties": { "credit_budget": {"type": "integer", "minimum": 10, "description": "Credits per voter"}, "allow_negative": {"type": "boolean", "description": "Allow negative votes (against)"} } }', '{"credit_budget": 100, "allow_negative": false}', 'advanced' ) ON CONFLICT (name) DO UPDATE SET display_name = EXCLUDED.display_name, description = EXCLUDED.description, config_schema = EXCLUDED.config_schema, default_config = EXCLUDED.default_config; -- Default plugins registry (for setup wizard) CREATE TABLE default_plugins ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), plugin_name VARCHAR(100) NOT NULL, plugin_type VARCHAR(50) NOT NULL, -- 'voting', 'integration', 'feature', 'theme' display_name VARCHAR(100) NOT NULL, description TEXT, is_core BOOLEAN NOT NULL DEFAULT FALSE, -- Core plugins can't be disabled is_recommended BOOLEAN NOT NULL DEFAULT TRUE, -- Recommended for new installs default_enabled BOOLEAN NOT NULL DEFAULT TRUE, config_defaults JSONB DEFAULT '{}', dependencies TEXT[], -- Other plugins this depends on category VARCHAR(50), sort_order INT DEFAULT 0, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Insert default plugins for setup INSERT INTO default_plugins (plugin_name, plugin_type, display_name, description, is_core, is_recommended, default_enabled, category, sort_order) VALUES -- Core plugins (always enabled) ('core.auth', 'feature', 'Authentication', 'User authentication and sessions', TRUE, TRUE, TRUE, 'core', 1), ('core.communities', 'feature', 'Communities', 'Community management', TRUE, TRUE, TRUE, 'core', 2), ('core.proposals', 'feature', 'Proposals', 'Proposal creation and management', TRUE, TRUE, TRUE, 'core', 3), -- Voting plugins ('voting.approval', 'voting', 'Approval Voting', 'Simple approval voting', FALSE, TRUE, TRUE, 'voting', 10), ('voting.ranked_choice', 'voting', 'Ranked Choice', 'Instant runoff voting', FALSE, TRUE, TRUE, 'voting', 11), ('voting.schulze', 'voting', 'Schulze Method', 'Condorcet voting', FALSE, FALSE, FALSE, 'voting', 12), ('voting.star', 'voting', 'STAR Voting', 'Score then automatic runoff', FALSE, TRUE, TRUE, 'voting', 13), ('voting.quadratic', 'voting', 'Quadratic Voting', 'Intensity-weighted voting', FALSE, FALSE, FALSE, 'voting', 14), -- Feature plugins ('feature.delegation', 'feature', 'Liquid Delegation', 'Vote delegation system', FALSE, TRUE, TRUE, 'governance', 20), ('feature.deliberation', 'feature', 'Deliberation Phases', 'Structured discussion phases', FALSE, TRUE, TRUE, 'governance', 21), ('feature.moderation', 'feature', 'Moderation Tools', 'Content moderation', FALSE, TRUE, TRUE, 'moderation', 22), ('feature.notifications', 'feature', 'Notifications', 'User notifications', FALSE, TRUE, TRUE, 'communication', 23), -- Integration plugins ('integration.gitlab', 'integration', 'GitLab Integration', 'Connect to GitLab projects', FALSE, FALSE, FALSE, 'integrations', 30), ('integration.github', 'integration', 'GitHub Integration', 'Connect to GitHub repositories', FALSE, FALSE, FALSE, 'integrations', 31), ('integration.matrix', 'integration', 'Matrix Integration', 'Matrix chat notifications', FALSE, FALSE, FALSE, 'integrations', 32), ('integration.discourse', 'integration', 'Discourse Integration', 'Discourse forum sync', FALSE, FALSE, FALSE, 'integrations', 33) ON CONFLICT DO NOTHING; -- Instance plugin configuration (what's enabled at platform level) CREATE TABLE instance_plugins ( id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), plugin_name VARCHAR(100) NOT NULL UNIQUE, is_enabled BOOLEAN NOT NULL DEFAULT TRUE, config JSONB DEFAULT '{}', enabled_at TIMESTAMPTZ, enabled_by UUID REFERENCES users(id), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); -- Indexes CREATE INDEX idx_voting_method_plugins_active ON voting_method_plugins(is_active); CREATE INDEX idx_community_voting_methods_community ON community_voting_methods(community_id); CREATE INDEX idx_default_plugins_type ON default_plugins(plugin_type); CREATE INDEX idx_instance_plugins_enabled ON instance_plugins(is_enabled); -- Triggers CREATE TRIGGER voting_method_plugins_updated_at BEFORE UPDATE ON voting_method_plugins FOR EACH ROW EXECUTE FUNCTION update_updated_at(); CREATE TRIGGER community_voting_methods_updated_at BEFORE UPDATE ON community_voting_methods FOR EACH ROW EXECUTE FUNCTION update_updated_at(); CREATE TRIGGER instance_plugins_updated_at BEFORE UPDATE ON instance_plugins FOR EACH ROW EXECUTE FUNCTION update_updated_at();