feat: polls with live voting via WebSocket

- /poll command opens creation modal (2-10 options)
- PollDisplay with vote bars, percentages, live WS updates
- Backend: polls/poll_options/poll_votes tables, Create/Get/Vote endpoints
- attachPolls enriches message list responses
- POLL_UPDATE broadcast on vote for real-time sync
This commit is contained in:
2026-07-02 12:35:05 -04:00
parent d8b4defaff
commit 40f8d193ff
10 changed files with 741 additions and 1 deletions
+25
View File
@@ -509,5 +509,30 @@ CREATE TABLE IF NOT EXISTS server_groups (
);
CREATE INDEX IF NOT EXISTS idx_server_groups_server ON server_groups(server_id);
ALTER TABLE channels ADD COLUMN IF NOT EXISTS group_id UUID REFERENCES server_groups(id) ON DELETE SET NULL;
CREATE TABLE IF NOT EXISTS polls (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
message_id UUID NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
question TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_polls_message ON polls(message_id);
CREATE TABLE IF NOT EXISTS poll_options (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
poll_id UUID NOT NULL REFERENCES polls(id) ON DELETE CASCADE,
text TEXT NOT NULL,
position INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_poll_options_poll ON poll_options(poll_id);
CREATE TABLE IF NOT EXISTS poll_votes (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
option_id UUID NOT NULL REFERENCES poll_options(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE (option_id, user_id)
);
CREATE INDEX IF NOT EXISTS idx_poll_votes_option ON poll_votes(option_id);
`