Each poll has a role-based permission system. The owner assigns roles to users they discover or invite. Roles control what actions a user can perform on a poll.
Design
Roles & Permissions
Action
Viewer
Participant
Moderator
Owner
View poll & results
✅
✅
✅
✅
Add options
❌
✅
✅
✅
Vote
❌
✅
✅
✅
Add/remove users
❌
❌
✅
✅
Start/stop poll
❌
❌
✅
✅
Delete poll
❌
❌
❌
✅
Implementation
Owner is implicit (poll.ownerId === userId)
Roles stored in poll.roles[] array
Role changes are broadcast to all connected peers
Moderators can invite users by peer ID (discovered via spec 007) or by sharing a poll link
Permission checks happen both client-side (UI) and on message receipt (owner validates)
Invite Flow
Owner/moderator discovers a user (see spec 007) or has their peer ID
Assigns them a role → updates poll.roles[]
When that user connects, they receive the poll state including their role
Users without a role who connect via link get viewer by default